diff options
Diffstat (limited to 'src/map')
82 files changed, 50084 insertions, 36953 deletions
diff --git a/src/map/CMakeLists.txt b/src/map/CMakeLists.txt deleted file mode 100644 index 51c3538ef..000000000 --- a/src/map/CMakeLists.txt +++ /dev/null @@ -1,12 +0,0 @@ - -# -# setup -# -set( MAP_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR} CACHE INTERNAL "" ) -set( SQL_MAP_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR} CACHE INTERNAL "" ) - - -# -# targets -# -add_subdirectory( sql ) diff --git a/src/map/HPMmap.c b/src/map/HPMmap.c new file mode 100644 index 000000000..cb8c979c6 --- /dev/null +++ b/src/map/HPMmap.c @@ -0,0 +1,215 @@ +// Copyright (c) Hercules Dev Team, licensed under GNU GPL. +// See the LICENSE file + +#define HERCULES_CORE + +#include "HPMmap.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#include "atcommand.h" +#include "battle.h" +#include "battleground.h" +#include "chat.h" +#include "chrif.h" +#include "clif.h" +#include "date.h" +#include "duel.h" +#include "elemental.h" +#include "guild.h" +#include "homunculus.h" +#include "instance.h" +#include "intif.h" +#include "irc-bot.h" +#include "itemdb.h" +#include "log.h" +#include "mail.h" +#include "map.h" +#include "mapreg.h" +#include "mercenary.h" +#include "mob.h" +#include "npc.h" +#include "party.h" +#include "path.h" +#include "pc.h" +#include "pc_groups.h" +#include "pet.h" +#include "quest.h" +#include "script.h" +#include "searchstore.h" +#include "skill.h" +#include "status.h" +#include "storage.h" +#include "trade.h" +#include "unit.h" +#include "vending.h" +#include "../common/HPM.h" +#include "../common/cbasetypes.h" +#include "../common/conf.h" +#include "../common/db.h" +#include "../common/des.h" +#include "../common/ers.h" +#include "../common/malloc.h" +#include "../common/mapindex.h" +#include "../common/mmo.h" +#include "../common/showmsg.h" +#include "../common/socket.h" +#include "../common/strlib.h" +#include "../common/sysinfo.h" + +#include "../common/HPMDataCheck.h" + +struct HPM_atcommand_list { + //tracking currently not enabled + // - requires modifying how plugins calls atcommand creation + // - needs load/unload during runtime support + //unsigned int pID;/* plugin id */ + char name[ATCOMMAND_LENGTH]; + AtCommandFunc func; +}; + +struct HPM_atcommand_list *atcommand_list = NULL; +unsigned int atcommand_list_items = 0; + +/** + * (char*) data name -> (unsigned int) HPMDataCheck[] index + **/ +DBMap *datacheck_db; + +bool HPM_map_grabHPData(struct HPDataOperationStorage *ret, enum HPluginDataTypes type, void *ptr) { + /* record address */ + switch( type ) { + case HPDT_MSD: + ret->HPDataSRCPtr = (void**)(&((struct map_session_data *)ptr)->hdata); + ret->hdatac = &((struct map_session_data *)ptr)->hdatac; + break; + case HPDT_NPCD: + ret->HPDataSRCPtr = (void**)(&((struct npc_data *)ptr)->hdata); + ret->hdatac = &((struct npc_data *)ptr)->hdatac; + break; + case HPDT_MAP: + ret->HPDataSRCPtr = (void**)(&((struct map_data *)ptr)->hdata); + ret->hdatac = &((struct map_data *)ptr)->hdatac; + break; + case HPDT_PARTY: + ret->HPDataSRCPtr = (void**)(&((struct party_data *)ptr)->hdata); + ret->hdatac = &((struct party_data *)ptr)->hdatac; + break; + case HPDT_GUILD: + ret->HPDataSRCPtr = (void**)(&((struct guild *)ptr)->hdata); + ret->hdatac = &((struct guild *)ptr)->hdatac; + break; + case HPDT_INSTANCE: + ret->HPDataSRCPtr = (void**)(&((struct instance_data *)ptr)->hdata); + ret->hdatac = &((struct instance_data *)ptr)->hdatac; + break; + default: + return false; + } + return true; +} + +void HPM_map_plugin_load_sub(struct hplugin *plugin) { + plugin->hpi->addCommand = HPM->import_symbol("addCommand",plugin->idx); + plugin->hpi->addScript = HPM->import_symbol("addScript",plugin->idx); + plugin->hpi->addPCGPermission = HPM->import_symbol("addGroupPermission",plugin->idx); +} + +bool HPM_map_add_atcommand(char *name, AtCommandFunc func) { + unsigned int i = 0; + + for(i = 0; i < atcommand_list_items; i++) { + if( !strcmpi(atcommand_list[i].name,name) ) { + ShowDebug("HPM_map_add_atcommand: duplicate command '%s', skipping...\n", name); + return false; + } + } + + i = atcommand_list_items; + + RECREATE(atcommand_list, struct HPM_atcommand_list , ++atcommand_list_items); + + safestrncpy(atcommand_list[i].name, name, sizeof(atcommand_list[i].name)); + atcommand_list[i].func = func; + + return true; +} + +void HPM_map_atcommands(void) { + unsigned int i; + + for(i = 0; i < atcommand_list_items; i++) { + atcommand->add(atcommand_list[i].name,atcommand_list[i].func,true); + } +} + +/** + * Called by HPM->DataCheck on a plugins incoming data, ensures data structs in use are matching! + **/ +bool HPM_map_DataCheck (struct s_HPMDataCheck *src, unsigned int size, char *name) { + unsigned int i, j; + + for(i = 0; i < size; i++) { + + if( !strdb_exists(datacheck_db, src[i].name) ) { + ShowError("HPMDataCheck:%s: '%s' was not found\n",name,src[i].name); + return false; + } else { + j = strdb_uiget(datacheck_db, src[i].name);/* not double lookup; exists sets cache to found data */ + if( src[i].size != HPMDataCheck[j].size ) { + ShowWarning("HPMDataCheck:%s: '%s' size mismatch %u != %u\n",name,src[i].name,src[i].size,HPMDataCheck[j].size); + return false; + } + } + } + + return true; +} + +/** + * Adds a new group permission to the HPM-provided list + **/ +void HPM_map_add_group_permission(unsigned int pluginID, char *name, unsigned int *mask) { + unsigned char index = pcg->HPMpermissions_count; + + RECREATE(pcg->HPMpermissions, struct pc_groups_new_permission, ++pcg->HPMpermissions_count); + + pcg->HPMpermissions[index].pID = pluginID; + pcg->HPMpermissions[index].name = aStrdup(name); + pcg->HPMpermissions[index].mask = mask; +} + +void HPM_map_do_init(void) { + unsigned int i; + + /** + * Populates datacheck_db for easy lookup later on + **/ + datacheck_db = strdb_alloc(DB_OPT_BASE,0); + + for(i = 0; i < HPMDataCheckLen; i++) { + strdb_uiput(datacheck_db, HPMDataCheck[i].name, i); + } + +} + +void HPM_map_do_final(void) { + unsigned char i; + + if( atcommand_list ) + aFree(atcommand_list); + /** + * why is pcg->HPM being cleared here? because PCG's do_final is not final, + * is used on reload, and would thus cause plugin-provided permissions to go away + **/ + for( i = 0; i < pcg->HPMpermissions_count; i++ ) { + aFree(pcg->HPMpermissions[i].name); + } + if( pcg->HPMpermissions ) + aFree(pcg->HPMpermissions); + + db_destroy(datacheck_db); +} diff --git a/src/map/HPMmap.h b/src/map/HPMmap.h new file mode 100644 index 000000000..99c4224ff --- /dev/null +++ b/src/map/HPMmap.h @@ -0,0 +1,29 @@ +// Copyright (c) Hercules Dev Team, licensed under GNU GPL. +// See the LICENSE file + +#ifndef MAP_HPMMAP_H +#define MAP_HPMMAP_H + +#include "../common/cbasetypes.h" +#include "../map/atcommand.h" +#include "../common/HPM.h" + +struct hplugin; +struct map_session_data; + +bool HPM_map_grabHPData(struct HPDataOperationStorage *ret, enum HPluginDataTypes type, void *ptr); + +bool HPM_map_add_atcommand(char *name, AtCommandFunc func); +void HPM_map_atcommands(void); + +void HPM_map_plugin_load_sub(struct hplugin *plugin); + +void HPM_map_do_final(void); + +void HPM_map_add_group_permission(unsigned int pluginID, char *name, unsigned int *mask); + +bool HPM_map_DataCheck(struct s_HPMDataCheck *src, unsigned int size, char *name); + +void HPM_map_do_init(void); + +#endif /* MAP_HPMMAP_H */ diff --git a/src/map/Makefile.in b/src/map/Makefile.in index bb99b6a05..fc58c9d70 100644 --- a/src/map/Makefile.in +++ b/src/map/Makefile.in @@ -1,43 +1,47 @@ - -COMMON_H = $(shell ls ../common/*.h) - -MT19937AR_OBJ = ../../3rdparty/mt19937ar/mt19937ar.o -MT19937AR_H = ../../3rdparty/mt19937ar/mt19937ar.h -MT19937AR_INCLUDE = -I../../3rdparty/mt19937ar - -LIBCONFIG_OBJ = ../../3rdparty/libconfig/libconfig.o ../../3rdparty/libconfig/grammar.o \ - ../../3rdparty/libconfig/scanctx.o ../../3rdparty/libconfig/scanner.o ../../3rdparty/libconfig/strbuf.o -LIBCONFIG_H = ../../3rdparty/libconfig/libconfig.h ../../3rdparty/libconfig/grammar.h \ - ../../3rdparty/libconfig/parsectx.h ../../3rdparty/libconfig/scanctx.h ../../3rdparty/libconfig/scanner.h \ - ../../3rdparty/libconfig/strbuf.h ../../3rdparty/libconfig/wincompat.h -LIBCONFIG_INCLUDE = -I../../3rdparty/libconfig - -MAP_OBJ = map.o chrif.o clif.o pc.o status.o npc.o \ - npc_chat.o chat.o path.o itemdb.o mob.o script.o \ - storage.o skill.o atcommand.o battle.o battleground.o \ - intif.o trade.o party.o vending.o guild.o pet.o \ - log.o mail.o date.o unit.o homunculus.o mercenary.o quest.o instance.o \ - buyingstore.o searchstore.o duel.o pc_groups.o elemental.o irc-bot.o -MAP_SQL_OBJ = $(MAP_OBJ:%=obj_sql/%) \ - obj_sql/mapreg_sql.o -MAP_H = map.h chrif.h clif.h pc.h status.h npc.h \ - chat.h itemdb.h mob.h script.h path.h \ - storage.h skill.h atcommand.h battle.h battleground.h \ - intif.h trade.h party.h vending.h guild.h pet.h \ - log.h mail.h date.h unit.h homunculus.h mercenary.h quest.h instance.h mapreg.h \ - buyingstore.h searchstore.h duel.h pc_groups.h \ - ../config/core.h ../config/renewal.h ../config/secure.h ../config/const.h \ - ../config/classes/general.h elemental.h packets.h packets_struct.h irc-bot.h +# Copyright (c) Hercules Dev Team, licensed under GNU GPL. +# See the LICENSE file + +# @configure_input@ + +CONFIG_D = ../config +CONFIG_H = $(wildcard $(CONFIG_D)/*.h) $(wildcard $(CONFIG_D)/*/*.h) + +COMMON_D = ../common +COMMON_H = $(wildcard $(COMMON_D)/*.h) +SYSINFO_INC = $(COMMON_D)/sysinfo.inc + +LIBCONFIG_D = ../../3rdparty/libconfig +LIBCONFIG_OBJ = $(addprefix $(LIBCONFIG_D)/, libconfig.o grammar.o scanctx.o \ + scanner.o strbuf.o) +LIBCONFIG_H = $(addprefix $(LIBCONFIG_D)/, libconfig.h grammar.h parsectx.h \ + scanctx.h scanner.h strbuf.h wincompat.h) +LIBCONFIG_INCLUDE = -I$(LIBCONFIG_D) + +MT19937AR_D = ../../3rdparty/mt19937ar +MT19937AR_OBJ = $(MT19937AR_D)/mt19937ar.o +MT19937AR_H = $(MT19937AR_D)/mt19937ar.h +MT19937AR_INCLUDE = -I$(MT19937AR_D) + +MAP_C = atcommand.c battle.c battleground.c buyingstore.c chat.c chrif.c \ + clif.c date.c duel.c elemental.c guild.c homunculus.c HPMmap.c \ + instance.c intif.c irc-bot.c itemdb.c log.c mail.c map.c mapreg_sql.c \ + mercenary.c mob.c npc.c npc_chat.c party.c path.c pc.c pc_groups.c \ + pet.c quest.c script.c searchstore.c skill.c status.c storage.c \ + trade.c unit.c vending.c +MAP_OBJ = $(addprefix obj_sql/, $(patsubst %c,%o,$(MAP_C))) +MAP_H = atcommand.h battle.h battleground.h buyingstore.h chat.h chrif.h \ + clif.h date.h duel.h elemental.h guild.h homunculus.h HPMmap.h \ + instance.h intif.h irc-bot.h itemdb.h log.h mail.h map.h mapreg.h \ + mercenary.h mob.h npc.h packets.h packets_struct.h party.h path.h \ + pc.h pc_groups.h pet.h quest.h script.h searchstore.h skill.h \ + status.h storage.h trade.h unit.h vending.h HAVE_MYSQL=@HAVE_MYSQL@ ifeq ($(HAVE_MYSQL),yes) - ALL_DEPENDS=txt sql - SQL_DEPENDS=map-server + MAP_SERVER_SQL_DEPENDS=$(MAP_OBJ) $(COMMON_D)/obj_sql/common_sql.a $(COMMON_D)/obj_all/common.a $(MT19937AR_OBJ) $(LIBCONFIG_OBJ $(SYSINFO_INC)) else - ALL_TARGET=txt - SQL_DEPENDS=needs_mysql + MAP_SERVER_SQL_DEPENDS=needs_mysql endif -TXT_DEPENDS=map-server HAVE_PCRE=@HAVE_PCRE@ ifeq ($(HAVE_PCRE),yes) @@ -48,41 +52,47 @@ endif @SET_MAKE@ +CC = @CC@ +export CC + ##################################################################### -.PHONY : all txt sql clean help +.PHONY: all sql map-server clean buildclean help -all: $(ALL_DEPENDS) +all: sql -txt: $(TXT_DEPENDS) +sql: map-server -sql: $(SQL_DEPENDS) +buildclean: + @echo " CLEAN map (build temp files)" + @rm -rf *.o obj_sql -clean: +clean: buildclean @echo " CLEAN map" - @rm -rf *.o obj_txt obj_sql ../../map-server@EXEEXT@ ../../map-server@EXEEXT@ + @rm -rf ../../map-server@EXEEXT@ help: -ifeq ($(HAVE_MYSQL),yes) - @echo "possible targets are 'sql' 'txt' 'all' 'clean' 'help'" - @echo "'sql' - map server (SQL version)" -else - @echo "possible targets are 'txt' 'all' 'clean' 'help'" -endif - @echo "'txt' - map server (TXT version)" - @echo "'all' - builds all above targets" - @echo "'clean' - cleans builds and objects" - @echo "'help' - outputs this message" + @echo "possible targets are 'map-server' 'all' 'clean' 'help'" + @echo "'map-server' - map server" + @echo "'all' - builds all above targets" + @echo "'clean' - cleans builds and objects" + @echo "'buildclean' - cleans build temporary (object) files, without deleting the" + @echo " executables" + @echo "'help' - outputs this message" ##################################################################### +Makefile: Makefile.in + @$(MAKE) -C ../.. src/map/Makefile + +$(SYSINFO_INC): $(MAP_C) $(MAP_H) $(COMMON_H) $(CONFIG_H) $(MT19937AR_H) $(LIBCONFIG_H) + @echo " MAKE $@" + @$(MAKE) -C ../.. sysinfo + needs_mysql: @echo "MySQL not found or disabled by the configure script" @exit 1 # object directories -obj_txt: - @echo " MKDIR obj_txt" - @-mkdir obj_txt obj_sql: @echo " MKDIR obj_sql" @@ -90,25 +100,32 @@ obj_sql: # executables -map-server: obj_sql $(MAP_SQL_OBJ) ../common/obj_sql/common_sql.a ../common/obj_all/common.a - @echo " LD $@" - @@CC@ @LDFLAGS@ -o ../../map-server@EXEEXT@ $(MAP_SQL_OBJ) ../common/obj_sql/common_sql.a ../common/obj_all/common.a $(MT19937AR_OBJ) $(LIBCONFIG_OBJ) @LIBS@ @PCRE_LIBS@ @MYSQL_LIBS@ +map-server: ../../map-server@EXEEXT@ + +../../map-server@EXEEXT@: $(MAP_SERVER_SQL_DEPENDS) Makefile + @echo " LD $(notdir $@)" + @$(CC) @LDFLAGS@ -o ../../map-server@EXEEXT@ $(MAP_OBJ) $(COMMON_D)/obj_sql/common_sql.a \ + $(COMMON_D)/obj_all/common.a $(MT19937AR_OBJ) $(LIBCONFIG_OBJ) @LIBS@ @PCRE_LIBS@ @MYSQL_LIBS@ # map object files -obj_sql/%.o: %.c $(MAP_H) $(COMMON_H) $(MT19937AR_H) $(LIBCONFIG_H) +obj_sql/%.o: %.c $(MAP_H) $(COMMON_H) $(CONFIG_H) $(MT19937AR_H) $(LIBCONFIG_H) | obj_sql @echo " CC $<" - @@CC@ @CFLAGS@ $(MT19937AR_INCLUDE) $(LIBCONFIG_INCLUDE) $(PCRE_CFLAGS) @MYSQL_CFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $< + @$(CC) @CFLAGS@ @DEFS@ $(MT19937AR_INCLUDE) $(LIBCONFIG_INCLUDE) $(PCRE_CFLAGS) @MYSQL_CFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $< # missing object files -../common/obj_all/common.a: - @$(MAKE) -C ../common sql - -../common/obj_sql/common_sql.a: - @$(MAKE) -C ../common sql - -MT19937AR_OBJ: - @$(MAKE) -C ../../3rdparty/mt19937ar - -LIBCONFIG_OBJ: - @$(MAKE) -C ../../3rdparty/libconfig +$(COMMON_D)/obj_all/common.a: + @echo " MAKE $@" + @$(MAKE) -C $(COMMON_D) sql + +$(COMMON_D)/obj_sql/common_sql.a: + @echo " MAKE $@" + @$(MAKE) -C $(COMMON_D) sql + +$(MT19937AR_OBJ): + @echo " MAKE $@" + @$(MAKE) -C $(MT19937AR_D) + +$(LIBCONFIG_OBJ): + @echo " MAKE $@" + @$(MAKE) -C $(LIBCONFIG_D) diff --git a/src/map/atcommand.c b/src/map/atcommand.c index b6a9e42ee..b5e8fa797 100644 --- a/src/map/atcommand.c +++ b/src/map/atcommand.c @@ -2,64 +2,65 @@ // See the LICENSE file // Portions Copyright (c) Athena Dev Teams -#include "../common/cbasetypes.h" -#include "../common/mmo.h" -#include "../common/timer.h" -#include "../common/nullpo.h" -#include "../common/core.h" -#include "../common/showmsg.h" -#include "../common/malloc.h" -#include "../common/random.h" -#include "../common/socket.h" -#include "../common/strlib.h" -#include "../common/utils.h" -#include "../common/conf.h" +#define HERCULES_CORE +#include "../config/core.h" // AUTOLOOTITEM_SIZE, AUTOTRADE_PERSISTENCY, MAX_SUGGESTIONS, MOB_FLEE(), MOB_HIT(), RENEWAL, RENEWAL_DROP, RENEWAL_EXP #include "atcommand.h" + +#include <math.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "HPMmap.h" #include "battle.h" #include "chat.h" -#include "clif.h" #include "chrif.h" +#include "clif.h" #include "duel.h" +#include "elemental.h" +#include "guild.h" +#include "homunculus.h" #include "intif.h" #include "itemdb.h" #include "log.h" +#include "mail.h" #include "map.h" -#include "pc.h" -#include "pc_groups.h" // groupid2name -#include "status.h" -#include "skill.h" +#include "mapreg.h" +#include "mercenary.h" #include "mob.h" #include "npc.h" -#include "pet.h" -#include "homunculus.h" -#include "mail.h" -#include "mercenary.h" -#include "elemental.h" #include "party.h" -#include "guild.h" +#include "pc.h" +#include "pc_groups.h" // groupid2name +#include "pet.h" +#include "quest.h" #include "script.h" +#include "searchstore.h" +#include "skill.h" +#include "status.h" #include "storage.h" #include "trade.h" #include "unit.h" -#include "mapreg.h" -#include "quest.h" -#include "searchstore.h" - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <math.h> +#include "../common/cbasetypes.h" +#include "../common/conf.h" +#include "../common/core.h" +#include "../common/malloc.h" +#include "../common/mmo.h" // MAX_CARTS +#include "../common/nullpo.h" +#include "../common/random.h" +#include "../common/showmsg.h" +#include "../common/socket.h" +#include "../common/strlib.h" +#include "../common/sysinfo.h" +#include "../common/timer.h" +#include "../common/utils.h" -static char* msg_table[MAX_MSG]; // Server messages (0-499 reserved for GM commands, 500-999 reserved for others) +struct atcommand_interface atcommand_s; static char atcmd_output[CHAT_SIZE_MAX]; static char atcmd_player_name[NAME_LENGTH]; -static AtCommandInfo* get_atcommandinfo_byname(const char *name); // @help -static const char* atcommand_checkalias(const char *aliasname); // @help -static void atcommand_get_suggestions(struct map_session_data* sd, const char *name, bool atcommand); // @help - // @commands (script-based) struct atcmd_binding_data* get_atcommandbind_byname(const char* name) { int i = 0; @@ -67,7 +68,7 @@ struct atcmd_binding_data* get_atcommandbind_byname(const char* name) { if( *name == atcommand->at_symbol || *name == atcommand->char_symbol ) name++; // for backwards compatibility - ARR_FIND( 0, atcommand->binding_count, i, strcmp(atcommand->binding[i]->command, name) == 0 ); + ARR_FIND( 0, atcommand->binding_count, i, strcmpi(atcommand->binding[i]->command, name) == 0 ); return ( i < atcommand->binding_count ) ? atcommand->binding[i] : NULL; } @@ -75,58 +76,64 @@ struct atcmd_binding_data* get_atcommandbind_byname(const char* name) { //----------------------------------------------------------- // Return the message string of the specified number by [Yor] //----------------------------------------------------------- -const char* msg_txt(int msg_number) -{ +const char* atcommand_msg(int msg_number) { if (msg_number >= 0 && msg_number < MAX_MSG && - msg_table[msg_number] != NULL && msg_table[msg_number][0] != '\0') - return msg_table[msg_number]; + atcommand->msg_table[msg_number] != NULL && atcommand->msg_table[msg_number][0] != '\0') + return atcommand->msg_table[msg_number]; return "??"; } -/*========================================== - * Read Message Data - *------------------------------------------*/ -int msg_config_read(const char* cfgName) -{ +/** + * Reads Message Data + * + * @param[in] cfg_name configuration filename to read. + * @param[in] allow_override whether to allow duplicate message IDs to override the original value. + * @return success state. + */ +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; - if ((fp = fopen(cfgName, "r")) == NULL) { - ShowError("Messages file not found: %s\n", cfgName); - return 1; + if ((fp = fopen(cfg_name, "r")) == NULL) { + ShowError("Messages file not found: %s\n", cfg_name); + return false; } if ((--called) == 0) - memset(msg_table, 0, sizeof(msg_table[0]) * MAX_MSG); + memset(atcommand->msg_table, 0, sizeof(atcommand->msg_table[0]) * MAX_MSG); - while(fgets(line, sizeof(line), fp)) - { + while(fgets(line, sizeof(line), fp)) { if (line[0] == '/' && line[1] == '/') continue; - if (sscanf(line, "%[^:]: %[^\r\n]", w1, w2) != 2) + if (sscanf(line, "%1023[^:]: %1023[^\r\n]", w1, w2) != 2) continue; - if (strcmpi(w1, "import") == 0) - msg_config_read(w2); - else - { + if (strcmpi(w1, "import") == 0) { + msg_config_read(w2, true); + } else { msg_number = atoi(w1); - if (msg_number >= 0 && msg_number < MAX_MSG) - { - if (msg_table[msg_number] != NULL) - aFree(msg_table[msg_number]); - msg_table[msg_number] = (char *)aMalloc((strlen(w2) + 1)*sizeof (char)); - strcpy(msg_table[msg_number],w2); + if (msg_number >= 0 && msg_number < MAX_MSG) { + if (atcommand->msg_table[msg_number] != NULL) { + if (!allow_override) { + ShowError("Duplicate message: ID '%d' was already used for '%s'. Message '%s' will be ignored.\n", + msg_number, w2, atcommand->msg_table[msg_number]); + continue; + } + aFree(atcommand->msg_table[msg_number]); + } + /* this could easily become consecutive memory like get_str() and save the malloc overhead for over 1k calls [Ind] */ + atcommand->msg_table[msg_number] = (char *)aMalloc((strlen(w2) + 1)*sizeof (char)); + strcpy(atcommand->msg_table[msg_number],w2); } } } fclose(fp); - return 0; + return true; } /*========================================== @@ -136,7 +143,7 @@ void do_final_msg(void) { int i; for (i = 0; i < MAX_MSG; i++) - aFree(msg_table[i]); + aFree(atcommand->msg_table[i]); } /** @@ -159,45 +166,39 @@ ACMD(send) // read message type as hex number (without the 0x) if(!message || !*message || !((sscanf(message, "len %x", &type)==1 && (len=1)) - || sscanf(message, "%x", &type)==1) ) - { - int i; - for (i = 900; i <= 903; ++i) - clif->message(fd, msg_txt(i)); - return false; - } - -#define PARSE_ERROR(error,p) \ -{\ -clif->message(fd, (error));\ -sprintf(atcmd_output, ">%s", (p));\ -clif->message(fd, atcmd_output);\ -} - //define PARSE_ERROR - -#define CHECK_EOS(p) \ -if(*(p) == 0){\ -clif->message(fd, "Unexpected end of string");\ -return false;\ -} - //define CHECK_EOS - -#define SKIP_VALUE(p) \ -{\ -while(*(p) && !ISSPACE(*(p))) ++(p); /* non-space */\ -while(*(p) && ISSPACE(*(p))) ++(p); /* space */\ -} - //define SKIP_VALUE - -#define GET_VALUE(p,num) \ -{\ -if(sscanf((p), "x%lx", &(num)) < 1 && sscanf((p), "%ld ", &(num)) < 1){\ -PARSE_ERROR("Invalid number in:",(p));\ -return false;\ -}\ -} - //define GET_VALUE - + || sscanf(message, "%x", &type)==1) ) { + clif->message(fd, msg_txt(900)); // Usage: + clif->message(fd, msg_txt(901)); // @send len <packet hex number> + clif->message(fd, msg_txt(902)); // @send <packet hex number> {<value>}* + clif->message(fd, msg_txt(903)); // Value: <type=B(default),W,L><number> or S<length>"<string>" + return false; + } + +#define PARSE_ERROR(error,p) do {\ + clif->message(fd, (error));\ + sprintf(atcmd_output, ">%s", (p));\ + clif->message(fd, atcmd_output);\ +} while(0) //define PARSE_ERROR + +#define CHECK_EOS(p) do { \ + if(*(p) == 0){ \ + clif->message(fd, "Unexpected end of string");\ + return false;\ + } \ +} while(0) //define CHECK_EOS + +#define SKIP_VALUE(p) do { \ + while(*(p) && !ISSPACE(*(p))) ++(p); /* non-space */\ + while(*(p) && ISSPACE(*(p))) ++(p); /* space */\ +} while(0) //define SKIP_VALUE + +#define GET_VALUE(p,num) do { \ + if(sscanf((p), "x%lx", &(num)) < 1 && sscanf((p), "%ld ", &(num)) < 1){\ + PARSE_ERROR("Invalid number in:",(p));\ + return false;\ + }\ +} while(0) //define GET_VALUE + if (type > 0 && type < MAX_PACKET_DB) { if(len) @@ -219,8 +220,8 @@ return false;\ len=SHRT_MAX-4; // maximum length off=4; } - WFIFOHEAD(fd, len); - WFIFOW(fd,0)=TOW(type); + WFIFOHEAD(sd->fd, len); + WFIFOW(sd->fd,0)=TOW(type); // parse packet contents SKIP_VALUE(message); @@ -228,25 +229,25 @@ return false;\ if(ISDIGIT(*message) || *message == '-' || *message == '+') {// default (byte) GET_VALUE(message,num); - WFIFOB(fd,off)=TOB(num); + WFIFOB(sd->fd,off)=TOB(num); ++off; } else if(TOUPPER(*message) == 'B') {// byte ++message; GET_VALUE(message,num); - WFIFOB(fd,off)=TOB(num); + WFIFOB(sd->fd,off)=TOB(num); ++off; } else if(TOUPPER(*message) == 'W') {// word (2 bytes) ++message; GET_VALUE(message,num); - WFIFOW(fd,off)=TOW(num); + WFIFOW(sd->fd,off)=TOW(num); off+=2; } else if(TOUPPER(*message) == 'L') {// long word (4 bytes) ++message; GET_VALUE(message,num); - WFIFOL(fd,off)=TOL(num); + WFIFOL(sd->fd,off)=TOL(num); off+=4; } else if(TOUPPER(*message) == 'S') {// string - escapes are valid @@ -299,7 +300,7 @@ return false;\ num<<=8; num+=(ISDIGIT(*message)?*message-'0':TOLOWER(*message)-'a'+10); } - WFIFOB(fd,off)=TOB(num); + WFIFOB(sd->fd,off)=TOB(num); ++message; CHECK_EOS(message); continue; @@ -328,13 +329,13 @@ return false;\ CHECK_EOS(message); } } - WFIFOB(fd,off)=TOB(num); + WFIFOB(sd->fd,off)=TOB(num); continue; } } } else num=*message; - WFIFOB(fd,off)=TOB(num); + WFIFOB(sd->fd,off)=TOB(num); ++message; CHECK_EOS(message); }//for @@ -347,7 +348,7 @@ return false;\ // terminate the string if(off < end) {// fill the rest with 0's - memset(WFIFOP(fd,off),0,end-off); + memset(WFIFOP(sd->fd,off),0,end-off); off=end; } } else @@ -359,12 +360,12 @@ return false;\ } if(packet_db[type].len == -1) {// send dynamic packet - WFIFOW(fd,2)=TOW(off); - WFIFOSET(fd,off); + WFIFOW(sd->fd,2)=TOW(off); + WFIFOSET(sd->fd,off); } else {// send static packet if(off < len) - memset(WFIFOP(fd,off),0,len-off); - WFIFOSET(fd,len); + memset(WFIFOP(sd->fd,off),0,len-off); + WFIFOSET(sd->fd,len); } } else { clif->message(fd, msg_txt(259)); // Invalid packet @@ -382,15 +383,12 @@ return false;\ /*========================================== * @rura, @warp, @mapmove *------------------------------------------*/ -ACMD(mapmove) -{ +ACMD(mapmove) { char map_name[MAP_NAME_LENGTH_EXT]; - unsigned short mapindex; + unsigned short map_index; short x = 0, y = 0; int16 m = -1; - - nullpo_retr(-1, sd); - + memset(map_name, '\0', sizeof(map_name)); if (!message || !*message || @@ -401,30 +399,35 @@ ACMD(mapmove) return false; } - mapindex = mapindex_name2id(map_name); - if (mapindex) - m = iMap->mapindex2mapid(mapindex); + map_index = mapindex->name2id(map_name); + if (map_index) + m = map->mapindex2mapid(map_index); - if (!mapindex) { // m < 0 means on different server! [Kevin] + if (!map_index || m < 0) { // m < 0 means on different server or that map is disabled! [Kevin] clif->message(fd, msg_txt(1)); // Map not found. return false; } + + if( sd->bl.m == m && sd->bl.x == x && sd->bl.y == y ) { + clif->message(fd, msg_txt(253)); // You already are at your destination! + return false; + } - if ((x || y) && iMap->getcell(m, x, y, CELL_CHKNOPASS) && pc->get_group_level(sd) < battle_config.gm_ignore_warpable_area) - { //This is to prevent the pc->setpos call from printing an error. + if ((x || y) && map->getcell(m, x, y, CELL_CHKNOPASS) && pc_get_group_level(sd) < battle_config.gm_ignore_warpable_area) { + //This is to prevent the pc->setpos call from printing an error. clif->message(fd, msg_txt(2)); - if (!iMap->search_freecell(NULL, m, &x, &y, 10, 10, 1)) + if (!map->search_freecell(NULL, m, &x, &y, 10, 10, 1)) x = y = 0; //Invalid cell, use random spot. } - if (map[m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { + if (map->list[m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { clif->message(fd, msg_txt(247)); return false; } - if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { + if (sd->bl.m >= 0 && map->list[sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { clif->message(fd, msg_txt(248)); return false; } - if (pc->setpos(sd, mapindex, x, y, CLR_TELEPORT) != 0) { + if (pc->setpos(sd, map_index, x, y, CLR_TELEPORT) != 0) { clif->message(fd, msg_txt(1)); // Map not found. return false; } @@ -436,11 +439,9 @@ ACMD(mapmove) /*========================================== * Displays where a character is. Corrected version by Silent. [Skotlex] *------------------------------------------*/ -ACMD(where) -{ +ACMD(where) { struct map_session_data* pl_sd; - nullpo_retr(-1, sd); memset(atcmd_player_name, '\0', sizeof atcmd_player_name); if (!message || !*message || sscanf(message, "%23[^\n]", atcmd_player_name) < 1) { @@ -448,10 +449,10 @@ ACMD(where) return false; } - pl_sd = iMap->nick2sd(atcmd_player_name); + pl_sd = map->nick2sd(atcmd_player_name); if (pl_sd == NULL || strncmp(pl_sd->status.name, atcmd_player_name, NAME_LENGTH) != 0 || - (pc_has_permission(pl_sd, PC_PERM_HIDE_SESSION) && pc->get_group_level(pl_sd) > pc->get_group_level(sd) && !pc_has_permission(sd, PC_PERM_WHO_DISPLAY_AID)) + (pc_has_permission(pl_sd, PC_PERM_HIDE_SESSION) && pc_get_group_level(pl_sd) > pc_get_group_level(sd) && !pc_has_permission(sd, PC_PERM_WHO_DISPLAY_AID)) ) { clif->message(fd, msg_txt(3)); // Character not found. return false; @@ -466,45 +467,43 @@ ACMD(where) /*========================================== * *------------------------------------------*/ -ACMD(jumpto) -{ +ACMD(jumpto) { struct map_session_data *pl_sd = NULL; - - nullpo_retr(-1, sd); - + if (!message || !*message) { clif->message(fd, msg_txt(911)); // Please enter a player name (usage: @jumpto/@warpto/@goto <char name/ID>). return false; } - - if((pl_sd=iMap->nick2sd((char *)message)) == NULL && (pl_sd=iMap->charid2sd(atoi(message))) == NULL) - { - clif->message(fd, msg_txt(3)); // Character not found. + + if (sd->bl.m >= 0 && map->list[sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { + clif->message(fd, msg_txt(248)); // You are not authorized to warp from your current map. return false; } - - if (pl_sd->bl.m >= 0 && map[pl_sd->bl.m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) - { - clif->message(fd, msg_txt(247)); // You are not authorized to warp to this map. + + if( pc_isdead(sd) ) { + clif->message(fd, msg_txt(864)); // "You cannot use this command when dead." return false; } - - if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) - { - clif->message(fd, msg_txt(248)); // You are not authorized to warp from your current map. + + if((pl_sd=map->nick2sd((char *)message)) == NULL && (pl_sd=map->charid2sd(atoi(message))) == NULL) { + clif->message(fd, msg_txt(3)); // Character not found. return false; } - if( pc_isdead(sd) ) - { - clif->message(fd, msg_txt(664)); + if (pl_sd->bl.m >= 0 && map->list[pl_sd->bl.m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { + clif->message(fd, msg_txt(247)); // You are not authorized to warp to this map. return false; } - + + if( pl_sd->bl.m == sd->bl.m && pl_sd->bl.x == sd->bl.x && pl_sd->bl.y == sd->bl.y ) { + clif->message(fd, msg_txt(253)); // You already are at your destination! + return false; + } + pc->setpos(sd, pl_sd->mapindex, pl_sd->bl.x, pl_sd->bl.y, CLR_TELEPORT); sprintf(atcmd_output, msg_txt(4), pl_sd->status.name); // Jumped to %s - clif->message(fd, atcmd_output); - + clif->message(fd, atcmd_output); + return true; } @@ -514,30 +513,32 @@ ACMD(jumpto) ACMD(jump) { short x = 0, y = 0; - - nullpo_retr(-1, sd); - + memset(atcmd_output, '\0', sizeof(atcmd_output)); sscanf(message, "%hd %hd", &x, &y); - if (map[sd->bl.m].flag.noteleport && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { - clif->message(fd, msg_txt(248)); // You are not authorized to warp from your current map. + if (map->list[sd->bl.m].flag.noteleport && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { + clif->message(fd, msg_txt(248)); // You are not authorized to warp from your current map. return false; } - if( pc_isdead(sd) ) - { - clif->message(fd, msg_txt(664)); + if( pc_isdead(sd) ) { + clif->message(fd, msg_txt(864)); // "You cannot use this command when dead." return false; } - if ((x || y) && iMap->getcell(sd->bl.m, x, y, CELL_CHKNOPASS)) - { //This is to prevent the pc->setpos call from printing an error. + if ((x || y) && map->getcell(sd->bl.m, x, y, CELL_CHKNOPASS)) { + //This is to prevent the pc->setpos call from printing an error. clif->message(fd, msg_txt(2)); - if (!iMap->search_freecell(NULL, sd->bl.m, &x, &y, 10, 10, 1)) + if (!map->search_freecell(NULL, sd->bl.m, &x, &y, 10, 10, 1)) x = y = 0; //Invalid cell, use random spot. } + + if( x && y && sd->bl.x == x && sd->bl.y == y ) { + clif->message(fd, msg_txt(253)); // You already are at your destination! + return false; + } pc->setpos(sd, sd->mapindex, x, y, CLR_TELEPORT); sprintf(atcmd_output, msg_txt(5), sd->bl.x, sd->bl.y); // Jumped to %d %d @@ -549,8 +550,7 @@ ACMD(jump) * Display list of online characters with * various info. *------------------------------------------*/ -ACMD(who) -{ +ACMD(who) { struct map_session_data *pl_sd = NULL; struct s_mapiterator *iter = NULL; char map_name[MAP_NAME_LENGTH_EXT] = ""; @@ -565,27 +565,25 @@ ACMD(who) */ int display_type = 1; int map_id = -1; - - nullpo_retr(-1, sd); - - if (strstr(command, "map") != NULL) { - if (sscanf(message, "%15s %23s", map_name, player_name) < 1 || (map_id = iMap->mapname2mapid(map_name)) < 0) + + if (stristr(info->command, "map") != NULL) { + if (sscanf(message, "%15s %23s", map_name, player_name) < 1 || (map_id = map->mapname2mapid(map_name)) < 0) map_id = sd->bl.m; } else { sscanf(message, "%23s", player_name); } - if (strstr(command, "2") != NULL) + if (stristr(info->command, "2") != NULL) display_type = 2; - else if (strstr(command, "3") != NULL) + else if (stristr(info->command, "3") != NULL) display_type = 3; - level = pc->get_group_level(sd); + level = pc_get_group_level(sd); StrBuf->Init(&buf); iter = mapit_getallusers(); for (pl_sd = (TBL_PC*)mapit->first(iter); mapit->exists(iter); pl_sd = (TBL_PC*)mapit->next(iter)) { - if (!((pc_has_permission(pl_sd, PC_PERM_HIDE_SESSION) || (pl_sd->sc.option & OPTION_INVISIBLE)) && pc->get_group_level(pl_sd) > level)) { // you can look only lower or same level + if (!((pc_has_permission(pl_sd, PC_PERM_HIDE_SESSION) || (pl_sd->sc.option & OPTION_INVISIBLE)) && pc_get_group_level(pl_sd) > level)) { // you can look only lower or same level if (stristr(pl_sd->status.name, player_name) == NULL // search with no case sensitive || (map_id >= 0 && pl_sd->bl.m != map_id)) continue; @@ -593,7 +591,7 @@ ACMD(who) case 2: { StrBuf->Printf(&buf, msg_txt(343), pl_sd->status.name); // "Name: %s " if (pc_get_group_id(pl_sd) > 0) // Player title, if exists - StrBuf->Printf(&buf, msg_txt(344), pc_group_id2name(pc_get_group_id(pl_sd))); // "(%s) " + StrBuf->Printf(&buf, msg_txt(344), pcg->get_name(pl_sd->group)); // "(%s) " StrBuf->Printf(&buf, msg_txt(347), pl_sd->status.base_level, pl_sd->status.job_level, pc->job_name(pl_sd->status.class_)); // "| Lv:%d/%d | Job: %s" break; @@ -603,7 +601,7 @@ ACMD(who) StrBuf->Printf(&buf, msg_txt(912), pl_sd->status.char_id, pl_sd->status.account_id); // "(CID:%d/AID:%d) " StrBuf->Printf(&buf, msg_txt(343), pl_sd->status.name); // "Name: %s " if (pc_get_group_id(pl_sd) > 0) // Player title, if exists - StrBuf->Printf(&buf, msg_txt(344), pc_group_id2name(pc_get_group_id(pl_sd))); // "(%s) " + StrBuf->Printf(&buf, msg_txt(344), pcg->get_name(pl_sd->group)); // "(%s) " StrBuf->Printf(&buf, msg_txt(348), mapindex_id2name(pl_sd->mapindex), pl_sd->bl.x, pl_sd->bl.y); // "| Location: %s %d %d" break; } @@ -613,7 +611,7 @@ ACMD(who) StrBuf->Printf(&buf, msg_txt(343), pl_sd->status.name); // "Name: %s " if (pc_get_group_id(pl_sd) > 0) // Player title, if exists - StrBuf->Printf(&buf, msg_txt(344), pc_group_id2name(pc_get_group_id(pl_sd))); // "(%s) " + StrBuf->Printf(&buf, msg_txt(344), pcg->get_name(pl_sd->group)); // "(%s) " if (p != NULL) StrBuf->Printf(&buf, msg_txt(345), p->party.name); // " | Party: '%s'" if (g != NULL) @@ -637,11 +635,11 @@ ACMD(who) StrBuf->Printf(&buf, msg_txt(30), count); // %d players found. } else { if (count == 0) - StrBuf->Printf(&buf, msg_txt(54), map[map_id].name); // No player found in map '%s'. + StrBuf->Printf(&buf, msg_txt(54), map->list[map_id].name); // No player found in map '%s'. else if (count == 1) - StrBuf->Printf(&buf, msg_txt(55), map[map_id].name); // 1 player found in map '%s'. + StrBuf->Printf(&buf, msg_txt(55), map->list[map_id].name); // 1 player found in map '%s'. else - StrBuf->Printf(&buf, msg_txt(56), count, map[map_id].name); // %d players found in map '%s'. + StrBuf->Printf(&buf, msg_txt(56), count, map->list[map_id].name); // %d players found in map '%s'. } clif->message(fd, StrBuf->Value(&buf)); StrBuf->Destroy(&buf); @@ -661,9 +659,7 @@ ACMD(whogm) char player_name[NAME_LENGTH]; struct guild *g; struct party_data *p; - - nullpo_retr(-1, sd); - + memset(atcmd_output, '\0', sizeof(atcmd_output)); memset(match_text, '\0', sizeof(match_text)); memset(player_name, '\0', sizeof(player_name)); @@ -674,12 +670,12 @@ ACMD(whogm) match_text[j] = TOLOWER(match_text[j]); count = 0; - level = pc->get_group_level(sd); + level = pc_get_group_level(sd); iter = mapit_getallusers(); for( pl_sd = (TBL_PC*)mapit->first(iter); mapit->exists(iter); pl_sd = (TBL_PC*)mapit->next(iter) ) { - pl_level = pc->get_group_level(pl_sd); + pl_level = pc_get_group_level(pl_sd); if (!pl_level) continue; @@ -737,15 +733,13 @@ ACMD(whogm) /*========================================== * *------------------------------------------*/ -ACMD(save) -{ - nullpo_retr(-1, sd); +ACMD(save) { pc->setsavepoint(sd, sd->mapindex, sd->bl.x, sd->bl.y); if (sd->status.pet_id > 0 && sd->pd) - intif_save_petdata(sd->status.account_id, &sd->pd->pet); + intif->save_petdata(sd->status.account_id, &sd->pd->pet); - chrif_save(sd,0); + chrif->save(sd,0); clif->message(fd, msg_txt(6)); // Your save point has been changed. @@ -755,19 +749,16 @@ ACMD(save) /*========================================== * *------------------------------------------*/ -ACMD(load) -{ +ACMD(load) { int16 m; - - nullpo_retr(-1, sd); - - m = iMap->mapindex2mapid(sd->status.save_point.map); - if (m >= 0 && map[m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { - clif->message(fd, msg_txt(249)); // You are not authorized to warp to your save map. + + m = map->mapindex2mapid(sd->status.save_point.map); + if (m >= 0 && map->list[m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { + clif->message(fd, msg_txt(249)); // You are not authorized to warp to your save map. return false; } - if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { - clif->message(fd, msg_txt(248)); // You are not authorized to warp from your current map. + if (sd->bl.m >= 0 && map->list[sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { + clif->message(fd, msg_txt(248)); // You are not authorized to warp from your current map. return false; } @@ -783,9 +774,7 @@ ACMD(load) ACMD(speed) { int speed; - - nullpo_retr(-1, sd); - + memset(atcmd_output, '\0', sizeof(atcmd_output)); if (!message || !*message || sscanf(message, "%d", &speed) < 1) { @@ -794,15 +783,21 @@ ACMD(speed) return false; } - if (speed < 0) { + sd->state.permanent_speed = 0; + + if (speed < 0) sd->base_status.speed = DEFAULT_WALK_SPEED; - sd->state.permanent_speed = 0; // Remove lock when set back to default speed. - } else { + else sd->base_status.speed = cap_value(speed, MIN_WALK_SPEED, MAX_WALK_SPEED); + + if( sd->base_status.speed != DEFAULT_WALK_SPEED ) { sd->state.permanent_speed = 1; // Set lock when set to non-default speed. - } + clif->message(fd, msg_txt(8)); // Speed changed. + } else + clif->message(fd, msg_txt(172)); //Speed returned to normal. + status_calc_bl(&sd->bl, SCB_SPEED); - clif->message(fd, msg_txt(8)); // Speed changed. + return true; } @@ -811,13 +806,10 @@ ACMD(speed) *------------------------------------------*/ ACMD(storage) { - nullpo_retr(-1, sd); - if (sd->npc_id || sd->state.vending || sd->state.buyingstore || sd->state.trading || sd->state.storage_flag) return false; - if (storage_storageopen(sd) == 1) - { //Already open. + if (storage->open(sd) == 1) { //Already open. clif->message(fd, msg_txt(250)); return false; } @@ -833,8 +825,6 @@ ACMD(storage) *------------------------------------------*/ ACMD(guildstorage) { - nullpo_retr(-1, sd); - if (!sd->status.guild_id) { clif->message(fd, msg_txt(252)); return false; @@ -853,7 +843,11 @@ ACMD(guildstorage) return false; } - storage_guild_storageopen(sd); + if( gstorage->open(sd) ) { + clif->message(fd, msg_txt(1201)); // Your guild's storage has already been opened by another member, try again later. + return false; + } + clif->message(fd, msg_txt(920)); // Guild storage opened. return true; } @@ -864,7 +858,6 @@ ACMD(guildstorage) ACMD(option) { int param1 = 0, param2 = 0, param3 = 0; - nullpo_retr(-1, sd); if (!message || !*message || sscanf(message, "%d %d %d", ¶m1, ¶m2, ¶m3) < 1 || param1 < 0 || param2 < 0 || param3 < 0) {// failed to match the parameters so inform the user of the options @@ -895,37 +888,35 @@ ACMD(option) /*========================================== * *------------------------------------------*/ -ACMD(hide) -{ - nullpo_retr(-1, sd); +ACMD(hide) { if (sd->sc.option & OPTION_INVISIBLE) { sd->sc.option &= ~OPTION_INVISIBLE; if (sd->disguise != -1 ) - status_set_viewdata(&sd->bl, sd->disguise); + status->set_viewdata(&sd->bl, sd->disguise); else - status_set_viewdata(&sd->bl, sd->status.class_); + status->set_viewdata(&sd->bl, sd->status.class_); clif->message(fd, msg_txt(10)); // Invisible: Off // increment the number of pvp players on the map - map[sd->bl.m].users_pvp++; + map->list[sd->bl.m].users_pvp++; - if( map[sd->bl.m].flag.pvp && !map[sd->bl.m].flag.pvp_nocalcrank ) - {// register the player for ranking calculations - sd->pvp_timer = iTimer->add_timer( iTimer->gettick() + 200, pc->calc_pvprank_timer, sd->bl.id, 0 ); + if( map->list[sd->bl.m].flag.pvp && !map->list[sd->bl.m].flag.pvp_nocalcrank ) { + // register the player for ranking calculations + sd->pvp_timer = timer->add( timer->gettick() + 200, pc->calc_pvprank_timer, sd->bl.id, 0 ); } //bugreport:2266 - iMap->foreachinmovearea(clif->insight, &sd->bl, AREA_SIZE, sd->bl.x, sd->bl.y, BL_ALL, &sd->bl); + map->foreachinmovearea(clif->insight, &sd->bl, AREA_SIZE, sd->bl.x, sd->bl.y, BL_ALL, &sd->bl); } else { sd->sc.option |= OPTION_INVISIBLE; sd->vd.class_ = INVISIBLE_CLASS; clif->message(fd, msg_txt(11)); // Invisible: On // decrement the number of pvp players on the map - map[sd->bl.m].users_pvp--; + map->list[sd->bl.m].users_pvp--; - if( map[sd->bl.m].flag.pvp && !map[sd->bl.m].flag.pvp_nocalcrank && sd->pvp_timer != INVALID_TIMER ) - {// unregister the player for ranking - iTimer->delete_timer( sd->pvp_timer, pc->calc_pvprank_timer ); + if( map->list[sd->bl.m].flag.pvp && !map->list[sd->bl.m].flag.pvp_nocalcrank && sd->pvp_timer != INVALID_TIMER ) { + // unregister the player for ranking + timer->delete( sd->pvp_timer, pc->calc_pvprank_timer ); sd->pvp_timer = INVALID_TIMER; } } @@ -937,51 +928,52 @@ ACMD(hide) /*========================================== * Changes a character's class *------------------------------------------*/ -ACMD(jobchange) -{ +ACMD(jobchange) { int job = 0, upper = 0; const char* text; - nullpo_retr(-1, sd); - if (!message || !*message || sscanf(message, "%d %d", &job, &upper) < 1) { - int i; - bool found = false; - + if (!message || !*message || sscanf(message, "%d %d", &job, &upper) < 1) { upper = 0; - - // Normal Jobs - for( i = JOB_NOVICE; i < JOB_MAX_BASIC && !found; i++ ){ - if (strncmpi(message, pc->job_name(i), 16) == 0) { - job = i; - found = true; + + if( message ) { + int i; + bool found = false; + + // Normal Jobs + for( i = JOB_NOVICE; i < JOB_MAX_BASIC && !found; i++ ) { + if (strncmpi(message, pc->job_name(i), 16) == 0) { + job = i; + found = true; + } } - } - - // High Jobs, Babys and Third - for( i = JOB_NOVICE_HIGH; i < JOB_MAX && !found; i++ ){ - if (strncmpi(message, pc->job_name(i), 16) == 0) { - job = i; - found = true; + + // High Jobs, Babies and Third + for( i = JOB_NOVICE_HIGH; i < JOB_MAX && !found; i++ ){ + if (strncmpi(message, pc->job_name(i), 16) == 0) { + job = i; + found = true; + } + } + + if (!found) { + text = atcommand_help_string(info); + if (text) + clif->messageln(fd, text); + return false; } - } - - if (!found) { - text = atcommand_help_string(info); - if (text) - clif->messageln(fd, text); - return false; } } - + /* WHY DO WE LIST THEM THEN? */ + // Deny direct transformation into dummy jobs if (job == JOB_KNIGHT2 || job == JOB_CRUSADER2 || job == JOB_WEDDING || job == JOB_XMAS || job == JOB_SUMMER || job == JOB_LORD_KNIGHT2 || job == JOB_PALADIN2 || job == JOB_BABY_KNIGHT2 || job == JOB_BABY_CRUSADER2 || job == JOB_STAR_GLADIATOR2 || (job >= JOB_RUNE_KNIGHT2 && job <= JOB_MECHANIC_T2) || (job >= JOB_BABY_RUNE2 && job <= JOB_BABY_MECHANIC2) - ) // Deny direct transformation into dummy jobs - {clif->message(fd, msg_txt(923)); //"You can not change to this job by command." - return true;} + ) { + clif->message(fd, msg_txt(923)); //"You can not change to this job by command." + return true; + } - if (pcdb_checkid(job)) - { + if (pcdb_checkid(job)) { if (pc->jobchange(sd, job, upper) == 0) clif->message(fd, msg_txt(12)); // Your job has been changed. else { @@ -1003,7 +995,6 @@ ACMD(jobchange) *------------------------------------------*/ ACMD(kill) { - nullpo_retr(-1, sd); status_kill(&sd->bl); clif->message(sd->fd, msg_txt(13)); // A pity! You've died. if (fd != sd->fd) @@ -1016,10 +1007,8 @@ ACMD(kill) *------------------------------------------*/ ACMD(alive) { - nullpo_retr(-1, sd); - if (!status_revive(&sd->bl, 100, 100)) - { - clif->message(fd, msg_txt(667)); + if (!status->revive(&sd->bl, 100, 100)) { + clif->message(fd, msg_txt(867)); // "You're not dead." return false; } clif->skill_nodamage(&sd->bl,&sd->bl,ALL_RESURRECTION,4,1); @@ -1032,24 +1021,23 @@ ACMD(alive) *------------------------------------------*/ ACMD(kami) { - unsigned long color=0; - nullpo_retr(-1, sd); + unsigned int color=0; memset(atcmd_output, '\0', sizeof(atcmd_output)); - if(*(command + 5) != 'c' && *(command + 5) != 'C') { + if(*(info->command + 4) != 'c' && *(info->command + 4) != 'C') { if (!message || !*message) { clif->message(fd, msg_txt(980)); // Please enter a message (usage: @kami <message>). return false; } sscanf(message, "%199[^\n]", atcmd_output); - if (strstr(command, "l") != NULL) - clif->broadcast(&sd->bl, atcmd_output, strlen(atcmd_output) + 1, 0, ALL_SAMEMAP); + if (stristr(info->command, "l") != NULL) + clif->broadcast(&sd->bl, atcmd_output, strlen(atcmd_output) + 1, BC_DEFAULT, ALL_SAMEMAP); else - intif_broadcast(atcmd_output, strlen(atcmd_output) + 1, (*(command + 5) == 'b' || *(command + 5) == 'B') ? 0x10 : 0); + intif->broadcast(atcmd_output, strlen(atcmd_output) + 1, (*(info->command + 4) == 'b' || *(info->command + 4) == 'B') ? BC_BLUE : BC_YELLOW); } else { - if(!message || !*message || (sscanf(message, "%lx %199[^\n]", &color, atcmd_output) < 2)) { + if(!message || !*message || (sscanf(message, "%u %199[^\n]", &color, atcmd_output) < 2)) { clif->message(fd, msg_txt(981)); // Please enter color and message (usage: @kamic <color> <message>). return false; } @@ -1058,7 +1046,7 @@ ACMD(kami) clif->message(fd, msg_txt(982)); // Invalid color. return false; } - intif_broadcast2(atcmd_output, strlen(atcmd_output) + 1, color, 0x190, 12, 0, 0); + intif->broadcast2(atcmd_output, strlen(atcmd_output) + 1, color, 0x190, 12, 0, 0); } return true; } @@ -1069,7 +1057,6 @@ ACMD(kami) ACMD(heal) { int hp = 0, sp = 0; // [Valaris] thanks to fov - nullpo_retr(-1, sd); sscanf(message, "%d %d", &hp, &sp); @@ -1086,7 +1073,7 @@ ACMD(heal) } if ( hp > 0 && sp >= 0 ) { - if(!status_heal(&sd->bl, hp, sp, 0)) + if(!status->heal(&sd->bl, hp, sp, 0)) clif->message(fd, msg_txt(157)); // HP and SP are already with the good value. else clif->message(fd, msg_txt(17)); // HP, SP recovered. @@ -1094,8 +1081,8 @@ ACMD(heal) } if ( hp < 0 && sp <= 0 ) { - status_damage(NULL, &sd->bl, -hp, -sp, 0, 0); - clif->damage(&sd->bl,&sd->bl, iTimer->gettick(), 0, 0, -hp, 0, 4, 0); + status->damage(NULL, &sd->bl, -hp, -sp, 0, 0); + clif->damage(&sd->bl,&sd->bl, 0, 0, -hp, 0, 4, 0); clif->message(fd, msg_txt(156)); // HP or/and SP modified. return true; } @@ -1103,18 +1090,18 @@ ACMD(heal) //Opposing signs. if ( hp ) { if (hp > 0) - status_heal(&sd->bl, hp, 0, 0); + status->heal(&sd->bl, hp, 0, 0); else { - status_damage(NULL, &sd->bl, -hp, 0, 0, 0); - clif->damage(&sd->bl,&sd->bl, iTimer->gettick(), 0, 0, -hp, 0, 4, 0); + status->damage(NULL, &sd->bl, -hp, 0, 0, 0); + clif->damage(&sd->bl,&sd->bl, 0, 0, -hp, 0, 4, 0); } } if ( sp ) { if (sp > 0) - status_heal(&sd->bl, 0, sp, 0); + status->heal(&sd->bl, 0, sp, 0); else - status_damage(NULL, &sd->bl, 0, -sp, 0, 0); + status->damage(NULL, &sd->bl, 0, -sp, 0, 0); } clif->message(fd, msg_txt(156)); // HP or/and SP modified. @@ -1123,48 +1110,84 @@ ACMD(heal) /*========================================== * @item command (usage: @item <name/id_of_item> <quantity>) (modified by [Yor] for pet_egg) + * @itembound command (usage: @itembound <name/id_of_item> <quantity> <bound type>) (revised by [Mhalicot]) *------------------------------------------*/ ACMD(item) { char item_name[100]; - int number = 0, item_id, flag = 0; + int number = 0, item_id, flag = 0, bound = 0; struct item item_tmp; struct item_data *item_data; int get_count, i; - nullpo_retr(-1, sd); memset(item_name, '\0', sizeof(item_name)); - - if (!message || !*message || ( - sscanf(message, "\"%99[^\"]\" %d", item_name, &number) < 1 && - sscanf(message, "%99s %d", item_name, &number) < 1 - )) { - clif->message(fd, msg_txt(983)); // Please enter an item name or ID (usage: @item <item name/ID> <quantity>). + + if (!strcmpi(info->command,"itembound") && (!message || !*message || ( + sscanf(message, "\"%99[^\"]\" %d %d", item_name, &number, &bound) < 2 && + sscanf(message, "%99s %d %d", item_name, &number, &bound) < 2 + ))) { + clif->message(fd, msg_txt(295)); // Please enter an item name or ID (usage: @itembound <item name/ID> <quantity> <bound_type>). + return false; + } else if (!message || !*message || ( + sscanf(message, "\"%99[^\"]\" %d", item_name, &number) < 1 && + sscanf(message, "%99s %d", item_name, &number) < 1 )) + { + clif->message(fd, msg_txt(983)); // Please enter an item name or ID (usage: @item <item name/ID> <quantity>). return false; } if (number <= 0) number = 1; - if ((item_data = itemdb_searchname(item_name)) == NULL && - (item_data = itemdb_exists(atoi(item_name))) == NULL) + if ((item_data = itemdb->search_name(item_name)) == NULL && + (item_data = itemdb->exists(atoi(item_name))) == NULL) { clif->message(fd, msg_txt(19)); // Invalid item ID or name. return false; } + if(!strcmpi(info->command,"itembound") ) { + if( !(bound >= IBT_MIN && bound <= IBT_MAX) ) { + clif->message(fd, msg_txt(298)); // Invalid bound type + return false; + } + switch( (enum e_item_bound_type)bound ) { + case IBT_CHARACTER: + case IBT_ACCOUNT: + break; /* no restrictions */ + case IBT_PARTY: + if( !sd->status.party_id ) { + clif->message(fd, msg_txt(1498)); //You can't add a party bound item to a character without party! + return false; + } + break; + case IBT_GUILD: + if( !sd->status.guild_id ) { + clif->message(fd, msg_txt(1499)); //You can't add a guild bound item to a character without guild! + return false; + } + break; + } + } + item_id = item_data->nameid; get_count = number; //Check if it's stackable. - if (!itemdb_isstackable2(item_data)) - get_count = 1; + if (!itemdb->isstackable2(item_data)) { + if( bound && (item_data->type == IT_PETEGG || item_data->type == IT_PETARMOR) ) { + clif->message(fd, msg_txt(498)); // Cannot create bounded pet eggs or pet armors. + return false; + } + get_count = 1; + } for (i = 0; i < number; i += get_count) { // if not pet egg - if (!pet_create_egg(sd, item_id)) { + if (!pet->create_egg(sd, item_id)) { memset(&item_tmp, 0, sizeof(item_tmp)); item_tmp.nameid = item_id; item_tmp.identify = 1; + item_tmp.bound = (unsigned char)bound; if ((flag = pc->additem(sd, &item_tmp, get_count, LOG_TYPE_COMMAND))) clif->additem(sd, 0, 0, flag); @@ -1177,22 +1200,27 @@ ACMD(item) } /*========================================== - * + * @item2 and @itembound2 command (revised by [Mhalicot]) *------------------------------------------*/ ACMD(item2) { struct item item_tmp; struct item_data *item_data; char item_name[100]; - int item_id, number = 0; + int item_id, number = 0, bound = 0; int identify = 0, refine = 0, attr = 0; int c1 = 0, c2 = 0, c3 = 0, c4 = 0; - nullpo_retr(-1, sd); memset(item_name, '\0', sizeof(item_name)); - if (!message || !*message || ( - sscanf(message, "\"%99[^\"]\" %d %d %d %d %d %d %d %d", item_name, &number, &identify, &refine, &attr, &c1, &c2, &c3, &c4) < 9 && + if (!strcmpi(info->command,"itembound2") && (!message || !*message || ( + sscanf(message, "\"%99[^\"]\" %d %d %d %d %d %d %d %d %d", item_name, &number, &identify, &refine, &attr, &c1, &c2, &c3, &c4, &bound) < 10 && + sscanf(message, "%99s %d %d %d %d %d %d %d %d %d", item_name, &number, &identify, &refine, &attr, &c1, &c2, &c3, &c4, &bound) < 10 ))) { + clif->message(fd, msg_txt(296)); // Please enter all parameters (usage: @itembound2 <item name/ID> <quantity> + clif->message(fd, msg_txt(297)); // <identify_flag> <refine> <attribute> <card1> <card2> <card3> <card4> <bound_type>). + return false; + } else if ( !message || !*message || ( + sscanf(message, "\"%99[^\"]\" %d %d %d %d %d %d %d %d", item_name, &number, &identify, &refine, &attr, &c1, &c2, &c3, &c4) < 9 && sscanf(message, "%99s %d %d %d %d %d %d %d %d", item_name, &number, &identify, &refine, &attr, &c1, &c2, &c3, &c4) < 9 )) { clif->message(fd, msg_txt(984)); // Please enter all parameters (usage: @item2 <item name/ID> <quantity> @@ -1202,10 +1230,15 @@ ACMD(item2) if (number <= 0) number = 1; - + + if( !strcmpi(info->command,"itembound2") && !(bound >= IBT_MIN && bound <= IBT_MAX) ) { + clif->message(fd, msg_txt(298)); // Invalid bound type + return false; + } + item_id = 0; - if ((item_data = itemdb_searchname(item_name)) != NULL || - (item_data = itemdb_exists(atoi(item_name))) != NULL) + if ((item_data = itemdb->search_name(item_name)) != NULL || + (item_data = itemdb->exists(atoi(item_name))) != NULL) item_id = item_data->nameid; if (item_id > 500) { @@ -1213,9 +1246,14 @@ ACMD(item2) int loop, get_count, i; loop = 1; get_count = number; - if (item_data->type == IT_WEAPON || item_data->type == IT_ARMOR || - item_data->type == IT_PETEGG || item_data->type == IT_PETARMOR) { - loop = number; + if( !strcmpi(info->command,"itembound2") ) + bound = 1; + if( !itemdb->isstackable2(item_data) ) { + if( bound && (item_data->type == IT_PETEGG || item_data->type == IT_PETARMOR) ) { + clif->message(fd, msg_txt(498)); // Cannot create bounded pet eggs or pet armors. + return false; + } + loop = number; get_count = 1; if (item_data->type == IT_PETEGG) { identify = 1; @@ -1235,10 +1273,12 @@ ACMD(item2) item_tmp.identify = identify; item_tmp.refine = refine; item_tmp.attribute = attr; + item_tmp.bound = (unsigned char)bound; item_tmp.card[0] = c1; item_tmp.card[1] = c2; item_tmp.card[2] = c3; item_tmp.card[3] = c4; + if ((flag = pc->additem(sd, &item_tmp, get_count, LOG_TYPE_COMMAND))) clif->additem(sd, 0, 0, flag); } @@ -1259,7 +1299,6 @@ ACMD(item2) ACMD(itemreset) { int i; - nullpo_retr(-1, sd); for (i = 0; i < MAX_INVENTORY; i++) { if (sd->status.inventory[i].amount && sd->status.inventory[i].equip == 0) { @@ -1277,7 +1316,7 @@ ACMD(itemreset) ACMD(baselevelup) { int level=0, i=0, status_point=0; - nullpo_retr(-1, sd); + level = atoi(message); if (!message || !*message || !level) { @@ -1290,13 +1329,14 @@ ACMD(baselevelup) clif->message(fd, msg_txt(47)); // Base level can't go any higher. return false; } // End Addition - if ((unsigned int)level > pc->maxbaselv(sd) || (unsigned int)level > pc->maxbaselv(sd) - sd->status.base_level) // fix positiv overflow + if ((unsigned int)level > pc->maxbaselv(sd) || (unsigned int)level > pc->maxbaselv(sd) - sd->status.base_level) // fix positive overflow level = pc->maxbaselv(sd) - sd->status.base_level; for (i = 0; i < level; i++) status_point += pc->gets_status_point(sd->status.base_level + i); sd->status.status_point += status_point; sd->status.base_level += (unsigned int)level; + status_calc_pc(sd, SCO_FORCE); status_percent_heal(&sd->bl, 100, 100); clif->misceffect(&sd->bl, 0); clif->message(fd, msg_txt(21)); // Base level raised. @@ -1318,13 +1358,13 @@ ACMD(baselevelup) sd->status.status_point -= status_point; sd->status.base_level -= (unsigned int)level; clif->message(fd, msg_txt(22)); // Base level lowered. + status_calc_pc(sd, SCO_FORCE); } sd->status.base_exp = 0; clif->updatestatus(sd, SP_STATUSPOINT); clif->updatestatus(sd, SP_BASELEVEL); clif->updatestatus(sd, SP_BASEEXP); clif->updatestatus(sd, SP_NEXTBASEEXP); - status_calc_pc(sd, 0); pc->baselevelchanged(sd); if(sd->status.party_id) party->send_levelup(sd); @@ -1337,7 +1377,6 @@ ACMD(baselevelup) ACMD(joblevelup) { int level=0; - nullpo_retr(-1, sd); level = atoi(message); @@ -1350,7 +1389,7 @@ ACMD(joblevelup) clif->message(fd, msg_txt(23)); // Job level can't go any higher. return false; } - if ((unsigned int)level > pc->maxjoblv(sd) || (unsigned int)level > pc->maxjoblv(sd) - sd->status.job_level) // fix positiv overflow + if ((unsigned int)level > pc->maxjoblv(sd) || (unsigned int)level > pc->maxjoblv(sd) - sd->status.job_level) // fix positive overflow level = pc->maxjoblv(sd) - sd->status.job_level; sd->status.job_level += (unsigned int)level; sd->status.skill_point += level; @@ -1362,11 +1401,11 @@ ACMD(joblevelup) return false; } level *=-1; - if ((unsigned int)level >= sd->status.job_level) // fix negativ overflow + if ((unsigned int)level >= sd->status.job_level) // fix negative overflow level = sd->status.job_level-1; sd->status.job_level -= (unsigned int)level; if (sd->status.skill_point < level) - pc->resetskill(sd,0); //Reset skills since we need to substract more points. + pc->resetskill(sd,0); //Reset skills since we need to subtract more points. if (sd->status.skill_point < level) sd->status.skill_point = 0; else @@ -1378,7 +1417,7 @@ ACMD(joblevelup) clif->updatestatus(sd, SP_JOBEXP); clif->updatestatus(sd, SP_NEXTJOBEXP); clif->updatestatus(sd, SP_SKILLPOINT); - status_calc_pc(sd, 0); + status_calc_pc(sd, SCO_FORCE); return true; } @@ -1390,30 +1429,28 @@ ACMD(help) { const char *command_name = NULL; char *default_command = "help"; AtCommandInfo *tinfo = NULL; - - nullpo_retr(-1, sd); - + if (!message || !*message) { command_name = default_command; // If no command_name specified, display help for @help. } else { if (*message == atcommand->at_symbol || *message == atcommand->char_symbol) ++message; - command_name = atcommand_checkalias(message); + command_name = atcommand->check_alias(message); } if (!atcommand->can_use2(sd, command_name, COMMAND_ATCOMMAND)) { sprintf(atcmd_output, msg_txt(153), message); // "%s is Unknown Command" clif->message(fd, atcmd_output); - atcommand_get_suggestions(sd, command_name, true); + atcommand->get_suggestions(sd, command_name, true); return false; } - tinfo = get_atcommandinfo_byname(atcommand_checkalias(command_name)); + tinfo = atcommand->get_info_byname(atcommand->check_alias(command_name)); if ( !tinfo || tinfo->help == NULL ) { sprintf(atcmd_output, msg_txt(988), atcommand->at_symbol, command_name); // There is no help for %c%s. clif->message(fd, atcmd_output); - atcommand_get_suggestions(sd, command_name, true); + atcommand->get_suggestions(sd, command_name, true); return false; } @@ -1429,7 +1466,7 @@ ACMD(help) { StrBuf->Init(&buf); StrBuf->AppendStr(&buf, msg_txt(990)); // Available aliases: - command_info = get_atcommandinfo_byname(command_name); + command_info = atcommand->get_info_byname(command_name); iter = db_iterator(atcommand->alias_db); for (alias_info = dbi_first(iter); dbi_exists(iter); alias_info = dbi_next(iter)) { if (alias_info->command == command_info) { @@ -1450,13 +1487,13 @@ ACMD(help) { // helper function, used in foreach calls to stop auto-attack timers // parameter: '0' - everyone, 'id' - only those attacking someone with that id -static int atcommand_stopattack(struct block_list *bl,va_list ap) +int atcommand_stopattack(struct block_list *bl,va_list ap) { - struct unit_data *ud = unit_bl2ud(bl); + struct unit_data *ud = unit->bl2ud(bl); int id = va_arg(ap, int); if (ud && ud->attacktimer != INVALID_TIMER && (!id || id == ud->target)) { - unit_stop_attack(bl); + unit->stop_attack(bl); return 1; } return 0; @@ -1464,35 +1501,33 @@ static int atcommand_stopattack(struct block_list *bl,va_list ap) /*========================================== * *------------------------------------------*/ -static int atcommand_pvpoff_sub(struct block_list *bl,va_list ap) +int atcommand_pvpoff_sub(struct block_list *bl,va_list ap) { TBL_PC* sd = (TBL_PC*)bl; clif->pvpset(sd, 0, 0, 2); if (sd->pvp_timer != INVALID_TIMER) { - iTimer->delete_timer(sd->pvp_timer, pc->calc_pvprank_timer); + timer->delete(sd->pvp_timer, pc->calc_pvprank_timer); sd->pvp_timer = INVALID_TIMER; } return 0; } -ACMD(pvpoff) -{ - nullpo_retr(-1, sd); +ACMD(pvpoff) { - if (!map[sd->bl.m].flag.pvp) { + if (!map->list[sd->bl.m].flag.pvp) { clif->message(fd, msg_txt(160)); // PvP is already Off. return false; } - iMap->zone_change2(sd->bl.m,map[sd->bl.m].prev_zone); - map[sd->bl.m].flag.pvp = 0; + map->zone_change2(sd->bl.m,map->list[sd->bl.m].prev_zone); + map->list[sd->bl.m].flag.pvp = 0; if (!battle_config.pk_mode) { clif->map_property_mapall(sd->bl.m, MAPPROPERTY_NOTHING); clif->maptypeproperty2(&sd->bl,ALL_SAMEMAP); } - iMap->foreachinmap(atcommand_pvpoff_sub,sd->bl.m, BL_PC); - iMap->foreachinmap(atcommand_stopattack,sd->bl.m, BL_CHAR, 0); + map->foreachinmap(atcommand->pvpoff_sub,sd->bl.m, BL_PC); + map->foreachinmap(atcommand->stopattack,sd->bl.m, BL_CHAR, 0); clif->message(fd, msg_txt(31)); // PvP: Off. return true; } @@ -1500,11 +1535,11 @@ ACMD(pvpoff) /*========================================== * *------------------------------------------*/ -static int atcommand_pvpon_sub(struct block_list *bl,va_list ap) +int atcommand_pvpon_sub(struct block_list *bl,va_list ap) { TBL_PC* sd = (TBL_PC*)bl; if (sd->pvp_timer == INVALID_TIMER) { - sd->pvp_timer = iTimer->add_timer(iTimer->gettick() + 200, pc->calc_pvprank_timer, sd->bl.id, 0); + sd->pvp_timer = timer->add(timer->gettick() + 200, pc->calc_pvprank_timer, sd->bl.id, 0); sd->pvp_rank = 0; sd->pvp_lastusers = 0; sd->pvp_point = 5; @@ -1514,22 +1549,20 @@ static int atcommand_pvpon_sub(struct block_list *bl,va_list ap) return 0; } -ACMD(pvpon) -{ - nullpo_retr(-1, sd); +ACMD(pvpon) { - if (map[sd->bl.m].flag.pvp) { + if (map->list[sd->bl.m].flag.pvp) { clif->message(fd, msg_txt(161)); // PvP is already On. return false; } - iMap->zone_change2(sd->bl.m,strdb_get(zone_db, MAP_ZONE_PVP_NAME)); - map[sd->bl.m].flag.pvp = 1; + map->zone_change2(sd->bl.m,strdb_get(map->zone_db, MAP_ZONE_PVP_NAME)); + map->list[sd->bl.m].flag.pvp = 1; if (!battle_config.pk_mode) {// display pvp circle and rank clif->map_property_mapall(sd->bl.m, MAPPROPERTY_FREEPVPZONE); clif->maptypeproperty2(&sd->bl,ALL_SAMEMAP); - iMap->foreachinmap(atcommand_pvpon_sub,sd->bl.m, BL_PC); + map->foreachinmap(atcommand->pvpon_sub,sd->bl.m, BL_PC); } clif->message(fd, msg_txt(32)); // PvP: On. @@ -1540,20 +1573,18 @@ ACMD(pvpon) /*========================================== * *------------------------------------------*/ -ACMD(gvgoff) -{ - nullpo_retr(-1, sd); +ACMD(gvgoff) { - if (!map[sd->bl.m].flag.gvg) { + if (!map->list[sd->bl.m].flag.gvg) { clif->message(fd, msg_txt(162)); // GvG is already Off. return false; } - iMap->zone_change2(sd->bl.m,map[sd->bl.m].prev_zone); - map[sd->bl.m].flag.gvg = 0; + map->zone_change2(sd->bl.m,map->list[sd->bl.m].prev_zone); + map->list[sd->bl.m].flag.gvg = 0; clif->map_property_mapall(sd->bl.m, MAPPROPERTY_NOTHING); clif->maptypeproperty2(&sd->bl,ALL_SAMEMAP); - iMap->foreachinmap(atcommand_stopattack,sd->bl.m, BL_CHAR, 0); + map->foreachinmap(atcommand->stopattack,sd->bl.m, BL_CHAR, 0); clif->message(fd, msg_txt(33)); // GvG: Off. return true; @@ -1562,17 +1593,15 @@ ACMD(gvgoff) /*========================================== * *------------------------------------------*/ -ACMD(gvgon) -{ - nullpo_retr(-1, sd); +ACMD(gvgon) { - if (map[sd->bl.m].flag.gvg) { + if (map->list[sd->bl.m].flag.gvg) { clif->message(fd, msg_txt(163)); // GvG is already On. return false; } - iMap->zone_change2(sd->bl.m,strdb_get(zone_db, MAP_ZONE_GVG_NAME)); - map[sd->bl.m].flag.gvg = 1; + map->zone_change2(sd->bl.m,strdb_get(map->zone_db, MAP_ZONE_GVG_NAME)); + map->list[sd->bl.m].flag.gvg = 1; clif->map_property_mapall(sd->bl.m, MAPPROPERTY_AGITZONE); clif->maptypeproperty2(&sd->bl,ALL_SAMEMAP); clif->message(fd, msg_txt(34)); // GvG: On. @@ -1586,7 +1615,6 @@ ACMD(gvgon) ACMD(model) { int hair_style = 0, hair_color = 0, cloth_color = 0; - nullpo_retr(-1, sd); memset(atcmd_output, '\0', sizeof(atcmd_output)); @@ -1603,7 +1631,7 @@ ACMD(model) pc->changelook(sd, LOOK_HAIR, hair_style); pc->changelook(sd, LOOK_HAIR_COLOR, hair_color); pc->changelook(sd, LOOK_CLOTHES_COLOR, cloth_color); - clif->message(fd, msg_txt(36)); // Appearence changed. + clif->message(fd, msg_txt(36)); // Appearance changed. } else { clif->message(fd, msg_txt(37)); // An invalid number was specified. return false; @@ -1618,7 +1646,6 @@ ACMD(model) ACMD(dye) { int cloth_color = 0; - nullpo_retr(-1, sd); memset(atcmd_output, '\0', sizeof(atcmd_output)); @@ -1630,7 +1657,7 @@ ACMD(dye) if (cloth_color >= MIN_CLOTH_COLOR && cloth_color <= MAX_CLOTH_COLOR) { pc->changelook(sd, LOOK_CLOTHES_COLOR, cloth_color); - clif->message(fd, msg_txt(36)); // Appearence changed. + clif->message(fd, msg_txt(36)); // Appearance changed. } else { clif->message(fd, msg_txt(37)); // An invalid number was specified. return false; @@ -1645,7 +1672,6 @@ ACMD(dye) ACMD(hair_style) { int hair_style = 0; - nullpo_retr(-1, sd); memset(atcmd_output, '\0', sizeof(atcmd_output)); @@ -1657,7 +1683,7 @@ ACMD(hair_style) if (hair_style >= MIN_HAIR_STYLE && hair_style <= MAX_HAIR_STYLE) { pc->changelook(sd, LOOK_HAIR, hair_style); - clif->message(fd, msg_txt(36)); // Appearence changed. + clif->message(fd, msg_txt(36)); // Appearance changed. } else { clif->message(fd, msg_txt(37)); // An invalid number was specified. return false; @@ -1672,7 +1698,6 @@ ACMD(hair_style) ACMD(hair_color) { int hair_color = 0; - nullpo_retr(-1, sd); memset(atcmd_output, '\0', sizeof(atcmd_output)); @@ -1684,7 +1709,7 @@ ACMD(hair_color) if (hair_color >= MIN_HAIR_COLOR && hair_color <= MAX_HAIR_COLOR) { pc->changelook(sd, LOOK_HAIR_COLOR, hair_color); - clif->message(fd, msg_txt(36)); // Appearence changed. + clif->message(fd, msg_txt(36)); // Appearance changed. } else { clif->message(fd, msg_txt(37)); // An invalid number was specified. return false; @@ -1696,69 +1721,63 @@ ACMD(hair_color) /*========================================== * @go [city_number or city_name] - Updated by Harbin *------------------------------------------*/ -ACMD(go) -{ +ACMD(go) { int i; - int town; + int town = INT_MAX; // Initialized to INT_MAX instead of -1 to avoid conflicts with those who map [-3:-1] to @memo locations. char map_name[MAP_NAME_LENGTH]; - int16 m; const struct { char map[MAP_NAME_LENGTH]; int x, y; + int min_match; ///< Minimum string length to match } data[] = { - { MAP_PRONTERA, 156, 191 }, // 0=Prontera - { MAP_MORROC, 156, 93 }, // 1=Morroc - { MAP_GEFFEN, 119, 59 }, // 2=Geffen - { MAP_PAYON, 162, 233 }, // 3=Payon - { MAP_ALBERTA, 192, 147 }, // 4=Alberta + { MAP_PRONTERA, 156, 191, 3 }, // 0 = Prontera + { MAP_MORROC, 156, 93, 4 }, // 1 = Morroc + { MAP_GEFFEN, 119, 59, 3 }, // 2 = Geffen + { MAP_PAYON, 162, 233, 3 }, // 3 = Payon + { MAP_ALBERTA, 192, 147, 3 }, // 4 = Alberta #ifdef RENEWAL - { MAP_IZLUDE, 128, 146 }, // 5=Izlude (Renewal) + { MAP_IZLUDE, 128, 146, 3 }, // 5 = Izlude (Renewal) #else - { MAP_IZLUDE, 128, 114 }, // 5=Izlude + { MAP_IZLUDE, 128, 114, 3 }, // 5 = Izlude #endif - { MAP_ALDEBARAN, 140, 131 }, // 6=Al de Baran - { MAP_LUTIE, 147, 134 }, // 7=Lutie - { MAP_COMODO, 209, 143 }, // 8=Comodo - { MAP_YUNO, 157, 51 }, // 9=Yuno - { MAP_AMATSU, 198, 84 }, // 10=Amatsu - { MAP_GONRYUN, 160, 120 }, // 11=Gonryun - { MAP_UMBALA, 89, 157 }, // 12=Umbala - { MAP_NIFLHEIM, 21, 153 }, // 13=Niflheim - { MAP_LOUYANG, 217, 40 }, // 14=Louyang - { MAP_NOVICE, 53, 111 }, // 15=Training Grounds - { MAP_JAIL, 23, 61 }, // 16=Prison - { MAP_JAWAII, 249, 127 }, // 17=Jawaii - { MAP_AYOTHAYA, 151, 117 }, // 18=Ayothaya - { MAP_EINBROCH, 64, 200 }, // 19=Einbroch - { MAP_LIGHTHALZEN, 158, 92 }, // 20=Lighthalzen - { MAP_EINBECH, 70, 95 }, // 21=Einbech - { MAP_HUGEL, 96, 145 }, // 22=Hugel - { MAP_RACHEL, 130, 110 }, // 23=Rachel - { MAP_VEINS, 216, 123 }, // 24=Veins - { MAP_MOSCOVIA, 223, 184 }, // 25=Moscovia - { MAP_MIDCAMP, 180, 240 }, // 26=Midgard Camp - { MAP_MANUK, 282, 138 }, // 27=Manuk - { MAP_SPLENDIDE, 197, 176 }, // 28=Splendide - { MAP_BRASILIS, 182, 239 }, // 29=Brasilis - { MAP_DICASTES, 198, 187 }, // 30=El Dicastes - { MAP_MORA, 44, 151 }, // 31=Mora - { MAP_DEWATA, 200, 180 }, // 32=Dewata - { MAP_MALANGDO, 140, 114 }, // 33=Malangdo Island - { MAP_MALAYA, 242, 211 }, // 34=Malaya Port - { MAP_ECLAGE, 110, 39 }, // 35=Eclage + { MAP_ALDEBARAN, 140, 131, 3 }, // 6 = Aldebaran + { MAP_LUTIE, 147, 134, 3 }, // 7 = Lutie + { MAP_COMODO, 209, 143, 3 }, // 8 = Comodo + { MAP_YUNO, 157, 51, 3 }, // 9 = Juno + { MAP_AMATSU, 198, 84, 3 }, // 10 = Amatsu + { MAP_GONRYUN, 160, 120, 3 }, // 11 = Kunlun + { MAP_UMBALA, 89, 157, 3 }, // 12 = Umbala + { MAP_NIFLHEIM, 21, 153, 3 }, // 13 = Niflheim + { MAP_LOUYANG, 217, 40, 3 }, // 14 = Luoyang + { MAP_NOVICE, 53, 111, 3 }, // 15 = Training Grounds + { MAP_JAIL, 23, 61, 3 }, // 16 = Prison + { MAP_JAWAII, 249, 127, 3 }, // 17 = Jawaii + { MAP_AYOTHAYA, 151, 117, 3 }, // 18 = Ayothaya + { MAP_EINBROCH, 64, 200, 5 }, // 19 = Einbroch + { MAP_LIGHTHALZEN, 158, 92, 3 }, // 20 = Lighthalzen + { MAP_EINBECH, 70, 95, 5 }, // 21 = Einbech + { MAP_HUGEL, 96, 145, 3 }, // 22 = Hugel + { MAP_RACHEL, 130, 110, 3 }, // 23 = Rachel + { MAP_VEINS, 216, 123, 3 }, // 24 = Veins + { MAP_MOSCOVIA, 223, 184, 3 }, // 25 = Moscovia + { MAP_MIDCAMP, 180, 240, 3 }, // 26 = Midgard Camp + { MAP_MANUK, 282, 138, 3 }, // 27 = Manuk + { MAP_SPLENDIDE, 197, 176, 3 }, // 28 = Splendide + { MAP_BRASILIS, 182, 239, 3 }, // 29 = Brasilis + { MAP_DICASTES, 198, 187, 3 }, // 30 = El Dicastes + { MAP_MORA, 44, 151, 4 }, // 31 = Mora + { MAP_DEWATA, 200, 180, 3 }, // 32 = Dewata + { MAP_MALANGDO, 140, 114, 5 }, // 33 = Malangdo Island + { MAP_MALAYA, 242, 211, 5 }, // 34 = Malaya Port + { MAP_ECLAGE, 110, 39, 3 }, // 35 = Eclage }; - - nullpo_retr(-1, sd); - + memset(map_name, '\0', sizeof(map_name)); memset(atcmd_output, '\0', sizeof(atcmd_output)); - // get the number - town = atoi(message); - - if (!message || !*message || sscanf(message, "%11s", map_name) < 1 || town < 0 || town >= ARRAYLENGTH(data)) - {// no value matched so send the list of locations + if (!message || !*message || sscanf(message, "%11s", map_name) < 1) { + // no value matched so send the list of locations const char* text; // attempt to find the text help string @@ -1772,114 +1791,64 @@ ACMD(go) return false; } - - // get possible name of the city - map_name[MAP_NAME_LENGTH-1] = '\0'; - for (i = 0; map_name[i]; i++) - map_name[i] = TOLOWER(map_name[i]); - // try to identify the map name - if (strncmp(map_name, "prontera", 3) == 0) { - town = 0; - } else if (strncmp(map_name, "morocc", 4) == 0 || - strncmp(map_name, "morroc", 4) == 0) { - town = 1; - } else if (strncmp(map_name, "geffen", 3) == 0) { - town = 2; - } else if (strncmp(map_name, "payon", 3) == 0) { - town = 3; - } else if (strncmp(map_name, "alberta", 3) == 0) { - town = 4; - } else if (strncmp(map_name, "izlude", 3) == 0) { - town = 5; - } else if (strncmp(map_name, "aldebaran", 3) == 0) { - town = 6; - } else if (strncmp(map_name, "lutie", 3) == 0 || - strcmp(map_name, "christmas") == 0 || - strncmp(map_name, "xmas", 3) == 0 || - strncmp(map_name, "x-mas", 3) == 0) { - town = 7; - } else if (strncmp(map_name, "comodo", 3) == 0) { - town = 8; - } else if (strncmp(map_name, "juno", 3) == 0 || - strncmp(map_name, "yuno", 3) == 0) { - town = 9; - } else if (strncmp(map_name, "amatsu", 3) == 0) { - town = 10; - } else if (strncmp(map_name, "kunlun", 3) == 0 || - strncmp(map_name, "gonryun", 3) == 0) { - town = 11; - } else if (strncmp(map_name, "umbala", 3) == 0) { - town = 12; - } else if (strncmp(map_name, "niflheim", 3) == 0) { - town = 13; - } else if (strncmp(map_name, "louyang", 3) == 0) { - town = 14; - } else if (strncmp(map_name, "new_1-1", 3) == 0 || - strncmp(map_name, "startpoint", 3) == 0 || - strncmp(map_name, "beginning", 3) == 0) { - town = 15; - } else if (strncmp(map_name, "sec_pri", 3) == 0 || - strncmp(map_name, "prison", 3) == 0 || - strncmp(map_name, "jail", 3) == 0) { - town = 16; - } else if (strncmp(map_name, "jawaii", 3) == 0) { - town = 17; - } else if (strncmp(map_name, "ayothaya", 3) == 0) { - town = 18; - } else if (strncmp(map_name, "einbroch", 5) == 0) { - town = 19; - } else if (strncmp(map_name, "lighthalzen", 3) == 0) { - town = 20; - } else if (strncmp(map_name, "einbech", 5) == 0) { - town = 21; - } else if (strncmp(map_name, "hugel", 3) == 0) { - town = 22; - } else if (strncmp(map_name, "rachel", 3) == 0) { - town = 23; - } else if (strncmp(map_name, "veins", 3) == 0) { - town = 24; - } else if (strncmp(map_name, "moscovia", 3) == 0) { - town = 25; - } else if (strncmp(map_name, "mid_camp", 3) == 0) { - town = 26; - } else if (strncmp(map_name, "manuk", 3) == 0) { - town = 27; - } else if (strncmp(map_name, "splendide", 3) == 0) { - town = 28; - } else if (strncmp(map_name, "brasilis", 3) == 0) { - town = 29; - } else if (strncmp(map_name, "dicastes01", 3) == 0) { - town = 30; - } else if (strcmp(map_name, "mora") == 0) { - town = 31; - } else if (strncmp(map_name, "dewata", 3) == 0) { - town = 32; - } else if (strncmp(map_name, "malangdo", 5) == 0) { - town = 33; - } else if (strncmp(map_name, "malaya", 5) == 0) { - town = 34; - } else if (strncmp(map_name, "eclage", 3) == 0) { - town = 35; - } - - if (town >= 0 && town < ARRAYLENGTH(data)) - { - m = iMap->mapname2mapid(data[town].map); - if (m >= 0 && map[m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { + + // Numeric entry + if (ISDIGIT(*message) || (message[0] == '-' && ISDIGIT(message[1]))) { + town = atoi(message); + } + + if (town < 0 || town >= ARRAYLENGTH(data)) { + map_name[MAP_NAME_LENGTH-1] = '\0'; + + // Match maps on the list + for (i = 0; i < ARRAYLENGTH(data); i++) { + if (strncmpi(map_name, data[i].map, data[i].min_match) == 0) { + town = i; + break; + } + } + } + + if (town < 0 || town >= ARRAYLENGTH(data)) { + // Alternate spellings + if (strncmpi(map_name, "morroc", 4) == 0) { // Correct town name for 'morocc' + town = 1; + } else if (strncmpi(map_name, "lutie", 3) == 0) { // Correct town name for 'xmas' + town = 7; + } else if (strncmpi(map_name, "juno", 3) == 0) { // Correct town name for 'yuno' + town = 9; + } else if (strncmpi(map_name, "kunlun", 3) == 0) { // Original town name for 'gonryun' + town = 11; + } else if (strncmpi(map_name, "luoyang", 3) == 0) { // Original town name for 'louyang' + town = 14; + } else if (strncmpi(map_name, "startpoint", 3) == 0 // Easy to remember alternatives to 'new_1-1' + || strncmpi(map_name, "beginning", 3) == 0) { + town = 15; + } else if (strncmpi(map_name, "prison", 3) == 0 // Easy to remember alternatives to 'sec_pri' + || strncmpi(map_name, "jail", 3) == 0) { + town = 16; + } else if (strncmpi(map_name, "rael", 3) == 0) { // Original town name for 'rachel' + town = 23; + } + } + + if (town >= 0 && town < ARRAYLENGTH(data)) { + int16 m = map->mapname2mapid(data[town].map); + if (m >= 0 && map->list[m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { clif->message(fd, msg_txt(247)); return false; } - if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { + if (sd->bl.m >= 0 && map->list[sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { clif->message(fd, msg_txt(248)); return false; } - if (pc->setpos(sd, mapindex_name2id(data[town].map), data[town].x, data[town].y, CLR_TELEPORT) == 0) { + if (pc->setpos(sd, mapindex->name2id(data[town].map), data[town].x, data[town].y, CLR_TELEPORT) == 0) { clif->message(fd, msg_txt(0)); // Warped. } else { clif->message(fd, msg_txt(1)); // Map not found. return false; } - } else { // if you arrive here, you have an error in town variable when reading of names + } else { clif->message(fd, msg_txt(38)); // Invalid location number or name. return false; } @@ -1901,14 +1870,13 @@ ACMD(monster) int i, k, range; short mx, my; unsigned int size; - nullpo_retr(-1, sd); memset(name, '\0', sizeof(name)); memset(monster, '\0', sizeof(monster)); memset(atcmd_output, '\0', sizeof(atcmd_output)); if (!message || !*message) { - clif->message(fd, msg_txt(80)); // Give the display name or monster name/id please. + clif->message(fd, msg_txt(80)); // Please specify a display name or monster name/id. return false; } if (sscanf(message, "\"%23[^\"]\" %23s %d", name, monster, &number) > 1 || @@ -1928,19 +1896,14 @@ ACMD(monster) return false; } - if ((mob_id = mobdb_searchname(monster)) == 0) // check name first (to avoid possible name begining by a number) - mob_id = mobdb_checkid(atoi(monster)); + if ((mob_id = mob->db_searchname(monster)) == 0) // check name first (to avoid possible name beginning by a number) + mob_id = mob->db_checkid(atoi(monster)); if (mob_id == 0) { clif->message(fd, msg_txt(40)); // Invalid monster ID or name. return false; } - - if (mob_id == MOBID_EMPERIUM) { - clif->message(fd, msg_txt(83)); // Monster 'Emperium' cannot be spawned. - return false; - } - + if (number <= 0) number = 1; @@ -1951,12 +1914,12 @@ ACMD(monster) if (battle_config.atc_spawn_quantity_limit && number > battle_config.atc_spawn_quantity_limit) number = battle_config.atc_spawn_quantity_limit; - if (strcmp(command+1, "monstersmall") == 0) - size = SZ_MEDIUM; // This is just gorgeous [mkbu95] - else if (strcmp(command+1, "monsterbig") == 0) + if (strcmpi(info->command, "monstersmall") == 0) + size = SZ_SMALL; + else if (strcmpi(info->command, "monsterbig") == 0) size = SZ_BIG; else - size = SZ_SMALL; + size = SZ_MEDIUM; if (battle_config.etc_log) ShowInfo("%s monster='%s' name='%s' id=%d count=%d (%d,%d)\n", command, monster, name, mob_id, number, sd->bl.x, sd->bl.y); @@ -1964,8 +1927,8 @@ ACMD(monster) count = 0; range = (int)sqrt((float)number) +2; // calculation of an odd number (+ 4 area around) for (i = 0; i < number; i++) { - iMap->search_freecell(&sd->bl, 0, &mx, &my, range, range, 0); - k = mob_once_spawn(sd, sd->bl.m, mx, my, name, mob_id, 1, eventname, size, AI_NONE); + map->search_freecell(&sd->bl, 0, &mx, &my, range, range, 0); + k = mob->once_spawn(sd, sd->bl.m, mx, my, name, mob_id, 1, eventname, size, AI_NONE|(mob_id == MOBID_EMPERIUM?0x200:0x0)); count += (k != 0) ? 1 : 0; } @@ -1987,7 +1950,7 @@ ACMD(monster) /*========================================== * *------------------------------------------*/ -static int atkillmonster_sub(struct block_list *bl, va_list ap) +int atkillmonster_sub(struct block_list *bl, va_list ap) { struct mob_data *md; int flag; @@ -2005,24 +1968,22 @@ static int atkillmonster_sub(struct block_list *bl, va_list ap) return 1; } -ACMD(killmonster) -{ +ACMD(killmonster) { int map_id, drop_flag; char map_name[MAP_NAME_LENGTH_EXT]; - nullpo_retr(-1, sd); memset(map_name, '\0', sizeof(map_name)); if (!message || !*message || sscanf(message, "%15s", map_name) < 1) map_id = sd->bl.m; else { - if ((map_id = iMap->mapname2mapid(map_name)) < 0) + if ((map_id = map->mapname2mapid(map_name)) < 0) map_id = sd->bl.m; } - drop_flag = strcmp(command+1, "killmonster2"); + drop_flag = strcmpi(info->command, "killmonster2"); - iMap->foreachinmap(atkillmonster_sub, map_id, BL_MOB, -drop_flag); + map->foreachinmap(atcommand->atkillmonster_sub, map_id, BL_MOB, -drop_flag); clif->message(fd, msg_txt(165)); // All monsters killed! @@ -2036,7 +1997,6 @@ ACMD(refine) { int i,j, position = 0, refine = 0, current_position, final_refine; int count; - nullpo_retr(-1, sd); memset(atcmd_output, '\0', sizeof(atcmd_output)); @@ -2068,9 +2028,10 @@ ACMD(refine) refine = cap_value(refine, -MAX_REFINE, MAX_REFINE); count = 0; - for (j = 0; j < EQI_MAX-1; j++) { + for (j = 0; j < EQI_MAX; j++) { if ((i = sd->equip_index[j]) < 0) continue; + if(j == EQI_AMMO) continue; /* can't equip ammo */ if(j == EQI_HAND_R && sd->equip_index[EQI_HAND_L] == i) continue; if(j == EQI_HEAD_MID && sd->equip_index[EQI_HEAD_LOW] == i) @@ -2116,7 +2077,6 @@ ACMD(produce) int item_id, attribute = 0, star = 0; struct item_data *item_data; struct item tmp_item; - nullpo_retr(-1, sd); memset(atcmd_output, '\0', sizeof(atcmd_output)); memset(item_name, '\0', sizeof(item_name)); @@ -2129,15 +2089,15 @@ ACMD(produce) return false; } - if ( (item_data = itemdb_searchname(item_name)) == NULL && - (item_data = itemdb_exists(atoi(item_name))) == NULL ) { + if ( (item_data = itemdb->search_name(item_name)) == NULL && + (item_data = itemdb->exists(atoi(item_name))) == NULL ) { clif->message(fd, msg_txt(170)); //This item is not an equipment. return false; } item_id = item_data->nameid; - if (itemdb_isequip2(item_data)) { + if (itemdb->isequip2(item_data)) { int flag = 0; if (attribute < MIN_ATTRIBUTE || attribute > MAX_ATTRIBUTE) attribute = ATTRIBUTE_NORMAL; @@ -2172,14 +2132,13 @@ ACMD(produce) ACMD(memo) { int position = 0; - nullpo_retr(-1, sd); memset(atcmd_output, '\0', sizeof(atcmd_output)); if( !message || !*message || sscanf(message, "%d", &position) < 1 ) { int i; - clif->message(sd->fd, msg_txt(668)); + clif->message(sd->fd, msg_txt(868)); // "Your current memo positions are:" for( i = 0; i < MAX_MEMOPOINTS; i++ ) { if( sd->status.memo_point[i].map ) @@ -2205,21 +2164,19 @@ ACMD(memo) /*========================================== * *------------------------------------------*/ -ACMD(gat) -{ +ACMD(gat) { int y; - nullpo_retr(-1, sd); memset(atcmd_output, '\0', sizeof(atcmd_output)); for (y = 2; y >= -2; y--) { sprintf(atcmd_output, "%s (x= %d, y= %d) %02X %02X %02X %02X %02X", - map[sd->bl.m].name, sd->bl.x - 2, sd->bl.y + y, - iMap->getcell(sd->bl.m, sd->bl.x - 2, sd->bl.y + y, CELL_GETTYPE), - iMap->getcell(sd->bl.m, sd->bl.x - 1, sd->bl.y + y, CELL_GETTYPE), - iMap->getcell(sd->bl.m, sd->bl.x, sd->bl.y + y, CELL_GETTYPE), - iMap->getcell(sd->bl.m, sd->bl.x + 1, sd->bl.y + y, CELL_GETTYPE), - iMap->getcell(sd->bl.m, sd->bl.x + 2, sd->bl.y + y, CELL_GETTYPE)); + map->list[sd->bl.m].name, sd->bl.x - 2, sd->bl.y + y, + map->getcell(sd->bl.m, sd->bl.x - 2, sd->bl.y + y, CELL_GETTYPE), + map->getcell(sd->bl.m, sd->bl.x - 1, sd->bl.y + y, CELL_GETTYPE), + map->getcell(sd->bl.m, sd->bl.x, sd->bl.y + y, CELL_GETTYPE), + map->getcell(sd->bl.m, sd->bl.x + 1, sd->bl.y + y, CELL_GETTYPE), + map->getcell(sd->bl.m, sd->bl.x + 2, sd->bl.y + y, CELL_GETTYPE)); clif->message(fd, atcmd_output); } @@ -2233,7 +2190,6 @@ ACMD(gat) ACMD(displaystatus) { int i, type, flag, tick, val1 = 0, val2 = 0, val3 = 0; - nullpo_retr(-1, sd); if (!message || !*message || (i = sscanf(message, "%d %d %d %d %d %d", &type, &flag, &tick, &val1, &val2, &val3)) < 1) { clif->message(fd, msg_txt(1009)); // Please enter a status type/flag (usage: @displaystatus <status type> <flag> <tick> {<val1> {<val2> {<val3>}}}). @@ -2305,7 +2261,6 @@ ACMD(skillpoint) { int point; unsigned int new_skill_point; - nullpo_retr(-1, sd); if (!message || !*message || (point = atoi(message)) == 0) { clif->message(fd, msg_txt(1011)); // Please enter a number (usage: @skpoint <number of points>). @@ -2353,7 +2308,6 @@ ACMD(skillpoint) ACMD(zeny) { int zeny=0, ret=-1; - nullpo_retr(-1, sd); if (!message || !*message || (zeny = atoi(message)) == 0) { clif->message(fd, msg_txt(1012)); // Please enter an amount (usage: @zeny <amount>). @@ -2369,20 +2323,22 @@ ACMD(zeny) if((ret=pc->payzeny(sd,-zeny,LOG_TYPE_COMMAND,NULL)) == 1) clif->message(fd, msg_txt(41)); // Unable to decrease the number/value. } - if(!ret) clif->message(fd, msg_txt(176)); //ret=0 mean cmd success + + if( ret ) //ret != 0 means cmd failure + return false; + + clif->message(fd, msg_txt(176)); return true; } /*========================================== * *------------------------------------------*/ -ACMD(param) -{ +ACMD(param) { int i, value = 0, new_value, max; const char* param[] = { "str", "agi", "vit", "int", "dex", "luk" }; - short* status[6]; + short* stats[6]; //we don't use direct initialization because it isn't part of the c standard. - nullpo_retr(-1, sd); memset(atcmd_output, '\0', sizeof(atcmd_output)); @@ -2391,38 +2347,38 @@ ACMD(param) return false; } - ARR_FIND( 0, ARRAYLENGTH(param), i, strcmpi(command+1, param[i]) == 0 ); + ARR_FIND( 0, ARRAYLENGTH(param), i, strcmpi(info->command, param[i]) == 0 ); if( i == ARRAYLENGTH(param) || i > MAX_STATUS_TYPE) { // normally impossible... clif->message(fd, msg_txt(1013)); // Please enter a valid value (usage: @str/@agi/@vit/@int/@dex/@luk <+/-adjustment>). return false; } - status[0] = &sd->status.str; - status[1] = &sd->status.agi; - status[2] = &sd->status.vit; - status[3] = &sd->status.int_; - status[4] = &sd->status.dex; - status[5] = &sd->status.luk; + stats[0] = &sd->status.str; + stats[1] = &sd->status.agi; + stats[2] = &sd->status.vit; + stats[3] = &sd->status.int_; + stats[4] = &sd->status.dex; + stats[5] = &sd->status.luk; if( battle_config.atcommand_max_stat_bypass ) max = SHRT_MAX; else max = pc_maxparameter(sd); - if(value < 0 && *status[i] <= -value) { + if(value < 0 && *stats[i] <= -value) { new_value = 1; - } else if(max - *status[i] < value) { + } else if(max - *stats[i] < value) { new_value = max; } else { - new_value = *status[i] + value; + new_value = *stats[i] + value; } - if (new_value != *status[i]) { - *status[i] = new_value; + if (new_value != *stats[i]) { + *stats[i] = new_value; clif->updatestatus(sd, SP_STR + i); clif->updatestatus(sd, SP_USTR + i); - status_calc_pc(sd, 0); + status_calc_pc(sd, SCO_FORCE); clif->message(fd, msg_txt(42)); // Stat changed. } else { if (value < 0) @@ -2438,19 +2394,17 @@ ACMD(param) /*========================================== * Stat all by fritz (rewritten by [Yor]) *------------------------------------------*/ -ACMD(stat_all) -{ +ACMD(stat_all) { int index, count, value, max, new_value; - short* status[6]; + short* stats[6]; //we don't use direct initialization because it isn't part of the c standard. - nullpo_retr(-1, sd); - status[0] = &sd->status.str; - status[1] = &sd->status.agi; - status[2] = &sd->status.vit; - status[3] = &sd->status.int_; - status[4] = &sd->status.dex; - status[5] = &sd->status.luk; + stats[0] = &sd->status.str; + stats[1] = &sd->status.agi; + stats[2] = &sd->status.vit; + stats[3] = &sd->status.int_; + stats[4] = &sd->status.dex; + stats[5] = &sd->status.luk; if (!message || !*message || sscanf(message, "%d", &value) < 1 || value == 0) { value = pc_maxparameter(sd); @@ -2463,17 +2417,17 @@ ACMD(stat_all) } count = 0; - for (index = 0; index < ARRAYLENGTH(status); index++) { + for (index = 0; index < ARRAYLENGTH(stats); index++) { - if (value > 0 && *status[index] > max - value) + if (value > 0 && *stats[index] > max - value) new_value = max; - else if (value < 0 && *status[index] <= -value) + else if (value < 0 && *stats[index] <= -value) new_value = 1; else - new_value = *status[index] +value; + new_value = *stats[index] +value; - if (new_value != (int)*status[index]) { - *status[index] = new_value; + if (new_value != (int)*stats[index]) { + *stats[index] = new_value; clif->updatestatus(sd, SP_STR + index); clif->updatestatus(sd, SP_USTR + index); count++; @@ -2481,7 +2435,7 @@ ACMD(stat_all) } if (count > 0) { // if at least 1 stat modified - status_calc_pc(sd, 0); + status_calc_pc(sd, SCO_FORCE); clif->message(fd, msg_txt(84)); // All stats changed! } else { if (value < 0) @@ -2497,12 +2451,10 @@ ACMD(stat_all) /*========================================== * *------------------------------------------*/ -ACMD(guildlevelup) -{ +ACMD(guildlevelup) { int level = 0; - short added_level; + int16 added_level; struct guild *guild_info; - nullpo_retr(-1, sd); if (!message || !*message || sscanf(message, "%d", &level) < 1 || level == 0) { clif->message(fd, msg_txt(1014)); // Please enter a valid level (usage: @guildlvup/@guildlvlup <# of levels>). @@ -2513,19 +2465,21 @@ ACMD(guildlevelup) clif->message(fd, msg_txt(43)); // You're not in a guild. return false; } - //if (strcmp(sd->status.name, guild_info->master) != 0) { - // clif->message(fd, msg_txt(44)); // You're not the master of your guild. - // return false; - //} +#if 0 // By enabling this, only the guild leader can use this command + if (strcmp(sd->status.name, guild_info->master) != 0) { + clif->message(fd, msg_txt(44)); // You're not the master of your guild. + return false; + } +#endif // 0 - added_level = (short)level; - if (level > 0 && (level > MAX_GUILDLEVEL || added_level > ((short)MAX_GUILDLEVEL - guild_info->guild_lv))) // fix positiv overflow - added_level = (short)MAX_GUILDLEVEL - guild_info->guild_lv; - else if (level < 0 && (level < -MAX_GUILDLEVEL || added_level < (1 - guild_info->guild_lv))) // fix negativ overflow - added_level = 1 - guild_info->guild_lv; + if (level > INT16_MAX || (level > 0 && level > MAX_GUILDLEVEL - guild_info->guild_lv)) // fix positive overflow + level = MAX_GUILDLEVEL - guild_info->guild_lv; + else if (level < INT16_MIN || (level < 0 && level < 1 - guild_info->guild_lv)) // fix negative overflow + level = 1 - guild_info->guild_lv; + added_level = (int16)level; if (added_level != 0) { - intif_guild_change_basicinfo(guild_info->guild_id, GBI_GUILDLV, &added_level, sizeof(added_level)); + intif->guild_change_basicinfo(guild_info->guild_id, GBI_GUILDLV, &added_level, sizeof(added_level)); clif->message(fd, msg_txt(179)); // Guild level changed. } else { clif->message(fd, msg_txt(45)); // Guild level change failed. @@ -2542,31 +2496,30 @@ ACMD(makeegg) { struct item_data *item_data; int id, pet_id; - nullpo_retr(-1, sd); if (!message || !*message) { clif->message(fd, msg_txt(1015)); // Please enter a monster/egg name/ID (usage: @makeegg <pet>). return false; } - if ((item_data = itemdb_searchname(message)) != NULL) // for egg name + if ((item_data = itemdb->search_name(message)) != NULL) // for egg name id = item_data->nameid; else - if ((id = mobdb_searchname(message)) != 0) // for monster name + if ((id = mob->db_searchname(message)) != 0) // for monster name ; else id = atoi(message); - pet_id = search_petDB_index(id, PET_CLASS); + pet_id = pet->search_petDB_index(id, PET_CLASS); if (pet_id < 0) - pet_id = search_petDB_index(id, PET_EGG); + pet_id = pet->search_petDB_index(id, PET_EGG); if (pet_id >= 0) { - sd->catch_target_class = pet_db[pet_id].class_; - intif_create_pet( + sd->catch_target_class = pet->db[pet_id].class_; + intif->create_pet( sd->status.account_id, sd->status.char_id, - (short)pet_db[pet_id].class_, (short)mob_db(pet_db[pet_id].class_)->lv, - (short)pet_db[pet_id].EggID, 0, (short)pet_db[pet_id].intimate, - 100, 0, 1, pet_db[pet_id].jname); + (short)pet->db[pet_id].class_, (short)mob->db(pet->db[pet_id].class_)->lv, + (short)pet->db[pet_id].EggID, 0, (short)pet->db[pet_id].intimate, + 100, 0, 1, pet->db[pet_id].jname); } else { clif->message(fd, msg_txt(180)); // The monster/egg name/id doesn't exist. return false; @@ -2580,7 +2533,6 @@ ACMD(makeegg) *------------------------------------------*/ ACMD(hatch) { - nullpo_retr(-1, sd); if (sd->status.pet_id <= 0) clif->sendegg(sd); else { @@ -2598,7 +2550,6 @@ ACMD(petfriendly) { int friendly; struct pet_data *pd; - nullpo_retr(-1, sd); if (!message || !*message || (friendly = atoi(message)) < 0) { clif->message(fd, msg_txt(1016)); // Please enter a valid value (usage: @petfriendly <0-1000>). @@ -2622,7 +2573,7 @@ ACMD(petfriendly) return false; } - pet_set_intimate(pd, friendly); + pet->set_intimate(pd, friendly); clif->send_petstatus(sd); clif->message(fd, msg_txt(182)); // Pet intimacy changed. return true; @@ -2635,7 +2586,6 @@ ACMD(pethungry) { int hungry; struct pet_data *pd; - nullpo_retr(-1, sd); if (!message || !*message || (hungry = atoi(message)) < 0) { clif->message(fd, msg_txt(1017)); // Please enter a valid number (usage: @pethungry <0-100>). @@ -2669,7 +2619,6 @@ ACMD(pethungry) ACMD(petrename) { struct pet_data *pd; - nullpo_retr(-1, sd); if (!sd->status.pet_id || !sd->pd) { clif->message(fd, msg_txt(184)); // Sorry, but you have no pet. return false; @@ -2681,7 +2630,7 @@ ACMD(petrename) } pd->pet.rename_flag = 0; - intif_save_petdata(sd->status.account_id, &pd->pet); + intif->save_petdata(sd->status.account_id, &pd->pet); clif->send_petstatus(sd); clif->message(fd, msg_txt(187)); // You can now rename your pet. @@ -2694,30 +2643,28 @@ ACMD(petrename) ACMD(recall) { struct map_session_data *pl_sd = NULL; - nullpo_retr(-1, sd); if (!message || !*message) { clif->message(fd, msg_txt(1018)); // Please enter a player name (usage: @recall <char name/ID>). return false; } - if((pl_sd=iMap->nick2sd((char *)message)) == NULL && (pl_sd=iMap->charid2sd(atoi(message))) == NULL) - { + if((pl_sd=map->nick2sd((char *)message)) == NULL && (pl_sd=map->charid2sd(atoi(message))) == NULL) { clif->message(fd, msg_txt(3)); // Character not found. return false; } - if ( pc->get_group_level(sd) < pc->get_group_level(pl_sd) ) + if ( pc_get_group_level(sd) < pc_get_group_level(pl_sd) ) { clif->message(fd, msg_txt(81)); // Your GM level doesn't authorize you to preform this action on the specified player. return false; } - if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { + if (sd->bl.m >= 0 && map->list[sd->bl.m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { clif->message(fd, msg_txt(1019)); // You are not authorized to warp someone to this map. return false; } - if (pl_sd->bl.m >= 0 && map[pl_sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { + if (pl_sd->bl.m >= 0 && map->list[pl_sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { clif->message(fd, msg_txt(1020)); // You are not authorized to warp this player from their map. return false; } @@ -2737,16 +2684,15 @@ ACMD(recall) { *------------------------------------------*/ ACMD(char_block) { - nullpo_retr(-1, sd); memset(atcmd_player_name, '\0', sizeof(atcmd_player_name)); if (!message || !*message || sscanf(message, "%23[^\n]", atcmd_player_name) < 1) { - clif->message(fd, msg_txt(1021)); // Please enter a player name (usage: @charblock/@block <char name>). + clif->message(fd, msg_txt(1021)); // Please enter a player name (usage: @block <char name>). return false; } - chrif_char_ask_name(sd->status.account_id, atcmd_player_name, 1, 0, 0, 0, 0, 0, 0); // type: 1 - block + chrif->char_ask_name(sd->status.account_id, atcmd_player_name, 1, 0, 0, 0, 0, 0, 0); // type: 1 - block clif->message(fd, msg_txt(88)); // Character name sent to char-server to ask it. return true; @@ -2765,7 +2711,7 @@ ACMD(char_block) * mn: minute * s: second * <example> @ban +1m-2mn1s-6y test_player - * this example adds 1 month and 1 second, and substracts 2 minutes and 6 years at the same time. + * this example adds 1 month and 1 second, and subtracts 2 minutes and 6 years at the same time. *------------------------------------------*/ ACMD(char_ban) { @@ -2773,13 +2719,12 @@ ACMD(char_ban) int year, month, day, hour, minute, second, value; time_t timestamp; struct tm *tmtime; - nullpo_retr(-1, sd); memset(atcmd_output, '\0', sizeof(atcmd_output)); memset(atcmd_player_name, '\0', sizeof(atcmd_player_name)); if (!message || !*message || sscanf(message, "%255s %23[^\n]", atcmd_output, atcmd_player_name) < 2) { - clif->message(fd, msg_txt(1022)); // Please enter ban time and a player name (usage: @charban/@ban/@banish/@charbanish <time> <char name>). + clif->message(fd, msg_txt(1022)); // Please enter ban time and a player name (usage: @ban <time> <char name>). return false; } @@ -2843,7 +2788,7 @@ ACMD(char_ban) return false; } - chrif_char_ask_name(sd->status.account_id, atcmd_player_name, 2, year, month, day, hour, minute, second); // type: 2 - ban + chrif->char_ask_name(sd->status.account_id, atcmd_player_name, !strcmpi(info->command,"charban") ? 6 : 2, year, month, day, hour, minute, second); // type: 2 - ban; 6 - charban clif->message(fd, msg_txt(88)); // Character name sent to char-server to ask it. return true; @@ -2854,17 +2799,16 @@ ACMD(char_ban) *------------------------------------------*/ ACMD(char_unblock) { - nullpo_retr(-1, sd); memset(atcmd_player_name, '\0', sizeof(atcmd_player_name)); if (!message || !*message || sscanf(message, "%23[^\n]", atcmd_player_name) < 1) { - clif->message(fd, msg_txt(1024)); // Please enter a player name (usage: @charunblock <char name>). + clif->message(fd, msg_txt(1024)); // Please enter a player name (usage: @unblock <char name>). return false; } // send answer to login server via char-server - chrif_char_ask_name(sd->status.account_id, atcmd_player_name, 3, 0, 0, 0, 0, 0, 0); // type: 3 - unblock + chrif->char_ask_name(sd->status.account_id, atcmd_player_name, 3, 0, 0, 0, 0, 0, 0); // type: 3 - unblock clif->message(fd, msg_txt(88)); // Character name sent to char-server to ask it. return true; @@ -2875,17 +2819,16 @@ ACMD(char_unblock) *------------------------------------------*/ ACMD(char_unban) { - nullpo_retr(-1, sd); memset(atcmd_player_name, '\0', sizeof(atcmd_player_name)); if (!message || !*message || sscanf(message, "%23[^\n]", atcmd_player_name) < 1) { - clif->message(fd, msg_txt(1025)); // Please enter a player name (usage: @charunban <char name>). + clif->message(fd, msg_txt(1025)); // Please enter a player name (usage: @unban <char name>). return false; } // send answer to login server via char-server - chrif_char_ask_name(sd->status.account_id, atcmd_player_name, 4, 0, 0, 0, 0, 0, 0); // type: 4 - unban + chrif->char_ask_name(sd->status.account_id, atcmd_player_name, !strcmpi(info->command,"charunban") ? 7 : 4, 0, 0, 0, 0, 0, 0); // type: 4 - unban account; type 7 - unban character clif->message(fd, msg_txt(88)); // Character name sent to char-server to ask it. return true; @@ -2894,11 +2837,9 @@ ACMD(char_unban) /*========================================== * *------------------------------------------*/ -ACMD(night) -{ - nullpo_retr(-1, sd); +ACMD(night) { - if (iMap->night_flag != 1) { + if (map->night_flag != 1) { pc->map_night_timer(pc->night_timer_tid, 0, 0, 1); } else { clif->message(fd, msg_txt(89)); // Night mode is already enabled. @@ -2911,11 +2852,9 @@ ACMD(night) /*========================================== * *------------------------------------------*/ -ACMD(day) -{ - nullpo_retr(-1, sd); +ACMD(day) { - if (iMap->night_flag != 0) { + if (map->night_flag != 0) { pc->map_day_timer(pc->day_timer_tid, 0, 0, 1); } else { clif->message(fd, msg_txt(90)); // Day mode is already enabled. @@ -2932,22 +2871,20 @@ ACMD(doom) { struct map_session_data* pl_sd; struct s_mapiterator* iter; - - nullpo_retr(-1, sd); - + iter = mapit_getallusers(); for( pl_sd = (TBL_PC*)mapit->first(iter); mapit->exists(iter); pl_sd = (TBL_PC*)mapit->next(iter) ) { - if (pl_sd->fd != fd && pc->get_group_level(sd) >= pc->get_group_level(pl_sd)) + if (pl_sd->fd != fd && pc_get_group_level(sd) >= pc_get_group_level(pl_sd)) { status_kill(&pl_sd->bl); clif->specialeffect(&pl_sd->bl,450,AREA); - clif->message(pl_sd->fd, msg_txt(61)); // The holy messenger has given judgement. + clif->message(pl_sd->fd, msg_txt(61)); // The holy messenger has given judgment. } } mapit->free(iter); - clif->message(fd, msg_txt(62)); // Judgement was made. + clif->message(fd, msg_txt(62)); // Judgment was made. return true; } @@ -2959,22 +2896,20 @@ ACMD(doommap) { struct map_session_data* pl_sd; struct s_mapiterator* iter; - - nullpo_retr(-1, sd); - + iter = mapit_getallusers(); for( pl_sd = (TBL_PC*)mapit->first(iter); mapit->exists(iter); pl_sd = (TBL_PC*)mapit->next(iter) ) { - if (pl_sd->fd != fd && sd->bl.m == pl_sd->bl.m && pc->get_group_level(sd) >= pc->get_group_level(pl_sd)) + if (pl_sd->fd != fd && sd->bl.m == pl_sd->bl.m && pc_get_group_level(sd) >= pc_get_group_level(pl_sd)) { status_kill(&pl_sd->bl); clif->specialeffect(&pl_sd->bl,450,AREA); - clif->message(pl_sd->fd, msg_txt(61)); // The holy messenger has given judgement. + clif->message(pl_sd->fd, msg_txt(61)); // The holy messenger has given judgment. } } mapit->free(iter); - clif->message(fd, msg_txt(62)); // Judgement was made. + clif->message(fd, msg_txt(62)); // Judgment was made. return true; } @@ -2982,9 +2917,9 @@ ACMD(doommap) /*========================================== * *------------------------------------------*/ -static void atcommand_raise_sub(struct map_session_data* sd) { +void atcommand_raise_sub(struct map_session_data* sd) { - status_revive(&sd->bl, 100, 100); + status->revive(&sd->bl, 100, 100); clif->skill_nodamage(&sd->bl,&sd->bl,ALL_RESURRECTION,4,1); clif->message(sd->fd, msg_txt(63)); // Mercy has been shown. @@ -2997,13 +2932,11 @@ ACMD(raise) { struct map_session_data* pl_sd; struct s_mapiterator* iter; - - nullpo_retr(-1, sd); - + iter = mapit_getallusers(); for( pl_sd = (TBL_PC*)mapit->first(iter); mapit->exists(iter); pl_sd = (TBL_PC*)mapit->next(iter) ) if( pc_isdead(pl_sd) ) - atcommand_raise_sub(pl_sd); + atcommand->raise_sub(pl_sd); mapit->free(iter); clif->message(fd, msg_txt(64)); // Mercy has been granted. @@ -3018,13 +2951,11 @@ ACMD(raisemap) { struct map_session_data* pl_sd; struct s_mapiterator* iter; - - nullpo_retr(-1, sd); - + iter = mapit_getallusers(); for( pl_sd = (TBL_PC*)mapit->first(iter); mapit->exists(iter); pl_sd = (TBL_PC*)mapit->next(iter) ) if (sd->bl.m == pl_sd->bl.m && pc_isdead(pl_sd) ) - atcommand_raise_sub(pl_sd); + atcommand->raise_sub(pl_sd); mapit->free(iter); clif->message(fd, msg_txt(64)); // Mercy has been granted. @@ -3038,7 +2969,6 @@ ACMD(raisemap) ACMD(kick) { struct map_session_data *pl_sd; - nullpo_retr(-1, sd); memset(atcmd_player_name, '\0', sizeof(atcmd_player_name)); @@ -3047,15 +2977,14 @@ ACMD(kick) return false; } - if((pl_sd=iMap->nick2sd((char *)message)) == NULL && (pl_sd=iMap->charid2sd(atoi(message))) == NULL) - { + if((pl_sd=map->nick2sd((char *)message)) == NULL && (pl_sd=map->charid2sd(atoi(message))) == NULL) { clif->message(fd, msg_txt(3)); // Character not found. return false; } - if ( pc->get_group_level(sd) < pc->get_group_level(pl_sd) ) + if ( pc_get_group_level(sd) < pc_get_group_level(pl_sd) ) { - clif->message(fd, msg_txt(81)); // Your GM level don't authorise you to do this action on this player. + clif->message(fd, msg_txt(81)); // Your GM level don't authorize you to do this action on this player. return false; } @@ -3071,12 +3000,11 @@ ACMD(kickall) { struct map_session_data* pl_sd; struct s_mapiterator* iter; - nullpo_retr(-1, sd); iter = mapit_getallusers(); for( pl_sd = (TBL_PC*)mapit->first(iter); mapit->exists(iter); pl_sd = (TBL_PC*)mapit->next(iter) ) { - if (pc->get_group_level(sd) >= pc->get_group_level(pl_sd)) { // you can kick only lower or same gm level + if (pc_get_group_level(sd) >= pc_get_group_level(pl_sd)) { // you can kick only lower or same gm level if (sd->status.account_id != pl_sd->status.account_id) clif->GM_kick(NULL, pl_sd); } @@ -3093,7 +3021,6 @@ ACMD(kickall) *------------------------------------------*/ ACMD(allskill) { - nullpo_retr(-1, sd); pc->allskillup(sd); // all skills sd->status.skill_point = 0; // 0 skill points clif->updatestatus(sd, SP_SKILLPOINT); // update @@ -3108,7 +3035,6 @@ ACMD(allskill) ACMD(questskill) { uint16 skill_id, index; - nullpo_retr(-1, sd); if (!message || !*message || (skill_id = atoi(message)) <= 0) {// also send a list of skills applicable to this command @@ -3151,7 +3077,6 @@ ACMD(questskill) ACMD(lostskill) { uint16 skill_id, index; - nullpo_retr(-1, sd); if (!message || !*message || (skill_id = atoi(message)) <= 0) {// also send a list of skills applicable to this command @@ -3197,14 +3122,13 @@ ACMD(spiritball) { int max_spiritballs; int number; - nullpo_retr(-1, sd); max_spiritballs = min(ARRAYLENGTH(sd->spirit_timer), 0x7FFF); if( !message || !*message || (number = atoi(message)) < 0 || number > max_spiritballs ) { char msg[CHAT_SIZE_MAX]; - safesnprintf(msg, sizeof(msg), msg_txt(1028), max_spiritballs); // Please enter a party name (usage: @party <party_name>). + safesnprintf(msg, sizeof(msg), msg_txt(1028), max_spiritballs); // Please enter an amount (usage: @spiritball <number: 0-%d>). clif->message(fd, msg); return false; } @@ -3224,7 +3148,6 @@ ACMD(spiritball) ACMD(party) { char party_name[NAME_LENGTH]; - nullpo_retr(-1, sd); memset(party_name, '\0', sizeof(party_name)); @@ -3245,7 +3168,6 @@ ACMD(guild) { char guild_name[NAME_LENGTH]; int prev; - nullpo_retr(-1, sd); memset(guild_name, '\0', sizeof(guild_name)); @@ -3264,7 +3186,6 @@ ACMD(guild) ACMD(breakguild) { - nullpo_retr(-1, sd); if (sd->status.guild_id) { // Check if the player has a guild struct guild *g; @@ -3296,15 +3217,13 @@ ACMD(breakguild) /*========================================== * *------------------------------------------*/ -ACMD(agitstart) -{ - nullpo_retr(-1, sd); - if (iMap->agit_flag == 1) { +ACMD(agitstart) { + if (map->agit_flag == 1) { clif->message(fd, msg_txt(73)); // War of Emperium is currently in progress. return false; } - iMap->agit_flag = 1; + map->agit_flag = 1; guild->agit_start(); clif->message(fd, msg_txt(72)); // War of Emperium has been initiated. @@ -3314,15 +3233,13 @@ ACMD(agitstart) /*========================================== * *------------------------------------------*/ -ACMD(agitstart2) -{ - nullpo_retr(-1, sd); - if (iMap->agit2_flag == 1) { +ACMD(agitstart2) { + if (map->agit2_flag == 1) { clif->message(fd, msg_txt(404)); // "War of Emperium SE is currently in progress." return false; } - iMap->agit2_flag = 1; + map->agit2_flag = 1; guild->agit2_start(); clif->message(fd, msg_txt(403)); // "War of Emperium SE has been initiated." @@ -3332,15 +3249,13 @@ ACMD(agitstart2) /*========================================== * *------------------------------------------*/ -ACMD(agitend) -{ - nullpo_retr(-1, sd); - if (iMap->agit_flag == 0) { +ACMD(agitend) { + if (map->agit_flag == 0) { clif->message(fd, msg_txt(75)); // War of Emperium is currently not in progress. return false; } - iMap->agit_flag = 0; + map->agit_flag = 0; guild->agit_end(); clif->message(fd, msg_txt(74)); // War of Emperium has been ended. @@ -3350,15 +3265,13 @@ ACMD(agitend) /*========================================== * *------------------------------------------*/ -ACMD(agitend2) -{ - nullpo_retr(-1, sd); - if (iMap->agit2_flag == 0) { +ACMD(agitend2) { + if (map->agit2_flag == 0) { clif->message(fd, msg_txt(406)); // "War of Emperium SE is currently not in progress." return false; } - iMap->agit2_flag = 0; + map->agit2_flag = 0; guild->agit2_end(); clif->message(fd, msg_txt(405)); // "War of Emperium SE has been ended." @@ -3368,23 +3281,19 @@ ACMD(agitend2) /*========================================== * @mapexit - shuts down the map server *------------------------------------------*/ -ACMD(mapexit) -{ - nullpo_retr(-1, sd); - - iMap->do_shutdown(); +ACMD(mapexit) { + map->do_shutdown(); return true; } /*========================================== - * idsearch <part_of_name>: revrited by [Yor] + * idsearch <part_of_name>: rewrite by [Yor] *------------------------------------------*/ ACMD(idsearch) { char item_name[100]; unsigned int i, match; struct item_data *item_array[MAX_SEARCH]; - nullpo_retr(-1, sd); memset(item_name, '\0', sizeof(item_name)); memset(atcmd_output, '\0', sizeof(atcmd_output)); @@ -3394,9 +3303,9 @@ ACMD(idsearch) return false; } - sprintf(atcmd_output, msg_txt(77), item_name); // The reference result of '%s' (name: id): + sprintf(atcmd_output, msg_txt(77), item_name); // Search results for '%s' (name: id): clif->message(fd, atcmd_output); - match = itemdb_searchname_array(item_array, MAX_SEARCH, item_name); + match = itemdb->search_name_array(item_array, MAX_SEARCH, item_name, 0); if (match > MAX_SEARCH) { sprintf(atcmd_output, msg_txt(269), MAX_SEARCH, match); clif->message(fd, atcmd_output); @@ -3406,7 +3315,7 @@ ACMD(idsearch) sprintf(atcmd_output, msg_txt(78), item_array[i]->jname, item_array[i]->nameid); // %s: %d clif->message(fd, atcmd_output); } - sprintf(atcmd_output, msg_txt(79), match); // It is %d affair above. + sprintf(atcmd_output, msg_txt(79), match); // %d results found. clif->message(fd, atcmd_output); return true; @@ -3420,24 +3329,21 @@ ACMD(recallall) struct map_session_data* pl_sd; struct s_mapiterator* iter; int count; - nullpo_retr(-1, sd); memset(atcmd_output, '\0', sizeof(atcmd_output)); - if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { - clif->message(fd, msg_txt(1032)); // You are not authorized to warp somenone to your current map. + if (sd->bl.m >= 0 && map->list[sd->bl.m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { + clif->message(fd, msg_txt(1032)); // You are not authorized to warp someone to your current map. return false; } count = 0; iter = mapit_getallusers(); - for( pl_sd = (TBL_PC*)mapit->first(iter); mapit->exists(iter); pl_sd = (TBL_PC*)mapit->next(iter) ) - { - if (sd->status.account_id != pl_sd->status.account_id && pc->get_group_level(sd) >= pc->get_group_level(pl_sd)) - { + for( pl_sd = (TBL_PC*)mapit->first(iter); mapit->exists(iter); pl_sd = (TBL_PC*)mapit->next(iter) ) { + if (sd->status.account_id != pl_sd->status.account_id && pc_get_group_level(sd) >= pc_get_group_level(pl_sd)) { if (pl_sd->bl.m == sd->bl.m && pl_sd->bl.x == sd->bl.x && pl_sd->bl.y == sd->bl.y) continue; // Don't waste time warping the character to the same place. - if (pl_sd->bl.m >= 0 && map[pl_sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) + if (pl_sd->bl.m >= 0 && map->list[pl_sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) count++; else { if (pc_isdead(pl_sd)) { //Wake them up @@ -3469,7 +3375,6 @@ ACMD(guildrecall) int count; char guild_name[NAME_LENGTH]; struct guild *g; - nullpo_retr(-1, sd); memset(guild_name, '\0', sizeof(guild_name)); memset(atcmd_output, '\0', sizeof(atcmd_output)); @@ -3479,8 +3384,8 @@ ACMD(guildrecall) return false; } - if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { - clif->message(fd, msg_txt(1032)); // You are not authorized to warp somenone to your current map. + if (sd->bl.m >= 0 && map->list[sd->bl.m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { + clif->message(fd, msg_txt(1032)); // You are not authorized to warp someone to your current map. return false; } @@ -3496,11 +3401,10 @@ ACMD(guildrecall) iter = mapit_getallusers(); for( pl_sd = (TBL_PC*)mapit->first(iter); mapit->exists(iter); pl_sd = (TBL_PC*)mapit->next(iter) ) { - if (sd->status.account_id != pl_sd->status.account_id && pl_sd->status.guild_id == g->guild_id) - { - if (pc->get_group_level(pl_sd) > pc->get_group_level(sd) || (pl_sd->bl.m == sd->bl.m && pl_sd->bl.x == sd->bl.x && pl_sd->bl.y == sd->bl.y)) + if (sd->status.account_id != pl_sd->status.account_id && pl_sd->status.guild_id == g->guild_id) { + if (pc_get_group_level(pl_sd) > pc_get_group_level(sd) || (pl_sd->bl.m == sd->bl.m && pl_sd->bl.x == sd->bl.x && pl_sd->bl.y == sd->bl.y)) continue; // Skip GMs greater than you... or chars already on the cell - if (pl_sd->bl.m >= 0 && map[pl_sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) + if (pl_sd->bl.m >= 0 && map->list[pl_sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) count++; else pc->setpos(pl_sd, sd->mapindex, sd->bl.x, sd->bl.y, CLR_RESPAWN); @@ -3528,7 +3432,6 @@ ACMD(partyrecall) char party_name[NAME_LENGTH]; struct party_data *p; int count; - nullpo_retr(-1, sd); memset(party_name, '\0', sizeof(party_name)); memset(atcmd_output, '\0', sizeof(atcmd_output)); @@ -3538,8 +3441,8 @@ ACMD(partyrecall) return false; } - if (sd->bl.m >= 0 && map[sd->bl.m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { - clif->message(fd, msg_txt(1032)); // You are not authorized to warp somenone to your current map. + if (sd->bl.m >= 0 && map->list[sd->bl.m].flag.nowarpto && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) { + clif->message(fd, msg_txt(1032)); // You are not authorized to warp someone to your current map. return false; } @@ -3553,13 +3456,11 @@ ACMD(partyrecall) count = 0; iter = mapit_getallusers(); - for( pl_sd = (TBL_PC*)mapit->first(iter); mapit->exists(iter); pl_sd = (TBL_PC*)mapit->next(iter) ) - { - if (sd->status.account_id != pl_sd->status.account_id && pl_sd->status.party_id == p->party.party_id) - { - if (pc->get_group_level(pl_sd) > pc->get_group_level(sd) || (pl_sd->bl.m == sd->bl.m && pl_sd->bl.x == sd->bl.x && pl_sd->bl.y == sd->bl.y)) + for( pl_sd = (TBL_PC*)mapit->first(iter); mapit->exists(iter); pl_sd = (TBL_PC*)mapit->next(iter) ) { + if (sd->status.account_id != pl_sd->status.account_id && pl_sd->status.party_id == p->party.party_id) { + if (pc_get_group_level(pl_sd) > pc_get_group_level(sd) || (pl_sd->bl.m == sd->bl.m && pl_sd->bl.x == sd->bl.x && pl_sd->bl.y == sd->bl.y)) continue; // Skip GMs greater than you... or chars already on the cell - if (pl_sd->bl.m >= 0 && map[pl_sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) + if (pl_sd->bl.m >= 0 && map->list[pl_sd->bl.m].flag.nowarp && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE)) count++; else pc->setpos(pl_sd, sd->mapindex, sd->bl.x, sd->bl.y, CLR_RESPAWN); @@ -3582,8 +3483,7 @@ ACMD(partyrecall) *------------------------------------------*/ ACMD(reloaditemdb) { - nullpo_retr(-1, sd); - itemdb_reload(); + itemdb->reload(); clif->message(fd, msg_txt(97)); // Item database has been reloaded. return true; @@ -3593,13 +3493,12 @@ ACMD(reloaditemdb) * *------------------------------------------*/ ACMD(reloadmobdb) { - nullpo_retr(-1, sd); - mob_reload(); - read_petdb(); + mob->reload(); + pet->read_db(); homun->reload(); - read_mercenarydb(); - read_mercenary_skilldb(); - reload_elementaldb(); + mercenary->read_db(); + mercenary->read_skilldb(); + elemental->reload_db(); clif->message(fd, msg_txt(98)); // Monster database has been reloaded. return true; @@ -3610,11 +3509,10 @@ ACMD(reloadmobdb) { *------------------------------------------*/ ACMD(reloadskilldb) { - nullpo_retr(-1, sd); skill->reload(); homun->reload_skill(); - reload_elemental_skilldb(); - read_mercenary_skilldb(); + elemental->reload_skilldb(); + mercenary->read_skilldb(); clif->message(fd, msg_txt(99)); // Skill database has been reloaded. return true; @@ -3623,26 +3521,25 @@ ACMD(reloadskilldb) /*========================================== * @reloadatcommand - reloads conf/atcommand.conf conf/groups.conf *------------------------------------------*/ -void atcommand_doload(); ACMD(reloadatcommand) { config_t run_test; - if (conf_read_file(&run_test, "conf/groups.conf")) { + if (libconfig->read_file(&run_test, "conf/groups.conf")) { clif->message(fd, msg_txt(1036)); // Error reading groups.conf, reload failed. return false; } - config_destroy(&run_test); + libconfig->destroy(&run_test); - if (conf_read_file(&run_test, iMap->ATCOMMAND_CONF_FILENAME)) { + if (libconfig->read_file(&run_test, map->ATCOMMAND_CONF_FILENAME)) { clif->message(fd, msg_txt(1037)); // Error reading atcommand.conf, reload failed. return false; } - config_destroy(&run_test); + libconfig->destroy(&run_test); - atcommand_doload(); - pc_groups_reload(); + atcommand->doload(); + pcg->reload(); clif->message(fd, msg_txt(254)); return true; } @@ -3654,7 +3551,7 @@ ACMD(reloadbattleconf) struct Battle_Config prev_config; memcpy(&prev_config, &battle_config, sizeof(prev_config)); - battle->config_read(iMap->BATTLE_CONF_FILENAME); + battle->config_read(map->BATTLE_CONF_FILENAME); if( prev_config.item_rate_mvp != battle_config.item_rate_mvp || prev_config.item_rate_common != battle_config.item_rate_common @@ -3688,8 +3585,8 @@ ACMD(reloadbattleconf) || prev_config.job_exp_rate != battle_config.job_exp_rate ) { // Exp or Drop rates changed. - mob_reload(); //Needed as well so rate changes take effect. - chrif_ragsrvinfo(battle_config.base_exp_rate, battle_config.job_exp_rate, battle_config.item_rate_common); + mob->reload(); //Needed as well so rate changes take effect. + chrif->ragsrvinfo(battle_config.base_exp_rate, battle_config.job_exp_rate, battle_config.item_rate_common); } clif->message(fd, msg_txt(255)); return true; @@ -3697,9 +3594,8 @@ ACMD(reloadbattleconf) /*========================================== * @reloadstatusdb - reloads job_db1.txt job_db2.txt job_db2-2.txt refine_db.txt size_fix.txt *------------------------------------------*/ -ACMD(reloadstatusdb) -{ - status_readdb(); +ACMD(reloadstatusdb) { + status->readdb(); clif->message(fd, msg_txt(256)); return true; } @@ -3716,12 +3612,10 @@ ACMD(reloadpcdb) /*========================================== * @reloadscript - reloads all scripts (npcs, warps, mob spawns, ...) *------------------------------------------*/ -ACMD(reloadscript) -{ +ACMD(reloadscript) { struct s_mapiterator* iter; struct map_session_data* pl_sd; - nullpo_retr(-1, sd); //atcommand_broadcast( fd, sd, "@broadcast", "Server is reloading scripts..." ); //atcommand_broadcast( fd, sd, "@broadcast", "You will feel a bit of lag at this point !" ); @@ -3746,9 +3640,9 @@ ACMD(reloadscript) mapit->free(iter); flush_fifos(); - iMap->reloadnpc(true); // reload config files seeking for npcs - script_reload(); - npc_reload(); + map->reloadnpc(true, NULL, 0); // reload config files seeking for npcs + script->reload(); + npc->reload(); clif->message(fd, msg_txt(100)); // Scripts have been reloaded. @@ -3773,9 +3667,7 @@ ACMD(mapinfo) { int i, m_id, chat_num = 0, list = 0, vend_num = 0; unsigned short m_index; char mapname[24]; - - nullpo_retr(-1, sd); - + memset(atcmd_output, '\0', sizeof(atcmd_output)); memset(mapname, '\0', sizeof(mapname)); memset(direction, '\0', sizeof(direction)); @@ -3789,16 +3681,16 @@ ACMD(mapinfo) { if (mapname[0] == '\0') { safestrncpy(mapname, mapindex_id2name(sd->mapindex), MAP_NAME_LENGTH); - m_id = iMap->mapindex2mapid(sd->mapindex); + m_id = map->mapindex2mapid(sd->mapindex); } else { - m_id = iMap->mapname2mapid(mapname); + m_id = map->mapname2mapid(mapname); } if (m_id < 0) { clif->message(fd, msg_txt(1)); // Map not found. return false; } - m_index = mapindex_name2id(mapname); //This one shouldn't fail since the previous seek did not. + m_index = mapindex->name2id(mapname); //This one shouldn't fail since the previous seek did not. clif->message(fd, msg_txt(1039)); // ------ Map Info ------ @@ -3809,135 +3701,135 @@ ACMD(mapinfo) { if( pl_sd->mapindex == m_index ) { if( pl_sd->state.vending ) vend_num++; - else if( (cd = (struct chat_data*)iMap->id2bl(pl_sd->chatID)) != NULL && cd->usersd[0] == pl_sd ) + else if( (cd = (struct chat_data*)map->id2bl(pl_sd->chatID)) != NULL && cd->usersd[0] == pl_sd ) chat_num++; } } mapit->free(iter); - sprintf(atcmd_output, msg_txt(1040), mapname, map[m_id].zone->name, map[m_id].users, map[m_id].npc_num, chat_num, vend_num); // Map: %s (Zone:%s) | Players: %d | NPCs: %d | Chats: %d | Vendings: %d + sprintf(atcmd_output, msg_txt(1040), mapname, map->list[m_id].zone->name, map->list[m_id].users, map->list[m_id].npc_num, chat_num, vend_num); // Map: %s (Zone:%s) | Players: %d | NPCs: %d | Chats: %d | Vendings: %d clif->message(fd, atcmd_output); clif->message(fd, msg_txt(1041)); // ------ Map Flags ------ - if (map[m_id].flag.town) + if (map->list[m_id].flag.town) clif->message(fd, msg_txt(1042)); // Town Map - if (battle_config.autotrade_mapflag == map[m_id].flag.autotrade) + if (battle_config.autotrade_mapflag == map->list[m_id].flag.autotrade) clif->message(fd, msg_txt(1043)); // Autotrade Enabled else clif->message(fd, msg_txt(1044)); // Autotrade Disabled - if (map[m_id].flag.battleground) + if (map->list[m_id].flag.battleground) clif->message(fd, msg_txt(1045)); // Battlegrounds ON strcpy(atcmd_output,msg_txt(1046)); // PvP Flags: - if (map[m_id].flag.pvp) + if (map->list[m_id].flag.pvp) strcat(atcmd_output, msg_txt(1047)); // Pvp ON | - if (map[m_id].flag.pvp_noguild) + if (map->list[m_id].flag.pvp_noguild) strcat(atcmd_output, msg_txt(1048)); // NoGuild | - if (map[m_id].flag.pvp_noparty) + if (map->list[m_id].flag.pvp_noparty) strcat(atcmd_output, msg_txt(1049)); // NoParty | - if (map[m_id].flag.pvp_nightmaredrop) + if (map->list[m_id].flag.pvp_nightmaredrop) strcat(atcmd_output, msg_txt(1050)); // NightmareDrop | - if (map[m_id].flag.pvp_nocalcrank) + if (map->list[m_id].flag.pvp_nocalcrank) strcat(atcmd_output, msg_txt(1051)); // NoCalcRank | clif->message(fd, atcmd_output); strcpy(atcmd_output,msg_txt(1052)); // GvG Flags: - if (map[m_id].flag.gvg) + if (map->list[m_id].flag.gvg) strcat(atcmd_output, msg_txt(1053)); // GvG ON | - if (map[m_id].flag.gvg_dungeon) + if (map->list[m_id].flag.gvg_dungeon) strcat(atcmd_output, msg_txt(1054)); // GvG Dungeon | - if (map[m_id].flag.gvg_castle) + if (map->list[m_id].flag.gvg_castle) strcat(atcmd_output, msg_txt(1055)); // GvG Castle | - if (map[m_id].flag.gvg_noparty) + if (map->list[m_id].flag.gvg_noparty) strcat(atcmd_output, msg_txt(1056)); // NoParty | clif->message(fd, atcmd_output); strcpy(atcmd_output,msg_txt(1057)); // Teleport Flags: - if (map[m_id].flag.noteleport) + if (map->list[m_id].flag.noteleport) strcat(atcmd_output, msg_txt(1058)); // NoTeleport | - if (map[m_id].flag.monster_noteleport) + if (map->list[m_id].flag.monster_noteleport) strcat(atcmd_output, msg_txt(1059)); // Monster NoTeleport | - if (map[m_id].flag.nowarp) + if (map->list[m_id].flag.nowarp) strcat(atcmd_output, msg_txt(1060)); // NoWarp | - if (map[m_id].flag.nowarpto) + if (map->list[m_id].flag.nowarpto) strcat(atcmd_output, msg_txt(1061)); // NoWarpTo | - if (map[m_id].flag.noreturn) + if (map->list[m_id].flag.noreturn) strcat(atcmd_output, msg_txt(1062)); // NoReturn | - if (map[m_id].flag.nomemo) + if (map->list[m_id].flag.nomemo) strcat(atcmd_output, msg_txt(1064)); // NoMemo | clif->message(fd, atcmd_output); sprintf(atcmd_output, msg_txt(1065), // No Exp Penalty: %s | No Zeny Penalty: %s - (map[m_id].flag.noexppenalty) ? msg_txt(1066) : msg_txt(1067), (map[m_id].flag.nozenypenalty) ? msg_txt(1066) : msg_txt(1067)); // On / Off + (map->list[m_id].flag.noexppenalty) ? msg_txt(1066) : msg_txt(1067), + (map->list[m_id].flag.nozenypenalty) ? msg_txt(1066) : msg_txt(1067)); // On / Off clif->message(fd, atcmd_output); - if (map[m_id].flag.nosave) { - if (!map[m_id].save.map) + if (map->list[m_id].flag.nosave) { + if (!map->list[m_id].save.map) clif->message(fd, msg_txt(1068)); // No Save (Return to last Save Point) - else if (map[m_id].save.x == -1 || map[m_id].save.y == -1 ) { - sprintf(atcmd_output, msg_txt(1069), mapindex_id2name(map[m_id].save.map)); // No Save, Save Point: %s,Random + else if (map->list[m_id].save.x == -1 || map->list[m_id].save.y == -1 ) { + sprintf(atcmd_output, msg_txt(1069), mapindex_id2name(map->list[m_id].save.map)); // No Save, Save Point: %s,Random clif->message(fd, atcmd_output); - } - else { + } else { sprintf(atcmd_output, msg_txt(1070), // No Save, Save Point: %s,%d,%d - mapindex_id2name(map[m_id].save.map),map[m_id].save.x,map[m_id].save.y); + mapindex_id2name(map->list[m_id].save.map),map->list[m_id].save.x,map->list[m_id].save.y); clif->message(fd, atcmd_output); } } strcpy(atcmd_output,msg_txt(1071)); // Weather Flags: - if (map[m_id].flag.snow) + if (map->list[m_id].flag.snow) strcat(atcmd_output, msg_txt(1072)); // Snow | - if (map[m_id].flag.fog) + if (map->list[m_id].flag.fog) strcat(atcmd_output, msg_txt(1073)); // Fog | - if (map[m_id].flag.sakura) + if (map->list[m_id].flag.sakura) strcat(atcmd_output, msg_txt(1074)); // Sakura | - if (map[m_id].flag.clouds) + if (map->list[m_id].flag.clouds) strcat(atcmd_output, msg_txt(1075)); // Clouds | - if (map[m_id].flag.clouds2) + if (map->list[m_id].flag.clouds2) strcat(atcmd_output, msg_txt(1076)); // Clouds2 | - if (map[m_id].flag.fireworks) + if (map->list[m_id].flag.fireworks) strcat(atcmd_output, msg_txt(1077)); // Fireworks | - if (map[m_id].flag.leaves) + if (map->list[m_id].flag.leaves) strcat(atcmd_output, msg_txt(1078)); // Leaves | - if (map[m_id].flag.nightenabled) + if (map->list[m_id].flag.nightenabled) strcat(atcmd_output, msg_txt(1080)); // Displays Night | clif->message(fd, atcmd_output); strcpy(atcmd_output,msg_txt(1081)); // Other Flags: - if (map[m_id].flag.nobranch) + if (map->list[m_id].flag.nobranch) strcat(atcmd_output, msg_txt(1082)); // NoBranch | - if (map[m_id].flag.notrade) + if (map->list[m_id].flag.notrade) strcat(atcmd_output, msg_txt(1083)); // NoTrade | - if (map[m_id].flag.novending) + if (map->list[m_id].flag.novending) strcat(atcmd_output, msg_txt(1084)); // NoVending | - if (map[m_id].flag.nodrop) + if (map->list[m_id].flag.nodrop) strcat(atcmd_output, msg_txt(1085)); // NoDrop | - if (map[m_id].flag.noskill) + if (map->list[m_id].flag.noskill) strcat(atcmd_output, msg_txt(1086)); // NoSkill | - if (map[m_id].flag.noicewall) + if (map->list[m_id].flag.noicewall) strcat(atcmd_output, msg_txt(1087)); // NoIcewall | - if (map[m_id].flag.allowks) + if (map->list[m_id].flag.allowks) strcat(atcmd_output, msg_txt(1088)); // AllowKS | - if (map[m_id].flag.reset) + if (map->list[m_id].flag.reset) strcat(atcmd_output, msg_txt(1089)); // Reset | clif->message(fd, atcmd_output); strcpy(atcmd_output,msg_txt(1090)); // Other Flags: - if (map[m_id].nocommand) + if (map->list[m_id].nocommand) strcat(atcmd_output, msg_txt(1091)); // NoCommand | - if (map[m_id].flag.nobaseexp) + if (map->list[m_id].flag.nobaseexp) strcat(atcmd_output, msg_txt(1092)); // NoBaseEXP | - if (map[m_id].flag.nojobexp) + if (map->list[m_id].flag.nojobexp) strcat(atcmd_output, msg_txt(1093)); // NoJobEXP | - if (map[m_id].flag.nomobloot) + if (map->list[m_id].flag.nomobloot) strcat(atcmd_output, msg_txt(1094)); // NoMobLoot | - if (map[m_id].flag.nomvploot) + if (map->list[m_id].flag.nomvploot) strcat(atcmd_output, msg_txt(1095)); // NoMVPLoot | - if (map[m_id].flag.partylock) + if (map->list[m_id].flag.partylock) strcat(atcmd_output, msg_txt(1096)); // PartyLock | - if (map[m_id].flag.guildlock) + if (map->list[m_id].flag.guildlock) strcat(atcmd_output, msg_txt(1097)); // GuildLock | clif->message(fd, atcmd_output); @@ -3960,9 +3852,8 @@ ACMD(mapinfo) { break; case 2: clif->message(fd, msg_txt(1100)); // ----- NPCs in Map ----- - for (i = 0; i < map[m_id].npc_num;) - { - nd = map[m_id].npc[i]; + for (i = 0; i < map->list[m_id].npc_num;) { + nd = map->list[m_id].npc[i]; switch(nd->dir) { case 0: strcpy(direction, msg_txt(1101)); break; // North case 1: strcpy(direction, msg_txt(1102)); break; // North West @@ -3989,7 +3880,7 @@ ACMD(mapinfo) { iter = mapit_getallusers(); for( pl_sd = (TBL_PC*)mapit->first(iter); mapit->exists(iter); pl_sd = (TBL_PC*)mapit->next(iter) ) { - if ((cd = (struct chat_data*)iMap->id2bl(pl_sd->chatID)) != NULL && + if ((cd = (struct chat_data*)map->id2bl(pl_sd->chatID)) != NULL && pl_sd->mapindex == m_index && cd->usersd[0] == pl_sd) { @@ -4006,7 +3897,6 @@ ACMD(mapinfo) { default: // normally impossible to arrive here clif->message(fd, msg_txt(1118)); // Please enter at least one valid list number (usage: @mapinfo <0-3> <map>). return false; - break; } return true; @@ -4017,14 +3907,22 @@ ACMD(mapinfo) { *------------------------------------------*/ ACMD(mount_peco) { - nullpo_retr(-1, sd); - if (sd->disguise != -1) { clif->message(fd, msg_txt(212)); // Cannot mount while in disguise. return false; } - if( (sd->class_&MAPID_THIRDMASK) == MAPID_RUNE_KNIGHT && pc->checkskill(sd,RK_DRAGONTRAINING) > 0 ) { + if( sd->sc.data[SC_ALL_RIDING] ) { + clif->message(fd, msg_txt(1476)); // You are already mounting something else + return false; + } + + if( (sd->class_&MAPID_THIRDMASK) == MAPID_RUNE_KNIGHT ) { + if( !pc->checkskill(sd,RK_DRAGONTRAINING) ) { + sprintf(atcmd_output, msg_txt(213), skill->get_desc(RK_DRAGONTRAINING)); // You need %s to mount! + clif->message(fd, atcmd_output); + return false; + } if( !(sd->sc.option&OPTION_DRAGON1) ) { clif->message(sd->fd,msg_txt(1119)); // You have mounted your Dragon. pc->setoption(sd, sd->sc.option|OPTION_DRAGON1); @@ -4034,7 +3932,12 @@ ACMD(mount_peco) } return true; } - if( (sd->class_&MAPID_THIRDMASK) == MAPID_RANGER && pc->checkskill(sd,RA_WUGRIDER) > 0 ) { + if( (sd->class_&MAPID_THIRDMASK) == MAPID_RANGER ) { + if( !pc->checkskill(sd,RA_WUGRIDER) ) { + sprintf(atcmd_output, msg_txt(213), skill->get_desc(RA_WUGRIDER)); // You need %s to mount! + clif->message(fd, atcmd_output); + return false; + } if( !pc_isridingwug(sd) ) { clif->message(sd->fd,msg_txt(1121)); // You have mounted your Warg. pc->setoption(sd, sd->sc.option|OPTION_WUGRIDER); @@ -4054,36 +3957,36 @@ ACMD(mount_peco) } return true; } - if (!pc_isriding(sd)) { // if actually no peco - - if (!pc->checkskill(sd, KN_RIDING)) { - clif->message(fd, msg_txt(213)); // You can not mount a Peco Peco with your current job. - return false; + if( sd->class_&MAPID_SWORDMAN && sd->class_&JOBL_2 ) { + if( !pc_isriding(sd) ) { // if actually no peco + if (!pc->checkskill(sd, KN_RIDING)) { + sprintf(atcmd_output, msg_txt(213), skill->get_desc(KN_RIDING)); // You need %s to mount! + clif->message(fd, atcmd_output); + return false; + } + pc->setoption(sd, sd->sc.option | OPTION_RIDING); + clif->message(fd, msg_txt(102)); // You have mounted a Peco Peco. + } else {//Dismount + pc->setoption(sd, sd->sc.option & ~OPTION_RIDING); + clif->message(fd, msg_txt(214)); // You have released your Peco Peco. } - - pc->setoption(sd, sd->sc.option | OPTION_RIDING); - clif->message(fd, msg_txt(102)); // You have mounted a Peco Peco. - } else {//Dismount - pc->setoption(sd, sd->sc.option & ~OPTION_RIDING); - clif->message(fd, msg_txt(214)); // You have released your Peco Peco. + return true; } - - return true; + clif->message(fd, msg_txt(215)); // Your class can't mount! + return false; } /*========================================== *Spy Commands by Syrus22 *------------------------------------------*/ -ACMD(guildspy) -{ +ACMD(guildspy) { char guild_name[NAME_LENGTH]; struct guild *g; - nullpo_retr(-1, sd); memset(guild_name, '\0', sizeof(guild_name)); memset(atcmd_output, '\0', sizeof(atcmd_output)); - if (!iMap->enable_spy) + if (!map->enable_spy) { clif->message(fd, msg_txt(1125)); // The mapserver has spy command support disabled. return false; @@ -4115,16 +4018,14 @@ ACMD(guildspy) /*========================================== * *------------------------------------------*/ -ACMD(partyspy) -{ +ACMD(partyspy) { char party_name[NAME_LENGTH]; struct party_data *p; - nullpo_retr(-1, sd); memset(party_name, '\0', sizeof(party_name)); memset(atcmd_output, '\0', sizeof(atcmd_output)); - if (!iMap->enable_spy) + if (!map->enable_spy) { clif->message(fd, msg_txt(1125)); // The mapserver has spy command support disabled. return false; @@ -4160,7 +4061,6 @@ ACMD(partyspy) ACMD(repairall) { int count, i; - nullpo_retr(-1, sd); count = 0; for (i = 0; i < MAX_INVENTORY; i++) { @@ -4186,10 +4086,8 @@ ACMD(repairall) /*========================================== * @nuke [Valaris] *------------------------------------------*/ -ACMD(nuke) -{ +ACMD(nuke) { struct map_session_data *pl_sd; - nullpo_retr(-1, sd); memset(atcmd_player_name, '\0', sizeof(atcmd_player_name)); @@ -4198,12 +4096,12 @@ ACMD(nuke) return false; } - if ((pl_sd = iMap->nick2sd(atcmd_player_name)) != NULL) { - if (pc->get_group_level(sd) >= pc->get_group_level(pl_sd)) { // you can kill only lower or same GM level - skill->castend_nodamage_id(&pl_sd->bl, &pl_sd->bl, NPC_SELFDESTRUCTION, 99, iTimer->gettick(), 0); + if ((pl_sd = map->nick2sd(atcmd_player_name)) != NULL) { + if (pc_get_group_level(sd) >= pc_get_group_level(pl_sd)) { // you can kill only lower or same GM level + skill->castend_nodamage_id(&pl_sd->bl, &pl_sd->bl, NPC_SELFDESTRUCTION, 99, timer->gettick(), 0); clif->message(fd, msg_txt(109)); // Player has been nuked! } else { - clif->message(fd, msg_txt(81)); // Your GM level don't authorise you to do this action on this player. + clif->message(fd, msg_txt(81)); // Your GM level don't authorize you to do this action on this player. return false; } } else { @@ -4217,13 +4115,10 @@ ACMD(nuke) /*========================================== * @tonpc *------------------------------------------*/ -ACMD(tonpc) -{ +ACMD(tonpc) { char npcname[NAME_LENGTH+1]; struct npc_data *nd; - - nullpo_retr(-1, sd); - + memset(npcname, 0, sizeof(npcname)); if (!message || !*message || sscanf(message, "%23[^\n]", npcname) < 1) { @@ -4231,8 +4126,8 @@ ACMD(tonpc) return false; } - if ((nd = npc_name2id(npcname)) != NULL) { - if (pc->setpos(sd, map_id2index(nd->bl.m), nd->bl.x, nd->bl.y, CLR_TELEPORT) == 0) + if ((nd = npc->name2id(npcname)) != NULL) { + if (nd->bl.m != -1 && pc->setpos(sd, map_id2index(nd->bl.m), nd->bl.x, nd->bl.y, CLR_TELEPORT) == 0) clif->message(fd, msg_txt(0)); // Warped. else return false; @@ -4250,7 +4145,6 @@ ACMD(tonpc) ACMD(shownpc) { char NPCname[NAME_LENGTH+1]; - nullpo_retr(-1, sd); memset(NPCname, '\0', sizeof(NPCname)); @@ -4259,8 +4153,8 @@ ACMD(shownpc) return false; } - if (npc_name2id(NPCname) != NULL) { - npc_enable(NPCname, 1); + if (npc->name2id(NPCname) != NULL) { + npc->enable(NPCname, 1); clif->message(fd, msg_txt(110)); // Npc Enabled. } else { clif->message(fd, msg_txt(111)); // This NPC doesn't exist. @@ -4276,7 +4170,6 @@ ACMD(shownpc) ACMD(hidenpc) { char NPCname[NAME_LENGTH+1]; - nullpo_retr(-1, sd); memset(NPCname, '\0', sizeof(NPCname)); @@ -4285,12 +4178,12 @@ ACMD(hidenpc) return false; } - if (npc_name2id(NPCname) == NULL) { + if (npc->name2id(NPCname) == NULL) { clif->message(fd, msg_txt(111)); // This NPC doesn't exist. return false; } - npc_enable(NPCname, 0); + npc->enable(NPCname, 0); clif->message(fd, msg_txt(112)); // Npc Disabled. return true; } @@ -4312,9 +4205,9 @@ ACMD(loadnpc) fclose(fp); // add to list of script sources and run it - npc_addsrcfile(message); - npc_parsesrcfile(message,true); - npc_read_event_script(); + npc->addsrcfile(message); + npc->parsesrcfile(message,true); + npc->read_event_script(); clif->message(fd, msg_txt(262)); @@ -4325,7 +4218,6 @@ ACMD(unloadnpc) { struct npc_data *nd; char NPCname[NAME_LENGTH+1]; - nullpo_retr(-1, sd); memset(NPCname, '\0', sizeof(NPCname)); @@ -4334,14 +4226,14 @@ ACMD(unloadnpc) return false; } - if ((nd = npc_name2id(NPCname)) == NULL) { + if ((nd = npc->name2id(NPCname)) == NULL) { clif->message(fd, msg_txt(111)); // This NPC doesn't exist. return false; } - npc_unload_duplicates(nd); - npc_unload(nd,true); - npc_read_event_script(); + npc->unload_duplicates(nd); + npc->unload(nd,true); + npc->read_event_script(); clif->message(fd, msg_txt(112)); // Npc Disabled. return true; } @@ -4352,10 +4244,9 @@ ACMD(unloadnpc) char* txt_time(unsigned int duration) { int days, hours, minutes, seconds; - char temp[CHAT_SIZE_MAX]; static char temp1[CHAT_SIZE_MAX]; + int tlen = 0; - memset(temp, '\0', sizeof(temp)); memset(temp1, '\0', sizeof(temp1)); days = duration / (60 * 60 * 24); @@ -4366,22 +4257,22 @@ char* txt_time(unsigned int duration) seconds = duration - (60 * minutes); if (days == 1) - sprintf(temp, msg_txt(219), days); // %d day + tlen += sprintf(tlen + temp1, msg_txt(219), days); // %d day else if (days > 1) - sprintf(temp, msg_txt(220), days); // %d days + tlen += sprintf(tlen + temp1, msg_txt(220), days); // %d days if (hours == 1) - sprintf(temp1, msg_txt(221), temp, hours); // %s %d hour + tlen += sprintf(tlen + temp1, msg_txt(221), hours); // %d hour else if (hours > 1) - sprintf(temp1, msg_txt(222), temp, hours); // %s %d hours + tlen += sprintf(tlen + temp1, msg_txt(222), hours); // %d hours if (minutes < 2) - sprintf(temp, msg_txt(223), temp1, minutes); // %s %d minute + tlen += sprintf(tlen + temp1, msg_txt(223), minutes); // %d minute else - sprintf(temp, msg_txt(224), temp1, minutes); // %s %d minutes + tlen += sprintf(tlen + temp1, msg_txt(224), minutes); // %d minutes if (seconds == 1) - sprintf(temp1, msg_txt(225), temp, seconds); // %s and %d second + sprintf(tlen + temp1, msg_txt(225), seconds); // and %d second else if (seconds > 1) - sprintf(temp1, msg_txt(226), temp, seconds); // %s and %d seconds - + sprintf(tlen + temp1, msg_txt(226), seconds); // and %d seconds + return temp1; } @@ -4389,14 +4280,10 @@ char* txt_time(unsigned int duration) * @time/@date/@serverdate/@servertime: Display the date/time of the server (by [Yor] * Calculation management of GM modification (@day/@night GM commands) is done *------------------------------------------*/ -ACMD(servertime) -{ - const struct TimerData * timer_data; - const struct TimerData * timer_data2; +ACMD(servertime) { 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, ... char temp[CHAT_SIZE_MAX]; - nullpo_retr(-1, sd); memset(temp, '\0', sizeof(temp)); @@ -4406,62 +4293,49 @@ ACMD(servertime) strftime(temp, sizeof(temp)-1, msg_txt(230), datetime); // Server time (normal time): %A, %B %d %Y %X. clif->message(fd, temp); - if (battle_config.night_duration == 0 && battle_config.day_duration == 0) { - if (iMap->night_flag == 0) + if (pc->day_timer_tid != INVALID_TIMER && pc->night_timer_tid != INVALID_TIMER) { + const struct TimerData * timer_data = timer->get(pc->night_timer_tid); + const struct TimerData * timer_data2 = timer->get(pc->day_timer_tid); + + if (map->night_flag == 0) { + sprintf(temp, msg_txt(235), // Game time: The game is actually in daylight for %s. + txt_time((unsigned int)(DIFF_TICK(timer_data->tick,timer->gettick())/1000))); + clif->message(fd, temp); + if (DIFF_TICK(timer_data->tick, timer_data2->tick) > 0) + sprintf(temp, msg_txt(237), // Game time: After, the game will be in night for %s. + txt_time((unsigned int)(DIFF_TICK(timer_data->interval,DIFF_TICK(timer_data->tick,timer_data2->tick)) / 1000))); + else + sprintf(temp, msg_txt(237), // Game time: After, the game will be in night for %s. + txt_time((unsigned int)(DIFF_TICK(timer_data2->tick,timer_data->tick)/1000))); + clif->message(fd, temp); + } else { + sprintf(temp, msg_txt(233), // Game time: The game is actually in night for %s. + txt_time((unsigned int)(DIFF_TICK(timer_data2->tick,timer->gettick()) / 1000))); + clif->message(fd, temp); + if (DIFF_TICK(timer_data2->tick,timer_data->tick) > 0) + sprintf(temp, msg_txt(239), // Game time: After, the game will be in daylight for %s. + txt_time((unsigned int)((timer_data2->interval - DIFF_TICK(timer_data2->tick, timer_data->tick)) / 1000))); + else + sprintf(temp, msg_txt(239), // Game time: After, the game will be in daylight for %s. + txt_time((unsigned int)(DIFF_TICK(timer_data->tick, timer_data2->tick) / 1000))); + clif->message(fd, temp); + } + sprintf(temp, msg_txt(238), txt_time(timer_data2->interval / 1000)); // Game time: A day cycle has a normal duration of %s. + clif->message(fd, temp); + } else { + if (map->night_flag == 0) clif->message(fd, msg_txt(231)); // Game time: The game is in permanent daylight. else clif->message(fd, msg_txt(232)); // Game time: The game is in permanent night. - } else if (battle_config.night_duration == 0) - if (iMap->night_flag == 1) { // we start with night - timer_data = iTimer->get_timer(pc->day_timer_tid); - sprintf(temp, msg_txt(233), txt_time(DIFF_TICK(timer_data->tick,iTimer->gettick())/1000)); // Game time: The game is actualy in night for %s. - clif->message(fd, temp); - clif->message(fd, msg_txt(234)); // Game time: After, the game will be in permanent daylight. - } else - clif->message(fd, msg_txt(231)); // Game time: The game is in permanent daylight. - else if (battle_config.day_duration == 0) - if (iMap->night_flag == 0) { // we start with day - timer_data = iTimer->get_timer(pc->night_timer_tid); - sprintf(temp, msg_txt(235), txt_time(DIFF_TICK(timer_data->tick,iTimer->gettick())/1000)); // Game time: The game is actualy in daylight for %s. - clif->message(fd, temp); - clif->message(fd, msg_txt(236)); // Game time: After, the game will be in permanent night. - } else - clif->message(fd, msg_txt(232)); // Game time: The game is in permanent night. - else { - if (iMap->night_flag == 0) { - timer_data = iTimer->get_timer(pc->night_timer_tid); - timer_data2 = iTimer->get_timer(pc->day_timer_tid); - sprintf(temp, msg_txt(235), txt_time(DIFF_TICK(timer_data->tick,iTimer->gettick())/1000)); // Game time: The game is actualy in daylight for %s. - clif->message(fd, temp); - if (DIFF_TICK(timer_data->tick, timer_data2->tick) > 0) - sprintf(temp, msg_txt(237), txt_time(DIFF_TICK(timer_data->interval,DIFF_TICK(timer_data->tick,timer_data2->tick)) / 1000)); // Game time: After, the game will be in night for %s. - else - sprintf(temp, msg_txt(237), txt_time(DIFF_TICK(timer_data2->tick,timer_data->tick)/1000)); // Game time: After, the game will be in night for %s. - clif->message(fd, temp); - sprintf(temp, msg_txt(238), txt_time(timer_data->interval / 1000)); // Game time: A day cycle has a normal duration of %s. - clif->message(fd, temp); - } else { - timer_data = iTimer->get_timer(pc->day_timer_tid); - timer_data2 = iTimer->get_timer(pc->night_timer_tid); - sprintf(temp, msg_txt(233), txt_time(DIFF_TICK(timer_data->tick,iTimer->gettick()) / 1000)); // Game time: The game is actualy in night for %s. - clif->message(fd, temp); - if (DIFF_TICK(timer_data->tick,timer_data2->tick) > 0) - sprintf(temp, msg_txt(239), txt_time((timer_data->interval - DIFF_TICK(timer_data->tick, timer_data2->tick)) / 1000)); // Game time: After, the game will be in daylight for %s. - else - sprintf(temp, msg_txt(239), txt_time(DIFF_TICK(timer_data2->tick, timer_data->tick) / 1000)); // Game time: After, the game will be in daylight for %s. - clif->message(fd, temp); - sprintf(temp, msg_txt(238), txt_time(timer_data->interval / 1000)); // Game time: A day cycle has a normal duration of %s. - clif->message(fd, temp); - } - } + } return true; } //Added by Coltaro -//We're using this function here instead of using time_t so that it only counts player's jail time when he/she's online (and since the idea is to reduce the amount of minutes one by one in status_change_timer...). +//We're using this function here instead of using time_t so that it only counts player's jail time when he/she's online (and since the idea is to reduce the amount of minutes one by one in status->change_timer...). //Well, using time_t could still work but for some reason that looks like more coding x_x -static void get_jail_time(int jailtime, int* year, int* month, int* day, int* hour, int* minute) +void get_jail_time(int jailtime, int* year, int* month, int* day, int* hour, int* minute) { const int factor_year = 518400; //12*30*24*60 = 518400 const int factor_month = 43200; //30*24*60 = 43200 @@ -4490,12 +4364,10 @@ static void get_jail_time(int jailtime, int* year, int* month, int* day, int* ho * @jail <char_name> by [Yor] * Special warp! No check with nowarp and nowarpto flag *------------------------------------------*/ -ACMD(jail) -{ +ACMD(jail) { struct map_session_data *pl_sd; int x, y; unsigned short m_index; - nullpo_retr(-1, sd); memset(atcmd_player_name, '\0', sizeof(atcmd_player_name)); @@ -4504,14 +4376,14 @@ ACMD(jail) return false; } - if ((pl_sd = iMap->nick2sd(atcmd_player_name)) == NULL) { + if ((pl_sd = map->nick2sd(atcmd_player_name)) == NULL) { clif->message(fd, msg_txt(3)); // Character not found. return false; } - if (pc->get_group_level(sd) < pc->get_group_level(pl_sd)) + if (pc_get_group_level(sd) < pc_get_group_level(pl_sd)) { // you can jail only lower or same GM - clif->message(fd, msg_txt(81)); // Your GM level don't authorise you to do this action on this player. + clif->message(fd, msg_txt(81)); // Your GM level don't authorize you to do this action on this player. return false; } @@ -4523,20 +4395,20 @@ ACMD(jail) switch(rnd() % 2) { //Jail Locations case 0: - m_index = mapindex_name2id(MAP_JAIL); + m_index = mapindex->name2id(MAP_JAIL); x = 24; y = 75; break; default: - m_index = mapindex_name2id(MAP_JAIL); + m_index = mapindex->name2id(MAP_JAIL); x = 49; y = 75; break; } //Duration of INT_MAX to specify infinity. - sc_start4(&pl_sd->bl,SC_JAILED,100,INT_MAX,m_index,x,y,1000); - clif->message(pl_sd->fd, msg_txt(117)); // GM has send you in jails. + sc_start4(NULL,&pl_sd->bl,SC_JAILED,100,INT_MAX,m_index,x,y,1000); + clif->message(pl_sd->fd, msg_txt(117)); // You have been jailed by a GM. clif->message(fd, msg_txt(118)); // Player warped in jails. return true; } @@ -4545,8 +4417,7 @@ ACMD(jail) * @unjail/@discharge <char_name> by [Yor] * Special warp! No check with nowarp and nowarpto flag *------------------------------------------*/ -ACMD(unjail) -{ +ACMD(unjail) { struct map_session_data *pl_sd; memset(atcmd_player_name, '\0', sizeof(atcmd_player_name)); @@ -4556,14 +4427,14 @@ ACMD(unjail) return false; } - if ((pl_sd = iMap->nick2sd(atcmd_player_name)) == NULL) { + if ((pl_sd = map->nick2sd(atcmd_player_name)) == NULL) { clif->message(fd, msg_txt(3)); // Character not found. return false; } - if (pc->get_group_level(sd) < pc->get_group_level(pl_sd)) { // you can jail only lower or same GM + if (pc_get_group_level(sd) < pc_get_group_level(pl_sd)) { // you can jail only lower or same GM - clif->message(fd, msg_txt(81)); // Your GM level don't authorise you to do this action on this player. + clif->message(fd, msg_txt(81)); // Your GM level don't authorize you to do this action on this player. return false; } @@ -4574,20 +4445,18 @@ ACMD(unjail) } //Reset jail time to 1 sec. - sc_start(&pl_sd->bl,SC_JAILED,100,1,1000); + sc_start(NULL,&pl_sd->bl,SC_JAILED,100,1,1000); clif->message(pl_sd->fd, msg_txt(120)); // A GM has discharged you from jail. clif->message(fd, msg_txt(121)); // Player unjailed. return true; } -ACMD(jailfor) -{ +ACMD(jailfor) { struct map_session_data *pl_sd = NULL; int year, month, day, hour, minute, value; char * modif_p; int jailtime = 0,x,y; short m_index = 0; - nullpo_retr(-1, sd); if (!message || !*message || sscanf(message, "%255s %23[^\n]",atcmd_output,atcmd_player_name) < 2) { clif->message(fd, msg_txt(400)); //Usage: @jailfor <time> <character name> @@ -4636,13 +4505,13 @@ ACMD(jailfor) return false; } - if ((pl_sd = iMap->nick2sd(atcmd_player_name)) == NULL) { + if ((pl_sd = map->nick2sd(atcmd_player_name)) == NULL) { clif->message(fd, msg_txt(3)); // Character not found. return false; } - if (pc->get_group_level(pl_sd) > pc->get_group_level(sd)) { - clif->message(fd, msg_txt(81)); // Your GM level don't authorise you to do this action on this player. + if (pc_get_group_level(pl_sd) > pc_get_group_level(sd)) { + clif->message(fd, msg_txt(81)); // Your GM level don't authorize you to do this action on this player. return false; } @@ -4663,7 +4532,7 @@ ACMD(jailfor) clif->message(pl_sd->fd, msg_txt(120)); // GM has discharge you. clif->message(fd, msg_txt(121)); // Player unjailed } else { - get_jail_time(jailtime,&year,&month,&day,&hour,&minute); + atcommand->get_jail_time(jailtime,&year,&month,&day,&hour,&minute); sprintf(atcmd_output,msg_txt(402),msg_txt(1137),year,month,day,hour,minute); //%s in jail for %d years, %d months, %d days, %d hours and %d minutes clif->message(pl_sd->fd, atcmd_output); sprintf(atcmd_output,msg_txt(402),msg_txt(1138),year,month,day,hour,minute); //This player is now in jail for %d years, %d months, %d days, %d hours and %d minutes @@ -4678,16 +4547,16 @@ ACMD(jailfor) switch(rnd()%2) { case 1: //Jail #1 - m_index = mapindex_name2id(MAP_JAIL); + m_index = mapindex->name2id(MAP_JAIL); x = 49; y = 75; break; default: //Default Jail - m_index = mapindex_name2id(MAP_JAIL); + m_index = mapindex->name2id(MAP_JAIL); x = 24; y = 75; break; } - sc_start4(&pl_sd->bl,SC_JAILED,100,jailtime,m_index,x,y,jailtime?60000:1000); //jailtime = 0: Time was reset to 0. Wait 1 second to warp player out (since it's done in status_change_timer). + sc_start4(NULL,&pl_sd->bl,SC_JAILED,100,jailtime,m_index,x,y,jailtime?60000:1000); //jailtime = 0: Time was reset to 0. Wait 1 second to warp player out (since it's done in status->change_timer). return true; } @@ -4697,8 +4566,6 @@ ACMD(jailtime) { int year, month, day, hour, minute; - nullpo_retr(-1, sd); - if (!sd->sc.data[SC_JAILED]) { clif->message(fd, msg_txt(1139)); // You are not in jail. return false; @@ -4715,7 +4582,7 @@ ACMD(jailtime) } //Get remaining jail time - get_jail_time(sd->sc.data[SC_JAILED]->val1,&year,&month,&day,&hour,&minute); + atcommand->get_jail_time(sd->sc.data[SC_JAILED]->val1,&year,&month,&day,&hour,&minute); sprintf(atcmd_output,msg_txt(402),msg_txt(1142),year,month,day,hour,minute); // You will remain in jail for %d years, %d months, %d days, %d hours and %d minutes clif->message(fd, atcmd_output); @@ -4729,7 +4596,6 @@ ACMD(jailtime) ACMD(disguise) { int id = 0; - nullpo_retr(-1, sd); if (!message || !*message) { clif->message(fd, msg_txt(1143)); // Please enter a Monster/NPC name/ID (usage: @disguise <name/ID>). @@ -4738,12 +4604,12 @@ ACMD(disguise) if ((id = atoi(message)) > 0) { //Acquired an ID - if (!mobdb_checkid(id) && !npcdb_checkid(id)) + if (!mob->db_checkid(id) && !npcdb_checkid(id)) id = 0; //Invalid id for either mobs or npcs. } else { //Acquired a Name - if ((id = mobdb_searchname(message)) == 0) + if ((id = mob->db_searchname(message)) == 0) { - struct npc_data* nd = npc_name2id(message); + struct npc_data* nd = npc->name2id(message); if (nd != NULL) id = nd->class_; } @@ -4760,7 +4626,13 @@ ACMD(disguise) clif->message(fd, msg_txt(1144)); // Character cannot be disguised while mounted. return false; } - + + if(sd->sc.data[SC_MONSTER_TRANSFORM]) + { + clif->message(fd, msg_txt(1487)); // Character cannot be disguised while in monster form. + return false; + } + pc->disguise(sd, id); clif->message(fd, msg_txt(122)); // Disguise applied. @@ -4775,17 +4647,16 @@ ACMD(disguiseall) int mob_id=0; struct map_session_data *pl_sd; struct s_mapiterator* iter; - nullpo_retr(-1, sd); if (!message || !*message) { clif->message(fd, msg_txt(1145)); // Please enter a Monster/NPC name/ID (usage: @disguiseall <name/ID>). return false; } - if ((mob_id = mobdb_searchname(message)) == 0) // check name first (to avoid possible name begining by a number) + if ((mob_id = mob->db_searchname(message)) == 0) // check name first (to avoid possible name begining by a number) mob_id = atoi(message); - if (!mobdb_checkid(mob_id) && !npcdb_checkid(mob_id)) { //if mob or npc... + if (!mob->db_checkid(mob_id) && !npcdb_checkid(mob_id)) { //if mob or npc... clif->message(fd, msg_txt(123)); // Monster/NPC name/id not found. return false; } @@ -4818,11 +4689,11 @@ ACMD(disguiseguild) } if( (id = atoi(monster)) > 0 ) { - if( !mobdb_checkid(id) && !npcdb_checkid(id) ) + if( !mob->db_checkid(id) && !npcdb_checkid(id) ) id = 0; } else { - if( (id = mobdb_searchname(monster)) == 0 ) { - struct npc_data* nd = npc_name2id(monster); + if( (id = mob->db_searchname(monster)) == 0 ) { + struct npc_data* nd = npc->name2id(monster); if( nd != NULL ) id = nd->class_; } @@ -4852,10 +4723,9 @@ ACMD(disguiseguild) *------------------------------------------*/ ACMD(undisguise) { - nullpo_retr(-1, sd); if (sd->disguise != -1) { pc->disguise(sd, -1); - clif->message(fd, msg_txt(124)); // Undisguise applied. + clif->message(fd, msg_txt(124)); // Disguise removed. } else { clif->message(fd, msg_txt(125)); // You're not disguised. return false; @@ -4870,7 +4740,6 @@ ACMD(undisguise) ACMD(undisguiseall) { struct map_session_data *pl_sd; struct s_mapiterator* iter; - nullpo_retr(-1, sd); iter = mapit_getallusers(); for( pl_sd = (TBL_PC*)mapit->first(iter); mapit->exists(iter); pl_sd = (TBL_PC*)mapit->next(iter) ) @@ -4878,7 +4747,7 @@ ACMD(undisguiseall) { pc->disguise(pl_sd, -1); mapit->free(iter); - clif->message(fd, msg_txt(124)); // Undisguise applied. + clif->message(fd, msg_txt(124)); // Disguise removed. return true; } @@ -4892,7 +4761,6 @@ ACMD(undisguiseguild) struct map_session_data *pl_sd; struct guild *g; int i; - nullpo_retr(-1, sd); memset(guild_name, '\0', sizeof(guild_name)); @@ -4910,7 +4778,7 @@ ACMD(undisguiseguild) if( (pl_sd = g->member[i].sd) && pl_sd->disguise != -1 ) pc->disguise(pl_sd, -1); - clif->message(fd, msg_txt(124)); // Undisguise applied. + clif->message(fd, msg_txt(124)); // Disguise removed. return true; } @@ -4922,7 +4790,7 @@ ACMD(exp) { char output[CHAT_SIZE_MAX]; double nextb, nextj; - nullpo_retr(-1, sd); + memset(output, '\0', sizeof(output)); nextb = pc->nextbaseexp(sd); @@ -4944,7 +4812,6 @@ ACMD(exp) *------------------------------------------*/ ACMD(broadcast) { - nullpo_retr(-1, sd); memset(atcmd_output, '\0', sizeof(atcmd_output)); @@ -4954,7 +4821,7 @@ ACMD(broadcast) } sprintf(atcmd_output, "%s: %s", sd->status.name, message); - intif_broadcast(atcmd_output, strlen(atcmd_output) + 1, 0); + intif->broadcast(atcmd_output, strlen(atcmd_output) + 1, BC_DEFAULT); return true; } @@ -4964,8 +4831,6 @@ ACMD(broadcast) *------------------------------------------*/ ACMD(localbroadcast) { - nullpo_retr(-1, sd); - memset(atcmd_output, '\0', sizeof(atcmd_output)); if (!message || !*message) { @@ -4975,7 +4840,7 @@ ACMD(localbroadcast) sprintf(atcmd_output, "%s: %s", sd->status.name, message); - clif->broadcast(&sd->bl, atcmd_output, strlen(atcmd_output) + 1, 0, ALL_SAMEMAP); + clif->broadcast(&sd->bl, atcmd_output, strlen(atcmd_output) + 1, BC_DEFAULT, ALL_SAMEMAP); return true; } @@ -4987,31 +4852,30 @@ ACMD(email) { char actual_email[100]; char new_email[100]; - nullpo_retr(-1, sd); memset(actual_email, '\0', sizeof(actual_email)); memset(new_email, '\0', sizeof(new_email)); if (!message || !*message || sscanf(message, "%99s %99s", actual_email, new_email) < 2) { - clif->message(fd, msg_txt(1151)); // Please enter 2 emails (usage: @email <actual@email> <new@email>). + clif->message(fd, msg_txt(1151)); // Please enter two e-mail addresses (usage: @email <current@email> <new@email>). return false; } if (e_mail_check(actual_email) == 0) { - clif->message(fd, msg_txt(144)); // Invalid actual email. If you have default e-mail, give a@a.com. + clif->message(fd, msg_txt(144)); // Invalid e-mail. If your email hasn't been set, use a@a.com. return false; } else if (e_mail_check(new_email) == 0) { - clif->message(fd, msg_txt(145)); // Invalid new email. Please enter a real e-mail. + clif->message(fd, msg_txt(145)); // Invalid new email. Please enter a real e-mail address. return false; } else if (strcmpi(new_email, "a@a.com") == 0) { - clif->message(fd, msg_txt(146)); // New email must be a real e-mail. + clif->message(fd, msg_txt(146)); // New email must be a real e-mail address. return false; } else if (strcmpi(actual_email, new_email) == 0) { - clif->message(fd, msg_txt(147)); // New email must be different of the actual e-mail. + clif->message(fd, msg_txt(147)); // New e-mail must be different from the current e-mail address. return false; } - chrif_changeemail(sd->status.account_id, actual_email, new_email); + chrif->changeemail(sd->status.account_id, actual_email, new_email); clif->message(fd, msg_txt(148)); // Information sended to login-server via char-server. return true; } @@ -5022,7 +4886,6 @@ ACMD(email) ACMD(effect) { int type = 0, flag = 0; - nullpo_retr(-1, sd); if (!message || !*message || sscanf(message, "%d", &type) < 1) { clif->message(fd, msg_txt(1152)); // Please enter an effect number (usage: @effect <effect number>). @@ -5040,7 +4903,6 @@ ACMD(effect) *------------------------------------------*/ ACMD(killer) { - nullpo_retr(-1, sd); sd->state.killer = !sd->state.killer; if(sd->state.killer) @@ -5056,16 +4918,14 @@ ACMD(killer) * @killable by MouseJstr * enable other people killing you *------------------------------------------*/ -ACMD(killable) -{ - nullpo_retr(-1, sd); +ACMD(killable) { sd->state.killable = !sd->state.killable; if(sd->state.killable) clif->message(fd, msg_txt(242)); else { clif->message(fd, msg_txt(288)); - iMap->foreachinrange(atcommand_stopattack,&sd->bl, AREA_SIZE, BL_CHAR, sd->bl.id); + map->foreachinrange(atcommand->stopattack,&sd->bl, AREA_SIZE, BL_CHAR, sd->bl.id); } return true; } @@ -5074,10 +4934,8 @@ ACMD(killable) * @skillon by MouseJstr * turn skills on for the map *------------------------------------------*/ -ACMD(skillon) -{ - nullpo_retr(-1, sd); - map[sd->bl.m].flag.noskill = 0; +ACMD(skillon) { + map->list[sd->bl.m].flag.noskill = 0; clif->message(fd, msg_txt(244)); return true; } @@ -5086,10 +4944,8 @@ ACMD(skillon) * @skilloff by MouseJstr * Turn skills off on the map *------------------------------------------*/ -ACMD(skilloff) -{ - nullpo_retr(-1, sd); - map[sd->bl.m].flag.noskill = 1; +ACMD(skilloff) { + map->list[sd->bl.m].flag.noskill = 1; clif->message(fd, msg_txt(243)); return true; } @@ -5098,11 +4954,10 @@ ACMD(skilloff) * @npcmove by MouseJstr * move a npc *------------------------------------------*/ -ACMD(npcmove) -{ +ACMD(npcmove) { int x = 0, y = 0, m; struct npc_data *nd = 0; - nullpo_retr(-1, sd); + memset(atcmd_player_name, '\0', sizeof atcmd_player_name); if (!message || !*message || sscanf(message, "%d %d %23[^\n]", &x, &y, atcmd_player_name) < 3) { @@ -5110,23 +4965,21 @@ ACMD(npcmove) return false; } - if ((nd = npc_name2id(atcmd_player_name)) == NULL) - { + if ((nd = npc->name2id(atcmd_player_name)) == NULL) { clif->message(fd, msg_txt(111)); // This NPC doesn't exist. return false; } - if ((m=nd->bl.m) < 0 || nd->bl.prev == NULL) - { - clif->message(fd, msg_txt(1154)); // NPC is not on this map. + if ((m=nd->bl.m) < 0 || nd->bl.prev == NULL) { + clif->message(fd, msg_txt(1154)); // NPC is not in this map. return false; //Not on a map. } - x = cap_value(x, 0, map[m].xs-1); - y = cap_value(y, 0, map[m].ys-1); - iMap->foreachinrange(clif->outsight, &nd->bl, AREA_SIZE, BL_PC, &nd->bl); - iMap->moveblock(&nd->bl, x, y, iTimer->gettick()); - iMap->foreachinrange(clif->insight, &nd->bl, AREA_SIZE, BL_PC, &nd->bl); + x = cap_value(x, 0, map->list[m].xs-1); + y = cap_value(y, 0, map->list[m].ys-1); + map->foreachinrange(clif->outsight, &nd->bl, AREA_SIZE, BL_PC, &nd->bl); + map->moveblock(&nd->bl, x, y, timer->gettick()); + map->foreachinrange(clif->insight, &nd->bl, AREA_SIZE, BL_PC, &nd->bl); clif->message(fd, msg_txt(1155)); // NPC moved. return true; @@ -5143,7 +4996,6 @@ ACMD(addwarp) unsigned short m; struct npc_data* nd; - nullpo_retr(-1, sd); memset(warpname, '\0', sizeof(warpname)); if (!message || !*message || sscanf(message, "%31s %d %d %23[^\n]", mapname, &x, &y, warpname) < 4) { @@ -5151,7 +5003,7 @@ ACMD(addwarp) return false; } - m = mapindex_name2id(mapname); + m = mapindex->name2id(mapname); if( m == 0 ) { sprintf(atcmd_output, msg_txt(1157), mapname); // Unknown map '%s'. @@ -5159,7 +5011,7 @@ ACMD(addwarp) return false; } - nd = npc_add_warp(warpname, sd->bl.m, sd->bl.x, sd->bl.y, 2, 2, m, x, y); + nd = npc->add_warp(warpname, sd->bl.m, sd->bl.x, sd->bl.y, 2, 2, m, x, y); if( nd == NULL ) return false; @@ -5172,10 +5024,8 @@ ACMD(addwarp) * @follow by [MouseJstr] * Follow a player .. staying no more then 5 spaces away *------------------------------------------*/ -ACMD(follow) -{ +ACMD(follow) { struct map_session_data *pl_sd = NULL; - nullpo_retr(-1, sd); if (!message || !*message) { if (sd->followtarget == -1) @@ -5186,7 +5036,7 @@ ACMD(follow) return true; } - if ( (pl_sd = iMap->nick2sd((char *)message)) == NULL ) + if ( (pl_sd = map->nick2sd((char *)message)) == NULL ) { clif->message(fd, msg_txt(3)); // Character not found. return false; @@ -5211,7 +5061,7 @@ ACMD(follow) ACMD(dropall) { int i; - nullpo_retr(-1, sd); + for (i = 0; i < MAX_INVENTORY; i++) { if (sd->status.inventory[i].amount) { if(sd->status.inventory[i].equip != 0) @@ -5229,11 +5079,10 @@ ACMD(dropall) ACMD(storeall) { int i; - nullpo_retr(-1, sd); if (sd->state.storage_flag != 1) { //Open storage. - if( storage_storageopen(sd) == 1 ) { + if( storage->open(sd) == 1 ) { clif->message(fd, msg_txt(1161)); // You currently cannot open your storage. return false; } @@ -5243,10 +5092,10 @@ ACMD(storeall) if (sd->status.inventory[i].amount) { if(sd->status.inventory[i].equip != 0) pc->unequipitem(sd, i, 3); - storage_storageadd(sd, i, sd->status.inventory[i].amount); + storage->add(sd, i, sd->status.inventory[i].amount); } } - storage_storageclose(sd); + storage->close(sd); clif->message(fd, msg_txt(1162)); // All items stored. return true; @@ -5255,7 +5104,6 @@ ACMD(storeall) ACMD(clearstorage) { int i, j; - nullpo_retr(-1, sd); if (sd->state.storage_flag == 1) { clif->message(fd, msg_txt(250)); @@ -5264,9 +5112,9 @@ ACMD(clearstorage) j = sd->status.storage.storage_amount; for (i = 0; i < j; ++i) { - storage_delitem(sd, i, sd->status.storage.items[i].amount); + storage->delitem(sd, i, sd->status.storage.items[i].amount); } - storage_storageclose(sd); + storage->close(sd); clif->message(fd, msg_txt(1394)); // Your storage was cleaned. return true; @@ -5276,8 +5124,7 @@ ACMD(cleargstorage) { int i, j; struct guild *g; - struct guild_storage *gstorage; - nullpo_retr(-1, sd); + struct guild_storage *guild_storage; g = sd->guild; @@ -5296,18 +5143,18 @@ ACMD(cleargstorage) return false; } - gstorage = guild2storage2(sd->status.guild_id); - if (gstorage == NULL) {// Doesn't have opened @gstorage yet, so we skip the deletion since *shouldn't* have any item there. + guild_storage = gstorage->id2storage2(sd->status.guild_id); + if (guild_storage == NULL) {// Doesn't have opened @gstorage yet, so we skip the deletion since *shouldn't* have any item there. return false; } - j = gstorage->storage_amount; - gstorage->lock = 1; // Lock @gstorage: do not allow any item to be retrieved or stored from any guild member + j = guild_storage->storage_amount; + guild_storage->lock = 1; // Lock @gstorage: do not allow any item to be retrieved or stored from any guild member for (i = 0; i < j; ++i) { - guild_storage_delitem(sd, gstorage, i, gstorage->items[i].amount); + gstorage->delitem(sd, guild_storage, i, guild_storage->items[i].amount); } - storage_guild_storageclose(sd); - gstorage->lock = 0; // Cleaning done, release lock + gstorage->close(sd); + guild_storage->lock = 0; // Cleaning done, release lock clif->message(fd, msg_txt(1395)); // Your guild storage was cleaned. return true; @@ -5316,16 +5163,16 @@ ACMD(cleargstorage) ACMD(clearcart) { int i; - nullpo_retr(-1, sd); if (pc_iscarton(sd) == 0) { clif->message(fd, msg_txt(1396)); // You do not have a cart to be cleaned. return false; } - if (sd->state.vending == 1) { //Somehow... - return false; - } + if( sd->state.vending == 1 ) { + clif->message(fd, msg_txt(548)); // You can't clean a cart while vending! + return false; + } for( i = 0; i < MAX_CART; i++ ) if(sd->status.cart[i].nameid > 0) @@ -5345,14 +5192,13 @@ ACMD(clearcart) #define MAX_SKILLID_PARTIAL_RESULTS 5 #define MAX_SKILLID_PARTIAL_RESULTS_LEN 74 /* "skill " (6) + "%d:" (up to 5) + "%s" (up to 30) + " (%s)" (up to 33) */ ACMD(skillid) { - int skillen, idx, i, found = 0; + int idx, i, found = 0; + size_t skillen; DBIterator* iter; DBKey key; DBData *data; char partials[MAX_SKILLID_PARTIAL_RESULTS][MAX_SKILLID_PARTIAL_RESULTS_LEN]; - - nullpo_retr(-1, sd); - + if (!message || !*message) { clif->message(fd, msg_txt(1163)); // Please enter a skill name to look up (usage: @skillid <skill name>). return false; @@ -5360,15 +5206,15 @@ ACMD(skillid) { skillen = strlen(message); - iter = db_iterator(skilldb_name2id); + iter = db_iterator(skill->name2id_db); for( data = iter->first(iter,&key); iter->exists(iter); data = iter->next(iter,&key) ) { idx = skill->get_index(DB->data2i(data)); - if (strnicmp(key.str, message, skillen) == 0 || strnicmp(skill_db[idx].desc, message, skillen) == 0) { - sprintf(atcmd_output, msg_txt(1164), DB->data2i(data), skill_db[idx].desc, key.str); // skill %d: %s (%s) + if (strnicmp(key.str, message, skillen) == 0 || strnicmp(skill->db[idx].desc, message, skillen) == 0) { + sprintf(atcmd_output, msg_txt(1164), DB->data2i(data), skill->db[idx].desc, key.str); // skill %d: %s (%s) clif->message(fd, atcmd_output); - } else if ( found < MAX_SKILLID_PARTIAL_RESULTS && ( stristr(key.str,message) || stristr(skill_db[idx].desc,message) ) ) { - snprintf(partials[found++], MAX_SKILLID_PARTIAL_RESULTS_LEN, msg_txt(1164), DB->data2i(data), skill_db[idx].desc, key.str); + } else if ( found < MAX_SKILLID_PARTIAL_RESULTS && ( stristr(key.str,message) || stristr(skill->db[idx].desc,message) ) ) { + snprintf(partials[found++], MAX_SKILLID_PARTIAL_RESULTS_LEN, msg_txt(1164), DB->data2i(data), skill->db[idx].desc, key.str); } } @@ -5390,29 +5236,28 @@ ACMD(skillid) { * @useskill by [MouseJstr] * A way of using skills without having to find them in the skills menu *------------------------------------------*/ -ACMD(useskill) -{ +ACMD(useskill) { struct map_session_data *pl_sd = NULL; struct block_list *bl; uint16 skill_id; uint16 skill_lv; char target[100]; - nullpo_retr(-1, sd); if(!message || !*message || sscanf(message, "%hu %hu %23[^\n]", &skill_id, &skill_lv, target) != 3) { clif->message(fd, msg_txt(1165)); // Usage: @useskill <skill ID> <skill level> <target> return false; } - if(!strcmp(target,"self")) pl_sd = sd; //quick keyword - else if ( (pl_sd = iMap->nick2sd(target)) == NULL ){ + if(!strcmp(target,"self")) + pl_sd = sd; //quick keyword + else if ( (pl_sd = map->nick2sd(target)) == NULL ) { clif->message(fd, msg_txt(3)); // Character not found. return false; } - if ( pc->get_group_level(sd) < pc->get_group_level(pl_sd) ) + if ( pc_get_group_level(sd) < pc_get_group_level(pl_sd) ) { - clif->message(fd, msg_txt(81)); // Your GM level don't authorise you to do this action on this player. + clif->message(fd, msg_txt(81)); // Your GM level don't authorized you to do this action on this player. return false; } @@ -5422,11 +5267,13 @@ ACMD(useskill) else bl = &sd->bl; + pc->delinvincibletimer(sd); + if (skill->get_inf(skill_id)&INF_GROUND_SKILL) - unit_skilluse_pos(bl, pl_sd->bl.x, pl_sd->bl.y, skill_id, skill_lv); + unit->skilluse_pos(bl, pl_sd->bl.x, pl_sd->bl.y, skill_id, skill_lv); else - unit_skilluse_id(bl, pl_sd->bl.id, skill_id, skill_lv); - + unit->skilluse_id(bl, pl_sd->bl.id, skill_id, skill_lv); + return true; } @@ -5435,22 +5282,19 @@ ACMD(useskill) * Debug command to locate new skill IDs. It sends the * three possible skill-effect packets to the area. *------------------------------------------*/ -ACMD(displayskill) -{ - struct status_data * status; - unsigned int tick; +ACMD(displayskill) { + struct status_data *st; + int64 tick; uint16 skill_id; uint16 skill_lv = 1; - nullpo_retr(-1, sd); - if (!message || !*message || sscanf(message, "%hu %hu", &skill_id, &skill_lv) < 1) - { + if (!message || !*message || sscanf(message, "%hu %hu", &skill_id, &skill_lv) < 1) { clif->message(fd, msg_txt(1166)); // Usage: @displayskill <skill ID> {<skill level>} return false; } - status = status_get_status_data(&sd->bl); - tick = iTimer->gettick(); - clif->skill_damage(&sd->bl,&sd->bl, tick, status->amotion, status->dmotion, 1, 1, skill_id, skill_lv, 5); + st = status->get_status_data(&sd->bl); + tick = timer->gettick(); + clif->skill_damage(&sd->bl,&sd->bl, tick, st->amotion, st->dmotion, 1, 1, skill_id, skill_lv, 5); clif->skill_nodamage(&sd->bl, &sd->bl, skill_id, skill_lv, 1); clif->skill_poseffect(&sd->bl, skill_id, skill_lv, sd->bl.x, sd->bl.y, tick); return true; @@ -5460,22 +5304,19 @@ ACMD(displayskill) * @skilltree by [MouseJstr] * prints the skill tree for a player required to get to a skill *------------------------------------------*/ -ACMD(skilltree) -{ +ACMD(skilltree) { struct map_session_data *pl_sd = NULL; uint16 skill_id; int meets, j, c=0; char target[NAME_LENGTH]; struct skill_tree_entry *ent; - nullpo_retr(-1, sd); if(!message || !*message || sscanf(message, "%hu %23[^\r\n]", &skill_id, target) != 2) { clif->message(fd, msg_txt(1167)); // Usage: @skilltree <skill ID> <target> return false; } - if ( (pl_sd = iMap->nick2sd(target)) == NULL ) - { + if ( (pl_sd = map->nick2sd(target)) == NULL ) { clif->message(fd, msg_txt(3)); // Character not found. return false; } @@ -5486,21 +5327,21 @@ ACMD(skilltree) sprintf(atcmd_output, msg_txt(1168), pc->job_name(c), pc->checkskill(pl_sd, NV_BASIC)); // Player is using %s skill tree (%d basic points). clif->message(fd, atcmd_output); - ARR_FIND( 0, MAX_SKILL_TREE, j, skill_tree[c][j].id == 0 || skill_tree[c][j].id == skill_id ); - if( j == MAX_SKILL_TREE || skill_tree[c][j].id == 0 ) + ARR_FIND( 0, MAX_SKILL_TREE, j, pc->skill_tree[c][j].id == 0 || pc->skill_tree[c][j].id == skill_id ); + if( j == MAX_SKILL_TREE || pc->skill_tree[c][j].id == 0 ) { clif->message(fd, msg_txt(1169)); // The player cannot use that skill. - return true; + return false; } - ent = &skill_tree[c][j]; + ent = &pc->skill_tree[c][j]; meets = 1; for(j=0;j<MAX_PC_SKILL_REQUIRE;j++) { if( ent->need[j].id && pc->checkskill(sd,ent->need[j].id) < ent->need[j].lv) { - sprintf(atcmd_output, msg_txt(1170), ent->need[j].lv, skill_db[ent->need[j].id].desc); // Player requires level %d of skill %s. + sprintf(atcmd_output, msg_txt(1170), ent->need[j].lv, skill->db[ent->need[j].id].desc); // Player requires level %d of skill %s. clif->message(fd, atcmd_output); meets = 0; } @@ -5513,8 +5354,7 @@ ACMD(skilltree) } // Hand a ring with partners name on it to this char -void getring (struct map_session_data* sd) -{ +void getring(struct map_session_data* sd) { int flag, item_id; struct item item_tmp; item_id = (sd->status.sex) ? WEDDING_RING_M : WEDDING_RING_F; @@ -5528,7 +5368,7 @@ void getring (struct map_session_data* sd) if((flag = pc->additem(sd,&item_tmp,1,LOG_TYPE_COMMAND))) { clif->additem(sd,0,0,flag); - iMap->addflooritem(&item_tmp,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0); + map->addflooritem(&item_tmp,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0); } } @@ -5536,19 +5376,16 @@ void getring (struct map_session_data* sd) * @marry by [MouseJstr], fixed by Lupus * Marry two players *------------------------------------------*/ -ACMD(marry) -{ +ACMD(marry) { struct map_session_data *pl_sd = NULL; char player_name[NAME_LENGTH] = ""; - - nullpo_retr(-1, sd); - + if (!message || !*message || sscanf(message, "%23s", player_name) != 1) { clif->message(fd, msg_txt(1172)); // Usage: @marry <char name> return false; } - if ((pl_sd = iMap->nick2sd(player_name)) == NULL) { + if ((pl_sd = map->nick2sd(player_name)) == NULL) { clif->message(fd, msg_txt(3)); return false; } @@ -5571,8 +5408,6 @@ ACMD(marry) *------------------------------------------*/ ACMD(divorce) { - nullpo_retr(-1, sd); - if (pc->divorce(sd) != 0) { sprintf(atcmd_output, msg_txt(1175), sd->status.name); // '%s' is not married. clif->message(fd, atcmd_output); @@ -5615,10 +5450,9 @@ ACMD(changelook) * Turns on/off Autotrade for a specific player *------------------------------------------*/ ACMD(autotrade) { - nullpo_retr(-1, sd); - if( map[sd->bl.m].flag.autotrade != battle_config.autotrade_mapflag ) { - clif->message(fd, msg_txt(1179)); // Autotrade is not allowed on this map. + if( map->list[sd->bl.m].flag.autotrade != battle_config.autotrade_mapflag ) { + clif->message(fd, msg_txt(1179)); // Autotrade is not allowed in this map. return false; } @@ -5628,40 +5462,52 @@ ACMD(autotrade) { } if( !sd->state.vending && !sd->state.buyingstore ) { //check if player is vending or buying - clif->message(fd, msg_txt(549)); // "You should have a shop open to use @autotrade." + clif->message(fd, msg_txt(549)); // "You should have a shop open in order to use @autotrade." return false; } sd->state.autotrade = 1; if( battle_config.at_timeout ) { int timeout = atoi(message); - status_change_start(&sd->bl, SC_AUTOTRADE, 10000, 0, 0, 0, 0, ((timeout > 0) ? min(timeout,battle_config.at_timeout) : battle_config.at_timeout) * 60000, 0); + status->change_start(NULL,&sd->bl, SC_AUTOTRADE, 10000, 0, 0, 0, 0, ((timeout > 0) ? min(timeout,battle_config.at_timeout) : battle_config.at_timeout) * 60000, 0); } + + /* currently standalone is not supporting buyingstores, so we rely on the previous method */ + if( sd->state.buyingstore ) { + clif->authfail_fd(fd, 15); + return true; + } + clif->chsys_quit(sd); clif->authfail_fd(sd->fd, 15); + +#ifdef AUTOTRADE_PERSISTENCY + pc->autotrade_prepare(sd); + + return false;/* we fail to not cause it to proceed on is_atcommand */ +#else return true; +#endif } /*========================================== * @changegm by durf (changed by Lupus) * Changes Master of your Guild to a specified guild member *------------------------------------------*/ -ACMD(changegm) -{ +ACMD(changegm) { struct guild *g; struct map_session_data *pl_sd; - nullpo_retr(-1, sd); if (sd->status.guild_id == 0 || (g = sd->guild) == NULL || strcmp(g->master,sd->status.name)) { clif->message(fd, msg_txt(1181)); // You need to be a Guild Master to use this command. return false; } - if( map[sd->bl.m].flag.guildlock || map[sd->bl.m].flag.gvg_castle ) { - clif->message(fd, msg_txt(1182)); // You cannot change guild leaders on this map. + if( map->list[sd->bl.m].flag.guildlock || map->list[sd->bl.m].flag.gvg_castle ) { + clif->message(fd, msg_txt(1182)); // You cannot change guild leaders in this map. return false; } @@ -5670,7 +5516,7 @@ ACMD(changegm) return false; } - if((pl_sd=iMap->nick2sd((char *) message)) == NULL || pl_sd->status.guild_id != sd->status.guild_id) { + if((pl_sd=map->nick2sd((char *) message)) == NULL || pl_sd->status.guild_id != sd->status.guild_id) { clif->message(fd, msg_txt(1184)); // Target character must be online and be a guild member. return false; } @@ -5683,17 +5529,14 @@ ACMD(changegm) * @changeleader by Skotlex * Changes the leader of a party. *------------------------------------------*/ -ACMD(changeleader) -{ - nullpo_retr(-1, sd); +ACMD(changeleader) { - if( !message[0] ) - { + if( !message[0] ) { clif->message(fd, msg_txt(1185)); // Usage: @changeleader <party_member_name> return false; } - if (party->changeleader(sd, iMap->nick2sd((char *) message))) + if (party->changeleader(sd, map->nick2sd((char *) message))) return true; return false; } @@ -5707,7 +5550,6 @@ ACMD(partyoption) struct party_data *p; int mi, option; char w1[16], w2[16]; - nullpo_retr(-1, sd); if (sd->status.party_id == 0 || (p = party->search(sd->status.party_id)) == NULL) { @@ -5749,7 +5591,7 @@ ACMD(partyoption) ACMD(autoloot) { int rate; - nullpo_retr(-1, sd); + // autoloot command without value if(!message || !*message) { @@ -5795,16 +5637,16 @@ ACMD(autolootitem) } else if (!strcmp(message,"reset")) action = 4; - } - - if (action < 3) // add or remove - { - if ((item_data = itemdb_exists(atoi(message))) == NULL) - item_data = itemdb_searchname(message); - if (!item_data) { - // No items founds in the DB with Id or Name - clif->message(fd, msg_txt(1189)); // Item not found. - return false; + + if (action < 3) // add or remove + { + if ((item_data = itemdb->exists(atoi(message))) == NULL) + item_data = itemdb->search_name(message); + if (!item_data) { + // No items founds in the DB with Id or Name + clif->message(fd, msg_txt(1189)); // Item not found. + return false; + } } } @@ -5853,7 +5695,7 @@ ACMD(autolootitem) { if (sd->state.autolootid[i] == 0) continue; - if (!(item_data = itemdb_exists(sd->state.autolootid[i]))) { + if (!(item_data = itemdb->exists(sd->state.autolootid[i]))) { ShowDebug("Non-existant item %d on autolootitem list (account_id: %d, char_id: %d)", sd->state.autolootid[i], sd->status.account_id, sd->status.char_id); continue; } @@ -5870,39 +5712,115 @@ ACMD(autolootitem) } return true; } -/** - * No longer available, keeping here just in case it's back someday. [Ind] - **/ + /*========================================== - * It is made to rain. + * @autoloottype + * Credits: + * chriser,Aleos *------------------------------------------*/ -//ACMD(rain) -//{ -// nullpo_retr(-1, sd); -// if (map[sd->bl.m].flag.rain) { -// map[sd->bl.m].flag.rain=0; -// clif->weather(sd->bl.m); -// clif->message(fd, msg_txt(1201)); // The rain has stopped. -// } else { -// map[sd->bl.m].flag.rain=1; -// clif->weather(sd->bl.m); -// clif->message(fd, msg_txt(1202)); // It has started to rain. -// } -// return true; -//} +ACMD(autoloottype) { + int i; + uint8 action = 3; // 1=add, 2=remove, 3=help+list (default), 4=reset + enum item_types type = -1; + int ITEM_NONE = 0; + + if (message && *message) { + if (message[0] == '+') { + message++; + action = 1; + } else if (message[0] == '-') { + message++; + action = 2; + } else if (strcmp(message,"reset") == 0) { + action = 4; + } + + if (action < 3) { + // add or remove + if (strncmp(message, "healing", 3) == 0) + type = IT_HEALING; + else if (strncmp(message, "usable", 3) == 0) + type = IT_USABLE; + else if (strncmp(message, "etc", 3) == 0) + type = IT_ETC; + else if (strncmp(message, "weapon", 3) == 0) + type = IT_WEAPON; + else if (strncmp(message, "armor", 3) == 0) + type = IT_ARMOR; + else if (strncmp(message, "card", 3) == 0) + type = IT_CARD; + else if (strncmp(message, "petegg", 4) == 0) + type = IT_PETEGG; + else if (strncmp(message, "petarmor", 4) == 0) + type = IT_PETARMOR; + else if (strncmp(message, "ammo", 3) == 0) + type = IT_AMMO; + else { + clif->message(fd, msg_txt(1491)); // Item type not found. + return false; + } + } + } + + switch (action) { + case 1: + if (sd->state.autoloottype&(1<<type)) { + clif->message(fd, msg_txt(1490)); // You're already autolooting this item type. + return false; + } + sd->state.autoloottype |= (1<<type); // Stores the type + sprintf(atcmd_output, msg_txt(1492), itemdb->typename(type)); // Autolooting item type: '%s' + clif->message(fd, atcmd_output); + break; + case 2: + if (!(sd->state.autoloottype&(1<<type))) { + clif->message(fd, msg_txt(1493)); // You're currently not autolooting this item type. + return false; + } + sd->state.autoloottype &= ~(1<<type); + sprintf(atcmd_output, msg_txt(1494), itemdb->typename(type)); // Removed item type: '%s' from your autoloottype list. + clif->message(fd, atcmd_output); + break; + case 3: + clif->message(fd, msg_txt(38)); // Invalid location number, or name. + + { + // attempt to find the text help string + const char *text = atcommand_help_string(info); + if (text) clif->messageln(fd, text); // send the text to the client + } + + if (sd->state.autoloottype == ITEM_NONE) { + clif->message(fd, msg_txt(1495)); // Your autoloottype list is empty. + } else { + clif->message(fd, msg_txt(1496)); // Item types on your autoloottype list: + for(i=0; i < IT_MAX; i++) { + if (sd->state.autoloottype&(1<<i)) { + sprintf(atcmd_output, " '%s'", itemdb->typename(i)); + clif->message(fd, atcmd_output); + } + } + } + break; + case 4: + sd->state.autoloottype = ITEM_NONE; + clif->message(fd, msg_txt(1497)); // Your autoloottype list has been reset. + break; + } + return true; +} /*========================================== * It is made to snow. *------------------------------------------*/ -ACMD(snow) -{ - nullpo_retr(-1, sd); - if (map[sd->bl.m].flag.snow) { - map[sd->bl.m].flag.snow=0; +ACMD(snow) { + + if (map->list[sd->bl.m].flag.snow) { + map->list[sd->bl.m].flag.snow=0; clif->weather(sd->bl.m); clif->message(fd, msg_txt(1203)); // Snow has stopped falling. } else { - map[sd->bl.m].flag.snow=1; + map->list[sd->bl.m].flag.snow=1; clif->weather(sd->bl.m); clif->message(fd, msg_txt(1204)); // It has started to snow. } @@ -5913,15 +5831,14 @@ ACMD(snow) /*========================================== * Cherry tree snowstorm is made to fall. (Sakura) *------------------------------------------*/ -ACMD(sakura) -{ - nullpo_retr(-1, sd); - if (map[sd->bl.m].flag.sakura) { - map[sd->bl.m].flag.sakura=0; +ACMD(sakura) { + + if (map->list[sd->bl.m].flag.sakura) { + map->list[sd->bl.m].flag.sakura=0; clif->weather(sd->bl.m); clif->message(fd, msg_txt(1205)); // Cherry tree leaves no longer fall. } else { - map[sd->bl.m].flag.sakura=1; + map->list[sd->bl.m].flag.sakura=1; clif->weather(sd->bl.m); clif->message(fd, msg_txt(1206)); // Cherry tree leaves have begun to fall. } @@ -5931,15 +5848,14 @@ ACMD(sakura) /*========================================== * Clouds appear. *------------------------------------------*/ -ACMD(clouds) -{ - nullpo_retr(-1, sd); - if (map[sd->bl.m].flag.clouds) { - map[sd->bl.m].flag.clouds=0; +ACMD(clouds) { + + if (map->list[sd->bl.m].flag.clouds) { + map->list[sd->bl.m].flag.clouds=0; clif->weather(sd->bl.m); clif->message(fd, msg_txt(1207)); // The clouds has disappear. } else { - map[sd->bl.m].flag.clouds=1; + map->list[sd->bl.m].flag.clouds=1; clif->weather(sd->bl.m); clif->message(fd, msg_txt(1208)); // Clouds appear. } @@ -5950,15 +5866,14 @@ ACMD(clouds) /*========================================== * Different type of clouds using effect 516 *------------------------------------------*/ -ACMD(clouds2) -{ - nullpo_retr(-1, sd); - if (map[sd->bl.m].flag.clouds2) { - map[sd->bl.m].flag.clouds2=0; +ACMD(clouds2) { + + if (map->list[sd->bl.m].flag.clouds2) { + map->list[sd->bl.m].flag.clouds2=0; clif->weather(sd->bl.m); clif->message(fd, msg_txt(1209)); // The alternative clouds disappear. } else { - map[sd->bl.m].flag.clouds2=1; + map->list[sd->bl.m].flag.clouds2=1; clif->weather(sd->bl.m); clif->message(fd, msg_txt(1210)); // Alternative clouds appear. } @@ -5969,15 +5884,14 @@ ACMD(clouds2) /*========================================== * Fog hangs over. *------------------------------------------*/ -ACMD(fog) -{ - nullpo_retr(-1, sd); - if (map[sd->bl.m].flag.fog) { - map[sd->bl.m].flag.fog=0; +ACMD(fog) { + + if (map->list[sd->bl.m].flag.fog) { + map->list[sd->bl.m].flag.fog=0; clif->weather(sd->bl.m); clif->message(fd, msg_txt(1211)); // The fog has gone. } else { - map[sd->bl.m].flag.fog=1; + map->list[sd->bl.m].flag.fog=1; clif->weather(sd->bl.m); clif->message(fd, msg_txt(1212)); // Fog hangs over. } @@ -5987,15 +5901,14 @@ ACMD(fog) /*========================================== * Fallen leaves fall. *------------------------------------------*/ -ACMD(leaves) -{ - nullpo_retr(-1, sd); - if (map[sd->bl.m].flag.leaves) { - map[sd->bl.m].flag.leaves=0; +ACMD(leaves) { + + if (map->list[sd->bl.m].flag.leaves) { + map->list[sd->bl.m].flag.leaves=0; clif->weather(sd->bl.m); clif->message(fd, msg_txt(1213)); // Leaves no longer fall. } else { - map[sd->bl.m].flag.leaves=1; + map->list[sd->bl.m].flag.leaves=1; clif->weather(sd->bl.m); clif->message(fd, msg_txt(1214)); // Fallen leaves fall. } @@ -6006,15 +5919,14 @@ ACMD(leaves) /*========================================== * Fireworks appear. *------------------------------------------*/ -ACMD(fireworks) -{ - nullpo_retr(-1, sd); - if (map[sd->bl.m].flag.fireworks) { - map[sd->bl.m].flag.fireworks=0; +ACMD(fireworks) { + + if (map->list[sd->bl.m].flag.fireworks) { + map->list[sd->bl.m].flag.fireworks=0; clif->weather(sd->bl.m); clif->message(fd, msg_txt(1215)); // Fireworks have ended. } else { - map[sd->bl.m].flag.fireworks=1; + map->list[sd->bl.m].flag.fireworks=1; clif->weather(sd->bl.m); clif->message(fd, msg_txt(1216)); // Fireworks have launched. } @@ -6025,22 +5937,17 @@ ACMD(fireworks) /*========================================== * Clearing Weather Effects by Dexity *------------------------------------------*/ -ACMD(clearweather) -{ - nullpo_retr(-1, sd); - /** - * No longer available, keeping here just in case it's back someday. [Ind] - **/ - //map[sd->bl.m].flag.rain=0; - map[sd->bl.m].flag.snow=0; - map[sd->bl.m].flag.sakura=0; - map[sd->bl.m].flag.clouds=0; - map[sd->bl.m].flag.clouds2=0; - map[sd->bl.m].flag.fog=0; - map[sd->bl.m].flag.fireworks=0; - map[sd->bl.m].flag.leaves=0; +ACMD(clearweather) { + + map->list[sd->bl.m].flag.snow=0; + map->list[sd->bl.m].flag.sakura=0; + map->list[sd->bl.m].flag.clouds=0; + map->list[sd->bl.m].flag.clouds2=0; + map->list[sd->bl.m].flag.fog=0; + map->list[sd->bl.m].flag.fireworks=0; + map->list[sd->bl.m].flag.leaves=0; clif->weather(sd->bl.m); - clif->message(fd, msg_txt(291)); + clif->message(fd, msg_txt(291)); // "Weather effects will disappear after teleporting or refreshing." return true; } @@ -6076,23 +5983,21 @@ ACMD(mobsearch) int mob_id; int number = 0; struct s_mapiterator* it; - - nullpo_retr(-1, sd); - + if (!message || !*message || sscanf(message, "%99[^\n]", mob_name) < 1) { clif->message(fd, msg_txt(1218)); // Please enter a monster name (usage: @mobsearch <monster name>). return false; } if ((mob_id = atoi(mob_name)) == 0) - mob_id = mobdb_searchname(mob_name); - if(mob_id > 0 && mobdb_checkid(mob_id) == 0){ + mob_id = mob->db_searchname(mob_name); + if(mob_id > 0 && mob->db_checkid(mob_id) == 0){ snprintf(atcmd_output, sizeof atcmd_output, msg_txt(1219),mob_name); // Invalid mob ID %s! clif->message(fd, atcmd_output); return false; } - if(mob_id == atoi(mob_name) && mob_db(mob_id)->jname) - strcpy(mob_name,mob_db(mob_id)->jname); // --ja-- + if(mob_id == atoi(mob_name) && mob->db(mob_id)->jname) + strcpy(mob_name,mob->db(mob_id)->jname); // --ja-- // strcpy(mob_name,mob_db(mob_id)->name); // --en-- snprintf(atcmd_output, sizeof atcmd_output, msg_txt(1220), mob_name, mapindex_id2name(sd->mapindex)); // Mob Search... %s %s @@ -6126,33 +6031,28 @@ ACMD(mobsearch) * @cleanmap - cleans items on the ground * @cleanarea - cleans items on the ground within an specified area *------------------------------------------*/ -static int atcommand_cleanfloor_sub(struct block_list *bl, va_list ap) -{ +int atcommand_cleanfloor_sub(struct block_list *bl, va_list ap) { nullpo_ret(bl); - iMap->clearflooritem(bl); + map->clearflooritem(bl); return 0; } -ACMD(cleanmap) -{ - iMap->foreachinmap(atcommand_cleanfloor_sub, sd->bl.m, BL_ITEM); +ACMD(cleanmap) { + map->foreachinmap(atcommand->cleanfloor_sub, sd->bl.m, BL_ITEM); clif->message(fd, msg_txt(1221)); // All dropped items have been cleaned up. return true; } -ACMD(cleanarea) -{ +ACMD(cleanarea) { int x0 = 0, y0 = 0, x1 = 0, y1 = 0; if (!message || !*message || sscanf(message, "%d %d %d %d", &x0, &y0, &x1, &y1) < 1) { - iMap->foreachinarea(atcommand_cleanfloor_sub, sd->bl.m, sd->bl.x - (AREA_SIZE * 2), sd->bl.y - (AREA_SIZE * 2), sd->bl.x + (AREA_SIZE * 2), sd->bl.y + (AREA_SIZE * 2), BL_ITEM); - } - else if (sscanf(message, "%d %d %d %d", &x0, &y0, &x1, &y1) == 1) { - iMap->foreachinarea(atcommand_cleanfloor_sub, sd->bl.m, sd->bl.x - x0, sd->bl.y - x0, sd->bl.x + x0, sd->bl.y + x0, BL_ITEM); - } - else if (sscanf(message, "%d %d %d %d", &x0, &y0, &x1, &y1) == 4) { - iMap->foreachinarea(atcommand_cleanfloor_sub, sd->bl.m, x0, y0, x1, y1, BL_ITEM); + map->foreachinrange(atcommand->cleanfloor_sub, &sd->bl, AREA_SIZE * 2, BL_ITEM); + } else if (sscanf(message, "%d %d %d %d", &x0, &y0, &x1, &y1) == 1) { + map->foreachinrange(atcommand->cleanfloor_sub, &sd->bl, x0, BL_ITEM); + } else if (sscanf(message, "%d %d %d %d", &x0, &y0, &x1, &y1) == 4) { + map->foreachinarea(atcommand->cleanfloor_sub, sd->bl.m, x0, y0, x1, y1, BL_ITEM); } clif->message(fd, msg_txt(1221)); // All dropped items have been cleaned up. @@ -6167,11 +6067,11 @@ ACMD(npctalk) { char name[NAME_LENGTH],mes[100],temp[100]; struct npc_data *nd; - bool ifcolor=(*(command + 8) != 'c' && *(command + 8) != 'C')?0:1; - unsigned long color=0; + bool ifcolor=(*(info->command + 7) != 'c' && *(info->command + 7) != 'C')?0:1; + unsigned int color = 0; if (sd->sc.count && //no "chatting" while muted. - (sd->sc.data[SC_BERSERK] || sd->sc.data[SC_DEEP_SLEEP] || sd->sc.data[SC__BLOODYLUST] || + (sd->sc.data[SC_BERSERK] || (sd->sc.data[SC_DEEP_SLEEP] && sd->sc.data[SC_DEEP_SLEEP]->val2) || (sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOCHAT))) return false; @@ -6182,13 +6082,13 @@ ACMD(npctalk) } } else { - if (!message || !*message || sscanf(message, "%lx %23[^,], %99[^\n]", &color, name, mes) < 3) { + if (!message || !*message || sscanf(message, "%u %23[^,], %99[^\n]", &color, name, mes) < 3) { clif->message(fd, msg_txt(1223)); // Please enter the correct parameters (usage: @npctalkc <color> <npc name>, <message>). return false; } } - if (!(nd = npc_name2id(name))) { + if (!(nd = npc->name2id(name))) { clif->message(fd, msg_txt(111)); // This NPC doesn't exist return false; } @@ -6206,13 +6106,11 @@ ACMD(pettalk) { char mes[100],temp[100]; struct pet_data *pd; - - nullpo_retr(-1, sd); - + if ( battle_config.min_chat_delay ) { - if( DIFF_TICK(sd->cantalk_tick, iTimer->gettick()) > 0 ) + if( DIFF_TICK(sd->cantalk_tick, timer->gettick()) > 0 ) return true; - sd->cantalk_tick = iTimer->gettick() + battle_config.min_chat_delay; + sd->cantalk_tick = timer->gettick() + battle_config.min_chat_delay; } if(!sd->status.pet_id || !(pd=sd->pd)) @@ -6222,7 +6120,7 @@ ACMD(pettalk) } if (sd->sc.count && //no "chatting" while muted. - (sd->sc.data[SC_BERSERK] || sd->sc.data[SC_DEEP_SLEEP] || sd->sc.data[SC__BLOODYLUST] || + (sd->sc.data[SC_BERSERK] || (sd->sc.data[SC_DEEP_SLEEP] && sd->sc.data[SC_DEEP_SLEEP]->val2) || (sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOCHAT))) return false; @@ -6333,9 +6231,7 @@ ACMD(summon) int mob_id = 0; int duration = 0; struct mob_data *md; - unsigned int tick=iTimer->gettick(); - - nullpo_retr(-1, sd); + int64 tick=timer->gettick(); if (!message || !*message || sscanf(message, "%23s %d", name, &duration) < 1) { @@ -6349,24 +6245,24 @@ ACMD(summon) duration =60; if ((mob_id = atoi(name)) == 0) - mob_id = mobdb_searchname(name); - if(mob_id == 0 || mobdb_checkid(mob_id) == 0) + mob_id = mob->db_searchname(name); + if(mob_id == 0 || mob->db_checkid(mob_id) == 0) { clif->message(fd, msg_txt(40)); // Invalid monster ID or name. return false; } - md = mob_once_spawn_sub(&sd->bl, sd->bl.m, -1, -1, "--ja--", mob_id, "", SZ_SMALL, AI_NONE); + md = mob->once_spawn_sub(&sd->bl, sd->bl.m, -1, -1, "--ja--", mob_id, "", SZ_MEDIUM, AI_NONE); if(!md) return false; md->master_id=sd->bl.id; md->special_state.ai=1; - md->deletetimer=iTimer->add_timer(tick+(duration*60000),mob_timer_delete,md->bl.id,0); + md->deletetimer=timer->add(tick+(duration*60000),mob->timer_delete,md->bl.id,0); clif->specialeffect(&md->bl,344,AREA); - mob_spawn(md); - sc_start4(&md->bl, SC_MODECHANGE, 100, 1, 0, MD_AGGRESSIVE, 0, 60000); + mob->spawn(md); + sc_start4(NULL,&md->bl, SC_MODECHANGE, 100, 1, 0, MD_AGGRESSIVE, 0, 60000); clif->skill_poseffect(&sd->bl,AM_CALLHOMUN,1,md->bl.x,md->bl.y,tick); clif->message(fd, msg_txt(39)); // All monster summoned! @@ -6381,20 +6277,17 @@ ACMD(summon) ACMD(adjgroup) { int new_group = 0; - nullpo_retr(-1, sd); if (!message || !*message || sscanf(message, "%d", &new_group) != 1) { clif->message(fd, msg_txt(1226)); // Usage: @adjgroup <group_id> return false; } - if (!pc_group_exists(new_group)) { + if (pc->set_group(sd, new_group) != 0) { clif->message(fd, msg_txt(1227)); // Specified group does not exist. return false; } - - sd->group_id = new_group; - pc_group_pc_load(sd);/* update cache */ + clif->message(fd, msg_txt(1228)); // Group changed successfully. clif->message(sd->fd, msg_txt(1229)); // Your group has changed. return true; @@ -6404,18 +6297,15 @@ ACMD(adjgroup) * @trade by [MouseJstr] * Open a trade window with a remote player *------------------------------------------*/ -ACMD(trade) -{ +ACMD(trade) { struct map_session_data *pl_sd = NULL; - nullpo_retr(-1, sd); if (!message || !*message) { clif->message(fd, msg_txt(1230)); // Please enter a player name (usage: @trade <char name>). return false; } - if ( (pl_sd = iMap->nick2sd((char *)message)) == NULL ) - { + if ( (pl_sd = map->nick2sd((char *)message)) == NULL ) { clif->message(fd, msg_txt(3)); // Character not found. return false; } @@ -6431,7 +6321,6 @@ ACMD(trade) ACMD(setbattleflag) { char flag[128], value[128]; - nullpo_retr(-1, sd); if (!message || !*message || sscanf(message, "%127s %127s", flag, value) != 2) { clif->message(fd, msg_txt(1231)); // Usage: @setbattleflag <flag> <value> @@ -6451,17 +6340,15 @@ ACMD(setbattleflag) /*========================================== * @unmute [Valaris] *------------------------------------------*/ -ACMD(unmute) -{ +ACMD(unmute) { struct map_session_data *pl_sd = NULL; - nullpo_retr(-1, sd); if (!message || !*message) { clif->message(fd, msg_txt(1234)); // Please enter a player name (usage: @unmute <char name>). return false; } - if ( (pl_sd = iMap->nick2sd((char *)message)) == NULL ) + if ( (pl_sd = map->nick2sd((char *)message)) == NULL ) { clif->message(fd, msg_txt(3)); // Character not found. return false; @@ -6486,9 +6373,8 @@ ACMD(uptime) { unsigned long seconds = 0, day = 24*60*60, hour = 60*60, minute = 60, days = 0, hours = 0, minutes = 0; - nullpo_retr(-1, sd); - seconds = iTimer->get_uptime(); + seconds = timer->get_uptime(); days = seconds/day; seconds -= (seconds/day>0)?(seconds/day)*day:0; hours = seconds/hour; @@ -6509,38 +6395,35 @@ ACMD(uptime) ACMD(changesex) { int i; - nullpo_retr(-1, sd); + pc->resetskill(sd,4); - // to avoid any problem with equipment and invalid sex, equipment is unequiped. + // to avoid any problem with equipment and invalid sex, equipment is unequipped. for( i=0; i<EQI_MAX; i++ ) if( sd->equip_index[i] >= 0 ) pc->unequipitem(sd, sd->equip_index[i], 3); - chrif_changesex(sd); + chrif->changesex(sd); return true; } /*================================================ * @mute - Mutes a player for a set amount of time *------------------------------------------------*/ -ACMD(mute) -{ +ACMD(mute) { struct map_session_data *pl_sd = NULL; int manner; - nullpo_retr(-1, sd); if (!message || !*message || sscanf(message, "%d %23[^\n]", &manner, atcmd_player_name) < 1) { clif->message(fd, msg_txt(1237)); // Usage: @mute <time> <char name> return false; } - if ( (pl_sd = iMap->nick2sd(atcmd_player_name)) == NULL ) - { + if ( (pl_sd = map->nick2sd(atcmd_player_name)) == NULL ) { clif->message(fd, msg_txt(3)); // Character not found. return false; } - if ( pc->get_group_level(sd) < pc->get_group_level(pl_sd) ) + if ( pc_get_group_level(sd) < pc_get_group_level(pl_sd) ) { - clif->message(fd, msg_txt(81)); // Your GM level don't authorise you to do this action on this player. + clif->message(fd, msg_txt(81)); // Your GM level don't authorize you to do this action on this player. return false; } @@ -6549,7 +6432,7 @@ ACMD(mute) if( pl_sd->status.manner < manner ) { pl_sd->status.manner -= manner; - sc_start(&pl_sd->bl,SC_NOCHAT,100,0,0); + sc_start(NULL,&pl_sd->bl,SC_NOCHAT,100,0,0); } else { pl_sd->status.manner = 0; status_change_end(&pl_sd->bl, SC_NOCHAT, INVALID_TIMER); @@ -6565,7 +6448,6 @@ ACMD(mute) *------------------------------------------*/ ACMD(refresh) { - nullpo_retr(-1, sd); clif->refresh(sd); return true; } @@ -6574,7 +6456,6 @@ ACMD(refreshall) { struct map_session_data* iter_sd; struct s_mapiterator* iter; - nullpo_retr(-1, sd); iter = mapit_getallusers(); for (iter_sd = (TBL_PC*)mapit->first(iter); mapit->exists(iter); iter_sd = (TBL_PC*)mapit->next(iter)) @@ -6590,9 +6471,7 @@ ACMD(refreshall) ACMD(identify) { int i,num; - - nullpo_retr(-1, sd); - + for(i=num=0;i<MAX_INVENTORY;i++){ if(sd->status.inventory[i].nameid > 0 && sd->status.inventory[i].identify!=1){ num++; @@ -6608,7 +6487,7 @@ ACMD(identify) ACMD(misceffect) { int effect = 0; - nullpo_retr(-1, sd); + if (!message || !*message) return false; if (sscanf(message, "%d", &effect) < 1) @@ -6623,7 +6502,6 @@ ACMD(misceffect) { *------------------------------------------*/ ACMD(mail) { - nullpo_ret(sd); mail->openmail(sd); return true; } @@ -6639,7 +6517,7 @@ ACMD(mobinfo) unsigned char melement[10][8] = {"Neutral", "Water", "Earth", "Fire", "Wind", "Poison", "Holy", "Dark", "Ghost", "Undead"}; char atcmd_output2[CHAT_SIZE_MAX]; struct item_data *item_data; - struct mob_db *mob, *mob_array[MAX_SEARCH]; + struct mob_db *monster, *mob_array[MAX_SEARCH]; int count; int i, j, k; @@ -6652,12 +6530,11 @@ ACMD(mobinfo) } // If monster identifier/name argument is a name - if ((i = mobdb_checkid(atoi(message)))) - { - mob_array[0] = mob_db(i); + if ((i = mob->db_checkid(atoi(message)))) { + mob_array[0] = mob->db(i); count = 1; } else - count = mobdb_searchname_array(mob_array, MAX_SEARCH, message); + count = mob->db_searchname_array(mob_array, MAX_SEARCH, message, 0); if (!count) { clif->message(fd, msg_txt(40)); // Invalid monster ID or name. @@ -6669,66 +6546,97 @@ ACMD(mobinfo) clif->message(fd, atcmd_output); count = MAX_SEARCH; } + for (k = 0; k < count; k++) { - mob = mob_array[k]; + unsigned int job_exp, base_exp; + + monster = mob_array[k]; + + job_exp = monster->job_exp; + base_exp = monster->base_exp; + +#ifdef RENEWAL_EXP + if( battle_config.atcommand_mobinfo_type ) { + base_exp = base_exp * pc->level_penalty_mod(monster->lv - sd->status.base_level, monster->status.race, monster->status.mode, 1) / 100; + job_exp = job_exp * pc->level_penalty_mod(monster->lv - sd->status.base_level, monster->status.race, monster->status.mode, 1) / 100; + } +#endif // stats - if (mob->mexp) - sprintf(atcmd_output, msg_txt(1240), mob->name, mob->jname, mob->sprite, mob->vd.class_); // MVP Monster: '%s'/'%s'/'%s' (%d) + if (monster->mexp) + sprintf(atcmd_output, msg_txt(1240), monster->name, monster->jname, monster->sprite, monster->vd.class_); // MVP Monster: '%s'/'%s'/'%s' (%d) else - sprintf(atcmd_output, msg_txt(1241), mob->name, mob->jname, mob->sprite, mob->vd.class_); // Monster: '%s'/'%s'/'%s' (%d) + sprintf(atcmd_output, msg_txt(1241), monster->name, monster->jname, monster->sprite, monster->vd.class_); // Monster: '%s'/'%s'/'%s' (%d) clif->message(fd, atcmd_output); - sprintf(atcmd_output, msg_txt(1242), mob->lv, mob->status.max_hp, mob->base_exp, mob->job_exp,MOB_HIT(mob), MOB_FLEE(mob)); // Lv:%d HP:%d Base EXP:%u Job EXP:%u HIT:%d FLEE:%d + + sprintf(atcmd_output, msg_txt(1242), monster->lv, monster->status.max_hp, base_exp, job_exp, MOB_HIT(monster), MOB_FLEE(monster)); // Lv:%d HP:%d Base EXP:%u Job EXP:%u HIT:%d FLEE:%d clif->message(fd, atcmd_output); + sprintf(atcmd_output, msg_txt(1243), // DEF:%d MDEF:%d STR:%d AGI:%d VIT:%d INT:%d DEX:%d LUK:%d - mob->status.def, mob->status.mdef,mob->status.str, mob->status.agi, - mob->status.vit, mob->status.int_, mob->status.dex, mob->status.luk); + monster->status.def, monster->status.mdef, monster->status.str, monster->status.agi, + monster->status.vit, monster->status.int_, monster->status.dex, monster->status.luk); clif->message(fd, atcmd_output); sprintf(atcmd_output, msg_txt(1244), // ATK:%d~%d Range:%d~%d~%d Size:%s Race: %s Element: %s (Lv:%d) - mob->status.rhw.atk, mob->status.rhw.atk2, mob->status.rhw.range, - mob->range2 , mob->range3, msize[mob->status.size], - mrace[mob->status.race], melement[mob->status.def_ele], mob->status.ele_lv); + monster->status.rhw.atk, monster->status.rhw.atk2, monster->status.rhw.range, + monster->range2 , monster->range3, msize[monster->status.size], + mrace[monster->status.race], melement[monster->status.def_ele], monster->status.ele_lv); clif->message(fd, atcmd_output); + // drops clif->message(fd, msg_txt(1245)); // Drops: strcpy(atcmd_output, " "); j = 0; for (i = 0; i < MAX_MOB_DROP; i++) { int droprate; - if (mob->dropitem[i].nameid <= 0 || mob->dropitem[i].p < 1 || (item_data = itemdb_exists(mob->dropitem[i].nameid)) == NULL) + + if (monster->dropitem[i].nameid <= 0 || monster->dropitem[i].p < 1 || (item_data = itemdb->exists(monster->dropitem[i].nameid)) == NULL) continue; - droprate = mob->dropitem[i].p; + + droprate = monster->dropitem[i].p; + +#ifdef RENEWAL_DROP + if( battle_config.atcommand_mobinfo_type ) { + droprate = droprate * pc->level_penalty_mod(monster->lv - sd->status.base_level, monster->status.race, monster->status.mode, 2) / 100; + + if (droprate <= 0 && !battle_config.drop_rate0item) + droprate = 1; + } +#endif if (item_data->slot) sprintf(atcmd_output2, " - %s[%d] %02.02f%%", item_data->jname, item_data->slot, (float)droprate / 100); else sprintf(atcmd_output2, " - %s %02.02f%%", item_data->jname, (float)droprate / 100); + strcat(atcmd_output, atcmd_output2); + if (++j % 3 == 0) { clif->message(fd, atcmd_output); strcpy(atcmd_output, " "); } } + if (j == 0) clif->message(fd, msg_txt(1246)); // This monster has no drops. else if (j % 3 != 0) clif->message(fd, atcmd_output); // mvp - if (mob->mexp) { - sprintf(atcmd_output, msg_txt(1247), mob->mexp); // MVP Bonus EXP:%u + if (monster->mexp) { + sprintf(atcmd_output, msg_txt(1247), monster->mexp); // MVP Bonus EXP:%u clif->message(fd, atcmd_output); + strcpy(atcmd_output, msg_txt(1248)); // MVP Items: j = 0; for (i = 0; i < MAX_MVP_DROP; i++) { - if (mob->mvpitem[i].nameid <= 0 || (item_data = itemdb_exists(mob->mvpitem[i].nameid)) == NULL) + if (monster->mvpitem[i].nameid <= 0 || (item_data = itemdb->exists(monster->mvpitem[i].nameid)) == NULL) continue; - if (mob->mvpitem[i].p > 0) { + if (monster->mvpitem[i].p > 0) { j++; - if (j == 1) - sprintf(atcmd_output2, " %s %02.02f%%", item_data->jname, (float)mob->mvpitem[i].p / 100); + if(item_data->slot) + sprintf(atcmd_output2, " %s%s[%d] %02.02f%%",j != 1 ? "- " : "", item_data->jname, item_data->slot, (float)monster->mvpitem[i].p / 100); else - sprintf(atcmd_output2, " - %s %02.02f%%", item_data->jname, (float)mob->mvpitem[i].p / 100); + sprintf(atcmd_output2, " %s%s %02.02f%%",j != 1 ? "- " : "", item_data->jname, (float)monster->mvpitem[i].p / 100); strcat(atcmd_output, atcmd_output2); } } @@ -6751,27 +6659,34 @@ ACMD(showmobs) int mob_id; int number = 0; struct s_mapiterator* it; - - nullpo_retr(-1, sd); - - if(sscanf(message, "%99[^\n]", mob_name) < 0) + + if( sscanf(message, "%99[^\n]", mob_name) < 0 ) { + clif->message(fd, msg_txt(546)); // Please enter a mob name/id (usage: @showmobs <mob name/id>) return false; - - if((mob_id = atoi(mob_name)) == 0) - mob_id = mobdb_searchname(mob_name); - if(mob_id > 0 && mobdb_checkid(mob_id) == 0){ + } + + if( (mob_id = atoi(mob_name)) == 0 ) + mob_id = mob->db_searchname(mob_name); + + if( mob_id == 0 ) { + snprintf(atcmd_output, sizeof atcmd_output, msg_txt(547), mob_name); // Invalid mob name %s! + clif->message(fd, atcmd_output); + return false; + } + + if(mob_id > 0 && mob->db_checkid(mob_id) == 0){ snprintf(atcmd_output, sizeof atcmd_output, msg_txt(1250),mob_name); // Invalid mob id %s! clif->message(fd, atcmd_output); - return true; + return false; } - if(mob_db(mob_id)->status.mode&MD_BOSS && !pc_has_permission(sd, PC_PERM_SHOW_BOSS)){ // If player group does not have access to boss mobs. + if(mob->db(mob_id)->status.mode&MD_BOSS && !pc_has_permission(sd, PC_PERM_SHOW_BOSS)){ // If player group does not have access to boss mobs. clif->message(fd, msg_txt(1251)); // Can't show boss mobs! - return true; + return false; } - if(mob_id == atoi(mob_name) && mob_db(mob_id)->jname) - strcpy(mob_name,mob_db(mob_id)->jname); // --ja-- + if(mob_id == atoi(mob_name) && mob->db(mob_id)->jname) + strcpy(mob_name,mob->db(mob_id)->jname); // --ja-- //strcpy(mob_name,mob_db(mob_id)->name); // --en-- snprintf(atcmd_output, sizeof atcmd_output, msg_txt(1252), // Mob Search... %s %s @@ -6805,33 +6720,55 @@ ACMD(showmobs) /*========================================== * homunculus level up [orn] *------------------------------------------*/ -ACMD(homlevel) -{ +ACMD(homlevel) { TBL_HOM * hd; int level = 0; + enum homun_type htype; - nullpo_retr(-1, sd); - - if ( !message || !*message || ( level = atoi(message) ) < 1 ) { + if( !message || !*message || ( level = atoi(message) ) < 1 ) { clif->message(fd, msg_txt(1253)); // Please enter a level adjustment (usage: @homlevel <number of levels>). return false; } - if ( !homun_alive(sd->hd) ) { + if( !homun_alive(sd->hd) ) { clif->message(fd, msg_txt(1254)); // You do not have a homunculus. return false; } hd = sd->hd; + + if( (htype = homun->class2type(hd->homunculus.class_)) == HT_INVALID ) { + ShowError("atcommand_homlevel: invalid homun class %d (player %s)\n", hd->homunculus.class_,sd->status.name); + return false; + } + + switch( htype ) { + case HT_REG: + case HT_EVO: + if( hd->homunculus.level >= battle_config.hom_max_level ) { + snprintf(atcmd_output, sizeof(atcmd_output), msg_txt(1478), hd->homunculus.level); // Homun reached its maximum level of '%d' + clif->message(fd, atcmd_output); + return true; + } + break; + case HT_S: + if( hd->homunculus.level >= battle_config.hom_S_max_level ) { + snprintf(atcmd_output, sizeof(atcmd_output), msg_txt(1478), hd->homunculus.level); // Homun reached its maximum level of '%d' + clif->message(fd, atcmd_output); + return true; + } + break; + default: + ShowError("atcommand_homlevel: unknown htype '%d'\n",htype); + return false; + } - if ( battle_config.hom_max_level == hd->homunculus.level ) // Already reach maximum level - return true; - - do{ + + do { hd->homunculus.exp += hd->exp_next; } while( hd->homunculus.level < level && homun->levelup(hd) ); - status_calc_homunculus(hd,0); + status_calc_homunculus(hd,SCO_NONE); status_percent_heal(&hd->bl, 100, 100); clif->specialeffect(&hd->bl,568,AREA); return true; @@ -6842,8 +6779,6 @@ ACMD(homlevel) *------------------------------------------*/ ACMD(homevolution) { - nullpo_retr(-1, sd); - if ( !homun_alive(sd->hd) ) { clif->message(fd, msg_txt(1254)); // You do not have a homunculus. return false; @@ -6860,14 +6795,13 @@ ACMD(homevolution) ACMD(hommutate) { int homun_id; enum homun_type m_class, m_id; - nullpo_retr(-1, sd); - if (!homun_alive(sd->hd)) { + if( !homun_alive(sd->hd) ) { clif->message(fd, msg_txt(1254)); // You do not have a homunculus. return false; } - if (!message || !*message) { + if( !message || !*message ) { homun_id = 6048 + (rnd() % 4); } else { homun_id = atoi(message); @@ -6876,7 +6810,7 @@ ACMD(hommutate) { m_class = homun->class2type(sd->hd->homunculus.class_); m_id = homun->class2type(homun_id); - if (m_class != -1 && m_id != -1 && m_class == HT_EVO && m_id == HT_S && sd->hd->homunculus.level >= 99) { + if( m_class != HT_INVALID && m_id != HT_INVALID && m_class == HT_EVO && m_id == HT_S && sd->hd->homunculus.level >= 99 ) { homun->mutate(sd->hd, homun_id); } else { clif->emotion(&sd->hd->bl, E_SWT); @@ -6889,7 +6823,6 @@ ACMD(hommutate) { *------------------------------------------*/ ACMD(makehomun) { int homunid; - nullpo_retr(-1, sd); if (!message || !*message) { clif->message(fd, msg_txt(1256)); // Please enter a homunculus ID (usage: @makehomun <homunculus id>). @@ -6898,8 +6831,13 @@ ACMD(makehomun) { homunid = atoi(message); - if( homunid == -1 && sd->status.hom_id && !homun_alive(sd->hd) ) { - homun->call(sd); + if( homunid == -1 && sd->status.hom_id && !(sd->hd && homun_alive(sd->hd)) ) { + if( !sd->hd ) + homun->call(sd); + else if( sd->hd->homunculus.vaporize ) + homun->ressurect(sd, 100, sd->bl.x, sd->bl.y); + else + homun->call(sd); return true; } @@ -6924,9 +6862,7 @@ ACMD(makehomun) { ACMD(homfriendly) { int friendly = 0; - - nullpo_retr(-1, sd); - + if ( !homun_alive(sd->hd) ) { clif->message(fd, msg_txt(1254)); // You do not have a homunculus. return false; @@ -6951,9 +6887,7 @@ ACMD(homfriendly) ACMD(homhungry) { int hungry = 0; - - nullpo_retr(-1, sd); - + if ( !homun_alive(sd->hd) ) { clif->message(fd, msg_txt(1254)); // You do not have a homunculus. return false; @@ -6978,17 +6912,15 @@ ACMD(homhungry) ACMD(homtalk) { char mes[100],temp[100]; - - nullpo_retr(-1, sd); - + if ( battle_config.min_chat_delay ) { - if( DIFF_TICK(sd->cantalk_tick, iTimer->gettick()) > 0 ) + if( DIFF_TICK(sd->cantalk_tick, timer->gettick()) > 0 ) return true; - sd->cantalk_tick = iTimer->gettick() + battle_config.min_chat_delay; + sd->cantalk_tick = timer->gettick() + battle_config.min_chat_delay; } if (sd->sc.count && //no "chatting" while muted. - (sd->sc.data[SC_BERSERK] || sd->sc.data[SC_DEEP_SLEEP] || sd->sc.data[SC__BLOODYLUST] || + (sd->sc.data[SC_BERSERK] || (sd->sc.data[SC_DEEP_SLEEP] && sd->sc.data[SC_DEEP_SLEEP]->val2) || (sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOCHAT))) return false; @@ -7011,11 +6943,9 @@ ACMD(homtalk) /*========================================== * Show homunculus stats *------------------------------------------*/ -ACMD(hominfo) -{ +ACMD(hominfo) { struct homun_data *hd; - struct status_data *status; - nullpo_retr(-1, sd); + struct status_data *st; if ( !homun_alive(sd->hd) ) { clif->message(fd, msg_txt(1254)); // You do not have a homunculus. @@ -7023,15 +6953,15 @@ ACMD(hominfo) } hd = sd->hd; - status = status_get_status_data(&hd->bl); + st = status->get_status_data(&hd->bl); clif->message(fd, msg_txt(1261)); // Homunculus stats: snprintf(atcmd_output, sizeof(atcmd_output) ,msg_txt(1262), // HP: %d/%d - SP: %d/%d - status->hp, status->max_hp, status->sp, status->max_sp); + st->hp, st->max_hp, st->sp, st->max_sp); clif->message(fd, atcmd_output); snprintf(atcmd_output, sizeof(atcmd_output) ,msg_txt(1263), // ATK: %d - MATK: %d~%d - status->rhw.atk2 +status->batk, status->matk_min, status->matk_max); + st->rhw.atk2 +st->batk, st->matk_min, st->matk_max); clif->message(fd, atcmd_output); snprintf(atcmd_output, sizeof(atcmd_output) ,msg_txt(1264), // Hungry: %d - Intimacy: %u @@ -7040,8 +6970,8 @@ ACMD(hominfo) snprintf(atcmd_output, sizeof(atcmd_output) , msg_txt(1265), // Stats: Str %d / Agi %d / Vit %d / Int %d / Dex %d / Luk %d - status->str, status->agi, status->vit, - status->int_, status->dex, status->luk); + st->str, st->agi, st->vit, + st->int_, st->dex, st->luk); clif->message(fd, atcmd_output); return true; @@ -7053,9 +6983,7 @@ ACMD(homstats) struct s_homunculus_db *db; struct s_homunculus *hom; int lv, min, max, evo; - - nullpo_retr(-1, sd); - + if ( !homun_alive(sd->hd) ) { clif->message(fd, msg_txt(1254)); // You do not have a homunculus. return false; @@ -7117,7 +7045,6 @@ ACMD(homstats) } ACMD(homshuffle) { - nullpo_retr(-1, sd); if(!sd->hd) return false; // nothing to do @@ -7143,8 +7070,8 @@ ACMD(iteminfo) clif->message(fd, msg_txt(1276)); // Please enter an item name/ID (usage: @ii/@iteminfo <item name/ID>). return false; } - if ((item_array[0] = itemdb_exists(atoi(message))) == NULL) - count = itemdb_searchname_array(item_array, MAX_SEARCH, message); + if ((item_array[0] = itemdb->exists(atoi(message))) == NULL) + count = itemdb->search_name_array(item_array, MAX_SEARCH, message, 0); if (!count) { clif->message(fd, msg_txt(19)); // Invalid item ID or name. @@ -7160,7 +7087,7 @@ ACMD(iteminfo) item_data = item_array[i]; sprintf(atcmd_output, msg_txt(1277), // Item: '%s'/'%s'[%d] (%d) Type: %s | Extra Effect: %s item_data->name,item_data->jname,item_data->slot,item_data->nameid, - itemdb_typename(item_data->type), + itemdb->typename(item_data->type), (item_data->script==NULL)? msg_txt(1278) : msg_txt(1279) // None / With script ); clif->message(fd, atcmd_output); @@ -7170,10 +7097,12 @@ ACMD(iteminfo) if (item_data->maxchance == -1) strcpy(atcmd_output, msg_txt(1281)); // - Available in the shops only. - else if (!battle_config.atcommand_mobinfo_type && item_data->maxchance) - sprintf(atcmd_output, msg_txt(1282), (float)item_data->maxchance / 100 ); // - Maximal monsters drop chance: %02.02f%% - else - strcpy(atcmd_output, msg_txt(1283)); // - Monsters don't drop this item. + else if ( !battle_config.atcommand_mobinfo_type ) { + if( item_data->maxchance ) + sprintf(atcmd_output, msg_txt(1282), (float)item_data->maxchance / 100 ); // - Maximal monsters drop chance: %02.02f%% + else + strcpy(atcmd_output, msg_txt(1283)); // - Monsters don't drop this item. + } clif->message(fd, atcmd_output); } @@ -7192,8 +7121,8 @@ ACMD(whodrops) clif->message(fd, msg_txt(1284)); // Please enter item name/ID (usage: @whodrops <item name/ID>). return false; } - if ((item_array[0] = itemdb_exists(atoi(message))) == NULL) - count = itemdb_searchname_array(item_array, MAX_SEARCH, message); + if ((item_array[0] = itemdb->exists(atoi(message))) == NULL) + count = itemdb->search_name_array(item_array, MAX_SEARCH, message, 0); if (!count) { clif->message(fd, msg_txt(19)); // Invalid item ID or name. @@ -7219,7 +7148,7 @@ ACMD(whodrops) for (j=0; j < MAX_SEARCH && item_data->mob[j].chance > 0; j++) { - sprintf(atcmd_output, "- %s (%02.02f%%)", mob_db(item_data->mob[j].id)->jname, item_data->mob[j].chance/100.); + sprintf(atcmd_output, "- %s (%02.02f%%)", mob->db(item_data->mob[j].id)->jname, item_data->mob[j].chance/100.); clif->message(fd, atcmd_output); } } @@ -7229,7 +7158,7 @@ ACMD(whodrops) ACMD(whereis) { - struct mob_db *mob, *mob_array[MAX_SEARCH]; + struct mob_db *monster, *mob_array[MAX_SEARCH]; int count; int i, j, k; @@ -7239,12 +7168,12 @@ ACMD(whereis) } // If monster identifier/name argument is a name - if ((i = mobdb_checkid(atoi(message)))) + if ((i = mob->db_checkid(atoi(message)))) { - mob_array[0] = mob_db(i); + mob_array[0] = mob->db(i); count = 1; } else - count = mobdb_searchname_array(mob_array, MAX_SEARCH, message); + count = mob->db_searchname_array(mob_array, MAX_SEARCH, message, 0); if (!count) { clif->message(fd, msg_txt(40)); // Invalid monster ID or name. @@ -7257,15 +7186,14 @@ ACMD(whereis) count = MAX_SEARCH; } for (k = 0; k < count; k++) { - mob = mob_array[k]; - snprintf(atcmd_output, sizeof atcmd_output, msg_txt(1289), mob->jname); // %s spawns in: + monster = mob_array[k]; + snprintf(atcmd_output, sizeof atcmd_output, msg_txt(1289), monster->jname); // %s spawns in: clif->message(fd, atcmd_output); - for (i = 0; i < ARRAYLENGTH(mob->spawn) && mob->spawn[i].qty; i++) - { - j = iMap->mapindex2mapid(mob->spawn[i].mapindex); + for (i = 0; i < ARRAYLENGTH(monster->spawn) && monster->spawn[i].qty; i++) { + j = map->mapindex2mapid(monster->spawn[i].mapindex); if (j < 0) continue; - snprintf(atcmd_output, sizeof atcmd_output, "%s (%d)", map[j].name, mob->spawn[i].qty); + snprintf(atcmd_output, sizeof atcmd_output, "%s (%d)", map->list[j].name, monster->spawn[i].qty); clif->message(fd, atcmd_output); } if (i == 0) @@ -7276,26 +7204,19 @@ ACMD(whereis) } ACMD(version) { - const char *git = get_git_hash(); - const char *svn = get_svn_revision(); - - if ( git[0] != HERC_UNKNOWN_VER ) { - sprintf(atcmd_output,msg_txt(1295),git); // Git Hash '%s' - clif->message(fd,atcmd_output); - } else if ( svn[0] != HERC_UNKNOWN_VER ) { - sprintf(atcmd_output,msg_txt(1436),git); // SVN r%s - clif->message(fd,atcmd_output); - } else - clif->message(fd,msg_txt(1296)); // Cannot determine version - + sprintf(atcmd_output, msg_txt(1296), sysinfo->is64bit() ? 64 : 32, sysinfo->platform()); // Hercules %d-bit for %s + clif->message(fd, atcmd_output); + sprintf(atcmd_output, msg_txt(1295), sysinfo->vcstype(), sysinfo->vcsrevision_src(), sysinfo->vcsrevision_scripts()); // %s revision '%s' (src) / '%s' (scripts) + clif->message(fd, atcmd_output); + return true; } /*========================================== * @mutearea by MouseJstr *------------------------------------------*/ -static int atcommand_mutearea_sub(struct block_list *bl,va_list ap) -{ +int atcommand_mutearea_sub(struct block_list *bl,va_list ap) +{ // As it is being used [ACMD(mutearea)] there's no need to be a bool, but if there's need to reuse it, it's better to be this way int time, id; struct map_session_data *pl_sd = (struct map_session_data *)bl; @@ -7305,20 +7226,18 @@ static int atcommand_mutearea_sub(struct block_list *bl,va_list ap) id = va_arg(ap, int); time = va_arg(ap, int); - if (id != bl->id && !pc->get_group_level(pl_sd)) { + if (id != bl->id && !pc_get_group_level(pl_sd)) { pl_sd->status.manner -= time; if (pl_sd->status.manner < 0) - sc_start(&pl_sd->bl,SC_NOCHAT,100,0,0); + sc_start(NULL,&pl_sd->bl,SC_NOCHAT,100,0,0); else status_change_end(&pl_sd->bl, SC_NOCHAT, INVALID_TIMER); } - return 0; + return 1; } -ACMD(mutearea) -{ +ACMD(mutearea) { int time; - nullpo_ret(sd); if (!message || !*message) { clif->message(fd, msg_txt(1297)); // Please enter a time in minutes (usage: @mutearea/@stfu <time in minutes>). @@ -7327,9 +7246,9 @@ ACMD(mutearea) time = atoi(message); - iMap->foreachinarea(atcommand_mutearea_sub,sd->bl.m, - sd->bl.x-AREA_SIZE, sd->bl.y-AREA_SIZE, - sd->bl.x+AREA_SIZE, sd->bl.y+AREA_SIZE, BL_PC, sd->bl.id, time); + map->foreachinarea(atcommand->mutearea_sub,sd->bl.m, + sd->bl.x-AREA_SIZE, sd->bl.y-AREA_SIZE, + sd->bl.x+AREA_SIZE, sd->bl.y+AREA_SIZE, BL_PC, sd->bl.id, time); return true; } @@ -7339,7 +7258,6 @@ ACMD(rates) { char buf[CHAT_SIZE_MAX]; - nullpo_ret(sd); memset(buf, '\0', sizeof(buf)); snprintf(buf, CHAT_SIZE_MAX, msg_txt(1298), // Experience rates: Base %.2fx / Job %.2fx @@ -7365,13 +7283,12 @@ ACMD(rates) ACMD(me) { char tempmes[CHAT_SIZE_MAX]; - nullpo_retr(-1, sd); memset(tempmes, '\0', sizeof(tempmes)); memset(atcmd_output, '\0', sizeof(atcmd_output)); if (sd->sc.count && //no "chatting" while muted. - (sd->sc.data[SC_BERSERK] || sd->sc.data[SC_DEEP_SLEEP] || sd->sc.data[SC__BLOODYLUST] || + (sd->sc.data[SC_BERSERK] || (sd->sc.data[SC_DEEP_SLEEP] && sd->sc.data[SC_DEEP_SLEEP]->val2) || (sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOCHAT))) return false; @@ -7394,17 +7311,16 @@ ACMD(me) ACMD(size) { int size = 0; - nullpo_retr(-1, sd); - size = cap_value(atoi(message),SZ_SMALL,SZ_BIG); + size = cap_value(atoi(message),SZ_MEDIUM,SZ_BIG); if(sd->state.size) { - sd->state.size = SZ_SMALL; + sd->state.size = SZ_MEDIUM; pc->setpos(sd, sd->mapindex, sd->bl.x, sd->bl.y, CLR_TELEPORT); } sd->state.size = size; - if( size == SZ_MEDIUM ) + if( size == SZ_SMALL ) clif->specialeffect(&sd->bl,420,AREA); else if( size == SZ_BIG ) clif->specialeffect(&sd->bl,422,AREA); @@ -7426,12 +7342,12 @@ ACMD(sizeall) for( pl_sd = (TBL_PC*)mapit->first(iter); mapit->exists(iter); pl_sd = (TBL_PC*)mapit->next(iter) ) { if( pl_sd->state.size != size ) { if( pl_sd->state.size ) { - pl_sd->state.size = SZ_SMALL; + pl_sd->state.size = SZ_MEDIUM; pc->setpos(pl_sd, pl_sd->mapindex, pl_sd->bl.x, pl_sd->bl.y, CLR_TELEPORT); } pl_sd->state.size = size; - if( size == SZ_MEDIUM ) + if( size == SZ_SMALL ) clif->specialeffect(&pl_sd->bl,420,AREA); else if( size == SZ_BIG ) clif->specialeffect(&pl_sd->bl,422,AREA); @@ -7449,7 +7365,6 @@ ACMD(sizeguild) char guild_name[NAME_LENGTH]; struct map_session_data *pl_sd; struct guild *g; - nullpo_retr(-1, sd); memset(guild_name, '\0', sizeof(guild_name)); @@ -7463,17 +7378,17 @@ ACMD(sizeguild) return false; } - size = cap_value(size,SZ_SMALL,SZ_BIG); + size = cap_value(size,SZ_MEDIUM,SZ_BIG); for( i = 0; i < g->max_member; i++ ) { if( (pl_sd = g->member[i].sd) && pl_sd->state.size != size ) { if( pl_sd->state.size ) { - pl_sd->state.size = SZ_SMALL; + pl_sd->state.size = SZ_MEDIUM; pc->setpos(pl_sd, pl_sd->mapindex, pl_sd->bl.x, pl_sd->bl.y, CLR_TELEPORT); } pl_sd->state.size = size; - if( size == SZ_MEDIUM ) + if( size == SZ_SMALL ) clif->specialeffect(&pl_sd->bl,420,AREA); else if( size == SZ_BIG ) clif->specialeffect(&pl_sd->bl,422,AREA); @@ -7488,9 +7403,7 @@ ACMD(sizeguild) * @monsterignore * => Makes monsters ignore you. [Valaris] *------------------------------------------*/ -ACMD(monsterignore) -{ - nullpo_retr(-1, sd); +ACMD(monsterignore) { if (!sd->state.monster_ignore) { sd->state.monster_ignore = 1; @@ -7506,9 +7419,7 @@ ACMD(monsterignore) * @fakename * => Gives your character a fake name. [Valaris] *------------------------------------------*/ -ACMD(fakename) -{ - nullpo_retr(-1, sd); +ACMD(fakename){ if( !message || !*message ) { @@ -7516,6 +7427,8 @@ ACMD(fakename) { sd->fakename[0] = '\0'; clif->charnameack(0, &sd->bl); + if( sd->disguise ) + clif->charnameack(sd->fd, &sd->bl); clif->message(sd->fd, msg_txt(1307)); // Returned to real name. return true; } @@ -7532,6 +7445,8 @@ ACMD(fakename) safestrncpy(sd->fakename, message, sizeof(sd->fakename)); clif->charnameack(0, &sd->bl); + if( sd->disguise ) // Another packet should be sent so the client updates the name for sd + clif->charnameack(sd->fd, &sd->bl); clif->message(sd->fd, msg_txt(1310)); // Fake name enabled. return true; @@ -7541,70 +7456,74 @@ ACMD(fakename) * Ragnarok Resources *------------------------------------------*/ ACMD(mapflag) { -#define checkflag( cmd ) if ( map[ sd->bl.m ].flag.cmd ) clif->message(sd->fd,#cmd) -#define setflag( cmd ) \ -if ( strcmp( flag_name , #cmd ) == 0 ){\ -map[ sd->bl.m ].flag.cmd = flag;\ -sprintf(atcmd_output,"[ @mapflag ] %s flag has been set to %s value = %hd",#cmd,flag?"On":"Off",flag);\ -clif->message(sd->fd,atcmd_output);\ -return true;\ -} +#define CHECKFLAG( cmd ) do { if ( map->list[ sd->bl.m ].flag.cmd ) clif->message(sd->fd,#cmd); } while(0) +#define SETFLAG( cmd ) do { \ + if ( strcmp( flag_name , #cmd ) == 0 ) { \ + map->list[ sd->bl.m ].flag.cmd = flag; \ + sprintf(atcmd_output,"[ @mapflag ] %s flag has been set to %s value = %hd",#cmd,flag?"On":"Off",flag); \ + clif->message(sd->fd,atcmd_output); \ + return true; \ + } \ +} while(0) + char flag_name[100]; short flag=0,i; - nullpo_retr(-1, sd); + memset(flag_name, '\0', sizeof(flag_name)); if (!message || !*message || (sscanf(message, "%99s %hd", flag_name, &flag) < 1)) { clif->message(sd->fd,msg_txt(1311)); // Enabled Mapflags in this map: clif->message(sd->fd,"----------------------------------"); - checkflag(autotrade); checkflag(allowks); checkflag(nomemo); checkflag(noteleport); - checkflag(noreturn); checkflag(monster_noteleport); checkflag(nosave); checkflag(nobranch); - checkflag(noexppenalty); checkflag(pvp); checkflag(pvp_noparty); checkflag(pvp_noguild); - checkflag(pvp_nightmaredrop); checkflag(pvp_nocalcrank); checkflag(gvg_castle); checkflag(gvg); - checkflag(gvg_dungeon); checkflag(gvg_noparty); checkflag(battleground);checkflag(nozenypenalty); - checkflag(notrade); checkflag(noskill); checkflag(nowarp); checkflag(nowarpto); - checkflag(noicewall); checkflag(snow); checkflag(clouds); checkflag(clouds2); - checkflag(fog); checkflag(fireworks); checkflag(sakura); checkflag(leaves); - checkflag(nobaseexp); - checkflag(nojobexp); checkflag(nomobloot); checkflag(nomvploot); checkflag(nightenabled); - checkflag(nodrop); checkflag(novending); checkflag(loadevent); - checkflag(nochat); checkflag(partylock); checkflag(guildlock); checkflag(src4instance); + CHECKFLAG(autotrade); CHECKFLAG(allowks); CHECKFLAG(nomemo); CHECKFLAG(noteleport); + CHECKFLAG(noreturn); CHECKFLAG(monster_noteleport); CHECKFLAG(nosave); CHECKFLAG(nobranch); + CHECKFLAG(noexppenalty); CHECKFLAG(pvp); CHECKFLAG(pvp_noparty); CHECKFLAG(pvp_noguild); + CHECKFLAG(pvp_nightmaredrop); CHECKFLAG(pvp_nocalcrank); CHECKFLAG(gvg_castle); CHECKFLAG(gvg); + CHECKFLAG(gvg_dungeon); CHECKFLAG(gvg_noparty); CHECKFLAG(battleground); CHECKFLAG(nozenypenalty); + CHECKFLAG(notrade); CHECKFLAG(noskill); CHECKFLAG(nowarp); CHECKFLAG(nowarpto); + CHECKFLAG(noicewall); CHECKFLAG(snow); CHECKFLAG(clouds); CHECKFLAG(clouds2); + CHECKFLAG(fog); CHECKFLAG(fireworks); CHECKFLAG(sakura); CHECKFLAG(leaves); + CHECKFLAG(nobaseexp); + CHECKFLAG(nojobexp); CHECKFLAG(nomobloot); CHECKFLAG(nomvploot); CHECKFLAG(nightenabled); + CHECKFLAG(nodrop); CHECKFLAG(novending); CHECKFLAG(loadevent); + CHECKFLAG(nochat); CHECKFLAG(partylock); CHECKFLAG(guildlock); CHECKFLAG(src4instance); + CHECKFLAG(notomb); CHECKFLAG(nocashshop); clif->message(sd->fd," "); clif->message(sd->fd,msg_txt(1312)); // Usage: "@mapflag monster_noteleport 1" (0=Off | 1=On) clif->message(sd->fd,msg_txt(1313)); // Type "@mapflag available" to list the available mapflags. - return 1; + return true; } - for (i = 0; flag_name[i]; i++) flag_name[i] = (char)tolower(flag_name[i]); //lowercase + for (i = 0; flag_name[i]; i++) flag_name[i] = TOLOWER(flag_name[i]); //lowercase if ( strcmp( flag_name , "gvg" ) == 0 ) { - if( flag && !map[sd->bl.m].flag.gvg ) - iMap->zone_change2(sd->bl.m,strdb_get(zone_db, MAP_ZONE_GVG_NAME)); - else if ( !flag && map[sd->bl.m].flag.gvg ) - iMap->zone_change2(sd->bl.m,map[sd->bl.m].prev_zone); + if( flag && !map->list[sd->bl.m].flag.gvg ) + map->zone_change2(sd->bl.m,strdb_get(map->zone_db, MAP_ZONE_GVG_NAME)); + else if ( !flag && map->list[sd->bl.m].flag.gvg ) + map->zone_change2(sd->bl.m,map->list[sd->bl.m].prev_zone); } else if ( strcmp( flag_name , "pvp" ) == 0 ) { - if( flag && !map[sd->bl.m].flag.pvp ) - iMap->zone_change2(sd->bl.m,strdb_get(zone_db, MAP_ZONE_PVP_NAME)); - else if ( !flag && map[sd->bl.m].flag.pvp ) - iMap->zone_change2(sd->bl.m,map[sd->bl.m].prev_zone); + if( flag && !map->list[sd->bl.m].flag.pvp ) + map->zone_change2(sd->bl.m,strdb_get(map->zone_db, MAP_ZONE_PVP_NAME)); + else if ( !flag && map->list[sd->bl.m].flag.pvp ) + map->zone_change2(sd->bl.m,map->list[sd->bl.m].prev_zone); } else if ( strcmp( flag_name , "battleground" ) == 0 ) { - if( flag && !map[sd->bl.m].flag.battleground ) - iMap->zone_change2(sd->bl.m,strdb_get(zone_db, MAP_ZONE_BG_NAME)); - else if ( !flag && map[sd->bl.m].flag.battleground ) - iMap->zone_change2(sd->bl.m,map[sd->bl.m].prev_zone); - } - - setflag(autotrade); setflag(allowks); setflag(nomemo); setflag(noteleport); - setflag(noreturn); setflag(monster_noteleport);setflag(nosave); setflag(nobranch); - setflag(noexppenalty); setflag(pvp); setflag(pvp_noparty); setflag(pvp_noguild); - setflag(pvp_nightmaredrop); setflag(pvp_nocalcrank); setflag(gvg_castle); setflag(gvg); - setflag(gvg_dungeon); setflag(gvg_noparty); setflag(battleground); setflag(nozenypenalty); - setflag(notrade); setflag(noskill); setflag(nowarp); setflag(nowarpto); - setflag(noicewall); setflag(snow); setflag(clouds); setflag(clouds2); - setflag(fog); setflag(fireworks); setflag(sakura); setflag(leaves); - setflag(nobaseexp); - setflag(nojobexp); setflag(nomobloot); setflag(nomvploot); setflag(nightenabled); - setflag(nodrop); setflag(novending); setflag(loadevent); - setflag(nochat); setflag(partylock); setflag(guildlock); setflag(src4instance); + if( flag && !map->list[sd->bl.m].flag.battleground ) + map->zone_change2(sd->bl.m,strdb_get(map->zone_db, MAP_ZONE_BG_NAME)); + else if ( !flag && map->list[sd->bl.m].flag.battleground ) + map->zone_change2(sd->bl.m,map->list[sd->bl.m].prev_zone); + } + + SETFLAG(autotrade); SETFLAG(allowks); SETFLAG(nomemo); SETFLAG(noteleport); + SETFLAG(noreturn); SETFLAG(monster_noteleport); SETFLAG(nosave); SETFLAG(nobranch); + SETFLAG(noexppenalty); SETFLAG(pvp); SETFLAG(pvp_noparty); SETFLAG(pvp_noguild); + SETFLAG(pvp_nightmaredrop); SETFLAG(pvp_nocalcrank); SETFLAG(gvg_castle); SETFLAG(gvg); + SETFLAG(gvg_dungeon); SETFLAG(gvg_noparty); SETFLAG(battleground); SETFLAG(nozenypenalty); + SETFLAG(notrade); SETFLAG(noskill); SETFLAG(nowarp); SETFLAG(nowarpto); + SETFLAG(noicewall); SETFLAG(snow); SETFLAG(clouds); SETFLAG(clouds2); + SETFLAG(fog); SETFLAG(fireworks); SETFLAG(sakura); SETFLAG(leaves); + SETFLAG(nobaseexp); + SETFLAG(nojobexp); SETFLAG(nomobloot); SETFLAG(nomvploot); SETFLAG(nightenabled); + SETFLAG(nodrop); SETFLAG(novending); SETFLAG(loadevent); + SETFLAG(nochat); SETFLAG(partylock); SETFLAG(guildlock); SETFLAG(src4instance); + SETFLAG(notomb); SETFLAG(nocashshop); clif->message(sd->fd,msg_txt(1314)); // Invalid flag name or flag. clif->message(sd->fd,msg_txt(1312)); // Usage: "@mapflag monster_noteleport 1" (0=Off | 1=On) @@ -7616,10 +7535,10 @@ return true;\ clif->message(sd->fd,"nozenypenalty, notrade, noskill, nowarp, nowarpto, noicewall, snow, clouds, clouds2,"); clif->message(sd->fd,"fog, fireworks, sakura, leaves, nobaseexp, nojobexp, nomobloot,"); clif->message(sd->fd,"nomvploot, nightenabled, nodrop, novending, loadevent, nochat, partylock,"); - clif->message(sd->fd,"guildlock, src4instance"); + clif->message(sd->fd,"guildlock, src4instance, notomb, nocashshop"); -#undef checkflag -#undef setflag +#undef CHECKFLAG +#undef SETFLAG return true; } @@ -7675,157 +7594,154 @@ ACMD(showdelay) * @reject - reject invitation * @leave - leave duel *------------------------------------------*/ -ACMD(invite) -{ +ACMD(invite) { unsigned int did = sd->duel_group; - struct map_session_data *target_sd = iMap->nick2sd((char *)message); + struct map_session_data *target_sd = map->nick2sd((char *)message); - if(did == 0) { + if(did == 0) + { // "Duel: @invite without @duel." clif->message(fd, msg_txt(350)); - return true; + return false; } - if(duel_list[did].max_players_limit > 0 && - duel_list[did].members_count >= duel_list[did].max_players_limit) { + if(duel->list[did].max_players_limit > 0 && + duel->list[did].members_count >= duel->list[did].max_players_limit) { // "Duel: Limit of players is reached." clif->message(fd, msg_txt(351)); - return true; + return false; } if(target_sd == NULL) { // "Duel: Player not found." clif->message(fd, msg_txt(352)); - return true; + return false; } if(target_sd->duel_group > 0 || target_sd->duel_invite > 0) { // "Duel: Player already in duel." clif->message(fd, msg_txt(353)); - return true; + return false; } if(battle_config.duel_only_on_same_map && target_sd->bl.m != sd->bl.m) { + // "Duel: You can't invite %s because he/she isn't in the same map." sprintf(atcmd_output, msg_txt(364), message); clif->message(fd, atcmd_output); - return true; + return false; } - duel_invite(did, sd, target_sd); + duel->invite(did, sd, target_sd); // "Duel: Invitation has been sent." clif->message(fd, msg_txt(354)); return true; } -ACMD(duel) -{ +ACMD(duel) { unsigned int maxpl = 0; if(sd->duel_group > 0) { - duel_showinfo(sd->duel_group, sd); + duel->showinfo(sd->duel_group, sd); return true; } if(sd->duel_invite > 0) { // "Duel: @duel without @reject." clif->message(fd, msg_txt(355)); - return true; + return false; } - if(!duel_checktime(sd)) { + if(!duel->checktime(sd)) { char output[CHAT_SIZE_MAX]; // "Duel: You can take part in duel only one time per %d minutes." sprintf(output, msg_txt(356), battle_config.duel_time_interval); clif->message(fd, output); - return true; + return false; } if( message[0] ) { if(sscanf(message, "%d", &maxpl) >= 1) { if(maxpl < 2 || maxpl > 65535) { clif->message(fd, msg_txt(357)); // "Duel: Invalid value." - return true; + return false; } - duel_create(sd, maxpl); + duel->create(sd, maxpl); } else { struct map_session_data *target_sd; - target_sd = iMap->nick2sd((char *)message); + target_sd = map->nick2sd((char *)message); if(target_sd != NULL) { unsigned int newduel; - if((newduel = duel_create(sd, 2)) != -1) { + if((newduel = duel->create(sd, 2)) != -1) { if(target_sd->duel_group > 0 || target_sd->duel_invite > 0) { clif->message(fd, msg_txt(353)); // "Duel: Player already in duel." - return true; + return false; } - duel_invite(newduel, sd, target_sd); + duel->invite(newduel, sd, target_sd); clif->message(fd, msg_txt(354)); // "Duel: Invitation has been sent." } } else { // "Duel: Player not found." clif->message(fd, msg_txt(352)); - return true; + return false; } } } else - duel_create(sd, 0); + duel->create(sd, 0); return true; } -ACMD(leave) -{ +ACMD(leave) { if(sd->duel_group <= 0) { // "Duel: @leave without @duel." clif->message(fd, msg_txt(358)); - return true; + return false; } - duel_leave(sd->duel_group, sd); + duel->leave(sd->duel_group, sd); clif->message(fd, msg_txt(359)); // "Duel: You left the duel." return true; } -ACMD(accept) -{ - if(!duel_checktime(sd)) { +ACMD(accept) { + if(!duel->checktime(sd)) { char output[CHAT_SIZE_MAX]; // "Duel: You can take part in duel only one time per %d minutes." sprintf(output, msg_txt(356), battle_config.duel_time_interval); clif->message(fd, output); - return true; + return false; } if(sd->duel_invite <= 0) { - // "Duel: @accept without invititation." + // "Duel: @accept without invitation." clif->message(fd, msg_txt(360)); - return true; + return false; } - if( duel_list[sd->duel_invite].max_players_limit > 0 && duel_list[sd->duel_invite].members_count >= duel_list[sd->duel_invite].max_players_limit ) - { + if( duel->list[sd->duel_invite].max_players_limit > 0 + && duel->list[sd->duel_invite].members_count >= duel->list[sd->duel_invite].max_players_limit ) { // "Duel: Limit of players is reached." clif->message(fd, msg_txt(351)); - return true; + return false; } - duel_accept(sd->duel_invite, sd); + duel->accept(sd->duel_invite, sd); // "Duel: Invitation has been accepted." clif->message(fd, msg_txt(361)); return true; } -ACMD(reject) -{ +ACMD(reject) { if(sd->duel_invite <= 0) { - // "Duel: @reject without invititation." + // "Duel: @reject without invitation." clif->message(fd, msg_txt(362)); - return true; + return false; } - duel_reject(sd->duel_invite, sd); + duel->reject(sd->duel_invite, sd); // "Duel: Invitation has been rejected." clif->message(fd, msg_txt(363)); return true; @@ -7839,43 +7755,45 @@ ACMD(cash) char output[128]; int value; int ret=0; - nullpo_retr(-1, sd); if( !message || !*message || (value = atoi(message)) == 0 ) { clif->message(fd, msg_txt(1322)); // Please enter an amount. return false; } - if( !strcmpi(command+1,"cash") ) - { + if( !strcmpi(info->command,"cash") ) { if( value > 0 ) { if( (ret=pc->getcash(sd, value, 0)) >= 0){ - sprintf(output, msg_txt(505), ret, sd->cashPoints); - clif->disp_onlyself(sd, output, strlen(output)); - } - else clif->message(fd, msg_txt(149)); // Unable to decrease the number/value. + // If this option is set, the message is already sent by pc function + if( !battle_config.cashshop_show_points ){ + sprintf(output, msg_txt(505), ret, sd->cashPoints); + clif_disp_onlyself(sd, output, strlen(output)); + } + } else + clif->message(fd, msg_txt(149)); // Unable to decrease the number/value. } else { if( (ret=pc->paycash(sd, -value, 0)) >= 0){ sprintf(output, msg_txt(410), ret, sd->cashPoints); - clif->disp_onlyself(sd, output, strlen(output)); - } - else clif->message(fd, msg_txt(41)); // Unable to decrease the number/value. + clif_disp_onlyself(sd, output, strlen(output)); + } else + clif->message(fd, msg_txt(41)); // Unable to decrease the number/value. } - } - else - { // @points + } else { // @points if( value > 0 ) { - if( (ret=pc->getcash(sd, 0, value)) >= 0){ - sprintf(output, msg_txt(506), ret, sd->kafraPoints); - clif->disp_onlyself(sd, output, strlen(output)); - } - else clif->message(fd, msg_txt(149)); // Unable to decrease the number/value. + if( (ret=pc->getcash(sd, 0, value)) >= 0) { + // If this option is set, the message is already sent by pc function + if( !battle_config.cashshop_show_points ){ + sprintf(output, msg_txt(506), ret, sd->kafraPoints); + clif_disp_onlyself(sd, output, strlen(output)); + } + } else + clif->message(fd, msg_txt(149)); // Unable to decrease the number/value. } else { if( (ret=pc->paycash(sd, -value, -value)) >= 0){ sprintf(output, msg_txt(411), ret, sd->kafraPoints); - clif->disp_onlyself(sd, output, strlen(output)); - } - else clif->message(fd, msg_txt(41)); // Unable to decrease the number/value. + clif_disp_onlyself(sd, output, strlen(output)); + } else + clif->message(fd, msg_txt(41)); // Unable to decrease the number/value. } } @@ -7883,58 +7801,58 @@ ACMD(cash) } // @clone/@slaveclone/@evilclone <playername> [Valaris] -ACMD(clone) -{ +ACMD(clone) { int x=0,y=0,flag=0,master=0,i=0; struct map_session_data *pl_sd=NULL; if (!message || !*message) { clif->message(sd->fd,msg_txt(1323)); // You must enter a player name or ID. - return true; + return false; } - if((pl_sd=iMap->nick2sd((char *)message)) == NULL && (pl_sd=iMap->charid2sd(atoi(message))) == NULL) { + if((pl_sd=map->nick2sd((char *)message)) == NULL && (pl_sd=map->charid2sd(atoi(message))) == NULL) { clif->message(fd, msg_txt(3)); // Character not found. - return true; + return false; } - if(pc->get_group_level(pl_sd) > pc->get_group_level(sd)) { + if(pc_get_group_level(pl_sd) > pc_get_group_level(sd)) { clif->message(fd, msg_txt(126)); // Cannot clone a player of higher GM level than yourself. - return true; + return false; } - if (strcmpi(command+1, "clone") == 0) + if (strcmpi(info->command, "clone") == 0) flag = 1; - else if (strcmpi(command+1, "slaveclone") == 0) { + else if (strcmpi(info->command, "slaveclone") == 0) { flag = 2; if(pc_isdead(sd)){ + //"Unable to spawn slave clone." clif->message(fd, msg_txt(129+flag*2)); - return true; + return false; } master = sd->bl.id; if (battle_config.atc_slave_clone_limit - && mob_countslave(&sd->bl) >= battle_config.atc_slave_clone_limit) { + && mob->countslave(&sd->bl) >= battle_config.atc_slave_clone_limit) { clif->message(fd, msg_txt(127)); // You've reached your slave clones limit. - return true; + return false; } } do { x = sd->bl.x + (rnd() % 10 - 5); y = sd->bl.y + (rnd() % 10 - 5); - } while (iMap->getcell(sd->bl.m,x,y,CELL_CHKNOPASS) && i++ < 10); + } while (map->getcell(sd->bl.m,x,y,CELL_CHKNOPASS) && i++ < 10); if (i >= 10) { x = sd->bl.x; y = sd->bl.y; } - if((x = mob_clone_spawn(pl_sd, sd->bl.m, x, y, "", master, 0, flag?1:0, 0)) > 0) { + if((x = mob->clone_spawn(pl_sd, sd->bl.m, x, y, "", master, 0, flag?1:0, 0)) > 0) { clif->message(fd, msg_txt(128+flag*2)); // Evil Clone spawned. Clone spawned. Slave clone spawned. return true; } clif->message(fd, msg_txt(129+flag*2)); // Unable to spawn evil clone. Unable to spawn clone. Unable to spawn slave clone. - return true; + return false; } /*===================================== @@ -7966,8 +7884,8 @@ ACMD(request) } sprintf(atcmd_output, msg_txt(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)); + intif->wis_message_to_gm(sd->status.name, PC_PERM_RECEIVE_REQUESTS, atcmd_output); + clif_disp_onlyself(sd, atcmd_output, strlen(atcmd_output)); clif->message(sd->fd,msg_txt(279)); // @request sent. return true; } @@ -7986,9 +7904,12 @@ ACMD(feelreset) /*========================================== * AUCTION SYSTEM *------------------------------------------*/ -ACMD(auction) -{ - nullpo_ret(sd); +ACMD(auction) { + + if( !battle_config.feature_auction ) { + clif->colormes(sd->fd,COLOR_RED,msg_txt(1484)); + return false; + } clif->auction_openwindow(sd); @@ -8000,8 +7921,6 @@ ACMD(auction) *------------------------------------------*/ ACMD(ksprotection) { - nullpo_retr(-1,sd); - if( sd->state.noks ) { sd->state.noks = 0; clif->message(fd, msg_txt(1325)); // [ K.S Protection Inactive ] @@ -8031,23 +7950,19 @@ ACMD(ksprotection) /*========================================== * Map Kill Steal Protection Setting *------------------------------------------*/ -ACMD(allowks) -{ - nullpo_retr(-1,sd); +ACMD(allowks) { - if( map[sd->bl.m].flag.allowks ) { - map[sd->bl.m].flag.allowks = 0; + if( map->list[sd->bl.m].flag.allowks ) { + map->list[sd->bl.m].flag.allowks = 0; clif->message(fd, msg_txt(1330)); // [ Map K.S Protection Active ] } else { - map[sd->bl.m].flag.allowks = 1; + map->list[sd->bl.m].flag.allowks = 1; clif->message(fd, msg_txt(1331)); // [ Map K.S Protection Inactive ] } return true; } -ACMD(resetstat) -{ - nullpo_retr(-1, sd); +ACMD(resetstat) { pc->resetstate(sd); sprintf(atcmd_output, msg_txt(207), sd->status.name); @@ -8055,9 +7970,7 @@ ACMD(resetstat) return true; } -ACMD(resetskill) -{ - nullpo_retr(-1,sd); +ACMD(resetskill) { pc->resetskill(sd,1); sprintf(atcmd_output, msg_txt(206), sd->status.name); @@ -8077,31 +7990,21 @@ ACMD(itemlist) const struct item* items; int size; StringBuf buf; - - nullpo_retr(-1, sd); - - if( strcmp(command+1, "storagelist") == 0 ) - { + + if( strcmpi(info->command, "storagelist") == 0 ) { location = "storage"; items = sd->status.storage.items; size = MAX_STORAGE; - } - else - if( strcmp(command+1, "cartlist") == 0 ) - { - location = "cart"; - items = sd->status.cart; - size = MAX_CART; - } - else - if( strcmp(command+1, "itemlist") == 0 ) - { - location = "inventory"; - items = sd->status.inventory; - size = MAX_INVENTORY; - } - else - return 1; + } else if( strcmpi(info->command, "cartlist") == 0 ) { + location = "cart"; + items = sd->status.cart; + size = MAX_CART; + } else if( strcmpi(info->command, "itemlist") == 0 ) { + location = "inventory"; + items = sd->status.inventory; + size = MAX_INVENTORY; + } else + return false; StrBuf->Init(&buf); @@ -8112,7 +8015,7 @@ ACMD(itemlist) const struct item* it = &items[i]; struct item_data* itd; - if( it->nameid == 0 || (itd = itemdb_exists(it->nameid)) == NULL ) + if( it->nameid == 0 || (itd = itemdb->exists(it->nameid)) == NULL ) continue; counter += it->amount; @@ -8130,8 +8033,7 @@ ACMD(itemlist) else StrBuf->Printf(&buf, "%d %s (%s, id: %d)", it->amount, itd->jname, itd->name, it->nameid); - if( it->equip ) - { + if( it->equip ) { char equipstr[CHAT_SIZE_MAX]; strcpy(equipstr, msg_txt(1333)); // | equipped: if( it->equip & EQP_GARMENT ) @@ -8170,52 +8072,46 @@ ACMD(itemlist) clif->message(fd, StrBuf->Value(&buf)); StrBuf->Clear(&buf); - if( it->card[0] == CARD0_PET ) - {// pet egg + if( it->card[0] == CARD0_PET ) { + // pet egg if (it->card[3]) StrBuf->Printf(&buf, msg_txt(1348), (unsigned int)MakeDWord(it->card[1], it->card[2])); // -> (pet egg, pet id: %u, named) else StrBuf->Printf(&buf, msg_txt(1349), (unsigned int)MakeDWord(it->card[1], it->card[2])); // -> (pet egg, pet id: %u, unnamed) - } - else - if(it->card[0] == CARD0_FORGE) - {// forged item - StrBuf->Printf(&buf, msg_txt(1350), (unsigned int)MakeDWord(it->card[2], it->card[3]), it->card[1]>>8, it->card[1]&0x0f); // -> (crafted item, creator id: %u, star crumbs %d, element %d) + } else if(it->card[0] == CARD0_FORGE) { + // forged item + StrBuf->Printf(&buf, msg_txt(1350), (unsigned int)MakeDWord(it->card[2], it->card[3]), it->card[1]>>8, it->card[1]&0x0f); // -> (crafted item, creator id: %u, star crumbs %d, element %d) + } else if(it->card[0] == CARD0_CREATE) { + // created item + StrBuf->Printf(&buf, msg_txt(1351), (unsigned int)MakeDWord(it->card[2], it->card[3])); // -> (produced item, creator id: %u) + } else { + // normal item + int counter2 = 0; + + for( j = 0; j < itd->slot; ++j ) { + struct item_data* card; + + if( it->card[j] == 0 || (card = itemdb->exists(it->card[j])) == NULL ) + continue; + + counter2++; + + if( counter2 == 1 ) + StrBuf->AppendStr(&buf, msg_txt(1352)); // -> (card(s): + + if( counter2 != 1 ) + StrBuf->AppendStr(&buf, ", "); + + StrBuf->Printf(&buf, "#%d %s (id: %d)", counter2, card->jname, card->nameid); } - else - if(it->card[0] == CARD0_CREATE) - {// created item - StrBuf->Printf(&buf, msg_txt(1351), (unsigned int)MakeDWord(it->card[2], it->card[3])); // -> (produced item, creator id: %u) - } - else - {// normal item - int counter2 = 0; - - for( j = 0; j < itd->slot; ++j ) - { - struct item_data* card; - - if( it->card[j] == 0 || (card = itemdb_exists(it->card[j])) == NULL ) - continue; - - counter2++; - - if( counter2 == 1 ) - StrBuf->AppendStr(&buf, msg_txt(1352)); // -> (card(s): - - if( counter2 != 1 ) - StrBuf->AppendStr(&buf, ", "); - - StrBuf->Printf(&buf, "#%d %s (id: %d)", counter2, card->jname, card->nameid); - } - - if( counter2 > 0 ) - StrBuf->AppendStr(&buf, ")"); - } + + if( counter2 > 0 ) + StrBuf->AppendStr(&buf, ")"); + } if( StrBuf->Length(&buf) > 0 ) clif->message(fd, StrBuf->Value(&buf)); - + StrBuf->Clear(&buf); } @@ -8294,21 +8190,18 @@ ACMD(stats) return true; } -ACMD(delitem) -{ +ACMD(delitem) { char item_name[100]; int nameid, amount = 0, total, idx; struct item_data* id; - - nullpo_retr(-1, sd); - + if( !message || !*message || ( sscanf(message, "\"%99[^\"]\" %d", item_name, &amount) < 2 && sscanf(message, "%99s %d", item_name, &amount) < 2 ) || amount < 1 ) { clif->message(fd, msg_txt(1355)); // Please enter an item name/ID, a quantity, and a player name (usage: #delitem <player> <item_name_or_ID> <quantity>). return false; } - if( ( id = itemdb_searchname(item_name) ) != NULL || ( id = itemdb_exists(atoi(item_name)) ) != NULL ) + if( ( id = itemdb->search_name(item_name) ) != NULL || ( id = itemdb->exists(atoi(item_name)) ) != NULL ) { nameid = id->nameid; } @@ -8321,13 +8214,12 @@ ACMD(delitem) total = amount; // delete items - while( amount && ( idx = pc->search_inventory(sd, nameid) ) != -1 ) - { + while (amount && (idx = pc->search_inventory(sd, nameid)) != INDEX_NOT_FOUND) { int delamount = ( amount < sd->status.inventory[idx].amount ) ? amount : sd->status.inventory[idx].amount; if( sd->inventory_data[idx]->type == IT_PETEGG && sd->status.inventory[idx].card[0] == CARD0_PET ) {// delete pet - intif_delete_petdata(MakeDWord(sd->status.inventory[idx].card[1], sd->status.inventory[idx].card[2])); + intif->delete_petdata(MakeDWord(sd->status.inventory[idx].card[1], sd->status.inventory[idx].card[2])); } pc->delitem(sd, idx, delamount, 0, 0, LOG_TYPE_COMMAND); @@ -8360,17 +8252,15 @@ ACMD(delitem) /*========================================== * Custom Fonts *------------------------------------------*/ -ACMD(font) -{ +ACMD(font) { int font_id; - nullpo_retr(-1,sd); font_id = atoi(message); if( font_id == 0 ) { - if( sd->user_font ) + if( sd->status.font ) { - sd->user_font = 0; + sd->status.font = 0; clif->message(fd, msg_txt(1356)); // Returning to normal font. clif->font(sd); } @@ -8382,9 +8272,9 @@ ACMD(font) } else if( font_id < 0 || font_id > 9 ) clif->message(fd, msg_txt(1359)); // Invalid font. Use a value from 0 to 9. - else if( font_id != sd->user_font ) + else if( font_id != sd->status.font ) { - sd->user_font = font_id; + sd->status.font = font_id; clif->font(sd); clif->message(fd, msg_txt(1360)); // Font changed. } @@ -8397,7 +8287,7 @@ ACMD(font) /*========================================== * type: 1 = commands (@), 2 = charcommands (#) *------------------------------------------*/ -static void atcommand_commands_sub(struct map_session_data* sd, const int fd, AtCommandType type) +void atcommand_commands_sub(struct map_session_data* sd, const int fd, AtCommandType type) { char line_buff[CHATBOX_SIZE]; char* cur = line_buff; @@ -8408,18 +8298,18 @@ static void atcommand_commands_sub(struct map_session_data* sd, const int fd, At memset(line_buff,' ',CHATBOX_SIZE); line_buff[CHATBOX_SIZE-1] = 0; - clif->message(fd, msg_txt(273)); // "Commands available:" + clif->message(fd, msg_txt(273)); // "Available commands:" for (cmd = dbi_first(iter); dbi_exists(iter); cmd = dbi_next(iter)) { - unsigned int slen = 0; + size_t slen; switch( type ) { case COMMAND_CHARCOMMAND: - if( cmd->char_groups[sd->group_pos] == 0 ) + if( cmd->char_groups[pcg->get_idx(sd->group)] == 0 ) continue; break; case COMMAND_ATCOMMAND: - if( cmd->at_groups[sd->group_pos] == 0 ) + if( cmd->at_groups[pcg->get_idx(sd->group)] == 0 ) continue; break; default: @@ -8457,7 +8347,7 @@ static void atcommand_commands_sub(struct map_session_data* sd, const int fd, At *------------------------------------------*/ ACMD(commands) { - atcommand_commands_sub(sd, fd, COMMAND_ATCOMMAND); + atcommand->commands_sub(sd, fd, COMMAND_ATCOMMAND); return true; } @@ -8466,16 +8356,21 @@ ACMD(commands) *------------------------------------------*/ ACMD(charcommands) { - atcommand_commands_sub(sd, fd, COMMAND_CHARCOMMAND); + atcommand->commands_sub(sd, fd, COMMAND_CHARCOMMAND); return true; } /* for new mounts */ ACMD(mount2) { + if( sd->sc.option&(OPTION_WUGRIDER|OPTION_RIDING|OPTION_DRAGON|OPTION_MADOGEAR) ) { + clif->message(fd, msg_txt(1476)); // You are already mounting something else + return false; + } + clif->message(sd->fd,msg_txt(1362)); // NOTICE: If you crash with mount your LUA is outdated. if( !(sd->sc.data[SC_ALL_RIDING]) ) { clif->message(sd->fd,msg_txt(1363)); // You have mounted. - sc_start(&sd->bl,SC_ALL_RIDING,100,0,-1); + sc_start(NULL,&sd->bl,SC_ALL_RIDING,100,0,-1); } else { clif->message(sd->fd,msg_txt(1364)); // You have released your mount. status_change_end(&sd->bl, SC_ALL_RIDING, INVALID_TIMER); @@ -8495,7 +8390,7 @@ ACMD(accinfo) { //remove const type safestrncpy(query, message, NAME_LENGTH); - intif_request_accinfo( sd->fd, sd->bl.id, pc->get_group_level(sd), query ); + intif->request_accinfo( sd->fd, sd->bl.id, pc_get_group_level(sd), query ); return true; } @@ -8504,8 +8399,9 @@ ACMD(accinfo) { ACMD(set) { char reg[32], val[128]; struct script_data* data; - int toset = 0, len; + int toset = 0; bool is_str = false; + size_t len; if( !message || !*message || (toset = sscanf(message, "%31s %128[^\n]s", reg, val)) < 1 ) { clif->message(fd, msg_txt(1367)); // Usage: @set <variable name> <value> @@ -8535,9 +8431,9 @@ ACMD(set) { if( toset >= 2 ) {/* we only set the var if there is an val, otherwise we only output the value */ if( is_str ) - set_var(sd, reg, (void*) val); + script->set_var(sd, reg, (void*) val); else - set_var(sd, reg, (void*)__64BPTRSIZE((atoi(val)))); + script->set_var(sd, reg, (void*)h64BPTRSIZE((atoi(val)))); } @@ -8548,19 +8444,19 @@ ACMD(set) { switch( reg[0] ) { case '@': - data->u.str = pc->readregstr(sd, add_str(reg)); + data->u.str = pc->readregstr(sd, script->add_str(reg)); break; case '$': - data->u.str = mapreg_readregstr(add_str(reg)); + data->u.str = mapreg->readregstr(script->add_str(reg)); break; case '#': if( reg[1] == '#' ) - data->u.str = pc_readaccountreg2str(sd, reg);// global + data->u.str = pc_readaccountreg2str(sd, script->add_str(reg));// global else - data->u.str = pc_readaccountregstr(sd, reg);// local + data->u.str = pc_readaccountregstr(sd, script->add_str(reg));// local break; default: - data->u.str = pc_readglobalreg_str(sd, reg); + data->u.str = pc_readglobalreg_str(sd, script->add_str(reg)); break; } @@ -8577,19 +8473,19 @@ ACMD(set) { data->type = C_INT; switch( reg[0] ) { case '@': - data->u.num = pc->readreg(sd, add_str(reg)); + data->u.num = pc->readreg(sd, script->add_str(reg)); break; case '$': - data->u.num = mapreg_readreg(add_str(reg)); + data->u.num = mapreg->readreg(script->add_str(reg)); break; case '#': if( reg[1] == '#' ) - data->u.num = pc_readaccountreg2(sd, reg);// global + data->u.num = pc_readaccountreg2(sd, script->add_str(reg));// global else - data->u.num = pc_readaccountreg(sd, reg);// local + data->u.num = pc_readaccountreg(sd, script->add_str(reg));// local break; default: - data->u.num = pc_readglobalreg(sd, reg); + data->u.num = pc_readglobalreg(sd, script->add_str(reg)); break; } @@ -8618,13 +8514,13 @@ ACMD(set) { return true; } ACMD(reloadquestdb) { - do_reload_quest(); + quest->reload(); clif->message(fd, msg_txt(1377)); // Quest database has been reloaded. return true; } ACMD(addperm) { - int perm_size = ARRAYLENGTH(pc_g_permission_name); - bool add = (strcmpi(command+1, "addperm") == 0) ? true : false; + int perm_size = pcg->permission_count; + bool add = (strcmpi(info->command, "addperm") == 0) ? true : false; int i; if( !message || !*message ) { @@ -8632,37 +8528,37 @@ ACMD(addperm) { clif->message(fd, atcmd_output); clif->message(fd, msg_txt(1379)); // -- Permission List for( i = 0; i < perm_size; i++ ) { - sprintf(atcmd_output,"- %s",pc_g_permission_name[i].name); + sprintf(atcmd_output,"- %s",pcg->permissions[i].name); clif->message(fd, atcmd_output); } return false; } - ARR_FIND(0, perm_size, i, strcmpi(pc_g_permission_name[i].name, message) == 0); + ARR_FIND(0, perm_size, i, strcmpi(pcg->permissions[i].name, message) == 0); if( i == perm_size ) { sprintf(atcmd_output,msg_txt(1380),message); // '%s' is not a known permission. clif->message(fd, atcmd_output); clif->message(fd, msg_txt(1379)); // -- Permission List for( i = 0; i < perm_size; i++ ) { - sprintf(atcmd_output,"- %s",pc_g_permission_name[i].name); + sprintf(atcmd_output,"- %s",pcg->permissions[i].name); clif->message(fd, atcmd_output); } return false; } - if( add && (sd->permissions&pc_g_permission_name[i].permission) ) { - sprintf(atcmd_output, msg_txt(1381),sd->status.name,pc_g_permission_name[i].name); // User '%s' already possesses the '%s' permission. + if( add && (sd->extra_temp_permissions&pcg->permissions[i].permission) ) { + sprintf(atcmd_output, msg_txt(1381),sd->status.name,pcg->permissions[i].name); // User '%s' already possesses the '%s' permission. clif->message(fd, atcmd_output); return false; - } else if ( !add && !(sd->permissions&pc_g_permission_name[i].permission) ) { - sprintf(atcmd_output, msg_txt(1382),sd->status.name,pc_g_permission_name[i].name); // User '%s' doesn't possess the '%s' permission. + } else if ( !add && !(sd->extra_temp_permissions&pcg->permissions[i].permission) ) { + sprintf(atcmd_output, msg_txt(1382),sd->status.name,pcg->permissions[i].name); // User '%s' doesn't possess the '%s' permission. clif->message(fd, atcmd_output); sprintf(atcmd_output,msg_txt(1383),sd->status.name); // -- User '%s' Permissions clif->message(fd, atcmd_output); for( i = 0; i < perm_size; i++ ) { - if( sd->permissions&pc_g_permission_name[i].permission ) { - sprintf(atcmd_output,"- %s",pc_g_permission_name[i].name); + if( sd->extra_temp_permissions&pcg->permissions[i].permission ) { + sprintf(atcmd_output,"- %s",pcg->permissions[i].name); clif->message(fd, atcmd_output); } } @@ -8671,9 +8567,9 @@ ACMD(addperm) { } if( add ) - sd->permissions |= pc_g_permission_name[i].permission; + sd->extra_temp_permissions |= pcg->permissions[i].permission; else - sd->permissions &=~ pc_g_permission_name[i].permission; + sd->extra_temp_permissions &=~ pcg->permissions[i].permission; sprintf(atcmd_output, msg_txt(1384),sd->status.name); // User '%s' permissions updated successfully. The changes are temporary. @@ -8688,7 +8584,7 @@ ACMD(unloadnpcfile) { return false; } - if( npc_unloadfile(message) ) + if( npc->unloadfile(message) ) clif->message(fd, msg_txt(1386)); // File unloaded. Be aware that mapflags and monsters spawned directly are not removed. else { clif->message(fd, msg_txt(1387)); // File not found. @@ -8697,10 +8593,11 @@ ACMD(unloadnpcfile) { return true; } ACMD(cart) { -#define MC_CART_MDFY(x,idx) \ -sd->status.skill[idx].id = x?MC_PUSHCART:0; \ -sd->status.skill[idx].lv = x?1:0; \ -sd->status.skill[idx].flag = x?1:0; +#define MC_CART_MDFY(x,idx) do { \ + sd->status.skill[idx].id = (x)?MC_PUSHCART:0; \ + sd->status.skill[idx].lv = (x)?1:0; \ + sd->status.skill[idx].flag = (x)?1:0; \ +} while(0) int val = atoi(message); bool need_skill = pc->checkskill(sd, MC_PUSHCART) ? false : true; @@ -8739,32 +8636,40 @@ sd->status.skill[idx].flag = x?1:0; } /* [Ind/Hercules] */ ACMD(join) { - struct hChSysCh *channel; + struct hChSysCh *channel = NULL; char name[HCHSYS_NAME_LENGTH], pass[HCHSYS_NAME_LENGTH]; - if( !message || !*message || sscanf(message, "%s %s", name, pass) < 1 ) { + if (!message || !*message || sscanf(message, "%19s %19s", name, pass) < 1) { sprintf(atcmd_output, msg_txt(1399),command); // Unknown Channel (usage: %s <#channel_name>) clif->message(fd, atcmd_output); return false; } if( hChSys.local && strcmpi(name + 1, hChSys.local_name) == 0 ) { - if( !map[sd->bl.m].channel ) { + if( !map->list[sd->bl.m].channel ) { clif->chsys_mjoin(sd); - return true; + if( map->list[sd->bl.m].channel ) /* join might have refused, map has chatting capabilities disabled */ + return true; } else - channel = map[sd->bl.m].channel; + channel = map->list[sd->bl.m].channel; } else if( hChSys.ally && sd->status.guild_id && strcmpi(name + 1, hChSys.ally_name) == 0 ) { struct guild *g = sd->guild; if( !g ) return false;/* unlikely, but we wont let it crash anyway. */ - channel = (struct hChSysCh *)g->channel; + channel = g->channel; } else if( !( channel = strdb_get(clif->channel_db, name + 1) ) ) { sprintf(atcmd_output, msg_txt(1400),name,command); // Unknown Channel '%s' (usage: %s <#channel_name>) clif->message(fd, atcmd_output); return false; } + if( !channel ) { + sprintf(atcmd_output, msg_txt(1400),name,command); // Unknown Channel '%s' (usage: %s <#channel_name>) + clif->message(fd, atcmd_output); + return false; + } + + if( idb_exists(channel->users, sd->status.char_id) ) { - sprintf(atcmd_output, msg_txt(1475),name); // You're already in the '%s' channel + sprintf(atcmd_output, msg_txt(1436),name); // You're already in the '%s' channel clif->message(fd, atcmd_output); return false; } @@ -8793,8 +8698,8 @@ ACMD(join) { int i; for (i = 0; i < MAX_GUILDALLIANCE; i++) { if( g->alliance[i].opposition == 0 && g->alliance[i].guild_id && (sg = guild->search(g->alliance[i].guild_id) ) ) { - if( !(((struct hChSysCh*)sg->channel)->banned && idb_exists(((struct hChSysCh*)sg->channel)->banned, sd->status.account_id))) { - clif->chsys_join((struct hChSysCh *)sg->channel,sd); + if( !(sg->channel->banned && idb_exists(sg->channel->banned, sd->status.account_id))) { + clif->chsys_join(sg->channel,sd); } } } @@ -8857,28 +8762,29 @@ static inline void atcmd_channel_help(int fd, const char *command, bool can_crea /* [Ind/Hercules] */ ACMD(channel) { struct hChSysCh *channel; - char key[HCHSYS_NAME_LENGTH], sub1[HCHSYS_NAME_LENGTH], sub2[HCHSYS_NAME_LENGTH], sub3[HCHSYS_NAME_LENGTH]; + char subcmd[HCHSYS_NAME_LENGTH], sub1[HCHSYS_NAME_LENGTH], sub2[HCHSYS_NAME_LENGTH], sub3[HCHSYS_NAME_LENGTH]; unsigned char k = 0; sub1[0] = sub2[0] = sub3[0] = '\0'; - if( !message || !*message || sscanf(message, "%s %s %s %s", key, sub1, sub2, sub3) < 1 ) { + if (!message || !*message || sscanf(message, "%19s %19s %19s %19s", subcmd, sub1, sub2, sub3) < 1) { atcmd_channel_help(fd,command,( hChSys.allow_user_channel_creation || pc_has_permission(sd, PC_PERM_HCHSYS_ADMIN) )); return true; } - if( strcmpi(key,"create") == 0 && ( hChSys.allow_user_channel_creation || pc_has_permission(sd, PC_PERM_HCHSYS_ADMIN) ) ) { - if( sub1[0] != '#' ) { + if (strcmpi(subcmd,"create") == 0 && (hChSys.allow_user_channel_creation || pc_has_permission(sd, PC_PERM_HCHSYS_ADMIN))) { + // sub1 = channel name; sub2 = password; sub3 = unused + if (sub1[0] != '#') { clif->message(fd, msg_txt(1405));// Channel name must start with a '#' return false; - } else if ( strlen(sub1) < 3 || strlen(sub1) > HCHSYS_NAME_LENGTH ) { + } else if (strlen(sub1) < 3 || strlen(sub1) > HCHSYS_NAME_LENGTH) { sprintf(atcmd_output, msg_txt(1406), HCHSYS_NAME_LENGTH);// Channel length must be between 3 and %d clif->message(fd, atcmd_output); return false; - } else if ( sub3[0] != '\0' ) { + } else if (sub3[0] != '\0') { clif->message(fd, msg_txt(1408)); // Channel password may not contain spaces return false; } - if( strcmpi(sub1 + 1,hChSys.local_name) == 0 || strcmpi(sub1 + 1,hChSys.ally_name) == 0 || strdb_exists(clif->channel_db, sub1 + 1) ) { + if (strcmpi(sub1 + 1,hChSys.local_name) == 0 || strcmpi(sub1 + 1,hChSys.ally_name) == 0 || strdb_exists(clif->channel_db, sub1 + 1)) { sprintf(atcmd_output, msg_txt(1407), sub1);// Channel '%s' is not available clif->message(fd, atcmd_output); return false; @@ -8897,11 +8803,11 @@ ACMD(channel) { } clif->chsys_join(channel,sd); - - } else if ( strcmpi(key,"list") == 0 ) { - if( sub1[0] != '\0' && strcmpi(sub1,"colors") == 0 ) { + } else if (strcmpi(subcmd,"list") == 0) { + // sub1 = list type; sub2 = unused; sub3 = unused + if (sub1[0] != '\0' && strcmpi(sub1,"colors") == 0) { char mout[40]; - for( k = 0; k < hChSys.colors_count; k++ ) { + for (k = 0; k < hChSys.colors_count; k++) { unsigned short msg_len = 1; msg_len += sprintf(mout, "[ %s list colors ] : %s",command,hChSys.colors_name[k]); @@ -8917,48 +8823,48 @@ ACMD(channel) { DBIterator *iter = db_iterator(clif->channel_db); bool show_all = pc_has_permission(sd, PC_PERM_HCHSYS_ADMIN) ? true : false; clif->message(fd, msg_txt(1410)); // -- Public Channels - if( hChSys.local ) { - sprintf(atcmd_output, msg_txt(1409), hChSys.local_name, map[sd->bl.m].channel ? db_size(map[sd->bl.m].channel->users) : 0);// - #%s ( %d users ) + if (hChSys.local) { + sprintf(atcmd_output, msg_txt(1409), hChSys.local_name, map->list[sd->bl.m].channel ? db_size(map->list[sd->bl.m].channel->users) : 0);// - #%s ( %d users ) clif->message(fd, atcmd_output); } - if( hChSys.ally && sd->status.guild_id ) { + if (hChSys.ally && sd->status.guild_id) { struct guild *g = sd->guild; if( !g ) { dbi_destroy(iter); return false; } - sprintf(atcmd_output, msg_txt(1409), hChSys.ally_name, db_size(((struct hChSysCh *)g->channel)->users));// - #%s ( %d users ) + sprintf(atcmd_output, msg_txt(1409), hChSys.ally_name, db_size(g->channel->users));// - #%s ( %d users ) clif->message(fd, atcmd_output); } - for(channel = dbi_first(iter); dbi_exists(iter); channel = dbi_next(iter)) { - if( show_all || channel->type == hChSys_PUBLIC || channel->type == hChSys_IRC ) { + for (channel = dbi_first(iter); dbi_exists(iter); channel = dbi_next(iter)) { + if (show_all || channel->type == hChSys_PUBLIC || channel->type == hChSys_IRC) { sprintf(atcmd_output, msg_txt(1409), channel->name, db_size(channel->users));// - #%s ( %d users ) clif->message(fd, atcmd_output); } } dbi_destroy(iter); } - } else if ( strcmpi(key,"setcolor") == 0 ) { - - if( sub1[0] != '#' ) { + } else if (strcmpi(subcmd,"setcolor") == 0) { + // sub1 = channel name; sub2 = color; sub3 = unused + if (sub1[0] != '#') { clif->message(fd, msg_txt(1405));// Channel name must start with a '#' return false; } - if( !(channel = strdb_get(clif->channel_db, sub1 + 1)) ) { + if (!(channel = strdb_get(clif->channel_db, sub1 + 1))) { sprintf(atcmd_output, msg_txt(1407), sub1);// Channel '%s' is not available clif->message(fd, atcmd_output); return false; } - if( channel->owner != sd->status.char_id && !pc_has_permission(sd, PC_PERM_HCHSYS_ADMIN) ) { + if (channel->owner != sd->status.char_id && !pc_has_permission(sd, PC_PERM_HCHSYS_ADMIN)) { sprintf(atcmd_output, msg_txt(1412), sub1);// You're not the owner of channel '%s' clif->message(fd, atcmd_output); return false; } - for( k = 0; k < hChSys.colors_count; k++ ) { - if( strcmpi(sub2,hChSys.colors_name[k]) == 0 ) + for (k = 0; k < hChSys.colors_count; k++) { + if (strcmpi(sub2, hChSys.colors_name[k]) == 0) break; } - if( k == hChSys.colors_count ) { + if (k == hChSys.colors_count) { sprintf(atcmd_output, msg_txt(1411), sub2);// Unknown color '%s' clif->message(fd, atcmd_output); return false; @@ -8966,104 +8872,113 @@ ACMD(channel) { channel->color = k; sprintf(atcmd_output, msg_txt(1413),sub1,hChSys.colors_name[k]);// '%s' channel color updated to '%s' clif->message(fd, atcmd_output); - } else if ( strcmpi(key,"leave") == 0 ) { - - if( sub1[0] != '#' ) { + } else if (strcmpi(subcmd,"leave") == 0) { + // sub1 = channel name; sub2 = unused; sub3 = unused + if (sub1[0] != '#') { clif->message(fd, msg_txt(1405));// Channel name must start with a '#' return false; } - for(k = 0; k < sd->channel_count; k++) { - if( strcmpi(sub1+1,sd->channels[k]->name) == 0 ) + for (k = 0; k < sd->channel_count; k++) { + if (strcmpi(sub1+1,sd->channels[k]->name) == 0) break; } - if( k == sd->channel_count ) { + if (k == sd->channel_count) { sprintf(atcmd_output, msg_txt(1425),sub1);// You're not part of the '%s' channel clif->message(fd, atcmd_output); return false; } - if( sd->channels[k]->type == hChSys_ALLY ) { + if (sd->channels[k]->type == hChSys_ALLY) { do { - for(k = 0; k < sd->channel_count; k++) { - if( sd->channels[k]->type == hChSys_ALLY ) { + for (k = 0; k < sd->channel_count; k++) { + if (sd->channels[k]->type == hChSys_ALLY) { clif->chsys_left(sd->channels[k],sd); break; } } - } while( k != sd->channel_count ); - } else + } while (k != sd->channel_count); + } else { clif->chsys_left(sd->channels[k],sd); + } sprintf(atcmd_output, msg_txt(1426),sub1); // You've left the '%s' channel clif->message(fd, atcmd_output); - } else if ( strcmpi(key,"bindto") == 0 ) { - - if( sub1[0] != '#' ) { + } else if (strcmpi(subcmd,"bindto") == 0) { + // sub1 = channel name; sub2 = unused; sub3 = unused + if (sub1[0] != '#') { clif->message(fd, msg_txt(1405));// Channel name must start with a '#' return false; } - for(k = 0; k < sd->channel_count; k++) { - if( strcmpi(sub1+1,sd->channels[k]->name) == 0 ) + for (k = 0; k < sd->channel_count; k++) { + if (strcmpi(sub1+1,sd->channels[k]->name) == 0) break; } - if( k == sd->channel_count ) { + if (k == sd->channel_count) { sprintf(atcmd_output, msg_txt(1425),sub1);// You're not part of the '%s' channel clif->message(fd, atcmd_output); return false; } sd->gcbind = sd->channels[k]; - sprintf(atcmd_output, msg_txt(1431),sub1); // Your global chat is now binded to the '%s' channel + sprintf(atcmd_output, msg_txt(1431),sub1); // Your global chat is now bound to the '%s' channel clif->message(fd, atcmd_output); - } else if ( strcmpi(key,"unbind") == 0 ) { - - if( sd->gcbind == NULL ) { - clif->message(fd, msg_txt(1432));// Your global chat is not binded to any channel + } else if (strcmpi(subcmd,"unbind") == 0) { + // sub1 = unused; sub2 = unused; sub3 = unused + if (sd->gcbind == NULL) { + clif->message(fd, msg_txt(1432));// Your global chat is not bound to any channel return false; } - sprintf(atcmd_output, msg_txt(1433),sd->gcbind->name); // Your global chat is now unbinded from the '#%s' channel + sprintf(atcmd_output, msg_txt(1433),sd->gcbind->name); // Your global chat is no longer bound to the '#%s' channel clif->message(fd, atcmd_output); sd->gcbind = NULL; - } else if ( strcmpi(key,"ban") == 0 ) { + } else if (strcmpi(subcmd,"ban") == 0) { + // sub1 = channel name; sub2 = unused; sub3 = unused struct map_session_data *pl_sd = NULL; struct hChSysBanEntry *entry = NULL; + char sub4[NAME_LENGTH]; ///< player name - if( sub1[0] != '#' ) { + if (sub1[0] != '#') { clif->message(fd, msg_txt(1405));// Channel name must start with a '#' return false; } - if( !(channel = strdb_get(clif->channel_db, sub1 + 1)) ) { + if (!(channel = strdb_get(clif->channel_db, sub1 + 1))) { sprintf(atcmd_output, msg_txt(1407), sub1);// Channel '%s' is not available clif->message(fd, atcmd_output); return false; } - if( channel->owner != sd->status.char_id && !pc_has_permission(sd, PC_PERM_HCHSYS_ADMIN) ) { + if (channel->owner != sd->status.char_id && !pc_has_permission(sd, PC_PERM_HCHSYS_ADMIN)) { sprintf(atcmd_output, msg_txt(1412), sub1);// You're not the owner of channel '%s' clif->message(fd, atcmd_output); return false; } - if( sub2[0] == '\0' || ( pl_sd = iMap->nick2sd(sub2) ) == NULL ) { - sprintf(atcmd_output, msg_txt(1434), sub2);// Player '%s' was not found + if (!message || !*message || sscanf(message, "%19s %19s %23[^\n]", subcmd, sub1, sub4) < 3) { + sprintf(atcmd_output, msg_txt(1434), sub4);// Player '%s' was not found clif->message(fd, atcmd_output); return false; } + + if (sub4[0] == '\0' || (pl_sd = map->nick2sd(sub4)) == NULL) { + sprintf(atcmd_output, msg_txt(1434), sub4);// Player '%s' was not found + clif->message(fd, atcmd_output); + return false; + } - if( pc_has_permission(pl_sd, PC_PERM_HCHSYS_ADMIN) ) { + if (pc_has_permission(pl_sd, PC_PERM_HCHSYS_ADMIN)) { clif->message(fd, msg_txt(1464)); // Ban failed, not possible to ban this user. return false; } - if( channel->banned && idb_exists(channel->banned,pl_sd->status.account_id) ) { + if (channel->banned && idb_exists(channel->banned,pl_sd->status.account_id)) { sprintf(atcmd_output, msg_txt(1465), pl_sd->status.name);// Player '%s' is already banned from this channel clif->message(fd, atcmd_output); return false; } - if( !channel->banned ) + if (!channel->banned) channel->banned = idb_alloc(DB_OPT_BASE|DB_OPT_ALLOW_NULL_DATA|DB_OPT_RELEASE_DATA); CREATE(entry, struct hChSysBanEntry, 1); @@ -9076,39 +8991,47 @@ ACMD(channel) { sprintf(atcmd_output, msg_txt(1437),pl_sd->status.name,sub1); // Player '%s' has now been banned from '%s' channel clif->message(fd, atcmd_output); - } else if ( strcmpi(key,"unban") == 0 ) { + } else if (strcmpi(subcmd,"unban") == 0) { + // sub1 = channel name; sub2 = unused; sub3 = unused struct map_session_data *pl_sd = NULL; + char sub4[NAME_LENGTH]; ///< player name - if( sub1[0] != '#' ) { + if (sub1[0] != '#') { clif->message(fd, msg_txt(1405));// Channel name must start with a '#' return false; } - if( !(channel = strdb_get(clif->channel_db, sub1 + 1)) ) { + if (!(channel = strdb_get(clif->channel_db, sub1 + 1))) { sprintf(atcmd_output, msg_txt(1407), sub1);// Channel '%s' is not available clif->message(fd, atcmd_output); return false; } - if( channel->owner != sd->status.char_id && !pc_has_permission(sd, PC_PERM_HCHSYS_ADMIN) ) { + if (channel->owner != sd->status.char_id && !pc_has_permission(sd, PC_PERM_HCHSYS_ADMIN)) { sprintf(atcmd_output, msg_txt(1412), sub1);// You're not the owner of channel '%s' clif->message(fd, atcmd_output); return false; } - if( !channel->banned ) { + if (!channel->banned) { sprintf(atcmd_output, msg_txt(1439), sub1);// Channel '%s' has no banned players clif->message(fd, atcmd_output); return false; } - if( sub2[0] == '\0' || ( pl_sd = iMap->nick2sd(sub2) ) == NULL ) { - sprintf(atcmd_output, msg_txt(1434), sub2);// Player '%s' was not found + if (!message || !*message || sscanf(message, "%19s %19s %23[^\n]", subcmd, sub1, sub4) < 3) { + sprintf(atcmd_output, msg_txt(1434), sub4);// Player '%s' was not found + clif->message(fd, atcmd_output); + return false; + } + + if (sub4[0] == '\0' || (pl_sd = map->nick2sd(sub4)) == NULL) { + sprintf(atcmd_output, msg_txt(1434), sub4);// Player '%s' was not found clif->message(fd, atcmd_output); return false; } - if( !idb_exists(channel->banned,pl_sd->status.account_id) ) { + if (!idb_exists(channel->banned,pl_sd->status.account_id)) { sprintf(atcmd_output, msg_txt(1440), pl_sd->status.name);// Player '%s' is not banned from this channel clif->message(fd, atcmd_output); return false; @@ -9116,32 +9039,33 @@ ACMD(channel) { idb_remove(channel->banned, pl_sd->status.account_id); - if( !db_size(channel->banned) ) { + if (!db_size(channel->banned)) { db_destroy(channel->banned); channel->banned = NULL; } sprintf(atcmd_output, msg_txt(1441),pl_sd->status.name,sub1); // Player '%s' has now been unbanned from the '%s' channel clif->message(fd, atcmd_output); - } else if ( strcmpi(key,"unbanall") == 0 ) { - if( sub1[0] != '#' ) { + } else if (strcmpi(subcmd,"unbanall") == 0) { + // sub1 = channel name; sub2 = unused; sub3 = unused + if (sub1[0] != '#') { clif->message(fd, msg_txt(1405));// Channel name must start with a '#' return false; } - if( !(channel = strdb_get(clif->channel_db, sub1 + 1)) ) { + if (!(channel = strdb_get(clif->channel_db, sub1 + 1))) { sprintf(atcmd_output, msg_txt(1407), sub1);// Channel '%s' is not available clif->message(fd, atcmd_output); return false; } - if( channel->owner != sd->status.char_id && !pc_has_permission(sd, PC_PERM_HCHSYS_ADMIN) ) { + if (channel->owner != sd->status.char_id && !pc_has_permission(sd, PC_PERM_HCHSYS_ADMIN)) { sprintf(atcmd_output, msg_txt(1412), sub1);// You're not the owner of channel '%s' clif->message(fd, atcmd_output); return false; } - if( !channel->banned ) { + if (!channel->banned) { sprintf(atcmd_output, msg_txt(1439), sub1);// Channel '%s' has no banned players clif->message(fd, atcmd_output); return false; @@ -9152,29 +9076,30 @@ ACMD(channel) { sprintf(atcmd_output, msg_txt(1442),sub1); // Removed all bans from '%s' channel clif->message(fd, atcmd_output); - } else if ( strcmpi(key,"banlist") == 0 ) { + } else if (strcmpi(subcmd,"banlist") == 0) { + // sub1 = channel name; sub2 = unused; sub3 = unused DBIterator *iter = NULL; DBKey key; DBData *data; bool isA = pc_has_permission(sd, PC_PERM_HCHSYS_ADMIN)?true:false; - if( sub1[0] != '#' ) { + if (sub1[0] != '#') { clif->message(fd, msg_txt(1405));// Channel name must start with a '#' return false; } - if( !(channel = strdb_get(clif->channel_db, sub1 + 1)) ) { + if (!(channel = strdb_get(clif->channel_db, sub1 + 1))) { sprintf(atcmd_output, msg_txt(1407), sub1);// Channel '%s' is not available clif->message(fd, atcmd_output); return false; } - if( channel->owner != sd->status.char_id && !isA ) { + if (channel->owner != sd->status.char_id && !isA) { sprintf(atcmd_output, msg_txt(1412), sub1);// You're not the owner of channel '%s' clif->message(fd, atcmd_output); return false; } - if( !channel->banned ) { + if (!channel->banned) { sprintf(atcmd_output, msg_txt(1439), sub1);// Channel '%s' has no banned players clif->message(fd, atcmd_output); return false; @@ -9184,10 +9109,10 @@ ACMD(channel) { iter = db_iterator(channel->banned); - for( data = iter->first(iter,&key); iter->exists(iter); data = iter->next(iter,&key) ) { + for (data = iter->first(iter,&key); iter->exists(iter); data = iter->next(iter,&key)) { struct hChSysBanEntry * entry = DB->data2ptr(data); - if( !isA ) + if (!isA) sprintf(atcmd_output, msg_txt(1444), entry->name);// - %s %s else sprintf(atcmd_output, msg_txt(1445), entry->name, key.i);// - %s (%d) @@ -9197,57 +9122,58 @@ ACMD(channel) { dbi_destroy(iter); - } else if ( strcmpi(key,"setopt") == 0 ) { + } else if (strcmpi(subcmd,"setopt") == 0) { + // sub1 = channel name; sub2 = option name; sub3 = value const char* opt_str[3] = { "None", "JoinAnnounce", "MessageDelay", }; - if( sub1[0] != '#' ) { + if (sub1[0] != '#') { clif->message(fd, msg_txt(1405));// Channel name must start with a '#' return false; } - if( !(channel = strdb_get(clif->channel_db, sub1 + 1)) ) { + if (!(channel = strdb_get(clif->channel_db, sub1 + 1))) { sprintf(atcmd_output, msg_txt(1407), sub1);// Channel '%s' is not available clif->message(fd, atcmd_output); return false; } - if( channel->owner != sd->status.char_id && !pc_has_permission(sd, PC_PERM_HCHSYS_ADMIN) ) { + if (channel->owner != sd->status.char_id && !pc_has_permission(sd, PC_PERM_HCHSYS_ADMIN)) { sprintf(atcmd_output, msg_txt(1412), sub1);// You're not the owner of channel '%s' clif->message(fd, atcmd_output); return false; } - if( sub2[0] == '\0' ) { + if (sub2[0] == '\0') { clif->message(fd, msg_txt(1446));// You need to input a option return false; } - for( k = 1; k < 3; k++ ) { - if( strcmpi(sub2,opt_str[k]) == 0 ) + for (k = 1; k < 3; k++) { + if (strcmpi(sub2,opt_str[k]) == 0) break; } - if( k == 3 ) { + if (k == 3) { sprintf(atcmd_output, msg_txt(1447), sub2);// '%s' is not a known channel option clif->message(fd, atcmd_output); clif->message(fd, msg_txt(1448)); // -- Available options - for( k = 1; k < 3; k++ ) { + for (k = 1; k < 3; k++) { sprintf(atcmd_output, msg_txt(1444), opt_str[k]);// - '%s' clif->message(fd, atcmd_output); } return false; } - if( sub3[0] == '\0' ) { - if ( k == hChSys_OPT_MSG_DELAY ) { + if (sub3[0] == '\0') { + if (k == hChSys_OPT_MSG_DELAY) { sprintf(atcmd_output, msg_txt(1466), opt_str[k]);// For '%s' you need the amount of seconds (from 0 to 10) clif->message(fd, atcmd_output); return false; - } else if( channel->opt & k ) { + } else if (channel->opt & k) { sprintf(atcmd_output, msg_txt(1449), opt_str[k],opt_str[k]); // option '%s' is already enabled, if you'd like to disable it type '@channel setopt %s 0' clif->message(fd, atcmd_output); return false; @@ -9259,13 +9185,13 @@ ACMD(channel) { } } else { int v = atoi(sub3); - if( k == hChSys_OPT_MSG_DELAY ) { - if( v < 0 || v > 10 ) { + if (k == hChSys_OPT_MSG_DELAY) { + if (v < 0 || v > 10) { sprintf(atcmd_output, msg_txt(1451), v, opt_str[k]);// value '%d' for option '%s' is out of range (limit is 0-10) clif->message(fd, atcmd_output); return false; } - if( v == 0 ) { + if (v == 0) { channel->opt &=~ k; channel->msg_delay = 0; sprintf(atcmd_output, msg_txt(1453), opt_str[k],channel->name,v);// option '%s' is now disabled for channel '%s' @@ -9279,8 +9205,8 @@ ACMD(channel) { return true; } } else { - if( v ) { - if( channel->opt & k ) { + if (v) { + if (channel->opt & k) { sprintf(atcmd_output, msg_txt(1449), opt_str[k],opt_str[k]); // option '%s' is already enabled, if you'd like to disable it type '@channel opt %s 0' clif->message(fd, atcmd_output); return false; @@ -9290,7 +9216,7 @@ ACMD(channel) { clif->message(fd, atcmd_output); } } else { - if( !(channel->opt & k) ) { + if (!(channel->opt & k)) { sprintf(atcmd_output, msg_txt(1454), opt_str[k],channel->name); // option '%s' is not enabled on channel '%s' clif->message(fd, atcmd_output); return false; @@ -9304,7 +9230,6 @@ ACMD(channel) { } } - } else { atcmd_channel_help(fd,command,( hChSys.allow_user_channel_creation || pc_has_permission(sd, PC_PERM_HCHSYS_ADMIN) )); } @@ -9376,17 +9301,28 @@ ACMD(searchstore){ return true; } ACMD(costume){ - const char* names[4] = { + const char* names[] = { "Wedding", "Xmas", "Summer", "Hanbok", +#if PACKETVER >= 20131218 + "Oktoberfest", +#endif }; - const int name2id[4] = { SC_WEDDING, SC_XMAS, SC_SUMMER, SC_HANBOK }; - unsigned short k = 0; + const int name2id[] = { + SC_WEDDING, + SC_XMAS, + SC_SUMMER, + SC_HANBOK, +#if PACKETVER >= 20131218 + SC_OKTOBERFEST, +#endif + }; + unsigned short k = 0, len = ARRAYLENGTH(names); if( !message || !*message ) { - for( k = 0; k < 4; k++ ) { + for( k = 0; k < len; k++ ) { if( sd->sc.data[name2id[k]] ) { sprintf(atcmd_output,msg_txt(1473),names[k]);//Costume '%s' removed. clif->message(sd->fd,atcmd_output); @@ -9396,14 +9332,14 @@ ACMD(costume){ } clif->message(sd->fd,msg_txt(1472)); - for( k = 0; k < 4; k++ ) { + for( k = 0; k < len; k++ ) { sprintf(atcmd_output,msg_txt(1471),names[k]);//-- %s clif->message(sd->fd,atcmd_output); } return false; } - for( k = 0; k < 4; k++ ) { + for( k = 0; k < len; k++ ) { if( sd->sc.data[name2id[k]] ) { sprintf(atcmd_output,msg_txt(1470),names[k]);// You're already with a '%s' costume, type '@costume' to remove it. clif->message(sd->fd,atcmd_output); @@ -9411,20 +9347,33 @@ ACMD(costume){ } } - for( k = 0; k < 4; k++ ) { + for( k = 0; k < len; k++ ) { if( strcmpi(message,names[k]) == 0 ) break; } - if( k == 4 ) { + if( k == len ) { sprintf(atcmd_output,msg_txt(1469),message);// '%s' is not a known costume clif->message(sd->fd,atcmd_output); return false; } - sc_start(&sd->bl, name2id[k], 100, 0, -1); + sc_start(NULL,&sd->bl, name2id[k], 100, 0, -1); return true; } +/* for debugging purposes (so users can easily provide us with debug info) */ +/* should be trashed as soon as its no longer necessary */ +ACMD(skdebug) { + sprintf(atcmd_output,"second: %d; third: %d",sd->sktree.second,sd->sktree.third); + clif->message(fd,atcmd_output); + sprintf(atcmd_output,"pc_calc_skilltree_normalize_job: %d",pc->calc_skilltree_normalize_job(sd)); + clif->message(fd,atcmd_output); + sprintf(atcmd_output,"change_lv_2nd/3rd: %d/%d",sd->change_level_2nd,sd->change_level_3rd); + clif->message(fd,atcmd_output); + sprintf(atcmd_output,"pc_calc_skillpoint:%d",pc->calc_skillpoint(sd)); + clif->message(fd,atcmd_output); + return true; +} /** * Fills the reference of available commands in atcommand DBMap **/ @@ -9463,6 +9412,8 @@ void atcommand_basecommands(void) { ACMD_DEF(heal), ACMD_DEF(item), ACMD_DEF(item2), + ACMD_DEF2("itembound", item), + ACMD_DEF2("itembound2", item2), ACMD_DEF(itemreset), ACMD_DEF(clearstorage), ACMD_DEF(cleargstorage), @@ -9539,7 +9490,9 @@ void atcommand_basecommands(void) { ACMD_DEF2("allstats", stat_all), ACMD_DEF2("block", char_block), ACMD_DEF2("ban", char_ban), + ACMD_DEF2("charban", char_ban),/* char-specific ban time */ ACMD_DEF2("unblock", char_unblock), + ACMD_DEF2("charunban", char_unban),/* char-specific ban time */ ACMD_DEF2("unban", char_unban), ACMD_DEF2("mount", mount_peco), ACMD_DEF(guildspy), @@ -9610,6 +9563,7 @@ void atcommand_basecommands(void) { ACMD_DEF(changelook), ACMD_DEF(autoloot), ACMD_DEF2("alootid", autolootitem), + ACMD_DEF(autoloottype), ACMD_DEF(mobinfo), ACMD_DEF(exp), ACMD_DEF(version), @@ -9688,24 +9642,43 @@ void atcommand_basecommands(void) { ACMD_DEF(fontcolor), ACMD_DEF(searchstore), ACMD_DEF(costume), + ACMD_DEF(skdebug), }; - AtCommandInfo* cmd; int i; for( i = 0; i < ARRAYLENGTH(atcommand_base); i++ ) { - if(atcommand->exists(atcommand_base[i].command)) { // Should not happen if atcommand_base[] array is OK + if(!atcommand->add(atcommand_base[i].command,atcommand_base[i].func,false)) { // Should not happen if atcommand_base[] array is OK ShowDebug("atcommand_basecommands: duplicate ACMD_DEF for '%s'.\n", atcommand_base[i].command); continue; } - CREATE(cmd, AtCommandInfo, 1); - safestrncpy(cmd->command, atcommand_base[i].command, sizeof(cmd->command)); - cmd->func = atcommand_base[i].func; - cmd->help = NULL;/* start as null dear */ - cmd->log = true; - strdb_put(atcommand->db, cmd->command, cmd); } + + /* @commands from plugins */ + HPM_map_atcommands(); + return; } +#undef ACMD_DEF +#undef ACMD_DEF2 + +bool atcommand_add(char *name,AtCommandFunc func, bool replace) { + AtCommandInfo* cmd; + + if( (cmd = atcommand->exists(name)) ) { //caller will handle/display on false + if( !replace ) + return false; + } else { + CREATE(cmd, AtCommandInfo, 1); + strdb_put(atcommand->db, name, cmd); + } + + safestrncpy(cmd->command, name, sizeof(cmd->command)); + cmd->func = func; + cmd->help = NULL; + cmd->log = true; + + return true; +} /*========================================== * Command lookup functions @@ -9714,15 +9687,14 @@ AtCommandInfo* atcommand_exists(const char* name) { return strdb_get(atcommand->db, name); } -static AtCommandInfo* get_atcommandinfo_byname(const char *name) { +AtCommandInfo* get_atcommandinfo_byname(const char *name) { AtCommandInfo *cmd; if ((cmd = strdb_get(atcommand->db, name))) return cmd; return NULL; } -static const char* atcommand_checkalias(const char *aliasname) -{ +const char* atcommand_checkalias(const char *aliasname) { AliasInfo *alias_info = NULL; if ((alias_info = (AliasInfo*)strdb_get(atcommand->alias_db, aliasname)) != NULL) return alias_info->command->command; @@ -9730,7 +9702,7 @@ static const char* atcommand_checkalias(const char *aliasname) } /// AtCommand suggestion -static void atcommand_get_suggestions(struct map_session_data* sd, const char *name, bool is_atcmd_cmd) { +void atcommand_get_suggestions(struct map_session_data* sd, const char *name, bool is_atcmd_cmd) { DBIterator* atcommand_iter; DBIterator* alias_iter; AtCommandInfo* command_info = NULL; @@ -9801,9 +9773,14 @@ static void atcommand_get_suggestions(struct map_session_data* sd, const char *n dbi_destroy(alias_iter); } -/// Executes an at-command. -bool is_atcommand(const int fd, struct map_session_data* sd, const char* message, int type) -{ +/** + * Executes an at-command + * @param fd fd associated to the invoking character + * @param sd sd associated to the invoking character + * @param message atcommand arguments + * @param player_invoked true if the command was invoked by a player, false if invoked by the server (bypassing any restrictions) + */ +bool atcommand_exec(const int fd, struct map_session_data *sd, const char *message, bool player_invoked) { char charname[NAME_LENGTH], params[100]; char charname2[NAME_LENGTH], params2[100]; char command[100]; @@ -9833,11 +9810,9 @@ bool is_atcommand(const int fd, struct map_session_data* sd, const char* message if ( *message != atcommand->at_symbol && *message != atcommand->char_symbol ) return false; - // type value 0 = server invoked: bypass restrictions - // 1 = player invoked - if ( type == 1) { + if (player_invoked) { //Commands are disabled on maps flagged as 'nocommand' - if ( map[sd->bl.m].nocommand && pc->get_group_level(sd) < map[sd->bl.m].nocommand ) { + if ( map->list[sd->bl.m].nocommand && pc_get_group_level(sd) < map->list[sd->bl.m].nocommand ) { clif->message(fd, msg_txt(143)); return false; } @@ -9872,10 +9847,10 @@ bool is_atcommand(const int fd, struct map_session_data* sd, const char* message break; } - if( !pc->get_group_level(sd) ) { + if( !pc_get_group_level(sd) ) { if( x >= 1 || y >= 1 ) { /* we have command */ - info = get_atcommandinfo_byname(atcommand_checkalias(command + 1)); - if( !info || info->char_groups[sd->group_pos] == 0 ) /* if we can't use or doesn't exist: don't even display the command failed message */ + info = atcommand->get_info_byname(atcommand->check_alias(command + 1)); + if( !info || info->char_groups[pcg->get_idx(sd->group)] == 0 ) /* if we can't use or doesn't exist: don't even display the command failed message */ return false; } else return false;/* display as normal message */ @@ -9886,13 +9861,16 @@ bool is_atcommand(const int fd, struct map_session_data* sd, const char* message return true; } while(0); } - else if (*message == atcommand->at_symbol) { + else /*if (*message == atcommand->at_symbol)*/ { //atcmd_msg is constructed above differently for charcommands //it's copied from message if not a charcommand so it can //pass through the rest of the code compatible with both symbols sprintf(atcmd_msg, "%s", message); } + if( battle_config.idletime_criteria & BCIDLE_ATCOMMAND ) + sd->idletime = sockt->last_tick; + //Clearing these to be used once more. memset(command, '\0', sizeof(command)); memset(params, '\0', sizeof(params)); @@ -9902,23 +9880,28 @@ bool is_atcommand(const int fd, struct map_session_data* sd, const char* message params[0] = '\0'; // @commands (script based) - if(type == 1 && atcommand->binding_count > 0) { + if(player_invoked && atcommand->binding_count > 0) { struct atcmd_binding_data * binding; // Get atcommand binding binding = atcommand->get_bind_byname(command); // Check if the binding isn't NULL and there is a NPC event, level of usage met, et cetera - if( binding != NULL && binding->npc_event[0] && - ((*atcmd_msg == atcommand->at_symbol && pc->get_group_level(sd) >= binding->group_lv) || - (*atcmd_msg == atcommand->char_symbol && pc->get_group_level(sd) >= binding->group_lv_char))) - { + if( binding != NULL + && binding->npc_event[0] + && ( + (*atcmd_msg == atcommand->at_symbol && pc_get_group_level(sd) >= binding->group_lv) + || (*atcmd_msg == atcommand->char_symbol && pc_get_group_level(sd) >= binding->group_lv_char) + ) + ) { // Check if self or character invoking; if self == character invoked, then self invoke. bool invokeFlag = ((*atcmd_msg == atcommand->at_symbol) ? 1 : 0); // Check if the command initiated is a character command - if (*message == atcommand->char_symbol && - (ssd = iMap->nick2sd(charname)) == NULL && (ssd = iMap->nick2sd(charname2)) == NULL ) { + if (*message == atcommand->char_symbol + && (ssd = map->nick2sd(charname)) == NULL + && (ssd = map->nick2sd(charname2)) == NULL + ) { sprintf(output, msg_txt(1389), command); // %s failed. Player not found. clif->message(fd, output); return true; @@ -9927,37 +9910,36 @@ bool is_atcommand(const int fd, struct map_session_data* sd, const char* message if( binding->log ) /* log only if this command should be logged [Ind/Hercules] */ logs->atcommand(sd, atcmd_msg); - npc_do_atcmd_event((invokeFlag ? sd : ssd), command, params, binding->npc_event); + npc->do_atcmd_event((invokeFlag ? sd : ssd), command, params, binding->npc_event); return true; } } //Grab the command information and check for the proper GM level required to use it or if the command exists - info = get_atcommandinfo_byname(atcommand_checkalias(command + 1)); + info = atcommand->get_info_byname(atcommand->check_alias(command + 1)); if (info == NULL) { - if( pc->get_group_level(sd) ) { // TODO: remove or replace with proper permission + if( pc_get_group_level(sd) ) { // TODO: remove or replace with proper permission sprintf(output, msg_txt(153), command); // "%s is Unknown Command." clif->message(fd, output); - atcommand_get_suggestions(sd, command + 1, *message == atcommand->at_symbol); + atcommand->get_suggestions(sd, command + 1, *message == atcommand->at_symbol); return true; } else return false; } - // type == 1 : player invoked - if (type == 1) { + if (player_invoked) { int i; - if ((*command == atcommand->at_symbol && info->at_groups[sd->group_pos] == 0) || - (*command == atcommand->char_symbol && info->char_groups[sd->group_pos] == 0) ) { + if ((*command == atcommand->at_symbol && info->at_groups[pcg->get_idx(sd->group)] == 0) || + (*command == atcommand->char_symbol && info->char_groups[pcg->get_idx(sd->group)] == 0) ) { return false; } if( pc_isdead(sd) && pc_has_permission(sd,PC_PERM_DISABLE_CMD_DEAD) ) { clif->message(fd, msg_txt(1393)); // You can't use commands while dead return true; } - for(i = 0; i < map[sd->bl.m].zone->disabled_commands_count; i++) { - if( info->func == map[sd->bl.m].zone->disabled_commands[i]->cmd ) { - if( sd->group_level < map[sd->bl.m].zone->disabled_commands[i]->group_lv ) { + for(i = 0; i < map->list[sd->bl.m].zone->disabled_commands_count; i++) { + if( info->func == map->list[sd->bl.m].zone->disabled_commands[i]->cmd ) { + if( pc_get_group_level(sd) < map->list[sd->bl.m].zone->disabled_commands[i]->group_lv ) { clif->colormes(sd->fd,COLOR_RED,"This command is disabled in this area"); return true; } else @@ -9967,8 +9949,10 @@ bool is_atcommand(const int fd, struct map_session_data* sd, const char* message } // Check if target is valid only if confirmed that player can use command. - if (*message == atcommand->char_symbol && - (ssd = iMap->nick2sd(charname)) == NULL && (ssd = iMap->nick2sd(charname2)) == NULL ) { + if (*message == atcommand->char_symbol + && (ssd = map->nick2sd(charname)) == NULL + && (ssd = map->nick2sd(charname2)) == NULL + ) { sprintf(output, msg_txt(1389), command); // %s failed. Player not found. clif->message(fd, output); return true; @@ -9976,6 +9960,11 @@ bool is_atcommand(const int fd, struct map_session_data* sd, const char* message //Attempt to use the command if ( (info->func(fd, (*atcmd_msg == atcommand->at_symbol) ? sd : ssd, command, params,info) != true) ) { +#ifdef AUTOTRADE_PERSISTENCY + // Autotrade was successful if standalone is set + if( ((*atcmd_msg == atcommand->at_symbol) ? sd->state.standalone : ssd->state.standalone) ) + return true; +#endif sprintf(output,msg_txt(154), command); // %s failed. clif->message(fd, output); return true; @@ -9990,17 +9979,17 @@ bool is_atcommand(const int fd, struct map_session_data* sd, const char* message /*========================================== * *------------------------------------------*/ -static void atcommand_config_read(const char* config_filename) { +void atcommand_config_read(const char* config_filename) { config_t atcommand_config; config_setting_t *aliases = NULL, *help = NULL, *nolog = NULL; const char *symbol = NULL; int num_aliases = 0; - if (conf_read_file(&atcommand_config, config_filename)) + if (libconfig->read_file(&atcommand_config, config_filename)) return; // Command symbols - if (config_lookup_string(&atcommand_config, "atcommand_symbol", &symbol)) { + if (libconfig->lookup_string(&atcommand_config, "atcommand_symbol", &symbol)) { if (ISPRINT(*symbol) && // no control characters *symbol != '/' && // symbol of client commands *symbol != '%' && // symbol of party chat @@ -10009,7 +9998,7 @@ static void atcommand_config_read(const char* config_filename) { atcommand->at_symbol = *symbol; } - if (config_lookup_string(&atcommand_config, "charcommand_symbol", &symbol)) { + if (libconfig->lookup_string(&atcommand_config, "charcommand_symbol", &symbol)) { if (ISPRINT(*symbol) && // no control characters *symbol != '/' && // symbol of client commands *symbol != '%' && // symbol of party chat @@ -10019,10 +10008,10 @@ static void atcommand_config_read(const char* config_filename) { } // Command aliases - aliases = config_lookup(&atcommand_config, "aliases"); + aliases = libconfig->lookup(&atcommand_config, "aliases"); if (aliases != NULL) { int i = 0; - int count = config_setting_length(aliases); + int count = libconfig->setting_length(aliases); for (i = 0; i < count; ++i) { config_setting_t *command; @@ -10030,7 +10019,7 @@ static void atcommand_config_read(const char* config_filename) { int j = 0, alias_count = 0; AtCommandInfo *commandinfo = NULL; - command = config_setting_get_elem(aliases, i); + command = libconfig->setting_get_elem(aliases, i); if (config_setting_type(command) != CONFIG_TYPE_ARRAY) continue; commandname = config_setting_name(command); @@ -10038,9 +10027,9 @@ static void atcommand_config_read(const char* config_filename) { ShowConfigWarning(command, "atcommand_config_read: can not set alias for non-existent command %s", commandname); continue; } - alias_count = config_setting_length(command); + alias_count = libconfig->setting_length(command); for (j = 0; j < alias_count; ++j) { - const char *alias = config_setting_get_string_elem(command, j); + const char *alias = libconfig->setting_get_string_elem(command, j); if (alias != NULL) { AliasInfo *alias_info; if (strdb_exists(atcommand->alias_db, alias)) { @@ -10057,17 +10046,17 @@ static void atcommand_config_read(const char* config_filename) { } } - nolog = config_lookup(&atcommand_config, "nolog"); + nolog = libconfig->lookup(&atcommand_config, "nolog"); if (nolog != NULL) { int i = 0; - int count = config_setting_length(nolog); + int count = libconfig->setting_length(nolog); for (i = 0; i < count; ++i) { config_setting_t *command; const char *commandname = NULL; AtCommandInfo *commandinfo = NULL; - command = config_setting_get_elem(nolog, i); + command = libconfig->setting_get_elem(nolog, i); commandname = config_setting_name(command); if ( !( commandinfo = atcommand_exists(commandname) ) ) { ShowConfigWarning(command, "atcommand_config_read: can not disable logging for non-existent command %s", commandname); @@ -10075,13 +10064,13 @@ static void atcommand_config_read(const char* config_filename) { } commandinfo->log = false; } - } + } // Commands help // We only check if all commands exist - help = config_lookup(&atcommand_config, "help"); + help = libconfig->lookup(&atcommand_config, "help"); if (help != NULL) { - int count = config_setting_length(help); + int count = libconfig->setting_length(help); int i; for (i = 0; i < count; ++i) { @@ -10089,14 +10078,14 @@ static void atcommand_config_read(const char* config_filename) { const char *commandname; AtCommandInfo *commandinfo = NULL; - command = config_setting_get_elem(help, i); + command = libconfig->setting_get_elem(help, i); commandname = config_setting_name(command); if ( !( commandinfo = atcommand_exists(commandname) ) ) ShowConfigWarning(command, "atcommand_config_read: command %s does not exist", commandname); else { if( commandinfo->help == NULL ) { - const char *str = config_setting_get_string(command); - int len = strlen(str); + const char *str = libconfig->setting_get_string(command); + size_t len = strlen(str); commandinfo->help = aMalloc( len * sizeof(char) ); safestrncpy(commandinfo->help, str, len); } @@ -10106,129 +10095,166 @@ static void atcommand_config_read(const char* config_filename) { ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' command aliases in '"CL_WHITE"%s"CL_RESET"'.\n", num_aliases, config_filename); - config_destroy(&atcommand_config); + libconfig->destroy(&atcommand_config); return; } -void atcommand_db_load_groups(void) { + +/** + * In group configuration file, setting for each command is either + * <commandname> : <bool> (only atcommand), or + * <commandname> : [ <bool>, <bool> ] ([ atcommand, charcommand ]) + * Maps AtCommandType enums to indexes of <commandname> value array, + * COMMAND_ATCOMMAND (1) being index 0, COMMAND_CHARCOMMAND (2) being index 1. + * @private + */ +static inline int AtCommandType2idx(AtCommandType type) { return (type-1); } + +/** + * Loads permissions for groups to use commands. + * + */ +void atcommand_db_load_groups(GroupSettings **groups, config_setting_t **commands_, size_t sz) +{ DBIterator *iter = db_iterator(atcommand->db); - AtCommandInfo* cmd; - int i; + AtCommandInfo *atcmd; - for (cmd = dbi_first(iter); dbi_exists(iter); cmd = dbi_next(iter)) { - cmd->at_groups = aMalloc( pc_group_max * sizeof(char) ); - cmd->char_groups = aMalloc( pc_group_max * sizeof(char) ); - for(i = 0; i < pc_group_max; i++) { - int idx = pc_group_id2idx(atcommand->group_ids[i]); - if( pc_group_can_use_command(atcommand->group_ids[i], cmd->command, COMMAND_ATCOMMAND ) ) - cmd->at_groups[idx] = 1; - else - cmd->at_groups[idx] = 0; - if( pc_group_can_use_command(atcommand->group_ids[i], cmd->command, COMMAND_CHARCOMMAND ) ) - cmd->char_groups[idx] = 1; - else - cmd->char_groups[idx] = 0; + for (atcmd = dbi_first(iter); dbi_exists(iter); atcmd = dbi_next(iter)) { + int i; + CREATE(atcmd->at_groups, char, sz); + CREATE(atcmd->char_groups, char, sz); + for (i = 0; i < sz; i++) { + GroupSettings *group = groups[i]; + config_setting_t *commands = commands_[i]; + int result = 0; + int idx = -1; + + if (group == NULL) { + ShowError("atcommand_db_load_groups: group is NULL\n"); + continue; + } + + idx = pcg->get_idx(group); + if (idx < 0 || idx >= sz) { + ShowError("atcommand_db_load_groups: index (%d) out of bounds [0,%"PRIuS"]\n", idx, sz - 1); + continue; + } + + if (pcg->has_permission(group, PC_PERM_USE_ALL_COMMANDS)) { + atcmd->at_groups[idx] = atcmd->char_groups[idx] = 1; + continue; + } + + if (commands != NULL) { + config_setting_t *cmd = NULL; + + // <commandname> : <bool> (only atcommand) + if (config_setting_lookup_bool(commands, atcmd->command, &result) && result) { + atcmd->at_groups[idx] = 1; + } + else + // <commandname> : [ <bool>, <bool> ] ([ atcommand, charcommand ]) + if ((cmd = config_setting_get_member(commands, atcmd->command)) != NULL && + config_setting_is_aggregate(cmd) && + config_setting_length(cmd) == 2 + ) { + if (config_setting_get_bool_elem(cmd, AtCommandType2idx(COMMAND_ATCOMMAND))) { + atcmd->at_groups[idx] = 1; + } + if (config_setting_get_bool_elem(cmd, AtCommandType2idx(COMMAND_CHARCOMMAND))) { + atcmd->char_groups[idx] = 1; + } + } + } } } - dbi_destroy(iter); - return; } + bool atcommand_can_use(struct map_session_data *sd, const char *command) { - AtCommandInfo *info = get_atcommandinfo_byname(atcommand_checkalias(command + 1)); + AtCommandInfo *info = atcommand->get_info_byname(atcommand->check_alias(command + 1)); if (info == NULL) return false; - if ((*command == atcommand->at_symbol && info->at_groups[sd->group_pos] != 0) || - (*command == atcommand->char_symbol && info->char_groups[sd->group_pos] != 0) ) { + if ((*command == atcommand->at_symbol && info->at_groups[pcg->get_idx(sd->group)] != 0) || + (*command == atcommand->char_symbol && info->char_groups[pcg->get_idx(sd->group)] != 0) ) { return true; } return false; } bool atcommand_can_use2(struct map_session_data *sd, const char *command, AtCommandType type) { - AtCommandInfo *info = get_atcommandinfo_byname(atcommand_checkalias(command)); + AtCommandInfo *info = atcommand->get_info_byname(atcommand->check_alias(command)); if (info == NULL) return false; - if ((type == COMMAND_ATCOMMAND && info->at_groups[sd->group_pos] != 0) || - (type == COMMAND_CHARCOMMAND && info->char_groups[sd->group_pos] != 0) ) { + if ((type == COMMAND_ATCOMMAND && info->at_groups[pcg->get_idx(sd->group)] != 0) || + (type == COMMAND_CHARCOMMAND && info->char_groups[pcg->get_idx(sd->group)] != 0) ) { return true; } return false; } bool atcommand_hp_add(char *name, AtCommandFunc func) { - AtCommandInfo* cmd; - + /* if commands are added after group permissions are thrown in, they end up with no permissions */ + /* so we restrict commands to be linked in during boot */ if( runflag == MAPSERVER_ST_RUNNING ) { ShowDebug("atcommand_hp_add: Commands can't be added after server is ready, skipping '%s'...\n",name); return false; } - if( !atcommand->db ) - atcommand->db = stridb_alloc(DB_OPT_DUP_KEY|DB_OPT_RELEASE_DATA, ATCOMMAND_LENGTH); - - if( atcommand->exists(name) ) { - ShowDebug("atcommand_hp_add: duplicate command '%s', skipping...\n", name); - return false; - } - - CREATE(cmd, AtCommandInfo, 1); - - safestrncpy(cmd->command, name, sizeof(cmd->command)); - cmd->func = func; - cmd->help = NULL;/* start as null dear */ - cmd->log = true; - - strdb_put(atcommand->db, cmd->command, cmd); - return true; + return HPM_map_add_atcommand(name,func); } -void atcommand_db_clear(void) { - if (atcommand->db != NULL) { - DBIterator *iter = db_iterator(atcommand->db); - AtCommandInfo* cmd; - - for (cmd = dbi_first(iter); dbi_exists(iter); cmd = dbi_next(iter)) { - aFree(cmd->at_groups); - aFree(cmd->char_groups); - if( cmd->help != NULL ) - aFree(cmd->help); - } - dbi_destroy(iter); +/** + * @see DBApply + */ +int atcommand_db_clear_sub(DBKey key, DBData *data, va_list args) { + AtCommandInfo *cmd = DB->data2ptr(data); + aFree(cmd->at_groups); + aFree(cmd->char_groups); + if (cmd->help != NULL) + aFree(cmd->help); + return 0; +} - db_destroy(atcommand->db); +void atcommand_db_clear(void) { + if( atcommand->db != NULL ) { + atcommand->db->destroy(atcommand->db, atcommand->cmd_db_clear_sub); atcommand->db = NULL; } - if (atcommand->alias_db != NULL) + if( atcommand->alias_db != NULL ) { db_destroy(atcommand->alias_db); + atcommand->alias_db = NULL; + } } void atcommand_doload(void) { if( runflag >= MAPSERVER_ST_RUNNING ) - atcommand_db_clear(); - if( !atcommand->db ) + atcommand->cmd_db_clear(); + if( atcommand->db == NULL ) atcommand->db = stridb_alloc(DB_OPT_DUP_KEY|DB_OPT_RELEASE_DATA, ATCOMMAND_LENGTH); - atcommand->alias_db = stridb_alloc(DB_OPT_DUP_KEY|DB_OPT_RELEASE_DATA, ATCOMMAND_LENGTH); - atcommand_basecommands(); //fills initial atcommand_db with known commands - atcommand_config_read(iMap->ATCOMMAND_CONF_FILENAME); + if( atcommand->alias_db == NULL ) + atcommand->alias_db = stridb_alloc(DB_OPT_DUP_KEY|DB_OPT_RELEASE_DATA, ATCOMMAND_LENGTH); + atcommand->base_commands(); //fills initial atcommand_db with known commands + atcommand->config_read(map->ATCOMMAND_CONF_FILENAME); } -void do_init_atcommand(void) { +void do_init_atcommand(bool minimal) { + if (minimal) + return; + atcommand->at_symbol = '@'; atcommand->char_symbol = '#'; atcommand->binding_count = 0; - atcommand_doload(); + atcommand->doload(); } void do_final_atcommand(void) { - atcommand_db_clear(); - if( atcommand->group_ids ) - aFree(atcommand->group_ids); + atcommand->cmd_db_clear(); } void atcommand_defaults(void) { @@ -10237,16 +10263,37 @@ void atcommand_defaults(void) { atcommand->db = NULL; atcommand->alias_db = NULL; + memset(atcommand->msg_table, 0, sizeof(atcommand->msg_table)); + atcommand->init = do_init_atcommand; atcommand->final = do_final_atcommand; - atcommand->parse = is_atcommand; + atcommand->exec = atcommand_exec; + atcommand->create = atcommand_hp_add; atcommand->can_use = atcommand_can_use; atcommand->can_use2 = atcommand_can_use2; - atcommand->create = atcommand_hp_add; atcommand->load_groups = atcommand_db_load_groups; atcommand->exists = atcommand_exists; atcommand->msg_read = msg_config_read; atcommand->final_msg = do_final_msg; atcommand->get_bind_byname = get_atcommandbind_byname; + atcommand->get_info_byname = get_atcommandinfo_byname; + atcommand->check_alias = atcommand_checkalias; + atcommand->get_suggestions = atcommand_get_suggestions; + atcommand->config_read = atcommand_config_read; + atcommand->stopattack = atcommand_stopattack; + atcommand->pvpoff_sub = atcommand_pvpoff_sub; + atcommand->pvpon_sub = atcommand_pvpon_sub; + atcommand->atkillmonster_sub = atkillmonster_sub; + atcommand->raise_sub = atcommand_raise_sub; + atcommand->get_jail_time = get_jail_time; + atcommand->cleanfloor_sub = atcommand_cleanfloor_sub; + atcommand->mutearea_sub = atcommand_mutearea_sub; + atcommand->commands_sub = atcommand_commands_sub; + atcommand->cmd_db_clear = atcommand_db_clear; + atcommand->cmd_db_clear_sub = atcommand_db_clear_sub; + atcommand->doload = atcommand_doload; + atcommand->base_commands = atcommand_basecommands; + atcommand->add = atcommand_add; + atcommand->msg = atcommand_msg; } diff --git a/src/map/atcommand.h b/src/map/atcommand.h index f09b1f2b8..356487bd1 100644 --- a/src/map/atcommand.h +++ b/src/map/atcommand.h @@ -2,9 +2,11 @@ // See the LICENSE file // Portions Copyright (c) Athena Dev Teams -#ifndef _ATCOMMAND_H_ -#define _ATCOMMAND_H_ +#ifndef MAP_ATCOMMAND_H +#define MAP_ATCOMMAND_H +#include "pc_groups.h" +#include "../common/conf.h" #include "../common/db.h" /** @@ -12,13 +14,14 @@ **/ struct map_session_data; struct AtCommandInfo; +struct block_list; /** * Defines **/ #define ATCOMMAND_LENGTH 50 #define MAX_MSG 1500 - +#define msg_txt(idx) atcommand->msg(idx) /** * Enumerations **/ @@ -68,32 +71,54 @@ struct atcommand_interface { /* atcommand binding */ struct atcmd_binding_data** binding; int binding_count; - unsigned int *group_ids; /* other vars */ DBMap* db; //name -> AtCommandInfo DBMap* alias_db; //alias -> AtCommandInfo /* */ - void (*init) (void); + char* msg_table[MAX_MSG]; // Server messages (0-499 reserved for GM commands, 500-999 reserved for others) + /* */ + void (*init) (bool minimal); void (*final) (void); /* */ - bool (*parse) (const int fd, struct map_session_data* sd, const char* message, int type); + bool (*exec) (const int fd, struct map_session_data *sd, const char *message, bool player_invoked); bool (*create) (char *name, AtCommandFunc func); bool (*can_use) (struct map_session_data *sd, const char *command); bool (*can_use2) (struct map_session_data *sd, const char *command, AtCommandType type); - void (*load_groups) (void); + void (*load_groups) (GroupSettings **groups, config_setting_t **commands_, size_t sz); AtCommandInfo* (*exists) (const char* name); - int (*msg_read) (const char* cfgName); + bool (*msg_read) (const char *cfg_name, bool allow_override); void (*final_msg) (void); /* atcommand binding */ struct atcmd_binding_data* (*get_bind_byname) (const char* name); -} atcommand_s; + /* */ + AtCommandInfo* (*get_info_byname) (const char *name); // @help + const char* (*check_alias) (const char *aliasname); // @help + void (*get_suggestions) (struct map_session_data* sd, const char *name, bool is_atcmd_cmd); // @help + void (*config_read) (const char* config_filename); + /* command-specific subs */ + int (*stopattack) (struct block_list *bl,va_list ap); + int (*pvpoff_sub) (struct block_list *bl,va_list ap); + int (*pvpon_sub) (struct block_list *bl,va_list ap); + int (*atkillmonster_sub) (struct block_list *bl, va_list ap); + void (*raise_sub) (struct map_session_data* sd); + void (*get_jail_time) (int jailtime, int* year, int* month, int* day, int* hour, int* minute); + int (*cleanfloor_sub) (struct block_list *bl, va_list ap); + int (*mutearea_sub) (struct block_list *bl,va_list ap); + /* */ + void (*commands_sub) (struct map_session_data* sd, const int fd, AtCommandType type); + void (*cmd_db_clear) (void); + int (*cmd_db_clear_sub) (DBKey key, DBData *data, va_list args); + void (*doload) (void); + void (*base_commands) (void); + bool (*add) (char *name, AtCommandFunc func, bool replace); + const char* (*msg) (int msg_number); +}; struct atcommand_interface *atcommand; -const char* msg_txt(int msg_number); void atcommand_defaults(void); + /* 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) -#define ACMD_A(x) atcommand_ ## x -#endif /* _ATCOMMAND_H_ */ +#endif /* MAP_ATCOMMAND_H */ diff --git a/src/map/battle.c b/src/map/battle.c index 731c6f618..fc159c921 100644 --- a/src/map/battle.c +++ b/src/map/battle.c @@ -2,44 +2,47 @@ // See the LICENSE file // Portions Copyright (c) Athena Dev Teams -#include "../common/cbasetypes.h" -#include "../common/timer.h" -#include "../common/nullpo.h" -#include "../common/malloc.h" -#include "../common/showmsg.h" -#include "../common/ers.h" -#include "../common/random.h" -#include "../common/socket.h" -#include "../common/strlib.h" -#include "../common/utils.h" +#define HERCULES_CORE -#include "map.h" -#include "path.h" -#include "pc.h" -#include "status.h" -#include "skill.h" -#include "homunculus.h" -#include "mercenary.h" -#include "elemental.h" -#include "mob.h" -#include "itemdb.h" -#include "clif.h" -#include "pet.h" -#include "guild.h" -#include "party.h" +#include "../config/core.h" // CELL_NOSTACK, CIRCULAR_AREA, CONSOLE_INPUT, HMAP_ZONE_DAMAGE_CAP_TYPE, OFFICIAL_WALKPATH, RENEWAL, RENEWAL_ASPD, RENEWAL_CAST, RENEWAL_DROP, RENEWAL_EDP, RENEWAL_EXP, RENEWAL_LVDMG, RE_LVL_DMOD(), RE_LVL_MDMOD(), RE_LVL_TMDMOD(), RE_SKILL_REDUCTION(), SCRIPT_CALLFUNC_CHECK, SECURE_NPCTIMEOUT, STATS_OPT_OUT #include "battle.h" -#include "battleground.h" -#include "chrif.h" +#include <math.h> #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <math.h> -int attr_fix_table[4][ELE_MAX][ELE_MAX]; +#include "battleground.h" +#include "chrif.h" +#include "clif.h" +#include "elemental.h" +#include "guild.h" +#include "homunculus.h" +#include "itemdb.h" +#include "map.h" +#include "mercenary.h" +#include "mob.h" +#include "party.h" +#include "path.h" +#include "pc.h" +#include "pet.h" +#include "skill.h" +#include "status.h" +#include "../common/HPM.h" +#include "../common/cbasetypes.h" +#include "../common/ers.h" +#include "../common/malloc.h" +#include "../common/nullpo.h" +#include "../common/random.h" +#include "../common/showmsg.h" +#include "../common/socket.h" +#include "../common/strlib.h" +#include "../common/sysinfo.h" +#include "../common/timer.h" +#include "../common/utils.h" struct Battle_Config battle_config; -static struct eri *delay_damage_ers; //For battle delay damage structures. +struct battle_interface battle_s; int battle_getcurrentskill(struct block_list *bl) { //Returns the current/last skill in use by this bl. struct unit_data *ud; @@ -49,13 +52,13 @@ int battle_getcurrentskill(struct block_list *bl) { //Returns the current/last s return su->group?su->group->skill_id:0; } - ud = unit_bl2ud(bl); + ud = unit->bl2ud(bl); return ud?ud->skill_id:0; } /*========================================== - * Get random targetting enemy + * Get random targeting enemy *------------------------------------------*/ int battle_gettargeted_sub(struct block_list *bl, va_list ap) { struct block_list **bl_list; @@ -73,7 +76,7 @@ int battle_gettargeted_sub(struct block_list *bl, va_list ap) { if (*c >= 24) return 0; - if ( !(ud = unit_bl2ud(bl)) ) + if ( !(ud = unit->bl2ud(bl)) ) return 0; if (ud->target == target_id || ud->skilltarget == target_id) { @@ -90,7 +93,7 @@ struct block_list* battle_gettargeted(struct block_list *target) { nullpo_retr(NULL, target); memset(bl_list, 0, sizeof(bl_list)); - iMap->foreachinrange(battle->get_targeted_sub, target, AREA_SIZE, BL_CHAR, bl_list, &c, target->id); + map->foreachinrange(battle->get_targeted_sub, target, AREA_SIZE, BL_CHAR, bl_list, &c, target->id); if ( c == 0 ) return NULL; if( c > 24 ) @@ -99,7 +102,7 @@ struct block_list* battle_gettargeted(struct block_list *target) { } -//Returns the id of the current targetted character of the passed bl. [Skotlex] +//Returns the id of the current targeted character of the passed bl. [Skotlex] int battle_gettarget(struct block_list* bl) { switch (bl->type) { @@ -129,7 +132,7 @@ int battle_getenemy_sub(struct block_list *bl, va_list ap) { if (*c >= 24) return 0; - if (status_isdead(bl)) + if (status->isdead(bl)) return 0; if (battle->check_target(target, bl, BCT_ENEMY) > 0) { @@ -146,7 +149,7 @@ struct block_list* battle_getenemy(struct block_list *target, int type, int rang int c = 0; memset(bl_list, 0, sizeof(bl_list)); - iMap->foreachinrange(battle->get_enemy_sub, target, range, type, bl_list, &c, target); + map->foreachinrange(battle->get_enemy_sub, target, range, type, bl_list, &c, target); if ( c == 0 ) return NULL; @@ -171,7 +174,7 @@ int battle_getenemyarea_sub(struct block_list *bl, va_list ap) { if( *c >= 23 ) return 0; - if( status_isdead(bl) ) + if( status->isdead(bl) ) return 0; if( battle->check_target(src, bl, BCT_ENEMY) > 0 ) {// Is Enemy!... @@ -188,7 +191,7 @@ struct block_list* battle_getenemyarea(struct block_list *src, int x, int y, int int c = 0; memset(bl_list, 0, sizeof(bl_list)); - iMap->foreachinarea(battle->get_enemy_area_sub, src->m, x - range, y - range, x + range, y + range, type, bl_list, &c, src, ignore_id); + map->foreachinarea(battle->get_enemy_area_sub, src->m, x - range, y - range, x + range, y + range, type, bl_list, &c, src, ignore_id); if( c == 0 ) return NULL; @@ -198,81 +201,76 @@ struct block_list* battle_getenemyarea(struct block_list *src, int x, int y, int return bl_list[rnd()%c]; } -// Dammage delayed info -struct delay_damage { - int src_id; - int target_id; - int damage; - int delay; - unsigned short distance; - uint16 skill_lv; - uint16 skill_id; - enum damage_lv dmg_lv; - unsigned short attack_type; - bool additional_effects; -}; - -int battle_delay_damage_sub(int tid, unsigned int tick, int id, intptr_t data) { +int battle_delay_damage_sub(int tid, int64 tick, int id, intptr_t data) { struct delay_damage *dat = (struct delay_damage *)data; if ( dat ) { - struct block_list* src; - struct block_list* target = iMap->id2bl(dat->target_id); + struct block_list* src = NULL; + struct block_list* target = map->id2bl(dat->target_id); - if( !target || status_isdead(target) ) {/* nothing we can do */ - ers_free(delay_damage_ers, dat); + if( !target || status->isdead(target) ) {/* nothing we can do */ + if( dat->src_type == BL_PC && ( src = map->id2bl(dat->src_id) ) && --((TBL_PC*)src)->delayed_damage == 0 && ((TBL_PC*)src)->state.hold_recalc ) { + ((TBL_PC*)src)->state.hold_recalc = 0; + status_calc_pc(((TBL_PC*)src),SCO_FORCE); + } + ers_free(battle->delay_damage_ers, dat); return 0; } - src = iMap->id2bl(dat->src_id); - - if( src && target->m == src->m && - (target->type != BL_PC || ((TBL_PC*)target)->invincible_timer == INVALID_TIMER) && - check_distance_bl(src, target, dat->distance) ) //Check to see if you haven't teleported. [Skotlex] - { - iMap->freeblock_lock(); + src = map->id2bl(dat->src_id); + + //Check to see if you haven't teleported. [Skotlex] + if( src && target->m == src->m + && (target->type != BL_PC || ((TBL_PC*)target)->invincible_timer == INVALID_TIMER) + && check_distance_bl(src, target, dat->distance) + ) { + map->freeblock_lock(); status_fix_damage(src, target, dat->damage, dat->delay); - if( dat->attack_type && !status_isdead(target) && dat->additional_effects ) + if( dat->attack_type && !status->isdead(target) && dat->additional_effects ) skill->additional_effect(src,target,dat->skill_id,dat->skill_lv,dat->attack_type,dat->dmg_lv,tick); if( dat->dmg_lv > ATK_BLOCK && dat->attack_type ) skill->counter_additional_effect(src,target,dat->skill_id,dat->skill_lv,dat->attack_type,tick); - iMap->freeblock_unlock(); + map->freeblock_unlock(); } else if( !src && dat->skill_id == CR_REFLECTSHIELD ) { /** * it was monster reflected damage, and the monster died, we pass the damage to the character as expected **/ - iMap->freeblock_lock(); + map->freeblock_lock(); status_fix_damage(target, target, dat->damage, dat->delay); - iMap->freeblock_unlock(); + map->freeblock_unlock(); + } + + if( src && src->type == BL_PC && --((TBL_PC*)src)->delayed_damage == 0 && ((TBL_PC*)src)->state.hold_recalc ) { + ((TBL_PC*)src)->state.hold_recalc = 0; + status_calc_pc(((TBL_PC*)src),SCO_FORCE); } } - ers_free(delay_damage_ers, dat); + ers_free(battle->delay_damage_ers, dat); return 0; } -int battle_delay_damage (unsigned int tick, int amotion, struct block_list *src, struct block_list *target, int attack_type, uint16 skill_id, uint16 skill_lv, int damage, enum damage_lv dmg_lv, int ddelay, bool additional_effects) -{ +int battle_delay_damage(int64 tick, int amotion, struct block_list *src, struct block_list *target, int attack_type, uint16 skill_id, uint16 skill_lv, int64 damage, enum damage_lv dmg_lv, int ddelay, bool additional_effects) { struct delay_damage *dat; struct status_change *sc; nullpo_ret(src); nullpo_ret(target); - sc = status_get_sc(target); + sc = status->get_sc(target); if( sc && sc->data[SC_DEVOTION] && damage > 0 && skill_id != PA_PRESSURE && skill_id != CR_REFLECTSHIELD ) damage = 0; if ( !battle_config.delay_battle_damage || amotion <= 1 ) { - iMap->freeblock_lock(); - status_fix_damage(src, target, damage, ddelay); // We have to seperate here between reflect damage and others [icescope] - if( attack_type && !status_isdead(target) && additional_effects ) - skill->additional_effect(src, target, skill_id, skill_lv, attack_type, dmg_lv, iTimer->gettick()); + map->freeblock_lock(); + status_fix_damage(src, target, damage, ddelay); // We have to separate here between reflect damage and others [icescope] + if( attack_type && !status->isdead(target) && additional_effects ) + skill->additional_effect(src, target, skill_id, skill_lv, attack_type, dmg_lv, timer->gettick()); if( dmg_lv > ATK_BLOCK && attack_type ) - skill->counter_additional_effect(src, target, skill_id, skill_lv, attack_type, iTimer->gettick()); - iMap->freeblock_unlock(); + skill->counter_additional_effect(src, target, skill_id, skill_lv, attack_type, timer->gettick()); + map->freeblock_unlock(); return 0; } - dat = ers_alloc(delay_damage_ers, struct delay_damage); + dat = ers_alloc(battle->delay_damage_ers, struct delay_damage); dat->src_id = src->id; dat->target_id = target->id; dat->skill_id = skill_id; @@ -283,10 +281,15 @@ int battle_delay_damage (unsigned int tick, int amotion, struct block_list *src, dat->delay = ddelay; dat->distance = distance_bl(src, target)+10; //Attack should connect regardless unless you teleported. dat->additional_effects = additional_effects; + dat->src_type = src->type; if (src->type != BL_PC && amotion > 1000) amotion = 1000; //Aegis places a damage-delay cap of 1 sec to non player attacks. [Skotlex] - iTimer->add_timer(tick+amotion, battle->delay_damage_sub, 0, (intptr_t)dat); + if( src->type == BL_PC ) { + ((TBL_PC*)src)->delayed_damage++; + } + + timer->add(tick+amotion, battle->delay_damage_sub, 0, (intptr_t)dat); return 0; } @@ -299,7 +302,7 @@ int battle_attr_ratio(int atk_elem,int def_type, int def_lv) if (def_type < 0 || def_type > ELE_MAX || def_lv < 1 || def_lv > 4) return 100; - return attr_fix_table[def_lv-1][atk_elem][def_type]; + return battle->attr_fix_table[def_lv-1][atk_elem][def_type]; } /*========================================== @@ -307,13 +310,13 @@ int battle_attr_ratio(int atk_elem,int def_type, int def_lv) * Added passing of the chars so that the status changes can affect it. [Skotlex] * Note: Passing src/target == NULL is perfectly valid, it skips SC_ checks. *------------------------------------------*/ -int battle_attr_fix(struct block_list *src, struct block_list *target, int damage,int atk_elem,int def_type, int def_lv) +int64 battle_attr_fix(struct block_list *src, struct block_list *target, int64 damage,int atk_elem,int def_type, int def_lv) { struct status_change *sc=NULL, *tsc=NULL; int ratio; - if (src) sc = status_get_sc(src); - if (target) tsc = status_get_sc(target); + if (src) sc = status->get_sc(src); + if (target) tsc = status->get_sc(target); if (atk_elem < 0 || atk_elem >= ELE_MAX) atk_elem = rnd()%ELE_MAX; @@ -324,70 +327,74 @@ int battle_attr_fix(struct block_list *src, struct block_list *target, int damag return damage; } - ratio = attr_fix_table[def_lv-1][atk_elem][def_type]; + ratio = battle->attr_fix_table[def_lv-1][atk_elem][def_type]; if (sc && sc->count) { if(sc->data[SC_VOLCANO] && atk_elem == ELE_FIRE) - ratio += enchant_eff[sc->data[SC_VOLCANO]->val1-1]; + ratio += skill->enchant_eff[sc->data[SC_VOLCANO]->val1-1]; if(sc->data[SC_VIOLENTGALE] && atk_elem == ELE_WIND) - ratio += enchant_eff[sc->data[SC_VIOLENTGALE]->val1-1]; + ratio += skill->enchant_eff[sc->data[SC_VIOLENTGALE]->val1-1]; if(sc->data[SC_DELUGE] && atk_elem == ELE_WATER) - ratio += enchant_eff[sc->data[SC_DELUGE]->val1-1]; + ratio += skill->enchant_eff[sc->data[SC_DELUGE]->val1-1]; + if(sc->data[SC_FIRE_CLOAK_OPTION] && atk_elem == ELE_FIRE) + damage += damage * sc->data[SC_FIRE_CLOAK_OPTION]->val2 / 100; } if( target && target->type == BL_SKILL ) { if( atk_elem == ELE_FIRE && battle->get_current_skill(target) == GN_WALLOFTHORN ) { struct skill_unit *su = (struct skill_unit*)target; struct skill_unit_group *sg; - struct block_list *src; + struct block_list *sgsrc; - if( !su || !su->alive || (sg = su->group) == NULL || !sg || sg->val3 == -1 || - (src = iMap->id2bl(sg->src_id)) == NULL || status_isdead(src) ) + if( !su || !su->alive + || (sg = su->group) == NULL || sg->val3 == -1 + || (sgsrc = map->id2bl(sg->src_id)) == NULL || status->isdead(sgsrc) + ) return 0; if( sg->unit_id != UNT_FIREWALL ) { int x,y; x = sg->val3 >> 16; y = sg->val3 & 0xffff; - skill->unitsetting(src,su->group->skill_id,su->group->skill_lv,x,y,1); + skill->unitsetting(sgsrc,su->group->skill_id,su->group->skill_lv,x,y,1); sg->val3 = -1; - sg->limit = DIFF_TICK(iTimer->gettick(),sg->tick)+300; + sg->limit = DIFF_TICK32(timer->gettick(),sg->tick)+300; } } } - if( tsc && tsc->count ) { //since an atk can only have one type let's optimise this a bit + if( tsc && tsc->count ) { //since an atk can only have one type let's optimize this a bit switch(atk_elem){ - case ELE_FIRE: - if( tsc->data[SC_SPIDERWEB]) { - tsc->data[SC_SPIDERWEB]->val1 = 0; // free to move now - if( tsc->data[SC_SPIDERWEB]->val2-- > 0 ) - damage <<= 1; // double damage - if( tsc->data[SC_SPIDERWEB]->val2 == 0 ) - status_change_end(target, SC_SPIDERWEB, INVALID_TIMER); - } - if( tsc->data[SC_THORNS_TRAP]) - status_change_end(target, SC_THORNS_TRAP, INVALID_TIMER); - if( tsc->data[SC_FIRE_CLOAK_OPTION]) - damage -= damage * tsc->data[SC_FIRE_CLOAK_OPTION]->val2 / 100; - if( tsc->data[SC_CRYSTALIZE] && target->type != BL_MOB) - status_change_end(target, SC_CRYSTALIZE, INVALID_TIMER); - if( tsc->data[SC_EARTH_INSIGNIA]) damage += damage/2; - if( tsc->data[SC_VOLCANIC_ASH]) damage += damage/2; //150% - break; - case ELE_HOLY: - if( tsc->data[SC_ORATIO]) ratio += tsc->data[SC_ORATIO]->val1 * 2; - break; - case ELE_POISON: - if( tsc->data[SC_VENOMIMPRESS]) ratio += tsc->data[SC_VENOMIMPRESS]->val2; - break; - case ELE_WIND: - if( tsc->data[SC_CRYSTALIZE] && target->type != BL_MOB) damage += damage/2; - if( tsc->data[SC_WATER_INSIGNIA]) damage += damage/2; - break; - case ELE_WATER: - if( tsc->data[SC_FIRE_INSIGNIA]) damage += damage/2; - break; - case ELE_EARTH: - if( tsc->data[SC_WIND_INSIGNIA]) damage += damage/2; - break; + case ELE_FIRE: + if( tsc->data[SC_SPIDERWEB]) { + tsc->data[SC_SPIDERWEB]->val1 = 0; // free to move now + if( tsc->data[SC_SPIDERWEB]->val2-- > 0 ) + damage <<= 1; // double damage + if( tsc->data[SC_SPIDERWEB]->val2 == 0 ) + status_change_end(target, SC_SPIDERWEB, INVALID_TIMER); + } + if( tsc->data[SC_THORNS_TRAP]) + status_change_end(target, SC_THORNS_TRAP, INVALID_TIMER); + if( tsc->data[SC_COLD] && target->type != BL_MOB) + status_change_end(target, SC_COLD, INVALID_TIMER); + if( tsc->data[SC_EARTH_INSIGNIA]) damage += damage/2; + if( tsc->data[SC_FIRE_CLOAK_OPTION]) + damage -= damage * tsc->data[SC_FIRE_CLOAK_OPTION]->val2 / 100; + if( tsc->data[SC_VOLCANIC_ASH]) damage += damage/2; //150% + break; + case ELE_HOLY: + if( tsc->data[SC_ORATIO]) ratio += tsc->data[SC_ORATIO]->val1 * 2; + break; + case ELE_POISON: + if( tsc->data[SC_VENOMIMPRESS] && atk_elem == ELE_POISON ) ratio += tsc->data[SC_VENOMIMPRESS]->val2; + break; + case ELE_WIND: + if( tsc->data[SC_COLD] && target->type != BL_MOB) damage += damage/2; + if( tsc->data[SC_WATER_INSIGNIA]) damage += damage/2; + break; + case ELE_WATER: + if( tsc->data[SC_FIRE_INSIGNIA]) damage += damage/2; + break; + case ELE_EARTH: + if( tsc->data[SC_WIND_INSIGNIA]) damage += damage/2; + break; } } //end tsc check if( src && src->type == BL_PC ){ @@ -408,77 +415,78 @@ int battle_attr_fix(struct block_list *src, struct block_list *target, int damag if( t < 5 && atk_elem == t ) damage -= damage * ( tsd->charm[t] * 3 ) / 100;// -3% custom value } - return damage*ratio/100; + if( ratio < 100 ) + return damage - (damage * (100 - ratio) / 100); + else + return damage + (damage * (ratio - 100) / 100); } +int64 battle_calc_weapon_damage(struct block_list *src, struct block_list *bl, uint16 skill_id, uint16 skill_lv, struct weapon_atk *watk, int nk, bool n_ele, short s_ele, short s_ele_, int size, int type, int flag, int flag2){ // [malufett] #ifdef RENEWAL -int battle_calc_weapon_damage(struct block_list *src, struct block_list *bl, uint16 skill_id, uint16 skill_lv, struct weapon_atk *watk, int nk, bool n_ele, short s_ele, short s_ele_, int size, int type, int flag, int flag2){ // [malufett] - int damage, eatk = 0; + int64 damage, eatk = 0; struct status_change *sc; struct map_session_data *sd; if( !src || !bl ) return 0; - sc = status_get_sc(src); + sc = status->get_sc(src); sd = BL_CAST(BL_PC, src); - damage = status_get_weapon_atk(src, watk, flag); + damage = status->get_weapon_atk(src, watk, flag); if( sd ){ if( type == EQI_HAND_R ) damage = battle->calc_sizefix(sd, damage, EQI_HAND_R, size, flag&8); else damage = battle->calc_sizefix(sd, damage, EQI_HAND_L, size, flag&8); - - if( sd->bonus.eatk > 0 ) - eatk = sd->bonus.eatk; + if( flag&2 && sd->bonus.arrow_atk ) - eatk += sd->bonus.arrow_atk; + damage += sd->bonus.arrow_atk; + + if( sd->battle_status.equip_atk != 0 ) + eatk = sd->base_status.equip_atk; } - + if( sc && sc->count ){ if( sc->data[SC_ZENKAI] && watk->ele == sc->data[SC_ZENKAI]->val2 ) eatk += 200; - #ifdef RENEWAL_EDP - if( sc->data[SC_EDP] && skill_id != AS_GRIMTOOTH && skill_id != AS_VENOMKNIFE ){ - eatk = eatk * sc->data[SC_EDP]->val3 / 100; // 400% - damage = damage * sc->data[SC_EDP]->val4 / 100; // 500% - damage--; // temporary until we find the correct formula [malufett] + #ifdef RENEWAL_EDP + if( sc->data[SC_EDP] && skill_id != AS_GRIMTOOTH && skill_id != AS_VENOMKNIFE && skill_id != ASC_BREAKER ){ + eatk = eatk * (sc->data[SC_EDP]->val4 / 100 - 1); + damage = damage * (sc->data[SC_EDP]->val4 / 100); } #endif } - /* [malufett] - some unknown factors that needs to be discovered. PS: it's something related with ranged attacks - if( eatk ){ - eatk += unknown value; - eatk = eatk * (unknown value) / 100; + if( skill_id != ASC_METEORASSAULT ){ + if( sc && sc->data[SC_SUB_WEAPONPROPERTY] ) // Temporary. [malufett] + damage += damage * sc->data[SC_SUB_WEAPONPROPERTY]->val2 / 100; } - */ - if( sc && sc->data[SC_WATK_ELEMENT] ) - damage = damage + eatk; - else - damage = battle->calc_elefix(src, bl, skill_id, skill_lv, damage + eatk, nk, n_ele, s_ele, s_ele_, false, flag); - + // Temporary. [malufett] + damage = battle->calc_elefix(src, bl, skill_id, skill_lv, damage + eatk, nk, n_ele, s_ele, s_ele_, type == EQI_HAND_L, flag); + /** - * In RE Shield Bommerang takes weapon element only for damage calculation, + * In RE Shield Boomerang takes weapon element only for damage calculation, * - resist calculation is always against neutral **/ if ( skill_id == CR_SHIELDBOOMERANG ) s_ele = s_ele_ = ELE_NEUTRAL; - if( type == EQI_HAND_R ) - damage = battle->calc_cardfix(BF_WEAPON, src, bl, nk, s_ele, s_ele_, damage, 2, flag2); - else - damage = battle->calc_cardfix(BF_WEAPON, src, bl, nk, s_ele, s_ele_, damage, 3, flag2); + // attacker side + damage = battle->calc_cardfix(BF_WEAPON, src, bl, nk, s_ele, s_ele_, damage, 2|(type == EQI_HAND_L), flag2); + // target side + damage = battle->calc_cardfix(BF_WEAPON, src, bl, nk, s_ele, s_ele_, damage, 0, flag2); + return damage; -} +#else + return 0; #endif +} /*========================================== * Calculates the standard damage of a normal attack assuming it hits, - * it calculates nothing extra fancy, is needed for magnum break's WATK_ELEMENT bonus. [Skotlex] + * it calculates nothing extra fancy, is needed for magnum breaks WATK_ELEMENT bonus. [Skotlex] *------------------------------------------ * Pass damage2 as NULL to not calc it. * Flag values: @@ -488,34 +496,29 @@ int battle_calc_weapon_damage(struct block_list *src, struct block_list *bl, uin * &8: Skip target size adjustment (Extremity Fist?) *&16: Arrow attack but BOW, REVOLVER, RIFLE, SHOTGUN, GATLING or GRENADE type weapon not equipped (i.e. shuriken, kunai and venom knives not affected by DEX) */ - -#ifdef RENEWAL -int battle_calc_base_damage(struct block_list *src, struct block_list *bl, uint16 skill_id, uint16 skill_lv, int nk, bool n_ele, short s_ele, short s_ele_, int type, int flag, int flag2) -{ - int damage, batk; - struct status_change *sc = status_get_sc(src); - struct status_data *status = status_get_status_data(src); +/* 'battle_calc_base_damage' is used on renewal, 'battle_calc_base_damage2' otherwise. */ +int64 battle_calc_base_damage(struct block_list *src, struct block_list *bl, uint16 skill_id, uint16 skill_lv, int nk, bool n_ele, short s_ele, short s_ele_, int type, int flag, int flag2) { + int64 damage, batk; + struct status_data *st = status->get_status_data(src); - if( sc && sc->data[SC_TK_SEVENWIND] && !sc->data[SC_WATK_ELEMENT] ) - batk = battle->calc_elefix(src, bl, skill_id, skill_lv, status->batk, nk, n_ele, s_ele, s_ele_, false, flag); - else - batk = status->batk; + batk = battle->calc_elefix(src, bl, skill_id, skill_lv, status->calc_batk(bl, status->get_sc(src), st->batk, false), nk, n_ele, ELE_NEUTRAL, ELE_NEUTRAL, false, flag); if( type == EQI_HAND_L ) - damage = batk + 3 * battle->calc_weapon_damage(src, bl, skill_id, skill_lv, &status->lhw, nk, n_ele, s_ele, s_ele_, status_get_size(bl), type, flag, flag2) / 4; + damage = batk + 3 * battle->calc_weapon_damage(src, bl, skill_id, skill_lv, &st->lhw, nk, n_ele, s_ele, s_ele_, status_get_size(bl), type, flag, flag2) / 4; else - damage = (batk << 1) + battle->calc_weapon_damage(src, bl, skill_id, skill_lv, &status->rhw, nk, n_ele, s_ele, s_ele_, status_get_size(bl), type, flag, flag2); -#else -static int battle_calc_base_damage(struct status_data *status, struct weapon_atk *wa, struct status_change *sc, unsigned short t_size, struct map_session_data *sd, int flag) -{ + damage = (batk << 1) + battle->calc_weapon_damage(src, bl, skill_id, skill_lv, &st->rhw, nk, n_ele, s_ele, s_ele_, status_get_size(bl), type, flag, flag2); + + return damage; +} +int64 battle_calc_base_damage2(struct status_data *st, struct weapon_atk *wa, struct status_change *sc, unsigned short t_size, struct map_session_data *sd, int flag) { unsigned int atkmin=0, atkmax=0; short type = 0; - int damage = 0; + int64 damage = 0; if (!sd) { //Mobs/Pets if(flag&4) { - atkmin = status->matk_min; - atkmax = status->matk_max; + atkmin = st->matk_min; + atkmax = st->matk_max; } else { atkmin = wa->atk; atkmax = wa->atk2; @@ -524,10 +527,10 @@ static int battle_calc_base_damage(struct status_data *status, struct weapon_atk atkmin = atkmax; } else { //PCs atkmax = wa->atk; - type = (wa == &status->lhw)?EQI_HAND_L:EQI_HAND_R; + type = (wa == &st->lhw)?EQI_HAND_L:EQI_HAND_R; if (!(flag&1) || (flag&2)) { //Normal attacks - atkmin = status->dex; + atkmin = st->dex; if (sd->equip_index[type] >= 0 && sd->inventory_data[sd->equip_index[type]]) atkmin = atkmin*(80 + sd->inventory_data[sd->equip_index[type]]->wlv*20)/100; @@ -564,11 +567,11 @@ static int battle_calc_base_damage(struct status_data *status, struct weapon_atk //Finally, add baseatk if(flag&4) - damage += status->matk_min; + damage += st->matk_min; else - damage += status->batk; + damage += st->batk; - //rodatazone says that Overrefine bonuses are part of baseatk + //rodatazone says that Overrefined bonuses are part of baseatk //Here we also apply the weapon_atk_rate bonus so it is correctly applied on left/right hands. if(sd) { if (type == EQI_HAND_L) { @@ -583,11 +586,10 @@ static int battle_calc_base_damage(struct status_data *status, struct weapon_atk damage += damage * sd->weapon_atk_rate[sd->weapontype1] / 100; } } -#endif return damage; } -int battle_calc_sizefix(struct map_session_data *sd, int damage, int type, int size, bool ignore){ +int64 battle_calc_sizefix(struct map_session_data *sd, int64 damage, int type, int size, bool ignore){ //SizeFix only for players if (!(sd->special_state.no_sizefix || (ignore))) damage = damage * ( type == EQI_HAND_L ? sd->left_weapon.atkmods[size] : sd->right_weapon.atkmods[size] ) / 100; @@ -597,32 +599,31 @@ int battle_calc_sizefix(struct map_session_data *sd, int damage, int type, int s /*========================================== * Passive skill damages increases *------------------------------------------*/ -int battle_addmastery(struct map_session_data *sd,struct block_list *target,int dmg,int type) -{ - int damage,skill; - struct status_data *status = status_get_status_data(target); - int weapon; +int64 battle_addmastery(struct map_session_data *sd,struct block_list *target,int64 dmg,int type) { + int64 damage; + struct status_data *st = status->get_status_data(target); + int weapon, skill_lv; damage = dmg; nullpo_ret(sd); - if((skill = pc->checkskill(sd,AL_DEMONBANE)) > 0 && - target->type == BL_MOB && //This bonus doesnt work against players. - (battle->check_undead(status->race,status->def_ele) || status->race==RC_DEMON) ) - damage += (int)(skill*(3+sd->status.base_level/20.0)); - //damage += (skill * 3); - if( (skill = pc->checkskill(sd, RA_RANGERMAIN)) > 0 && (status->race == RC_BRUTE || status->race == RC_PLANT || status->race == RC_FISH) ) - damage += (skill * 5); - if( (skill = pc->checkskill(sd,NC_RESEARCHFE)) > 0 && (status->def_ele == ELE_FIRE || status->def_ele == ELE_EARTH) ) - damage += (skill * 10); + if((skill_lv = pc->checkskill(sd,AL_DEMONBANE)) > 0 && + target->type == BL_MOB && //This bonus doesn't work against players. + (battle->check_undead(st->race,st->def_ele) || st->race==RC_DEMON) ) + damage += (int)(skill_lv*(3+sd->status.base_level/20.0)); + //damage += (skill_lv * 3); + if( (skill_lv = pc->checkskill(sd, RA_RANGERMAIN)) > 0 && (st->race == RC_BRUTE || st->race == RC_PLANT || st->race == RC_FISH) ) + damage += (skill_lv * 5); + if( (skill_lv = pc->checkskill(sd,NC_RESEARCHFE)) > 0 && (st->def_ele == ELE_FIRE || st->def_ele == ELE_EARTH) ) + damage += (skill_lv * 10); if( pc_ismadogear(sd) ) - damage += 20 + 20 * pc->checkskill(sd, NC_MADOLICENCE); + damage += 15 * pc->checkskill(sd, NC_MADOLICENCE); #ifdef RENEWAL - if( (skill = pc->checkskill(sd,BS_WEAPONRESEARCH)) > 0 ) - damage += (skill * 2); + if( (skill_lv = pc->checkskill(sd,BS_WEAPONRESEARCH)) > 0 ) + damage += (skill_lv * 2); #endif - if((skill = pc->checkskill(sd,HT_BEASTBANE)) > 0 && (status->race==RC_BRUTE || status->race==RC_INSECT) ) { - damage += (skill * 4); + if((skill_lv = pc->checkskill(sd,HT_BEASTBANE)) > 0 && (st->race==RC_BRUTE || st->race==RC_INSECT) ) { + damage += (skill_lv * 4); if (sd->sc.data[SC_SOULLINK] && sd->sc.data[SC_SOULLINK]->val2 == SL_HUNTER) damage += sd->status.str; } @@ -631,76 +632,74 @@ int battle_addmastery(struct map_session_data *sd,struct block_list *target,int weapon = sd->weapontype1; else weapon = sd->weapontype2; - switch(weapon) - { + switch(weapon) { case W_1HSWORD: #ifdef RENEWAL - if((skill = pc->checkskill(sd,AM_AXEMASTERY)) > 0) - damage += (skill * 3); + if((skill_lv = pc->checkskill(sd,AM_AXEMASTERY)) > 0) + damage += (skill_lv * 3); #endif case W_DAGGER: - if((skill = pc->checkskill(sd,SM_SWORD)) > 0) - damage += (skill * 4); - if((skill = pc->checkskill(sd,GN_TRAINING_SWORD)) > 0) - damage += skill * 10; + if((skill_lv = pc->checkskill(sd,SM_SWORD)) > 0) + damage += (skill_lv * 4); + if((skill_lv = pc->checkskill(sd,GN_TRAINING_SWORD)) > 0) + damage += skill_lv * 10; break; case W_2HSWORD: #ifdef RENEWAL - if((skill = pc->checkskill(sd,AM_AXEMASTERY)) > 0) - damage += (skill * 3); + if((skill_lv = pc->checkskill(sd,AM_AXEMASTERY)) > 0) + damage += (skill_lv * 3); #endif - if((skill = pc->checkskill(sd,SM_TWOHAND)) > 0) - damage += (skill * 4); + if((skill_lv = pc->checkskill(sd,SM_TWOHAND)) > 0) + damage += (skill_lv * 4); break; case W_1HSPEAR: case W_2HSPEAR: - if((skill = pc->checkskill(sd,KN_SPEARMASTERY)) > 0) { - - if(!pc_isriding(sd)) - damage += (skill * 4); - else if(pc_isridingdragon(sd)) - damage += (skill * 10); + if((skill_lv = pc->checkskill(sd,KN_SPEARMASTERY)) > 0) { + if(pc_isridingdragon(sd)) + damage += (skill_lv * 10); + else if(pc_isriding(sd)) + damage += (skill_lv * 5); else - damage += (skill * 5); + damage += (skill_lv * 4); } break; case W_1HAXE: case W_2HAXE: - if((skill = pc->checkskill(sd,AM_AXEMASTERY)) > 0) - damage += (skill * 3); - if((skill = pc->checkskill(sd,NC_TRAININGAXE)) > 0) - damage += (skill * 5); + if((skill_lv = pc->checkskill(sd,AM_AXEMASTERY)) > 0) + damage += (skill_lv * 3); + if((skill_lv = pc->checkskill(sd,NC_TRAININGAXE)) > 0) + damage += (skill_lv * 5); break; case W_MACE: case W_2HMACE: - if((skill = pc->checkskill(sd,PR_MACEMASTERY)) > 0) - damage += (skill * 3); - if((skill = pc->checkskill(sd,NC_TRAININGAXE)) > 0) - damage += (skill * 5); + if((skill_lv = pc->checkskill(sd,PR_MACEMASTERY)) > 0) + damage += (skill_lv * 3); + if((skill_lv = pc->checkskill(sd,NC_TRAININGAXE)) > 0) + damage += (skill_lv * 5); break; case W_FIST: - if((skill = pc->checkskill(sd,TK_RUN)) > 0) - damage += (skill * 10); - // No break, fallthrough to Knuckles + if((skill_lv = pc->checkskill(sd,TK_RUN)) > 0) + damage += (skill_lv * 10); + // No break, fall through to Knuckles case W_KNUCKLE: - if((skill = pc->checkskill(sd,MO_IRONHAND)) > 0) - damage += (skill * 3); + if((skill_lv = pc->checkskill(sd,MO_IRONHAND)) > 0) + damage += (skill_lv * 3); break; case W_MUSICAL: - if((skill = pc->checkskill(sd,BA_MUSICALLESSON)) > 0) - damage += (skill * 3); + if((skill_lv = pc->checkskill(sd,BA_MUSICALLESSON)) > 0) + damage += (skill_lv * 3); break; case W_WHIP: - if((skill = pc->checkskill(sd,DC_DANCINGLESSON)) > 0) - damage += (skill * 3); + if((skill_lv = pc->checkskill(sd,DC_DANCINGLESSON)) > 0) + damage += (skill_lv * 3); break; case W_BOOK: - if((skill = pc->checkskill(sd,SA_ADVANCEDBOOK)) > 0) - damage += (skill * 3); + if((skill_lv = pc->checkskill(sd,SA_ADVANCEDBOOK)) > 0) + damage += (skill_lv * 3); break; case W_KATAR: - if((skill = pc->checkskill(sd,AS_KATAR)) > 0) - damage += (skill * 3); + if((skill_lv = pc->checkskill(sd,AS_KATAR)) > 0) + damage += (skill_lv * 3); break; } @@ -710,19 +709,23 @@ int battle_addmastery(struct map_session_data *sd,struct block_list *target,int /*========================================== * Calculates ATK masteries. *------------------------------------------*/ -int battle_calc_masteryfix(struct block_list *src, struct block_list *target, uint16 skill_id, uint16 skill_lv, int damage, int div, bool left, bool weapon){ - int skill, i; - struct map_session_data *sd; +int64 battle_calc_masteryfix(struct block_list *src, struct block_list *target, uint16 skill_id, uint16 skill_lv, int64 damage, int div, bool left, bool weapon) { + int skill2_lv, i; struct status_change *sc; + struct map_session_data *sd; + struct status_data *tstatus; nullpo_ret(src); nullpo_ret(target); - + + sc = status->get_sc(src); sd = BL_CAST(BL_PC, src); - sc = status_get_sc(src); + tstatus = status->get_status_data(target); if ( !sd ) return damage; + + damage = battle->add_mastery(sd, target, damage, left); switch( skill_id ){ // specific skill masteries case MO_INVESTIGATE: @@ -732,119 +735,164 @@ int battle_calc_masteryfix(struct block_list *src, struct block_list *target, ui case CR_ACIDDEMONSTRATION: return damage; case NJ_SYURIKEN: - if( (skill = pc->checkskill(sd,NJ_TOBIDOUGU)) > 0 && weapon ) - damage += 3 * skill; - break; + if( (skill2_lv = pc->checkskill(sd,NJ_TOBIDOUGU)) > 0 +#ifndef RENEWAL + && weapon +#endif + ) + damage += 3 * skill2_lv; + break; +#ifndef RENEWAL case NJ_KUNAI: if( weapon ) damage += 60; break; - case RA_WUGDASH: +#endif + case RA_WUGDASH://(Caster Current Weight x 10 / 8) + if( sd->weight ) + damage += sd->weight / 8 ; case RA_WUGSTRIKE: - case RA_WUGBITE: + case RA_WUGBITE: damage += 30*pc->checkskill(sd, RA_TOOTHOFWUG); break; - } - - if ( sc && sc->data[SC_MIRACLE] ) i = 2; //Star anger - else - ARR_FIND(0, MAX_PC_FEELHATE, i, status_get_class(target) == sd->hate_mob[i]); - if ( i < MAX_PC_FEELHATE && (skill=pc->checkskill(sd,sg_info[i].anger_id)) && weapon ){ - int ratio = sd->status.base_level + status_get_dex(src) + status_get_luk(src); - if ( i == 2 ) ratio += status_get_str(src); //Star Anger - if (skill < 4 ) - ratio /= (12 - 3 * skill); - damage += damage * ratio / 100; + case HT_FREEZINGTRAP: + damage += 40 * pc->checkskill(sd, RA_RESEARCHTRAP); + break; } - if( sc ){ + if( sc ){ // sc considered as masteries if(sc->data[SC_GN_CARTBOOST]) damage += 10 * sc->data[SC_GN_CARTBOOST]->val1; if(sc->data[SC_CAMOUFLAGE]) damage += 30 * ( 10 - sc->data[SC_CAMOUFLAGE]->val4 ); +#ifdef RENEWAL + if(sc->data[SC_NIBELUNGEN] && weapon) + damage += sc->data[SC_NIBELUNGEN]->val2; + if(sc->data[SC_IMPOSITIO]) + damage += sc->data[SC_IMPOSITIO]->val2; + if(sc->data[SC_DRUMBATTLE]){ + if(tstatus->size == SZ_MEDIUM) + damage += sc->data[SC_DRUMBATTLE]->val2; + else if(tstatus->size == SZ_SMALL) + damage += 10 * sc->data[SC_DRUMBATTLE]->val1; + //else no bonus for large target + } + if(sc->data[SC_GS_MADNESSCANCEL]) + damage += 100; + if(sc->data[SC_GS_GATLINGFEVER]){ + if(tstatus->size == SZ_MEDIUM) + damage += 10 * sc->data[SC_GS_GATLINGFEVER]->val1; + else if(tstatus->size == SZ_SMALL) + damage += -5 * sc->data[SC_GS_GATLINGFEVER]->val1; + else + damage += sc->data[SC_GS_GATLINGFEVER]->val1; + } + //if(sc->data[SC_SPECIALZONE]) + // damage += sc->data[SC_SPECIALZONE]->val2 >> 4; +#endif } // general skill masteries #ifdef RENEWAL + if( div < 0 ) // div fix + div = 1; if( skill_id == MO_FINGEROFFENSIVE )//The finger offensive spheres on moment of attack do count. [Skotlex] damage += div * sd->spiritball_old * 3; else damage += div * sd->spiritball * 3; if( skill_id != CR_SHIELDBOOMERANG ) // Only Shield boomerang doesn't takes the Star Crumbs bonus. damage += div * (left ? sd->left_weapon.star : sd->right_weapon.star); + if( skill_id != MC_CARTREVOLUTION && (skill2_lv=pc->checkskill(sd,BS_HILTBINDING)) > 0 ) + damage += 4; + + if(sd->status.party_id && (skill2_lv=pc->checkskill(sd,TK_POWER)) > 0) { + if( (i = party->foreachsamemap(party->sub_count, sd, 0)) > 1 ) + damage += 2 * skill2_lv * i * (damage /*+ unknown value*/) / 100 /*+ unknown value*/; + } #else if( skill_id != ASC_BREAKER && weapon ) // Adv Katar Mastery is does not applies to ASC_BREAKER, but other masteries DO apply >_> - if( sd->status.weapon == W_KATAR && (skill=pc->checkskill(sd,ASC_KATAR)) > 0 ) - damage += damage * (10 + 2 * skill) / 100; + if( sd->status.weapon == W_KATAR && (skill2_lv=pc->checkskill(sd,ASC_KATAR)) > 0 ) + damage += damage * (10 + 2 * skill2_lv) / 100; #endif + // percentage factor masteries + if ( sc && sc->data[SC_MIRACLE] ) + i = 2; //Star anger + else + ARR_FIND(0, MAX_PC_FEELHATE, i, status->get_class(target) == sd->hate_mob[i]); + if ( i < MAX_PC_FEELHATE && (skill2_lv=pc->checkskill(sd,pc->sg_info[i].anger_id)) && weapon ) { + int ratio = sd->status.base_level + status_get_dex(src) + status_get_luk(src); + if ( i == 2 ) ratio += status_get_str(src); //Star Anger + if (skill2_lv < 4 ) + ratio /= (12 - 3 * skill2_lv); + damage += damage * ratio / 100; + } - damage = battle->add_mastery(sd, target, damage, left); - - if((skill = pc->checkskill(sd,AB_EUCHARISTICA)) > 0 && - (status_get_status_data(target)->race == RC_DEMON || status_get_status_data(target)->def_ele == ELE_DARK) ) - damage += damage * skill / 100; + if( sd->status.class_ == JOB_ARCH_BISHOP_T || sd->status.class_ == JOB_ARCH_BISHOP ){ + if((skill2_lv = pc->checkskill(sd,AB_EUCHARISTICA)) > 0 && + (tstatus->race == RC_DEMON || tstatus->def_ele == ELE_DARK) ) + damage += damage * skill2_lv / 100; + } return damage; } /*========================================== * Elemental attribute fix. *------------------------------------------*/ -int battle_calc_elefix(struct block_list *src, struct block_list *target, uint16 skill_id, uint16 skill_lv, int damage, int nk, int n_ele, int s_ele, int s_ele_, bool left, int flag){ - struct status_data *sstatus, *tstatus; - struct status_change *sc; - +int64 battle_calc_elefix(struct block_list *src, struct block_list *target, uint16 skill_id, uint16 skill_lv, int64 damage, int nk, int n_ele, int s_ele, int s_ele_, bool left, int flag){ + struct status_data *tstatus; + nullpo_ret(src); nullpo_ret(target); - sstatus = status_get_status_data(src); - tstatus = status_get_status_data(target); - sc = status_get_sc(src); - - if( (nk&NK_NO_ELEFIX) && n_ele ) + tstatus = status->get_status_data(target); + + if( (nk&NK_NO_ELEFIX) || n_ele ) return damage; - if( damage > 0 ) - { + if( damage > 0 ) { if( left ) damage = battle->attr_fix(src, target, damage, s_ele_, tstatus->def_ele, tstatus->ele_lv); else{ damage=battle->attr_fix(src, target, damage, s_ele, tstatus->def_ele, tstatus->ele_lv); if( skill_id == MC_CARTREVOLUTION ) //Cart Revolution applies the element fix once more with neutral element damage = battle->attr_fix(src,target,damage,ELE_NEUTRAL,tstatus->def_ele, tstatus->ele_lv); + if( skill_id == NC_ARMSCANNON ) + damage = battle->attr_fix(src,target,damage,ELE_NEUTRAL,tstatus->def_ele, tstatus->ele_lv); + if( skill_id == GN_CARTCANNON ) + damage = battle->attr_fix(src,target,damage,ELE_NEUTRAL,tstatus->def_ele, tstatus->ele_lv); if( skill_id == GS_GROUNDDRIFT ) //Additional 50*lv Neutral damage. - damage += battle_attr_fix(src,target,50*skill_lv,ELE_NEUTRAL,tstatus->def_ele, tstatus->ele_lv); + damage += battle->attr_fix(src,target,50*skill_lv,ELE_NEUTRAL,tstatus->def_ele, tstatus->ele_lv); } } - if( sc && sc->data[SC_WATK_ELEMENT] ) - { // Descriptions indicate this means adding a percent of a normal attack in another element. [Skotlex] - damage = -#ifndef RENEWAL - battle->calc_base_damage(sstatus, &sstatus->rhw, sc, tstatus->size, ((TBL_PC*)src), (flag?2:0)) -#else - battle->calc_base_damage(src, target, skill_id, skill_lv, nk, n_ele, s_ele, s_ele_, EQI_HAND_R, (flag?2:0)|(sc && sc->data[SC_MAXIMIZEPOWER]?1:0)|(sc && sc->data[SC_WEAPONPERFECT]?8:0), 0) -#endif - * sc->data[SC_WATK_ELEMENT]->val2 / 100; - - damage += battle->attr_fix(src, target, damage, sc->data[SC_WATK_ELEMENT]->val1, tstatus->def_ele, tstatus->ele_lv); - if( left ){ - damage = + #ifndef RENEWAL - battle->calc_base_damage(sstatus, &sstatus->lhw, sc, tstatus->size, ((TBL_PC*)src), (flag?2:0)) -#else - battle->calc_base_damage(src, target, skill_id, skill_lv, nk, n_ele, s_ele, s_ele_, EQI_HAND_L, (flag?2:0)|(sc && sc->data[SC_MAXIMIZEPOWER]?1:0)|(sc && sc->data[SC_WEAPONPERFECT]?8:0), 0) -#endif - * sc->data[SC_WATK_ELEMENT]->val2 / 100; - damage += battle->attr_fix(src, target, damage, sc->data[SC_WATK_ELEMENT]->val1, tstatus->def_ele, tstatus->ele_lv); + { + struct status_data *sstatus; + struct status_change *sc; + + sstatus = status->get_status_data(src); + sc = status->get_sc(src); + + if( sc && sc->data[SC_SUB_WEAPONPROPERTY] ) { // Descriptions indicate this means adding a percent of a normal attack in another element. [Skotlex] + int64 temp = battle->calc_base_damage2(sstatus, &sstatus->rhw, sc, tstatus->size, BL_CAST(BL_PC, src), (flag?2:0)) * sc->data[SC_SUB_WEAPONPROPERTY]->val2 / 100; + damage += battle->attr_fix(src, target, temp, sc->data[SC_SUB_WEAPONPROPERTY]->val1, tstatus->def_ele, tstatus->ele_lv); + if( left ) { + temp = battle->calc_base_damage2(sstatus, &sstatus->lhw, sc, tstatus->size, BL_CAST(BL_PC, src), (flag?2:0)) * sc->data[SC_SUB_WEAPONPROPERTY]->val2 / 100; + damage += battle->attr_fix(src, target, temp, sc->data[SC_SUB_WEAPONPROPERTY]->val1, tstatus->def_ele, tstatus->ele_lv); } + } } - +#endif return damage; } /*========================================== * Calculates card bonuses damage adjustments. + * cflag(cardfix flag): + * &1 - calc for left hand. + * &2 - atker side cardfix(BF_WEAPON) otherwise target side(BF_WEAPON). *------------------------------------------*/ -int battle_calc_cardfix(int attack_type, struct block_list *src, struct block_list *target, int nk, int s_ele, int s_ele_, int damage, int left, int flag){ +int64 battle_calc_cardfix(int attack_type, struct block_list *src, struct block_list *target, int nk, int s_ele, int s_ele_, int64 damage, int cflag, int wflag){ struct map_session_data *sd, *tsd; short cardfix = 1000, t_class, s_class, s_race2, t_race2; struct status_data *sstatus, *tstatus; @@ -858,24 +906,24 @@ int battle_calc_cardfix(int attack_type, struct block_list *src, struct block_li sd = BL_CAST(BL_PC, src); tsd = BL_CAST(BL_PC, target); - t_class = status_get_class(target); - s_class = status_get_class(src); - sstatus = status_get_status_data(src); - tstatus = status_get_status_data(target); - s_race2 = status_get_race2(src); - + t_class = status->get_class(target); + s_class = status->get_class(src); + sstatus = status->get_status_data(src); + tstatus = status->get_status_data(target); + s_race2 = status->get_race2(src); + switch(attack_type){ case BF_MAGIC: if ( sd && !(nk&NK_NO_CARDFIX_ATK) ) { - cardfix=cardfix*(100+sd->magic_addrace[tstatus->race])/100; + cardfix = cardfix * (100 + sd->magic_addrace[tstatus->race]) / 100; if (!(nk&NK_NO_ELEFIX)) - cardfix=cardfix*(100+sd->magic_addele[tstatus->def_ele])/100; - cardfix=cardfix*(100+sd->magic_addsize[tstatus->size])/100; - cardfix=cardfix*(100+sd->magic_addrace[is_boss(target)?RC_BOSS:RC_NONBOSS])/100; - cardfix=cardfix*(100+sd->magic_atk_ele[s_ele])/100; - for(i=0; i< ARRAYLENGTH(sd->add_mdmg) && sd->add_mdmg[i].rate;i++) { + cardfix = cardfix*(100+sd->magic_addele[tstatus->def_ele]) / 100; + cardfix = cardfix * (100 + sd->magic_addsize[tstatus->size]) / 100; + cardfix = cardfix * (100 + sd->magic_addrace[is_boss(target)?RC_BOSS:RC_NONBOSS]) / 100; + cardfix = cardfix * (100 + sd->magic_atk_ele[s_ele])/100; + for(i=0; i< ARRAYLENGTH(sd->add_mdmg) && sd->add_mdmg[i].rate; i++) { if(sd->add_mdmg[i].class_ == t_class) { - cardfix=cardfix*(100+sd->add_mdmg[i].rate)/100; + cardfix = cardfix * (100 + sd->add_mdmg[i].rate) / 100; break; } } @@ -891,225 +939,217 @@ int battle_calc_cardfix(int attack_type, struct block_list *src, struct block_li for (i = 0; ARRAYLENGTH(tsd->subele2) > i && tsd->subele2[i].rate != 0; i++) { if(tsd->subele2[i].ele != s_ele) continue; - if(!(tsd->subele2[i].flag&flag&BF_WEAPONMASK && - tsd->subele2[i].flag&flag&BF_RANGEMASK && - tsd->subele2[i].flag&flag&BF_SKILLMASK)) + if(!(tsd->subele2[i].flag&wflag&BF_WEAPONMASK && + tsd->subele2[i].flag&wflag&BF_RANGEMASK && + tsd->subele2[i].flag&wflag&BF_SKILLMASK)) continue; ele_fix += tsd->subele2[i].rate; } - cardfix=cardfix*(100-ele_fix)/100; + cardfix = cardfix * (100 - ele_fix) / 100; } - cardfix=cardfix*(100-tsd->subsize[sstatus->size])/100; - cardfix=cardfix*(100-tsd->subrace2[s_race2])/100; - cardfix=cardfix*(100-tsd->subrace[sstatus->race])/100; - cardfix=cardfix*(100-tsd->subrace[is_boss(src)?RC_BOSS:RC_NONBOSS])/100; + cardfix = cardfix * (100 - tsd->subsize[sstatus->size]) / 100; + cardfix = cardfix * (100 - tsd->subrace2[s_race2]) / 100; + cardfix = cardfix * (100 - tsd->subrace[sstatus->race]) / 100; + cardfix = cardfix * (100 - tsd->subrace[is_boss(src)?RC_BOSS:RC_NONBOSS]) / 100; if( sstatus->race != RC_DEMIHUMAN ) - cardfix=cardfix*(100-tsd->subrace[RC_NONDEMIHUMAN])/100; + cardfix = cardfix * (100-tsd->subrace[RC_NONDEMIHUMAN]) / 100; for(i=0; i < ARRAYLENGTH(tsd->add_mdef) && tsd->add_mdef[i].rate;i++) { if(tsd->add_mdef[i].class_ == s_class) { - cardfix=cardfix*(100-tsd->add_mdef[i].rate)/100; + cardfix = cardfix * (100-tsd->add_mdef[i].rate) / 100; break; } } +#ifndef RENEWAL //It was discovered that ranged defense also counts vs magic! [Skotlex] - if ( flag&BF_SHORT ) + if ( wflag&BF_SHORT ) cardfix = cardfix * ( 100 - tsd->bonus.near_attack_def_rate ) / 100; else cardfix = cardfix * ( 100 - tsd->bonus.long_attack_def_rate ) / 100; +#endif cardfix = cardfix * ( 100 - tsd->bonus.magic_def_rate ) / 100; if( tsd->sc.data[SC_PROTECT_MDEF] ) cardfix = cardfix * ( 100 - tsd->sc.data[SC_PROTECT_MDEF]->val1 ) / 100; - if (cardfix != 1000) + if( cardfix != 1000 ) damage = damage * cardfix / 1000; } break; case BF_WEAPON: - t_race2 = status_get_race2(target); - if( sd && !(nk&NK_NO_CARDFIX_ATK) && (left&2) ) - { - short cardfix_ = 1000; - if(sd->state.arrow_atk) - { - cardfix=cardfix*(100+sd->right_weapon.addrace[tstatus->race]+sd->arrow_addrace[tstatus->race])/100; - if (!(nk&NK_NO_ELEFIX)) - { - int ele_fix = sd->right_weapon.addele[tstatus->def_ele] + sd->arrow_addele[tstatus->def_ele]; - for (i = 0; ARRAYLENGTH(sd->right_weapon.addele2) > i && sd->right_weapon.addele2[i].rate != 0; i++) { - if (sd->right_weapon.addele2[i].ele != tstatus->def_ele) continue; - if(!(sd->right_weapon.addele2[i].flag&flag&BF_WEAPONMASK && - sd->right_weapon.addele2[i].flag&flag&BF_RANGEMASK && - sd->right_weapon.addele2[i].flag&flag&BF_SKILLMASK)) - continue; - ele_fix += sd->right_weapon.addele2[i].rate; - } - cardfix=cardfix*(100+ele_fix)/100; - } - cardfix=cardfix*(100+sd->right_weapon.addsize[tstatus->size]+sd->arrow_addsize[tstatus->size])/100; - cardfix=cardfix*(100+sd->right_weapon.addrace2[t_race2])/100; - cardfix=cardfix*(100+sd->right_weapon.addrace[is_boss(target)?RC_BOSS:RC_NONBOSS]+sd->arrow_addrace[is_boss(target)?RC_BOSS:RC_NONBOSS])/100; - if( tstatus->race != RC_DEMIHUMAN ) - cardfix=cardfix*(100+sd->right_weapon.addrace[RC_NONDEMIHUMAN]+sd->arrow_addrace[RC_NONDEMIHUMAN])/100; - } - else - { // Melee attack - if( !battle_config.left_cardfix_to_right ) - { - cardfix=cardfix*(100+sd->right_weapon.addrace[tstatus->race])/100; - if (!(nk&NK_NO_ELEFIX)) { - int ele_fix = sd->right_weapon.addele[tstatus->def_ele]; - for (i = 0; ARRAYLENGTH(sd->right_weapon.addele2) > i && sd->right_weapon.addele2[i].rate != 0; i++) { + t_race2 = status->get_race2(target); + if( cflag&2 ){ + if( sd && !(nk&NK_NO_CARDFIX_ATK) ){ + short cardfix_ = 1000; + if( sd->state.arrow_atk ){ + cardfix = cardfix * (100 + sd->right_weapon.addrace[tstatus->race] + sd->arrow_addrace[tstatus->race]) / 100; + if( !(nk&NK_NO_ELEFIX) ){ + int ele_fix = sd->right_weapon.addele[tstatus->def_ele] + sd->arrow_addele[tstatus->def_ele]; + for(i = 0; ARRAYLENGTH(sd->right_weapon.addele2) > i && sd->right_weapon.addele2[i].rate != 0; i++){ if (sd->right_weapon.addele2[i].ele != tstatus->def_ele) continue; - if(!(sd->right_weapon.addele2[i].flag&flag&BF_WEAPONMASK && - sd->right_weapon.addele2[i].flag&flag&BF_RANGEMASK && - sd->right_weapon.addele2[i].flag&flag&BF_SKILLMASK)) + if(!(sd->right_weapon.addele2[i].flag&wflag&BF_WEAPONMASK && + sd->right_weapon.addele2[i].flag&wflag&BF_RANGEMASK && + sd->right_weapon.addele2[i].flag&wflag&BF_SKILLMASK)) continue; ele_fix += sd->right_weapon.addele2[i].rate; } - cardfix=cardfix*(100+ele_fix)/100; + cardfix = cardfix * (100 + ele_fix) / 100; } - cardfix=cardfix*(100+sd->right_weapon.addsize[tstatus->size])/100; - cardfix=cardfix*(100+sd->right_weapon.addrace2[t_race2])/100; - cardfix=cardfix*(100+sd->right_weapon.addrace[is_boss(target)?RC_BOSS:RC_NONBOSS])/100; + cardfix = cardfix * (100 + sd->right_weapon.addsize[tstatus->size]+sd->arrow_addsize[tstatus->size]) / 100; + cardfix = cardfix * (100 + sd->right_weapon.addrace2[t_race2]) / 100; + cardfix = cardfix * (100 + sd->right_weapon.addrace[is_boss(target)?RC_BOSS:RC_NONBOSS] + sd->arrow_addrace[is_boss(target)?RC_BOSS:RC_NONBOSS]) / 100; if( tstatus->race != RC_DEMIHUMAN ) - cardfix=cardfix*(100+sd->right_weapon.addrace[RC_NONDEMIHUMAN])/100; - - if( left&1 ) - { - cardfix_=cardfix_*(100+sd->left_weapon.addrace[tstatus->race])/100; - if (!(nk&NK_NO_ELEFIX)) { - int ele_fix_lh = sd->left_weapon.addele[tstatus->def_ele]; - for (i = 0; ARRAYLENGTH(sd->left_weapon.addele2) > i && sd->left_weapon.addele2[i].rate != 0; i++) { - if (sd->left_weapon.addele2[i].ele != tstatus->def_ele) continue; - if(!(sd->left_weapon.addele2[i].flag&flag&BF_WEAPONMASK && - sd->left_weapon.addele2[i].flag&flag&BF_RANGEMASK && - sd->left_weapon.addele2[i].flag&flag&BF_SKILLMASK)) + cardfix = cardfix * (100 + sd->right_weapon.addrace[RC_NONDEMIHUMAN]+sd->arrow_addrace[RC_NONDEMIHUMAN]) / 100; + }else{ // Melee attack + if( !battle_config.left_cardfix_to_right ){ + cardfix=cardfix*(100+sd->right_weapon.addrace[tstatus->race])/100; + if( !(nk&NK_NO_ELEFIX) ){ + int ele_fix = sd->right_weapon.addele[tstatus->def_ele]; + for (i = 0; ARRAYLENGTH(sd->right_weapon.addele2) > i && sd->right_weapon.addele2[i].rate != 0; i++) { + if (sd->right_weapon.addele2[i].ele != tstatus->def_ele) continue; + if(!(sd->right_weapon.addele2[i].flag&wflag&BF_WEAPONMASK && + sd->right_weapon.addele2[i].flag&wflag&BF_RANGEMASK && + sd->right_weapon.addele2[i].flag&wflag&BF_SKILLMASK)) continue; - ele_fix_lh += sd->left_weapon.addele2[i].rate; + ele_fix += sd->right_weapon.addele2[i].rate; + } + cardfix = cardfix * (100+ele_fix) / 100; + } + cardfix = cardfix * (100+sd->right_weapon.addsize[tstatus->size]) / 100; + cardfix = cardfix * (100+sd->right_weapon.addrace2[t_race2]) / 100; + cardfix = cardfix * (100+sd->right_weapon.addrace[is_boss(target)?RC_BOSS:RC_NONBOSS]) / 100; + if( tstatus->race != RC_DEMIHUMAN ) + cardfix = cardfix * (100 + sd->right_weapon.addrace[RC_NONDEMIHUMAN]) / 100; + + if( cflag&1 ){ + cardfix_ = cardfix_*(100+sd->left_weapon.addrace[tstatus->race])/100; + if (!(nk&NK_NO_ELEFIX)){ + int ele_fix_lh = sd->left_weapon.addele[tstatus->def_ele]; + for (i = 0; ARRAYLENGTH(sd->left_weapon.addele2) > i && sd->left_weapon.addele2[i].rate != 0; i++) { + if (sd->left_weapon.addele2[i].ele != tstatus->def_ele) continue; + if(!(sd->left_weapon.addele2[i].flag&wflag&BF_WEAPONMASK && + sd->left_weapon.addele2[i].flag&wflag&BF_RANGEMASK && + sd->left_weapon.addele2[i].flag&wflag&BF_SKILLMASK)) + continue; + ele_fix_lh += sd->left_weapon.addele2[i].rate; + } + cardfix = cardfix * (100+ele_fix_lh) / 100; } - cardfix=cardfix*(100+ele_fix_lh)/100; + cardfix_ = cardfix_ * (100+sd->left_weapon.addsize[tstatus->size]) / 100; + cardfix_ = cardfix_ * (100+sd->left_weapon.addrace2[t_race2]) / 100; + cardfix_ = cardfix_ * (100+sd->left_weapon.addrace[is_boss(target)?RC_BOSS:RC_NONBOSS]) / 100; + if( tstatus->race != RC_DEMIHUMAN ) + cardfix_ = cardfix_*(100+sd->left_weapon.addrace[RC_NONDEMIHUMAN])/100; + } + }else{ + int ele_fix = sd->right_weapon.addele[tstatus->def_ele] + sd->left_weapon.addele[tstatus->def_ele]; + for (i = 0; ARRAYLENGTH(sd->right_weapon.addele2) > i && sd->right_weapon.addele2[i].rate != 0; i++){ + if (sd->right_weapon.addele2[i].ele != tstatus->def_ele) continue; + if(!(sd->right_weapon.addele2[i].flag&wflag&BF_WEAPONMASK && + sd->right_weapon.addele2[i].flag&wflag&BF_RANGEMASK && + sd->right_weapon.addele2[i].flag&wflag&BF_SKILLMASK)) + continue; + ele_fix += sd->right_weapon.addele2[i].rate; + } + for (i = 0; ARRAYLENGTH(sd->left_weapon.addele2) > i && sd->left_weapon.addele2[i].rate != 0; i++){ + if (sd->left_weapon.addele2[i].ele != tstatus->def_ele) continue; + if(!(sd->left_weapon.addele2[i].flag&wflag&BF_WEAPONMASK && + sd->left_weapon.addele2[i].flag&wflag&BF_RANGEMASK && + sd->left_weapon.addele2[i].flag&wflag&BF_SKILLMASK)) + continue; + ele_fix += sd->left_weapon.addele2[i].rate; } - cardfix_=cardfix_*(100+sd->left_weapon.addsize[tstatus->size])/100; - cardfix_=cardfix_*(100+sd->left_weapon.addrace2[t_race2])/100; - cardfix_=cardfix_*(100+sd->left_weapon.addrace[is_boss(target)?RC_BOSS:RC_NONBOSS])/100; + + cardfix = cardfix * (100 + sd->right_weapon.addrace[tstatus->race] + sd->left_weapon.addrace[tstatus->race]) / 100; + cardfix = cardfix * (100 + ele_fix) / 100; + cardfix = cardfix * (100 + sd->right_weapon.addsize[tstatus->size] + sd->left_weapon.addsize[tstatus->size])/100; + cardfix = cardfix * (100 + sd->right_weapon.addrace2[t_race2] + sd->left_weapon.addrace2[t_race2])/100; + cardfix = cardfix * (100 + sd->right_weapon.addrace[is_boss(target)?RC_BOSS:RC_NONBOSS] + sd->left_weapon.addrace[is_boss(target)?RC_BOSS:RC_NONBOSS]) / 100; if( tstatus->race != RC_DEMIHUMAN ) - cardfix_=cardfix_*(100+sd->left_weapon.addrace[RC_NONDEMIHUMAN])/100; + cardfix = cardfix * (100+sd->right_weapon.addrace[RC_NONDEMIHUMAN] + sd->left_weapon.addrace[RC_NONDEMIHUMAN]) / 100; } } - else - { - int ele_fix = sd->right_weapon.addele[tstatus->def_ele] + sd->left_weapon.addele[tstatus->def_ele]; - for (i = 0; ARRAYLENGTH(sd->right_weapon.addele2) > i && sd->right_weapon.addele2[i].rate != 0; i++) { - if (sd->right_weapon.addele2[i].ele != tstatus->def_ele) continue; - if(!(sd->right_weapon.addele2[i].flag&flag&BF_WEAPONMASK && - sd->right_weapon.addele2[i].flag&flag&BF_RANGEMASK && - sd->right_weapon.addele2[i].flag&flag&BF_SKILLMASK)) - continue; - ele_fix += sd->right_weapon.addele2[i].rate; - } - for (i = 0; ARRAYLENGTH(sd->left_weapon.addele2) > i && sd->left_weapon.addele2[i].rate != 0; i++) { - if (sd->left_weapon.addele2[i].ele != tstatus->def_ele) continue; - if(!(sd->left_weapon.addele2[i].flag&flag&BF_WEAPONMASK && - sd->left_weapon.addele2[i].flag&flag&BF_RANGEMASK && - sd->left_weapon.addele2[i].flag&flag&BF_SKILLMASK)) - continue; - ele_fix += sd->left_weapon.addele2[i].rate; + + for( i = 0; i < ARRAYLENGTH(sd->right_weapon.add_dmg) && sd->right_weapon.add_dmg[i].rate; i++ ){ + if( sd->right_weapon.add_dmg[i].class_ == t_class ){ + cardfix = cardfix * (100 + sd->right_weapon.add_dmg[i].rate) / 100; + break; } + } - cardfix=cardfix*(100+sd->right_weapon.addrace[tstatus->race]+sd->left_weapon.addrace[tstatus->race])/100; - cardfix=cardfix*(100+ele_fix)/100; - cardfix=cardfix*(100+sd->right_weapon.addsize[tstatus->size]+sd->left_weapon.addsize[tstatus->size])/100; - cardfix=cardfix*(100+sd->right_weapon.addrace2[t_race2]+sd->left_weapon.addrace2[t_race2])/100; - cardfix=cardfix*(100+sd->right_weapon.addrace[is_boss(target)?RC_BOSS:RC_NONBOSS]+sd->left_weapon.addrace[is_boss(target)?RC_BOSS:RC_NONBOSS])/100; - if( tstatus->race != RC_DEMIHUMAN ) - cardfix=cardfix*(100+sd->right_weapon.addrace[RC_NONDEMIHUMAN]+sd->left_weapon.addrace[RC_NONDEMIHUMAN])/100; + if( cflag&1 ){ + for( i = 0; i < ARRAYLENGTH(sd->left_weapon.add_dmg) && sd->left_weapon.add_dmg[i].rate; i++ ){ + if( sd->left_weapon.add_dmg[i].class_ == t_class ){ + cardfix_ = cardfix_ * (100 + sd->left_weapon.add_dmg[i].rate) / 100; + break; + } + } } +#ifndef RENEWAL + if( wflag&BF_LONG ) + cardfix = cardfix * (100 + sd->bonus.long_attack_atk_rate) / 100; +#endif + if( (cflag&1) && cardfix_ != 1000 ) + damage = damage * cardfix_ / 1000; + else if( cardfix != 1000 ) + damage = damage * cardfix / 1000; } - for( i = 0; i < ARRAYLENGTH(sd->right_weapon.add_dmg) && sd->right_weapon.add_dmg[i].rate; i++ ) - { - if( sd->right_weapon.add_dmg[i].class_ == t_class ) - { - cardfix=cardfix*(100+sd->right_weapon.add_dmg[i].rate)/100; - break; + }else{ + // Target side + if( tsd && !(nk&NK_NO_CARDFIX_DEF) ){ + if( !(nk&NK_NO_ELEFIX) ){ + int ele_fix = tsd->subele[s_ele]; + for (i = 0; ARRAYLENGTH(tsd->subele2) > i && tsd->subele2[i].rate != 0; i++) + { + if(tsd->subele2[i].ele != s_ele) continue; + if(!(tsd->subele2[i].flag&wflag&BF_WEAPONMASK && + tsd->subele2[i].flag&wflag&BF_RANGEMASK && + tsd->subele2[i].flag&wflag&BF_SKILLMASK)) + continue; + ele_fix += tsd->subele2[i].rate; + } + cardfix = cardfix * (100-ele_fix) / 100; + if( cflag&1 && s_ele_ != s_ele ){ + int ele_fix_lh = tsd->subele[s_ele_]; + for (i = 0; ARRAYLENGTH(tsd->subele2) > i && tsd->subele2[i].rate != 0; i++){ + if(tsd->subele2[i].ele != s_ele_) continue; + if(!(tsd->subele2[i].flag&wflag&BF_WEAPONMASK && + tsd->subele2[i].flag&wflag&BF_RANGEMASK && + tsd->subele2[i].flag&wflag&BF_SKILLMASK)) + continue; + ele_fix_lh += tsd->subele2[i].rate; + } + cardfix = cardfix * (100 - ele_fix_lh) / 100; + } } - } - - if( left&1 ) - { - for( i = 0; i < ARRAYLENGTH(sd->left_weapon.add_dmg) && sd->left_weapon.add_dmg[i].rate; i++ ) - { - if( sd->left_weapon.add_dmg[i].class_ == t_class ) + cardfix = cardfix * (100-tsd->subsize[sstatus->size]) / 100; + cardfix = cardfix * (100-tsd->subrace2[s_race2]) / 100; + cardfix = cardfix * (100-tsd->subrace[sstatus->race]) / 100; + cardfix = cardfix * (100-tsd->subrace[is_boss(src)?RC_BOSS:RC_NONBOSS]) / 100; + if( sstatus->race != RC_DEMIHUMAN ) + cardfix = cardfix * (100-tsd->subrace[RC_NONDEMIHUMAN]) / 100; + + for( i = 0; i < ARRAYLENGTH(tsd->add_def) && tsd->add_def[i].rate;i++ ){ + if( tsd->add_def[i].class_ == s_class ) { - cardfix_=cardfix_*(100+sd->left_weapon.add_dmg[i].rate)/100; + cardfix = cardfix * (100 - tsd->add_def[i].rate) / 100; break; } } - } - if( flag&BF_LONG ) - cardfix = cardfix * ( 100 + sd->bonus.long_attack_atk_rate ) / 100; - if( (left&1) && cardfix_ != 1000 ) - damage = damage * cardfix_ / 1000; - else if( cardfix != 1000 ) - damage = damage * cardfix / 1000; + if( wflag&BF_SHORT ) + cardfix = cardfix * (100 - tsd->bonus.near_attack_def_rate) / 100; + else // BF_LONG (there's no other choice) + cardfix = cardfix * (100 - tsd->bonus.long_attack_def_rate) / 100; - }else if( tsd && !(nk&NK_NO_CARDFIX_DEF) ){ - if( !(nk&NK_NO_ELEFIX) ) - { - int ele_fix = tsd->subele[s_ele]; - for (i = 0; ARRAYLENGTH(tsd->subele2) > i && tsd->subele2[i].rate != 0; i++) - { - if(tsd->subele2[i].ele != s_ele) continue; - if(!(tsd->subele2[i].flag&flag&BF_WEAPONMASK && - tsd->subele2[i].flag&flag&BF_RANGEMASK && - tsd->subele2[i].flag&flag&BF_SKILLMASK)) - continue; - ele_fix += tsd->subele2[i].rate; - } - cardfix=cardfix*(100-ele_fix)/100; - if( left&1 && s_ele_ != s_ele ) - { - int ele_fix_lh = tsd->subele[s_ele_]; - for (i = 0; ARRAYLENGTH(tsd->subele2) > i && tsd->subele2[i].rate != 0; i++) - { - if(tsd->subele2[i].ele != s_ele_) continue; - if(!(tsd->subele2[i].flag&flag&BF_WEAPONMASK && - tsd->subele2[i].flag&flag&BF_RANGEMASK && - tsd->subele2[i].flag&flag&BF_SKILLMASK)) - continue; - ele_fix_lh += tsd->subele2[i].rate; - } - cardfix=cardfix*(100-ele_fix_lh)/100; - } - } - cardfix=cardfix*(100-tsd->subsize[sstatus->size])/100; - cardfix=cardfix*(100-tsd->subrace2[s_race2])/100; - cardfix=cardfix*(100-tsd->subrace[sstatus->race])/100; - cardfix=cardfix*(100-tsd->subrace[is_boss(src)?RC_BOSS:RC_NONBOSS])/100; - if( sstatus->race != RC_DEMIHUMAN ) - cardfix=cardfix*(100-tsd->subrace[RC_NONDEMIHUMAN])/100; + if( tsd->sc.data[SC_PROTECT_DEF] ) + cardfix = cardfix * (100 - tsd->sc.data[SC_PROTECT_DEF]->val1) / 100; - for( i = 0; i < ARRAYLENGTH(tsd->add_def) && tsd->add_def[i].rate;i++ ) { - if( tsd->add_def[i].class_ == s_class ) { - cardfix=cardfix*(100-tsd->add_def[i].rate)/100; - break; + if( cardfix != 1000 ) + damage = damage * cardfix / 1000; } } - - if( flag&BF_SHORT ) - cardfix = cardfix * ( 100 - tsd->bonus.near_attack_def_rate ) / 100; - else // BF_LONG (there's no other choice) - cardfix = cardfix * ( 100 - tsd->bonus.long_attack_def_rate ) / 100; - - if( tsd->sc.data[SC_PROTECT_DEF] ) - cardfix = cardfix * ( 100 - tsd->sc.data[SC_PROTECT_DEF]->val1 ) / 100; - - if( cardfix != 1000 ) - damage = damage * cardfix / 1000; - } break; case BF_MISC: if( tsd && !(nk&NK_NO_CARDFIX_DEF) ){ @@ -1120,25 +1160,25 @@ int battle_calc_cardfix(int attack_type, struct block_list *src, struct block_li for (i = 0; ARRAYLENGTH(tsd->subele2) > i && tsd->subele2[i].rate != 0; i++) { if(tsd->subele2[i].ele != s_ele) continue; - if(!(tsd->subele2[i].flag&flag&BF_WEAPONMASK && - tsd->subele2[i].flag&flag&BF_RANGEMASK && - tsd->subele2[i].flag&flag&BF_SKILLMASK)) + if(!(tsd->subele2[i].flag&wflag&BF_WEAPONMASK && + tsd->subele2[i].flag&wflag&BF_RANGEMASK && + tsd->subele2[i].flag&wflag&BF_SKILLMASK)) continue; ele_fix += tsd->subele2[i].rate; } - cardfix=cardfix*(100-ele_fix)/100; + cardfix = cardfix * (100 - ele_fix) / 100; } - cardfix=cardfix*(100-tsd->subsize[sstatus->size])/100; - cardfix=cardfix*(100-tsd->subrace2[s_race2])/100; - cardfix=cardfix*(100-tsd->subrace[sstatus->race])/100; - cardfix=cardfix*(100-tsd->subrace[is_boss(src)?RC_BOSS:RC_NONBOSS])/100; + cardfix = cardfix*(100-tsd->subsize[sstatus->size]) / 100; + cardfix = cardfix*(100-tsd->subrace2[s_race2]) / 100; + cardfix = cardfix*(100-tsd->subrace[sstatus->race]) / 100; + cardfix = cardfix*(100-tsd->subrace[is_boss(src)?RC_BOSS:RC_NONBOSS]) / 100; if( sstatus->race != RC_DEMIHUMAN ) - cardfix=cardfix*(100-tsd->subrace[RC_NONDEMIHUMAN])/100; + cardfix = cardfix * (100 - tsd->subrace[RC_NONDEMIHUMAN]) / 100; cardfix = cardfix * ( 100 - tsd->bonus.misc_def_rate ) / 100; - if( flag&BF_SHORT ) + if( wflag&BF_SHORT ) cardfix = cardfix * ( 100 - tsd->bonus.near_attack_def_rate ) / 100; - else // BF_LONG (there's no other choice) + else // BF_LONG (there's no other choice) cardfix = cardfix * ( 100 - tsd->bonus.long_attack_def_rate ) / 100; if (cardfix != 1000) @@ -1157,7 +1197,7 @@ int battle_calc_cardfix(int attack_type, struct block_list *src, struct block_li * &2 - pdef(Pierce defense) * &4 - tdef(Total defense reduction) *------------------------------------------*/ -int battle_calc_defense(int attack_type, struct block_list *src, struct block_list *target, uint16 skill_id, uint16 skill_lv, int damage, int flag, int pdef){ +int64 battle_calc_defense(int attack_type, struct block_list *src, struct block_list *target, uint16 skill_id, uint16 skill_lv, int64 damage, int flag, int pdef){ struct status_data *sstatus, *tstatus; struct map_session_data *sd, *tsd; struct status_change *sc, *tsc; @@ -1171,10 +1211,10 @@ int battle_calc_defense(int attack_type, struct block_list *src, struct block_li sd = BL_CAST(BL_PC, src); tsd = BL_CAST(BL_PC, target); - sstatus = status_get_status_data(src); - tstatus = status_get_status_data(target); - sc = status_get_sc(src); - tsc = status_get_sc(target); + sstatus = status->get_status_data(src); + tstatus = status->get_status_data(target); + sc = status->get_sc(src); + tsc = status->get_sc(target); switch(attack_type){ case BF_WEAPON: @@ -1183,14 +1223,14 @@ int battle_calc_defense(int attack_type, struct block_list *src, struct block_li * def1 = equip def * def2 = status def **/ - defType def1 = status_get_def(target); //Don't use tstatus->def1 due to skill timer reductions. + defType def1 = status->get_def(target); //Don't use tstatus->def1 due to skill timer reductions. short def2 = tstatus->def2, vit_def; -#ifdef RENEWAL - def1 = status_calc_def2(target, tsc, def1, false); // equip def(RE) - def2 = status_calc_def(target, tsc, def2, false); // status def(RE) +#ifdef RENEWAL + def1 = status->calc_def2(target, tsc, def1, false); // equip def(RE) + def2 = status->calc_def(target, tsc, def2, false); // status def(RE) #else - def1 = status_calc_def(target, tsc, def1, false); // equip def(RE) - def2 = status_calc_def2(target, tsc, def2, false); // status def(RE) + def1 = status->calc_def(target, tsc, def1, false); // equip def(RE) + def2 = status->calc_def2(target, tsc, def2, false); // status def(RE) #endif if( sd ){ @@ -1211,7 +1251,7 @@ int battle_calc_defense(int attack_type, struct block_list *src, struct block_li if( battle_config.vit_penalty_type && battle_config.vit_penalty_target&target->type ) { unsigned char target_count; //256 max targets should be a sane max - target_count = unit_counttargeted(target); + target_count = unit->counttargeted(target); if(target_count >= battle_config.vit_penalty_count) { if(battle_config.vit_penalty_type == 1) { if( !tsc || !tsc->data[SC_STEELBODY] ) @@ -1236,9 +1276,9 @@ int battle_calc_defense(int attack_type, struct block_list *src, struct block_li #else vit_def = def2; #endif - if((battle->check_undead(sstatus->race,sstatus->def_ele) || sstatus->race==RC_DEMON) && //This bonus already doesnt work vs players + if((battle->check_undead(sstatus->race,sstatus->def_ele) || sstatus->race==RC_DEMON) && //This bonus already doesn't work vs players src->type == BL_MOB && (i=pc->checkskill(tsd,AL_DP)) > 0) - vit_def += i*(int)(3 +(tsd->status.base_level+1)*0.04); // submitted by orn + vit_def += i*(int)(3 +(tsd->status.base_level+1)*0.04); // [orn] if( src->type == BL_MOB && (i=pc->checkskill(tsd,RA_RANGERMAIN))>0 && (sstatus->race == RC_BRUTE || sstatus->race == RC_FISH || sstatus->race == RC_PLANT) ) vit_def += i*5; @@ -1260,12 +1300,12 @@ int battle_calc_defense(int attack_type, struct block_list *src, struct block_li #ifdef RENEWAL /** * RE DEF Reduction - * Damage = Attack * (4000+eDEF)/(4000+eDEF*10) - sDEF - * Pierce defence gains 1 atk per def/2 + * Pierce defense gains 1 atk per def/2 **/ - if( def1 == -400 ) /* being hit by a gazillion units, you hit the jackpot and got -400 which creates a division by 0 and subsequently crashes */ - def1 = -399; + if( def1 < -399 ) // it stops at -399 + def1 = 399; // in aegis it set to 1 but in our case it may lead to exploitation so limit it to 399 + //return 1; if( flag&2 ) damage += def1 >> 1; @@ -1274,7 +1314,7 @@ int battle_calc_defense(int attack_type, struct block_list *src, struct block_li if( flag&4 ) damage -= (def1 + vit_def); else - damage = damage * (4000+def1) / (4000+10*def1) - vit_def; + damage = (int)((100.0f - def1 / (def1 + 400.0f) * 90.0f) / 100.0f * damage - vit_def); } #else @@ -1296,11 +1336,11 @@ int battle_calc_defense(int attack_type, struct block_list *src, struct block_li defType mdef = tstatus->mdef; short mdef2= tstatus->mdef2; #ifdef RENEWAL - mdef2 = status_calc_mdef(target, tsc, mdef2, false); // status mdef(RE) - mdef = status_calc_mdef2(target, tsc, mdef, false); // equip mde(RE) + mdef2 = status->calc_mdef(target, tsc, mdef2, false); // status mdef(RE) + mdef = status->calc_mdef2(target, tsc, mdef, false); // equip mde(RE) #else - mdef2 = status_calc_mdef2(target, tsc, mdef2, false); // status mdef(RE) - mdef = status_calc_mdef(target, tsc, mdef, false); // equip mde(RE) + mdef2 = status->calc_mdef2(target, tsc, mdef2, false); // status mdef(RE) + mdef = status->calc_mdef(target, tsc, mdef, false); // equip mde(RE) #endif if( flag&1 ) mdef = 0; @@ -1318,9 +1358,12 @@ int battle_calc_defense(int attack_type, struct block_list *src, struct block_li #ifdef RENEWAL /** * RE MDEF Reduction - * Damage = Magic Attack * (1000+eMDEF)/(1000+eMDEF) - sMDEF **/ - damage = damage * (1000 + mdef) / (1000 + mdef * 10) - mdef2; + if( mdef < -99 ) // it stops at -99 + mdef = 99; // in aegis it set to 1 but in our case it may lead to exploitation so limit it to 99 + //return 1; + + damage = (int)((100.0f - mdef / (mdef + 100.0f) * 90.0f) / 100.0f * damage - mdef2); #else if(battle_config.magic_defense_type) damage = damage - mdef*battle_config.magic_defense_type - mdef2; @@ -1333,23 +1376,37 @@ int battle_calc_defense(int attack_type, struct block_list *src, struct block_li return damage; } +// Minstrel/Wanderer number check for chorus skills. +int battle_calc_chorusbonus(struct map_session_data *sd) { + int members = 0; + + if (!sd || !sd->status.party_id) + return 0; + + members = party->foreachsamemap(party->sub_count_chorus, sd, 0); + + if (members < 3) + return 0; // Bonus remains 0 unless 3 or more Minstrel's/Wanderer's are in the party. + if (members > 7) + return 5; // Maximum effect possible from 7 or more Minstrel's/Wanderer's + return members - 2; // Effect bonus from additional Minstrel's/Wanderer's if not above the max possible +} + int battle_calc_skillratio(int attack_type, struct block_list *src, struct block_list *target, uint16 skill_id, uint16 skill_lv, int skillratio, int flag){ - int i, addedratio; + int i; struct status_change *sc, *tsc; struct map_session_data *sd, *tsd; - struct status_data *status, *tstatus; + struct status_data *st, *tst; nullpo_ret(src); nullpo_ret(target); sd = BL_CAST(BL_PC, src); tsd = BL_CAST(BL_PC, target); - sc = status_get_sc(src); - tsc = status_get_sc(target); - status = status_get_status_data(src); - tstatus = status_get_status_data(target); - - addedratio = skillratio - 100; + sc = status->get_sc(src); + tsc = status->get_sc(target); + st = status->get_status_data(src); + tst = status->get_status_data(target); switch(attack_type){ case BF_MAGIC: @@ -1365,7 +1422,7 @@ int battle_calc_skillratio(int attack_type, struct block_list *src, struct block #endif break; case MG_SOULSTRIKE: - if (battle->check_undead(tstatus->race,tstatus->def_ele)) + if (battle->check_undead(tst->race,tst->def_ele)) skillratio += 5*skill_lv; break; case MG_FIREWALL: @@ -1412,13 +1469,13 @@ int battle_calc_skillratio(int attack_type, struct block_list *src, struct block skillratio += 10 * skill_lv - 30; break; case SL_STIN: - skillratio += (tstatus->size!=SZ_SMALL?-99:10*skill_lv); //target size must be small (0) for full damage. + skillratio += (tst->size!=SZ_SMALL?-99:10*skill_lv); //target size must be small (0) for full damage. break; case SL_STUN: - skillratio += (tstatus->size!=SZ_BIG?5*skill_lv:-99); //Full damage is dealt on small/medium targets + skillratio += (tst->size!=SZ_BIG?5*skill_lv:-99); //Full damage is dealt on small/medium targets break; case SL_SMA: - skillratio += -60 + status_get_lv(src); //Base damage is 40% + lv% + skillratio += -60 + status->get_lv(src); //Base damage is 40% + lv% break; case NJ_KOUENKA: skillratio -= 10; @@ -1471,25 +1528,24 @@ int battle_calc_skillratio(int attack_type, struct block_list *src, struct block * Arch Bishop **/ case AB_JUDEX: - skillratio += 180 + 20 * skill_lv; - if (skill_lv > 4) skillratio += 20; + skillratio = 300 + 20 * skill_lv; RE_LVL_DMOD(100); break; case AB_ADORAMUS: - skillratio += 400 + 100 * skill_lv; + skillratio = 500 + 100 * skill_lv; RE_LVL_DMOD(100); break; case AB_DUPLELIGHT_MAGIC: - skillratio += 100 + 20 * skill_lv; + skillratio = 200 + 20 * skill_lv; break; /** * Warlock **/ - case WL_SOULEXPANSION: // MATK [{( Skill Level + 4 ) x 100 ) + ( Caster?s INT )} x ( Caster?s Base Level / 100 )] % - skillratio += 300 + 100 * skill_lv + status_get_int(src); + case WL_SOULEXPANSION: // MATK [{( Skill Level + 4 ) x 100 ) + ( Caster's INT )} x ( Caster's Base Level / 100 )] % + skillratio = 100 * (skill_lv + 4) + st->int_; RE_LVL_DMOD(100); break; - case WL_FROSTMISTY: // MATK [{( Skill Level x 100 ) + 200 } x ( Caster痴 Base Level / 100 )] % + case WL_FROSTMISTY: // MATK [{( Skill Level x 100 ) + 200 } x ( Caster's Base Level / 100 )] % skillratio += 100 + 100 * skill_lv; RE_LVL_DMOD(100); break; @@ -1532,14 +1588,14 @@ int battle_calc_skillratio(int attack_type, struct block_list *src, struct block if( sd && sd->status.party_id ){ struct map_session_data* psd; - int static p_sd[5] = {0, 0, 0, 0, 0}, c; // just limit it to 5 + int p_sd[5] = {0, 0, 0, 0, 0}, c; // just limit it to 5 c = 0; memset (p_sd, 0, sizeof(p_sd)); - party_foreachsamemap(skill->check_condition_char_sub, sd, 3, &sd->bl, &c, &p_sd, skill_id); - c = ( c > 1 ? rand()%c : 0 ); + party->foreachsamemap(skill->check_condition_char_sub, sd, 3, &sd->bl, &c, &p_sd, skill_id); + c = ( c > 1 ? rnd()%c : 0 ); - if( (psd = iMap->id2sd(p_sd[c])) && pc->checkskill(psd,WL_COMET) > 0 ){ + if( (psd = map->id2sd(p_sd[c])) && pc->checkskill(psd,WL_COMET) > 0 ){ skillratio = skill_lv * 400; //MATK [{( Skill Level x 400 ) x ( Caster's Base Level / 120 )} + 2500 ] % RE_LVL_DMOD(120); skillratio += 2500; @@ -1554,7 +1610,7 @@ int battle_calc_skillratio(int attack_type, struct block_list *src, struct block skillratio += 100 * flag; break; case WL_EARTHSTRAIN: - skillratio += 1900 + 100 * skill_lv; + skillratio = 2000 + 100 * skill_lv; RE_LVL_DMOD(100); break; case WL_TETRAVORTEX_FIRE: @@ -1567,107 +1623,91 @@ int battle_calc_skillratio(int attack_type, struct block_list *src, struct block case WL_SUMMON_ATK_WATER: case WL_SUMMON_ATK_WIND: case WL_SUMMON_ATK_GROUND: - skillratio = skill_lv * (status_get_lv(src) + ( sd ? sd->status.job_level : 50 ));// This is close to official, but lacking a little info to finalize. [Rytech] + skillratio = (1 + skill_lv) / 2 * (status->get_lv(src) + (sd ? sd->status.job_level : 50)); RE_LVL_DMOD(100); break; case LG_RAYOFGENESIS: { - int16 lv = skill_lv; + uint16 lv = skill_lv; int bandingBonus = 0; if( sc && sc->data[SC_BANDING] ) bandingBonus = 200 * (sd ? skill->check_pc_partner(sd,skill_id,&lv,skill->get_splash(skill_id,skill_lv),0) : 1); skillratio = ((300 * skill_lv) + bandingBonus) * (sd ? sd->status.job_level : 1) / 25; } - break; - case LG_SHIELDSPELL:// [(Casters Base Level x 4) + (Shield MDEF x 100) + (Casters INT x 2)] % - if( sd ) { - skillratio = status_get_lv(src) * 4 + sd->bonus.shieldmdef * 100 + status_get_int(src) * 2; - } else - skillratio += 1900; //2000% break; - case WM_METALICSOUND: - skillratio += 120 * skill_lv + 60 * ( sd? pc->checkskill(sd, WM_LESSON) : 10 ) - 100; + case LG_SHIELDSPELL: + if ( sd && skill_lv == 2 ) // [(Casters Base Level x 4) + (Shield MDEF x 100) + (Casters INT x 2)] % + skillratio = 4 * status->get_lv(src) + 100 * sd->bonus.shieldmdef + 2 * st->int_; + else + skillratio = 0; break; - /*case WM_SEVERE_RAINSTORM: - skillratio += 50 * skill_lv; + case WM_METALICSOUND: + skillratio = 120 * skill_lv + 60 * ( sd? pc->checkskill(sd, WM_LESSON) : 10 ); + RE_LVL_DMOD(100); break; - - WM_SEVERE_RAINSTORM just set a unit place, - refer to WM_SEVERE_RAINSTORM_MELEE to set the formula. - */ case WM_REVERBERATION_MAGIC: - // MATK [{(Skill Level x 100) + 100} x Casters Base Level / 100] % - skillratio += 100 * (sd ? pc->checkskill(sd, WM_REVERBERATION) : 1); + skillratio = 100 * skill_lv + 100; RE_LVL_DMOD(100); break; case SO_FIREWALK: - skillratio = 300; + skillratio = 60 * skill_lv; RE_LVL_DMOD(100); if( sc && sc->data[SC_HEATER_OPTION] ) - skillratio += sc->data[SC_HEATER_OPTION]->val3; + skillratio += sc->data[SC_HEATER_OPTION]->val3 / 2; break; case SO_ELECTRICWALK: - skillratio = 300; + skillratio = 60 * skill_lv; RE_LVL_DMOD(100); if( sc && sc->data[SC_BLAST_OPTION] ) - skillratio += sd ? sd->status.job_level / 2 : 0; + skillratio += sc->data[SC_BLAST_OPTION]->val2 / 2; break; case SO_EARTHGRAVE: - skillratio = ( 200 * ( sd ? pc->checkskill(sd, SA_SEISMICWEAPON) : 10 ) + status_get_int(src) * skill_lv ); + skillratio = st->int_ * skill_lv + 200 * (sd ? pc->checkskill(sd,SA_SEISMICWEAPON) : 1); RE_LVL_DMOD(100); if( sc && sc->data[SC_CURSED_SOIL_OPTION] ) - skillratio += sc->data[SC_CURSED_SOIL_OPTION]->val2; + skillratio += sc->data[SC_CURSED_SOIL_OPTION]->val3 * 5; break; case SO_DIAMONDDUST: - skillratio = ( 200 * ( sd ? pc->checkskill(sd, SA_FROSTWEAPON) : 10 ) + status_get_int(src) * skill_lv ); - RE_LVL_DMOD(100); + skillratio = (st->int_ * skill_lv + 200 * (sd ? pc->checkskill(sd, SA_FROSTWEAPON) : 1)) * status->get_lv(src) / 100; if( sc && sc->data[SC_COOLER_OPTION] ) - skillratio += sc->data[SC_COOLER_OPTION]->val3; + skillratio += sc->data[SC_COOLER_OPTION]->val3 * 5; break; case SO_POISON_BUSTER: - skillratio += 1100 + 300 * skill_lv; + skillratio += 900 + 300 * skill_lv; + RE_LVL_DMOD(100); if( sc && sc->data[SC_CURSED_SOIL_OPTION] ) - skillratio += sc->data[SC_CURSED_SOIL_OPTION]->val2; + skillratio += sc->data[SC_CURSED_SOIL_OPTION]->val3 * 5; break; case SO_PSYCHIC_WAVE: - skillratio += -100 + skill_lv * 70 + (status_get_int(src) * 3); + skillratio = 70 * skill_lv + 3 * st->int_; RE_LVL_DMOD(100); - if( sc ){ - if( sc->data[SC_HEATER_OPTION] ) - skillratio += sc->data[SC_HEATER_OPTION]->val3; - else if(sc->data[SC_COOLER_OPTION] ) - skillratio += sc->data[SC_COOLER_OPTION]->val3; - else if(sc->data[SC_BLAST_OPTION] ) - skillratio += sc->data[SC_BLAST_OPTION]->val2; - else if(sc->data[SC_CURSED_SOIL_OPTION] ) - skillratio += sc->data[SC_CURSED_SOIL_OPTION]->val3; - } + if( sc && ( sc->data[SC_HEATER_OPTION] || sc->data[SC_COOLER_OPTION] + || sc->data[SC_BLAST_OPTION] || sc->data[SC_CURSED_SOIL_OPTION] ) ) + skillratio += skillratio * 20 / 100; break; - case SO_VARETYR_SPEAR: //MATK [{( Endow Tornado skill level x 50 ) + ( Caster INT x Varetyr Spear Skill level )} x Caster Base Level / 100 ] % + case SO_VARETYR_SPEAR: skillratio = status_get_int(src) * skill_lv + ( sd ? pc->checkskill(sd, SA_LIGHTNINGLOADER) * 50 : 0 ); RE_LVL_DMOD(100); if( sc && sc->data[SC_BLAST_OPTION] ) - skillratio += sd ? sd->status.job_level * 5 : 0; + skillratio += sc->data[SC_BLAST_OPTION]->val2 * 5; break; case SO_CLOUD_KILL: - skillratio += -100 + skill_lv * 40; + skillratio = 40 * skill_lv; RE_LVL_DMOD(100); if( sc && sc->data[SC_CURSED_SOIL_OPTION] ) - skillratio += sc->data[SC_CURSED_SOIL_OPTION]->val2; - break; - case GN_DEMONIC_FIRE: - if( skill_lv > 20) - { // Fire expansion Lv.2 - skillratio += 110 + 20 * (skill_lv - 20) + status_get_int(src) * 3; // Need official INT bonus. [LimitLine] - } - else if( skill_lv > 10 ) - { // Fire expansion Lv.1 - skillratio += 110 + 20 * (skill_lv - 10) / 2; + skillratio += sc->data[SC_CURSED_SOIL_OPTION]->val3; + break; + case GN_DEMONIC_FIRE: { + int fire_expansion_lv = skill_lv / 100; + skill_lv = skill_lv % 100; + skillratio = 110 + 20 * skill_lv; + if ( fire_expansion_lv == 1 ) + skillratio += status_get_int(src) + (sd?sd->status.job_level:50); + else if ( fire_expansion_lv == 2 ) + skillratio += status_get_int(src) * 10; } - else - skillratio += 110 + 20 * skill_lv; break; - // Magical Elemental Spirits Attack Skills + // Magical Elemental Spirits Attack Skills case EL_FIRE_MANTLE: case EL_WATER_SCREW: skillratio += 900; @@ -1686,9 +1726,7 @@ int battle_calc_skillratio(int attack_type, struct block_list *src, struct block skillratio += 1100; break; case MH_ERASER_CUTTER: - if(skill_lv%2) skillratio += 400; //600:800:1000 - else skillratio += 700; //1000:1200 - skillratio += 100 * skill_lv; + skillratio += 400 + 100 * skill_lv + (skill_lv%2 > 0 ? 0 : 300); break; case MH_XENO_SLASHER: if(skill_lv%2) skillratio += 350 + 50 * skill_lv; //500:600:700 @@ -1788,7 +1826,7 @@ int battle_calc_skillratio(int attack_type, struct block_list *src, struct block skillratio += 30 * skill_lv; break; case AS_SONICBLOW: - skillratio += -50 + 5 * skill_lv; + skillratio += 300 + 40 * skill_lv; break; case TF_SPRINKLESAND: skillratio += 30; @@ -1866,7 +1904,7 @@ int battle_calc_skillratio(int attack_type, struct block_list *src, struct block #ifndef RENEWAL case MO_EXTREMITYFIST: { //Overflow check. [Skotlex] - unsigned int ratio = skillratio + 100*(8 + status->sp/10); + unsigned int ratio = skillratio + 100*(8 + st->sp/10); //You'd need something like 6K SP to reach this max, so should be fine for most purposes. if (ratio > 60000) ratio = 60000; //We leave some room here in case skillratio gets further increased. skillratio = (unsigned short)ratio; @@ -1922,8 +1960,12 @@ int battle_calc_skillratio(int attack_type, struct block_list *src, struct block #ifndef RENEWAL case ASC_BREAKER: skillratio += 100*skill_lv-100; - break; + #else + case LK_SPIRALPIERCE: + case ML_SPIRALPIERCE: + skillratio += 50 * skill_lv; #endif + break; case PA_SACRIFICE: skillratio += 10 * skill_lv - 10; break; @@ -1954,10 +1996,9 @@ int battle_calc_skillratio(int attack_type, struct block_list *src, struct block case TK_JUMPKICK: skillratio += -70 + 10*skill_lv; if (sc && sc->data[SC_COMBOATTACK] && sc->data[SC_COMBOATTACK]->val1 == skill_id) - skillratio += 10 * status_get_lv(src) / 3; //Tumble bonus - if (flag) - { - skillratio += 10 * status_get_lv(src) / 3; //Running bonus (TODO: What is the real bonus?) + skillratio += 10 * status->get_lv(src) / 3; //Tumble bonus + if (flag) { + skillratio += 10 * status->get_lv(src) / 3; //Running bonus (TODO: What is the real bonus?) if( sc && sc->data[SC_STRUP] ) // Spurt bonus skillratio *= 2; } @@ -1966,16 +2007,21 @@ int battle_calc_skillratio(int attack_type, struct block_list *src, struct block skillratio += 50 * skill_lv; break; case GS_BULLSEYE: - //Only works well against brute/demihumans non bosses. - if((tstatus->race == RC_BRUTE || tstatus->race == RC_DEMIHUMAN) - && !(tstatus->mode&MD_BOSS)) + //Only works well against brute/demi-humans non bosses. + if((tst->race == RC_BRUTE || tst->race == RC_DEMIHUMAN) + && !(tst->mode&MD_BOSS)) skillratio += 400; break; case GS_TRACKING: skillratio += 100 * (skill_lv+1); break; case GS_PIERCINGSHOT: - skillratio += 20 * skill_lv; +#ifdef RENEWAL + if( sd && sd->weapontype1 == W_RIFLE ) + skillratio += 50 + 30 * skill_lv; + else +#endif + skillratio += 20 * skill_lv; break; case GS_RAPIDSHOWER: skillratio += 10 * skill_lv; @@ -2008,6 +2054,11 @@ int battle_calc_skillratio(int attack_type, struct block_list *src, struct block case NJ_KIRIKAGE: skillratio += 100 * (skill_lv-1); break; +#ifdef RENEWAL + case NJ_KUNAI: + skillratio += 50 + 150 * skill_lv; + break; +#endif case KN_CHARGEATK: { int k = (flag-1)/3; //+100% every 3 cells of distance @@ -2031,8 +2082,8 @@ int battle_calc_skillratio(int attack_type, struct block_list *src, struct block skillratio += ((skill_lv-1)%5+1) * 100; break; case RK_SONICWAVE: - skillratio += -100 + 100 * (skill_lv + 5); - skillratio = skillratio * (100 + (status_get_lv(src)-100) / 2) / 100; + skillratio = (skill_lv + 5) * 100; + skillratio = skillratio * (100 + (status->get_lv(src)-100) / 2) / 100; break; case RK_HUNDREDSPEAR: skillratio += 500 + (80 * skill_lv); @@ -2041,43 +2092,34 @@ int battle_calc_skillratio(int attack_type, struct block_list *src, struct block if( index >= 0 && sd->inventory_data[index] && sd->inventory_data[index]->type == IT_WEAPON ) skillratio += (10000 - min(10000, sd->inventory_data[index]->weight)) / 10; - skillratio = skillratio * (100 + (status_get_lv(src)-100) / 2) / 100 + 50 * pc->checkskill(sd,LK_SPIRALPIERCE); + skillratio = skillratio * (100 + (status->get_lv(src)-100) / 2) / 100 + 50 * pc->checkskill(sd,LK_SPIRALPIERCE); } break; case RK_WINDCUTTER: - skillratio += -100 + 50 * (skill_lv + 2); + skillratio = (skill_lv + 2) * 50; RE_LVL_DMOD(100); break; case RK_IGNITIONBREAK: - i = distance_bl(src,target); - if( i < 2 ) - skillratio += 300 * skill_lv; - else if( i < 4 ) - skillratio += 250 * skill_lv; - else - skillratio += 200 * skill_lv; - skillratio = (skillratio - 100) * (100 + (status_get_lv(src)-100)) / 100; - if( status->rhw.ele == ELE_FIRE ) - skillratio += 100 * skill_lv; - break; - case RK_CRUSHSTRIKE: - if( sd ) - {//ATK [{Weapon Level * (Weapon Upgrade Level + 6) * 100} + (Weapon ATK) + (Weapon Weight)]% - short index = sd->equip_index[EQI_HAND_R]; - if( index >= 0 && sd->inventory_data[index] && sd->inventory_data[index]->type == IT_WEAPON ) - skillratio += -100 + sd->inventory_data[index]->weight/10 + status->rhw.atk + - 100 * sd->inventory_data[index]->wlv * (sd->status.inventory[index].refine + 6); - } + i = distance_bl(src,target); + if( i < 2 ) + skillratio = 300 * skill_lv; + else if( i < 4 ) + skillratio = 250 * skill_lv; + else + skillratio = 200 * skill_lv; + skillratio = skillratio * status->get_lv(src) / 100; + if( st->rhw.ele == ELE_FIRE ) + skillratio += 100 * skill_lv; break; case RK_STORMBLAST: - skillratio += -100 + 100 * (sd ? pc->checkskill(sd,RK_RUNEMASTERY) : 1) + 100 * (status_get_int(src) / 4); + skillratio = ((sd ? pc->checkskill(sd,RK_RUNEMASTERY) : 1) + status_get_int(src) / 8) * 100; break; case RK_PHANTOMTHRUST: - skillratio += -100 + 50 * skill_lv + 10 * ( sd ? pc->checkskill(sd,KN_SPEARMASTERY) : 10); + skillratio = 50 * skill_lv + 10 * (sd ? pc->checkskill(sd,KN_SPEARMASTERY) : 10); RE_LVL_DMOD(150); break; /** - * GC Guilotine Cross + * GC Guillotine Cross **/ case GC_CROSSIMPACT: skillratio += 900 + 100 * skill_lv; @@ -2090,10 +2132,9 @@ int battle_calc_skillratio(int attack_type, struct block_list *src, struct block //ATK [{(Skill Level x 100) + 300} x Caster's Base Level / 120]% + ATK [(AGI x 2) + (Caster's Job Level x 4)]% skillratio += 200 + (100 * skill_lv); RE_LVL_DMOD(120); - skillratio += status_get_agi(src) * 2 + (sd?sd->status.job_level:0) * 4; break; case GC_ROLLINGCUTTER: - skillratio += -50 + 50 * skill_lv; + skillratio = 50 + 50 * skill_lv; RE_LVL_DMOD(100); break; case GC_CROSSRIPPERSLASHER: @@ -2126,127 +2167,142 @@ int battle_calc_skillratio(int attack_type, struct block_list *src, struct block skillratio += 100 + 100 * skill_lv; break; case RA_WUGDASH:// ATK 300% - skillratio += 200; + skillratio = 300; + if( sc && sc->data[SC_DANCE_WITH_WUG] ) + skillratio += 10 * sc->data[SC_DANCE_WITH_WUG]->val1 * (2 + battle->calc_chorusbonus(sd)); break; case RA_WUGSTRIKE: - skillratio += -100 + 200 * skill_lv; + skillratio = 200 * skill_lv; + if( sc && sc->data[SC_DANCE_WITH_WUG] ) + skillratio += 10 * sc->data[SC_DANCE_WITH_WUG]->val1 * (2 + battle->calc_chorusbonus(sd)); break; case RA_WUGBITE: skillratio += 300 + 200 * skill_lv; if ( skill_lv == 5 ) skillratio += 100; break; case RA_SENSITIVEKEEN: - skillratio += 50 * skill_lv; + skillratio = 150 * skill_lv; break; /** * Mechanic **/ case NC_BOOSTKNUCKLE: - skillratio += 100 + 100 * skill_lv + status_get_dex(src); - RE_LVL_DMOD(100); + skillratio = skill_lv * 100 + 200 + st->dex; + RE_LVL_DMOD(120); break; case NC_PILEBUNKER: - skillratio += 200 + 100 * skill_lv + status_get_str(src); + skillratio = skill_lv*100 + 300 + status_get_str(src); RE_LVL_DMOD(100); break; case NC_VULCANARM: - skillratio += -100 + 70 * skill_lv + status_get_dex(src); + skillratio = 70 * skill_lv + status_get_dex(src); RE_LVL_DMOD(100); break; case NC_FLAMELAUNCHER: case NC_COLDSLOWER: - skillratio += 200 + 300 * skill_lv; + skillratio += 200 + 100 * skill_lv + status_get_str(src); RE_LVL_DMOD(100); break; case NC_ARMSCANNON: - switch( tstatus->size ) { - case SZ_SMALL: skillratio += 100 + 500 * skill_lv; break;// Small - case SZ_MEDIUM: skillratio += 100 + 400 * skill_lv; break;// Medium - case SZ_BIG: skillratio += 100 + 300 * skill_lv; break;// Large + switch( tst->size ) { + case SZ_MEDIUM: skillratio = 300 + 350 * skill_lv; break; // Medium + case SZ_SMALL: skillratio = 300 + 400 * skill_lv; break; // Small + case SZ_BIG: skillratio = 300 + 300 * skill_lv; break; // Large } - RE_LVL_DMOD(100); - //NOTE: Their's some other factors that affects damage, but not sure how exactly. Will recheck one day. [Rytech] + RE_LVL_DMOD(120); break; case NC_AXEBOOMERANG: - skillratio += 60 + 40 * skill_lv; + skillratio = 250 + 50 * skill_lv; if( sd ) { short index = sd->equip_index[EQI_HAND_R]; if( index >= 0 && sd->inventory_data[index] && sd->inventory_data[index]->type == IT_WEAPON ) - skillratio += sd->inventory_data[index]->weight / 10;// Weight is divided by 10 since 10 weight in coding make 1 whole actural weight. [Rytech] + skillratio += sd->inventory_data[index]->weight / 10; } RE_LVL_DMOD(100); break; case NC_POWERSWING: - skillratio += 80 + 20 * skill_lv + status_get_str(src) + status_get_dex(src); - RE_LVL_DMOD(100); + skillratio = 300 + 100*skill_lv + ( status_get_str(src)+status_get_dex(src) ) * status->get_lv(src) / 100; break; case NC_AXETORNADO: - skillratio += 100 + 100 * skill_lv + status_get_vit(src); + skillratio = 200 + 100 * skill_lv + st->vit; RE_LVL_DMOD(100); + if( st->rhw.ele == ELE_WIND ) + skillratio = skillratio * 125 / 100; + if ( distance_bl(src, target) > 2 ) // Will deal 75% damage outside of 5x5 area. + skillratio = skillratio * 75 / 100; break; case SC_FATALMENACE: - skillratio += 100 * skill_lv; + skillratio = 100 * (skill_lv+1) * status->get_lv(src) / 100; break; case SC_TRIANGLESHOT: - skillratio += 270 + 30 * skill_lv; + skillratio = ( 300 + (skill_lv-1) * status_get_agi(src)/2 ) * status->get_lv(src) / 120; break; case SC_FEINTBOMB: - skillratio += 100 + 100 * skill_lv; + skillratio = (skill_lv+1) * (st->dex/2) * (sd?sd->status.job_level:50)/10 * status->get_lv(src) / 120; break; - case LG_CANNONSPEAR:// Stimated formula. Still need confirm it. - skillratio += -100 + (50 + status_get_str(src)) * skill_lv; + case LG_CANNONSPEAR: + skillratio = (50 + st->str) * skill_lv; RE_LVL_DMOD(100); break; case LG_BANISHINGPOINT: - skillratio += -100 + ((50 * skill_lv) + (30 * ((sd)?pc->checkskill(sd,SM_BASH):1))); + skillratio = 50 * skill_lv + 30 * (sd ? pc->checkskill(sd,SM_BASH) : 10); RE_LVL_DMOD(100); break; case LG_SHIELDPRESS: - skillratio += 60 + 43 * skill_lv; + skillratio = 150 * skill_lv + st->str; + if( sd ) { + short index = sd->equip_index[EQI_HAND_L]; + if( index >= 0 && sd->inventory_data[index] && sd->inventory_data[index]->type == IT_ARMOR ) + skillratio += sd->inventory_data[index]->weight / 10; + } RE_LVL_DMOD(100); break; case LG_PINPOINTATTACK: - skillratio += -100 + ((100 * skill_lv) + (10 * status_get_agi(src)) ); - RE_LVL_DMOD(100); + skillratio = 100 * skill_lv + 5 * st->agi; + RE_LVL_DMOD(120); break; case LG_RAGEBURST: - if( sd && sd->spiritball_old ) - skillratio += -100 + (sd->spiritball_old * 200); - else - skillratio += -100 + 15 * 200; + if( sc ){ + skillratio += -100 + (status_get_max_hp(src) - status_get_hp(src)) / 100 + sc->fv_counter * 200; + clif->millenniumshield(src, (sc->fv_counter = 0)); + } RE_LVL_DMOD(100); break; - case LG_SHIELDSPELL:// [(Casters Base Level x 4) + (Shield DEF x 10) + (Casters VIT x 2)] % - if( sd ) { + case LG_SHIELDSPELL: + if ( sd && skill_lv == 1 ) { struct item_data *shield_data = sd->inventory_data[sd->equip_index[EQI_HAND_L]]; - skillratio += -100 + status_get_lv(src) * 4 + status_get_vit(src) * 2; if( shield_data ) - skillratio += shield_data->def * 10; - } else - skillratio += 2400; //2500% + skillratio = 4 * status->get_lv(src) + 10 * shield_data->def + 2 * st->vit; + } + else + skillratio = 0; // Prevents ATK damage from being done on LV 2 usage since LV 2 us MATK. [Rytech] break; case LG_MOONSLASHER: - skillratio += -100 + (120 * skill_lv + ((sd) ? pc->checkskill(sd,LG_OVERBRAND) : 5) * 80); + skillratio = 120 * skill_lv + 80 * (sd ? pc->checkskill(sd,LG_OVERBRAND) : 5); RE_LVL_DMOD(100); break; case LG_OVERBRAND: - skillratio += -100 + 400 * skill_lv + (pc->checkskill(sd,CR_SPEARQUICKEN) * 30); - RE_LVL_DMOD(100); + skillratio += -100 + 50 * (((sd) ? pc->checkskill(sd,CR_SPEARQUICKEN) : 1) + 8 * skill_lv); + RE_LVL_DMOD(150); break; case LG_OVERBRAND_BRANDISH: - skillratio += -100 + 300 * skill_lv + (2 * (status_get_str(src) + status_get_dex(src)) / 3); - RE_LVL_DMOD(100); + skillratio += -100 + 300 * skill_lv + status_get_str(src) + status_get_dex(src); + RE_LVL_DMOD(150); break; case LG_OVERBRAND_PLUSATK: - skillratio += -100 + 150 * skill_lv; + skillratio += -100 + 100 * skill_lv; RE_LVL_DMOD(100); break; case LG_RAYOFGENESIS: - skillratio += 200 + 300 * skill_lv; + skillratio = 300 + 300 * skill_lv; RE_LVL_DMOD(100); break; case LG_EARTHDRIVE: - skillratio = (skillratio + 100) * skill_lv; + if( sd ) { + short index = sd->equip_index[EQI_HAND_L]; + if( index >= 0 && sd->inventory_data[index] && sd->inventory_data[index]->type == IT_ARMOR ) + skillratio = (1 + skill_lv) * sd->inventory_data[index]->weight / 10; + } RE_LVL_DMOD(100); break; case LG_HESPERUSLIT: @@ -2284,7 +2340,7 @@ int battle_calc_skillratio(int attack_type, struct block_list *src, struct block int hp = status_get_max_hp(src) * (10 + 2 * skill_lv) / 100, sp = status_get_max_sp(src) * (6 + skill_lv) / 100; if( sc && sc->data[SC_COMBOATTACK] && sc->data[SC_COMBOATTACK]->val1 == SR_FALLENEMPIRE ) // ATK [((Caster consumed HP + SP) / 2) x Caster Base Level / 100] % - skillratio += -100 + hp+sp / 2; + skillratio += -100 + (hp+sp) / 2; else skillratio += -100 + (hp+sp) / 4; RE_LVL_DMOD(100); @@ -2292,15 +2348,17 @@ int battle_calc_skillratio(int attack_type, struct block_list *src, struct block break; case SR_RAMPAGEBLASTER: skillratio += 20 * skill_lv * (sd?sd->spiritball_old:5) - 100; - if( sc && sc->data[SC_EXPLOSIONSPIRITS] ){ + if( sc && sc->data[SC_EXPLOSIONSPIRITS] ) { skillratio += sc->data[SC_EXPLOSIONSPIRITS]->val1 * 20; RE_LVL_DMOD(120); - }else + } else { RE_LVL_DMOD(150); + } break; case SR_KNUCKLEARROW: - if( flag&4 ){ // ATK [(Skill Level x 150) + (1000 x Target current weight / Maximum weight) + (Target Base Level x 5) x (Caster Base Level / 150)] % - skillratio += -100 + 150 * skill_lv + status_get_lv(target) * 5 * (status_get_lv(src) / 100) ; + if ( flag&4 || map->list[src->m].flag.gvg_castle || tst->mode&MD_BOSS ) { + // ATK [(Skill Level x 150) + (1000 x Target current weight / Maximum weight) + (Target Base Level x 5) x (Caster Base Level / 150)] % + skillratio = 150 * skill_lv + status->get_lv(target) * 5 * (status->get_lv(src) / 100) ; if( tsd && tsd->weight ) skillratio += 100 * (tsd->weight / tsd->max_weight); }else // ATK [(Skill Level x 100 + 500) x Caster Base Level / 100] % @@ -2308,7 +2366,7 @@ int battle_calc_skillratio(int attack_type, struct block_list *src, struct block RE_LVL_DMOD(100); break; case SR_WINDMILL: // ATK [(Caster Base Level + Caster DEX) x Caster Base Level / 100] % - skillratio += -100 + status_get_lv(src) + status_get_dex(src); + skillratio = status->get_lv(src) + status_get_dex(src); RE_LVL_DMOD(100); break; case SR_GATEOFHELL: @@ -2328,74 +2386,77 @@ int battle_calc_skillratio(int attack_type, struct block_list *src, struct block RE_LVL_DMOD(150); break; case SR_RIDEINLIGHTNING: // ATK [{(Skill Level x 200) + Additional Damage} x Caster Base Level / 100] % - if( (status->rhw.ele) == ELE_WIND || (status->lhw.ele) == ELE_WIND ) + if( (st->rhw.ele) == ELE_WIND || (st->lhw.ele) == ELE_WIND ) skillratio += skill_lv * 50; skillratio += -100 + 200 * skill_lv; RE_LVL_DMOD(100); break; case WM_REVERBERATION_MELEE: - // ATK [{(Skill Level x 100) + 300} x Caster Base Level / 100] - skillratio += 200 + 100 * pc->checkskill(sd, WM_REVERBERATION); + skillratio += 200 + 100 * skill_lv; RE_LVL_DMOD(100); break; case WM_SEVERE_RAINSTORM_MELEE: - //ATK [{(Caster DEX + AGI) x (Skill Level / 5)} x Caster Base Level / 100] % - skillratio += -100 + (status_get_dex(src) + status_get_agi(src)) * (skill_lv * 2); + skillratio = (st->agi + st->dex) * skill_lv / 5; RE_LVL_DMOD(100); - skillratio /= 10; break; case WM_GREAT_ECHO: - skillratio += 800 + 100 * skill_lv; - if( sd ) { // Still need official value [pakpil] - short lv = (short)skill_lv; - skillratio += 100 * skill->check_pc_partner(sd,skill_id,&lv,skill->get_splash(skill_id,skill_lv),0); - } - break; - case WM_SOUND_OF_DESTRUCTION: - skillratio += 400; + { + int chorusbonus = battle->calc_chorusbonus(sd); + skillratio += 300 + 200 * skill_lv; + //Chorus bonus don't count the first 2 Minstrel's/Wanderer's and only increases when their's 3 or more. [Rytech] + if (chorusbonus >= 1 && chorusbonus <= 5) + skillratio += 100<<(chorusbonus-1); // 1->100; 2->200; 3->400; 4->800; 5->1600 + RE_LVL_DMOD(100); + } break; case GN_CART_TORNADO: - // ATK [( Skill Level x 50 ) + ( Cart Weight / ( 150 - Caster Base STR ))] + ( Cart Remodeling Skill Level x 50 )] % - skillratio += -100 + 50 * skill_lv; - if( sd && sd->cart_weight) - skillratio += sd->cart_weight/10 / max(150-status_get_str(src),1) + pc->checkskill(sd, GN_REMODELING_CART) * 50; + { + int strbonus = st->str; // FIXME Supposed to take only base STR, but current code wont allow that. So well just take STR for now. [Rytech] + if ( strbonus > 130 ) // Max base stat limit on official is 130. So well allow no higher then 125 STR here. This limit prevents + strbonus = 130; // the division from going any lower then 30 so the server wont divide by 0 if someone has 150 STR. + skillratio = 50 * skill_lv + (sd ? sd->cart_weight : battle_config.max_cart_weight) / 10 / (150 - strbonus) + 50 * (sd ? pc->checkskill(sd, GN_REMODELING_CART) : 5); + } break; case GN_CARTCANNON: - // ATK [{( Cart Remodeling Skill Level x 50 ) x ( INT / 40 )} + ( Cart Cannon Skill Level x 60 )] % - skillratio += -100 + 60 * skill_lv; - if( sd ) skillratio += pc->checkskill(sd, GN_REMODELING_CART) * 50 * (status_get_int(src) / 40); + skillratio = 50 * (sd ? pc->checkskill(sd, GN_REMODELING_CART) : 5) * (st->int_ / 40) + 60 * skill_lv; break; case GN_SPORE_EXPLOSION: - skillratio += 200 + 100 * skill_lv; - break; + skillratio = 100 * skill_lv + (200 + st->int_) * status->get_lv(src) / 100; case GN_CRAZYWEED_ATK: skillratio += 400 + 100 * skill_lv; break; case GN_SLINGITEM_RANGEMELEEATK: if( sd ) { switch( sd->itemid ) { - case 13260: // Apple Bomob - case 13261: // Coconut Bomb - case 13262: // Melon Bomb - case 13263: // Pinapple Bomb - skillratio += 400; // Unconfirded + case ITEMID_APPLE_BOMB: + skillratio = st->str + st->dex + 300; + break; + case ITEMID_MELON_BOMB: + skillratio = st->str + st->dex + 500; + break; + case ITEMID_COCONUT_BOMB: + case ITEMID_PINEAPPLE_BOMB: + case ITEMID_BANANA_BOMB: + skillratio = st->str + st->dex + 800; + break; + case ITEMID_BLACK_LUMP: + skillratio = (st->str + st->agi + st->dex) / 3; // Black Lump + break; + case ITEMID_BLACK_HARD_LUMP: + skillratio = (st->str + st->agi + st->dex) / 2; // Hard Black Lump break; - case 13264: // Banana Bomb 2000% - skillratio += 1900; + case ITEMID_VERY_HARD_LUMP: + skillratio = st->str + st->agi + st->dex; // Extremely Hard Black Lump break; - case 13265: skillratio -= 75; break; // Black Lump 25% - case 13266: skillratio -= 25; break; // Hard Black Lump 75% - case 13267: skillratio += 100; break; // Extremely Hard Black Lump 200% } - } else - skillratio += 300; // Bombs + } break; case SO_VARETYR_SPEAR://ATK [{( Striking Level x 50 ) + ( Varetyr Spear Skill Level x 50 )} x Caster Base Level / 100 ] % skillratio += -100 + 50 * skill_lv + ( sd ? pc->checkskill(sd, SO_STRIKING) * 50 : 0 ); if( sc && sc->data[SC_BLAST_OPTION] ) - skillratio += sd ? sd->status.job_level * 5 : 0; + skillratio += (sd ? sd->status.job_level * 5 : 0); break; - // Physical Elemantal Spirits Attack Skills + // Physical Elemental Spirits Attack Skills case EL_CIRCLE_OF_FIRE: case EL_FIRE_BOMB_ATK: case EL_STONE_RAIN: @@ -2427,7 +2488,7 @@ int battle_calc_skillratio(int attack_type, struct block_list *src, struct block skillratio += -100 + 150 * skill_lv; RE_LVL_DMOD(120); if( tsc && tsc->data[SC_KO_JYUMONJIKIRI] ) - skillratio += status_get_lv(src) * skill_lv; + skillratio += status->get_lv(src) * skill_lv; case KO_HUUMARANKA: skillratio += -100 + 150 * skill_lv + status_get_agi(src) + status_get_dex(src) + 100 * (sd ? pc->checkskill(sd, NJ_HUUMA) : 0); break; @@ -2454,13 +2515,43 @@ int battle_calc_skillratio(int attack_type, struct block_list *src, struct block skillratio += -100 + 100 * skill_lv; break; } - if( sc && sc->data[SC_EDP] ){ - skillratio -= addedratio; - if( skill_id == AS_SONICBLOW || - skill_id == GC_COUNTERSLASH || - skill_id == GC_CROSSIMPACT ) - skillratio >>= 1; - skillratio += addedratio; + //Skill damage modifiers that stack linearly + if(sc && skill_id != PA_SACRIFICE){ +#ifdef RENEWAL_EDP + if( sc->data[SC_EDP] ){ + if( skill_id == AS_SONICBLOW || + skill_id == GC_COUNTERSLASH || + skill_id == GC_CROSSIMPACT ) + skillratio >>= 1; + } +#endif + if(sc->data[SC_OVERTHRUST]) + skillratio += sc->data[SC_OVERTHRUST]->val3; + if(sc->data[SC_OVERTHRUSTMAX]) + skillratio += sc->data[SC_OVERTHRUSTMAX]->val2; + if(sc->data[SC_BERSERK]) +#ifndef RENEWAL + skillratio += 100; +#else + skillratio += 200; + if( sc->data[SC_TRUESIGHT] ) + skillratio += 2*sc->data[SC_TRUESIGHT]->val1; + if( sc->data[SC_LKCONCENTRATION] ) + skillratio += sc->data[SC_LKCONCENTRATION]->val2; + if( sd && sd->status.weapon == W_KATAR && (i=pc->checkskill(sd,ASC_KATAR)) > 0 ) + skillratio += skillratio * (10 + 2 * i) / 100; +#endif + if( (!skill_id || skill_id == KN_AUTOCOUNTER) && sc->data[SC_CRUSHSTRIKE] ){ + if( sd ) + {//ATK [{Weapon Level * (Weapon Upgrade Level + 6) * 100} + (Weapon ATK) + (Weapon Weight)]% + short index = sd->equip_index[EQI_HAND_R]; + if( index >= 0 && sd->inventory_data[index] && sd->inventory_data[index]->type == IT_WEAPON ) + skillratio += -100 + sd->inventory_data[index]->weight/10 + st->rhw.atk + + 100 * sd->inventory_data[index]->wlv * (sd->status.inventory[index].refine + 6); + } + status_change_end(src, SC_CRUSHSTRIKE, INVALID_TIMER); + skill->break_equip(src,EQP_WEAPON,2000,BCT_SELF); // 20% chance to destroy the weapon. + } } } if( skillratio < 1 ) @@ -2468,14 +2559,13 @@ int battle_calc_skillratio(int attack_type, struct block_list *src, struct block return skillratio; } /*========================================== - * Check dammage trough status. - * ATK may be MISS, BLOCKED FAIL, reduc, increase, end status... + * Check damage trough status. + * ATK may be MISS, BLOCKED FAIL, reduce, increase, end status... * After this we apply bg/gvg reduction *------------------------------------------*/ -int battle_calc_damage(struct block_list *src,struct block_list *bl,struct Damage *d,int damage,uint16 skill_id,uint16 skill_lv) -{ +int64 battle_calc_damage(struct block_list *src,struct block_list *bl,struct Damage *d,int64 damage,uint16 skill_id,uint16 skill_lv) { struct map_session_data *sd = NULL; - struct status_change *sc; + struct status_change *sc, *tsc; struct status_change_entry *sce; int div_ = d->div_, flag = d->flag; @@ -2483,9 +2573,8 @@ int battle_calc_damage(struct block_list *src,struct block_list *bl,struct Damag if( !damage ) return 0; - if( battle_config.ksprotection && mob_ksprotected(src, bl) ) + if( battle_config.ksprotection && mob->ksprotected(src, bl) ) return 0; - if (bl->type == BL_PC) { sd=(struct map_session_data *)bl; //Special no damage states @@ -2501,7 +2590,8 @@ int battle_calc_damage(struct block_list *src,struct block_list *bl,struct Damag if(!damage) return 0; } - sc = status_get_sc(bl); + sc = status->get_sc(bl); + tsc = status->get_sc(src); if( sc && sc->data[SC_INVINCIBLE] && !sc->data[SC_INVINCIBLEOFF] ) return 1; @@ -2522,7 +2612,7 @@ int battle_calc_damage(struct block_list *src,struct block_list *bl,struct Damag skill_id == MG_SOULSTRIKE || skill_id == WL_SOULEXPANSION || (skill_id && skill->get_ele(skill_id, skill_lv) == ELE_GHOST) || - (!skill_id && (status_get_status_data(src))->rhw.ele == ELE_GHOST) + (!skill_id && (status->get_status_data(src))->rhw.ele == ELE_GHOST) ){ if( skill_id == WL_SOULEXPANSION ) damage <<= 1; // If used against a player in White Imprison, the skill deals double damage. @@ -2533,8 +2623,7 @@ int battle_calc_damage(struct block_list *src,struct block_list *bl,struct Damag } } - if(sc->data[SC_ZEPHYR] && - flag&(BF_LONG|BF_SHORT)){ + if( sc->data[SC_ZEPHYR] && ((flag&BF_LONG) || rand()%100 < 10) ) { d->dmg_lv = ATK_BLOCK; return 0; } @@ -2542,30 +2631,38 @@ int battle_calc_damage(struct block_list *src,struct block_list *bl,struct Damag if( sc->data[SC_SAFETYWALL] && (flag&(BF_SHORT|BF_MAGIC))==BF_SHORT ) { struct skill_unit_group* group = skill->id2group(sc->data[SC_SAFETYWALL]->val3); - uint16 skill_id = sc->data[SC_SAFETYWALL]->val2; + uint16 src_skill_id = sc->data[SC_SAFETYWALL]->val2; if (group) { - if(skill_id == MH_STEINWAND){ - if (--group->val2<=0) - skill->del_unitgroup(group,ALC_MARK); - d->dmg_lv = ATK_BLOCK; - return 0; + d->dmg_lv = ATK_BLOCK; + if(src_skill_id == MH_STEINWAND){ + if (--group->val2<=0) + skill->del_unitgroup(group,ALC_MARK); + if( (group->val3 - damage) > 0 ) + group->val3 -= (int)cap_value(damage, INT_MIN, INT_MAX); + else + skill->del_unitgroup(group,ALC_MARK); + return 0; + } + if( skill_id == SO_ELEMENTAL_SHIELD ) { + if ( ( group->val2 - damage) > 0 ) { + group->val2 -= (int)cap_value(damage,INT_MIN,INT_MAX); + } else + skill->del_unitgroup(group,ALC_MARK); + return 0; } /** * in RE, SW possesses a lifetime equal to 3 times the caster's health **/ #ifdef RENEWAL - d->dmg_lv = ATK_BLOCK; if ( ( group->val2 - damage) > 0 ) { - group->val2 -= damage; + group->val2 -= (int)cap_value(damage,INT_MIN,INT_MAX); } else skill->del_unitgroup(group,ALC_MARK); - return 0; #else if (--group->val2<=0) skill->del_unitgroup(group,ALC_MARK); - d->dmg_lv = ATK_BLOCK; - return 0; #endif + return 0; } status_change_end(bl, SC_SAFETYWALL, INVALID_TIMER); } @@ -2574,11 +2671,26 @@ int battle_calc_damage(struct block_list *src,struct block_list *bl,struct Damag d->dmg_lv = ATK_BLOCK; return 0; } + if( sc->data[SC_NEUTRALBARRIER] && (flag&(BF_MAGIC|BF_LONG)) == BF_LONG && skill_id != CR_ACIDDEMONSTRATION ) { + d->dmg_lv = ATK_BLOCK; + return 0; + } + if( sc->data[SC__MAELSTROM] && (flag&BF_MAGIC) && skill_id && (skill->get_inf(skill_id)&INF_GROUND_SKILL) ) { + // {(Maelstrom Skill LevelxAbsorbed Skill Level)+(Caster's Job/5)}/2 + int sp = (sc->data[SC__MAELSTROM]->val1 * skill_lv + sd->status.job_level / 5) / 2; + status->heal(bl, 0, sp, 3); + d->dmg_lv = ATK_BLOCK; + return 0; + } if( sc->data[SC_WEAPONBLOCKING] && flag&(BF_SHORT|BF_WEAPON) && rnd()%100 < sc->data[SC_WEAPONBLOCKING]->val2 ) { clif->skill_nodamage(bl,src,GC_WEAPONBLOCKING,1,1); d->dmg_lv = ATK_BLOCK; - sc_start2(bl,SC_COMBOATTACK,100,GC_WEAPONBLOCKING,src->id,2000); + sc_start2(src,bl,SC_COMBOATTACK,100,GC_WEAPONBLOCKING,src->id,2000); + return 0; + } + if( sc->data[SC_HOVERING] && skill_id && (skill->get_inf(skill_id)&INF_GROUND_SKILL || skill_id == SR_WINDMILL) ) { + d->dmg_lv = ATK_BLOCK; return 0; } if( (sce=sc->data[SC_AUTOGUARD]) && flag&BF_WEAPON && !(skill->get_nk(skill_id)&NK_NO_CARDFIX_ATK) && rnd()%100 < sce->val2 ) @@ -2592,23 +2704,23 @@ int battle_calc_damage(struct block_list *src,struct block_list *bl,struct Damag delay = 200; else delay = 100; - unit_set_walkdelay(bl, iTimer->gettick(), delay, 1); + unit->set_walkdelay(bl, timer->gettick(), delay, 1); if(sc->data[SC_CR_SHRINK] && rnd()%100<5*sce->val1) skill->blown(bl,src,skill->get_blewcount(CR_SHRINK,1),-1,0); + d->dmg_lv = ATK_MISS; return 0; } if( (sce = sc->data[SC_MILLENNIUMSHIELD]) && sce->val2 > 0 && damage > 0 ) { clif->skill_nodamage(bl, bl, RK_MILLENNIUMSHIELD, 1, 1); - sce->val3 -= damage; // absorb damage + sce->val3 -= (int)cap_value(damage,INT_MIN,INT_MAX); // absorb damage d->dmg_lv = ATK_BLOCK; - sc_start(bl,SC_STUN,15,0,skill->get_time2(RK_MILLENNIUMSHIELD,sce->val1)); // There is a chance to be stuned when one shield is broken. + sc_start(src,bl,SC_STUN,15,0,skill->get_time2(RK_MILLENNIUMSHIELD,sce->val1)); // There is a chance to be stunned when one shield is broken. if( sce->val3 <= 0 ) { // Shield Down sce->val2--; if( sce->val2 > 0 ) { - if( sd ) - clif->millenniumshield(sd,sce->val2); + clif->millenniumshield(bl,sce->val2); sce->val3 = 1000; // Next Shield } else status_change_end(bl,SC_MILLENNIUMSHIELD,INVALID_TIMER); // All shields down @@ -2629,21 +2741,16 @@ int battle_calc_damage(struct block_list *src,struct block_list *bl,struct Damag if (sd && pc_issit(sd)) pc->setstand(sd); //Stand it to dodge. clif->skill_nodamage(bl,bl,TK_DODGE,1,1); if (!sc->data[SC_COMBOATTACK]) - sc_start4(bl, SC_COMBOATTACK, 100, TK_JUMPKICK, src->id, 1, 0, 2000); + sc_start4(src, bl, SC_COMBOATTACK, 100, TK_JUMPKICK, src->id, 1, 0, 2000); return 0; } - if(sc->data[SC_HERMODE] && flag&BF_MAGIC) + if((sc->data[SC_HERMODE] || sc->data[SC_HOVERING]) && flag&BF_MAGIC) return 0; if(sc->data[SC_NJ_TATAMIGAESHI] && (flag&(BF_MAGIC|BF_LONG)) == BF_LONG) return 0; - if( sc->data[SC_NEUTRALBARRIER] && (flag&(BF_MAGIC|BF_LONG)) == (BF_MAGIC|BF_LONG) ) { - d->dmg_lv = ATK_MISS; - return 0; - } - if((sce=sc->data[SC_KAUPE]) && rnd()%100 < sce->val2) { //Kaupe blocks damage (skill or otherwise) from players, mobs, homuns, mercenaries. clif->specialeffect(bl, 462, AREA); @@ -2662,9 +2769,9 @@ int battle_calc_damage(struct block_list *src,struct block_list *bl,struct Damag if (((sce=sc->data[SC_NJ_UTSUSEMI]) || sc->data[SC_NJ_BUNSINJYUTSU]) && flag&BF_WEAPON && !(skill->get_nk(skill_id)&NK_NO_CARDFIX_ATK)) { - skill->additional_effect (src, bl, skill_id, skill_lv, flag, ATK_BLOCK, iTimer->gettick() ); - if( !status_isdead(src) ) - skill->counter_additional_effect( src, bl, skill_id, skill_lv, flag, iTimer->gettick() ); + skill->additional_effect (src, bl, skill_id, skill_lv, flag, ATK_BLOCK, timer->gettick() ); + if( !status->isdead(src) ) + skill->counter_additional_effect( src, bl, skill_id, skill_lv, flag, timer->gettick() ); if (sce) { clif->specialeffect(bl, 462, AREA); skill->blown(src,bl,sce->val3,-1,0); @@ -2703,7 +2810,7 @@ int battle_calc_damage(struct block_list *src,struct block_list *bl,struct Damag damage += damage / 2; // 1.5 times more damage while in Deep Sleep. status_change_end(bl,SC_DEEP_SLEEP,INVALID_TIMER); } - if( tsd && sd && sc->data[SC_CRYSTALIZE] && flag&BF_WEAPON ){ + if( tsd && sd && sc->data[SC_COLD] && flag&BF_WEAPON ){ switch(tsd->status.weapon){ case W_MACE: case W_2HMACE: @@ -2744,32 +2851,37 @@ int battle_calc_damage(struct block_list *src,struct block_list *bl,struct Damag #endif if(sc->data[SC_DEFENDER] && - (flag&(BF_LONG|BF_WEAPON)) == (BF_LONG|BF_WEAPON)) + ((flag&(BF_LONG|BF_WEAPON)) == (BF_LONG|BF_WEAPON) || skill_id == CR_ACIDDEMONSTRATION)) damage = damage * ( 100 - sc->data[SC_DEFENDER]->val2 ) / 100; if(sc->data[SC_GS_ADJUSTMENT] && (flag&(BF_LONG|BF_WEAPON)) == (BF_LONG|BF_WEAPON)) damage -= damage * 20 / 100; - if(sc->data[SC_FOGWALL] && skill_id != RK_DRAGONBREATH && skill_id != RK_DRAGONBREATH_WATER) { - if(flag&BF_SKILL) //25% reduction - damage -= damage * 25 / 100; + if(sc->data[SC_FOGWALL]) { + if(flag&BF_SKILL) { //25% reduction + if ( !(skill->get_inf(skill_id)&INF_GROUND_SKILL) && !(skill->get_nk(skill_id)&NK_SPLASH) ) + damage -= 25*damage/100; + } else if ((flag&(BF_LONG|BF_WEAPON)) == (BF_LONG|BF_WEAPON)) damage >>= 2; //75% reduction } + if ( sc->data[SC_WATER_BARRIER] ) + damage = damage * ( 100 - 20 ) / 100; + // Compressed code, fixed by map.h [Epoque] if (src->type == BL_MOB) { int i; if (sc->data[SC_MANU_DEF]) - for (i=0;ARRAYLENGTH(mob_manuk)>i;i++) - if (mob_manuk[i]==((TBL_MOB*)src)->class_) { + for (i=0;ARRAYLENGTH(mob->manuk)>i;i++) + if (mob->manuk[i]==((TBL_MOB*)src)->class_) { damage -= damage * sc->data[SC_MANU_DEF]->val1 / 100; break; } if (sc->data[SC_SPL_DEF]) - for (i=0;ARRAYLENGTH(mob_splendide)>i;i++) - if (mob_splendide[i]==((TBL_MOB*)src)->class_) { + for (i=0;ARRAYLENGTH(mob->splendide)>i;i++) + if (mob->splendide[i]==((TBL_MOB*)src)->class_) { damage -= damage * sc->data[SC_SPL_DEF]->val1 / 100; break; } @@ -2779,17 +2891,19 @@ int battle_calc_damage(struct block_list *src,struct block_list *bl,struct Damag sce->val3&flag && sce->val4&flag) damage -= damage * sc->data[SC_ARMOR]->val2 / 100; + if( sc->data[SC_ENERGYCOAT] && (skill_id == GN_HELLS_PLANT_ATK || #ifdef RENEWAL - if(sc->data[SC_ENERGYCOAT] && (flag&BF_WEAPON || flag&BF_MAGIC) && skill_id != WS_CARTTERMINATION) + ((flag&BF_WEAPON || flag&BF_MAGIC) && skill_id != WS_CARTTERMINATION) #else - if(sc->data[SC_ENERGYCOAT] && (flag&BF_WEAPON && skill_id != WS_CARTTERMINATION)) + (flag&BF_WEAPON && skill_id != WS_CARTTERMINATION) #endif + ) ) { - struct status_data *status = status_get_status_data(bl); - int per = 100*status->sp / status->max_sp -1; //100% should be counted as the 80~99% interval + struct status_data *sstatus = status->get_status_data(bl); + int per = 100*sstatus->sp / sstatus->max_sp -1; //100% should be counted as the 80~99% interval per /=20; //Uses 20% SP intervals. //SP Cost: 1% + 0.5% per every 20% SP - if (!status_charge(bl, 0, (10+5*per)*status->max_sp/1000)) + if (!status->charge(bl, 0, (10+5*per)*sstatus->max_sp/1000)) status_change_end(bl, SC_ENERGYCOAT, INVALID_TIMER); //Reduction: 6% + 6% every 20% damage -= damage * (6 * (1+per)) / 100; @@ -2801,11 +2915,14 @@ int battle_calc_damage(struct block_list *src,struct block_list *bl,struct Damag damage -= damage * sc->data[SC_PAIN_KILLER]->val3 / 100; } if((sce=sc->data[SC_MAGMA_FLOW]) && (rnd()%100 <= sce->val2) ){ - skill->castend_damage_id(bl,src,MH_MAGMA_FLOW,sce->val1,iTimer->gettick(),0); + skill->castend_damage_id(bl,src,MH_MAGMA_FLOW,sce->val1,timer->gettick(),0); } + if( sc->data[SC_DARKCROW] && (flag&(BF_SHORT|BF_MAGIC)) == BF_SHORT ) + damage += damage * sc->data[SC_DARKCROW]->val2 / 100; + if( (sce = sc->data[SC_STONEHARDSKIN]) && flag&(BF_SHORT|BF_WEAPON) && damage > 0 ) { - sce->val2 -= damage; + sce->val2 -= (int)cap_value(damage,INT_MIN,INT_MAX); if( src->type == BL_PC ) { TBL_PC *ssd = BL_CAST(BL_PC, src); if (ssd && ssd->status.weapon != W_BOW) @@ -2814,7 +2931,7 @@ int battle_calc_damage(struct block_list *src,struct block_list *bl,struct Damag skill->break_equip(src, EQP_WEAPON, 3000, BCT_SELF); // 30% chance to reduce monster's ATK by 25% for 10 seconds. if( src->type == BL_MOB ) - sc_start(src, SC_NOEQUIPWEAPON, 30, 0, skill->get_time2(RK_STONEHARDSKIN, sce->val1)); + sc_start(bl,src, SC_NOEQUIPWEAPON, 30, 0, skill->get_time2(RK_STONEHARDSKIN, sce->val1)); if( sce->val2 <= 0 ) status_change_end(bl, SC_STONEHARDSKIN, INVALID_TIMER); } @@ -2838,12 +2955,12 @@ int battle_calc_damage(struct block_list *src,struct block_list *bl,struct Damag //Finally Kyrie because it may, or not, reduce damage to 0. if((sce = sc->data[SC_KYRIE]) && damage > 0){ - sce->val2-=damage; + sce->val2 -= (int)cap_value(damage,INT_MIN,INT_MAX); if(flag&BF_WEAPON || skill_id == TF_THROWSTONE){ if(sce->val2>=0) damage=0; else - damage=-sce->val2; + damage=-sce->val2; } if((--sce->val3)<=0 || (sce->val2<=0) || skill_id == AL_HOLYLIGHT) status_change_end(bl, SC_KYRIE, INVALID_TIMER); @@ -2858,10 +2975,10 @@ int battle_calc_damage(struct block_list *src,struct block_list *bl,struct Damag if( (sce = sc->data[SC_LIGHTNINGWALK]) && flag&BF_LONG && rnd()%100 < sce->val1 ) { int dx[8]={0,-1,-1,-1,0,1,1,1}; int dy[8]={1,1,0,-1,-1,-1,0,1}; - uint8 dir = iMap->calc_dir(bl, src->x, src->y); - if( unit_movepos(bl, src->x-dx[dir], src->y-dy[dir], 1, 1) ) { + uint8 dir = map->calc_dir(bl, src->x, src->y); + if( unit->movepos(bl, src->x-dx[dir], src->y-dy[dir], 1, 1) ) { clif->slide(bl,src->x-dx[dir],src->y-dy[dir]); - unit_setdir(bl, dir); + unit->setdir(bl, dir); } d->dmg_lv = ATK_DEF; status_change_end(bl, SC_LIGHTNINGWALK, INVALID_TIMER); @@ -2872,42 +2989,23 @@ int battle_calc_damage(struct block_list *src,struct block_list *bl,struct Damag //(since battle_drain is strictly for players currently) if ((sce=sc->data[SC_HAMI_BLOODLUST]) && flag&BF_WEAPON && damage > 0 && rnd()%100 < sce->val3) - status_heal(src, damage*sce->val4/100, 0, 3); + status->heal(src, damage*sce->val4/100, 0, 3); - if( sd && (sce = sc->data[SC_FORCEOFVANGUARD]) && flag&BF_WEAPON && rnd()%100 < sce->val2 ) - pc->addspiritball(sd,skill->get_time(LG_FORCEOFVANGUARD,sce->val1),sce->val3); - if (sc->data[SC_STYLE_CHANGE] && rnd()%2) { - TBL_HOM *hd = BL_CAST(BL_HOM,bl); - if (hd) homun->addspiritball(hd, 10); //add a sphere - } + if( (sce = sc->data[SC_FORCEOFVANGUARD]) && flag&BF_WEAPON + && rnd()%100 < sce->val2 && sc->fv_counter <= sce->val3 ) + clif->millenniumshield(bl, sc->fv_counter++); - if( sc->data[SC__DEADLYINFECT] && damage > 0 && rnd()%100 < 65 + 5 * sc->data[SC__DEADLYINFECT]->val1 ) - status_change_spread(bl, src); // Deadly infect attacked side - - if( sc && sc->data[SC__SHADOWFORM] ) { - struct block_list *s_bl = iMap->id2bl(sc->data[SC__SHADOWFORM]->val2); - if( !s_bl || s_bl->m != bl->m ) { // If the shadow form target is not present remove the sc. - status_change_end(bl, SC__SHADOWFORM, INVALID_TIMER); - } else if( status_isdead(s_bl) || !battle->check_target(src,s_bl,BCT_ENEMY)) { // If the shadow form target is dead or not your enemy remove the sc in both. - status_change_end(bl, SC__SHADOWFORM, INVALID_TIMER); - if( s_bl->type == BL_PC ) - ((TBL_PC*)s_bl)->shadowform_id = 0; - } else { - if( (--sc->data[SC__SHADOWFORM]->val3) < 0 ) { // If you have exceded max hits supported, remove the sc in both. - status_change_end(bl, SC__SHADOWFORM, INVALID_TIMER); - if( s_bl->type == BL_PC ) - ((TBL_PC*)s_bl)->shadowform_id = 0; - } else { - status_damage(bl, s_bl, damage, 0, clif->damage(s_bl, s_bl, iTimer->gettick(), 500, 500, damage, -1, 0, 0), 0); - return ATK_NONE; - } - } + if (sc->data[SC_STYLE_CHANGE] && rnd()%2) { + TBL_HOM *hd = BL_CAST(BL_HOM,bl); + if (hd) homun->addspiritball(hd, 10); //add a sphere } + if( sc->data[SC__DEADLYINFECT] && flag&BF_SHORT && damage > 0 && rnd()%100 < 30 + 10 * sc->data[SC__DEADLYINFECT]->val1 && !is_boss(src) ) + status->change_spread(bl, src); // Deadly infect attacked side } //SC effects from caster side. - sc = status_get_sc(src); + sc = status->get_sc(src); if (sc && sc->count) { if( sc->data[SC_INVINCIBLE] && !sc->data[SC_INVINCIBLEOFF] ) @@ -2919,24 +3017,33 @@ int battle_calc_damage(struct block_list *src,struct block_list *bl,struct Damag if ( ((sce=sc->data[SC_MANU_ATK]) && (flag&BF_WEAPON)) || ((sce=sc->data[SC_MANU_MATK]) && (flag&BF_MAGIC)) ) - for (i=0;ARRAYLENGTH(mob_manuk)>i;i++) - if (((TBL_MOB*)bl)->class_==mob_manuk[i]) { + for (i=0;ARRAYLENGTH(mob->manuk)>i;i++) + if (((TBL_MOB*)bl)->class_==mob->manuk[i]) { damage += damage * sce->val1 / 100; break; } if ( ((sce=sc->data[SC_SPL_ATK]) && (flag&BF_WEAPON)) || ((sce=sc->data[SC_SPL_MATK]) && (flag&BF_MAGIC)) ) - for (i=0;ARRAYLENGTH(mob_splendide)>i;i++) - if (((TBL_MOB*)bl)->class_==mob_splendide[i]) { + for (i=0;ARRAYLENGTH(mob->splendide)>i;i++) + if (((TBL_MOB*)bl)->class_==mob->splendide[i]) { damage += damage * sce->val1 / 100; break; } } - if( sc->data[SC_POISONINGWEAPON] && skill_id != GC_VENOMPRESSURE && (flag&BF_WEAPON) && damage > 0 && rnd()%100 < sc->data[SC_POISONINGWEAPON]->val3 ) - sc_start(bl,sc->data[SC_POISONINGWEAPON]->val2,100,sc->data[SC_POISONINGWEAPON]->val1,skill->get_time2(GC_POISONINGWEAPON, 1)); - if( sc->data[SC__DEADLYINFECT] && damage > 0 && rnd()%100 < 65 + 5 * sc->data[SC__DEADLYINFECT]->val1 ) - status_change_spread(src, bl); + if( tsc->data[SC_POISONINGWEAPON] ) { + short rate = 100; + struct status_data *tstatus = status->get_status_data(bl); + if ( !(flag&BF_SKILL) && (flag&BF_WEAPON) && damage > 0 && rnd()%100 < tsc->data[SC_POISONINGWEAPON]->val3 ) { + if ( tsc->data[SC_POISONINGWEAPON]->val1 == 9 ) // Oblivion Curse gives a 2nd success chance after the 1st one passes which is reducible. [Rytech] + rate = 100 - tstatus->int_ * 4 / 5; + sc_start(src,bl,tsc->data[SC_POISONINGWEAPON]->val2,rate,tsc->data[SC_POISONINGWEAPON]->val1,skill->get_time2(GC_POISONINGWEAPON,1) - (tstatus->vit + tstatus->luk) / 2 * 1000); + } + } + if( sc->data[SC__DEADLYINFECT] && flag&BF_SHORT && damage > 0 && rnd()%100 < 30 + 10 * sc->data[SC__DEADLYINFECT]->val1 && !is_boss(src) ) + status->change_spread(src, bl); + if (sc->data[SC_SHIELDSPELL_REF] && sc->data[SC_SHIELDSPELL_REF]->val1 == 1 && damage > 0) + skill->break_equip(bl,EQP_ARMOR,10000,BCT_ENEMY ); if (sc->data[SC_STYLE_CHANGE] && rnd()%2) { TBL_HOM *hd = BL_CAST(BL_HOM,bl); if (hd) homun->addspiritball(hd, 10); @@ -2945,7 +3052,7 @@ int battle_calc_damage(struct block_list *src,struct block_list *bl,struct Damag /* no data claims these settings affect anything other than players */ if( damage && sd && bl->type == BL_PC ) { switch( skill_id ) { - //case PA_PRESSURE: /* pressure also belongs to this list but it doesn't reach this area -- so dont worry about it */ + //case PA_PRESSURE: /* pressure also belongs to this list but it doesn't reach this area -- so don't worry about it */ case HW_GRAVITATION: case NJ_ZENYNAGE: case KO_MUCHANAGE: @@ -2953,16 +3060,16 @@ int battle_calc_damage(struct block_list *src,struct block_list *bl,struct Damag default: if (flag & BF_SKILL) { //Skills get a different reduction than non-skills. [Skotlex] if (flag&BF_WEAPON) - damage = damage * map[bl->m].weapon_damage_rate / 100; + damage = damage * map->list[bl->m].weapon_damage_rate / 100; if (flag&BF_MAGIC) - damage = damage * map[bl->m].magic_damage_rate / 100; + damage = damage * map->list[bl->m].magic_damage_rate / 100; if (flag&BF_MISC) - damage = damage * map[bl->m].misc_damage_rate / 100; + damage = damage * map->list[bl->m].misc_damage_rate / 100; } else { //Normal attacks get reductions based on range. if (flag & BF_SHORT) - damage = damage * map[bl->m].short_damage_rate / 100; + damage = damage * map->list[bl->m].short_damage_rate / 100; if (flag & BF_LONG) - damage = damage * map[bl->m].long_damage_rate / 100; + damage = damage * map->list[bl->m].long_damage_rate / 100; } if(!damage) damage = 1; break; @@ -2978,11 +3085,11 @@ int battle_calc_damage(struct block_list *src,struct block_list *bl,struct Damag damage = div_; } - if( bl->type == BL_MOB && !status_isdead(bl) && src != bl) { + if( bl->type == BL_MOB && !status->isdead(bl) && src != bl) { if (damage > 0 ) - mobskill_event((TBL_MOB*)bl,src,iTimer->gettick(),flag); + mob->skill_event((TBL_MOB*)bl,src,timer->gettick(),flag); if (skill_id) - mobskill_event((TBL_MOB*)bl,src,iTimer->gettick(),MSC_SKILLUSED|(skill_id<<16)); + mob->skill_event((TBL_MOB*)bl,src,timer->gettick(),MSC_SKILLUSED|(skill_id<<16)); } if( sd ) { if( pc_ismadogear(sd) && rnd()%100 < 50 ) { @@ -2991,12 +3098,12 @@ int battle_calc_damage(struct block_list *src,struct block_list *bl,struct Damag struct status_data *sstatus = NULL; if( src->type == BL_PC && ((TBL_PC*)src)->bonus.arrow_ele ) element = ((TBL_PC*)src)->bonus.arrow_ele; - else if( (sstatus = status_get_status_data(src)) ) { + else if( (sstatus = status->get_status_data(src)) ) { element = sstatus->rhw.ele; } } else if( element == -2 ) //Use enchantment's element - element = status_get_attack_sc_element(src,status_get_sc(src)); + element = status_get_attack_sc_element(src,status->get_sc(src)); else if( element == -3 ) //Use random element element = rnd()%ELE_MAX; if( element == ELE_FIRE || element == ELE_WATER ) @@ -3010,7 +3117,7 @@ int battle_calc_damage(struct block_list *src,struct block_list *bl,struct Damag /*========================================== * Calculates BG related damage adjustments. *------------------------------------------*/ -int battle_calc_bg_damage(struct block_list *src, struct block_list *bl, int damage, int div_, uint16 skill_id, uint16 skill_lv, int flag) +int64 battle_calc_bg_damage(struct block_list *src, struct block_list *bl, int64 damage, int div_, uint16 skill_id, uint16 skill_lv, int flag) { if( !damage ) return 0; @@ -3028,10 +3135,9 @@ int battle_calc_bg_damage(struct block_list *src, struct block_list *bl, int dam /*========================================== * Calculates GVG related damage adjustments. *------------------------------------------*/ -int battle_calc_gvg_damage(struct block_list *src,struct block_list *bl,int damage,int div_,uint16 skill_id,uint16 skill_lv,int flag) -{ +int64 battle_calc_gvg_damage(struct block_list *src,struct block_list *bl,int64 damage,int div_,uint16 skill_id,uint16 skill_lv,int flag) { struct mob_data* md = BL_CAST(BL_MOB, bl); - int class_ = status_get_class(bl); + int class_ = status->get_class(bl); if (!damage) //No reductions to make. return 0; @@ -3050,7 +3156,7 @@ int battle_calc_gvg_damage(struct block_list *src,struct block_list *bl,int dama } } if(src->type != BL_MOB) { - struct guild *g = src->type == BL_PC ? ((TBL_PC *)src)->guild : guild->search(status_get_guild_id(src)); + struct guild *g = src->type == BL_PC ? ((TBL_PC *)src)->guild : guild->search(status->get_guild_id(src)); if (class_ == MOBID_EMPERIUM && (!g || guild->checkskill(g,GD_APPROVAL) <= 0 )) return 0; @@ -3065,6 +3171,7 @@ int battle_calc_gvg_damage(struct block_list *src,struct block_list *bl,int dama case HW_GRAVITATION: case NJ_ZENYNAGE: case KO_MUCHANAGE: + case NC_SELFDESTRUCTION: break; default: /* Uncomment if you want god-mode Emperiums at 100 defense. [Kisuka] @@ -3081,8 +3188,8 @@ int battle_calc_gvg_damage(struct block_list *src,struct block_list *bl,int dama /*========================================== * HP/SP drain calculation *------------------------------------------*/ -int battle_calc_drain(int damage, int rate, int per) { - int diff = 0; +int battle_calc_drain(int64 damage, int rate, int per) { + int64 diff = 0; if (per && rnd()%1000 < rate) { diff = (damage * per) / 100; @@ -3093,7 +3200,7 @@ int battle_calc_drain(int damage, int rate, int per) { diff = -1; } } - return diff; + return (int)cap_value(diff,INT_MIN,INT_MAX); } /*========================================== @@ -3104,7 +3211,7 @@ void battle_consume_ammo(TBL_PC*sd, int skill_id, int lv) { if (!battle_config.arrow_decrement) return; - if (skill) { + if (skill_id) { qty = skill->get_ammo_qty(skill_id, lv); if (!qty) qty = 1; } @@ -3123,19 +3230,26 @@ int battle_range_type(struct block_list *src, struct block_list *target, uint16 return BF_SHORT; return BF_LONG; } + + if (skill_id == SR_GATEOFHELL) { + if (skill_lv < 5) + return BF_SHORT; + else + return BF_LONG; + } + //based on used skill's range if (skill->get_range2(src, skill_id, skill_lv) < 5) return BF_SHORT; return BF_LONG; } int battle_adjust_skill_damage(int m, unsigned short skill_id) { - - if( map[m].skill_count ) { + if( map->list[m].skill_count ) { int i; - ARR_FIND(0, map[m].skill_count, i, map[m].skills[i]->skill_id == skill_id ); + ARR_FIND(0, map->list[m].skill_count, i, map->list[m].skills[i]->skill_id == skill_id ); - if( i < map[m].skill_count ) { - return map[m].skills[i]->modifier; + if( i < map->list[m].skill_count ) { + return map->list[m].skills[i]->modifier; } } @@ -3146,7 +3260,7 @@ int battle_blewcount_bonus(struct map_session_data *sd, uint16 skill_id) { int i; if (!sd->skillblown[0].id) return 0; - //Apply the bonus blewcount. [Skotlex] + //Apply the bonus blow count. [Skotlex] for (i = 0; i < ARRAYLENGTH(sd->skillblown) && sd->skillblown[i].id; i++) { if (sd->skillblown[i].id == skill_id) return sd->skillblown[i].val; @@ -3154,7 +3268,7 @@ int battle_blewcount_bonus(struct map_session_data *sd, uint16 skill_id) { return 0; } //For quick div adjustment. -#define damage_div_fix(dmg, div) { if (div > 1) (dmg)*=div; else if (div < 0) (div)*=-1; } +#define damage_div_fix(dmg, div) do { if ((div) > 1) (dmg)*=(div); else if ((div) < 0) (div)*=-1; } while(0) /*========================================== * battle_calc_magic_attack [DracoRPG] *------------------------------------------*/ @@ -3164,11 +3278,10 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list unsigned int skillratio = 100; //Skill dmg modifiers. TBL_PC *sd; -// TBL_PC *tsd; - struct status_change *sc, *tsc; + struct status_change *sc; struct Damage ad; - struct status_data *sstatus = status_get_status_data(src); - struct status_data *tstatus = status_get_status_data(target); + struct status_data *sstatus = status->get_status_data(src); + struct status_data *tstatus = status->get_status_data(target); struct { unsigned imdef : 1; unsigned infdef : 1; @@ -3177,11 +3290,9 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list memset(&ad,0,sizeof(ad)); memset(&flag,0,sizeof(flag)); - if(src==NULL || target==NULL) - { - nullpo_info(NLP_MARK); - return ad; - } + nullpo_retr(ad, src); + nullpo_retr(ad, target); + //Initial Values ad.damage = 1; ad.div_=skill->get_num(skill_id,skill_lv); @@ -3194,9 +3305,8 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list flag.imdef = nk&NK_IGNORE_DEF?1:0; sd = BL_CAST(BL_PC, src); -// tsd = BL_CAST(BL_PC, target); - sc = status_get_sc(src); - tsc = status_get_sc(target); + + sc = status->get_sc(src); //Initialize variables that will be used afterwards s_ele = skill->get_ele(skill_id, skill_lv); @@ -3208,7 +3318,7 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list if( i < 5 ) s_ele = i; } }else if (s_ele == -2) //Use status element - s_ele = status_get_attack_sc_element(src,status_get_sc(src)); + s_ele = status_get_attack_sc_element(src,status->get_sc(src)); else if( s_ele == -3 ) //Use random element s_ele = rnd()%ELE_MAX; @@ -3230,11 +3340,8 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list //Skill Range Criteria ad.flag |= battle->range_type(src, target, skill_id, skill_lv); flag.infdef=(tstatus->mode&MD_PLANT?1:0); - if( target->type == BL_SKILL){ - TBL_SKILL *su = (TBL_SKILL*)target; - if( su->group && (su->group->skill_id == WM_REVERBERATION || su->group->skill_id == WM_POEMOFNETHERWORLD) ) - flag.infdef = 1; - } + if( !flag.infdef && target->type == BL_SKILL && ((TBL_SKILL*)target)->group->unit_id == UNT_REVERBERATION ) + flag.infdef = 1; // Reverberation takes 1 damage switch(skill_id) { case MG_FIREWALL: @@ -3272,22 +3379,24 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list ad.damage = 0; //reinitialize.. #endif //MATK_RATE scales the damage. 100 = no change. 50 is halved, 200 is doubled, etc -#define MATK_RATE( a ) { ad.damage= ad.damage*(a)/100; } +#define MATK_RATE( a ) ( ad.damage= ad.damage*(a)/100 ) //Adds dmg%. 100 = +100% (double) damage. 10 = +10% damage -#define MATK_ADDRATE( a ) { ad.damage+= ad.damage*(a)/100; } +#define MATK_ADDRATE( a ) ( ad.damage+= ad.damage*(a)/100 ) //Adds an absolute value to damage. 100 = +100 damage -#define MATK_ADD( a ) { ad.damage+= a; } +#define MATK_ADD( a ) ( ad.damage+= (a) ) switch (skill_id) { //Calc base damage according to skill case AL_HEAL: case PR_BENEDICTIO: case PR_SANCTUARY: + ad.damage = skill->calc_heal(src, target, skill_id, skill_lv, false); + break; /** * Arch Bishop **/ case AB_HIGHNESSHEAL: - ad.damage = skill->calc_heal(src, target, skill_id, skill_lv, false); + ad.damage = skill->calc_heal(src, target, AL_HEAL, 10, false) * ( 17 + 3 * skill_lv ) / 10; break; case PR_ASPERSIO: ad.damage = 40; @@ -3295,16 +3404,16 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list case ALL_RESURRECTION: case PR_TURNUNDEAD: //Undead check is on skill_castend_damageid code. - i = 20*skill_lv + sstatus->luk + sstatus->int_ + status_get_lv(src) + i = 20*skill_lv + sstatus->luk + sstatus->int_ + status->get_lv(src) + 200 - 200*tstatus->hp/tstatus->max_hp; // there is no changed in success chance in renewal. [malufett] if(i > 700) i = 700; if(rnd()%1000 < i && !(tstatus->mode&MD_BOSS)) ad.damage = tstatus->hp; else { #ifdef RENEWAL - MATK_ADD(status_get_matk(src, 2)); + MATK_ADD(status->get_matk(src, 2)); #else - ad.damage = status_get_lv(src) + sstatus->int_ + skill_lv * 10; + ad.damage = status->get_lv(src) + sstatus->int_ + skill_lv * 10; #endif } break; @@ -3316,10 +3425,10 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list **/ case AB_RENOVATIO: //Damage calculation from iRO wiki. [Jobbie] - ad.damage = (int)((15 * status_get_lv(src)) + (1.5 * sstatus->int_)); + ad.damage = status->get_lv(src) * 10 + sstatus->int_; break; - default: { - MATK_ADD( status_get_matk(src, 2) ); + default: { + MATK_ADD( status->get_matk(src, 2) ); if (nk&NK_SPLASHSPLIT) { // Divide MATK in case of multiple targets skill if(mflag>0) @@ -3330,44 +3439,44 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list if (sc){ if( sc->data[SC_TELEKINESIS_INTENSE] && s_ele == ELE_GHOST ) - skillratio += sc->data[SC_TELEKINESIS_INTENSE]->val3; + ad.damage += sc->data[SC_TELEKINESIS_INTENSE]->val3; } switch(skill_id){ case MG_FIREBOLT: case MG_COLDBOLT: case MG_LIGHTNINGBOLT: if ( sc && sc->data[SC_SPELLFIST] && mflag&BF_SHORT ) { - skillratio += (sc->data[SC_SPELLFIST]->val4 * 100) + (sc->data[SC_SPELLFIST]->val2 * 100) - 100;// val4 = used bolt level, val2 = used spellfist level. [Rytech] + skillratio = sc->data[SC_SPELLFIST]->val2 * 50 + sc->data[SC_SPELLFIST]->val4 * 100;// val4 = used bolt level, val2 = used spellfist level. [Rytech] ad.div_ = 1;// ad mods, to make it work similar to regular hits [Xazax] ad.flag = BF_WEAPON|BF_SHORT; ad.type = 0; } - break; default: MATK_RATE(battle->calc_skillratio(BF_MAGIC, src, target, skill_id, skill_lv, skillratio, mflag)); } //Constant/misc additions from skills if (skill_id == WZ_FIREPILLAR) MATK_ADD(50); - if( sd && (i=pc->checkskill(sd,AB_EUCHARISTICA)) > 0 && + if( sd && ( sd->status.class_ == JOB_ARCH_BISHOP_T || sd->status.class_ == JOB_ARCH_BISHOP ) && + (i=pc->checkskill(sd,AB_EUCHARISTICA)) > 0 && (tstatus->race == RC_DEMON || tstatus->def_ele == ELE_DARK) ) MATK_ADDRATE(i); } } #ifndef HMAP_ZONE_DAMAGE_CAP_TYPE if( target && skill_id ) { - for(i = 0; i < map[target->m].zone->capped_skills_count; i++) { - if( skill_id == map[target->m].zone->capped_skills[i]->nameid && (map[target->m].zone->capped_skills[i]->type & target->type) ) { - if( target->type == BL_MOB && map[target->m].zone->capped_skills[i]->subtype != MZS_NONE ) { - if( (((TBL_MOB*)target)->status.mode&MD_BOSS) && !(map[target->m].zone->disabled_skills[i]->subtype&MZS_BOSS) ) + for(i = 0; i < map->list[target->m].zone->capped_skills_count; i++) { + if( skill_id == map->list[target->m].zone->capped_skills[i]->nameid && (map->list[target->m].zone->capped_skills[i]->type & target->type) ) { + if( target->type == BL_MOB && map->list[target->m].zone->capped_skills[i]->subtype != MZS_NONE ) { + if( (((TBL_MOB*)target)->status.mode&MD_BOSS) && !(map->list[target->m].zone->disabled_skills[i]->subtype&MZS_BOSS) ) continue; - if( ((TBL_MOB*)target)->special_state.clone && !(map[target->m].zone->disabled_skills[i]->subtype&MZS_CLONE) ) + if( ((TBL_MOB*)target)->special_state.clone && !(map->list[target->m].zone->disabled_skills[i]->subtype&MZS_CLONE) ) continue; } - if( ad.damage > map[target->m].zone->capped_skills[i]->cap ) - ad.damage = map[target->m].zone->capped_skills[i]->cap; - if( ad.damage2 > map[target->m].zone->capped_skills[i]->cap ) - ad.damage2 = map[target->m].zone->capped_skills[i]->cap; + if( ad.damage > map->list[target->m].zone->capped_skills[i]->cap ) + ad.damage = map->list[target->m].zone->capped_skills[i]->cap; + if( ad.damage2 > map->list[target->m].zone->capped_skills[i]->cap ) + ad.damage2 = map->list[target->m].zone->capped_skills[i]->cap; break; } } @@ -3377,11 +3486,36 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list ad.damage = battle->calc_cardfix(BF_MAGIC, src, target, nk, s_ele, 0, ad.damage, 0, ad.flag); #endif if(sd) { + uint16 rskill;/* redirect skill */ //Damage bonuses if ((i = pc->skillatk_bonus(sd, skill_id))) ad.damage += ad.damage*i/100; - - if( (i = battle->adjust_skill_damage(src->m,skill_id)) ) + switch(skill_id){ + case WL_CHAINLIGHTNING_ATK: + rskill = WL_CHAINLIGHTNING; + break; + case AB_DUPLELIGHT_MAGIC: + rskill = AB_DUPLELIGHT; + break; + case WL_TETRAVORTEX_FIRE: + case WL_TETRAVORTEX_WATER: + case WL_TETRAVORTEX_WIND: + case WL_TETRAVORTEX_GROUND: + rskill = WL_TETRAVORTEX; + break; + case WL_SUMMON_ATK_FIRE: + case WL_SUMMON_ATK_WIND: + case WL_SUMMON_ATK_WATER: + case WL_SUMMON_ATK_GROUND: + rskill = WL_RELEASE; + break; + case WM_REVERBERATION_MAGIC: + rskill = WM_REVERBERATION; + break; + default: + rskill = skill_id; + } + if( (i = battle->adjust_skill_damage(src->m,rskill)) ) MATK_RATE(i); //Ignore Defense? @@ -3439,7 +3573,6 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list ad.damage = 0; } } - #ifndef RENEWAL ad.damage = battle->calc_cardfix(BF_MAGIC, src, target, nk, s_ele, 0, ad.damage, 0, ad.flag); #endif @@ -3453,7 +3586,7 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list ad.damage=battle->calc_damage(src,target,&ad,ad.damage,skill_id,skill_lv); if( map_flag_gvg2(target->m) ) ad.damage=battle->calc_gvg_damage(src,target,ad.damage,ad.div_,skill_id,skill_lv,ad.flag); - else if( map[target->m].flag.battleground ) + else if( map->list[target->m].flag.battleground ) ad.damage=battle->calc_bg_damage(src,target,ad.damage,ad.div_,skill_id,skill_lv,ad.flag); switch( skill_id ) { /* post-calc modifiers */ @@ -3467,10 +3600,13 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list } return ad; +#undef MATK_RATE +#undef MATK_ADDRATE +#undef MATK_ADD } /*========================================== - * Calculate Misc dammage for skill_id + * Calculate Misc damage for skill_id *------------------------------------------*/ struct Damage battle_calc_misc_attack(struct block_list *src,struct block_list *target,uint16 skill_id,uint16 skill_lv,int mflag) { int temp; @@ -3479,19 +3615,17 @@ struct Damage battle_calc_misc_attack(struct block_list *src,struct block_list * struct map_session_data *sd, *tsd; struct Damage md; //DO NOT CONFUSE with md of mob_data! - struct status_data *sstatus = status_get_status_data(src); - struct status_data *tstatus = status_get_status_data(target); - struct status_change *tsc = status_get_sc(target); + struct status_data *sstatus = status->get_status_data(src); + struct status_data *tstatus = status->get_status_data(target); + struct status_change *tsc = status->get_sc(target); #ifdef RENEWAL - struct status_change *sc = status_get_sc(src); + struct status_change *sc = status->get_sc(src); #endif memset(&md,0,sizeof(md)); - if( src == NULL || target == NULL ){ - nullpo_info(NLP_MARK); - return md; - } + nullpo_retr(md, src); + nullpo_retr(md, target); //Some initial values md.amotion=skill->get_inf(skill_id)&INF_GROUND_SKILL?0:sstatus->amotion; @@ -3527,7 +3661,7 @@ struct Damage battle_calc_misc_attack(struct block_list *src,struct block_list * case MA_LANDMINE: case HT_BLASTMINE: case HT_CLAYMORETRAP: - md.damage = skill_lv * sstatus->dex * (3+status_get_lv(src)/100) * (1+sstatus->int_/35); + md.damage = skill_lv * sstatus->dex * (3+status->get_lv(src)/100) * (1+sstatus->int_/35); md.damage += md.damage * (rnd()%20-10) / 100; md.damage += 40 * (sd?pc->checkskill(sd,RA_RESEARCHTRAP):0); break; @@ -3585,12 +3719,12 @@ struct Damage battle_calc_misc_attack(struct block_list *src,struct block_list * case PA_GOSPEL: md.damage = 1+rnd()%9999; break; - case CR_ACIDDEMONSTRATION: + case CR_ACIDDEMONSTRATION: #ifdef RENEWAL {// [malufett] - int matk=0, atk; - short tdef = status_get_total_def(target); - short tmdef = status_get_total_mdef(target); + int64 matk=0, atk; + short tdef = status->get_total_def(target); + short tmdef = status->get_total_mdef(target); int targetVit = min(120, status_get_vit(target)); short totaldef = (tmdef + tdef - ((uint64)(tmdef + tdef) >> 32)) >> 1; @@ -3602,19 +3736,19 @@ struct Damage battle_calc_misc_attack(struct block_list *src,struct block_list * md.damage = 7 * targetVit * skill_lv * (atk + matk) / 100; /* // Pending [malufett] - if( unknown condition ) - md.damage >>= 1; if( unknown condition ){ md.damage = 7 * md.damage % 20; md.damage = 7 * md.damage / 20; }*/ }else{ - float vitfactor = 0.0f, temp; + float vitfactor = 0.0f, ftemp; if( (vitfactor=(status_get_vit(target)-120.0f)) > 0) vitfactor = (vitfactor * (matk + atk) / 10) / status_get_vit(target); - temp = max(0, vitfactor) + (targetVit * (matk + atk)) / 10; - md.damage = (int)(temp * 70 * skill_lv / 100); + ftemp = max(0, vitfactor) + (targetVit * (matk + atk)) / 10; + md.damage = (int64)(ftemp * 70 * skill_lv / 100); + if (target->type == BL_PC) + md.damage >>= 1; } md.damage -= totaldef; } @@ -3626,7 +3760,10 @@ struct Damage battle_calc_misc_attack(struct block_list *src,struct block_list * md.damage = 0; if (tsd) md.damage>>=1; #endif - if (md.damage < 0 || md.damage > INT_MAX>>1) + // Some monsters have totaldef higher than md.damage in some cases, leading to md.damage < 0 + if( md.damage < 0 ) + md.damage = 0; + if( md.damage > INT_MAX>>1 ) //Overflow prevention, will anyone whine if I cap it to a few billion? //Not capped to INT_MAX to give some room for further damage increase. md.damage = INT_MAX>>1; @@ -3648,7 +3785,7 @@ struct Damage battle_calc_misc_attack(struct block_list *src,struct block_list * md.damage=md.damage / 2; break; case GS_FLING: - md.damage = sd?sd->status.job_level:status_get_lv(src); + md.damage = sd?sd->status.job_level:status->get_lv(src); break; case HVAN_EXPLOSION: //[orn] md.damage = sstatus->max_hp * (50 + 50 * skill_lv) / 100; @@ -3660,9 +3797,9 @@ struct Damage battle_calc_misc_attack(struct block_list *src,struct block_list * nk|=NK_IGNORE_FLEE|NK_NO_ELEFIX; //These two are not properties of the weapon based part. #else int ratio = 300 + 50 * skill_lv; - int matk = battle->calc_magic_attack(src, target, skill_id, skill_lv, mflag).damage; - short totaldef = status_get_total_def(target) + status_get_total_mdef(target); - int atk = battle->calc_base_damage(src, target, skill_id, skill_lv, nk, false, s_ele, ELE_NEUTRAL, EQI_HAND_R, (sc && sc->data[SC_MAXIMIZEPOWER]?1:0)|(sc && sc->data[SC_WEAPONPERFECT]?8:0), md.flag); + int64 matk = battle->calc_magic_attack(src, target, skill_id, skill_lv, mflag).damage; + short totaldef = status->get_total_def(target) + status->get_total_mdef(target); + int64 atk = battle->calc_base_damage(src, target, skill_id, skill_lv, nk, false, s_ele, ELE_NEUTRAL, EQI_HAND_R, (sc && sc->data[SC_MAXIMIZEPOWER]?1:0)|(sc && sc->data[SC_WEAPONPERFECT]?8:0), md.flag); if( sc && sc->data[SC_EDP] ) ratio >>= 1; @@ -3682,7 +3819,7 @@ struct Damage battle_calc_misc_attack(struct block_list *src,struct block_list * case RK_DRAGONBREATH_WATER: md.damage = ((status_get_hp(src) / 50) + (status_get_max_sp(src) / 4)) * skill_lv; RE_LVL_MDMOD(150); - if (sd) md.damage = md.damage * (100 + 5 * (pc->checkskill(sd,RK_DRAGONTRAINING) - 1)) / 100; + if (sd) md.damage = md.damage * (95 + 5 * pc->checkskill(sd,RK_DRAGONTRAINING)) / 100; md.flag |= BF_LONG|BF_WEAPON; break; /** @@ -3704,15 +3841,19 @@ struct Damage battle_calc_misc_attack(struct block_list *src,struct block_list * md.damage = md.damage * 200 / (skill_id == RA_CLUSTERBOMB?50:100); break; + case WM_SOUND_OF_DESTRUCTION: + md.damage = 1000 * skill_lv + sstatus->int_ * (sd ? pc->checkskill(sd,WM_LESSON) : 10); + md.damage += md.damage * 10 * battle->calc_chorusbonus(sd) / 100; + break; /** * Mechanic **/ case NC_SELFDESTRUCTION: { #ifdef RENEWAL - short totaldef = status_get_total_def(target); + short totaldef = status->get_total_def(target); #else - short totaldef = tstatus->def2 + (short)status_get_def(target); + short totaldef = tstatus->def2 + (short)status->get_def(target); #endif md.damage = ( (sd?pc->checkskill(sd,NC_MAINFRAME):10) + 8 ) * ( skill_lv + 1 ) * ( status_get_sp(src) + sstatus->vit ); RE_LVL_MDMOD(100); @@ -3726,16 +3867,16 @@ struct Damage battle_calc_misc_attack(struct block_list *src,struct block_list * md.damage = 100 + 200 * skill_lv + sstatus->int_; break; case GN_HELLS_PLANT_ATK: - //[{( Hell Plant Skill Level x Casters Base Level ) x 10 } + {( Casters INT x 7 ) / 2 } x { 18 + ( Casters Job Level / 4 )] x ( 5 / ( 10 - Summon Flora Skill Level )) - md.damage = ( skill_lv * status_get_lv(src) * 10 ) + ( sstatus->int_ * 7 / 2 ) * ( 18 + (sd?sd->status.job_level:0) / 4 ) * ( 5 / (10 - (sd?pc->checkskill(sd,AM_CANNIBALIZE):0)) ); + md.damage = skill_lv * status->get_lv(src) * 10 + sstatus->int_ * 7 / 2 * (18 + (sd ? sd->status.job_level : 0) / 4) * (5 / (10 - (sd ? pc->checkskill(sd, AM_CANNIBALIZE) : 0))); + md.damage = md.damage*(1000 + tstatus->mdef) / (1000 + tstatus->mdef * 10) - tstatus->mdef2; break; case KO_HAPPOKUNAI: { struct Damage wd = battle->calc_weapon_attack(src,target,skill_id,skill_lv,mflag); #ifdef RENEWAL - short totaldef = status_get_total_def(target); + short totaldef = status->get_total_def(target); #else - short totaldef = tstatus->def2 + (short)status_get_def(target); + short totaldef = tstatus->def2 + (short)status->get_def(target); #endif md.damage = 3 * wd.damage * (5 + skill_lv) / 5; md.damage -= totaldef; @@ -3768,12 +3909,12 @@ struct Damage battle_calc_misc_attack(struct block_list *src,struct block_list * if(battle_config.agi_penalty_type && battle_config.agi_penalty_target&target->type) { unsigned char attacker_count; //256 max targets should be a sane max - attacker_count = unit_counttargeted(target); + attacker_count = unit->counttargeted(target); if(attacker_count >= battle_config.agi_penalty_count) { if (battle_config.agi_penalty_type == 1) flee = (flee * (100 - (attacker_count - (battle_config.agi_penalty_count - 1))*battle_config.agi_penalty_num))/100; - else //asume type 2: absolute reduction + else // assume type 2: absolute reduction flee -= (attacker_count - (battle_config.agi_penalty_count - 1))*battle_config.agi_penalty_num; if(flee < 1) flee = 1; } @@ -3799,28 +3940,36 @@ struct Damage battle_calc_misc_attack(struct block_list *src,struct block_list * } #ifndef HMAP_ZONE_DAMAGE_CAP_TYPE if( target && skill_id ) { - for(i = 0; i < map[target->m].zone->capped_skills_count; i++) { - if( skill_id == map[target->m].zone->capped_skills[i]->nameid && (map[target->m].zone->capped_skills[i]->type & target->type) ) { - if( target->type == BL_MOB && map[target->m].zone->capped_skills[i]->subtype != MZS_NONE ) { - if( (((TBL_MOB*)target)->status.mode&MD_BOSS) && !(map[target->m].zone->disabled_skills[i]->subtype&MZS_BOSS) ) + for(i = 0; i < map->list[target->m].zone->capped_skills_count; i++) { + if( skill_id == map->list[target->m].zone->capped_skills[i]->nameid && (map->list[target->m].zone->capped_skills[i]->type & target->type) ) { + if( target->type == BL_MOB && map->list[target->m].zone->capped_skills[i]->subtype != MZS_NONE ) { + if( (((TBL_MOB*)target)->status.mode&MD_BOSS) && !(map->list[target->m].zone->disabled_skills[i]->subtype&MZS_BOSS) ) continue; - if( ((TBL_MOB*)target)->special_state.clone && !(map[target->m].zone->disabled_skills[i]->subtype&MZS_CLONE) ) + if( ((TBL_MOB*)target)->special_state.clone && !(map->list[target->m].zone->disabled_skills[i]->subtype&MZS_CLONE) ) continue; } - if( md.damage > map[target->m].zone->capped_skills[i]->cap ) - md.damage = map[target->m].zone->capped_skills[i]->cap; - if( md.damage2 > map[target->m].zone->capped_skills[i]->cap ) - md.damage2 = map[target->m].zone->capped_skills[i]->cap; + if( md.damage > map->list[target->m].zone->capped_skills[i]->cap ) + md.damage = map->list[target->m].zone->capped_skills[i]->cap; + if( md.damage2 > map->list[target->m].zone->capped_skills[i]->cap ) + md.damage2 = map->list[target->m].zone->capped_skills[i]->cap; break; } } } #endif md.damage = battle->calc_cardfix(BF_MISC, src, target, nk, s_ele, 0, md.damage, 0, md.flag); - - if (sd && (i = pc->skillatk_bonus(sd, skill_id))) - md.damage += md.damage*i/100; - + if(skill_id){ + uint16 rskill;/* redirect skill id */ + switch(skill_id){ + case GN_HELLS_PLANT_ATK: + rskill = GN_HELLS_PLANT; + break; + default: + rskill = skill_id; + } + if (sd && (i = pc->skillatk_bonus(sd, rskill))) + md.damage += md.damage*i/100; + } if( (i = battle->adjust_skill_damage(src->m,skill_id)) ) md.damage = md.damage * i / 100; @@ -3839,10 +3988,6 @@ struct Damage battle_calc_misc_attack(struct block_list *src,struct block_list * default: md.damage = 1; } - }else if( target->type == BL_SKILL ){ - TBL_SKILL *su = (TBL_SKILL*)target; - if( su->group && (su->group->skill_id == WM_REVERBERATION || su->group->skill_id == WM_POEMOFNETHERWORLD) ) - md.damage = 1; } if(!(nk&NK_NO_ELEFIX)) @@ -3851,7 +3996,7 @@ struct Damage battle_calc_misc_attack(struct block_list *src,struct block_list * md.damage=battle->calc_damage(src,target,&md,md.damage,skill_id,skill_lv); if( map_flag_gvg2(target->m) ) md.damage=battle->calc_gvg_damage(src,target,md.damage,md.div_,skill_id,skill_lv,md.flag); - else if( map[target->m].flag.battleground ) + else if( map->list[target->m].flag.battleground ) md.damage=battle->calc_bg_damage(src,target,md.damage,md.div_,skill_id,skill_lv,md.flag); switch( skill_id ) { @@ -3869,7 +4014,7 @@ struct Damage battle_calc_misc_attack(struct block_list *src,struct block_list * if( sd ) { if ( md.damage > sd->status.zeny ) md.damage = sd->status.zeny; - pc->payzeny(sd, md.damage,LOG_TYPE_STEAL,NULL); + pc->payzeny(sd, (int)cap_value(md.damage,INT_MIN,INT_MAX),LOG_TYPE_STEAL,NULL); } break; } @@ -3884,16 +4029,16 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list { unsigned int skillratio = 100; //Skill dmg modifiers. short temp=0; - short s_ele, s_ele_, t_class; + short s_ele, s_ele_; int i, nk; bool n_ele = false; // non-elemental struct map_session_data *sd, *tsd; struct Damage wd; - struct status_change *sc = status_get_sc(src); - struct status_change *tsc = status_get_sc(target); - struct status_data *sstatus = status_get_status_data(src); - struct status_data *tstatus = status_get_status_data(target); + struct status_change *sc = status->get_sc(src); + struct status_change *tsc = status->get_sc(target); + struct status_data *sstatus = status->get_status_data(src); + struct status_data *tstatus = status->get_status_data(target); struct { unsigned hit : 1; //the attack Hit? (not a miss) unsigned cri : 1; //Critical hit @@ -3907,18 +4052,16 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list unsigned lh : 1; //Attack considers left hand (wd.damage2) unsigned weapon : 1; //It's a weapon attack (consider VVS, and all that) #ifdef RENEWAL - unsigned tdef : 1; //Total defence reduction + unsigned tdef : 1; //Total defense reduction #endif } flag; memset(&wd,0,sizeof(wd)); memset(&flag,0,sizeof(flag)); - if(src==NULL || target==NULL) - { - nullpo_info(NLP_MARK); - return wd; - } + nullpo_retr(wd, src); + nullpo_retr(wd, target); + //Initial flag flag.rh=1; flag.weapon=1; @@ -3927,11 +4070,8 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list && skill_id != HT_FREEZINGTRAP #endif ?1:0); - if( target->type == BL_SKILL){ - TBL_SKILL *su = (TBL_SKILL*)target; - if( su->group && (su->group->skill_id == WM_REVERBERATION || su->group->skill_id == WM_POEMOFNETHERWORLD) ) - flag.infdef = 1; - } + if( !flag.infdef && target->type == BL_SKILL && ((TBL_SKILL*)target)->group->unit_id == UNT_REVERBERATION ) + flag.infdef = 1; // Reverberation takes 1 damage //Initial Values wd.type=0; //Normal attack @@ -4050,7 +4190,6 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list return wd; } - t_class = status_get_class(target); s_ele = s_ele_ = skill->get_ele(skill_id, skill_lv); if( !skill_id || s_ele == -1 ) { //Take weapon's element @@ -4116,7 +4255,7 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list } else if(sc && sc->data[SC_FEARBREEZE] && sd->weapontype1==W_BOW && (i = sd->equip_index[EQI_AMMO]) >= 0 && sd->inventory_data[i] && sd->status.inventory[i].amount > 1){ - int chance = rand()%100; + int chance = rnd()%100; wd.type = 0x08; switch(sc->data[SC_FEARBREEZE]->val1){ case 5: @@ -4167,13 +4306,17 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list //Therefore, we use the old value 3 on cases when an sd gets attacked by a mob cri -= tstatus->luk*(!sd&&tsd?3:2); #else - cri -= status_get_lv(target) / 15 + 2 * status_get_luk(target); + cri -= status->get_lv(target) / 15 + 2 * status_get_luk(target); #endif if( tsc && tsc->data[SC_SLEEP] ) { cri <<= 1; } switch (skill_id) { + case 0: + if(!(sc && sc->data[SC_AUTOCOUNTER])) + break; + status_change_end(src, SC_AUTOCOUNTER, INVALID_TIMER); case KN_AUTOCOUNTER: if(battle_config.auto_counter_type && (battle_config.auto_counter_type&src->type)) @@ -4235,7 +4378,7 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list if(battle_config.agi_penalty_type && battle_config.agi_penalty_target&target->type) { unsigned char attacker_count; //256 max targets should be a sane max - attacker_count = unit_counttargeted(target); + attacker_count = unit->counttargeted(target); if(attacker_count >= battle_config.agi_penalty_count) { if (battle_config.agi_penalty_type == 1) flee = (flee * (100 - (attacker_count - (battle_config.agi_penalty_count - 1))*battle_config.agi_penalty_num))/100; @@ -4300,6 +4443,12 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list case GC_VENOMPRESSURE: hitrate += 10 + 4 * skill_lv; break; + case SC_FATALMENACE: + hitrate -= 35 - 5 * skill_lv; + break; + case LG_BANISHINGPOINT: + hitrate += 3 * skill_lv; + break; } if( sd ) { @@ -4317,8 +4466,11 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list if( !sd ) hitrate = cap_value(hitrate, 5, 95); #endif - if(rnd()%100 >= hitrate) + if(rnd()%100 >= hitrate){ wd.dmg_lv = ATK_FLEE; + if (skill_id == SR_GATEOFHELL) + flag.hit = 1;/* will hit with the special */ + } else flag.hit = 1; } //End hit/miss calculation @@ -4328,51 +4480,67 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list //Assuming that 99% of the cases we will not need to check for the flag.rh... we don't. //ATK_RATE scales the damage. 100 = no change. 50 is halved, 200 is doubled, etc -#define ATK_RATE( a ) { wd.damage= wd.damage*(a)/100 ; if(flag.lh) wd.damage2= wd.damage2*(a)/100; } -#define ATK_RATE2( a , b ) { wd.damage= wd.damage*(a)/100 ; if(flag.lh) wd.damage2= wd.damage2*(b)/100; } -#define ATK_RATER(a){ wd.damage = wd.damage*(a)/100;} -#define ATK_RATEL(a){ wd.damage2 = wd.damage2*(a)/100;} +#define ATK_RATE( a ) do { int64 temp__ = (a); wd.damage= wd.damage*temp__/100 ; if(flag.lh) wd.damage2= wd.damage2*temp__/100; } while(0) +#define ATK_RATE2( a , b ) do { wd.damage= wd.damage*(a)/100 ; if(flag.lh) wd.damage2= wd.damage2*(b)/100; } while(0) +#define ATK_RATER(a) ( wd.damage = wd.damage*(a)/100 ) +#define ATK_RATEL(a) ( wd.damage2 = wd.damage2*(a)/100 ) //Adds dmg%. 100 = +100% (double) damage. 10 = +10% damage -#define ATK_ADDRATE( a ) { wd.damage+= wd.damage*(a)/100 ; if(flag.lh) wd.damage2+= wd.damage2*(a)/100; } -#define ATK_ADDRATE2( a , b ) { wd.damage+= wd.damage*(a)/100 ; if(flag.lh) wd.damage2+= wd.damage2*(b)/100; } +#define ATK_ADDRATE( a ) do { int64 temp__ = (a); wd.damage+= wd.damage*temp__/100; if(flag.lh) wd.damage2+= wd.damage2*temp__/100; } while(0) +#define ATK_ADDRATE2( a , b ) do { wd.damage+= wd.damage*(a)/100 ; if(flag.lh) wd.damage2+= wd.damage2*(b)/100; } while(0) //Adds an absolute value to damage. 100 = +100 damage -#define ATK_ADD( a ) { wd.damage+= a; if (flag.lh) wd.damage2+= a; } -#define ATK_ADD2( a , b ) { wd.damage+= a; if (flag.lh) wd.damage2+= b; } - +#define ATK_ADD( a ) do { int64 temp__ = (a); wd.damage += temp__; if (flag.lh) wd.damage2 += temp__; } while(0) +#define ATK_ADD2( a , b ) do { wd.damage += (a); if (flag.lh) wd.damage2 += (b); } while(0) +#ifdef RENEWAL +#define GET_NORMAL_ATTACK( f ) ( wd.damage = battle->calc_base_damage(src, target, skill_id, skill_lv, nk, n_ele, s_ele, s_ele_, EQI_HAND_R, (f), wd.flag) ) +#define GET_NORMAL_ATTACK2( f ) ( wd.damage2 = battle->calc_base_damage(src, target, skill_id, skill_lv, nk, n_ele, s_ele, s_ele_, EQI_HAND_L, (f), wd.flag) ) +#endif switch (skill_id) { //Calc base damage according to skill case PA_SACRIFICE: wd.damage = sstatus->max_hp* 9/100; wd.damage2 = 0; - break; - #ifdef RENEWAL - case MO_EXTREMITYFIST: // [malufett] - wd.damage = battle->calc_base_damage(src, target, skill_id, skill_lv, nk, n_ele, s_ele, s_ele_, EQI_HAND_R, (sc && sc->data[SC_MAXIMIZEPOWER]?1:0)|8, wd.flag); - // first value is still not confirm. - wd.damage = status_get_sp(src) + 10 * status_get_sp(src) * wd.damage / 100 + 8 * wd.damage; - flag.tdef = 1; + wd.damage = battle->calc_elefix(src, target, skill_id, skill_lv, wd.damage, nk, n_ele, s_ele, s_ele_, false, wd.flag); // temporary [malufett] +#endif break; case NJ_ISSEN: // [malufett] +#ifndef RENEWAL + wd.damage = 40*sstatus->str +skill_lv*(sstatus->hp/10 + 35); + wd.damage2 = 0; +#else { - short totaldef = status_get_total_def(target); + short totaldef = status->get_total_def(target); i = 0; - wd.damage = battle->calc_base_damage(src, target, skill_id, skill_lv, nk, n_ele, s_ele, s_ele_, EQI_HAND_R, (sc && sc->data[SC_MAXIMIZEPOWER]?1:0)|(sc && sc->data[SC_WEAPONPERFECT]?8:0), wd.flag); + GET_NORMAL_ATTACK( (sc && sc->data[SC_MAXIMIZEPOWER]?1:0)|(sc && sc->data[SC_WEAPONPERFECT]?8:0) ); if( sc && sc->data[SC_NJ_BUNSINJYUTSU] && (i=sc->data[SC_NJ_BUNSINJYUTSU]->val2) > 0 ) wd.div_ = ~( i++ + 2 ) + 1; - wd.damage *= sstatus->hp * skill_lv; - wd.damage = wd.damage / sstatus->max_hp + sstatus->hp + i * (wd.damage / sstatus->max_hp + sstatus->hp) / 5; + if( wd.damage ){ + wd.damage *= sstatus->hp * skill_lv; + wd.damage = wd.damage / sstatus->max_hp + sstatus->hp + i * (wd.damage / sstatus->max_hp + sstatus->hp) / 5; + } ATK_ADD(-totaldef); if( is_boss(target) ) ATK_RATE(50); - flag.idef = 1; + RE_SKILL_REDUCTION(); + } + break; + case NJ_SYURIKEN: // [malufett] + GET_NORMAL_ATTACK( (sc && sc->data[SC_MAXIMIZEPOWER]?1:0)|(sc && sc->data[SC_WEAPONPERFECT]?8:0) ); + wd.damage += battle->calc_masteryfix(src, target, skill_id, skill_lv, 4 * skill_lv + (sd ? sd->bonus.arrow_atk : 0), wd.div_, 0, flag.weapon) - status->get_total_def(target); + RE_SKILL_REDUCTION(); + break; + case MO_EXTREMITYFIST: // [malufett] + { + short totaldef = status->get_total_def(target); + GET_NORMAL_ATTACK( (sc && sc->data[SC_MAXIMIZEPOWER]?1:0)|8 ); + if( wd.damage ){ + wd.damage = (250 + 150 * skill_lv) + (10 * (status_get_sp(src)+1) * wd.damage / 100) + (8 * wd.damage); + ATK_ADD(-totaldef); + } + RE_SKILL_REDUCTION(); } -#else - - wd.damage = 40*sstatus->str +skill_lv*(sstatus->hp/10 + 35); - wd.damage2 = 0; #endif - break; + break; #ifndef RENEWAL case LK_SPIRALPIERCE: case ML_SPIRALPIERCE: @@ -4383,18 +4551,18 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list sd->inventory_data[index] && sd->inventory_data[index]->type == IT_WEAPON) wd.damage = sd->inventory_data[index]->weight*8/100; //80% of weight - } else - wd.damage = sstatus->rhw.atk2*8/10; //Else use Atk2 - - ATK_ADDRATE(50*skill_lv); //Skill modifier applies to weight only. + ATK_ADDRATE(50*skill_lv); //Skill modifier applies to weight only. + } else { + wd.damage = battle->calc_base_damage2(sstatus, &sstatus->rhw, sc, tstatus->size, sd, 0); //Monsters have no weight and use ATK instead + } i = sstatus->str/10; i*=i; ATK_ADD(i); //Add str bonus. switch (tstatus->size) { //Size-fix. Is this modified by weapon perfection? - case SZ_SMALL: //Small: 125% + case SZ_MEDIUM: //Medium: 125% ATK_RATE(125); break; - //case SZ_MEDIUM: //Medium: 100% + //case SZ_SMALL: //Medium: 100% case SZ_BIG: //Large: 75% ATK_RATE(75); break; @@ -4403,16 +4571,14 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list #endif case CR_SHIELDBOOMERANG: case PA_SHIELDCHAIN: - case LG_SHIELDPRESS: - case LG_EARTHDRIVE: wd.damage = sstatus->batk; if (sd) { + int damagevalue = 0; short index = sd->equip_index[EQI_HAND_L]; - if (index >= 0 && - sd->inventory_data[index] && - sd->inventory_data[index]->type == IT_ARMOR) - ATK_ADD(sd->inventory_data[index]->weight/10); + if( index >= 0 && sd->inventory_data[index] && sd->inventory_data[index]->type == IT_ARMOR ) + damagevalue = sd->inventory_data[index]->weight/10; + ATK_ADD(damagevalue); } else ATK_ADD(sstatus->rhw.atk2); //Else use Atk2 break; @@ -4447,16 +4613,16 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list i |= 16; // for ex. shuriken must not be influenced by DEX } #ifdef RENEWAL - wd.damage = battle->calc_base_damage(src, target, skill_id, skill_lv, nk, n_ele, s_ele, s_ele_, EQI_HAND_R, i, wd.flag); + GET_NORMAL_ATTACK( i ); wd.damage = battle->calc_masteryfix(src, target, skill_id, skill_lv, wd.damage, wd.div_, 0, flag.weapon); if (flag.lh){ - wd.damage2 = battle->calc_base_damage(src, target, skill_id, skill_lv, nk, n_ele, s_ele, s_ele_, EQI_HAND_L, i, wd.flag); + GET_NORMAL_ATTACK2( i ); wd.damage2 = battle->calc_masteryfix(src, target, skill_id, skill_lv, wd.damage2, wd.div_, 1, flag.weapon); } #else - wd.damage = battle->calc_base_damage(sstatus, &sstatus->rhw, sc, tstatus->size, sd, i); + wd.damage = battle->calc_base_damage2(sstatus, &sstatus->rhw, sc, tstatus->size, sd, i); if (flag.lh) - wd.damage2 = battle->calc_base_damage(sstatus, &sstatus->lhw, sc, tstatus->size, sd, i); + wd.damage2 = battle->calc_base_damage2(sstatus, &sstatus->lhw, sc, tstatus->size, sd, i); #endif if (nk&NK_SPLASHSPLIT){ // Divide ATK among targets if(wflag>0) @@ -4469,133 +4635,171 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list if(sd) { if (sd->bonus.atk_rate) ATK_ADDRATE(sd->bonus.atk_rate); - if(flag.cri && sd->bonus.crit_atk_rate) ATK_ADDRATE(sd->bonus.crit_atk_rate); + if(flag.cri && sc && sc->data[SC_MTF_CRIDAMAGE]) + ATK_ADDRATE(25);// temporary it should be 'bonus.crit_atk_rate' +#ifndef RENEWAL if(sd->status.party_id && (temp=pc->checkskill(sd,TK_POWER)) > 0){ - if( (i = party_foreachsamemap(party->sub_count, sd, 0)) > 1 ) // exclude the player himself [Inkfish] + if( (i = party->foreachsamemap(party->sub_count, sd, 0)) > 1 ) // exclude the player himself [Inkfish] ATK_ADDRATE(2*temp*i); } +#endif } break; } //End default case } //End switch(skill_id) - //Skill damage modifiers that stack linearly - if( sd && sd->status.weapon == W_KATAR && (i=pc->checkskill(sd,ASC_KATAR)) > 0 ) - skillratio += skillratio * (13 + 2 * i) / 100; - if(sc && skill_id != PA_SACRIFICE) - { - if(sc->data[SC_OVERTHRUST]) - skillratio += sc->data[SC_OVERTHRUST]->val3; - if(sc->data[SC_OVERTHRUSTMAX]) - skillratio += sc->data[SC_OVERTHRUSTMAX]->val2; - if (sc->data[SC_BERSERK] || sc->data[SC_SATURDAY_NIGHT_FEVER] || sc->data[SC__BLOODYLUST]) - skillratio += 100; -#ifdef RENEWAL - if( sc->data[SC_TRUESIGHT] ) - skillratio += 2*sc->data[SC_TRUESIGHT]->val1; - if( sc->data[SC_LKCONCENTRATION] ) - skillratio += sc->data[SC_LKCONCENTRATION]->val2; -#endif - if( sc->data[SC_UNLIMIT] && wd.flag&BF_LONG ) - ATK_ADD( 50 * sc->data[SC_UNLIMIT]->val1 ); + if( sc && skill_id != PA_SACRIFICE && sc->data[SC_UNLIMIT] && (wd.flag&(BF_LONG|BF_MAGIC)) == BF_LONG) { + switch(skill_id) { + case RA_WUGDASH: + case RA_WUGSTRIKE: + case RA_WUGBITE: + break; + default: + ATK_ADDRATE( 50 * sc->data[SC_UNLIMIT]->val1 ); + } } - if( tsc && skill_id != PA_SACRIFICE ){ - if( tsc->data[SC_DARKCROW] && wd.flag&BF_SHORT ) - ATK_ADD( 30 * tsc->data[SC_DARKCROW]->val1 ); + + if ( sc && !skill_id && sc->data[SC_EXEEDBREAK] ) { + ATK_ADDRATE(sc->data[SC_EXEEDBREAK]->val1); + status_change_end(src, SC_EXEEDBREAK, INVALID_TIMER); } - if( !skill_id ) - { - ATK_RATE(skillratio); + + #ifdef RENEWAL + if( sd && skill_id == NJ_KUNAI ){ + flag.tdef = 1; + ATK_ADD( sd->bonus.arrow_atk ); } - else - { - switch(skill_id){ + #endif + switch(skill_id){ + case SR_GATEOFHELL: #ifdef RENEWAL - case LK_SPIRALPIERCE: - case ML_SPIRALPIERCE: - {// Formula: Floor[Floor(Weapon Weight/2)*skill level + ATK ]*(100%+50%*s.lvl) * 5 multi-hits + RE_SKILL_REDUCTION(); + #endif // RENEWAL + if (wd.dmg_lv != ATK_FLEE) + ATK_RATE(battle->calc_skillratio(BF_WEAPON, src, target, skill_id, skill_lv, skillratio, wflag)); + else + wd.dmg_lv = ATK_DEF; + break; + #ifdef RENEWAL + case NJ_TATAMIGAESHI: + ATK_RATE(200); + case LK_SPIRALPIERCE: + case ML_SPIRALPIERCE: // [malufett] + if( skill_id != NJ_TATAMIGAESHI ){ short index = sd?sd->equip_index[EQI_HAND_R]:0; - int weight = 0; - + GET_NORMAL_ATTACK( (sc && sc->data[SC_MAXIMIZEPOWER]?1:0)|(sc && sc->data[SC_WEAPONPERFECT]?8:0) ); + wd.damage = wd.damage * 70 / 100; + //n_ele = true; // FIXME: This is has no effect if it's after GET_NORMAL_ATTACK (was this intended, or was it supposed to be put above?) + if (sd && index >= 0 && sd->inventory_data[index] && sd->inventory_data[index]->type == IT_WEAPON) - weight = sd->inventory_data[index]->weight/20; - ATK_ADD(weight * skill_lv); + ATK_ADD(sd->inventory_data[index]->weight * 7 / 100); + + switch (tstatus->size) { + case SZ_MEDIUM: //Medium: 115% + ATK_RATE(115); + break; + case SZ_BIG: //Large: 85% + ATK_RATE(85); + } + wd.damage = battle->calc_masteryfix(src, target, skill_id, skill_lv, wd.damage, wd.div_, 0, flag.weapon); } - case NJ_TATAMIGAESHI: - if( skill_id != LK_SPIRALPIERCE && skill_id != ML_SPIRALPIERCE ) - ATK_RATE(200); #endif - default: - ATK_RATE(battle->calc_skillratio(BF_WEAPON, src, target, skill_id, skill_lv, skillratio, wflag)); - } + default: + ATK_RATE(battle->calc_skillratio(BF_WEAPON, src, target, skill_id, skill_lv, skillratio, wflag)); + } //Constant/misc additions from skills - switch (skill_id) { - case MO_EXTREMITYFIST: - ATK_ADD(250 + 150*skill_lv); - break; + switch (skill_id) { #ifdef RENEWAL - case HW_MAGICCRASHER: - ATK_ADD(battle->calc_magic_attack(src, target, skill_id, skill_lv, wflag).damage / 5); - break; + case HW_MAGICCRASHER: + ATK_ADD(battle->calc_magic_attack(src, target, skill_id, skill_lv, wflag).damage / 5); + break; +#else + case MO_EXTREMITYFIST: + ATK_ADD(250 + 150*skill_lv); + break; #endif - case TK_DOWNKICK: - case TK_STORMKICK: - case TK_TURNKICK: - case TK_COUNTER: - case TK_JUMPKICK: - //TK_RUN kick damage bonus. - if(sd && sd->weapontype1 == W_FIST && sd->weapontype2 == W_FIST) - ATK_ADD(10*pc->checkskill(sd, TK_RUN)); - break; - case GS_MAGICALBULLET: + case TK_DOWNKICK: + case TK_STORMKICK: + case TK_TURNKICK: + case TK_COUNTER: + case TK_JUMPKICK: + //TK_RUN kick damage bonus. + if(sd && sd->weapontype1 == W_FIST && sd->weapontype2 == W_FIST) + ATK_ADD(10*pc->checkskill(sd, TK_RUN)); + break; + case GS_MAGICALBULLET: #ifndef RENEWAL - ATK_ADD( status_get_matk(src, 2) ); + ATK_ADD( status->get_matk(src, 2) ); #else - ATK_ADD( battle->calc_magic_attack(src, target, skill_id, skill_lv, wflag).damage ); - flag.tdef = 1; + ATK_ADD( battle->calc_magic_attack(src, target, skill_id, skill_lv, wflag).damage ); + flag.tdef = 1; #endif - case NJ_SYURIKEN: - ATK_ADD(4*skill_lv); - break; - case HT_FREEZINGTRAP: - if(sd) - ATK_ADD( 40 * pc->checkskill(sd, RA_RESEARCHTRAP) ); - break; - case RA_WUGDASH ://(Caster Current Weight x 10 / 8) - if( sd && sd->weight ) - ATK_ADD( sd->weight / 8 ); - break; - case SR_TIGERCANNON: // (Tiger Cannon skill level x 240) + (Target Base Level x 40) - ATK_ADD( skill_lv * 240 + status_get_lv(target) * 40 ); - if( sc && sc->data[SC_COMBOATTACK] - && sc->data[SC_COMBOATTACK]->val1 == SR_FALLENEMPIRE ) // (Tiger Cannon skill level x 500) + (Target Base Level x 40) - ATK_ADD( skill_lv * 500 + status_get_lv(target) * 40 ); - break; - case SR_FALLENEMPIRE:// [(Target Size value + Skill Level - 1) x Caster STR] + [(Target current weight x Caster DEX / 120)] - ATK_ADD( ((tstatus->size+1)*2 + skill_lv - 1) * sstatus->str); - if( tsd && tsd->weight ){ - ATK_ADD( (tsd->weight/10) * sstatus->dex / 120 ); - }else{ - ATK_ADD( status_get_lv(target) * 50 ); //mobs - } - break; - case KO_SETSUDAN: - if( tsc && tsc->data[SC_SOULLINK] ){ - ATK_ADDRATE(200*tsc->data[SC_SOULLINK]->val1); - status_change_end(target,SC_SOULLINK,INVALID_TIMER); - } - break; - case KO_MAKIBISHI: - wd.damage = 20 * skill_lv; - break; - } +#ifndef RENEWAL + case NJ_SYURIKEN: + ATK_ADD(4*skill_lv); +#endif + break; + case GC_COUNTERSLASH: + ATK_ADD( status_get_agi(src) * 2 + (sd?sd->status.job_level:0) * 4 ); + break; + case RA_WUGDASH: + if( sc && sc->data[SC_DANCE_WITH_WUG] ) + ATK_ADD(2 * sc->data[SC_DANCE_WITH_WUG]->val1 * (2 + battle->calc_chorusbonus(sd))); + break; + case SR_TIGERCANNON: + ATK_ADD( skill_lv * 240 + status->get_lv(target) * 40 ); + if( sc && sc->data[SC_COMBOATTACK] + && sc->data[SC_COMBOATTACK]->val1 == SR_FALLENEMPIRE ) + ATK_ADD( skill_lv * 500 + status->get_lv(target) * 40 ); + break; + case RA_WUGSTRIKE: + case RA_WUGBITE: + if(sd) + ATK_ADD(30*pc->checkskill(sd, RA_TOOTHOFWUG)); + if( sc && sc->data[SC_DANCE_WITH_WUG] ) + ATK_ADD(2 * sc->data[SC_DANCE_WITH_WUG]->val1 * (2 + battle->calc_chorusbonus(sd))); + break; + case LG_SHIELDPRESS: + if( sd ) { + int damagevalue = 0; + short index = sd->equip_index[EQI_HAND_L]; + if( index >= 0 && sd->inventory_data[index] && sd->inventory_data[index]->type == IT_ARMOR ) + damagevalue = sstatus->vit * sd->status.inventory[index].refine; + ATK_ADD(damagevalue); + } + break; + case SR_GATEOFHELL: + ATK_ADD (sstatus->max_hp - status_get_hp(src)); + if(sc && sc->data[SC_COMBOATTACK] && sc->data[SC_COMBOATTACK]->val1 == SR_FALLENEMPIRE) { + ATK_ADD( (sstatus->max_sp * (1 + skill_lv * 2 / 10)) + 40 * status->get_lv(src) ); + } else { + ATK_ADD( (sstatus->sp * (1 + skill_lv * 2 / 10)) + 10 * status->get_lv(src) ); + } + break; + case SR_FALLENEMPIRE:// [(Target Size value + Skill Level - 1) x Caster STR] + [(Target current weight x Caster DEX / 120)] + ATK_ADD( ((tstatus->size+1)*2 + skill_lv - 1) * sstatus->str); + if( tsd && tsd->weight ){ + ATK_ADD( (tsd->weight/10) * sstatus->dex / 120 ); + }else{ + ATK_ADD( status->get_lv(target) * 50 ); //mobs + } + break; + case KO_SETSUDAN: + if( tsc && tsc->data[SC_SOULLINK] ){ + ATK_ADDRATE(200*tsc->data[SC_SOULLINK]->val1); + status_change_end(target,SC_SOULLINK,INVALID_TIMER); + } + break; + case KO_MAKIBISHI: + wd.damage = 20 * skill_lv; + break; } #ifndef RENEWAL //Div fix. @@ -4607,24 +4811,20 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list if( sc->data[SC_TRUESIGHT] ) ATK_ADDRATE(2*sc->data[SC_TRUESIGHT]->val1); #endif - if( sc->data[SC_GLOOMYDAY_SK] && - ( skill_id == LK_SPIRALPIERCE || skill_id == KN_BRANDISHSPEAR || - skill_id == CR_SHIELDBOOMERANG || skill_id == PA_SHIELDCHAIN || - skill_id == LG_SHIELDPRESS || skill_id == RK_HUNDREDSPEAR || - skill_id == CR_SHIELDCHARGE ) ) - ATK_ADDRATE(sc->data[SC_GLOOMYDAY_SK]->val2); + +#ifndef RENEWAL_EDP if( sc->data[SC_EDP] ){ switch(skill_id){ -#ifndef RENEWAL_EDP - case AS_SPLASHER: case AS_VENOMKNIFE: + case AS_SPLASHER: case AS_GRIMTOOTH: - break; + case ASC_BREAKER: + case AS_VENOMKNIFE: case ASC_METEORASSAULT: break; default: ATK_ADDRATE(sc->data[SC_EDP]->val3); -#endif } } +#endif if(sc->data[SC_STYLE_CHANGE]){ TBL_HOM *hd = BL_CAST(BL_HOM,src); if (hd) ATK_ADD(hd->homunculus.spiritball * 3); @@ -4645,18 +4845,54 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list sc->data[SC_SOULLINK]->val2 == SL_CRUSADER) ATK_ADDRATE(100); break; - case NC_AXETORNADO: - if( (sstatus->rhw.ele) == ELE_WIND || (sstatus->lhw.ele) == ELE_WIND ) - ATK_ADDRATE(50); - break; + } + if( skill_id ){ + uint16 rskill;/* redirect skill id */ + switch(skill_id){ + case AB_DUPLELIGHT_MELEE: + rskill = AB_DUPLELIGHT; + break; + case LG_OVERBRAND_BRANDISH: + case LG_OVERBRAND_PLUSATK: + rskill = LG_OVERBRAND; + break; + case WM_SEVERE_RAINSTORM_MELEE: + rskill = WM_SEVERE_RAINSTORM; + break; + case WM_REVERBERATION_MELEE: + rskill = WM_REVERBERATION; + break; + case GN_CRAZYWEED_ATK: + rskill = GN_CRAZYWEED; + break; + case GN_SLINGITEM_RANGEMELEEATK: + rskill = GN_SLINGITEM; + break; + case RL_R_TRIP_PLUSATK: + rskill = RL_R_TRIP; + break; + case RL_B_FLICKER_ATK: + rskill = RL_FLICKER; + break; + case RL_GLITTERING_GREED_ATK: + rskill = RL_GLITTERING_GREED; + break; + default: + rskill = skill_id; + } + if( (i = battle->adjust_skill_damage(src->m,rskill)) ) + ATK_RATE(i); } - if( (i = battle->adjust_skill_damage(src->m,skill_id)) ) - ATK_RATE(i); - if( sd ) { if (skill_id && (i = pc->skillatk_bonus(sd, skill_id))) ATK_ADDRATE(i); + #ifdef RENEWAL + if( wd.flag&BF_LONG ) + ATK_ADDRATE(sd->bonus.long_attack_atk_rate); + if( sc && sc->data[SC_MTF_RANGEATK] ) + ATK_ADDRATE(25);// temporary it should be 'bonus.long_attack_atk_rate' + #endif if( (i=pc->checkskill(sd,AB_EUCHARISTICA)) > 0 && (tstatus->race == RC_DEMON || tstatus->def_ele == ELE_DARK) ) ATK_ADDRATE(-i); @@ -4736,6 +4972,19 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list #endif ATK_ADD(20*lv); } + + if( !skill_id ) { + if( sc->data[SC_ENCHANTBLADE] ) { + //[( ( Skill Lv x 20 ) + 100 ) x ( casterBaseLevel / 150 )] + casterInt + i = ( sc->data[SC_ENCHANTBLADE]->val1 * 20 + 100 ) * status->get_lv(src) / 150 + status_get_int(src); + i = i - status->get_total_mdef(target) + status->get_matk(src, 2); + if( i ) + ATK_ADD(i); + } + if( sc->data[SC_GIANTGROWTH] && rnd()%100 < 15 ) + ATK_ADDRATE(200); // Triple Damage + } + } #ifndef RENEWAL //Refine bonus @@ -4758,10 +5007,10 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list #ifndef RENEWAL wd.damage = battle->calc_masteryfix(src, target, skill_id, skill_lv, wd.damage, wd.div_, 0, flag.weapon); - if( flag.lh) + if( flag.lh ) wd.damage2 = battle->calc_masteryfix(src, target, skill_id, skill_lv, wd.damage2, wd.div_, 1, flag.weapon); #else - if( flag.cri ) + if( sd && flag.cri ) ATK_ADDRATE(40); #endif } //Here ends flag.hit section, the rest of the function applies to both hitting and missing attacks @@ -4784,23 +5033,24 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list return wd; //Enough, rest is not needed. #ifndef HMAP_ZONE_DAMAGE_CAP_TYPE if( target && skill_id ) { - for(i = 0; i < map[target->m].zone->capped_skills_count; i++) { - if( skill_id == map[target->m].zone->capped_skills[i]->nameid && (map[target->m].zone->capped_skills[i]->type & target->type) ) { - if( target->type == BL_MOB && map[target->m].zone->capped_skills[i]->subtype != MZS_NONE ) { - if( (((TBL_MOB*)target)->status.mode&MD_BOSS) && !(map[target->m].zone->disabled_skills[i]->subtype&MZS_BOSS) ) + for(i = 0; i < map->list[target->m].zone->capped_skills_count; i++) { + if( skill_id == map->list[target->m].zone->capped_skills[i]->nameid && (map->list[target->m].zone->capped_skills[i]->type & target->type) ) { + if( target->type == BL_MOB && map->list[target->m].zone->capped_skills[i]->subtype != MZS_NONE ) { + if( (((TBL_MOB*)target)->status.mode&MD_BOSS) && !(map->list[target->m].zone->disabled_skills[i]->subtype&MZS_BOSS) ) continue; - if( ((TBL_MOB*)target)->special_state.clone && !(map[target->m].zone->disabled_skills[i]->subtype&MZS_CLONE) ) + if( ((TBL_MOB*)target)->special_state.clone && !(map->list[target->m].zone->disabled_skills[i]->subtype&MZS_CLONE) ) continue; } - if( wd.damage > map[target->m].zone->capped_skills[i]->cap ) - wd.damage = map[target->m].zone->capped_skills[i]->cap; - if( wd.damage2 > map[target->m].zone->capped_skills[i]->cap ) - wd.damage2 = map[target->m].zone->capped_skills[i]->cap; + if( wd.damage > map->list[target->m].zone->capped_skills[i]->cap ) + wd.damage = map->list[target->m].zone->capped_skills[i]->cap; + if( wd.damage2 > map->list[target->m].zone->capped_skills[i]->cap ) + wd.damage2 = map->list[target->m].zone->capped_skills[i]->cap; break; } } } #endif + #ifndef RENEWAL if (sd) { if (skill_id != CR_SHIELDBOOMERANG) //Only Shield boomerang doesn't takes the Star Crumbs bonus. @@ -4811,13 +5061,11 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list ATK_ADD(wd.div_*sd->spiritball*3); } //Card Fix, sd side + wd.damage = battle->calc_cardfix(BF_WEAPON, src, target, nk, s_ele, s_ele_, wd.damage, 2, wd.flag); if( flag.lh ) wd.damage2 = battle->calc_cardfix(BF_WEAPON, src, target, nk, s_ele, s_ele_, wd.damage2, 3, wd.flag); -#ifdef RENEWAL - if( flag.cri ) - ATK_ADDRATE(sd->bonus.crit_atk_rate>=100?sd->bonus.crit_atk_rate-60:40); -#endif + if( skill_id == CR_SHIELDBOOMERANG || skill_id == PA_SHIELDCHAIN ) { //Refine bonus applies after cards and elements. short index= sd->equip_index[EQI_HAND_L]; @@ -4827,13 +5075,11 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list } //Card Fix, tsd side if(tsd){ //if player on player then it was already measured above - wd.damage = battle->calc_cardfix(BF_WEAPON, src, target, nk, s_ele, s_ele_, wd.damage, 2, wd.flag); - if( flag.lh ) - wd.damage2 = battle->calc_cardfix(BF_WEAPON, src, target, nk, s_ele, s_ele_, wd.damage2, 3, wd.flag); + wd.damage = battle->calc_cardfix(BF_WEAPON, src, target, nk, s_ele, s_ele_, wd.damage, (flag.lh?1:0), wd.flag); } #endif if( flag.infdef ) { //Plants receive 1 damage when hit - short class_ = status_get_class(target); + short class_ = status->get_class(target); if( flag.hit || wd.damage > 0 ) wd.damage = wd.div_; // In some cases, right hand no need to have a weapon to increase damage if( flag.lh && (flag.hit || wd.damage2 > 0) ) @@ -4884,12 +5130,13 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list temp = pc->checkskill(sd,TF_DOUBLE); wd.damage2 = wd.damage * (1 + (temp * 2))/100; - if(wd.damage && !wd.damage2) wd.damage2 = + if(wd.damage && !wd.damage2) { #ifdef RENEWAL - 0; + wd.damage2 = 0; #else - 1; + wd.damage2 = 1; #endif + } flag.lh = 1; } } @@ -4900,6 +5147,19 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list if(!flag.lh && wd.damage2) wd.damage2=0; + if( sc && sc->data[SC_GLOOMYDAY] ) { + switch( skill_id ) { + case KN_BRANDISHSPEAR: + case LK_SPIRALPIERCE: + case CR_SHIELDCHARGE: + case CR_SHIELDBOOMERANG: + case PA_SHIELDCHAIN: + case RK_HUNDREDSPEAR: + case LG_SHIELDPRESS: + wd.damage += wd.damage * sc->data[SC_GLOOMYDAY]->val2 / 100; + } + } + if( sc ) { //SG_FUSION hp penalty [Komurka] if (sc->data[SC_FUSION]) { @@ -4912,12 +5172,6 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list hp = 2*hp/100; //2% hp loss per hit status_zap(src, hp, 0); } - if( !skill_id ) { - if( sc->data[SC_ENCHANTBLADE] ) { // it also works with bear hands..intended in official - //[( ( Skill Lv x 20 ) + 100 ) x ( casterBaseLevel / 150 )] + casterInt - ATK_ADD(( sc->data[SC_ENCHANTBLADE]->val1 * 20 + 100 ) * status_get_lv(src) / 150 + status_get_int(src)); - } - } status_change_end(src,SC_CAMOUFLAGE, INVALID_TIMER); } @@ -4928,82 +5182,34 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list wd.damage += md.damage; break; } - case SR_GATEOFHELL: - ATK_ADD (sstatus->max_hp - status_get_hp(src)); - if(sc && sc->data[SC_COMBOATTACK] && sc->data[SC_COMBOATTACK]->val1 == SR_FALLENEMPIRE){ - ATK_ADD ( (sstatus->max_sp * (1 + skill_lv * 2 / 10)) + 40 * status_get_lv(src) ); - }else{ - ATK_ADD ( (sstatus->sp * (1 + skill_lv * 2 / 10)) + 10 * status_get_lv(src) ); - } - break; } - if( wd.damage + wd.damage2 ) - { //There is a total damage value - int damage = wd.damage + wd.damage2, rdamage = 0, rdelay = 0; - - if( src != target && - (!skill_id || skill_id || - ( src->type == BL_SKILL && ( skill_id == SG_SUN_WARM || skill_id == SG_MOON_WARM || skill_id == SG_STAR_WARM ) )) ){ - - rdamage = battle->calc_return_damage(target, src, &damage, wd.flag, 0, &rdelay); - - if( tsc && tsc->count ) { - if( tsc && tsc->data[SC_DEATHBOUND] ){ - wd.damage = damage; - wd.damage2 = 0; - status_change_end(target,SC_DEATHBOUND,INVALID_TIMER); - } - } - if( rdamage > 0 ) { - if( tsc && tsc->data[SC_LG_REFLECTDAMAGE] ) { - if( src != target ) {// Don't reflect your own damage (Grand Cross) - bool change = false; - if( sd && !sd->state.autocast ) - change = true; - if( change ) - sd->state.autocast = 1; - iMap->foreachinshootrange(battle->damage_area,target,skill->get_splash(LG_REFLECTDAMAGE,1),BL_CHAR,iTimer->gettick(),target,wd.amotion,sstatus->dmotion,rdamage,tstatus->race); - if( change ) - sd->state.autocast = 0; - } - } else { - //Use Reflect Shield to signal this kind of skill trigger. [Skotlex] - if( tsd && src != target ) - battle->drain(tsd, src, rdamage, rdamage, sstatus->race, is_boss(src)); - battle->delay_damage(iTimer->gettick(), wd.amotion,target,src,0,CR_REFLECTSHIELD,0,rdamage,ATK_DEF,rdelay,true); - skill->additional_effect(target, src, CR_REFLECTSHIELD, 1, BF_WEAPON|BF_SHORT|BF_NORMAL,ATK_DEF,iTimer->gettick()); - } - } - } - if(!wd.damage2) - { + if( wd.damage + wd.damage2 ) { //There is a total damage value + int64 damage = wd.damage + wd.damage2; + + if(!wd.damage2) { wd.damage = battle->calc_damage(src,target,&wd,wd.damage,skill_id,skill_lv); if( map_flag_gvg2(target->m) ) wd.damage=battle->calc_gvg_damage(src,target,wd.damage,wd.div_,skill_id,skill_lv,wd.flag); - else if( map[target->m].flag.battleground ) + else if( map->list[target->m].flag.battleground ) wd.damage=battle->calc_bg_damage(src,target,wd.damage,wd.div_,skill_id,skill_lv,wd.flag); - } - else if(!wd.damage) - { + } else if(!wd.damage) { wd.damage2 = battle->calc_damage(src,target,&wd,wd.damage2,skill_id,skill_lv); if( map_flag_gvg2(target->m) ) wd.damage2 = battle->calc_gvg_damage(src,target,wd.damage2,wd.div_,skill_id,skill_lv,wd.flag); - else if( map[target->m].flag.battleground ) + else if( map->list[target->m].flag.battleground ) wd.damage = battle->calc_bg_damage(src,target,wd.damage2,wd.div_,skill_id,skill_lv,wd.flag); - } - else - { + } else { #ifdef RENEWAL wd.damage = battle->calc_damage(src,target,&wd,wd.damage,skill_id,skill_lv); wd.damage2 = battle->calc_damage(src,target,&wd,wd.damage2,skill_id,skill_lv); #else - int d1 = wd.damage + wd.damage2,d2 = wd.damage2; + int64 d1 = wd.damage + wd.damage2,d2 = wd.damage2; wd.damage = battle->calc_damage(src,target,&wd,d1,skill_id,skill_lv); #endif if( map_flag_gvg2(target->m) ) wd.damage = battle->calc_gvg_damage(src,target,wd.damage,wd.div_,skill_id,skill_lv,wd.flag); - else if( map[target->m].flag.battleground ) + else if( map->list[target->m].flag.battleground ) wd.damage = battle->calc_bg_damage(src,target,wd.damage,wd.div_,skill_id,skill_lv,wd.flag); #ifndef RENEWAL wd.damage2 = d2*100/d1 * wd.damage/100; @@ -5011,6 +5217,25 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list wd.damage-=wd.damage2; #endif } + + if( src != target ) { // Don't reflect your own damage (Grand Cross) + + if( wd.dmg_lv == ATK_MISS || wd.dmg_lv == ATK_BLOCK ) { + int64 prev1 = wd.damage, prev2 = wd.damage2; + + wd.damage = damage; + wd.damage2 = 0; + + battle->reflect_damage(target, src, &wd, skill_id); + + wd.damage = prev1; + wd.damage2 = prev2; + + } else + battle->reflect_damage(target, src, &wd, skill_id); + + } + } //Reject Sword bugreport:4493 by Daegaladh if(wd.damage && tsc && tsc->data[SC_SWORDREJECT] && @@ -5021,8 +5246,8 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list )) && rnd()%100 < tsc->data[SC_SWORDREJECT]->val2 ) { - ATK_RATER(50) - status_fix_damage(target,src,wd.damage,clif->damage(target,src,iTimer->gettick(),0,0,wd.damage,0,0,0)); + ATK_RATER(50); + status_fix_damage(target,src,wd.damage,clif->damage(target,src,0,0,wd.damage,0,0,0)); clif->skill_nodamage(target,target,ST_REJECTSWORD,tsc->data[SC_SWORDREJECT]->val1,1); if( --(tsc->data[SC_SWORDREJECT]->val3) <= 0 ) status_change_end(target, SC_SWORDREJECT, INVALID_TIMER); @@ -5043,6 +5268,7 @@ struct Damage battle_calc_weapon_attack(struct block_list *src,struct block_list struct Damage battle_calc_attack(int attack_type,struct block_list *bl,struct block_list *target,uint16 skill_id,uint16 skill_lv,int count) { struct Damage d; + struct map_session_data *sd=BL_CAST(BL_PC,bl); switch(attack_type) { case BF_WEAPON: d = battle->calc_weapon_attack(bl,target,skill_id,skill_lv,count); break; case BF_MAGIC: d = battle->calc_magic_attack(bl,target,skill_id,skill_lv,count); break; @@ -5056,18 +5282,18 @@ struct Damage battle_calc_attack(int attack_type,struct block_list *bl,struct bl #ifdef HMAP_ZONE_DAMAGE_CAP_TYPE if( target && skill_id ) { int i; - for(i = 0; i < map[target->m].zone->capped_skills_count; i++) { - if( skill_id == map[target->m].zone->capped_skills[i]->nameid && (map[target->m].zone->capped_skills[i]->type & target->type) ) { - if( target->type == BL_MOB && map[target->m].zone->capped_skills[i]->subtype != MZS_NONE ) { - if( (((TBL_MOB*)target)->status.mode&MD_BOSS) && !(map[target->m].zone->disabled_skills[i]->subtype&MZS_BOSS) ) + for(i = 0; i < map->list[target->m].zone->capped_skills_count; i++) { + if( skill_id == map->list[target->m].zone->capped_skills[i]->nameid && (map->list[target->m].zone->capped_skills[i]->type & target->type) ) { + if( target->type == BL_MOB && map->list[target->m].zone->capped_skills[i]->subtype != MZS_NONE ) { + if( (((TBL_MOB*)target)->status.mode&MD_BOSS) && !(map->list[target->m].zone->disabled_skills[i]->subtype&MZS_BOSS) ) continue; - if( ((TBL_MOB*)target)->special_state.clone && !(map[target->m].zone->disabled_skills[i]->subtype&MZS_CLONE) ) + if( ((TBL_MOB*)target)->special_state.clone && !(map->list[target->m].zone->disabled_skills[i]->subtype&MZS_CLONE) ) continue; } - if( d.damage > map[target->m].zone->capped_skills[i]->cap ) - d.damage = map[target->m].zone->capped_skills[i]->cap; - if( d.damage2 > map[target->m].zone->capped_skills[i]->cap ) - d.damage2 = map[target->m].zone->capped_skills[i]->cap; + if( d.damage > map->list[target->m].zone->capped_skills[i]->cap ) + d.damage = map->list[target->m].zone->capped_skills[i]->cap; + if( d.damage2 > map->list[target->m].zone->capped_skills[i]->cap ) + d.damage2 = map->list[target->m].zone->capped_skills[i]->cap; break; } } @@ -5081,90 +5307,206 @@ struct Damage battle_calc_attack(int attack_type,struct block_list *bl,struct bl d.dmotion = 0; } else // Some skills like Weaponry Research will cause damage even if attack is dodged d.dmg_lv = ATK_DEF; + + if(sd && d.damage+d.damage2>1) { + if(sd->bonus.sp_vanish_rate && sd->bonus.sp_vanish_trigger && rnd()%10000<sd->bonus.sp_vanish_rate && + ( (d.flag&sd->bonus.sp_vanish_trigger&BF_WEAPONMASK) || (d.flag&sd->bonus.sp_vanish_trigger&BF_RANGEMASK) + || (d.flag&sd->bonus.sp_vanish_trigger&BF_SKILLMASK) )) + status_percent_damage(&sd->bl,target,0,-sd->bonus.sp_vanish_per,false); + } return d; } - -//Calculates BF_WEAPON returned damage. -int battle_calc_return_damage(struct block_list* bl, struct block_list *src, int *dmg, int flag, uint16 skill_id, int *delay){ - int rdamage = 0, damage = *dmg, rdelay = *delay, trdamage = 0; - struct map_session_data* sd; - struct status_change* sc; +//Performs reflect damage (magic (maya) is performed over skill.c). +void battle_reflect_damage(struct block_list *target, struct block_list *src, struct Damage *wd,uint16 skill_id) { + int64 damage = wd->damage + wd->damage2, rdamage = 0, trdamage = 0; + struct map_session_data *sd, *tsd; + struct status_change *sc; + struct status_change *ssc; + int64 tick = timer->gettick(); + int delay = 50, rdelay = 0; +#ifdef RENEWAL int max_reflect_damage; - sd = BL_CAST(BL_PC, bl); - sc = status_get_sc(bl); - max_reflect_damage = max(status_get_max_hp(bl), status_get_max_hp(bl) * status_get_lv(bl) / 100); + max_reflect_damage = max(status_get_max_hp(target), status_get_max_hp(target) * status->get_lv(target) / 100); +#endif -#define NORMALIZE_RDAMAGE(d){ trdamage += rdamage = max(1, min(max_reflect_damage, d)); } - - if( sc && sc->data[SC_CRESCENTELBOW] && !is_boss(src) && rnd()%100 < sc->data[SC_CRESCENTELBOW]->val2 ){ - //ATK [{(Target HP / 100) x Skill Level} x Caster Base Level / 125] % + [Received damage x {1 + (Skill Level x 0.2)}] - int ratio = (status_get_hp(src) / 100) * sc->data[SC_CRESCENTELBOW]->val1 * status_get_lv(bl) / 125; - if (ratio > 5000) ratio = 5000; // Maximum of 5000% ATK - rdamage = rdamage * ratio / 100 + (*dmg) * (10 + sc->data[SC_CRESCENTELBOW]->val1 * 20 / 10) / 10; - skill->blown(bl, src, skill->get_blewcount(SR_CRESCENTELBOW_AUTOSPELL, sc->data[SC_CRESCENTELBOW]->val1), unit_getdir(src), 0); - clif->skill_damage(bl, src, iTimer->gettick(), status_get_amotion(src), 0, rdamage, - 1, SR_CRESCENTELBOW_AUTOSPELL, sc->data[SC_CRESCENTELBOW]->val1, 6); // This is how official does - clif->damage(src, bl, iTimer->gettick(), status_get_amotion(src)+1000, 0, rdamage/10, 1, 0, 0); - status_damage(src, bl, status_damage(bl, src, rdamage, 0, 0, 1)/10, 0, 0, 1); - status_change_end(bl, SC_CRESCENTELBOW, INVALID_TIMER); - return 0; // Just put here to minimize redundancy - } - if( flag & BF_SHORT) {//Bounces back part of the damage. - if ( sd && sd->bonus.short_weapon_damage_return ){ - NORMALIZE_RDAMAGE(damage * sd->bonus.short_weapon_damage_return / 100); - rdelay = clif->damage(src, src, iTimer->gettick(), status_get_amotion(src), status_get_dmotion(src), rdamage, 1, 4, 0); - } - if( sc && sc->count ) { - if( sc->data[SC_REFLECTSHIELD] && skill_id != WS_CARTTERMINATION ){ - NORMALIZE_RDAMAGE(damage * sc->data[SC_REFLECTSHIELD]->val2 / 100); - rdelay = clif->skill_damage(src, src, iTimer->gettick(), status_get_amotion(src), status_get_dmotion(src), rdamage, 1, CR_REFLECTSHIELD, 1, 4); + sd = BL_CAST(BL_PC, src); + + tsd = BL_CAST(BL_PC, target); + sc = status->get_sc(target); + +#ifdef RENEWAL +#define NORMALIZE_RDAMAGE(d) ( trdamage += rdamage = max(1, min(max_reflect_damage, (d))) ) +#else +#define NORMALIZE_RDAMAGE(d) ( trdamage += rdamage = max(1, (d)) ) +#endif + + if( sc && !sc->count ) + sc = NULL; + + if( sc ) { + if (wd->flag & BF_SHORT && !(skill->get_inf(skill_id) & (INF_GROUND_SKILL | INF_SELF_SKILL))) { + if( sc->data[SC_CRESCENTELBOW] && !is_boss(src) && rnd()%100 < sc->data[SC_CRESCENTELBOW]->val2 ){ + //ATK [{(Target HP / 100) x Skill Level} x Caster Base Level / 125] % + [Received damage x {1 + (Skill Level x 0.2)}] + int ratio = (status_get_hp(src) / 100) * sc->data[SC_CRESCENTELBOW]->val1 * status->get_lv(target) / 125; + if (ratio > 5000) ratio = 5000; // Maximum of 5000% ATK + rdamage = ratio + (damage)* (10 + sc->data[SC_CRESCENTELBOW]->val1 * 20 / 10) / 10; + skill->blown(target, src, skill->get_blewcount(SR_CRESCENTELBOW_AUTOSPELL, sc->data[SC_CRESCENTELBOW]->val1), unit->getdir(src), 0); + clif->skill_damage(target, src, tick, status_get_amotion(src), 0, rdamage, + 1, SR_CRESCENTELBOW_AUTOSPELL, sc->data[SC_CRESCENTELBOW]->val1, 6); // This is how official does + clif->delay_damage(tick + delay, src, target,status_get_amotion(src)+1000,0, rdamage/10, 1, 0); + status->damage(src, target, status->damage(target, src, rdamage, 0, 0, 1)/10, 0, 0, 1); + status_change_end(target, SC_CRESCENTELBOW, INVALID_TIMER); + /* shouldn't this trigger skill->additional_effect? */ + return; // Just put here to minimize redundancy } - if( sc->data[SC_LG_REFLECTDAMAGE] && rand()%100 < (30 + 10*sc->data[SC_LG_REFLECTDAMAGE]->val1) ) { - if( skill_id != HT_LANDMINE && skill_id != HT_CLAYMORETRAP - && skill_id != RA_CLUSTERBOMB && (skill_id <= RA_VERDURETRAP || skill_id > RA_ICEBOUNDTRAP) && skill_id != MA_LANDMINE ){ - NORMALIZE_RDAMAGE((*dmg) * sc->data[SC_LG_REFLECTDAMAGE]->val2 / 100); - rdelay = clif->damage(src, src, iTimer->gettick(), status_get_amotion(src), status_get_dmotion(src), rdamage, 1, 4, 0); + } + + if( wd->flag & BF_SHORT ) { + if( !is_boss(src) ) { + if( sc->data[SC_DEATHBOUND] && skill_id != WS_CARTTERMINATION ) { + uint8 dir = map->calc_dir(target,src->x,src->y), + t_dir = unit->getdir(target); + + if( !map->check_dir(dir,t_dir) ) { + int64 rd1 = damage * sc->data[SC_DEATHBOUND]->val2 / 100; // Amplify damage. + + trdamage += rdamage = rd1 - (damage = rd1 * 30 / 100); // not normalized as intended. + rdelay = clif->skill_damage(src, target, tick, status_get_amotion(src), status_get_dmotion(src), -3000, 1, RK_DEATHBOUND, sc->data[SC_DEATHBOUND]->val1, 6); + skill->blown(target, src, skill->get_blewcount(RK_DEATHBOUND, sc->data[SC_DEATHBOUND]->val1), unit->getdir(src), 0); + + if( tsd ) /* is this right? rdamage as both left and right? */ + battle->drain(tsd, src, rdamage, rdamage, status_get_race(src), 0); + battle->delay_damage(tick, wd->amotion,target,src,0,CR_REFLECTSHIELD,0,rdamage,ATK_DEF,rdelay,true); + + delay += 100;/* gradual increase so the numbers don't clip in the client */ + } + wd->damage = wd->damage + wd->damage2; + wd->damage2 = 0; + status_change_end(target,SC_DEATHBOUND,INVALID_TIMER); } } - if( sc->data[SC_DEATHBOUND] && skill_id != WS_CARTTERMINATION && !is_boss(src) ) { - uint8 dir = iMap->calc_dir(bl,src->x,src->y), - t_dir = unit_getdir(bl); - - if( !iMap->check_dir(dir,t_dir) ) { - int rd1 = damage * sc->data[SC_DEATHBOUND]->val2 / 100; // Amplify damage. - trdamage += rdamage = rd1 - (*dmg = rd1 * 30 / 100); // not normalized as intended. - clif->skill_damage(src, bl, iTimer->gettick(), status_get_amotion(src), 0, -3000, 1, RK_DEATHBOUND, sc->data[SC_DEATHBOUND]->val1, 6); - skill->blown(bl, src, skill->get_blewcount(RK_DEATHBOUND, sc->data[SC_DEATHBOUND]->val1), unit_getdir(src), 0); - if( skill_id ) - status_change_end(bl, SC_DEATHBOUND, INVALID_TIMER); - rdelay = clif->damage(src, src, iTimer->gettick(), status_get_amotion(src), status_get_dmotion(src), rdamage, 1, 4, 0); + } + + if( sc->data[SC_KYOMU] ){ + // Nullify reflecting ability of the conditions onwards + return; + } + + } + + if( wd->flag & BF_SHORT ) { + if ( tsd && tsd->bonus.short_weapon_damage_return ) { + NORMALIZE_RDAMAGE(damage * tsd->bonus.short_weapon_damage_return / 100); + + rdelay = clif->delay_damage(tick+delay,src, src, status_get_amotion(src), status_get_dmotion(src), rdamage, 1, 4); + + /* is this right? rdamage as both left and right? */ + battle->drain(tsd, src, rdamage, rdamage, status_get_race(src), 0); + battle->delay_damage(tick, wd->amotion,target,src,0,CR_REFLECTSHIELD,0,rdamage,ATK_DEF,rdelay,true); + + delay += 100;/* gradual increase so the numbers don't clip in the client */ + } + + if( wd->dmg_lv >= ATK_BLOCK ) {/* yes block still applies, somehow gravity thinks it makes sense. */ + if( sc ) { + if( sc->data[SC_REFLECTSHIELD] && skill_id != WS_CARTTERMINATION ) { + NORMALIZE_RDAMAGE(damage * sc->data[SC_REFLECTSHIELD]->val2 / 100); + +#ifndef RENEWAL + rdelay = clif->delay_damage(tick+delay,src, src, status_get_amotion(src), status_get_dmotion(src), rdamage, 1, 4); +#else + rdelay = clif->skill_damage(src, src, tick, delay, status_get_dmotion(src), rdamage, 1, CR_REFLECTSHIELD, 1, 4); +#endif + /* is this right? rdamage as both left and right? */ + if( tsd ) + battle->drain(tsd, src, rdamage, rdamage, status_get_race(src), 0); + battle->delay_damage(tick, wd->amotion,target,src,0,CR_REFLECTSHIELD,0,rdamage,ATK_DEF,rdelay,true); + + delay += 100;/* gradual increase so the numbers don't clip in the client */ + } + if( sc->data[SC_LG_REFLECTDAMAGE] && rand()%100 < (30 + 10*sc->data[SC_LG_REFLECTDAMAGE]->val1) ) { + bool change = false; + + NORMALIZE_RDAMAGE(damage * sc->data[SC_LG_REFLECTDAMAGE]->val2 / 100); + + trdamage -= rdamage;/* wont count towards total */ + + if( sd && !sd->state.autocast ) { + change = true; + sd->state.autocast = 1; + } + + map->foreachinshootrange(battle->damage_area,target,skill->get_splash(LG_REFLECTDAMAGE,1),BL_CHAR,tick,target,delay,wd->dmotion,rdamage,status_get_race(target)); + + if( change ) + sd->state.autocast = 0; + + delay += 150;/* gradual increase so the numbers don't clip in the client */ + + if( (--sc->data[SC_LG_REFLECTDAMAGE]->val3) <= 0 ) + status_change_end(target, SC_LG_REFLECTDAMAGE, INVALID_TIMER); + } + if( sc->data[SC_SHIELDSPELL_DEF] && sc->data[SC_SHIELDSPELL_DEF]->val1 == 2 ){ + NORMALIZE_RDAMAGE(damage * sc->data[SC_SHIELDSPELL_DEF]->val2 / 100); + + rdelay = clif->delay_damage(tick+delay,src, src, status_get_amotion(src), status_get_dmotion(src), rdamage, 1, 4); + + /* is this right? rdamage as both left and right? */ + if( tsd ) + battle->drain(tsd, src, rdamage, rdamage, status_get_race(src), 0); + battle->delay_damage(tick, wd->amotion,target,src,0,CR_REFLECTSHIELD,0,rdamage,ATK_DEF,rdelay,true); + + delay += 100;/* gradual increase so the numbers don't clip in the client */ } } - if( sc->data[SC_SHIELDSPELL_DEF] && sc->data[SC_SHIELDSPELL_DEF]->val1 == 2 && !is_boss(src) ){ - NORMALIZE_RDAMAGE(damage * sc->data[SC_SHIELDSPELL_DEF]->val2 / 100); - rdelay = clif->damage(src, src, iTimer->gettick(), status_get_amotion(src), status_get_dmotion(src), rdamage, 1, 4, 0); + if( ( ssc = status->get_sc(src) ) ) { + if( ssc->data[SC_INSPIRATION] ) { + NORMALIZE_RDAMAGE(damage / 100); + + rdelay = clif->delay_damage(tick+delay,target, target, status_get_amotion(target), status_get_dmotion(target), rdamage, 1, 4); + + /* is this right? rdamage as both left and right? */ + if( sd ) + battle->drain(sd, target, rdamage, rdamage, status_get_race(target), 0); + battle->delay_damage(tick, wd->amotion,src,target,0,CR_REFLECTSHIELD,0,rdamage,ATK_DEF,rdelay,true); + + delay += 100;/* gradual increase so the numbers don't clip in the client */ + } } } - } else { - if (sd && sd->bonus.long_weapon_damage_return){ - NORMALIZE_RDAMAGE(damage * sd->bonus.long_weapon_damage_return / 100); - rdelay = clif->damage(src, src, iTimer->gettick(), status_get_amotion(src), status_get_dmotion(src), rdamage, 1, 4, 0); + } else {/* long */ + if ( tsd && tsd->bonus.long_weapon_damage_return ) { + NORMALIZE_RDAMAGE(damage * tsd->bonus.long_weapon_damage_return / 100); + + rdelay = clif->delay_damage(tick+delay,src, src, status_get_amotion(src), status_get_dmotion(src), rdamage, 1, 4); + + /* is this right? rdamage as both left and right? */ + battle->drain(tsd, src, rdamage, rdamage, status_get_race(src), 0); + battle->delay_damage(tick, wd->amotion,target,src,0,CR_REFLECTSHIELD,0,rdamage,ATK_DEF,rdelay,true); + + delay += 100;/* gradual increase so the numbers don't clip in the client */ } } - - if( !(sc && sc->data[SC_DEATHBOUND]) ){ - if( sc && sc->data[SC_KYOMU] ) // Nullify reflecting ability - return 0; + +#ifdef __clang_analyzer__ + // Tell Clang's static analyzer that we want to += it even the value is currently unused (it'd be used if we added new checks) + (void)delay; +#endif // __clang_analyzer + + /* something caused reflect */ + if( trdamage ) { + skill->additional_effect(target, src, CR_REFLECTSHIELD, 1, BF_WEAPON|BF_SHORT|BF_NORMAL,ATK_DEF,tick); } - return max(0, trdamage); + return; +#undef NORMALIZE_RDAMAGE } - -void battle_drain(TBL_PC *sd, struct block_list *tbl, int rdamage, int ldamage, int race, int boss) +void battle_drain(TBL_PC *sd, struct block_list *tbl, int64 rdamage, int64 ldamage, int race, int boss) { struct weapon_data *wd; - int type, thp = 0, tsp = 0, rhp = 0, rsp = 0, hp, sp, i, *damage; + int type, thp = 0, tsp = 0, rhp = 0, rsp = 0, hp, sp, i; + int64 *damage; for (i = 0; i < 4; i++) { //First two iterations: Right hand if (i < 2) { wd = &sd->right_weapon; damage = &rdamage; } @@ -5196,7 +5538,7 @@ void battle_drain(TBL_PC *sd, struct block_list *tbl, int rdamage, int ldamage, } } - if (sd->bonus.sp_vanish_rate && rnd()%1000 < sd->bonus.sp_vanish_rate) + if (sd->bonus.sp_vanish_rate && rnd()%1000 < sd->bonus.sp_vanish_rate && !sd->bonus.sp_vanish_trigger) status_percent_damage(&sd->bl, tbl, 0, (unsigned char)sd->bonus.sp_vanish_per, false); if( sd->sp_gain_race_attack[race] ) @@ -5206,20 +5548,20 @@ void battle_drain(TBL_PC *sd, struct block_list *tbl, int rdamage, int ldamage, if (!thp && !tsp) return; - status_heal(&sd->bl, thp, tsp, battle_config.show_hp_sp_drain?3:1); + status->heal(&sd->bl, thp, tsp, battle_config.show_hp_sp_drain?3:1); if (rhp || rsp) status_zap(tbl, rhp, rsp); } // Deals the same damage to targets in area. [pakpil] -int battle_damage_area( struct block_list *bl, va_list ap) { - unsigned int tick; +int battle_damage_area(struct block_list *bl, va_list ap) { + int64 tick; int amotion, dmotion, damage; struct block_list *src; nullpo_ret(bl); - tick=va_arg(ap, unsigned int); + tick = va_arg(ap, int64); src=va_arg(ap,struct block_list *); amotion=va_arg(ap,int); dmotion=va_arg(ap,int); @@ -5227,17 +5569,17 @@ int battle_damage_area( struct block_list *bl, va_list ap) { if( bl->type == BL_MOB && ((TBL_MOB*)bl)->class_ == MOBID_EMPERIUM ) return 0; if( bl != src && battle->check_target(src,bl,BCT_ENEMY) > 0 ) { - iMap->freeblock_lock(); + map->freeblock_lock(); if( src->type == BL_PC ) battle->drain((TBL_PC*)src, bl, damage, damage, status_get_race(bl), is_boss(bl)); if( amotion ) battle->delay_damage(tick, amotion,src,bl,0,CR_REFLECTSHIELD,0,damage,ATK_DEF,0,true); else status_fix_damage(src,bl,damage,0); - clif->damage(bl,bl,tick,amotion,dmotion,damage,1,ATK_BLOCK,0); + clif->damage(bl,bl,amotion,dmotion,damage,1,ATK_BLOCK,0); if( !(src && src->type == BL_PC && ((TBL_PC*)src)->state.autocast) ) skill->additional_effect(src, bl, CR_REFLECTSHIELD, 1, BF_WEAPON|BF_SHORT|BF_NORMAL,ATK_DEF,tick); - iMap->freeblock_unlock(); + map->freeblock_unlock(); } return 0; @@ -5245,11 +5587,11 @@ int battle_damage_area( struct block_list *bl, va_list ap) { /*========================================== * Do a basic physical attack (call trough unit_attack_timer) *------------------------------------------*/ -enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* target, unsigned int tick, int flag) { +enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* target, int64 tick, int flag) { struct map_session_data *sd = NULL, *tsd = NULL; struct status_data *sstatus, *tstatus; struct status_change *sc, *tsc; - int damage; + int64 damage; int skillv; struct Damage wd; @@ -5262,11 +5604,11 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t sd = BL_CAST(BL_PC, src); tsd = BL_CAST(BL_PC, target); - sstatus = status_get_status_data(src); - tstatus = status_get_status_data(target); + sstatus = status->get_status_data(src); + tstatus = status->get_status_data(target); - sc = status_get_sc(src); - tsc = status_get_sc(target); + sc = status->get_sc(src); + tsc = status->get_sc(target); if (sc && !sc->count) //Avoid sc checks when there's none to check for. [Skotlex] sc = NULL; @@ -5310,38 +5652,35 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t } } } - if (sc && sc->count) { - if (sc->data[SC_CLOAKING] && !(sc->data[SC_CLOAKING]->val4 & 2)) - status_change_end(src, SC_CLOAKING, INVALID_TIMER); - else if (sc->data[SC_CLOAKINGEXCEED] && !(sc->data[SC_CLOAKINGEXCEED]->val4 & 2)) - status_change_end(src, SC_CLOAKINGEXCEED, INVALID_TIMER); - } - if( tsc && tsc->data[SC_AUTOCOUNTER] && status_check_skilluse(target, src, KN_AUTOCOUNTER, 1) ) - { - uint8 dir = iMap->calc_dir(target,src->x,src->y); - int t_dir = unit_getdir(target); + if (sc && sc->count) { + if (sc->data[SC_CLOAKING] && !(sc->data[SC_CLOAKING]->val4 & 2)) + status_change_end(src, SC_CLOAKING, INVALID_TIMER); + else if (sc->data[SC_CLOAKINGEXCEED] && !(sc->data[SC_CLOAKINGEXCEED]->val4 & 2)) + status_change_end(src, SC_CLOAKINGEXCEED, INVALID_TIMER); + } + if( tsc && tsc->data[SC_AUTOCOUNTER] && status->check_skilluse(target, src, KN_AUTOCOUNTER, 1) ) { + uint8 dir = map->calc_dir(target,src->x,src->y); + int t_dir = unit->getdir(target); int dist = distance_bl(src, target); - if(dist <= 0 || (!iMap->check_dir(dir,t_dir) && dist <= tstatus->rhw.range+1)) - { + if(dist <= 0 || (!map->check_dir(dir,t_dir) && dist <= tstatus->rhw.range+1)) { uint16 skill_lv = tsc->data[SC_AUTOCOUNTER]->val1; clif->skillcastcancel(target); //Remove the casting bar. [Skotlex] - clif->damage(src, target, tick, sstatus->amotion, 1, 0, 1, 0, 0); //Display MISS. + clif->damage(src, target, sstatus->amotion, 1, 0, 1, 0, 0); //Display MISS. status_change_end(target, SC_AUTOCOUNTER, INVALID_TIMER); skill->attack(BF_WEAPON,target,target,src,KN_AUTOCOUNTER,skill_lv,tick,0); return ATK_BLOCK; } } - if( tsc && tsc->data[SC_BLADESTOP_WAIT] && !is_boss(src) && (src->type == BL_PC || tsd == NULL || distance_bl(src, target) <= (tsd->status.weapon == W_FIST ? 1 : 2)) ) { uint16 skill_lv = tsc->data[SC_BLADESTOP_WAIT]->val1; int duration = skill->get_time2(MO_BLADESTOP,skill_lv); status_change_end(target, SC_BLADESTOP_WAIT, INVALID_TIMER); - if(sc_start4(src, SC_BLADESTOP, 100, sd?pc->checkskill(sd, MO_BLADESTOP):5, 0, 0, target->id, duration)) - { //Target locked. - clif->damage(src, target, tick, sstatus->amotion, 1, 0, 1, 0, 0); //Display MISS. + if(sc_start4(target, src, SC_BLADESTOP, 100, sd?pc->checkskill(sd, MO_BLADESTOP):5, 0, 0, target->id, duration)) { + //Target locked. + clif->damage(src, target, sstatus->amotion, 1, 0, 1, 0, 0); //Display MISS. clif->bladestop(target, src->id, 1); - sc_start4(target, SC_BLADESTOP, 100, skill_lv, 0, 0, src->id, duration); + sc_start4(target, target, SC_BLADESTOP, 100, skill_lv, 0, 0, src->id, duration); return ATK_BLOCK; } } @@ -5369,7 +5708,7 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t /** * We need to calculate the DMG before the hp reduction, because it can kill the source. - * For futher information: bugreport:4950 + * For further information: bugreport:4950 **/ ret_val = (damage_lv)skill->attack(BF_WEAPON,src,src,target,PA_SACRIFICE,skill_lv,tick,0); @@ -5395,25 +5734,18 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t skill->get_time(MO_CALLSPIRITS, tsc->data[SC_GENTLETOUCH_ENERGYGAIN]->val1), tsc->data[SC_GENTLETOUCH_ENERGYGAIN]->val1); } - if( sc && sc->data[SC_CRUSHSTRIKE] ){ - uint16 skill_lv = sc->data[SC_CRUSHSTRIKE]->val1; - status_change_end(src, SC_CRUSHSTRIKE, INVALID_TIMER); - if( skill->attack(BF_WEAPON,src,src,target,RK_CRUSHSTRIKE,skill_lv,tick,0) ) - return ATK_DEF; - return ATK_MISS; - } + + if( tsc && tsc->data[SC_MTF_MLEATKED] && rnd()%100 < 20 ) + clif->skill_nodamage(target, target, SM_ENDURE, 5, + sc_start(target,target, SC_ENDURE, 100, 5, skill->get_time(SM_ENDURE, 5))); } if(tsc && tsc->data[SC_KAAHI] && tsc->data[SC_KAAHI]->val4 == INVALID_TIMER && tstatus->hp < tstatus->max_hp) - tsc->data[SC_KAAHI]->val4 = iTimer->add_timer(tick + skill->get_time2(SL_KAAHI,tsc->data[SC_KAAHI]->val1), kaahi_heal_timer, target->id, SC_KAAHI); //Activate heal. + tsc->data[SC_KAAHI]->val4 = timer->add(tick + skill->get_time2(SL_KAAHI,tsc->data[SC_KAAHI]->val1), status->kaahi_heal_timer, target->id, SC_KAAHI); //Activate heal. wd = battle->calc_attack(BF_WEAPON, src, target, 0, 0, flag); if( sc && sc->count ) { - if (sc->data[SC_EXEEDBREAK]) { - ATK_RATER(sc->data[SC_EXEEDBREAK]->val1) - status_change_end(src, SC_EXEEDBREAK, INVALID_TIMER); - } if( sc->data[SC_SPELLFIST] ) { if( --(sc->data[SC_SPELLFIST]->val1) >= 0 ){ struct Damage ad = battle->calc_attack(BF_MAGIC,src,target,sc->data[SC_SPELLFIST]->val3,sc->data[SC_SPELLFIST]->val4,flag|BF_SHORT); @@ -5421,8 +5753,6 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t }else status_change_end(src,SC_SPELLFIST,INVALID_TIMER); } - if( sc->data[SC_GIANTGROWTH] && (wd.flag&BF_SHORT) && rnd()%100 < sc->data[SC_GIANTGROWTH]->val2 ) - wd.damage *= 3; // Triple Damage if( sd && sc->data[SC_FEARBREEZE] && sc->data[SC_FEARBREEZE]->val4 > 0 && sd->status.inventory[sd->equip_index[EQI_AMMO]].amount >= sc->data[SC_FEARBREEZE]->val4 && battle_config.arrow_decrement){ pc->delitem(sd,sd->equip_index[EQI_AMMO],sc->data[SC_FEARBREEZE]->val4,0,1,LOG_TYPE_CONSUME); @@ -5445,7 +5775,7 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t } } - wd.dmotion = clif->damage(src, target, tick, wd.amotion, wd.dmotion, wd.damage, wd.div_ , wd.type, wd.damage2); + wd.dmotion = clif->damage(src, target, wd.amotion, wd.dmotion, wd.damage, wd.div_ , wd.type, wd.damage2); if (sd && sd->bonus.splash_range > 0 && damage > 0) skill->castend_damage_id(src, target, 0, 1, tick, 0); @@ -5454,20 +5784,26 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t if( su->group && su->group->skill_id == HT_BLASTMINE) skill->blown(src, target, 3, -1, 0); } - iMap->freeblock_lock(); - - battle->delay_damage(tick, wd.amotion, src, target, wd.flag, 0, 0, damage, wd.dmg_lv, wd.dmotion, true); + map->freeblock_lock(); + + if( skill->check_shadowform(target, damage, wd.div_) ){ + if( !status->isdead(target) ) + skill->additional_effect(src, target, 0, 0, wd.flag, wd.dmg_lv, tick); + if( wd.dmg_lv > ATK_BLOCK) + skill->counter_additional_effect(src, target, 0, 0, wd.flag,tick); + }else + battle->delay_damage(tick, wd.amotion, src, target, wd.flag, 0, 0, damage, wd.dmg_lv, wd.dmotion, true); if( tsc ) { if( tsc->data[SC_DEVOTION] ) { struct status_change_entry *sce = tsc->data[SC_DEVOTION]; - struct block_list *d_bl = iMap->id2bl(sce->val1); + struct block_list *d_bl = map->id2bl(sce->val1); if( d_bl && ( (d_bl->type == BL_MER && ((TBL_MER*)d_bl)->master && ((TBL_MER*)d_bl)->master->bl.id == target->id) || (d_bl->type == BL_PC && ((TBL_PC*)d_bl)->devotion[sce->val2] == target->id) ) && check_distance_bl(target, d_bl, sce->val3) ) { - clif->damage(d_bl, d_bl, iTimer->gettick(), 0, 0, damage, 0, 0, 0); + clif->damage(d_bl, d_bl, 0, 0, damage, 0, 0, 0); status_fix_damage(NULL, d_bl, damage, 0); } else @@ -5479,13 +5815,13 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t skill->attack(BF_MAGIC,&ed->bl,&ed->bl,src,EL_CIRCLE_OF_FIRE,tsc->data[SC_CIRCLE_OF_FIRE_OPTION]->val1,tick,wd.flag); } } else if( tsc->data[SC_WATER_SCREEN_OPTION] && tsc->data[SC_WATER_SCREEN_OPTION]->val1 ) { - struct block_list *e_bl = iMap->id2bl(tsc->data[SC_WATER_SCREEN_OPTION]->val1); - if( e_bl && !status_isdead(e_bl) ) { - clif->damage(e_bl,e_bl,tick,wd.amotion,wd.dmotion,damage,wd.div_,wd.type,wd.damage2); - status_damage(target,e_bl,damage,0,0,0); + struct block_list *e_bl = map->id2bl(tsc->data[SC_WATER_SCREEN_OPTION]->val1); + if( e_bl && !status->isdead(e_bl) ) { + clif->damage(e_bl,e_bl,wd.amotion,wd.dmotion,damage,wd.div_,wd.type,wd.damage2); + status->damage(target,e_bl,damage,0,0,0); // Just show damage in target. - clif->damage(src, target, tick, wd.amotion, wd.dmotion, damage, wd.div_, wd.type, wd.damage2 ); - iMap->freeblock_unlock(); + clif->damage(src, target, wd.amotion, wd.dmotion, damage, wd.div_, wd.type, wd.damage2 ); + map->freeblock_unlock(); return ATK_NONE; } } @@ -5502,7 +5838,7 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t if (skill_lv < 1) skill_lv = 1; sp = skill->get_sp(skill_id,skill_lv) * 2 / 3; - if (status_charge(src, 0, sp)) { + if (status->charge(src, 0, sp)) { switch (skill->get_casttype(skill_id)) { case CAST_GROUND: skill->castend_pos2(src, target->x, target->y, skill_id, skill_lv, tick, flag); @@ -5517,28 +5853,30 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t } } if (sd) { - if( wd.flag&BF_SHORT && sc && sc->data[SC__AUTOSHADOWSPELL] && rnd()%100 < sc->data[SC__AUTOSHADOWSPELL]->val3 && - sd->status.skill[skill->get_index(sc->data[SC__AUTOSHADOWSPELL]->val1)].id != 0 && sd->status.skill[skill->get_index(sc->data[SC__AUTOSHADOWSPELL]->val1)].flag == SKILL_FLAG_PLAGIARIZED ) - { - int r_skill = sd->status.skill[skill->get_index(sc->data[SC__AUTOSHADOWSPELL]->val1)].id, - r_lv = sc->data[SC__AUTOSHADOWSPELL]->val2; + if( wd.flag&BF_SHORT && sc + && sc->data[SC__AUTOSHADOWSPELL] && rnd()%100 < sc->data[SC__AUTOSHADOWSPELL]->val3 + && sd->status.skill[skill->get_index(sc->data[SC__AUTOSHADOWSPELL]->val1)].id != 0 + && sd->status.skill[skill->get_index(sc->data[SC__AUTOSHADOWSPELL]->val1)].flag == SKILL_FLAG_PLAGIARIZED + ) { + int r_skill = sd->status.skill[skill->get_index(sc->data[SC__AUTOSHADOWSPELL]->val1)].id; + int r_lv = sc->data[SC__AUTOSHADOWSPELL]->val2; if (r_skill != AL_HOLYLIGHT && r_skill != PR_MAGNUS) { int type; if( (type = skill->get_casttype(r_skill)) == CAST_GROUND ) { int maxcount = 0; - if( !(BL_PC&battle_config.skill_reiteration) && - skill->get_unit_flag(r_skill)&UF_NOREITERATION ) - type = -1; + if( !(BL_PC&battle_config.skill_reiteration) + && skill->get_unit_flag(r_skill)&UF_NOREITERATION ) + type = -1; - if( BL_PC&battle_config.skill_nofootset && - skill->get_unit_flag(r_skill)&UF_NOFOOTSET ) - type = -1; + if( BL_PC&battle_config.skill_nofootset + && skill->get_unit_flag(r_skill)&UF_NOFOOTSET ) + type = -1; - if( BL_PC&battle_config.land_skill_limit && - (maxcount = skill->get_maxcount(r_skill, r_lv)) > 0 - ) { + if( BL_PC&battle_config.land_skill_limit + && (maxcount = skill->get_maxcount(r_skill, r_lv)) > 0 + ) { int v; for(v=0;v<MAX_SKILLUNITGROUP && sd->ud.skillunit[v] && maxcount;v++) { if(sd->ud.skillunit[v]->skill_id == r_skill) @@ -5548,10 +5886,10 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t type = -1; } - if( type != CAST_GROUND ){ - clif->skill_fail(sd,r_skill,USESKILL_FAIL_LEVEL,0); - iMap->freeblock_unlock(); - return wd.dmg_lv; + if( type != CAST_GROUND ) { + clif->skill_fail(sd,r_skill,USESKILL_FAIL_LEVEL,0); + map->freeblock_unlock(); + return wd.dmg_lv; } } @@ -5584,12 +5922,14 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t } if (tsc) { - if (tsc->data[SC_POISONREACT] && - (rnd()%100 < tsc->data[SC_POISONREACT]->val3 - || sstatus->def_ele == ELE_POISON) && -// check_distance_bl(src, target, tstatus->rhw.range+1) && Doesn't checks range! o.O; - status_check_skilluse(target, src, TF_POISON, 0) - ) { //Poison React + if (tsc->data[SC_POISONREACT] + && ( rnd()%100 < tsc->data[SC_POISONREACT]->val3 + || sstatus->def_ele == ELE_POISON + ) + /* && check_distance_bl(src, target, tstatus->rhw.range+1) Doesn't check range! o.O; */ + && status->check_skilluse(target, src, TF_POISON, 0) + ) { + //Poison React struct status_change_entry *sce = tsc->data[SC_POISONREACT]; if (sstatus->def_ele == ELE_POISON) { sce->val2 = 0; @@ -5602,30 +5942,39 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t status_change_end(target, SC_POISONREACT, INVALID_TIMER); } } - iMap->freeblock_unlock(); + map->freeblock_unlock(); return wd.dmg_lv; } - -int battle_check_undead(int race,int element) +#undef ATK_RATE +#undef ATK_RATE2 +#undef ATK_RATER +#undef ATK_RATEL +#undef ATK_ADDRATE +#undef ATK_ADDRATE2 +#undef ATK_ADD +#undef ATK_ADD2 +#undef GET_NORMAL_ATTACK +#undef GET_NORMAL_ATTACK2 + +bool battle_check_undead(int race,int element) { if(battle_config.undead_detect_type == 0) { if(element == ELE_UNDEAD) - return 1; + return true; } else if(battle_config.undead_detect_type == 1) { if(race == RC_UNDEAD) - return 1; + return true; } else { if(element == ELE_UNDEAD || race == RC_UNDEAD) - return 1; + return true; } - return 0; + return false; } //Returns the upmost level master starting with the given object -struct block_list* battle_get_master(struct block_list *src) -{ +struct block_list* battle_get_master(struct block_list *src) { struct block_list *prev; //Used for infinite loop check (master of yourself?) do { prev = src; @@ -5636,7 +5985,7 @@ struct block_list* battle_get_master(struct block_list *src) break; case BL_MOB: if (((TBL_MOB*)src)->master_id) - src = iMap->id2bl(((TBL_MOB*)src)->master_id); + src = map->id2bl(((TBL_MOB*)src)->master_id); break; case BL_HOM: if (((TBL_HOM*)src)->master) @@ -5652,7 +6001,7 @@ struct block_list* battle_get_master(struct block_list *src) break; case BL_SKILL: if (((TBL_SKILL*)src)->group && ((TBL_SKILL*)src)->group->src_id) - src = iMap->id2bl(((TBL_SKILL*)src)->group->src_id); + src = map->id2bl(((TBL_SKILL*)src)->group->src_id); break; } } while (src && src != prev); @@ -5681,6 +6030,10 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f m = target->m; + if (flag&BCT_ENEMY && ( map->getcell(m,src->x,src->y,CELL_CHKBASILICA) || map->getcell(m,target->x,target->y,CELL_CHKBASILICA) ) ) { + return -1; + } + //t_bl/s_bl hold the 'master' of the attack, while src/target are the actual //objects involved. if( (t_bl = battle->get_master(target)) == NULL ) @@ -5692,7 +6045,7 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f if ( s_bl->type == BL_PC ) { switch( t_bl->type ) { case BL_MOB: // Source => PC, Target => MOB - if ( pc_has_permission((TBL_PC*)s_bl, PC_PERM_DISABLE_PVM) ) + if (pc_has_permission((TBL_PC*)s_bl, PC_PERM_DISABLE_PVM) ) return 0; break; case BL_PC: @@ -5706,7 +6059,7 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f switch( target->type ) { // Checks on actual target case BL_PC: { - struct status_change* sc = status_get_sc(src); + struct status_change* sc = status->get_sc(src); if (((TBL_PC*)target)->invincible_timer != INVALID_TIMER || pc_isinvisible((TBL_PC*)target)) return -1; //Cannot be targeted yet. if( sc && sc->count ) { @@ -5719,7 +6072,7 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f if(((((TBL_MOB*)target)->special_state.ai == 2 || //Marine Spheres (((TBL_MOB*)target)->special_state.ai == 3 && battle_config.summon_flora&1)) && //Floras s_bl->type == BL_PC && src->type != BL_MOB) || (((TBL_MOB*)target)->special_state.ai == 4 && t_bl->id != s_bl->id)) //Zanzoe - { //Targettable by players + { //Targetable by players state |= BCT_ENEMY; strip_enemy = 0; } @@ -5733,7 +6086,7 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f switch( battle->get_current_skill(src) ) { case RK_DRAGONBREATH:// it can only hit traps in pvp/gvg maps case RK_DRAGONBREATH_WATER: - if( !map[m].flag.pvp && !map[m].flag.gvg ) + if( !map->list[m].flag.pvp && !map->list[m].flag.gvg ) break; case 0://you can hit them without skills case MA_REMOVETRAP: @@ -5746,12 +6099,9 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f case MS_MAGNUM: case RA_DETONATOR: case RA_SENSITIVEKEEN: - case GN_CRAZYWEED_ATK: case RK_STORMBLAST: - case RK_PHANTOMTHRUST: case SR_RAMPAGEBLASTER: case NC_COLDSLOWER: - case NC_SELFDESTRUCTION: #ifdef RENEWAL case KN_BOWLINGBASH: case KN_SPEARSTAB: @@ -5765,19 +6115,18 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f case ASC_METEORASSAULT: case RG_RAID: case MC_CARTREVOLUTION: + case HT_CLAYMORETRAP: + case RA_ICEBOUNDTRAP: + case RA_FIRINGTRAP: #endif state |= BCT_ENEMY; strip_enemy = 0; break; default: - if(su->group->skill_id == WM_REVERBERATION || su->group->skill_id == WM_POEMOFNETHERWORLD){ - state |= BCT_ENEMY; - strip_enemy = 0; - }else - return 0; + return 0; } } else if (su->group->skill_id==WZ_ICEWALL || - su->group->skill_id == GN_WALLOFTHORN) { + su->group->skill_id == GN_WALLOFTHORN) { state |= BCT_ENEMY; strip_enemy = 0; } else //Excepting traps and icewall, you should not be able to target skills. @@ -5794,8 +6143,7 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f return 0; } //end switch actual target - switch( t_bl->type ) - { //Checks on target master + switch( t_bl->type ) { //Checks on target master case BL_PC: { struct map_session_data *sd; @@ -5803,7 +6151,7 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f sd = BL_CAST(BL_PC, t_bl); if( sd->state.monster_ignore && flag&BCT_ENEMY ) - return 0; // Global inminuty only to Attacks + return 0; // Global immunity only to Attacks if( sd->status.karma && s_bl->type == BL_PC && ((TBL_PC*)s_bl)->status.karma ) state |= BCT_ENEMY; // Characters with bad karma may fight amongst them if( sd->state.killable ) { @@ -5816,12 +6164,13 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f { struct mob_data *md = BL_CAST(BL_MOB, t_bl); - if( !((iMap->agit_flag || iMap->agit2_flag) && map[m].flag.gvg_castle) && md->guardian_data && md->guardian_data->guild_id ) + if( !((map->agit_flag || map->agit2_flag) && map->list[m].flag.gvg_castle) + && md->guardian_data && (md->guardian_data->g || md->guardian_data->castle->guild_id) ) return 0; // Disable guardians/emperiums owned by Guilds on non-woe times. break; } default: break; //other type doesn't have slave yet - } //end switch master target + } //end switch master target switch( src->type ) { //Checks on actual src type case BL_PET: @@ -5848,22 +6197,19 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f if (t_bl->type == BL_MOB && ((TBL_MOB*)t_bl)->class_ == MOBID_EMPERIUM && flag&BCT_ENEMY) return 0; //mercenary may not attack Emperium break; - } //end switch actual src + } //end switch actual src - switch( s_bl->type ) - { //Checks on source master + switch( s_bl->type ) { //Checks on source master case BL_PC: { struct map_session_data *sd = BL_CAST(BL_PC, s_bl); - if( s_bl != t_bl ) - { - if( sd->state.killer ) - { + if( s_bl != t_bl ) { + if( sd->state.killer ) { state |= BCT_ENEMY; // Can kill anything strip_enemy = 0; - } - else if( sd->duel_group && !((!battle_config.duel_allow_pvp && map[m].flag.pvp) || (!battle_config.duel_allow_gvg && map_flag_gvg(m))) ) - { + } else if( sd->duel_group + && !((!battle_config.duel_allow_pvp && map->list[m].flag.pvp) || (!battle_config.duel_allow_gvg && map_flag_gvg(m))) + ) { if( t_bl->type == BL_PC && (sd->duel_group == ((TBL_PC*)t_bl)->duel_group) ) return (BCT_ENEMY&flag)?1:-1; // Duel targets can ONLY be your enemy, nothing else. else @@ -5879,7 +6225,8 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f case BL_MOB: { struct mob_data *md = BL_CAST(BL_MOB, s_bl); - if( !((iMap->agit_flag || iMap->agit2_flag) && map[m].flag.gvg_castle) && md->guardian_data && md->guardian_data->guild_id ) + if( !((map->agit_flag || map->agit2_flag) && map->list[m].flag.gvg_castle) + && md->guardian_data && (md->guardian_data->g || md->guardian_data->castle->guild_id) ) return 0; // Disable guardians/emperium owned by Guilds on non-woe times. if( !md->special_state.ai ) @@ -5900,11 +6247,11 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f break; } default: - //Need some sort of default behaviour for unhandled types. + //Need some sort of default behavior for unhandled types. if (t_bl->type != s_bl->type) state |= BCT_ENEMY; break; - } //end switch on src master + } //end switch on src master if( (flag&BCT_ALL) == BCT_ALL ) { //All actually stands for all attackable chars @@ -5924,32 +6271,37 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f return (flag&state)?1:-1; } - if( map_flag_vs(m) ) - { //Check rivalry settings. + if( map_flag_vs(m) ) { + //Check rivalry settings. int sbg_id = 0, tbg_id = 0; - if( map[m].flag.battleground ) - { - sbg_id = bg_team_get_id(s_bl); - tbg_id = bg_team_get_id(t_bl); + if( map->list[m].flag.battleground ) { + sbg_id = bg->team_get_id(s_bl); + tbg_id = bg->team_get_id(t_bl); } - if( flag&(BCT_PARTY|BCT_ENEMY) ) - { - int s_party = status_get_party_id(s_bl); - if( s_party && s_party == status_get_party_id(t_bl) && !(map[m].flag.pvp && map[m].flag.pvp_noparty) && !(map_flag_gvg(m) && map[m].flag.gvg_noparty) && (!map[m].flag.battleground || sbg_id == tbg_id) ) + if( flag&(BCT_PARTY|BCT_ENEMY) ) { + int s_party = status->get_party_id(s_bl); + int s_guild = status->get_guild_id(s_bl); + + if( s_party && s_party == status->get_party_id(t_bl) + && !(map->list[m].flag.pvp && map->list[m].flag.pvp_noparty) + && !(map_flag_gvg(m) && map->list[m].flag.gvg_noparty && !( s_guild && s_guild == status->get_guild_id(t_bl) )) + && (!map->list[m].flag.battleground || sbg_id == tbg_id) ) state |= BCT_PARTY; else state |= BCT_ENEMY; } - if( flag&(BCT_GUILD|BCT_ENEMY) ) - { - int s_guild = status_get_guild_id(s_bl); - int t_guild = status_get_guild_id(t_bl); - if( !(map[m].flag.pvp && map[m].flag.pvp_noguild) && s_guild && t_guild && (s_guild == t_guild || (!(flag&BCT_SAMEGUILD) && guild->isallied(s_guild, t_guild))) && (!map[m].flag.battleground || sbg_id == tbg_id) ) + if( flag&(BCT_GUILD|BCT_ENEMY) ) { + int s_guild = status->get_guild_id(s_bl); + int t_guild = status->get_guild_id(t_bl); + if( !(map->list[m].flag.pvp && map->list[m].flag.pvp_noguild) + && s_guild && t_guild + && (s_guild == t_guild || (!(flag&BCT_SAMEGUILD) && guild->isallied(s_guild, t_guild))) + && (!map->list[m].flag.battleground || sbg_id == tbg_id) ) state |= BCT_GUILD; else state |= BCT_ENEMY; } - if( state&BCT_ENEMY && map[m].flag.battleground && sbg_id && sbg_id == tbg_id ) + if( state&BCT_ENEMY && map->list[m].flag.battleground && sbg_id && sbg_id == tbg_id ) state &= ~BCT_ENEMY; if( state&BCT_ENEMY && battle_config.pk_mode && !map_flag_gvg(m) && s_bl->type == BL_PC && t_bl->type == BL_PC ) @@ -5959,24 +6311,22 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f (sd->class_&MAPID_UPPERMASK) == MAPID_NOVICE || (sd2->class_&MAPID_UPPERMASK) == MAPID_NOVICE || (int)sd->status.base_level < battle_config.pk_min_level || - (int)sd2->status.base_level < battle_config.pk_min_level || + (int)sd2->status.base_level < battle_config.pk_min_level || (battle_config.pk_level_range && abs((int)sd->status.base_level - (int)sd2->status.base_level) > battle_config.pk_level_range) ) state &= ~BCT_ENEMY; } - }//end map_flag_vs chk rivality + }//end map_flag_vs chk rivality else { //Non pvp/gvg, check party/guild settings. - if( flag&BCT_PARTY || state&BCT_ENEMY ) - { - int s_party = status_get_party_id(s_bl); - if(s_party && s_party == status_get_party_id(t_bl)) + if( flag&BCT_PARTY || state&BCT_ENEMY ) { + int s_party = status->get_party_id(s_bl); + if(s_party && s_party == status->get_party_id(t_bl)) state |= BCT_PARTY; } - if( flag&BCT_GUILD || state&BCT_ENEMY ) - { - int s_guild = status_get_guild_id(s_bl); - int t_guild = status_get_guild_id(t_bl); + if( flag&BCT_GUILD || state&BCT_ENEMY ) { + int s_guild = status->get_guild_id(s_bl); + int t_guild = status->get_guild_id(t_bl); if(s_guild && t_guild && (s_guild == t_guild || (!(flag&BCT_SAMEGUILD) && guild->isallied(s_guild, t_guild)))) state |= BCT_GUILD; } @@ -5992,7 +6342,7 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f } /*========================================== * Check if can attack from this range - * Basic check then calling path_search for obstacle etc.. + * Basic check then calling path->search for obstacle etc.. *------------------------------------------*/ bool battle_check_range(struct block_list *src, struct block_list *bl, int range) { @@ -6006,7 +6356,7 @@ bool battle_check_range(struct block_list *src, struct block_list *bl, int range #ifndef CIRCULAR_AREA if( src->type == BL_PC ) { // Range for players' attacks and skills should always have a circular check. [Angezerus] int dx = src->x - bl->x, dy = src->y - bl->y; - if( !check_distance(dx, dy, range) ) + if( !path->check_distance(dx, dy, range) ) return false; } else #endif @@ -6017,12 +6367,12 @@ bool battle_check_range(struct block_list *src, struct block_list *bl, int range return true; // No need for path checking. if( d > AREA_SIZE ) - return false; // Avoid targetting objects beyond your range of sight. + return false; // Avoid targeting objects beyond your range of sight. - return path_search_long(NULL,src->m,src->x,src->y,bl->x,bl->y,CELL_CHKWALL); + return path->search_long(NULL,src->m,src->x,src->y,bl->x,bl->y,CELL_CHKWALL); } -static const struct _battle_data { +static const struct battle_data { const char* str; int* val; int defval; @@ -6287,7 +6637,6 @@ static const struct _battle_data { { "mobs_level_up_exp_rate", &battle_config.mobs_level_up_exp_rate, 1, 1, INT_MAX, }, { "pk_min_level", &battle_config.pk_min_level, 55, 1, INT_MAX, }, { "skill_steal_max_tries", &battle_config.skill_steal_max_tries, 0, 0, UCHAR_MAX, }, - { "finding_ore_rate", &battle_config.finding_ore_rate, 100, 0, INT_MAX, }, { "exp_calc_type", &battle_config.exp_calc_type, 0, 0, 1, }, { "exp_bonus_attacker", &battle_config.exp_bonus_attacker, 25, 0, INT_MAX, }, { "exp_bonus_max_attacker", &battle_config.exp_bonus_max_attacker, 12, 2, INT_MAX, }, @@ -6323,7 +6672,7 @@ static const struct _battle_data { { "duel_time_interval", &battle_config.duel_time_interval, 60, 0, INT_MAX, }, { "duel_only_on_same_map", &battle_config.duel_only_on_same_map, 0, 0, 1, }, { "skip_teleport_lv1_menu", &battle_config.skip_teleport_lv1_menu, 0, 0, 1, }, - { "mob_max_skilllvl", &battle_config.mob_max_skilllvl, 100, 1, INT_MAX, }, + { "mob_max_skilllvl", &battle_config.mob_max_skilllvl, 100, 1, INT_MAX, }, { "allow_skill_without_day", &battle_config.allow_skill_without_day, 0, 0, 1, }, { "allow_es_magic_player", &battle_config.allow_es_magic_pc, 0, 0, 1, }, { "skill_caster_check", &battle_config.skill_caster_check, 1, 0, 1, }, @@ -6365,6 +6714,7 @@ static const struct _battle_data { { "invincible.nodamage", &battle_config.invincible_nodamage, 0, 0, 1, }, { "mob_slave_keep_target", &battle_config.mob_slave_keep_target, 0, 0, 1, }, { "autospell_check_range", &battle_config.autospell_check_range, 0, 0, 1, }, + { "knockback_left", &battle_config.knockback_left, 1, 0, 1, }, { "client_reshuffle_dice", &battle_config.client_reshuffle_dice, 0, 0, 1, }, { "client_sort_storage", &battle_config.client_sort_storage, 0, 0, 1, }, { "feature.buying_store", &battle_config.feature_buying_store, 1, 0, 1, }, @@ -6375,14 +6725,16 @@ static const struct _battle_data { { "cashshop_show_points", &battle_config.cashshop_show_points, 0, 0, 1, }, { "mail_show_status", &battle_config.mail_show_status, 0, 0, 2, }, { "client_limit_unit_lv", &battle_config.client_limit_unit_lv, 0, 0, BL_ALL, }, + { "client_emblem_max_blank_percent", &battle_config.client_emblem_max_blank_percent, 100, 0, 100, }, // BattleGround Settings { "bg_update_interval", &battle_config.bg_update_interval, 1000, 100, INT_MAX, }, { "bg_flee_penalty", &battle_config.bg_flee_penalty, 20, 0, INT_MAX, }, /** * rAthena **/ - { "max_third_parameter", &battle_config.max_third_parameter, 120, 10, 10000, }, - { "max_baby_third_parameter", &battle_config.max_baby_third_parameter, 108, 10, 10000, }, + { "max_third_parameter", &battle_config.max_third_parameter, 130, 10, 10000, }, + { "max_baby_third_parameter", &battle_config.max_baby_third_parameter, 117, 10, 10000, }, + { "max_extended_parameter", &battle_config.max_extended_parameter, 125, 10, 10000, }, { "atcommand_max_stat_bypass", &battle_config.atcommand_max_stat_bypass, 0, 0, 100, }, { "skill_amotion_leniency", &battle_config.skill_amotion_leniency, 90, 0, 300 }, { "mvp_tomb_enabled", &battle_config.mvp_tomb_enabled, 1, 0, 1 }, @@ -6391,16 +6743,28 @@ static const struct _battle_data { { "atcommand_mobinfo_type", &battle_config.atcommand_mobinfo_type, 0, 0, 1 }, { "homunculus_max_level", &battle_config.hom_max_level, 99, 0, MAX_LEVEL, }, { "homunculus_S_max_level", &battle_config.hom_S_max_level, 150, 0, MAX_LEVEL, }, - { "mob_size_influence", &battle_config.mob_size_influence, 0, 0, 1, }, + { "mob_size_influence", &battle_config.mob_size_influence, 0, 0, 1, }, + { "bowling_bash_area", &battle_config.bowling_bash_area, 0, 0, 20, }, /** * Hercules **/ { "skill_trap_type", &battle_config.skill_trap_type, 0, 0, 1, }, { "item_restricted_consumption_type", &battle_config.item_restricted_consumption_type,1, 0, 1, }, - { "max_walk_path", &battle_config.max_walk_path, 17, 1, MAX_WALKPATH, }, - { "item_enabled_npc", &battle_config.item_enabled_npc, 1, 0, 1, }, - { "gm_ignore_warpable_area", &battle_config.gm_ignore_warpable_area, 0, 2, 100, }, - { "packet_obfuscation", &battle_config.packet_obfuscation, 1, 0, 3, }, + { "max_walk_path", &battle_config.max_walk_path, 17, 1, MAX_WALKPATH, }, + { "item_enabled_npc", &battle_config.item_enabled_npc, 1, 0, 1, }, + { "gm_ignore_warpable_area", &battle_config.gm_ignore_warpable_area, 0, 2, 100, }, + { "packet_obfuscation", &battle_config.packet_obfuscation, 1, 0, 3, }, + { "client_accept_chatdori", &battle_config.client_accept_chatdori, 0, 0, INT_MAX, }, + { "snovice_call_type", &battle_config.snovice_call_type, 0, 0, 1, }, + { "guild_notice_changemap", &battle_config.guild_notice_changemap, 2, 0, 2, }, + { "feature.banking", &battle_config.feature_banking, 1, 0, 1, }, + { "feature.auction", &battle_config.feature_auction, 0, 0, 2, }, + { "idletime_criteria", &battle_config.idletime_criteria, 0x25, 1, INT_MAX, }, + + { "mon_trans_disable_in_gvg", &battle_config.mon_trans_disable_in_gvg, 0, 0, 1, }, + { "case_sensitive_aegisnames", &battle_config.case_sensitive_aegisnames, 1, 0, 1, }, + { "guild_castle_invite", &battle_config.guild_castle_invite, 0, 0, 1, }, + { "guild_castle_expulsion", &battle_config.guild_castle_expulsion, 0, 0, 1, }, }; #ifndef STATS_OPT_OUT /** @@ -6409,8 +6773,6 @@ static const struct _battle_data { void Hercules_report(char* date, char *time_c) { int i, bd_size = ARRAYLENGTH(battle_data); unsigned int config = 0; - const char *svn = get_svn_revision(); - const char *git = get_git_hash(); char timestring[25]; time_t curtime; char* buf; @@ -6418,7 +6780,7 @@ void Hercules_report(char* date, char *time_c) { enum config_table { C_CIRCULAR_AREA = 0x0001, C_CELLNOSTACK = 0x0002, - C_CONSOLE_INPUT = 0x0004, + C_CONSOLE_INPUT = 0x0004, C_SCRIPT_CALLFUNC_CHECK = 0x0008, C_OFFICIAL_WALKPATH = 0x0010, C_RENEWAL = 0x0020, @@ -6429,12 +6791,15 @@ void Hercules_report(char* date, char *time_c) { C_RENEWAL_EDP = 0x0400, C_RENEWAL_ASPD = 0x0800, C_SECURE_NPCTIMEOUT = 0x1000, - C_SQL_DBS = 0x2000, + C_SQL_DB_ITEM = 0x2000, C_SQL_LOGS = 0x4000, - C_MEMWATCH = 0x8000, - C_DMALLOC = 0x10000, - C_GCOLLECT = 0x20000, - C_SEND_SHORTLIST = 0x40000, + C_MEMWATCH = 0x8000, + C_DMALLOC = 0x10000, + C_GCOLLECT = 0x20000, + C_SEND_SHORTLIST = 0x40000, + C_SQL_DB_MOB = 0x80000, + C_SQL_DB_MOBSKILL = 0x100000, + C_PACKETVER_RE = 0x200000, }; /* we get the current time */ @@ -6492,10 +6857,18 @@ void Hercules_report(char* date, char *time_c) { #ifdef SECURE_NPCTIMEOUT config |= C_SECURE_NPCTIMEOUT; #endif + +#ifdef PACKETVER_RE + config |= C_PACKETVER_RE; +#endif /* non-define part */ - if( iMap->db_use_sqldbs ) - config |= C_SQL_DBS; + if( map->db_use_sql_item_db ) + config |= C_SQL_DB_ITEM; + if( map->db_use_sql_mob_db ) + config |= C_SQL_DB_MOB; + if( map->db_use_sql_mob_skill_db ) + config |= C_SQL_DB_MOBSKILL; if( logs->config.sql_logs ) config |= C_SQL_LOGS; @@ -6516,37 +6889,47 @@ void Hercules_report(char* date, char *time_c) { #define BFLAG_LENGTH 35 - CREATE(buf, char, 6 + 12 + 9 + 24 + 41 + 4 + 4 + 4 + ( bd_size * ( BFLAG_LENGTH + 4 ) ) + 1 ); + CREATE(buf, char, 262 + ( bd_size * ( BFLAG_LENGTH + 4 ) ) + 1 ); /* build packet */ WBUFW(buf,0) = 0x3000; - WBUFW(buf,2) = 6 + 12 + 9 + 24 + 41 + 4 + 4 + 4 + ( bd_size * ( BFLAG_LENGTH + 4 ) ); - WBUFW(buf,4) = 0x9e; + WBUFW(buf,2) = 262 + ( bd_size * ( BFLAG_LENGTH + 4 ) ); + WBUFW(buf,4) = 0x9f; safestrncpy((char*)WBUFP(buf,6), date, 12); - safestrncpy((char*)WBUFP(buf,6 + 12), time_c, 9); - safestrncpy((char*)WBUFP(buf,6 + 12 + 9), timestring, 24); - - safestrncpy((char*)WBUFP(buf,6 + 12 + 9 + 24), git[0] != HERC_UNKNOWN_VER ? git : svn[0] != HERC_UNKNOWN_VER ? svn : "Unknown", 41); - WBUFL(buf,6 + 12 + 9 + 24 + 41) = iMap->getusers(); - - WBUFL(buf,6 + 12 + 9 + 24 + 41 + 4) = config; - WBUFL(buf,6 + 12 + 9 + 24 + 41 + 4 + 4) = bd_size; - + safestrncpy((char*)WBUFP(buf,18), time_c, 9); + safestrncpy((char*)WBUFP(buf,27), timestring, 24); + + safestrncpy((char*)WBUFP(buf,51), sysinfo->platform(), 16); + safestrncpy((char*)WBUFP(buf,67), sysinfo->osversion(), 50); + safestrncpy((char*)WBUFP(buf,117), sysinfo->cpu(), 32); + WBUFL(buf,149) = sysinfo->cpucores(); + safestrncpy((char*)WBUFP(buf,153), sysinfo->arch(), 8); + WBUFB(buf,161) = sysinfo->vcstypeid(); + WBUFB(buf,162) = sysinfo->is64bit(); + safestrncpy((char*)WBUFP(buf,163), sysinfo->vcsrevision_src(), 41); + safestrncpy((char*)WBUFP(buf,204), sysinfo->vcsrevision_scripts(), 41); + WBUFB(buf,245) = (sysinfo->is_superuser()? 1 : 0); + WBUFL(buf,246) = map->getusers(); + + WBUFL(buf,250) = config; + WBUFL(buf,254) = PACKETVER; + + WBUFL(buf,258) = bd_size; for( i = 0; i < bd_size; i++ ) { - safestrncpy((char*)WBUFP(buf,6 + 12 + 9 + 24 + 41 + 4 + 4 + 4 + ( i * ( BFLAG_LENGTH + 4 ) ) ), battle_data[i].str, 35); - WBUFL(buf,6 + 12 + 9 + 24 + 41 + 4 + 4 + 4 + BFLAG_LENGTH + ( i * ( BFLAG_LENGTH + 4 ) ) ) = *battle_data[i].val; + safestrncpy((char*)WBUFP(buf,262 + ( i * ( BFLAG_LENGTH + 4 ) ) ), battle_data[i].str, BFLAG_LENGTH); + WBUFL(buf,262 + BFLAG_LENGTH + ( i * ( BFLAG_LENGTH + 4 ) ) ) = *battle_data[i].val; } - chrif_send_report(buf, 6 + 12 + 9 + 24 + 41 + 4 + 4 + 4 + ( bd_size * ( BFLAG_LENGTH + 4 ) ) ); + chrif->send_report(buf, 262 + ( bd_size * ( BFLAG_LENGTH + 4 ) ) ); aFree(buf); #undef BFLAG_LENGTH } -static int Hercules_report_timer(int tid, unsigned int tick, int id, intptr_t data) { - if( chrif_isconnected() ) {/* char server relays it, so it must be online. */ +static int Hercules_report_timer(int tid, int64 tick, int id, intptr_t data) { + if( chrif->isconnected() ) {/* char server relays it, so it must be online. */ Hercules_report(__DATE__,__TIME__); } return 0; @@ -6559,8 +6942,11 @@ int battle_set_value(const char* w1, const char* w2) int i; ARR_FIND(0, ARRAYLENGTH(battle_data), i, strcmpi(w1, battle_data[i].str) == 0); - if (i == ARRAYLENGTH(battle_data)) + if (i == ARRAYLENGTH(battle_data)) { + if( HPM->parseConf(w1,w2,HPCT_BATTLE) ) /* if plugin-owned, succeed */ + return 1; return 0; // not found + } if (val < battle_data[i].min || val > battle_data[i].max) { @@ -6622,6 +7008,22 @@ void battle_adjust_conf(void) { battle_config.feature_search_stores = 0; } #endif + +#if PACKETVER < 20130724 + if( battle_config.feature_banking ) { + ShowWarning("conf/battle/feature.conf banking is enabled but it requires PACKETVER 2013-07-24 or newer, disabling...\n"); + battle_config.feature_banking = 0; + } +#endif + +#if PACKETVER > 20120000 && PACKETVER < 20130515 /* exact date (when it started) not known */ + if( battle_config.feature_auction == 1 ) { + ShowWarning("conf/battle/feature.conf:feature.auction is enabled but it is not stable on PACKETVER "EXPAND_AND_QUOTE(PACKETVER)", disabling...\n"); + ShowWarning("conf/battle/feature.conf:feature.auction change value to '2' to silence this warning and maintain it enabled\n"); + battle_config.feature_auction = 0; + } +#endif + #ifndef CELL_NOSTACK if (battle_config.cell_stack_limit != 1) @@ -6671,19 +7073,22 @@ int battle_config_read(const char* cfgName) return 0; } -void do_init_battle(void) { - delay_damage_ers = ers_new(sizeof(struct delay_damage),"battle.c::delay_damage_ers",ERS_OPT_CLEAR); - iTimer->add_timer_func_list(battle_delay_damage_sub, "battle_delay_damage_sub"); +void do_init_battle(bool minimal) { + if (minimal) + return; + + battle->delay_damage_ers = ers_new(sizeof(struct delay_damage),"battle.c::delay_damage_ers",ERS_OPT_CLEAR); + timer->add_func_list(battle->delay_damage_sub, "battle_delay_damage_sub"); #ifndef STATS_OPT_OUT - iTimer->add_timer_func_list(Hercules_report_timer, "Hercules_report_timer"); - iTimer->add_timer_interval(iTimer->gettick()+30000, Hercules_report_timer, 0, 0, 60000 * 30); + timer->add_func_list(Hercules_report_timer, "Hercules_report_timer"); + timer->add_interval(timer->gettick()+30000, Hercules_report_timer, 0, 0, 60000 * 30); #endif } void do_final_battle(void) { - ers_destroy(delay_damage_ers); + ers_destroy(battle->delay_damage_ers); } /* initialize the interface */ @@ -6692,6 +7097,9 @@ void battle_defaults(void) { battle->bc = &battle_config; + memset(battle->attr_fix_table, 0, sizeof(battle->attr_fix_table)); + battle->delay_damage_ers = NULL; + battle->init = do_init_battle; battle->final = do_final_battle; @@ -6699,25 +7107,21 @@ void battle_defaults(void) { battle->calc_damage = battle_calc_damage; battle->calc_gvg_damage = battle_calc_gvg_damage; battle->calc_bg_damage = battle_calc_bg_damage; - battle->calc_base_damage = battle_calc_base_damage; - battle->calc_misc_attack = battle_calc_misc_attack; - battle->calc_magic_attack = battle_calc_magic_attack; battle->weapon_attack = battle_weapon_attack; + battle->calc_weapon_attack = battle_calc_weapon_attack; battle->delay_damage = battle_delay_damage; battle->drain = battle_drain; - battle->calc_return_damage = battle_calc_return_damage; - battle->calc_weapon_attack = battle_calc_weapon_attack; -#ifdef RENEWAL - battle->calc_weapon_damage = battle_calc_weapon_damage; -#endif - battle->calc_defense = battle_calc_defense; + battle->reflect_damage = battle_reflect_damage; battle->attr_ratio = battle_attr_ratio; battle->attr_fix = battle_attr_fix; battle->calc_cardfix = battle_calc_cardfix; battle->calc_elefix = battle_calc_elefix; battle->calc_masteryfix = battle_calc_masteryfix; + battle->calc_chorusbonus = battle_calc_chorusbonus; battle->calc_skillratio = battle_calc_skillratio; battle->calc_sizefix = battle_calc_sizefix; + battle->calc_weapon_damage = battle_calc_weapon_damage; + battle->calc_defense = battle_calc_defense; battle->get_master = battle_get_master; battle->get_targeted = battle_gettargeted; battle->get_enemy = battle_getenemy; @@ -6733,6 +7137,10 @@ void battle_defaults(void) { battle->delay_damage_sub = battle_delay_damage_sub; battle->blewcount_bonus = battle_blewcount_bonus; battle->range_type = battle_range_type; + battle->calc_base_damage = battle_calc_base_damage; + battle->calc_base_damage2 = battle_calc_base_damage2; + battle->calc_misc_attack = battle_calc_misc_attack; + battle->calc_magic_attack = battle_calc_magic_attack; battle->adjust_skill_damage = battle_adjust_skill_damage; battle->add_mastery = battle_addmastery; battle->calc_drain = battle_calc_drain; diff --git a/src/map/battle.h b/src/map/battle.h index 7d41a02c5..dfa156796 100644 --- a/src/map/battle.h +++ b/src/map/battle.h @@ -2,8 +2,11 @@ // See the LICENSE file // Portions Copyright (c) Athena Dev Teams -#ifndef _BATTLE_H_ -#define _BATTLE_H_ +#ifndef MAP_BATTLE_H +#define MAP_BATTLE_H + +#include "map.h" //ELE_MAX +#include "../common/cbasetypes.h" /** * Declarations @@ -18,14 +21,14 @@ struct status_data; /** * Defines **/ -#define MIN_HAIR_STYLE battle_config.min_hair_style -#define MAX_HAIR_STYLE battle_config.max_hair_style -#define MIN_HAIR_COLOR battle_config.min_hair_color -#define MAX_HAIR_COLOR battle_config.max_hair_color -#define MIN_CLOTH_COLOR battle_config.min_cloth_color -#define MAX_CLOTH_COLOR battle_config.max_cloth_color +#define MIN_HAIR_STYLE (battle->bc->min_hair_style) +#define MAX_HAIR_STYLE (battle->bc->max_hair_style) +#define MIN_HAIR_COLOR (battle->bc->min_hair_color) +#define MAX_HAIR_COLOR (battle->bc->max_hair_color) +#define MIN_CLOTH_COLOR (battle->bc->min_cloth_color) +#define MAX_CLOTH_COLOR (battle->bc->max_cloth_color) -#define is_boss(bl) (status_get_mode(bl)&MD_BOSS) // Can refine later [Aru] +#define is_boss(bl) (status_get_mode(bl)&MD_BOSS) // Can refine later [Aru] /** * Enumerations @@ -55,28 +58,30 @@ typedef enum damage_lv { } damage_lv; enum e_battle_check_target { //New definitions [Skotlex] - BCT_NOONE = 0x000000, - BCT_SELF = 0x010000, - BCT_ENEMY = 0x020000, - BCT_PARTY = 0x040000, - BCT_GUILD = 0x080000, - BCT_NEUTRAL = 0x100000, - BCT_SAMEGUILD = 0x200000, // No Guild Allies - - BCT_NOGUILD = 0x170000, // This should be (~BCT_GUILD&BCT_ALL) - BCT_NOPARTY = 0x1b0000, // This should be (~BCT_PARTY&BCT_ALL) - BCT_NOENEMY = 0x1d0000, // This should be (~BCT_ENEMY&BCT_ALL) + BCT_NOONE = 0x000000, + BCT_SELF = 0x010000, + BCT_ENEMY = 0x020000, + BCT_PARTY = 0x040000, + BCT_GUILDALLY = 0x080000, // Only allies, NOT guildmates + BCT_NEUTRAL = 0x100000, + BCT_SAMEGUILD = 0x200000, // No Guild Allies + + BCT_GUILD = 0x280000, // Guild AND allies (BCT_SAMEGUILD|BCT_GUILDALLY) - BCT_ALL = 0x1f0000, // Sum of BCT_NOONE to BCT_NEUTRAL + BCT_NOGUILD = 0x170000, // This should be (~BCT_GUILD&BCT_ALL) + BCT_NOPARTY = 0x3b0000, // This should be (~BCT_PARTY&BCT_ALL) + BCT_NOENEMY = 0x3d0000, // This should be (~BCT_ENEMY&BCT_ALL) + + BCT_ALL = 0x3f0000, // Sum of BCT_NOONE to BCT_SAMEGUILD }; /** * Structures **/ -// dammage structure +// damage structure struct Damage { - int damage,damage2; //right, left dmg + int64 damage,damage2; //right, left dmg int type,div_; //chk clif_damage for type @TODO add an enum ? ; nb of hit int amotion,dmotion; int blewcount; //nb of knockback @@ -325,7 +330,6 @@ struct Battle_Config { int mobs_level_up_exp_rate; // [Valaris] int pk_min_level; // [celest] int skill_steal_max_tries; //max steal skill tries on a mob. if 0, then w/o limit [Lupus] - int finding_ore_rate; // orn int exp_calc_type; int exp_bonus_attacker; int exp_bonus_max_attacker; @@ -412,6 +416,7 @@ struct Battle_Config { int invincible_nodamage; int mob_slave_keep_target; int autospell_check_range; //Enable range check for autospell bonus. [L0ne_W0lf] + int knockback_left; int client_reshuffle_dice; // Reshuffle /dice int client_sort_storage; int feature_buying_store; @@ -422,6 +427,7 @@ struct Battle_Config { int cashshop_show_points; int mail_show_status; int client_limit_unit_lv; + int client_emblem_max_blank_percent; int hom_max_level; int hom_S_max_level; @@ -432,6 +438,7 @@ struct Battle_Config { // rAthena int max_third_parameter; int max_baby_third_parameter; + int max_extended_parameter; int atcommand_max_stat_bypass; int max_third_aspd; int vcast_stat_scale; @@ -439,28 +446,65 @@ struct Battle_Config { int mvp_tomb_enabled; int atcommand_suggestions_enabled; - int min_npc_vendchat_distance; + int min_npc_vendchat_distance; int atcommand_mobinfo_type; int mob_size_influence; // Enable modifications on earned experience, drop rates and monster status depending on monster size. [mkbu95] - + int bowling_bash_area; + /** Hercules **/ int skill_trap_type; int item_restricted_consumption_type; int max_walk_path; int item_enabled_npc; int packet_obfuscation; - + int idletime_criteria; int gm_ignore_warpable_area; -} battle_config; + int client_accept_chatdori; // [Ai4rei/Mirei] + int snovice_call_type; + int guild_notice_changemap; + + int feature_banking; + int feature_auction; + int mon_trans_disable_in_gvg; -/** - * Vars - **/ -//attribute table -extern int attr_fix_table[4][10][10]; + int case_sensitive_aegisnames; + int guild_castle_invite; + int guild_castle_expulsion; +}; + +extern struct Battle_Config battle_config; + +/* criteria for battle_config.idletime_critera */ +enum e_battle_config_idletime { + BCIDLE_WALK = 0x001, + BCIDLE_USESKILLTOID = 0x002, + BCIDLE_USESKILLTOPOS = 0x004, + BCIDLE_USEITEM = 0x008, + BCIDLE_ATTACK = 0x010, + BCIDLE_CHAT = 0x020, + BCIDLE_SIT = 0x040, + BCIDLE_EMOTION = 0x080, + BCIDLE_DROPITEM = 0x100, + BCIDLE_ATCOMMAND = 0x200, +}; + +// Damage delayed info +struct delay_damage { + int src_id; + int target_id; + int64 damage; + int delay; + unsigned short distance; + uint16 skill_lv; + uint16 skill_id; + enum damage_lv dmg_lv; + unsigned short attack_type; + bool additional_effects; + enum bl_type src_type; +}; /** * Battle.c Interface @@ -468,48 +512,51 @@ extern int attr_fix_table[4][10][10]; struct battle_interface { /* */ struct Battle_Config *bc; + /* */ + int attr_fix_table[4][ELE_MAX][ELE_MAX]; + struct eri *delay_damage_ers; //For battle delay damage structures. /* init */ - void (*init) (void); + void (*init) (bool minimal); /* final */ void (*final) (void); /* damage calculation */ struct Damage (*calc_attack) (int attack_type, struct block_list *bl, struct block_list *target, uint16 skill_id, uint16 skill_lv, int count); /* generic final damage calculation */ - int (*calc_damage) (struct block_list *src, struct block_list *bl, struct Damage *d, int damage, uint16 skill_id, uint16 skill_lv); + int64 (*calc_damage) (struct block_list *src, struct block_list *bl, struct Damage *d, int64 damage, uint16 skill_id, uint16 skill_lv); /* gvg final damage calculation */ - int (*calc_gvg_damage) (struct block_list *src, struct block_list *bl, int damage, int div_, uint16 skill_id, uint16 skill_lv, int flag); + int64 (*calc_gvg_damage) (struct block_list *src, struct block_list *bl, int64 damage, int div_, uint16 skill_id, uint16 skill_lv, int flag); /* battlegrounds final damage calculation */ - int (*calc_bg_damage) (struct block_list *src, struct block_list *bl, int damage, int div_, uint16 skill_id, uint16 skill_lv, int flag); + 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, unsigned int tick, int flag); + enum damage_lv (*weapon_attack) (struct block_list *bl, struct block_list *target, int64 tick, int flag); /* 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 */ - int (*delay_damage) (unsigned int tick, int amotion, struct block_list *src, struct block_list *target, int attack_type, uint16 skill_id, uint16 skill_lv, int damage, enum damage_lv dmg_lv, int ddelay, bool additional_effects); + int (*delay_damage) (int64 tick, int amotion, struct block_list *src, struct block_list *target, int attack_type, uint16 skill_id, uint16 skill_lv, int64 damage, enum damage_lv dmg_lv, int ddelay, bool additional_effects); /* drain damage */ - void (*drain) (struct map_session_data *sd, struct block_list *tbl, int rdamage, int ldamage, int race, int boss); - /* damage return/reflect */ - int (*calc_return_damage) (struct block_list *bl, struct block_list *src, int *, int flag, uint16 skill_id, int*); + void (*drain) (struct map_session_data *sd, struct block_list *tbl, int64 rdamage, int64 ldamage, int race, int boss); + /* damage reflect */ + void (*reflect_damage) (struct block_list *target, struct block_list *src, struct Damage *wd,uint16 skill_id); /* attribute rate */ int (*attr_ratio) (int atk_elem, int def_type, int def_lv); /* applies attribute modifiers */ - int (*attr_fix) (struct block_list *src, struct block_list *target, int damage, int atk_elem, int def_type, int def_lv); + int64 (*attr_fix) (struct block_list *src, struct block_list *target, int64 damage, int atk_elem, int def_type, int def_lv); /* applies card modifiers */ - int (*calc_cardfix) (int attack_type, struct block_list *src, struct block_list *target, int nk, int s_ele, int s_ele_, int damage, int left, int flag); - /* applies element modifiers */ - int (*calc_elefix) (struct block_list *src, struct block_list *target, uint16 skill_id, uint16 skill_lv, int damage, int nk, int n_ele, int s_ele, int s_ele_, bool left, int flag); - /* applies mastery modifiers */ - int (*calc_masteryfix) (struct block_list *src, struct block_list *target, uint16 skill_id, uint16 skill_lv, int damage, int div, bool left, bool weapon); - /* applies skill modifiers */ + int64 (*calc_cardfix) (int attack_type, struct block_list *src, struct block_list *target, int nk, int s_ele, int s_ele_, int64 damage, int left, int flag); + /* applies element modifiers */ + int64 (*calc_elefix) (struct block_list *src, struct block_list *target, uint16 skill_id, uint16 skill_lv, int64 damage, int nk, int n_ele, int s_ele, int s_ele_, bool left, int flag); + /* applies mastery modifiers */ + int64 (*calc_masteryfix) (struct block_list *src, struct block_list *target, uint16 skill_id, uint16 skill_lv, int64 damage, int div, bool left, bool weapon); + /* calculates chorus bonus */ + int (*calc_chorusbonus) (struct map_session_data *sd); + /* applies skill modifiers */ int (*calc_skillratio) (int attack_type, struct block_list *src, struct block_list *target, uint16 skill_id, uint16 skill_lv, int skillratio, int flag); /* applies size modifiers */ - int (*calc_sizefix) (struct map_session_data *sd, int damage, int type, int size, bool ignore); -#ifdef RENEWAL + int64 (*calc_sizefix) (struct map_session_data *sd, int64 damage, int type, int size, bool ignore); /* get weapon damage */ - int (*calc_weapon_damage) (struct block_list *src, struct block_list *bl, uint16 skill_id, uint16 skill_lv, struct weapon_atk *watk, int nk, bool n_ele, short s_ele, short s_ele_, int size, int type, int flag, int flag2); -#endif + int64 (*calc_weapon_damage) (struct block_list *src, struct block_list *bl, uint16 skill_id, uint16 skill_lv, struct weapon_atk *watk, int nk, bool n_ele, short s_ele, short s_ele_, int size, int type, int flag, int flag2); /* applies defense reductions */ - int (*calc_defense) (int attack_type, struct block_list *src, struct block_list *target, uint16 skill_id, uint16 skill_lv, int damage, int flag, int pdef); + int64 (*calc_defense) (int attack_type, struct block_list *src, struct block_list *target, uint16 skill_id, uint16 skill_lv, int64 damage, int flag, int pdef); /* get master (who does this unit respond to?) */ struct block_list *(*get_master) (struct block_list *src); /* returns a random unit who is targeting this unit */ @@ -521,31 +568,27 @@ struct battle_interface { /* the current skill being processed/casted by this unit */ int (*get_current_skill) (struct block_list *bl); /* is either this race or element enough to be considered undead? */ - int (*check_undead) (int race,int element); + bool (*check_undead) (int race,int element); /* check if src and target are part of flag (e.g. enemies or allies) */ int (*check_target) (struct block_list *src, struct block_list *target,int flag); /* is src and bl within range? */ bool (*check_range) (struct block_list *src,struct block_list *bl,int range); - /* consume amo for this skill and lv */ - void (*consume_ammo) (struct map_session_data* sd, int skill, int lv); + /* consume ammo for this skill and lv */ + void (*consume_ammo) (struct map_session_data* sd, int skill_id, int lv); int (*get_targeted_sub) (struct block_list *bl, va_list ap); int (*get_enemy_sub) (struct block_list *bl, va_list ap); int (*get_enemy_area_sub) (struct block_list *bl, va_list ap); - int (*delay_damage_sub) (int tid, unsigned int tick, int id, intptr_t data); + int (*delay_damage_sub) (int tid, int64 tick, int id, intptr_t data); int (*blewcount_bonus) (struct map_session_data *sd, uint16 skill_id); /* skill range criteria */ int (*range_type) (struct block_list *src, struct block_list *target, uint16 skill_id, uint16 skill_lv); - int (*calc_base_damage) -#ifdef RENEWAL - (struct block_list *src, struct block_list *bl, uint16 skill_id, uint16 skill_lv, int nk, bool n_ele, short s_ele, short s_ele_, int type, int flag, int flag2); -#else - (struct status_data *status, struct weapon_atk *wa, struct status_change *sc, unsigned short t_size, struct map_session_data *sd, int flag); -#endif + int64 (*calc_base_damage) (struct block_list *src, struct block_list *bl, uint16 skill_id, uint16 skill_lv, int nk, bool n_ele, short s_ele, short s_ele_, int type, int flag, int flag2); + int64 (*calc_base_damage2) (struct status_data *st, struct weapon_atk *wa, struct status_change *sc, unsigned short t_size, struct map_session_data *sd, int flag); struct Damage (*calc_misc_attack) (struct block_list *src,struct block_list *target,uint16 skill_id,uint16 skill_lv,int mflag); struct Damage (*calc_magic_attack) (struct block_list *src,struct block_list *target,uint16 skill_id,uint16 skill_lv,int mflag); int (*adjust_skill_damage) (int m, unsigned short skill_id); - int (*add_mastery) (struct map_session_data *sd,struct block_list *target,int dmg,int type); - int (*calc_drain) (int damage, int rate, int per); + int64 (*add_mastery) (struct map_session_data *sd,struct block_list *target,int64 dmg,int type); + int (*calc_drain) (int64 damage, int rate, int per); /* - battle_config */ int (*config_read) (const char *cfgName); void (*config_set_defaults) (void); @@ -556,10 +599,10 @@ struct battle_interface { /* picks a random enemy within the specified range */ struct block_list* (*get_enemy_area) (struct block_list *src, int x, int y, int range, int type, int ignore_id); /* damages area, originally for royal guard's reflect damage */ - int (*damage_area) ( struct block_list *bl, va_list ap); -} battle_s; + int (*damage_area) (struct block_list *bl, va_list ap); +}; struct battle_interface *battle; void battle_defaults(void); -#endif /* _BATTLE_H_ */ +#endif /* MAP_BATTLE_H */ diff --git a/src/map/battleground.c b/src/map/battleground.c index 64bc25269..f7131513d 100644 --- a/src/map/battleground.c +++ b/src/map/battleground.c @@ -2,179 +2,204 @@ // See the LICENSE file // Portions Copyright (c) Athena Dev Teams -#include "../common/cbasetypes.h" -#include "../common/timer.h" -#include "../common/malloc.h" -#include "../common/nullpo.h" -#include "../common/showmsg.h" -#include "../common/socket.h" -#include "../common/strlib.h" -#include "../common/conf.h" +#define HERCULES_CORE #include "battleground.h" + +#include <stdio.h> +#include <string.h> + #include "battle.h" #include "clif.h" +#include "homunculus.h" #include "map.h" +#include "mapreg.h" +#include "mercenary.h" +#include "mob.h" // struct mob_data #include "npc.h" -#include "pc.h" #include "party.h" +#include "pc.h" #include "pet.h" -#include "homunculus.h" -#include "mercenary.h" - -#include <string.h> -#include <stdio.h> +#include "../common/cbasetypes.h" +#include "../common/conf.h" +#include "../common/malloc.h" +#include "../common/nullpo.h" +#include "../common/showmsg.h" +#include "../common/socket.h" +#include "../common/strlib.h" +#include "../common/timer.h" -static DBMap* bg_team_db; // int bg_id -> struct battleground_data* -static unsigned int bg_team_counter = 0; // Next bg_id +struct battleground_interface bg_s; -struct battleground_data* bg_team_search(int bg_id) { // Search a BG Team using bg_id +/// Search a BG Team using bg_id +struct battleground_data* bg_team_search(int bg_id) { if( !bg_id ) return NULL; - return (struct battleground_data *)idb_get(bg_team_db, bg_id); + return (struct battleground_data *)idb_get(bg->team_db, bg_id); } -struct map_session_data* bg_getavailablesd(struct battleground_data *bg) { +struct map_session_data* bg_getavailablesd(struct battleground_data *bgd) { int i; - nullpo_retr(NULL, bg); - ARR_FIND(0, MAX_BG_MEMBERS, i, bg->members[i].sd != NULL); - return( i < MAX_BG_MEMBERS ) ? bg->members[i].sd : NULL; + nullpo_retr(NULL, bgd); + ARR_FIND(0, MAX_BG_MEMBERS, i, bgd->members[i].sd != NULL); + return( i < MAX_BG_MEMBERS ) ? bgd->members[i].sd : NULL; } -int bg_team_delete(int bg_id) -{ // Deletes BG Team from db +/// Deletes BG Team from db +bool bg_team_delete(int bg_id) { int i; struct map_session_data *sd; - struct battleground_data *bg = bg_team_search(bg_id); + struct battleground_data *bgd = bg->team_search(bg_id); - if( bg == NULL ) return 0; - for( i = 0; i < MAX_BG_MEMBERS; i++ ) - { - if( (sd = bg->members[i].sd) == NULL ) + if( bgd == NULL ) return false; + for( i = 0; i < MAX_BG_MEMBERS; i++ ) { + if( (sd = bgd->members[i].sd) == NULL ) continue; - bg_send_dot_remove(sd); + bg->send_dot_remove(sd); sd->bg_id = 0; } - idb_remove(bg_team_db, bg_id); - return 1; + idb_remove(bg->team_db, bg_id); + return true; } -int bg_team_warp(int bg_id, unsigned short mapindex, short x, short y) -{ // Warps a Team +/// Warps a Team +bool bg_team_warp(int bg_id, unsigned short map_index, short x, short y) { int i; - struct battleground_data *bg = bg_team_search(bg_id); - if( bg == NULL ) return 0; + struct battleground_data *bgd = bg->team_search(bg_id); + if( bgd == NULL ) return false; for( i = 0; i < MAX_BG_MEMBERS; i++ ) - if( bg->members[i].sd != NULL ) pc->setpos(bg->members[i].sd, mapindex, x, y, CLR_TELEPORT); - return 1; + if( bgd->members[i].sd != NULL ) pc->setpos(bgd->members[i].sd, map_index, x, y, CLR_TELEPORT); + return true; } -int bg_send_dot_remove(struct map_session_data *sd) -{ +void bg_send_dot_remove(struct map_session_data *sd) { if( sd && sd->bg_id ) clif->bg_xy_remove(sd); - return 0; } -int bg_team_join(int bg_id, struct map_session_data *sd) -{ // Player joins team +/// Player joins team +bool bg_team_join(int bg_id, struct map_session_data *sd) { int i; - struct battleground_data *bg = bg_team_search(bg_id); + struct battleground_data *bgd = bg->team_search(bg_id); struct map_session_data *pl_sd; - if( bg == NULL || sd == NULL || sd->bg_id ) return 0; + if( bgd == NULL || sd == NULL || sd->bg_id ) return false; - ARR_FIND(0, MAX_BG_MEMBERS, i, bg->members[i].sd == NULL); - if( i == MAX_BG_MEMBERS ) return 0; // No free slots + ARR_FIND(0, MAX_BG_MEMBERS, i, bgd->members[i].sd == NULL); + if( i == MAX_BG_MEMBERS ) return false; // No free slots sd->bg_id = bg_id; - bg->members[i].sd = sd; - bg->members[i].x = sd->bl.x; - bg->members[i].y = sd->bl.y; - bg->count++; + bgd->members[i].sd = sd; + bgd->members[i].x = sd->bl.x; + bgd->members[i].y = sd->bl.y; + /* populate 'where i came from' */ + if(map->list[sd->bl.m].flag.nosave || map->list[sd->bl.m].instance_id >= 0) { + struct map_data *m=&map->list[sd->bl.m]; + if(m->save.map) + memcpy(&bgd->members[i].source,&m->save,sizeof(struct point)); + else + memcpy(&bgd->members[i].source,&sd->status.save_point,sizeof(struct point)); + } else + memcpy(&bgd->members[i].source,&sd->status.last_point,sizeof(struct point)); + bgd->count++; guild->send_dot_remove(sd); for( i = 0; i < MAX_BG_MEMBERS; i++ ) { - if( (pl_sd = bg->members[i].sd) != NULL && pl_sd != sd ) + if( (pl_sd = bgd->members[i].sd) != NULL && pl_sd != sd ) clif->hpmeter_single(sd->fd, pl_sd->bl.id, pl_sd->battle_status.hp, pl_sd->battle_status.max_hp); } clif->bg_hp(sd); clif->bg_xy(sd); - return 1; + return true; } -int bg_team_leave(struct map_session_data *sd, int flag) -{ // Single Player leaves team +/// Single Player leaves team +int bg_team_leave(struct map_session_data *sd, enum bg_team_leave_type flag) { int i, bg_id; - struct battleground_data *bg; + struct battleground_data *bgd; char output[128]; if( sd == NULL || !sd->bg_id ) return 0; - - bg_send_dot_remove(sd); + bg->send_dot_remove(sd); bg_id = sd->bg_id; sd->bg_id = 0; - if( (bg = bg_team_search(bg_id)) == NULL ) + if( (bgd = bg->team_search(bg_id)) == NULL ) return 0; - ARR_FIND(0, MAX_BG_MEMBERS, i, bg->members[i].sd == sd); - if( i < MAX_BG_MEMBERS ) // Removes member from BG - memset(&bg->members[i], 0, sizeof(bg->members[0])); - bg->count--; - - if( flag ) - sprintf(output, "Server : %s has quit the game...", sd->status.name); - else - sprintf(output, "Server : %s is leaving the battlefield...", sd->status.name); - clif->bg_message(bg, 0, "Server", output, strlen(output) + 1); + ARR_FIND(0, MAX_BG_MEMBERS, i, bgd->members[i].sd == sd); + if( i < MAX_BG_MEMBERS ) { // Removes member from BG + if( sd->bg_queue.arena ) { + bg->queue_pc_cleanup(sd); + pc->setpos(sd,bgd->members[i].source.map, bgd->members[i].source.x, bgd->members[i].source.y, CLR_OUTSIGHT); + } + memset(&bgd->members[i], 0, sizeof(bgd->members[0])); + } - if( bg->logout_event[0] && flag ) - npc_event(sd, bg->logout_event, 0); + if( --bgd->count != 0 ) { + switch( flag ) { + default: + case BGTL_QUIT: + sprintf(output, "Server : %s has quit the game...", sd->status.name); + break; + case BGTL_LEFT: + sprintf(output, "Server : %s is leaving the battlefield...", sd->status.name); + break; + case BGTL_AFK: + 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); + } - return bg->count; + if( bgd->logout_event[0] && flag ) + npc->event(sd, bgd->logout_event, 0); + + if( sd->bg_queue.arena ) { + bg->queue_pc_cleanup(sd); + } + + return bgd->count; } -int bg_member_respawn(struct map_session_data *sd) -{ // Respawn after killed - struct battleground_data *bg; - if( sd == NULL || !pc_isdead(sd) || !sd->bg_id || (bg = bg_team_search(sd->bg_id)) == NULL ) - return 0; - if( bg->mapindex == 0 ) - return 0; // Respawn not handled by Core - pc->setpos(sd, bg->mapindex, bg->x, bg->y, CLR_OUTSIGHT); - status_revive(&sd->bl, 1, 100); - - return 1; // Warped +/// Respawn after killed +bool bg_member_respawn(struct map_session_data *sd) { + struct battleground_data *bgd; + if( sd == NULL || !pc_isdead(sd) || !sd->bg_id || (bgd = bg->team_search(sd->bg_id)) == NULL ) + return false; + if( bgd->mapindex == 0 ) + return false; // Respawn not handled by Core + pc->setpos(sd, bgd->mapindex, bgd->x, bgd->y, CLR_OUTSIGHT); + status->revive(&sd->bl, 1, 100); + + return true; // Warped } -int bg_create(unsigned short mapindex, short rx, short ry, const char *ev, const char *dev) { - struct battleground_data *bg; - bg_team_counter++; +int bg_create(unsigned short map_index, short rx, short ry, const char *ev, const char *dev) { + struct battleground_data *bgd; + bg->team_counter++; - CREATE(bg, struct battleground_data, 1); - bg->bg_id = bg_team_counter; - bg->count = 0; - bg->mapindex = mapindex; - bg->x = rx; - bg->y = ry; - safestrncpy(bg->logout_event, ev, sizeof(bg->logout_event)); - safestrncpy(bg->die_event, dev, sizeof(bg->die_event)); + CREATE(bgd, struct battleground_data, 1); + bgd->bg_id = bg->team_counter; + bgd->count = 0; + bgd->mapindex = map_index; + bgd->x = rx; + bgd->y = ry; + safestrncpy(bgd->logout_event, ev, sizeof(bgd->logout_event)); + safestrncpy(bgd->die_event, dev, sizeof(bgd->die_event)); - memset(&bg->members, 0, sizeof(bg->members)); - idb_put(bg_team_db, bg_team_counter, bg); + memset(&bgd->members, 0, sizeof(bgd->members)); + idb_put(bg->team_db, bg->team_counter, bgd); - return bg->bg_id; + return bgd->bg_id; } -int bg_team_get_id(struct block_list *bl) -{ +int bg_team_get_id(struct block_list *bl) { nullpo_ret(bl); - switch( bl->type ) - { + switch( bl->type ) { case BL_PC: return ((TBL_PC*)bl)->bg_id; case BL_PET: @@ -185,7 +210,7 @@ int bg_team_get_id(struct block_list *bl) { struct map_session_data *msd; struct mob_data *md = (TBL_MOB*)bl; - if( md->special_state.ai && (msd = iMap->id2sd(md->master_id)) != NULL ) + if( md->special_state.ai && (msd = map->id2sd(md->master_id)) != NULL ) return msd->bg_id; return md->bg_id; } @@ -204,97 +229,124 @@ int bg_team_get_id(struct block_list *bl) return 0; } -int bg_send_message(struct map_session_data *sd, const char *mes, int len) -{ - struct battleground_data *bg; +bool bg_send_message(struct map_session_data *sd, const char *mes, int len) { + struct battleground_data *bgd; nullpo_ret(sd); - if( sd->bg_id == 0 || (bg = bg_team_search(sd->bg_id)) == NULL ) - return 0; - clif->bg_message(bg, sd->bl.id, sd->status.name, mes, len); - return 0; + 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); + return true; } /** * @see DBApply */ -int bg_send_xy_timer_sub(DBKey key, DBData *data, va_list ap) -{ - struct battleground_data *bg = DB->data2ptr(data); +int bg_send_xy_timer_sub(DBKey key, DBData *data, va_list ap) { + struct battleground_data *bgd = DB->data2ptr(data); struct map_session_data *sd; int i; - nullpo_ret(bg); + nullpo_ret(bgd); for( i = 0; i < MAX_BG_MEMBERS; i++ ) { - if( (sd = bg->members[i].sd) == NULL ) + if( (sd = bgd->members[i].sd) == NULL ) continue; - if( sd->bl.x != bg->members[i].x || sd->bl.y != bg->members[i].y ) { // xy update - bg->members[i].x = sd->bl.x; - bg->members[i].y = sd->bl.y; + if( sd->bl.x != bgd->members[i].x || sd->bl.y != bgd->members[i].y ) { // xy update + bgd->members[i].x = sd->bl.x; + bgd->members[i].y = sd->bl.y; clif->bg_xy(sd); } } return 0; } -int bg_send_xy_timer(int tid, unsigned int tick, int id, intptr_t data) { - bg_team_db->foreach(bg_team_db, bg_send_xy_timer_sub, tick); +int bg_send_xy_timer(int tid, int64 tick, int id, intptr_t data) { + bg->team_db->foreach(bg->team_db, bg->send_xy_timer_sub, tick); return 0; } + +enum bg_queue_types bg_str2teamtype (const char *str) { + char temp[200], *parse; + enum bg_queue_types type = BGQT_INVALID; + + safestrncpy(temp, str, 200); + + parse = strtok(temp,"|"); + + while (parse != NULL) { + normalize_name(parse," "); + if( strcmpi(parse,"all") == 0 ) + type |= BGQT_INDIVIDUAL|BGQT_PARTY|BGQT_GUILD; + else if( strcmpi(parse,"party") == 0 ) + type |= BGQT_PARTY; + else if( strcmpi(parse,"guild") == 0 ) + type |= BGQT_GUILD; + else if( strcmpi(parse,"solo") == 0 ) + type |= BGQT_INDIVIDUAL; + else { + ShowError("bg_str2teamtype: '%s' unknown type, skipping...\n",parse); + } + parse = strtok(NULL,"|"); + } + + return type; +} + void bg_config_read(void) { config_t bg_conf; config_setting_t *data = NULL; const char *config_filename = "conf/battlegrounds.conf"; // FIXME hardcoded name - if (conf_read_file(&bg_conf, config_filename)) + if (libconfig->read_file(&bg_conf, config_filename)) return; - data = config_lookup(&bg_conf, "battlegrounds"); + data = libconfig->lookup(&bg_conf, "battlegrounds"); if (data != NULL) { - config_setting_t *settings = config_setting_get_elem(data, 0); + config_setting_t *settings = libconfig->setting_get_elem(data, 0); config_setting_t *arenas; const char *delay_var; - int i, arena_count = 0, total = 0, offline = 0; + int i, arena_count = 0, offline = 0; - if( !config_setting_lookup_string(settings, "global_delay_var", &delay_var) ) + if( !libconfig->setting_lookup_string(settings, "global_delay_var", &delay_var) ) delay_var = "BG_Delay_Tick"; safestrncpy(bg->gdelay_var, delay_var, BG_DELAY_VAR_LENGTH); - config_setting_lookup_int(settings, "maximum_afk_seconds", &bg->mafksec); - - config_setting_lookup_bool(settings, "feature_off", &offline); - + libconfig->setting_lookup_int(settings, "maximum_afk_seconds", &bg->mafksec); + + libconfig->setting_lookup_bool(settings, "feature_off", &offline); + if( offline == 0 ) bg->queue_on = true; - if( (arenas = config_setting_get_member(settings, "arenas")) != NULL ) { - arena_count = config_setting_length(arenas); + if( (arenas = libconfig->setting_get_member(settings, "arenas")) != NULL ) { + arena_count = libconfig->setting_length(arenas); CREATE( bg->arena, struct bg_arena *, arena_count ); for(i = 0; i < arena_count; i++) { - config_setting_t *arena = config_setting_get_elem(arenas, i); + config_setting_t *arena = libconfig->setting_get_elem(arenas, i); config_setting_t *reward; - const char *aName, *aEvent, *aDelayVar; + const char *aName, *aEvent, *aDelayVar, *aTeamTypes; int minLevel = 0, maxLevel = 0; int prizeWin, prizeLoss, prizeDraw; int minPlayers, maxPlayers, minTeamPlayers; int maxDuration; - int fillup_duration, pregame_duration; + int fillup_duration = 0, pregame_duration = 0; + enum bg_queue_types allowedTypes; bg->arena[i] = NULL; - if( !config_setting_lookup_string(arena, "name", &aName) ) { + if( !libconfig->setting_lookup_string(arena, "name", &aName) ) { ShowError("bg_config_read: failed to find 'name' for arena #%d\n",i); continue; } - if( !config_setting_lookup_string(arena, "event", &aEvent) ) { + if( !libconfig->setting_lookup_string(arena, "event", &aEvent) ) { ShowError("bg_config_read: failed to find 'event' for arena #%d\n",i); continue; } - config_setting_lookup_int(arena, "minLevel", &minLevel); - config_setting_lookup_int(arena, "maxLevel", &maxLevel); + libconfig->setting_lookup_int(arena, "minLevel", &minLevel); + libconfig->setting_lookup_int(arena, "maxLevel", &maxLevel); if( minLevel < 0 ) { ShowWarning("bg_config_read: invalid %d value for arena '%s' minLevel\n",minLevel,aName); @@ -305,14 +357,14 @@ void bg_config_read(void) { maxLevel = MAX_LEVEL; } - if( !(reward = config_setting_get_member(settings, "reward")) ) { + if( !(reward = libconfig->setting_get_member(arena, "reward")) ) { ShowError("bg_config_read: failed to find 'reward' for arena '%s'/#%d\n",aName,i); continue; } - config_setting_lookup_int(reward, "win", &prizeWin); - config_setting_lookup_int(reward, "loss", &prizeLoss); - config_setting_lookup_int(reward, "draw", &prizeDraw); + libconfig->setting_lookup_int(reward, "win", &prizeWin); + libconfig->setting_lookup_int(reward, "loss", &prizeLoss); + libconfig->setting_lookup_int(reward, "draw", &prizeDraw); if( prizeWin < 0 ) { ShowWarning("bg_config_read: invalid %d value for arena '%s' reward:win\n",prizeWin,aName); @@ -327,9 +379,9 @@ void bg_config_read(void) { prizeDraw = 0; } - config_setting_lookup_int(arena, "minPlayers", &minPlayers); - config_setting_lookup_int(arena, "maxPlayers", &maxPlayers); - config_setting_lookup_int(arena, "minTeamPlayers", &minTeamPlayers); + libconfig->setting_lookup_int(arena, "minPlayers", &minPlayers); + libconfig->setting_lookup_int(arena, "maxPlayers", &maxPlayers); + libconfig->setting_lookup_int(arena, "minTeamPlayers", &minTeamPlayers); if( minPlayers < 0 ) { ShowWarning("bg_config_read: invalid %d value for arena '%s' minPlayers\n",minPlayers,aName); @@ -344,20 +396,26 @@ void bg_config_read(void) { minTeamPlayers = 0; } - if( !config_setting_lookup_string(arena, "delay_var", &aDelayVar) ) { + if( !libconfig->setting_lookup_string(arena, "delay_var", &aDelayVar) ) { ShowError("bg_config_read: failed to find 'delay_var' for arena '%s'/#%d\n",aName,i); continue; } - config_setting_lookup_int(arena, "maxDuration", &maxDuration); + + if( !libconfig->setting_lookup_string(arena, "allowedTypes", &aTeamTypes) ) { + ShowError("bg_config_read: failed to find 'allowedTypes' for arena '%s'/#%d\n",aName,i); + continue; + } + + libconfig->setting_lookup_int(arena, "maxDuration", &maxDuration); if( maxDuration < 0 ) { ShowWarning("bg_config_read: invalid %d value for arena '%s' maxDuration\n",maxDuration,aName); maxDuration = 30; } - config_setting_lookup_int(arena, "fillDuration", &fillup_duration); - config_setting_lookup_int(arena, "pGameDuration", &pregame_duration); + libconfig->setting_lookup_int(arena, "fillDuration", &fillup_duration); + libconfig->setting_lookup_int(arena, "pGameDuration", &pregame_duration); if( fillup_duration < 20 ) { ShowWarning("bg_config_read: invalid %d value for arena '%s' fillDuration, minimum has to be 20, defaulting to 20.\n",fillup_duration,aName); @@ -369,6 +427,7 @@ void bg_config_read(void) { pregame_duration = 20; } + allowedTypes = bg->str2teamtype(aTeamTypes); CREATE( bg->arena[i], struct bg_arena, 1 ); @@ -385,19 +444,19 @@ void bg_config_read(void) { bg->arena[i]->min_team_players = minTeamPlayers; safestrncpy(bg->arena[i]->delay_var, aDelayVar, NAME_LENGTH); bg->arena[i]->maxDuration = maxDuration; - bg->arena[i]->queue_id = -1; + bg->arena[i]->queue_id = script->queue_create(); bg->arena[i]->begin_timer = INVALID_TIMER; bg->arena[i]->fillup_timer = INVALID_TIMER; bg->arena[i]->pregame_duration = pregame_duration; bg->arena[i]->fillup_duration = fillup_duration; - - total++; + bg->arena[i]->ongoing = false; + bg->arena[i]->allowed_types = allowedTypes; + } bg->arenas = arena_count; } - ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' arenas in '"CL_WHITE"%s"CL_RESET"'.\n", total, config_filename); - config_destroy(&bg_conf); + libconfig->destroy(&bg_conf); } } struct bg_arena *bg_name2arena (char *name) { @@ -411,20 +470,55 @@ struct bg_arena *bg_name2arena (char *name) { int bg_id2pos ( int queue_id, int account_id ) { struct hQueue *queue = script->queue(queue_id); if( queue ) { - int i; - for(i = 0; i < queue->items; i++ ) { - if( queue->item[i] == account_id ) { - return i; + int i, pos = 1; + for(i = 0; i < queue->size; i++ ) { + if( queue->item[i] > 0 ) { + if( queue->item[i] == account_id ) { + return pos; + } + pos++; } } } return 0; } +void bg_queue_ready_ack (struct bg_arena *arena, struct map_session_data *sd, bool response) { + if( arena->begin_timer == INVALID_TIMER || !sd->bg_queue.arena || sd->bg_queue.arena != arena ) { + bg->queue_pc_cleanup(sd); + return; + } + if( !response ) + bg->queue_pc_cleanup(sd); + else { + struct hQueue *queue = &script->hq[arena->queue_id]; + int i, count = 0; + sd->bg_queue.ready = 1; + + for( i = 0; i < queue->size; i++ ) { + if( queue->item[i] > 0 && ( sd = map->id2sd(queue->item[i]) ) ) { + if( sd->bg_queue.ready == 1 ) + count++; + } + } + /* check if all are ready then cancel timer, and start game */ + if( count == queue->items ) { + timer->delete(arena->begin_timer,bg->begin_timer); + arena->begin_timer = INVALID_TIMER; + bg->begin(arena); + } + + } + +} void bg_queue_player_cleanup(struct map_session_data *sd) { if ( sd->bg_queue.client_has_bg_data ) { - clif->bgqueue_notice_delete(sd,BGQND_CLOSEWINDOW, sd->bg_queue.arena->id); + if( sd->bg_queue.arena ) + clif->bgqueue_notice_delete(sd,BGQND_CLOSEWINDOW,sd->bg_queue.arena->name); + else + clif->bgqueue_notice_delete(sd,BGQND_FAIL_NOT_QUEUING,bg->arena[0]->name); } - script->queue_remove(sd->bg_queue.arena->queue_id,sd->status.account_id); + if( sd->bg_queue.arena ) + script->queue_remove(sd->bg_queue.arena->queue_id,sd->status.account_id); sd->bg_queue.arena = NULL; sd->bg_queue.ready = 0; sd->bg_queue.client_has_bg_data = 0; @@ -432,49 +526,116 @@ void bg_queue_player_cleanup(struct map_session_data *sd) { } void bg_match_over(struct bg_arena *arena, bool canceled) { struct hQueue *queue = &script->hq[arena->queue_id]; - int i;//, count = 0; - - /* if( !canceled ) <check time/score> */ + int i; - for( i = 0; i < queue->items; i++ ) { + if( !arena->ongoing ) + return; + arena->ongoing = false; + + for( i = 0; i < queue->size; i++ ) { struct map_session_data * sd = NULL; - if( ( sd = iMap->id2sd(queue->item[i]) ) ) { - bg->queue_pc_cleanup(sd); - clif->colormes(sd->fd,COLOR_RED,"BG Match Cancelled: not enough players"); + if( queue->item[i] > 0 && ( sd = map->id2sd(queue->item[i]) ) ) { + if( sd->bg_queue.arena ) { + bg->team_leave(sd, 0); + bg->queue_pc_cleanup(sd); + } + if( canceled ) + clif->colormes(sd->fd,COLOR_RED,"BG Match Canceled: not enough players"); + else { + pc_setglobalreg(sd, script->add_str(arena->delay_var), (unsigned int)time(NULL)); + } } } - bg->arena[i]->begin_timer = INVALID_TIMER; - bg->arena[i]->fillup_timer = INVALID_TIMER; + arena->begin_timer = INVALID_TIMER; + arena->fillup_timer = INVALID_TIMER; /* reset queue */ + script->queue_clear(arena->queue_id); } void bg_begin(struct bg_arena *arena) { struct hQueue *queue = &script->hq[arena->queue_id]; int i, count = 0; - - for( i = 0; i < queue->items; i++ ) { + + for( i = 0; i < queue->size; i++ ) { struct map_session_data * sd = NULL; - if( ( sd = iMap->id2sd(queue->item[i]) ) ) { + if( queue->item[i] > 0 && ( sd = map->id2sd(queue->item[i]) ) ) { if( sd->bg_queue.ready == 1 ) count++; else bg->queue_pc_cleanup(sd); } } + /* TODO/FIXME? I *think* it should check what kind of queue the player used, then check if his party/guild + * (his team) still meet the join criteria (sort of what bg->can_queue does) + */ if( count < arena->min_players ) { - bg_match_over(arena,true); + bg->match_over(arena,true); } else { - ; - /* we split evenly? */ - /* but if a party of say 10 joins, it cant be split evenly unless by luck there are 10 soloers in the queue besides them */ - /* not sure how to split T_T needs more info */ + arena->ongoing = true; + + if( bg->afk_timer_id == INVALID_TIMER && bg->mafksec > 0 ) + bg->afk_timer_id = timer->add(timer->gettick()+10000,bg->afk_timer,0,0); + + /* TODO: make this a arena-independent var? or just .@? */ + mapreg->setreg(script->add_str("$@bg_queue_id"),arena->queue_id); + mapreg->setregstr(script->add_str("$@bg_delay_var$"),bg->gdelay_var); + + count = 0; + for( i = 0; i < queue->size; i++ ) { + struct map_session_data * sd = NULL; + + if( queue->item[i] > 0 && ( sd = map->id2sd(queue->item[i]) ) ) { + if( sd->bg_queue.ready == 1 ) { + + mapreg->setreg(reference_uid(script->add_str("$@bg_member"), count), sd->status.account_id); + + mapreg->setreg(reference_uid(script->add_str("$@bg_member_group"), count), + sd->bg_queue.type == BGQT_GUILD ? sd->status.guild_id : + sd->bg_queue.type == BGQT_PARTY ? sd->status.party_id : + 0 + ); + mapreg->setreg(reference_uid(script->add_str("$@bg_member_type"), count), + sd->bg_queue.type == BGQT_GUILD ? 1 : + sd->bg_queue.type == BGQT_PARTY ? 2 : + 0 + ); + count++; + } + } + } + mapreg->setreg(script->add_str("$@bg_member_size"),count); + + npc->event_do(arena->npc_event); } } -int bg_begin_timer(int tid, unsigned int tick, int id, intptr_t data) { +int bg_begin_timer(int tid, int64 tick, int id, intptr_t data) { bg->begin(bg->arena[id]); + bg->arena[id]->begin_timer = INVALID_TIMER; + return 0; +} + +int bg_afk_timer(int tid, int64 tick, int id, intptr_t data) { + struct s_mapiterator* iter; + struct map_session_data* sd; + int count = 0; + + iter = mapit_getallusers(); + for( sd = (TBL_PC*)mapit->first(iter); mapit->exists(iter); sd = (TBL_PC*)mapit->next(iter) ) { + if( !sd->bg_queue.arena || !sd->bg_id ) + continue; + if( DIFF_TICK(sockt->last_tick, sd->idletime) > bg->mafksec ) + bg->team_leave(sd,BGTL_AFK); + count++; + } + mapit->free(iter); + + if( count ) + bg->afk_timer_id = timer->add(timer->gettick()+10000,bg->afk_timer,0,0); + else + bg->afk_timer_id = INVALID_TIMER; return 0; } @@ -482,31 +643,31 @@ void bg_queue_pregame(struct bg_arena *arena) { struct hQueue *queue = &script->hq[arena->queue_id]; int i; - for( i = 0; i < queue->items; i++ ) { + for( i = 0; i < queue->size; i++ ) { struct map_session_data * sd = NULL; - if( ( sd = iMap->id2sd(queue->item[i]) ) ) { + if( queue->item[i] > 0 && ( sd = map->id2sd(queue->item[i]) ) ) { clif->bgqueue_battlebegins(sd,arena->id,SELF); } } - arena->begin_timer = iTimer->add_timer( iTimer->gettick() + (arena->pregame_duration*1000), bg->begin_timer, arena->id, 0 ); + arena->begin_timer = timer->add( timer->gettick() + (arena->pregame_duration*1000), bg->begin_timer, arena->id, 0 ); } -int bg_fillup_timer(int tid, unsigned int tick, int id, intptr_t data) { +int bg_fillup_timer(int tid, int64 tick, int id, intptr_t data) { bg->queue_pregame(bg->arena[id]); + bg->arena[id]->fillup_timer = INVALID_TIMER; return 0; } void bg_queue_check(struct bg_arena *arena) { int count = script->hq[arena->queue_id].items; - if( count == arena->max_players ) { if( arena->fillup_timer != INVALID_TIMER ) { - iTimer->delete_timer(arena->fillup_timer,bg_fillup_timer); + timer->delete(arena->fillup_timer,bg->fillup_timer); arena->fillup_timer = INVALID_TIMER; } bg->queue_pregame(arena); } else if( count >= arena->min_players && arena->fillup_timer == INVALID_TIMER ) { - arena->fillup_timer = iTimer->add_timer( iTimer->gettick() + (arena->fillup_duration*1000), bg->fillup_timer, arena->id, 0 ); + arena->fillup_timer = timer->add( timer->gettick() + (arena->fillup_duration*1000), bg->fillup_timer, arena->id, 0 ); } } void bg_queue_add(struct map_session_data *sd, struct bg_arena *arena, enum bg_queue_types type) { @@ -514,7 +675,7 @@ void bg_queue_add(struct map_session_data *sd, struct bg_arena *arena, enum bg_q struct hQueue *queue; int i, count = 0; - if( arena->begin_timer != INVALID_TIMER ) { + if( arena->begin_timer != INVALID_TIMER || arena->ongoing ) { clif->bgqueue_ack(sd,BGQA_FAIL_QUEUING_FINISHED,arena->id); return; } @@ -545,11 +706,11 @@ void bg_queue_add(struct map_session_data *sd, struct bg_arena *arena, enum bg_q break; } - if( !(queue = script->queue(arena->queue_id)) || (queue->items+count) >= arena->max_players ) { + if( !(queue = script->queue(arena->queue_id)) || (queue->items+count) > arena->max_players ) { clif->bgqueue_ack(sd,BGQA_FAIL_PPL_OVERAMOUNT,arena->id); return; } - + switch( type ) { case BGQT_INDIVIDUAL: sd->bg_queue.type = type; @@ -585,14 +746,19 @@ void bg_queue_add(struct map_session_data *sd, struct bg_arena *arena, enum bg_q } break; } - + clif->bgqueue_ack(sd,BGQA_SUCCESS,arena->id); + bg->queue_check(arena); } enum BATTLEGROUNDS_QUEUE_ACK bg_canqueue(struct map_session_data *sd, struct bg_arena *arena, enum bg_queue_types type) { int tick; unsigned int tsec; - if ( sd->status.base_level > arena->max_level || sd->status.base_level < arena->max_level ) + + if( !(arena->allowed_types & type) ) + return BGQA_FAIL_TYPE_INVALID; + + if ( sd->status.base_level > arena->max_level || sd->status.base_level < arena->min_level ) return BGQA_FAIL_LEVEL_INCORRECT; if ( !(sd->class_&JOBL_2) ) /* TODO: maybe make this a per-arena setting, so users may make custom arenas like baby-only,whatever. */ @@ -600,7 +766,7 @@ enum BATTLEGROUNDS_QUEUE_ACK bg_canqueue(struct map_session_data *sd, struct bg_ tsec = (unsigned int)time(NULL); - if ( ( tick = pc_readglobalreg(sd, bg->gdelay_var) ) && tsec < tick ) { + if ( ( tick = pc_readglobalreg(sd, script->add_str(bg->gdelay_var)) ) && tsec < tick ) { char response[100]; if( (tick-tsec) > 60 ) sprintf(response, "You are a deserter! Wait %d minute(s) before you can apply again",(tick-tsec)/60); @@ -610,7 +776,7 @@ enum BATTLEGROUNDS_QUEUE_ACK bg_canqueue(struct map_session_data *sd, struct bg_ return BGQA_FAIL_DESERTER; } - if ( ( tick = pc_readglobalreg(sd, arena->cooldown_variable) ) && tsec < tick ) { + if ( ( tick = pc_readglobalreg(sd, script->add_str(arena->delay_var)) ) && tsec < tick ) { char response[100]; if( (tick-tsec) > 60 ) sprintf(response, "You can't reapply to this arena so fast. Apply to the different arena or wait %d minute(s)",(tick-tsec)/60); @@ -622,7 +788,7 @@ enum BATTLEGROUNDS_QUEUE_ACK bg_canqueue(struct map_session_data *sd, struct bg_ if( sd->bg_queue.arena != NULL ) return BGQA_DUPLICATE_REQUEST; - + switch(type) { case BGQT_GUILD: if( !sd->guild || !sd->state.gmaster_flag ) @@ -689,16 +855,20 @@ enum BATTLEGROUNDS_QUEUE_ACK bg_canqueue(struct map_session_data *sd, struct bg_ return BGQA_SUCCESS; } -void do_init_battleground(void) { - bg_team_db = idb_alloc(DB_OPT_RELEASE_DATA); - iTimer->add_timer_func_list(bg_send_xy_timer, "bg_send_xy_timer"); - iTimer->add_timer_interval(iTimer->gettick() + battle_config.bg_update_interval, bg_send_xy_timer, 0, 0, battle_config.bg_update_interval); +void do_init_battleground(bool minimal) { + if (minimal) + return; + + bg->team_db = idb_alloc(DB_OPT_RELEASE_DATA); + timer->add_func_list(bg->send_xy_timer, "bg_send_xy_timer"); + timer->add_interval(timer->gettick() + battle_config.bg_update_interval, bg->send_xy_timer, 0, 0, battle_config.bg_update_interval); + bg->config_read(); } void do_final_battleground(void) { int i; - bg_team_db->destroy(bg_team_db, NULL); + db_destroy(bg->team_db); for( i = 0; i < bg->arenas; i++ ) { if( bg->arena[i] ) @@ -714,9 +884,16 @@ void battleground_defaults(void) { bg->queue_on = false; bg->mafksec = 0; + bg->afk_timer_id = INVALID_TIMER; bg->arena = NULL; bg->arenas = 0; /* */ + bg->team_db = NULL; + bg->team_counter = 0; + /* */ + bg->init = do_init_battleground; + bg->final = do_final_battleground; + /* */ bg->name2arena = bg_name2arena; bg->queue_add = bg_queue_add; bg->can_queue = bg_canqueue; @@ -726,6 +903,25 @@ void battleground_defaults(void) { bg->begin_timer = bg_begin_timer; bg->queue_pregame = bg_queue_pregame; bg->fillup_timer = bg_fillup_timer; + bg->queue_ready_ack = bg_queue_ready_ack; + bg->match_over = bg_match_over; + bg->queue_check = bg_queue_check; + bg->team_search = bg_team_search; + bg->getavailablesd = bg_getavailablesd; + bg->team_delete = bg_team_delete; + bg->team_warp = bg_team_warp; + bg->send_dot_remove = bg_send_dot_remove; + bg->team_join = bg_team_join; + bg->team_leave = bg_team_leave; + bg->member_respawn = bg_member_respawn; + bg->create = bg_create; + bg->team_get_id = bg_team_get_id; + bg->send_message = bg_send_message; + bg->send_xy_timer_sub = bg_send_xy_timer_sub; + bg->send_xy_timer = bg_send_xy_timer; + bg->afk_timer = bg_afk_timer; + /* */ + bg->str2teamtype = bg_str2teamtype; /* */ bg->config_read = bg_config_read; } diff --git a/src/map/battleground.h b/src/map/battleground.h index 8fe9f3b77..c1d3be054 100644 --- a/src/map/battleground.h +++ b/src/map/battleground.h @@ -2,11 +2,12 @@ // See the LICENSE file // Portions Copyright (c) Athena Dev Teams -#ifndef _BATTLEGROUND_H_ -#define _BATTLEGROUND_H_ +#ifndef MAP_BATTLEGROUND_H +#define MAP_BATTLEGROUND_H -#include "../common/mmo.h" // struct party +#include "clif.h" #include "guild.h" +#include "../common/mmo.h" // struct party /** * Defines @@ -18,16 +19,24 @@ * Enumerations **/ enum bg_queue_types { - BGQT_INVALID, - BGQT_INDIVIDUAL, - BGQT_PARTY, - BGQT_GUILD + BGQT_INVALID = 0x0, + BGQT_INDIVIDUAL = 0x1, + BGQT_PARTY = 0x2, + /* yup no 0x3 */ + BGQT_GUILD = 0x4, +}; + +enum bg_team_leave_type { + BGTL_LEFT = 0x0, + BGTL_QUIT = 0x1, + BGTL_AFK = 0x2, }; struct battleground_member_data { unsigned short x, y; struct map_session_data *sd; unsigned afk : 1; + struct point source;/* where did i come from before i join? */ }; struct battleground_data { @@ -41,22 +50,6 @@ struct battleground_data { char die_event[EVENT_NAME_LENGTH]; }; -void do_init_battleground(void); -void do_final_battleground(void); - -struct battleground_data* bg_team_search(int bg_id); -int bg_send_dot_remove(struct map_session_data *sd); -int bg_team_get_id(struct block_list *bl); -struct map_session_data* bg_getavailablesd(struct battleground_data *bg); - -int bg_create(unsigned short mapindex, short rx, short ry, const char *ev, const char *dev); -int bg_team_join(int bg_id, struct map_session_data *sd); -int bg_team_delete(int bg_id); -int bg_team_leave(struct map_session_data *sd, int flag); -int bg_team_warp(int bg_id, unsigned short mapindex, short x, short y); -int bg_member_respawn(struct map_session_data *sd); -int bg_send_message(struct map_session_data *sd, const char *mes, int len); - struct bg_arena { char name[NAME_LENGTH]; unsigned char id; @@ -66,7 +59,6 @@ struct bg_arena { short min_players; short max_players; short min_team_players; - char cooldown_variable[NAME_LENGTH]; char delay_var[NAME_LENGTH]; unsigned short maxDuration; int queue_id; @@ -75,33 +67,59 @@ struct bg_arena { int game_timer; unsigned short fillup_duration; unsigned short pregame_duration; + bool ongoing; + enum bg_queue_types allowed_types; }; -/* battleground.c interface (incomplete) */ struct battleground_interface { bool queue_on; /* */ - int mafksec; + int mafksec, afk_timer_id; char gdelay_var[BG_DELAY_VAR_LENGTH]; /* */ struct bg_arena **arena; unsigned char arenas; /* */ + DBMap *team_db; // int bg_id -> struct battleground_data* + unsigned int team_counter; // Next bg_id + /* */ + void (*init) (bool minimal); + void (*final) (void); + /* */ struct bg_arena *(*name2arena) (char *name); void (*queue_add) (struct map_session_data *sd, struct bg_arena *arena, enum bg_queue_types type); enum BATTLEGROUNDS_QUEUE_ACK (*can_queue) (struct map_session_data *sd, struct bg_arena *arena, enum bg_queue_types type); int (*id2pos) (int queue_id, int account_id); void (*queue_pc_cleanup) (struct map_session_data *sd); void (*begin) (struct bg_arena *arena); - int (*begin_timer) (int tid, unsigned int tick, int id, intptr_t data); + int (*begin_timer) (int tid, int64 tick, int id, intptr_t data); void (*queue_pregame) (struct bg_arena *arena); - int (*fillup_timer) (int tid, unsigned int tick, int id, intptr_t data); + int (*fillup_timer) (int tid, int64 tick, int id, intptr_t data); + void (*queue_ready_ack) (struct bg_arena *arena, struct map_session_data *sd, bool response); + void (*match_over) (struct bg_arena *arena, bool canceled); + void (*queue_check) (struct bg_arena *arena); + struct battleground_data* (*team_search) (int bg_id); + struct map_session_data* (*getavailablesd) (struct battleground_data *bgd); + bool (*team_delete) (int bg_id); + bool (*team_warp) (int bg_id, unsigned short map_index, short x, short y); + void (*send_dot_remove) (struct map_session_data *sd); + bool (*team_join) (int bg_id, struct map_session_data *sd); + int (*team_leave) (struct map_session_data *sd, enum bg_team_leave_type flag); + bool (*member_respawn) (struct map_session_data *sd); + int (*create) (unsigned short map_index, short rx, short ry, const char *ev, const char *dev); + int (*team_get_id) (struct block_list *bl); + bool (*send_message) (struct map_session_data *sd, const char *mes, int len); + int (*send_xy_timer_sub) (DBKey key, DBData *data, va_list ap); + 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); + /* */ + enum bg_queue_types (*str2teamtype) (const char *str); /* */ void (*config_read) (void); -} bg_s; +}; struct battleground_interface *bg; void battleground_defaults(void); -#endif /* _BATTLEGROUND_H_ */ +#endif /* MAP_BATTLEGROUND_H */ diff --git a/src/map/buyingstore.c b/src/map/buyingstore.c index 764b51015..626d102a3 100644 --- a/src/map/buyingstore.c +++ b/src/map/buyingstore.c @@ -2,50 +2,29 @@ // See the LICENSE file // Portions Copyright (c) Athena Dev Teams -#include "../common/cbasetypes.h" -#include "../common/db.h" // ARR_FIND -#include "../common/showmsg.h" // ShowWarning -#include "../common/socket.h" // RBUF* -#include "../common/strlib.h" // safestrncpy +#define HERCULES_CORE + +#include "buyingstore.h" // struct s_buyingstore + #include "atcommand.h" // msg_txt #include "battle.h" // battle_config.* -#include "buyingstore.h" // struct s_buyingstore +#include "chrif.h" #include "clif.h" // clif->buyingstore_* #include "log.h" // log_pick_pc, log_zeny #include "pc.h" // struct map_session_data -#include "chrif.h" - - -/// constants (client-side restrictions) -#define BUYINGSTORE_MAX_PRICE 99990000 -#define BUYINGSTORE_MAX_AMOUNT 9999 - - -/// failure constants for clif functions -enum e_buyingstore_failure -{ - BUYINGSTORE_CREATE = 1, // "Failed to open buying store." - BUYINGSTORE_CREATE_OVERWEIGHT = 2, // "Total amount of then possessed items exceeds the weight limit by %d. Please re-enter." - BUYINGSTORE_TRADE_BUYER_ZENY = 3, // "All items within the buy limit were purchased." - BUYINGSTORE_TRADE_BUYER_NO_ITEMS = 4, // "All items were purchased." - BUYINGSTORE_TRADE_SELLER_FAILED = 5, // "The deal has failed." - BUYINGSTORE_TRADE_SELLER_COUNT = 6, // "The trade failed, because the entered amount of item %s is higher, than the buyer is willing to buy." - BUYINGSTORE_TRADE_SELLER_ZENY = 7, // "The trade failed, because the buyer is lacking required balance." - BUYINGSTORE_CREATE_NO_INFO = 8, // "No sale (purchase) information available." -}; - - -static unsigned int buyingstore_nextid = 0; -static const short buyingstore_blankslots[MAX_SLOTS] = { 0 }; // used when checking whether or not an item's card slots are blank +#include "../common/cbasetypes.h" +#include "../common/db.h" // ARR_FIND +#include "../common/showmsg.h" // ShowWarning +#include "../common/socket.h" // RBUF* +#include "../common/strlib.h" // safestrncpy +struct buyingstore_interface buyingstore_s; /// Returns unique buying store id -static unsigned int buyingstore_getuid(void) -{ - return buyingstore_nextid++; +unsigned int buyingstore_getuid(void) { + return buyingstore->nextid++; } - bool buyingstore_setup(struct map_session_data* sd, unsigned char slots) { if( !battle_config.feature_buying_store || sd->state.vending || sd->state.buyingstore || sd->state.trading || slots == 0 ) @@ -58,14 +37,14 @@ bool buyingstore_setup(struct map_session_data* sd, unsigned char slots) return false; } - if( map[sd->bl.m].flag.novending ) - {// custom: no vending maps + if( map->list[sd->bl.m].flag.novending ) { + // custom: no vending maps clif->message(sd->fd, msg_txt(276)); // "You can't open a shop on this map" return false; } - if( iMap->getcell(sd->bl.m, sd->bl.x, sd->bl.y, CELL_CHKNOVENDING) ) - {// custom: no vending cells + if( map->getcell(sd->bl.m, sd->bl.x, sd->bl.y, CELL_CHKNOVENDING) ) { + // custom: no vending cells clif->message(sd->fd, msg_txt(204)); // "You can't open a shop on this cell." return false; } @@ -100,7 +79,7 @@ void buyingstore_create(struct map_session_data* sd, int zenylimit, unsigned cha return; } - if( !pc->can_give_items(sd) ) + if( !pc_can_give_items(sd) ) {// custom: GM is not allowed to buy (give zeny) sd->buyingstore.slots = 0; clif->message(sd->fd, msg_txt(246)); @@ -113,14 +92,14 @@ void buyingstore_create(struct map_session_data* sd, int zenylimit, unsigned cha return; } - if( map[sd->bl.m].flag.novending ) - {// custom: no vending maps + if( map->list[sd->bl.m].flag.novending ) { + // custom: no vending maps clif->message(sd->fd, msg_txt(276)); // "You can't open a shop on this map" return; } - if( iMap->getcell(sd->bl.m, sd->bl.x, sd->bl.y, CELL_CHKNOVENDING) ) - {// custom: no vending cells + if( map->getcell(sd->bl.m, sd->bl.x, sd->bl.y, CELL_CHKNOVENDING) ) { + // custom: no vending cells clif->message(sd->fd, msg_txt(204)); // "You can't open a shop on this cell." return; } @@ -137,7 +116,7 @@ void buyingstore_create(struct map_session_data* sd, int zenylimit, unsigned cha amount = RBUFW(itemlist,i*8+2); price = RBUFL(itemlist,i*8+4); - if( ( id = itemdb_exists(nameid) ) == NULL || amount == 0 ) + if( ( id = itemdb->exists(nameid) ) == NULL || amount == 0 ) {// invalid input break; } @@ -147,8 +126,9 @@ void buyingstore_create(struct map_session_data* sd, int zenylimit, unsigned cha break; } - if( !id->flag.buyingstore || !itemdb_cantrade_sub(id, pc->get_group_level(sd), pc->get_group_level(sd)) || ( idx = pc->search_inventory(sd, nameid) ) == -1 ) - {// restrictions: allowed, no character-bound items and at least one must be owned + if (!id->flag.buyingstore || !itemdb->cantrade_sub(id, pc_get_group_level(sd), pc_get_group_level(sd)) + || (idx = pc->search_inventory(sd, nameid)) == INDEX_NOT_FOUND + ) { // restrictions: allowed, no character-bound items and at least one must be owned break; } @@ -221,14 +201,14 @@ void buyingstore_open(struct map_session_data* sd, int account_id) return; } - if( !pc->can_give_items(sd) ) + if( !pc_can_give_items(sd) ) {// custom: GM is not allowed to sell clif->message(sd->fd, msg_txt(246)); return; } - if( ( pl_sd = iMap->id2sd(account_id) ) == NULL || !pl_sd->state.buyingstore ) - {// not online or not buying + if( ( pl_sd = map->id2sd(account_id) ) == NULL || !pl_sd->state.buyingstore ) { + // not online or not buying return; } @@ -259,15 +239,15 @@ void buyingstore_trade(struct map_session_data* sd, int account_id, unsigned int return; } - if( !pc->can_give_items(sd) ) + if( !pc_can_give_items(sd) ) {// custom: GM is not allowed to sell clif->message(sd->fd, msg_txt(246)); clif->buyingstore_trade_failed_seller(sd, BUYINGSTORE_TRADE_SELLER_FAILED, 0); return; } - if( ( pl_sd = iMap->id2sd(account_id) ) == NULL || !pl_sd->state.buyingstore || pl_sd->buyer_id != buyer_id ) - {// not online, not buying or not same store + if( ( pl_sd = map->id2sd(account_id) ) == NULL || !pl_sd->state.buyingstore || pl_sd->buyer_id != buyer_id ) { + // not online, not buying or not same store clif->buyingstore_trade_failed_seller(sd, BUYINGSTORE_TRADE_SELLER_FAILED, 0); return; } @@ -314,8 +294,8 @@ void buyingstore_trade(struct map_session_data* sd, int account_id, unsigned int return; } - if( sd->status.inventory[index].expire_time || !itemdb_cantrade(&sd->status.inventory[index], pc->get_group_level(sd), pc->get_group_level(pl_sd)) || memcmp(sd->status.inventory[index].card, buyingstore_blankslots, sizeof(buyingstore_blankslots)) ) - {// non-tradable item + if( sd->status.inventory[index].expire_time || (sd->status.inventory[index].bound && !pc_can_give_bound_items(sd)) || !itemdb_cantrade(&sd->status.inventory[index], pc_get_group_level(sd), pc_get_group_level(pl_sd)) || memcmp(sd->status.inventory[index].card, buyingstore->blankslots, sizeof(buyingstore->blankslots)) ) + {// non-tradable item clif->buyingstore_trade_failed_seller(sd, BUYINGSTORE_TRADE_SELLER_FAILED, nameid); return; } @@ -383,9 +363,9 @@ void buyingstore_trade(struct map_session_data* sd, int account_id, unsigned int clif->buyingstore_update_item(pl_sd, nameid, amount); } - if( iMap->save_settings&128 ) { - chrif_save(sd, 0); - chrif_save(pl_sd, 0); + if( map->save_settings&128 ) { + chrif->save(sd, 0); + chrif->save(pl_sd, 0); } // check whether or not there is still something to buy @@ -407,9 +387,8 @@ void buyingstore_trade(struct map_session_data* sd, int account_id, unsigned int buyingstore_close(pl_sd); // remove auto-trader - if( pl_sd->state.autotrade ) - { - iMap->quit(pl_sd); + if( pl_sd->state.autotrade ) { + map->quit(pl_sd); } } @@ -470,7 +449,7 @@ bool buyingstore_searchall(struct map_session_data* sd, const struct s_search_st ; } - if( !searchstore->result(s->search_sd, sd->buyer_id, sd->status.account_id, sd->message, it->nameid, it->amount, it->price, buyingstore_blankslots, 0) ) + if( !searchstore->result(s->search_sd, sd->buyer_id, sd->status.account_id, sd->message, it->nameid, it->amount, it->price, buyingstore->blankslots, 0) ) {// result set full return false; } @@ -481,6 +460,9 @@ bool buyingstore_searchall(struct map_session_data* sd, const struct s_search_st void buyingstore_defaults(void) { buyingstore = &buyingstore_s; + buyingstore->nextid = 0; + memset(buyingstore->blankslots,0,sizeof(buyingstore->blankslots)); + /* */ buyingstore->setup = buyingstore_setup; buyingstore->create = buyingstore_create; buyingstore->close = buyingstore_close; @@ -488,5 +470,6 @@ void buyingstore_defaults(void) { buyingstore->trade = buyingstore_trade; buyingstore->search = buyingstore_search; buyingstore->searchall = buyingstore_searchall; + buyingstore->getuid = buyingstore_getuid; } diff --git a/src/map/buyingstore.h b/src/map/buyingstore.h index a416317be..c981cc444 100644 --- a/src/map/buyingstore.h +++ b/src/map/buyingstore.h @@ -2,13 +2,46 @@ // See the LICENSE file // Portions Copyright (c) Athena Dev Teams -#ifndef _BUYINGSTORE_H_ -#define _BUYINGSTORE_H_ +#ifndef MAP_BUYINGSTORE_H +#define MAP_BUYINGSTORE_H +#include "../common/cbasetypes.h" +#include "../common/mmo.h" // MAX_SLOTS + +struct map_session_data; + +/** + * Declarations + **/ struct s_search_store_search; +/** + * Defines + **/ #define MAX_BUYINGSTORE_SLOTS 5 +/// constants (client-side restrictions) +#define BUYINGSTORE_MAX_PRICE 99990000 +#define BUYINGSTORE_MAX_AMOUNT 9999 + +/** + * Enumerations + **/ +/// failure constants for clif functions +enum e_buyingstore_failure { + BUYINGSTORE_CREATE = 1, // "Failed to open buying store." + BUYINGSTORE_CREATE_OVERWEIGHT = 2, // "Total amount of then possessed items exceeds the weight limit by %d. Please re-enter." + BUYINGSTORE_TRADE_BUYER_ZENY = 3, // "All items within the buy limit were purchased." + BUYINGSTORE_TRADE_BUYER_NO_ITEMS = 4, // "All items were purchased." + BUYINGSTORE_TRADE_SELLER_FAILED = 5, // "The deal has failed." + BUYINGSTORE_TRADE_SELLER_COUNT = 6, // "The trade failed, because the entered amount of item %s is higher, than the buyer is willing to buy." + BUYINGSTORE_TRADE_SELLER_ZENY = 7, // "The trade failed, because the buyer is lacking required balance." + BUYINGSTORE_CREATE_NO_INFO = 8, // "No sale (purchase) information available." +}; + +/** + * Structures + **/ struct s_buyingstore_item { int price; unsigned short amount; @@ -21,7 +54,13 @@ struct s_buyingstore { unsigned char slots; }; +/** + * Interface + **/ struct buyingstore_interface { + unsigned int nextid; + short blankslots[MAX_SLOTS]; // used when checking whether or not an item's card slots are blank + /* */ bool (*setup) (struct map_session_data* sd, unsigned char slots); void (*create) (struct map_session_data* sd, int zenylimit, unsigned char result, const char* storename, const uint8* itemlist, unsigned int count); void (*close) (struct map_session_data* sd); @@ -29,10 +68,11 @@ struct buyingstore_interface { void (*trade) (struct map_session_data* sd, int account_id, unsigned int buyer_id, const uint8* itemlist, unsigned int count); bool (*search) (struct map_session_data* sd, unsigned short nameid); bool (*searchall) (struct map_session_data* sd, const struct s_search_store_search* s); -} buyingstore_s; + unsigned int (*getuid) (void); +}; struct buyingstore_interface *buyingstore; void buyingstore_defaults (void); -#endif // _BUYINGSTORE_H_ +#endif // MAP_BUYINGSTORE_H diff --git a/src/map/chat.c b/src/map/chat.c index c0452f2c5..cd7b5f811 100644 --- a/src/map/chat.c +++ b/src/map/chat.c @@ -1,12 +1,14 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder +// Copyright (c) Hercules Dev Team, licensed under GNU GPL. +// See the LICENSE file +// Portions Copyright (c) Athena Dev Teams + +#define HERCULES_CORE + +#include "chat.h" + +#include <stdio.h> +#include <string.h> -#include "../common/cbasetypes.h" -#include "../common/malloc.h" -#include "../common/nullpo.h" -#include "../common/showmsg.h" -#include "../common/strlib.h" -#include "../common/mmo.h" #include "atcommand.h" // msg_txt() #include "battle.h" // struct battle_config #include "clif.h" @@ -14,21 +16,23 @@ #include "npc.h" // npc_event_do() #include "pc.h" #include "skill.h" // ext_skill_unit_onplace() -#include "chat.h" - -#include <stdio.h> -#include <string.h> - +#include "../common/cbasetypes.h" +#include "../common/malloc.h" +#include "../common/mmo.h" +#include "../common/nullpo.h" +#include "../common/showmsg.h" +#include "../common/strlib.h" -int chat_triggerevent(struct chat_data *cd); // forward declaration +struct chat_interface chat_s; /// Initializes a chatroom object (common functionality for both pc and npc chatrooms). /// Returns a chatroom object on success, or NULL on failure. -static struct chat_data* chat_createchat(struct block_list* bl, const char* title, const char* pass, int limit, bool pub, int trigger, const char* ev, int zeny, int minLvl, int maxLvl) +struct chat_data* chat_createchat(struct block_list* bl, const char* title, const char* pass, int limit, bool pub, int trigger, const char* ev, int zeny, int minLvl, int maxLvl) { struct chat_data* cd; nullpo_retr(NULL, bl); + /* Given the overhead and the numerous instances (npc allocated or otherwise) wouldn't it be beneficial to have it use ERS? [Ind] */ cd = (struct chat_data *) aMalloc(sizeof(struct chat_data)); safestrncpy(cd->title, title, sizeof(cd->title)); @@ -44,21 +48,20 @@ static struct chat_data* chat_createchat(struct block_list* bl, const char* titl cd->owner = bl; safestrncpy(cd->npc_event, ev, sizeof(cd->npc_event)); - cd->bl.id = iMap->get_new_object_id(); + cd->bl.id = map->get_new_object_id(); cd->bl.m = bl->m; cd->bl.x = bl->x; cd->bl.y = bl->y; cd->bl.type = BL_CHAT; cd->bl.next = cd->bl.prev = NULL; - if( cd->bl.id == 0 ) - { + if( cd->bl.id == 0 ) { aFree(cd); - cd = NULL; + return NULL; } - iMap->addiddb(&cd->bl); - + map->addiddb(&cd->bl); + if( bl->type != BL_NPC ) cd->kick_list = idb_alloc(DB_OPT_BASE); @@ -68,34 +71,31 @@ static struct chat_data* chat_createchat(struct block_list* bl, const char* titl /*========================================== * player chatroom creation *------------------------------------------*/ -int chat_createpcchat(struct map_session_data* sd, const char* title, const char* pass, int limit, bool pub) -{ +bool chat_createpcchat(struct map_session_data* sd, const char* title, const char* pass, int limit, bool pub) { struct chat_data* cd; nullpo_ret(sd); if( sd->chatID ) - return 0; //Prevent people abusing the chat system by creating multiple chats, as pointed out by End of Exam. [Skotlex] + 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 ) {// not chat, when you already have a store open - return 0; + return false; } - if( map[sd->bl.m].flag.nochat ) - { + if( map->list[sd->bl.m].flag.nochat ) { clif->message(sd->fd, msg_txt(281)); - return 0; //Can't create chatrooms on this map. + return false; //Can't create chatrooms on this map. } - if( iMap->getcell(sd->bl.m,sd->bl.x,sd->bl.y,CELL_CHKNOCHAT) ) - { - clif->message (sd->fd, msg_txt(665)); - return 0; + if( map->getcell(sd->bl.m,sd->bl.x,sd->bl.y,CELL_CHKNOCHAT) ) { + clif->message (sd->fd, msg_txt(865)); // "Can't create chat rooms in this area." + return false; } pc_stop_walking(sd,1); - cd = chat_createchat(&sd->bl, title, pass, limit, pub, 0, "", 0, 1, MAX_LEVEL); + cd = chat->create(&sd->bl, title, pass, limit, pub, 0, "", 0, 1, MAX_LEVEL); if( cd ) { cd->users = 1; cd->usersd[0] = sd; @@ -103,51 +103,51 @@ int chat_createpcchat(struct map_session_data* sd, const char* title, const char pc_stop_attack(sd); clif->createchat(sd,0); clif->dispchat(cd,0); - } else - clif->createchat(sd,1); + return true; + } + clif->createchat(sd,1); // 1 = Room limit exceeded - return 0; + return false; } /*========================================== * join an existing chatroom *------------------------------------------*/ -int chat_joinchat(struct map_session_data* sd, int chatid, const char* pass) -{ +bool chat_joinchat(struct map_session_data* sd, int chatid, const char* pass) { struct chat_data* cd; nullpo_ret(sd); - cd = (struct chat_data*)iMap->id2bl(chatid); + cd = (struct chat_data*)map->id2bl(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 ) { - clif->joinchatfail(sd,0); - return 0; + clif->joinchatfail(sd,0); // room full + return false; } if( !cd->pub && strncmp(pass, cd->pass, sizeof(cd->pass)) != 0 && !pc_has_permission(sd, PC_PERM_JOIN_ALL_CHAT) ) { - clif->joinchatfail(sd,1); - return 0; + clif->joinchatfail(sd,1); // wrong password + return false; } if( sd->status.base_level < cd->minLvl || sd->status.base_level > cd->maxLvl ) { if(sd->status.base_level < cd->minLvl) - clif->joinchatfail(sd,5); + clif->joinchatfail(sd,5); // too low level else - clif->joinchatfail(sd,6); + clif->joinchatfail(sd,6); // too high level - return 0; + return false; } if( sd->status.zeny < cd->zeny ) { - clif->joinchatfail(sd,4); - return 0; + clif->joinchatfail(sd,4); // not enough zeny + return false; } if( cd->owner->type != BL_NPC && idb_exists(cd->kick_list,sd->status.char_id) ) { - clif->joinchatfail(sd,2);//You have been kicked out of the room. - return 0; + clif->joinchatfail(sd,2); // You have been kicked out of the room. + return false; } pc_stop_walking(sd,1); @@ -157,38 +157,41 @@ int chat_joinchat(struct map_session_data* sd, int chatid, const char* pass) pc_setchatid(sd,cd->bl.id); clif->joinchatok(sd, cd); //To the person who newly joined the list of all - clif->addchat(cd, sd); //Reports To the person who already in the chat - clif->dispchat(cd, 0); //Reported number of changes to the people around + clif->addchat(cd, sd); //Reports To the person who already in the chat + clif->dispchat(cd, 0); //Reported number of changes to the people around - chat_triggerevent(cd); //Event + chat->trigger_event(cd); //Event - return 0; + return true; } /*========================================== - * leave a chatroom + * Leave a chatroom + * Return + * 0: User not found in chatroom/Missing data + * 1: Success + * 2: Chat room deleted (chat room empty) + * 3: Owner changed (Owner left and a new one as assigned) *------------------------------------------*/ -int chat_leavechat(struct map_session_data* sd, bool kicked) -{ +int chat_leavechat(struct map_session_data* sd, bool kicked) { struct chat_data* cd; int i; int leavechar; - nullpo_retr(1, sd); + nullpo_retr(0, sd); - cd = (struct chat_data*)iMap->id2bl(sd->chatID); - if( cd == NULL ) - { + cd = (struct chat_data*)map->id2bl(sd->chatID); + if( cd == NULL ) { pc_setchatid(sd, 0); - return 1; + return 0; } ARR_FIND( 0, cd->users, i, cd->usersd[i] == sd ); if ( i == cd->users ) { // Not found in the chatroom? pc_setchatid(sd, 0); - return -1; + return 0; } clif->leavechat(cd, sd, kicked); @@ -202,61 +205,63 @@ int chat_leavechat(struct map_session_data* sd, bool kicked) if( cd->users == 0 && cd->owner->type == BL_PC ) { // Delete empty chatroom - struct skill_unit* unit; - struct skill_unit_group* group; + struct skill_unit* su; + struct skill_unit_group* group; clif->clearchat(cd, 0); db_destroy(cd->kick_list); - iMap->deliddb(&cd->bl); - iMap->delblock(&cd->bl); - iMap->freeblock(&cd->bl); + map->deliddb(&cd->bl); + map->delblock(&cd->bl); + map->freeblock(&cd->bl); - unit = iMap->find_skill_unit_oncell(&sd->bl, sd->bl.x, sd->bl.y, AL_WARP, NULL, 0); - group = (unit != NULL) ? unit->group : NULL; + su = map->find_skill_unit_oncell(&sd->bl, sd->bl.x, sd->bl.y, AL_WARP, NULL, 0); + group = (su != NULL) ? su->group : NULL; if (group != NULL) - skill->unit_onplace(unit, &sd->bl, group->tick); + skill->unit_onplace(su, &sd->bl, group->tick); - return 1; + return 2; } - if( leavechar == 0 && cd->owner->type == BL_PC ) - { // Set and announce new owner + if( leavechar == 0 && cd->owner->type == BL_PC ) { + // Set and announce new owner cd->owner = (struct block_list*) cd->usersd[0]; clif->changechatowner(cd, cd->usersd[0]); clif->clearchat(cd, 0); //Adjust Chat location after owner has been changed. - iMap->delblock( &cd->bl ); + map->delblock( &cd->bl ); cd->bl.x=cd->usersd[0]->bl.x; cd->bl.y=cd->usersd[0]->bl.y; - iMap->addblock( &cd->bl ); + map->addblock( &cd->bl ); clif->dispchat(cd,0); + return 3; // Owner changed } - else - clif->dispchat(cd,0); // refresh chatroom + clif->dispchat(cd,0); // refresh chatroom - return 0; + return 1; } /*========================================== - * change a chatroom's owner + * Change a chatroom's owner + * Return + * 0: User not found/Missing data + * 1: Success *------------------------------------------*/ -int chat_changechatowner(struct map_session_data* sd, const char* nextownername) -{ +bool chat_changechatowner(struct map_session_data* sd, const char* nextownername) { struct chat_data* cd; struct map_session_data* tmpsd; int i; - nullpo_retr(1, sd); + nullpo_ret(sd); - cd = (struct chat_data*)iMap->id2bl(sd->chatID); + cd = (struct chat_data*)map->id2bl(sd->chatID); if( cd == NULL || (struct block_list*) sd != cd->owner ) - return 1; + return false; ARR_FIND( 1, cd->users, i, strncmp(cd->usersd[i]->status.name, nextownername, NAME_LENGTH) == 0 ); if( i == cd->users ) - return -1; // name not found + return false; // name not found // erase temporarily clif->clearchat(cd,0); @@ -271,29 +276,31 @@ int chat_changechatowner(struct map_session_data* sd, const char* nextownername) cd->usersd[0] = tmpsd; // set the new chatroom position - iMap->delblock( &cd->bl ); + map->delblock( &cd->bl ); cd->bl.x = cd->owner->x; cd->bl.y = cd->owner->y; - iMap->addblock( &cd->bl ); + map->addblock( &cd->bl ); // and display again clif->dispchat(cd,0); - return 0; + return true; } /*========================================== - * change a chatroom's status (title, etc) + * Change a chatroom's status (title, etc) + * Return + * 0: Missing data + * 1: Success *------------------------------------------*/ -int chat_changechatstatus(struct map_session_data* sd, const char* title, const char* pass, int limit, bool pub) -{ +bool chat_changechatstatus(struct map_session_data* sd, const char* title, const char* pass, int limit, bool pub) { struct chat_data* cd; - nullpo_retr(1, sd); + nullpo_ret(sd); - cd = (struct chat_data*)iMap->id2bl(sd->chatID); + cd = (struct chat_data*)map->id2bl(sd->chatID); if( cd==NULL || (struct block_list *)sd != cd->owner ) - return 1; + return false; safestrncpy(cd->title, title, CHATROOM_TITLE_SIZE); safestrncpy(cd->pass, pass, CHATROOM_PASS_SIZE); @@ -303,122 +310,161 @@ int chat_changechatstatus(struct map_session_data* sd, const char* title, const clif->changechatstatus(cd); clif->dispchat(cd,0); - return 0; + return true; } /*========================================== - * kick an user from a chatroom + * Kick an user from a chatroom + * Return: + * 0: User cannot be kicked (is gm)/Missing data + * 1: Success *------------------------------------------*/ -int chat_kickchat(struct map_session_data* sd, const char* kickusername) -{ +bool chat_kickchat(struct map_session_data* sd, const char* kickusername) { struct chat_data* cd; int i; - nullpo_retr(1, sd); + nullpo_ret(sd); - cd = (struct chat_data *)iMap->id2bl(sd->chatID); + cd = (struct chat_data *)map->id2bl(sd->chatID); if( cd==NULL || (struct block_list *)sd != cd->owner ) - return -1; + return false; ARR_FIND( 0, cd->users, i, strncmp(cd->usersd[i]->status.name, kickusername, NAME_LENGTH) == 0 ); - if( i == cd->users ) - return -1; + if( i == cd->users ) // User not found + return false; if (pc_has_permission(cd->usersd[i], PC_PERM_NO_CHAT_KICK)) - return 0; //gm kick protection [Valaris] + return false; //gm kick protection [Valaris] - idb_put(cd->kick_list,cd->usersd[i]->status.char_id,(void*)1); + idb_iput(cd->kick_list,cd->usersd[i]->status.char_id,1); - chat_leavechat(cd->usersd[i],1); - return 0; + chat->leave(cd->usersd[i],1); + return true; } -/// Creates a chat room for the npc. -int chat_createnpcchat(struct npc_data* nd, const char* title, int limit, bool pub, int trigger, const char* ev, int zeny, int minLvl, int maxLvl) +/*========================================== + * Creates a chat room for the npc + *------------------------------------------*/ +bool chat_createnpcchat(struct npc_data* nd, const char* title, int limit, bool pub, int trigger, const char* ev, int zeny, int minLvl, int maxLvl) { struct chat_data* cd; nullpo_ret(nd); if( nd->chat_id ) { ShowError("chat_createnpcchat: npc '%s' already has a chatroom, cannot create new one!\n", nd->exname); - return 0; + return false; } if( zeny > MAX_ZENY || maxLvl > MAX_LEVEL ) { ShowError("chat_createnpcchat: npc '%s' has a required lvl or amount of zeny over the max limit!\n", nd->exname); - return 0; + return false; } - cd = chat_createchat(&nd->bl, title, "", limit, pub, trigger, ev, zeny, minLvl, maxLvl); + cd = chat->create(&nd->bl, title, "", limit, pub, trigger, ev, zeny, minLvl, maxLvl); if( cd ) { nd->chat_id = cd->bl.id; clif->dispchat(cd,0); + return true; } - return 0; + return false; } -/// Removes the chatroom from the npc. -int chat_deletenpcchat(struct npc_data* nd) -{ +/*========================================== + * Removes the chatroom from the npc. + * Return: + * 0: Missing data + * 1: Success + *------------------------------------------*/ +bool chat_deletenpcchat(struct npc_data* nd) { struct chat_data *cd; nullpo_ret(nd); - cd = (struct chat_data*)iMap->id2bl(nd->chat_id); + cd = (struct chat_data*)map->id2bl(nd->chat_id); if( cd == NULL ) - return 0; + return false; - chat_npckickall(cd); + chat->npc_kick_all(cd); clif->clearchat(cd, 0); - iMap->deliddb(&cd->bl); - iMap->delblock(&cd->bl); - iMap->freeblock(&cd->bl); + map->deliddb(&cd->bl); + map->delblock(&cd->bl); + map->freeblock(&cd->bl); nd->chat_id = 0; - return 0; + return true; } /*========================================== * Trigger npc event when we enter the chatroom + * Return + * 0: Couldn't trigger / Missing data + * 1: Success *------------------------------------------*/ -int chat_triggerevent(struct chat_data *cd) +bool chat_triggerevent(struct chat_data *cd) { nullpo_ret(cd); if( cd->users >= cd->trigger && cd->npc_event[0] ) - npc_event_do(cd->npc_event); - return 0; + { + npc->event_do(cd->npc_event); + return true; + } + return false; } /// Enables the event of the chat room. /// At most, 127 users are needed to trigger the event. -int chat_enableevent(struct chat_data* cd) +bool chat_enableevent(struct chat_data* cd) { nullpo_ret(cd); cd->trigger &= 0x7f; - chat_triggerevent(cd); - return 0; + chat->trigger_event(cd); + return true; } /// Disables the event of the chat room -int chat_disableevent(struct chat_data* cd) +bool chat_disableevent(struct chat_data* cd) { nullpo_ret(cd); cd->trigger |= 0x80; - return 0; + return true; } /// Kicks all the users from the chat room. -int chat_npckickall(struct chat_data* cd) +bool chat_npckickall(struct chat_data* cd) { nullpo_ret(cd); while( cd->users > 0 ) - chat_leavechat(cd->usersd[cd->users-1],0); + chat->leave(cd->usersd[cd->users-1],0); - return 0; + return true; +} + +/*===================================== +* Default Functions : chat.h +* Generated by HerculesInterfaceMaker +* created by Susu +*-------------------------------------*/ +void chat_defaults(void) { + chat = &chat_s; + + /* funcs */ + chat->create_pc_chat = chat_createpcchat; + chat->join = chat_joinchat; + chat->leave = chat_leavechat; + chat->change_owner = chat_changechatowner; + chat->change_status = chat_changechatstatus; + chat->kick = chat_kickchat; + chat->create_npc_chat = chat_createnpcchat; + chat->delete_npc_chat = chat_deletenpcchat; + chat->enable_event = chat_enableevent; + chat->disable_event = chat_disableevent; + chat->npc_kick_all = chat_npckickall; + chat->trigger_event = chat_triggerevent; + chat->create = chat_createchat; } diff --git a/src/map/chat.h b/src/map/chat.h index cb2e6ecd9..e055c04ed 100644 --- a/src/map/chat.h +++ b/src/map/chat.h @@ -1,17 +1,23 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder +// Copyright (c) Hercules Dev Team, licensed under GNU GPL. +// See the LICENSE file +// Portions Copyright (c) Athena Dev Teams -#ifndef _CHAT_H_ -#define _CHAT_H_ +#ifndef MAP_CHAT_H +#define MAP_CHAT_H #include "map.h" // struct block_list, CHATROOM_TITLE_SIZE -struct map_session_data; +#include "../common/cbasetypes.h" +#include "../common/db.h" + struct chat_data; +struct map_session_data; +struct npc_data; +#define MAX_CHAT_USERS 20 struct chat_data { struct block_list bl; // data for this map object - char title[CHATROOM_TITLE_SIZE]; // room title + char title[CHATROOM_TITLE_SIZE]; // room title char pass[CHATROOM_PASS_SIZE]; // password bool pub; // private/public flag uint8 users; // current user count @@ -20,24 +26,38 @@ struct chat_data { uint32 zeny; // required zeny to join uint32 minLvl; // minimum base level to join uint32 maxLvl; // maximum base level allowed to join - struct map_session_data* usersd[20]; + struct map_session_data* usersd[MAX_CHAT_USERS]; struct block_list* owner; char npc_event[EVENT_NAME_LENGTH]; + /* isn't this a waste? there is a enormous overhead, wouldn't something like skill_blockpc_start be better here? [Ind] */ DBMap* kick_list; //DBMap of users who were kicked from this chat }; +/*===================================== +* Interface : chat.h +* Generated by HerculesInterfaceMaker +* created by Susu +*-------------------------------------*/ +struct chat_interface { + + /* funcs */ + bool (*create_pc_chat) (struct map_session_data* sd, const char* title, const char* pass, int limit, bool pub); + bool (*join) (struct map_session_data* sd, int chatid, const char* pass); + int (*leave) (struct map_session_data* sd, bool kicked); + bool (*change_owner) (struct map_session_data* sd, const char* nextownername); + bool (*change_status) (struct map_session_data* sd, const char* title, const char* pass, int limit, bool pub); + bool (*kick) (struct map_session_data* sd, const char* kickusername); + bool (*create_npc_chat) (struct npc_data* nd, const char* title, int limit, bool pub, int trigger, const char* ev, int zeny, int minLvl, int maxLvl); + bool (*delete_npc_chat) (struct npc_data* nd); + bool (*enable_event) (struct chat_data* cd); + bool (*disable_event) (struct chat_data* cd); + bool (*npc_kick_all) (struct chat_data* cd); + bool (*trigger_event) (struct chat_data *cd); + struct chat_data* (*create) (struct block_list* bl, const char* title, const char* pass, int limit, bool pub, int trigger, const char* ev, int zeny, int minLvl, int maxLvl); +}; -int chat_createpcchat(struct map_session_data* sd, const char* title, const char* pass, int limit, bool pub); -int chat_joinchat(struct map_session_data* sd, int chatid, const char* pass); -int chat_leavechat(struct map_session_data* sd, bool kicked); -int chat_changechatowner(struct map_session_data* sd, const char* nextownername); -int chat_changechatstatus(struct map_session_data* sd, const char* title, const char* pass, int limit, bool pub); -int chat_kickchat(struct map_session_data* sd, const char* kickusername); +struct chat_interface *chat; -int chat_createnpcchat(struct npc_data* nd, const char* title, int limit, bool pub, int trigger, const char* ev, int zeny, int minLvl, int maxLvl); -int chat_deletenpcchat(struct npc_data* nd); -int chat_enableevent(struct chat_data* cd); -int chat_disableevent(struct chat_data* cd); -int chat_npckickall(struct chat_data* cd); +void chat_defaults(void); -#endif /* _CHAT_H_ */ +#endif /* MAP_CHAT_H */ diff --git a/src/map/chrif.c b/src/map/chrif.c index 6e076e6d8..4c8cd747b 100644 --- a/src/map/chrif.c +++ b/src/map/chrif.c @@ -2,14 +2,16 @@ // See the LICENSE file // Portions Copyright (c) Athena Dev Teams -#include "../common/cbasetypes.h" -#include "../common/malloc.h" -#include "../common/socket.h" -#include "../common/timer.h" -#include "../common/nullpo.h" -#include "../common/showmsg.h" -#include "../common/strlib.h" -#include "../common/ers.h" +#define HERCULES_CORE + +#include "../config/core.h" // AUTOTRADE_PERSISTENCY, STATS_OPT_OUT +#include "chrif.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <time.h> #include "map.h" #include "battle.h" @@ -24,29 +26,19 @@ #include "instance.h" #include "mercenary.h" #include "elemental.h" -#include "chrif.h" #include "quest.h" #include "storage.h" +#include "../common/HPM.h" +#include "../common/cbasetypes.h" +#include "../common/ers.h" +#include "../common/malloc.h" +#include "../common/nullpo.h" +#include "../common/showmsg.h" +#include "../common/socket.h" +#include "../common/strlib.h" +#include "../common/timer.h" -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/types.h> -#include <time.h> - -static int check_connect_char_server(int tid, unsigned int tick, int id, intptr_t data); - -static struct eri *auth_db_ers; //For reutilizing player login structures. -static DBMap* auth_db; // int id -> struct auth_node* - -static const int packet_len_table[0x3d] = { // U - used, F - free - 60, 3,-1,27,10,-1, 6,-1, // 2af8-2aff: U->2af8, U->2af9, U->2afa, U->2afb, U->2afc, U->2afd, U->2afe, U->2aff - 6,-1,18, 7,-1,39,30, 10, // 2b00-2b07: U->2b00, U->2b01, U->2b02, U->2b03, U->2b04, U->2b05, U->2b06, U->2b07 - 6,30, -1, 0,86, 7,44,34, // 2b08-2b0f: U->2b08, U->2b09, U->2b0a, F->2b0b, U->2b0c, U->2b0d, U->2b0e, U->2b0f - 11,10,10, 0,11, 0,266,10, // 2b10-2b17: U->2b10, U->2b11, U->2b12, F->2b13, U->2b14, F->2b15, U->2b16, U->2b17 - 2,10, 2,-1,-1,-1, 2, 7, // 2b18-2b1f: U->2b18, U->2b19, U->2b1a, U->2b1b, U->2b1c, U->2b1d, U->2b1e, U->2b1f - -1,10, 8, 2, 2,14,19,19, // 2b20-2b27: U->2b20, U->2b21, U->2b22, U->2b23, U->2b24, U->2b25, U->2b26, U->2b27 -}; +struct chrif_interface chrif_s; //Used Packets: //2af8: Outgoing, chrif_connect -> 'connect to charserver / auth @ charserver' @@ -56,14 +48,14 @@ static const int packet_len_table[0x3d] = { // U - used, F - free //2afc: Outgoing, chrif_scdata_request -> request sc_data for pc->authok'ed char. <- new command reuses previous one. //2afd: Incoming, chrif_authok -> 'client authentication ok' //2afe: Outgoing, send_usercount_tochar -> 'sends player count of this map server to charserver' -//2aff: Outgoing, send_users_tochar -> 'sends all actual connected character ids to charserver' -//2b00: Incoming, iMap->setusers -> 'set the actual usercount? PACKET.2B COUNT.L.. ?' (not sure) +//2aff: Outgoing, chrif_send_users_tochar -> 'sends all actual connected character ids to charserver' +//2b00: Incoming, map_setusers -> 'set the actual usercount? PACKET.2B COUNT.L.. ?' (not sure) //2b01: Outgoing, chrif_save -> 'charsave of char XY account XY (complete struct)' //2b02: Outgoing, chrif_charselectreq -> 'player returns from ingame to charserver to select another char.., this packets includes sessid etc' ? (not 100% sure) //2b03: Incoming, clif_charselectok -> '' (i think its the packet after enterworld?) (not sure) //2b04: Incoming, chrif_recvmap -> 'getting maps from charserver of other mapserver's' //2b05: Outgoing, chrif_changemapserver -> 'Tell the charserver the mapchange / quest for ok...' -//2b06: Incoming, chrif_changemapserverack -> 'awnser of 2b05, ok/fail, data: dunno^^' +//2b06: Incoming, chrif_changemapserverack -> 'answer of 2b05, ok/fail, data: dunno^^' //2b07: Outgoing, chrif_removefriend -> 'Tell charserver to remove friend_id from char_id friend list' //2b08: Outgoing, chrif_searchcharid -> '...' //2b09: Incoming, map_addchariddb -> 'Adds a name to the nick db' @@ -87,7 +79,7 @@ static const int packet_len_table[0x3d] = { // U - used, F - free //2b1b: Incoming, chrif_recvfamelist -> 'Receive fame ranking lists' //2b1c: Outgoing, chrif_save_scdata -> 'Send sc_data of player for saving.' //2b1d: Incoming, chrif_load_scdata -> 'received sc_data of player for loading.' -//2b1e: Incoming, chrif_update_ip -> 'Reqest forwarded from char-server for interserver IP sync.' [Lance] +//2b1e: Incoming, chrif_update_ip -> 'Request forwarded from char-server for interserver IP sync.' [Lance] //2b1f: Incoming, chrif_disconnectplayer -> 'disconnects a player (aid X) with the message XY ... 0x81 ..' [Sirius] //2b20: Incoming, chrif_removemap -> 'remove maps of a server (sample: its going offline)' [Sirius] //2b21: Incoming, chrif_save_ack. Returned after a character has been "final saved" on the char-server. [Skotlex] @@ -98,23 +90,8 @@ static const int packet_len_table[0x3d] = { // U - used, F - free //2b26: Outgoing, chrif_authreq -> 'client authentication request' //2b27: Incoming, chrif_authfail -> 'client authentication failed' -int chrif_connected = 0; -int char_fd = -1; -int srvinfo; -static char char_ip_str[128]; -static uint32 char_ip = 0; -static uint16 char_port = 6121; -static char userid[NAME_LENGTH], passwd[NAME_LENGTH]; -static int chrif_state = 0; -int other_mapserver_count=0; //Holds count of how many other map servers are online (apart of this instance) [Skotlex] - -//Interval at which map server updates online listing. [Valaris] -#define CHECK_INTERVAL 3600000 -//Interval at which map server sends number of connected users. [Skotlex] -#define UPDATE_INTERVAL 10000 //This define should spare writing the check in every function. [Skotlex] -#define chrif_check(a) { if(!chrif_isconnected()) return a; } - +#define chrif_check(a) do { if(!chrif->isconnected()) return a; } while(0) /// Resets all the data. void chrif_reset(void) { @@ -122,45 +99,49 @@ void chrif_reset(void) { exit(EXIT_FAILURE); } - /// Checks the conditions for the server to stop. /// Releases the cookie when all characters are saved. /// If all the conditions are met, it stops the core loop. void chrif_check_shutdown(void) { if( runflag != MAPSERVER_ST_SHUTDOWN ) return; - if( auth_db->size(auth_db) > 0 ) + if( db_size(chrif->auth_db) > 0 ) return; runflag = CORE_ST_STOP; } struct auth_node* chrif_search(int account_id) { - return (struct auth_node*)idb_get(auth_db, account_id); + return (struct auth_node*)idb_get(chrif->auth_db, account_id); } struct auth_node* chrif_auth_check(int account_id, int char_id, enum sd_state state) { - struct auth_node *node = chrif_search(account_id); + struct auth_node *node = chrif->search(account_id); return ( node && node->char_id == char_id && node->state == state ) ? node : NULL; } bool chrif_auth_delete(int account_id, int char_id, enum sd_state state) { struct auth_node *node; - - if ( (node = chrif_auth_check(account_id, char_id, state) ) ) { + + if ( (node = chrif->auth_check(account_id, char_id, state) ) ) { int fd = node->sd ? node->sd->fd : node->fd; if ( session[fd] && session[fd]->session_data == node->sd ) session[fd]->session_data = NULL; - if ( node->char_dat ) - aFree(node->char_dat); - - if ( node->sd ) + if ( node->sd ) { + + if( node->sd->regs.vars ) + node->sd->regs.vars->destroy(node->sd->regs.vars, script->reg_destroy); + + if( node->sd->regs.arrays ) + node->sd->regs.arrays->destroy(node->sd->regs.arrays, script->array_free_db); + aFree(node->sd); + } - ers_free(auth_db_ers, node); - idb_remove(auth_db,account_id); + ers_free(chrif->auth_db_ers, node); + idb_remove(chrif->auth_db,account_id); return true; } @@ -168,13 +149,13 @@ bool chrif_auth_delete(int account_id, int char_id, enum sd_state state) { } //Moves the sd character to the auth_db structure. -static bool chrif_sd_to_auth(TBL_PC* sd, enum sd_state state) { +bool chrif_sd_to_auth(TBL_PC* sd, enum sd_state state) { struct auth_node *node; - if ( chrif_search(sd->status.account_id) ) + if ( chrif->search(sd->status.account_id) ) return false; //Already exists? - node = ers_alloc(auth_db_ers, struct auth_node); + node = ers_alloc(chrif->auth_db_ers, struct auth_node); memset(node, 0, sizeof(struct auth_node)); @@ -185,17 +166,17 @@ static bool chrif_sd_to_auth(TBL_PC* sd, enum sd_state state) { node->sex = sd->status.sex; node->fd = sd->fd; node->sd = sd; //Data from logged on char. - node->node_created = iTimer->gettick(); //timestamp for node timeouts + node->node_created = timer->gettick(); //timestamp for node timeouts node->state = state; sd->state.active = 0; - idb_put(auth_db, node->account_id, node); + idb_put(chrif->auth_db, node->account_id, node); return true; } -static bool chrif_auth_logout(TBL_PC* sd, enum sd_state state) { +bool chrif_auth_logout(TBL_PC* sd, enum sd_state state) { if(sd->fd && state == ST_LOGOUT) { //Disassociate player, and free it after saving ack returns. [Skotlex] //fd info must not be lost for ST_MAPCHANGE as a final packet needs to be sent to the player. @@ -204,33 +185,33 @@ static bool chrif_auth_logout(TBL_PC* sd, enum sd_state state) { sd->fd = 0; } - return chrif_sd_to_auth(sd, state); + return chrif->sd_to_auth(sd, state); } bool chrif_auth_finished(TBL_PC* sd) { - struct auth_node *node= chrif_search(sd->status.account_id); + struct auth_node *node= chrif->search(sd->status.account_id); if ( node && node->sd == sd && node->state == ST_LOGIN ) { node->sd = NULL; - return chrif_auth_delete(node->account_id, node->char_id, ST_LOGIN); + return chrif->auth_delete(node->account_id, node->char_id, ST_LOGIN); } return false; } // sets char-server's user id void chrif_setuserid(char *id) { - memcpy(userid, id, NAME_LENGTH); + memcpy(chrif->userid, id, NAME_LENGTH); } // sets char-server's password void chrif_setpasswd(char *pwd) { - memcpy(passwd, pwd, NAME_LENGTH); + memcpy(chrif->passwd, pwd, NAME_LENGTH); } // security check, prints warning if using default password void chrif_checkdefaultlogin(void) { - if (strcmp(userid, "s1")==0 && strcmp(passwd, "p1")==0) { + 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"); @@ -238,30 +219,29 @@ void chrif_checkdefaultlogin(void) { } // sets char-server's ip address -int chrif_setip(const char* ip) { +bool chrif_setip(const char* ip) { char ip_str[16]; - if ( !( char_ip = host2ip(ip) ) ) { + if ( !( chrif->ip = host2ip(ip) ) ) { ShowWarning("Failed to Resolve Char Server Address! (%s)\n", ip); - - return 0; + return false; } - safestrncpy(char_ip_str, ip, sizeof(char_ip_str)); + safestrncpy(chrif->ip_str, ip, sizeof(chrif->ip_str)); - ShowInfo("Char Server IP Address : '"CL_WHITE"%s"CL_RESET"' -> '"CL_WHITE"%s"CL_RESET"'.\n", ip, ip2str(char_ip, ip_str)); + ShowInfo("Char Server IP Address : '"CL_WHITE"%s"CL_RESET"' -> '"CL_WHITE"%s"CL_RESET"'.\n", ip, ip2str(chrif->ip, ip_str)); - return 1; + return true; } // sets char-server's port number void chrif_setport(uint16 port) { - char_port = port; + chrif->port = port; } // says whether the char-server is connected or not int chrif_isconnected(void) { - return (char_fd > 0 && session[char_fd] != NULL && chrif_state == 2); + return (chrif->fd > 0 && session[chrif->fd] != NULL && chrif->state == 2); } /*========================================== @@ -269,76 +249,70 @@ int chrif_isconnected(void) { * Flag = 1: Character is quitting * Flag = 2: Character is changing map-servers *------------------------------------------*/ -int chrif_save(struct map_session_data *sd, int flag) { - nullpo_retr(-1, sd); +bool chrif_save(struct map_session_data *sd, int flag) { + nullpo_ret(sd); pc->makesavestatus(sd); if (flag && sd->state.active) { //Store player data which is quitting //FIXME: SC are lost if there's no connection at save-time because of the way its related data is cleared immediately after this function. [Skotlex] - if ( chrif_isconnected() ) - chrif_save_scdata(sd); - if ( !chrif_auth_logout(sd,flag == 1 ? ST_LOGOUT : ST_MAPCHANGE) ) + if ( chrif->isconnected() ) + chrif->save_scdata(sd); + if ( !chrif->auth_logout(sd,flag == 1 ? ST_LOGOUT : ST_MAPCHANGE) ) ShowError("chrif_save: Failed to set up player %d:%d for proper quitting!\n", sd->status.account_id, sd->status.char_id); } - chrif_check(-1); //Character is saved on reconnect. + chrif_check(false); //Character is saved on reconnect. //For data sync if (sd->state.storage_flag == 2) - storage_guild_storagesave(sd->status.account_id, sd->status.guild_id, flag); + gstorage->save(sd->status.account_id, sd->status.guild_id, flag); if (flag) sd->state.storage_flag = 0; //Force close it. - //Saving of registry values. - if (sd->state.reg_dirty&4) - intif_saveregistry(sd, 3); //Save char regs - if (sd->state.reg_dirty&2) - intif_saveregistry(sd, 2); //Save account regs - if (sd->state.reg_dirty&1) - intif_saveregistry(sd, 1); //Save account2 regs - - WFIFOHEAD(char_fd, sizeof(sd->status) + 13); - WFIFOW(char_fd,0) = 0x2b01; - WFIFOW(char_fd,2) = sizeof(sd->status) + 13; - WFIFOL(char_fd,4) = sd->status.account_id; - WFIFOL(char_fd,8) = sd->status.char_id; - WFIFOB(char_fd,12) = (flag==1)?1:0; //Flag to tell char-server this character is quitting. - memcpy(WFIFOP(char_fd,13), &sd->status, sizeof(sd->status)); - WFIFOSET(char_fd, WFIFOW(char_fd,2)); + //Saving of registry values. + if (sd->vars_dirty) + intif->saveregistry(sd); + + WFIFOHEAD(chrif->fd, sizeof(sd->status) + 13); + WFIFOW(chrif->fd,0) = 0x2b01; + WFIFOW(chrif->fd,2) = sizeof(sd->status) + 13; + WFIFOL(chrif->fd,4) = sd->status.account_id; + WFIFOL(chrif->fd,8) = sd->status.char_id; + WFIFOB(chrif->fd,12) = (flag==1)?1:0; //Flag to tell char-server this character is quitting. + memcpy(WFIFOP(chrif->fd,13), &sd->status, sizeof(sd->status)); + WFIFOSET(chrif->fd, WFIFOW(chrif->fd,2)); if( sd->status.pet_id > 0 && sd->pd ) - intif_save_petdata(sd->status.account_id,&sd->pd->pet); + intif->save_petdata(sd->status.account_id,&sd->pd->pet); if( sd->hd && homun_alive(sd->hd) ) homun->save(sd->hd); - if( sd->md && mercenary_get_lifetime(sd->md) > 0 ) - mercenary_save(sd->md); - if( sd->ed && elemental_get_lifetime(sd->ed) > 0 ) - elemental_save(sd->ed); + if( sd->md && mercenary->get_lifetime(sd->md) > 0 ) + mercenary->save(sd->md); + if( sd->ed && elemental->get_lifetime(sd->ed) > 0 ) + elemental->save(sd->ed); if( sd->save_quest ) - intif_quest_save(sd); + intif->quest_save(sd); - return 0; + return true; } // connects to char-server (plaintext) -int chrif_connect(int fd) { - ShowStatus("Logging in to char server...\n", char_fd); +void chrif_connect(int fd) { + ShowStatus("Logging in to char server...\n"); WFIFOHEAD(fd,60); WFIFOW(fd,0) = 0x2af8; - memcpy(WFIFOP(fd,2), userid, NAME_LENGTH); - memcpy(WFIFOP(fd,26), passwd, NAME_LENGTH); + memcpy(WFIFOP(fd,2), chrif->userid, NAME_LENGTH); + memcpy(WFIFOP(fd,26), chrif->passwd, NAME_LENGTH); WFIFOL(fd,50) = 0; WFIFOL(fd,54) = htonl(clif->map_ip); WFIFOW(fd,58) = htons(clif->map_port); WFIFOSET(fd,60); - - return 0; } // sends maps to char-server -int chrif_sendmap(int fd) { +void chrif_sendmap(int fd) { int i; ShowStatus("Sending maps to char server...\n"); @@ -347,108 +321,102 @@ int chrif_sendmap(int fd) { WFIFOHEAD(fd, 4 + instance->start_id * 4); WFIFOW(fd,0) = 0x2afa; for(i = 0; i < instance->start_id; i++) - WFIFOW(fd,4+i*4) = map[i].index; + WFIFOW(fd,4+i*4) = map_id2index(i); WFIFOW(fd,2) = 4 + i * 4; WFIFOSET(fd,WFIFOW(fd,2)); - - return 0; } // receive maps from some other map-server (relayed via char-server) -int chrif_recvmap(int fd) { +void chrif_recvmap(int fd) { int i, j; uint32 ip = ntohl(RFIFOL(fd,4)); uint16 port = ntohs(RFIFOW(fd,8)); for(i = 10, j = 0; i < RFIFOW(fd,2); i += 4, j++) { - iMap->setipport(RFIFOW(fd,i), ip, port); + map->setipport(RFIFOW(fd,i), ip, port); } if (battle_config.etc_log) ShowStatus("Received maps from %d.%d.%d.%d:%d (%d maps)\n", CONVIP(ip), port, j); - other_mapserver_count++; - - return 0; + chrif->other_mapserver_count++; } // remove specified maps (used when some other map-server disconnects) -int chrif_removemap(int fd) { +void chrif_removemap(int fd) { int i, j; uint32 ip = RFIFOL(fd,4); uint16 port = RFIFOW(fd,8); for(i = 10, j = 0; i < RFIFOW(fd, 2); i += 4, j++) - iMap->eraseipport(RFIFOW(fd, i), ip, port); + map->eraseipport(RFIFOW(fd, i), ip, port); - other_mapserver_count--; + chrif->other_mapserver_count--; if(battle_config.etc_log) ShowStatus("remove map of server %d.%d.%d.%d:%d (%d maps)\n", CONVIP(ip), port, j); - - return 0; } // received after a character has been "final saved" on the char-server -static void chrif_save_ack(int fd) { - chrif_auth_delete(RFIFOL(fd,2), RFIFOL(fd,6), ST_LOGOUT); - chrif_check_shutdown(); +void chrif_save_ack(int fd) { + chrif->auth_delete(RFIFOL(fd,2), RFIFOL(fd,6), ST_LOGOUT); + chrif->check_shutdown(); } // request to move a character between mapservers -int chrif_changemapserver(struct map_session_data* sd, uint32 ip, uint16 port) { - nullpo_retr(-1, sd); +bool chrif_changemapserver(struct map_session_data* sd, uint32 ip, uint16 port) { + nullpo_ret(sd); - if (other_mapserver_count < 1) {//No other map servers are online! + if (chrif->other_mapserver_count < 1) {//No other map servers are online! clif->authfail_fd(sd->fd, 0); - return -1; + return false; } - chrif_check(-1); - - WFIFOHEAD(char_fd,35); - WFIFOW(char_fd, 0) = 0x2b05; - WFIFOL(char_fd, 2) = sd->bl.id; - WFIFOL(char_fd, 6) = sd->login_id1; - WFIFOL(char_fd,10) = sd->login_id2; - WFIFOL(char_fd,14) = sd->status.char_id; - WFIFOW(char_fd,18) = sd->mapindex; - WFIFOW(char_fd,20) = sd->bl.x; - WFIFOW(char_fd,22) = sd->bl.y; - WFIFOL(char_fd,24) = htonl(ip); - WFIFOW(char_fd,28) = htons(port); - WFIFOB(char_fd,30) = sd->status.sex; - WFIFOL(char_fd,31) = htonl(session[sd->fd]->client_addr); - WFIFOL(char_fd,35) = sd->group_id; - WFIFOSET(char_fd,39); + chrif_check(false); + + WFIFOHEAD(chrif->fd,35); + WFIFOW(chrif->fd, 0) = 0x2b05; + WFIFOL(chrif->fd, 2) = sd->bl.id; + WFIFOL(chrif->fd, 6) = sd->login_id1; + WFIFOL(chrif->fd,10) = sd->login_id2; + WFIFOL(chrif->fd,14) = sd->status.char_id; + WFIFOW(chrif->fd,18) = sd->mapindex; + WFIFOW(chrif->fd,20) = sd->bl.x; + WFIFOW(chrif->fd,22) = sd->bl.y; + WFIFOL(chrif->fd,24) = htonl(ip); + WFIFOW(chrif->fd,28) = htons(port); + WFIFOB(chrif->fd,30) = sd->status.sex; + WFIFOL(chrif->fd,31) = htonl(session[sd->fd]->client_addr); + WFIFOL(chrif->fd,35) = sd->group_id; + WFIFOSET(chrif->fd,39); - return 0; + return true; } -/// map-server change request acknowledgement (positive or negative) +/// map-server change request acknowledgment (positive or negative) /// R 2b06 <account_id>.L <login_id1>.L <login_id2>.L <char_id>.L <map_index>.W <x>.W <y>.W <ip>.L <port>.W -int chrif_changemapserverack(int account_id, int login_id1, int login_id2, int char_id, short map_index, short x, short y, uint32 ip, uint16 port) { +bool chrif_changemapserverack(int account_id, int login_id1, int login_id2, int char_id, short map_index, short x, short y, uint32 ip, uint16 port) { struct auth_node *node; - if ( !( node = chrif_auth_check(account_id, char_id, ST_MAPCHANGE) ) ) - return -1; + if ( !( node = chrif->auth_check(account_id, char_id, ST_MAPCHANGE) ) ) + return false; if ( !login_id1 ) { - ShowError("map server change failed.\n"); + ShowError("chrif_changemapserverack: map server change failed.\n"); clif->authfail_fd(node->fd, 0); } else clif->changemapserver(node->sd, map_index, x, y, ntohl(ip), ntohs(port)); //Player has been saved already, remove him from memory. [Skotlex] - chrif_auth_delete(account_id, char_id, ST_MAPCHANGE); + chrif->auth_delete(account_id, char_id, ST_MAPCHANGE); - return 0; + return (!login_id1)?false:true; // Is this the best approach here? } /*========================================== * *------------------------------------------*/ -int chrif_connectack(int fd) { +void chrif_connectack(int fd) { static bool char_init_done = false; if (RFIFOB(fd,2)) { @@ -457,52 +425,49 @@ int chrif_connectack(int fd) { } ShowStatus("Successfully logged on to Char Server (Connection: '"CL_WHITE"%d"CL_RESET"').\n",fd); - chrif_state = 1; - chrif_connected = 1; + chrif->state = 1; + chrif->connected = 1; - chrif_sendmap(fd); + chrif->sendmap(fd); - ShowStatus("Event '"CL_WHITE"OnInterIfInit"CL_RESET"' executed with '"CL_WHITE"%d"CL_RESET"' NPCs.\n", npc_event_doall("OnInterIfInit")); + ShowStatus("Event '"CL_WHITE"OnInterIfInit"CL_RESET"' executed with '"CL_WHITE"%d"CL_RESET"' NPCs.\n", npc->event_doall("OnInterIfInit")); if( !char_init_done ) { char_init_done = true; - ShowStatus("Event '"CL_WHITE"OnInterIfInitOnce"CL_RESET"' executed with '"CL_WHITE"%d"CL_RESET"' NPCs.\n", npc_event_doall("OnInterIfInitOnce")); + ShowStatus("Event '"CL_WHITE"OnInterIfInitOnce"CL_RESET"' executed with '"CL_WHITE"%d"CL_RESET"' NPCs.\n", npc->event_doall("OnInterIfInitOnce")); guild->castle_map_init(); } - socket_datasync(fd, true); - chrif_skillid2idx(fd); - - return 0; + sockt->datasync(fd, true); + chrif->skillid2idx(fd); } /** * @see DBApply */ -static int chrif_reconnect(DBKey key, DBData *data, va_list ap) { +int chrif_reconnect(DBKey key, DBData *data, va_list ap) { struct auth_node *node = DB->data2ptr(data); switch (node->state) { case ST_LOGIN: - if ( node->sd && node->char_dat == NULL ) {//Since there is no way to request the char auth, make it fail. + if ( node->sd ) {//Since there is no way to request the char auth, make it fail. pc->authfail(node->sd); chrif_char_offline(node->sd); - chrif_auth_delete(node->account_id, node->char_id, ST_LOGIN); + chrif->auth_delete(node->account_id, node->char_id, ST_LOGIN); } break; case ST_LOGOUT: //Re-send final save - chrif_save(node->sd, 1); + chrif->save(node->sd, 1); break; case ST_MAPCHANGE: { //Re-send map-change request. struct map_session_data *sd = node->sd; uint32 ip; uint16 port; - if( iMap->mapname2ipport(sd->mapindex,&ip,&port) == 0 ) - chrif_changemapserver(sd, ip, port); + if( map->mapname2ipport(sd->mapindex,&ip,&port) == 0 ) + chrif->changemapserver(sd, ip, port); else //too much lag/timeout is the closest explanation for this error. clif->authfail_fd(sd->fd, 3); - break; } } @@ -513,81 +478,88 @@ static int chrif_reconnect(DBKey key, DBData *data, va_list ap) { /// Called when all the connection steps are completed. void chrif_on_ready(void) { + static bool once = false; ShowStatus("Map Server is now online.\n"); - chrif_state = 2; + chrif->state = 2; - chrif_check_shutdown(); + chrif->check_shutdown(); //If there are players online, send them to the char-server. [Skotlex] - send_users_tochar(); + chrif->send_users_tochar(); //Auth db reconnect handling - auth_db->foreach(auth_db,chrif_reconnect); + chrif->auth_db->foreach(chrif->auth_db,chrif->reconnect); //Re-save any storages that were modified in the disconnection time. [Skotlex] - do_reconnect_storage(); + storage->reconnect(); //Re-save any guild castles that were modified in the disconnection time. guild->castle_reconnect(-1, 0, 0); + + if( !once ) { +#ifdef AUTOTRADE_PERSISTENCY + pc->autotrade_load(); +#endif + once = true; + } } /*========================================== * *------------------------------------------*/ -int chrif_sendmapack(int fd) { +void chrif_sendmapack(int fd) { if (RFIFOB(fd,2)) { ShowFatalError("chrif : send map list to char server failed %d\n", RFIFOB(fd,2)); exit(EXIT_FAILURE); } - memcpy(iMap->wisp_server_name, RFIFOP(fd,3), NAME_LENGTH); + memcpy(map->wisp_server_name, RFIFOP(fd,3), NAME_LENGTH); - chrif_on_ready(); - - return 0; + chrif->on_ready(); } /*========================================== * Request sc_data from charserver [Skotlex] *------------------------------------------*/ -int chrif_scdata_request(int account_id, int char_id) { +bool chrif_scdata_request(int account_id, int char_id) { #ifdef ENABLE_SC_SAVING - chrif_check(-1); + chrif_check(false); - WFIFOHEAD(char_fd,10); - WFIFOW(char_fd,0) = 0x2afc; - WFIFOL(char_fd,2) = account_id; - WFIFOL(char_fd,6) = char_id; - WFIFOSET(char_fd,10); + WFIFOHEAD(chrif->fd,10); + WFIFOW(chrif->fd,0) = 0x2afc; + WFIFOL(chrif->fd,2) = account_id; + WFIFOL(chrif->fd,6) = char_id; + WFIFOSET(chrif->fd,10); #endif - return 0; + return true; } /*========================================== * Request auth confirmation *------------------------------------------*/ -void chrif_authreq(struct map_session_data *sd) { - struct auth_node *node= chrif_search(sd->bl.id); - - if( node != NULL || !chrif_isconnected() ) { +void chrif_authreq(struct map_session_data *sd, bool hstandalone) { + struct auth_node *node= chrif->search(sd->bl.id); + + if( node != NULL || !chrif->isconnected() ) { set_eof(sd->fd); return; } - WFIFOHEAD(char_fd,19); - WFIFOW(char_fd,0) = 0x2b26; - WFIFOL(char_fd,2) = sd->status.account_id; - WFIFOL(char_fd,6) = sd->status.char_id; - WFIFOL(char_fd,10) = sd->login_id1; - WFIFOB(char_fd,14) = sd->status.sex; - WFIFOL(char_fd,15) = htonl(session[sd->fd]->client_addr); - WFIFOSET(char_fd,19); - chrif_sd_to_auth(sd, ST_LOGIN); + WFIFOHEAD(chrif->fd,20); + WFIFOW(chrif->fd,0) = 0x2b26; + WFIFOL(chrif->fd,2) = sd->status.account_id; + WFIFOL(chrif->fd,6) = sd->status.char_id; + WFIFOL(chrif->fd,10) = sd->login_id1; + WFIFOB(chrif->fd,14) = sd->status.sex; + WFIFOL(chrif->fd,15) = htonl(session[sd->fd]->client_addr); + WFIFOB(chrif->fd,19) = hstandalone ? 1 : 0; + WFIFOSET(chrif->fd,20); + chrif->sd_to_auth(sd, ST_LOGIN); } /*========================================== @@ -597,14 +569,14 @@ void chrif_authok(int fd) { int account_id, group_id, char_id; uint32 login_id1,login_id2; time_t expiration_time; - struct mmo_charstatus* status; + struct mmo_charstatus* charstatus; struct auth_node *node; bool changing_mapservers; TBL_PC* sd; //Check if both servers agree on the struct's size if( RFIFOW(fd,2) - 25 != sizeof(struct mmo_charstatus) ) { - ShowError("chrif_authok: Data size mismatch! %d != %d\n", RFIFOW(fd,2) - 25, sizeof(struct mmo_charstatus)); + ShowError("chrif_authok: Data size mismatch! %d != %"PRIuS"\n", RFIFOW(fd,2) - 25, sizeof(struct mmo_charstatus)); return; } @@ -614,15 +586,15 @@ void chrif_authok(int fd) { expiration_time = (time_t)(int32)RFIFOL(fd,16); group_id = RFIFOL(fd,20); changing_mapservers = (RFIFOB(fd,24)); - status = (struct mmo_charstatus*)RFIFOP(fd,25); - char_id = status->char_id; + charstatus = (struct mmo_charstatus*)RFIFOP(fd,25); + char_id = charstatus->char_id; //Check if we don't already have player data in our server //Causes problems if the currently connected player tries to quit or this data belongs to an already connected player which is trying to re-auth. - if ( ( sd = iMap->id2sd(account_id) ) != NULL ) + if ( ( sd = map->id2sd(account_id) ) != NULL ) return; - - if ( ( node = chrif_search(account_id) ) == NULL ) + + if ( ( node = chrif->search(account_id) ) == NULL ) return; // should not happen if ( node->state != ST_LOGIN ) @@ -632,7 +604,7 @@ void chrif_authok(int fd) { /* //When we receive double login info and the client has not connected yet, //discard the older one and keep the new one. - chrif_auth_delete(node->account_id, node->char_id, ST_LOGIN); + chrif->auth_delete(node->account_id, node->char_id, ST_LOGIN); */ return; // should not happen } @@ -640,19 +612,18 @@ void chrif_authok(int fd) { sd = node->sd; if( runflag == MAPSERVER_ST_RUNNING && - node->char_dat == NULL && node->account_id == account_id && node->char_id == char_id && node->login_id1 == login_id1 ) { //Auth Ok - if (pc->authok(sd, login_id2, expiration_time, group_id, status, changing_mapservers)) + if (pc->authok(sd, login_id2, expiration_time, group_id, charstatus, changing_mapservers)) return; } else { //Auth Failed pc->authfail(sd); } chrif_char_offline(sd); //Set him offline, the char server likely has it set as online already. - chrif_auth_delete(account_id, char_id, ST_LOGIN); + chrif->auth_delete(account_id, char_id, ST_LOGIN); } // client authentication failed @@ -667,7 +638,7 @@ void chrif_authfail(int fd) {/* HELLO WORLD. ip in RFIFOL 15 is not being used ( login_id1 = RFIFOL(fd,10); sex = RFIFOB(fd,14); - node = chrif_search(account_id); + node = chrif->search(account_id); if( node != NULL && node->account_id == account_id && @@ -677,7 +648,7 @@ void chrif_authfail(int fd) {/* HELLO WORLD. ip in RFIFOL 15 is not being used ( node->state == ST_LOGIN ) {// found a match clif->authfail_fd(node->fd, 0); - chrif_auth_delete(account_id, char_id, ST_LOGIN); + chrif->auth_delete(account_id, char_id, ST_LOGIN); } } @@ -690,18 +661,18 @@ int auth_db_cleanup_sub(DBKey key, DBData *data, va_list ap) { struct auth_node *node = DB->data2ptr(data); const char* states[] = { "Login", "Logout", "Map change" }; - if(DIFF_TICK(iTimer->gettick(),node->node_created)>60000) { + if(DIFF_TICK(timer->gettick(),node->node_created)>60000) { switch (node->state) { case ST_LOGOUT: //Re-save attempt (->sd should never be null here). - node->node_created = iTimer->gettick(); //Refresh tick (avoid char-server load if connection is really bad) - chrif_save(node->sd, 1); + node->node_created = timer->gettick(); //Refresh tick (avoid char-server load if connection is really bad) + chrif->save(node->sd, 1); break; default: //Clear data. any connected players should have timed out by now. ShowInfo("auth_db: Node (state %s) timed out for %d:%d\n", states[node->state], node->account_id, node->char_id); - chrif_char_offline_nsd(node->account_id, node->char_id); - chrif_auth_delete(node->account_id, node->char_id, node->state); + chrif->char_offline_nsd(node->account_id, node->char_id); + chrif->auth_delete(node->account_id, node->char_id, node->state); break; } return 1; @@ -709,150 +680,156 @@ int auth_db_cleanup_sub(DBKey key, DBData *data, va_list ap) { return 0; } -int auth_db_cleanup(int tid, unsigned int tick, int id, intptr_t data) { +int auth_db_cleanup(int tid, int64 tick, int id, intptr_t data) { chrif_check(0); - auth_db->foreach(auth_db, auth_db_cleanup_sub); + chrif->auth_db->foreach(chrif->auth_db, chrif->auth_db_cleanup_sub); return 0; } /*========================================== - * + * Request char selection *------------------------------------------*/ -int chrif_charselectreq(struct map_session_data* sd, uint32 s_ip) { - nullpo_retr(-1, sd); +bool chrif_charselectreq(struct map_session_data* sd, uint32 s_ip) { + nullpo_ret(sd); - if( !sd || !sd->bl.id || !sd->login_id1 ) - return -1; + if( !sd->bl.id || !sd->login_id1 ) + return false; - chrif_check(-1); + chrif_check(false); - WFIFOHEAD(char_fd,18); - WFIFOW(char_fd, 0) = 0x2b02; - WFIFOL(char_fd, 2) = sd->bl.id; - WFIFOL(char_fd, 6) = sd->login_id1; - WFIFOL(char_fd,10) = sd->login_id2; - WFIFOL(char_fd,14) = htonl(s_ip); - WFIFOSET(char_fd,18); + WFIFOHEAD(chrif->fd,22); + WFIFOW(chrif->fd, 0) = 0x2b02; + WFIFOL(chrif->fd, 2) = sd->bl.id; + WFIFOL(chrif->fd, 6) = sd->login_id1; + WFIFOL(chrif->fd,10) = sd->login_id2; + WFIFOL(chrif->fd,14) = htonl(s_ip); + WFIFOL(chrif->fd,18) = sd->group_id; + WFIFOSET(chrif->fd,22); - return 0; + return true; } /*========================================== * Search Char trough id on char serv *------------------------------------------*/ -int chrif_searchcharid(int char_id) { +bool chrif_searchcharid(int char_id) { if( !char_id ) - return -1; + return false; - chrif_check(-1); + chrif_check(false); - WFIFOHEAD(char_fd,6); - WFIFOW(char_fd,0) = 0x2b08; - WFIFOL(char_fd,2) = char_id; - WFIFOSET(char_fd,6); + WFIFOHEAD(chrif->fd,6); + WFIFOW(chrif->fd,0) = 0x2b08; + WFIFOL(chrif->fd,2) = char_id; + WFIFOSET(chrif->fd,6); - return 0; + return true; } /*========================================== * Change Email *------------------------------------------*/ -int chrif_changeemail(int id, const char *actual_email, const char *new_email) { +bool chrif_changeemail(int id, const char *actual_email, const char *new_email) { if (battle_config.etc_log) ShowInfo("chrif_changeemail: account: %d, actual_email: '%s', new_email: '%s'.\n", id, actual_email, new_email); - chrif_check(-1); + chrif_check(false); - WFIFOHEAD(char_fd,86); - WFIFOW(char_fd,0) = 0x2b0c; - WFIFOL(char_fd,2) = id; - memcpy(WFIFOP(char_fd,6), actual_email, 40); - memcpy(WFIFOP(char_fd,46), new_email, 40); - WFIFOSET(char_fd,86); + WFIFOHEAD(chrif->fd,86); + WFIFOW(chrif->fd,0) = 0x2b0c; + WFIFOL(chrif->fd,2) = id; + memcpy(WFIFOP(chrif->fd,6), actual_email, 40); + memcpy(WFIFOP(chrif->fd,46), new_email, 40); + WFIFOSET(chrif->fd,86); - return 0; + return true; } /*========================================== * S 2b0e <accid>.l <name>.24B <type>.w { <year>.w <month>.w <day>.w <hour>.w <minute>.w <second>.w } * Send an account modification request to the login server (via char server). * type of operation: - * 1: block, 2: ban, 3: unblock, 4: unban, 5: changesex (use next function for 5) + * 1: block, 2: ban, 3: unblock, 4: unban, 5: changesex (use next function for 5), 6: charban *------------------------------------------*/ -int chrif_char_ask_name(int acc, const char* character_name, unsigned short operation_type, int year, int month, int day, int hour, int minute, int second) { - - chrif_check(-1); - - WFIFOHEAD(char_fd,44); - WFIFOW(char_fd,0) = 0x2b0e; - WFIFOL(char_fd,2) = acc; - safestrncpy((char*)WFIFOP(char_fd,6), character_name, NAME_LENGTH); - WFIFOW(char_fd,30) = operation_type; - - if ( operation_type == 2 ) { - WFIFOW(char_fd,32) = year; - WFIFOW(char_fd,34) = month; - WFIFOW(char_fd,36) = day; - WFIFOW(char_fd,38) = hour; - WFIFOW(char_fd,40) = minute; - WFIFOW(char_fd,42) = second; +bool chrif_char_ask_name(int acc, const char* character_name, unsigned short operation_type, int year, int month, int day, int hour, int minute, int second) { + + chrif_check(false); + + WFIFOHEAD(chrif->fd,44); + WFIFOW(chrif->fd,0) = 0x2b0e; + WFIFOL(chrif->fd,2) = acc; + safestrncpy((char*)WFIFOP(chrif->fd,6), character_name, NAME_LENGTH); + WFIFOW(chrif->fd,30) = operation_type; + + if ( operation_type == 2 || operation_type == 6 ) { + WFIFOW(chrif->fd,32) = year; + WFIFOW(chrif->fd,34) = month; + WFIFOW(chrif->fd,36) = day; + WFIFOW(chrif->fd,38) = hour; + WFIFOW(chrif->fd,40) = minute; + WFIFOW(chrif->fd,42) = second; } - WFIFOSET(char_fd,44); - return 0; + WFIFOSET(chrif->fd,44); + return true; } -int chrif_changesex(struct map_session_data *sd) { - chrif_check(-1); +bool chrif_changesex(struct map_session_data *sd) { + chrif_check(false); - WFIFOHEAD(char_fd,44); - WFIFOW(char_fd,0) = 0x2b0e; - WFIFOL(char_fd,2) = sd->status.account_id; - safestrncpy((char*)WFIFOP(char_fd,6), sd->status.name, NAME_LENGTH); - WFIFOW(char_fd,30) = 5; - WFIFOSET(char_fd,44); + WFIFOHEAD(chrif->fd,44); + WFIFOW(chrif->fd,0) = 0x2b0e; + WFIFOL(chrif->fd,2) = sd->status.account_id; + safestrncpy((char*)WFIFOP(chrif->fd,6), sd->status.name, NAME_LENGTH); + WFIFOW(chrif->fd,30) = 5; + WFIFOSET(chrif->fd,44); - clif->message(sd->fd, msg_txt(408)); //"Need disconnection to perform change-sex request..." + clif->message(sd->fd, msg_txt(408)); //"Disconnecting to perform change-sex request..." if (sd->fd) clif->authfail_fd(sd->fd, 15); else - iMap->quit(sd); - return 0; + map->quit(sd); + return true; } /*========================================== * R 2b0f <accid>.l <name>.24B <type>.w <answer>.w - * Processing a reply to chrif_char_ask_name() (request to modify an account). + * Processing a reply to chrif->char_ask_name() (request to modify an account). * type of operation: - * 1: block, 2: ban, 3: unblock, 4: unban, 5: changesex + * 1: block, 2: ban, 3: unblock, 4: unban, 5: changesex, 6: charban, 7: charunban * type of answer: * 0: login-server request done * 1: player not found * 2: gm level too low * 3: login-server offline *------------------------------------------*/ -static void chrif_char_ask_name_answer(int acc, const char* player_name, uint16 type, uint16 answer) { +bool chrif_char_ask_name_answer(int acc, const char* player_name, uint16 type, uint16 answer) { struct map_session_data* sd; char action[25]; char output[256]; + bool charsrv = ( type == 6 || type == 7 ) ? true : false; - sd = iMap->id2sd(acc); + sd = map->id2sd(acc); if( acc < 0 || sd == NULL ) { ShowError("chrif_char_ask_name_answer failed - player not online.\n"); - return; + return false; } + /* re-use previous msg_txt */ + if( type == 6 ) type = 2; + if( type == 7 ) type = 4; + if( type > 0 && type <= 5 ) snprintf(action,25,"%s",msg_txt(427+type)); //block|ban|unblock|unban|change the sex of else snprintf(action,25,"???"); switch( answer ) { - case 0 : sprintf(output, msg_txt(424), action, NAME_LENGTH, player_name); break; + case 0 : sprintf(output, msg_txt(charsrv?434:424), action, NAME_LENGTH, player_name); break; case 1 : sprintf(output, msg_txt(425), NAME_LENGTH, player_name); break; case 2 : sprintf(output, msg_txt(426), action, NAME_LENGTH, player_name); break; case 3 : sprintf(output, msg_txt(427), action, NAME_LENGTH, player_name); break; @@ -860,115 +837,76 @@ static void chrif_char_ask_name_answer(int acc, const char* player_name, uint16 } clif->message(sd->fd, output); + return true; } /*========================================== * Request char server to change sex of char (modified by Yor) *------------------------------------------*/ -int chrif_changedsex(int fd) { - int acc, sex; - struct map_session_data *sd; - - acc = RFIFOL(fd,2); - sex = RFIFOL(fd,6); +void chrif_changedsex(int fd) { + int acc = RFIFOL(fd,2); + //int sex = RFIFOL(fd,6); // Dead store. Uncomment if needed again. if ( battle_config.etc_log ) ShowNotice("chrif_changedsex %d.\n", acc); - - sd = iMap->id2sd(acc); - if ( sd ) { //Normally there should not be a char logged on right now! - if ( sd->status.sex == sex ) - return 0; //Do nothing? Likely safe. - sd->status.sex = !sd->status.sex; - - // reset skill of some job - if ((sd->class_&MAPID_UPPERMASK) == MAPID_BARDDANCER) { - int i, idx = 0; - // remove specifical skills of Bard classes - for(i = 315; i <= 322; i++) { - idx = skill->get_index(i); - if (sd->status.skill[idx].id > 0 && sd->status.skill[idx].flag == SKILL_FLAG_PERMANENT) { - sd->status.skill_point += sd->status.skill[idx].lv; - sd->status.skill[idx].id = 0; - sd->status.skill[idx].lv = 0; - } - } - // remove specifical skills of Dancer classes - for(i = 323; i <= 330; i++) { - idx = skill->get_index(i); - if (sd->status.skill[idx].id > 0 && sd->status.skill[idx].flag == SKILL_FLAG_PERMANENT) { - sd->status.skill_point += sd->status.skill[idx].lv; - sd->status.skill[idx].id = 0; - sd->status.skill[idx].lv = 0; - } - } - clif->updatestatus(sd, SP_SKILLPOINT); - // change job if necessary - if (sd->status.sex) //Changed from Dancer - sd->status.class_ -= 1; - else //Changed from Bard - sd->status.class_ += 1; - //sd->class_ needs not be updated as both Dancer/Bard are the same. - } - // save character - sd->login_id1++; // change identify, because if player come back in char within the 5 seconds, he can change its characters - // do same modify in login-server for the account, but no in char-server (it ask again login_id1 to login, and don't remember it) - clif->message(sd->fd, msg_txt(409)); //"Your sex has been changed (need disconnection by the server)..." - set_eof(sd->fd); // forced to disconnect for the change - iMap->quit(sd); // Remove leftovers (e.g. autotrading) [Paradox924X] - } - return 0; + + // Path to activate this response: + // Map(start) (0x2b0e) -> Char(0x2727) -> Login + // Login(0x2723) [ALL] -> Char (0x2b0d)[ALL] -> Map (HERE) + // Char will usually be "logged in" despite being forced to log-out in the beginning + // of this process, but there's no need to perform map-server specific response + // as everything should been changed through char-server [Panikon] } /*========================================== * Request Char Server to Divorce Players *------------------------------------------*/ -int chrif_divorce(int partner_id1, int partner_id2) { - chrif_check(-1); +bool chrif_divorce(int partner_id1, int partner_id2) { + chrif_check(false); - WFIFOHEAD(char_fd,10); - WFIFOW(char_fd,0) = 0x2b11; - WFIFOL(char_fd,2) = partner_id1; - WFIFOL(char_fd,6) = partner_id2; - WFIFOSET(char_fd,10); + WFIFOHEAD(chrif->fd,10); + WFIFOW(chrif->fd,0) = 0x2b11; + WFIFOL(chrif->fd,2) = partner_id1; + WFIFOL(chrif->fd,6) = partner_id2; + WFIFOSET(chrif->fd,10); - return 0; + return true; } /*========================================== * Divorce players * only used if 'partner_id' is offline *------------------------------------------*/ -int chrif_divorceack(int char_id, int partner_id) { +bool chrif_divorceack(int char_id, int partner_id) { struct map_session_data* sd; int i; if( !char_id || !partner_id ) - return 0; + return false; - if( ( sd = iMap->charid2sd(char_id) ) != NULL && sd->status.partner_id == partner_id ) { + if( ( sd = map->charid2sd(char_id) ) != NULL && sd->status.partner_id == partner_id ) { sd->status.partner_id = 0; for(i = 0; i < MAX_INVENTORY; i++) if (sd->status.inventory[i].nameid == WEDDING_RING_M || sd->status.inventory[i].nameid == WEDDING_RING_F) pc->delitem(sd, i, 1, 0, 0, LOG_TYPE_OTHER); } - if( ( sd = iMap->charid2sd(partner_id) ) != NULL && sd->status.partner_id == char_id ) { + if( ( sd = map->charid2sd(partner_id) ) != NULL && sd->status.partner_id == char_id ) { sd->status.partner_id = 0; for(i = 0; i < MAX_INVENTORY; i++) if (sd->status.inventory[i].nameid == WEDDING_RING_M || sd->status.inventory[i].nameid == WEDDING_RING_F) pc->delitem(sd, i, 1, 0, 0, LOG_TYPE_OTHER); } - return 0; + return true; } /*========================================== * Removes Baby from parents *------------------------------------------*/ -int chrif_deadopt(int father_id, int mother_id, int child_id) { +void chrif_deadopt(int father_id, int mother_id, int child_id) { struct map_session_data* sd; int idx = skill->get_index(WE_CALLBABY); - if( father_id && ( sd = iMap->charid2sd(father_id) ) != NULL && sd->status.child == child_id ) { + if( father_id && ( sd = map->charid2sd(father_id) ) != NULL && sd->status.child == child_id ) { sd->status.child = 0; sd->status.skill[idx].id = 0; sd->status.skill[idx].lv = 0; @@ -976,7 +914,7 @@ int chrif_deadopt(int father_id, int mother_id, int child_id) { clif->deleteskill(sd,WE_CALLBABY); } - if( mother_id && ( sd = iMap->charid2sd(mother_id) ) != NULL && sd->status.child == child_id ) { + if( mother_id && ( sd = map->charid2sd(mother_id) ) != NULL && sd->status.child == child_id ) { sd->status.child = 0; sd->status.skill[idx].id = 0; sd->status.skill[idx].lv = 0; @@ -984,49 +922,54 @@ int chrif_deadopt(int father_id, int mother_id, int child_id) { clif->deleteskill(sd,WE_CALLBABY); } - return 0; } /*========================================== - * Disconnection of a player (account has been banned of has a status, from login-server) by [Yor] + * Disconnection of a player (account or char has been banned of has a status, from login or char server) by [Yor] *------------------------------------------*/ -int chrif_accountban(int fd) { - int acc; +void chrif_idbanned(int fd) { + int id; struct map_session_data *sd; - acc = RFIFOL(fd,2); + id = RFIFOL(fd,2); if ( battle_config.etc_log ) - ShowNotice("chrif_accountban %d.\n", acc); + ShowNotice("chrif_idbanned %d.\n", id); - sd = iMap->id2sd(acc); + sd = ( RFIFOB(fd,6) == 2 ) ? map->charid2sd(id) : map->id2sd(id); - if ( acc < 0 || sd == NULL ) { - ShowError("chrif_accountban failed - player not online.\n"); - return 0; + if ( id < 0 || sd == NULL ) { + /* player not online or unknown id, either way no error is necessary (since if you try to ban a offline char it still works) */ + return; } sd->login_id1++; // change identify, because if player come back in char within the 5 seconds, he can change its characters - if (RFIFOB(fd,6) == 0) { // 0: change of statut, 1: ban - int ret_status = RFIFOL(fd,7); // status or final date of a banishment - if(0<ret_status && ret_status<=9) - clif->message(sd->fd, msg_txt(411+ret_status)); - else if(ret_status==100) - clif->message(sd->fd, msg_txt(421)); - else - clif->message(sd->fd, msg_txt(420)); //"Your account has not more authorised." - } else if (RFIFOB(fd,6) == 1) { // 0: change of statut, 1: ban + if (RFIFOB(fd,6) == 0) { // 0: change of status + int ret_status = RFIFOL(fd,7); // status or final date of a banishment + if(0<ret_status && ret_status<=9) + clif->message(sd->fd, msg_txt(411+ret_status)); // Message IDs (for search convenience): 412, 413, 414, 415, 416, 417, 418, 419, 420 + else if(ret_status==100) + clif->message(sd->fd, msg_txt(421)); + else + clif->message(sd->fd, msg_txt(420)); //"Your account has not more authorized." + } else if (RFIFOB(fd,6) == 1) { // 1: ban time_t timestamp; char tmpstr[2048]; timestamp = (time_t)RFIFOL(fd,7); // status or final date of a banishment strcpy(tmpstr, msg_txt(423)); //"Your account has been banished until " strftime(tmpstr + strlen(tmpstr), 24, "%d-%m-%Y %H:%M:%S", localtime(×tamp)); clif->message(sd->fd, tmpstr); + } else if (RFIFOB(fd,6) == 2) { // 2: change of status for character + time_t timestamp; + char tmpstr[2048]; + timestamp = (time_t)RFIFOL(fd,7); // status or final date of a banishment + strcpy(tmpstr, msg_txt(433)); //"This character has been banned until " + strftime(tmpstr + strlen(tmpstr), 24, "%d-%m-%Y %H:%M:%S", localtime(×tamp)); + clif->message(sd->fd, tmpstr); } set_eof(sd->fd); // forced to disconnect for the change - iMap->quit(sd); // Remove leftovers (e.g. autotrading) [Paradox924X] - return 0; + map->quit(sd); // Remove leftovers (e.g. autotrading) [Paradox924X] } //Disconnect the player out of the game, simple packet @@ -1035,11 +978,11 @@ int chrif_disconnectplayer(int fd) { struct map_session_data* sd; int account_id = RFIFOL(fd, 2); - sd = iMap->id2sd(account_id); + sd = map->id2sd(account_id); if( sd == NULL ) { - struct auth_node* auth = chrif_search(account_id); + struct auth_node* auth = chrif->search(account_id); - if( auth != NULL && chrif_auth_delete(account_id, auth->char_id, ST_LOGIN) ) + if( auth != NULL && chrif->auth_delete(account_id, auth->char_id, ST_LOGIN) ) return 0; return -1; @@ -1047,7 +990,7 @@ int chrif_disconnectplayer(int fd) { if (!sd->fd) { //No connection if (sd->state.autotrade) - iMap->quit(sd); //Remove it. + map->quit(sd); //Remove it. //Else we don't remove it because the char should have a timer to remove the player because it force-quit before, //and we don't want them kicking their previous instance before the 10 secs penalty time passes. [Skotlex] return 0; @@ -1072,45 +1015,45 @@ int chrif_updatefamelist(struct map_session_data* sd) { chrif_check(-1); switch(sd->class_ & MAPID_UPPERMASK) { - case MAPID_BLACKSMITH: type = 1; break; - case MAPID_ALCHEMIST: type = 2; break; - case MAPID_TAEKWON: type = 3; break; + case MAPID_BLACKSMITH: type = RANKTYPE_BLACKSMITH; break; + case MAPID_ALCHEMIST: type = RANKTYPE_ALCHEMIST; break; + case MAPID_TAEKWON: type = RANKTYPE_TAEKWON; break; default: return 0; } - WFIFOHEAD(char_fd, 11); - WFIFOW(char_fd,0) = 0x2b10; - WFIFOL(char_fd,2) = sd->status.char_id; - WFIFOL(char_fd,6) = sd->status.fame; - WFIFOB(char_fd,10) = type; - WFIFOSET(char_fd,11); + WFIFOHEAD(chrif->fd, 11); + WFIFOW(chrif->fd,0) = 0x2b10; + WFIFOL(chrif->fd,2) = sd->status.char_id; + WFIFOL(chrif->fd,6) = sd->status.fame; + WFIFOB(chrif->fd,10) = type; + WFIFOSET(chrif->fd,11); return 0; } -int chrif_buildfamelist(void) { - chrif_check(-1); +bool chrif_buildfamelist(void) { + chrif_check(false); - WFIFOHEAD(char_fd,2); - WFIFOW(char_fd,0) = 0x2b1a; - WFIFOSET(char_fd,2); + WFIFOHEAD(chrif->fd,2); + WFIFOW(chrif->fd,0) = 0x2b1a; + WFIFOSET(chrif->fd,2); - return 0; + return true; } -int chrif_recvfamelist(int fd) { +void chrif_recvfamelist(int fd) { int num, size; int total = 0, len = 8; - memset (smith_fame_list, 0, sizeof(smith_fame_list)); - memset (chemist_fame_list, 0, sizeof(chemist_fame_list)); - memset (taekwon_fame_list, 0, sizeof(taekwon_fame_list)); + memset(pc->smith_fame_list, 0, sizeof(pc->smith_fame_list)); + memset(pc->chemist_fame_list, 0, sizeof(pc->chemist_fame_list)); + memset(pc->taekwon_fame_list, 0, sizeof(pc->taekwon_fame_list)); size = RFIFOW(fd, 6); //Blacksmith block size for (num = 0; len < size && num < MAX_FAME_LIST; num++) { - memcpy(&smith_fame_list[num], RFIFOP(fd,len), sizeof(struct fame_list)); + memcpy(&pc->smith_fame_list[num], RFIFOP(fd,len), sizeof(struct fame_list)); len += sizeof(struct fame_list); } @@ -1119,7 +1062,7 @@ int chrif_recvfamelist(int fd) { size = RFIFOW(fd, 4); //Alchemist block size for (num = 0; len < size && num < MAX_FAME_LIST; num++) { - memcpy(&chemist_fame_list[num], RFIFOP(fd,len), sizeof(struct fame_list)); + memcpy(&pc->chemist_fame_list[num], RFIFOP(fd,len), sizeof(struct fame_list)); len += sizeof(struct fame_list); } @@ -1128,15 +1071,13 @@ int chrif_recvfamelist(int fd) { size = RFIFOW(fd, 2); //Total packet length for (num = 0; len < size && num < MAX_FAME_LIST; num++) { - memcpy(&taekwon_fame_list[num], RFIFOP(fd,len), sizeof(struct fame_list)); + memcpy(&pc->taekwon_fame_list[num], RFIFOP(fd,len), sizeof(struct fame_list)); len += sizeof(struct fame_list); } total += num; ShowInfo("Received Fame List of '"CL_WHITE"%d"CL_RESET"' characters.\n", total); - - return 0; } /// fame ranking update confirmation @@ -1146,9 +1087,9 @@ int chrif_updatefamelist_ack(int fd) { uint8 index; switch (RFIFOB(fd,2)) { - case 1: list = smith_fame_list; break; - case 2: list = chemist_fame_list; break; - case 3: list = taekwon_fame_list; break; + case RANKTYPE_BLACKSMITH: list = pc->smith_fame_list; break; + case RANKTYPE_ALCHEMIST: list = pc->chemist_fame_list; break; + case RANKTYPE_TAEKWON: list = pc->taekwon_fame_list; break; default: return 0; } @@ -1162,31 +1103,31 @@ int chrif_updatefamelist_ack(int fd) { return 1; } -int chrif_save_scdata(struct map_session_data *sd) { //parses the sc_data of the player and sends it to the char-server for saving. [Skotlex] +bool chrif_save_scdata(struct map_session_data *sd) { //parses the sc_data of the player and sends it to the char-server for saving. [Skotlex] #ifdef ENABLE_SC_SAVING int i, count=0; - unsigned int tick; + int64 tick; struct status_change_data data; struct status_change *sc = &sd->sc; - const struct TimerData *timer; + const struct TimerData *td; - chrif_check(-1); - tick = iTimer->gettick(); + chrif_check(false); + tick = timer->gettick(); - WFIFOHEAD(char_fd, 14 + SC_MAX*sizeof(struct status_change_data)); - WFIFOW(char_fd,0) = 0x2b1c; - WFIFOL(char_fd,4) = sd->status.account_id; - WFIFOL(char_fd,8) = sd->status.char_id; + WFIFOHEAD(chrif->fd, 14 + SC_MAX*sizeof(struct status_change_data)); + WFIFOW(chrif->fd,0) = 0x2b1c; + WFIFOL(chrif->fd,4) = sd->status.account_id; + WFIFOL(chrif->fd,8) = sd->status.char_id; for (i = 0; i < SC_MAX; i++) { if (!sc->data[i]) continue; if (sc->data[i]->timer != INVALID_TIMER) { - timer = iTimer->get_timer(sc->data[i]->timer); - if (timer == NULL || timer->func != status_change_timer || DIFF_TICK(timer->tick,tick) < 0) + td = timer->get(sc->data[i]->timer); + if (td == NULL || td->func != status->change_timer || DIFF_TICK(td->tick,tick) < 0) continue; - data.tick = DIFF_TICK(timer->tick,tick); //Duration that is left before ending. + data.tick = DIFF_TICK32(td->tick,tick); //Duration that is left before ending. } else data.tick = -1; //Infinite duration data.type = i; @@ -1194,24 +1135,24 @@ int chrif_save_scdata(struct map_session_data *sd) { //parses the sc_data of the data.val2 = sc->data[i]->val2; data.val3 = sc->data[i]->val3; data.val4 = sc->data[i]->val4; - memcpy(WFIFOP(char_fd,14 +count*sizeof(struct status_change_data)), + memcpy(WFIFOP(chrif->fd,14 +count*sizeof(struct status_change_data)), &data, sizeof(struct status_change_data)); count++; } if (count == 0) - return 0; //Nothing to save. + return true; //Nothing to save. | Everything was as successful as if there was something to save. - WFIFOW(char_fd,12) = count; - WFIFOW(char_fd,2) = 14 +count*sizeof(struct status_change_data); //Total packet size - WFIFOSET(char_fd,WFIFOW(char_fd,2)); + WFIFOW(chrif->fd,12) = count; + WFIFOW(chrif->fd,2) = 14 +count*sizeof(struct status_change_data); //Total packet size + WFIFOSET(chrif->fd,WFIFOW(chrif->fd,2)); #endif - return 0; + return true; } //Retrieve and load sc_data for a player. [Skotlex] -int chrif_load_scdata(int fd) { +bool chrif_load_scdata(int fd) { #ifdef ENABLE_SC_SAVING struct map_session_data *sd; @@ -1221,127 +1162,116 @@ int chrif_load_scdata(int fd) { aid = RFIFOL(fd,4); //Player Account ID cid = RFIFOL(fd,8); //Player Char ID - sd = iMap->id2sd(aid); + sd = map->id2sd(aid); if ( !sd ) { ShowError("chrif_load_scdata: Player of AID %d not found!\n", aid); - return -1; + return false; } if ( sd->status.char_id != cid ) { ShowError("chrif_load_scdata: Receiving data for account %d, char id does not matches (%d != %d)!\n", aid, sd->status.char_id, cid); - return -1; + return false; } count = RFIFOW(fd,12); //sc_count for (i = 0; i < count; i++) { data = (struct status_change_data*)RFIFOP(fd,14 + i*sizeof(struct status_change_data)); - status_change_start(&sd->bl, (sc_type)data->type, 10000, data->val1, data->val2, data->val3, data->val4, data->tick, 15); + status->change_start(NULL, &sd->bl, (sc_type)data->type, 10000, data->val1, data->val2, data->val3, data->val4, data->tick, 15); } + + pc->scdata_received(sd); #endif - return 0; + return true; } /*========================================== * Send rates to char server [Wizputer] * S 2b16 <base rate>.L <job rate>.L <drop rate>.L *------------------------------------------*/ -int chrif_ragsrvinfo(int base_rate, int job_rate, int drop_rate) { - chrif_check(-1); +bool chrif_ragsrvinfo(int base_rate, int job_rate, int drop_rate) { + chrif_check(false); - WFIFOHEAD(char_fd,14); - WFIFOW(char_fd,0) = 0x2b16; - WFIFOL(char_fd,2) = base_rate; - WFIFOL(char_fd,6) = job_rate; - WFIFOL(char_fd,10) = drop_rate; - WFIFOSET(char_fd,14); + WFIFOHEAD(chrif->fd,14); + WFIFOW(chrif->fd,0) = 0x2b16; + WFIFOL(chrif->fd,2) = base_rate; + WFIFOL(chrif->fd,6) = job_rate; + WFIFOL(chrif->fd,10) = drop_rate; + WFIFOSET(chrif->fd,14); - return 0; + return true; } /*========================================= - * Tell char-server charcter disconnected [Wizputer] + * Tell char-server character disconnected [Wizputer] *-----------------------------------------*/ -int chrif_char_offline(struct map_session_data *sd) { - chrif_check(-1); - - WFIFOHEAD(char_fd,10); - WFIFOW(char_fd,0) = 0x2b17; - WFIFOL(char_fd,2) = sd->status.char_id; - WFIFOL(char_fd,6) = sd->status.account_id; - WFIFOSET(char_fd,10); +bool chrif_char_offline_nsd(int account_id, int char_id) { + chrif_check(false); - return 0; -} -int chrif_char_offline_nsd(int account_id, int char_id) { - chrif_check(-1); - - WFIFOHEAD(char_fd,10); - WFIFOW(char_fd,0) = 0x2b17; - WFIFOL(char_fd,2) = char_id; - WFIFOL(char_fd,6) = account_id; - WFIFOSET(char_fd,10); + WFIFOHEAD(chrif->fd,10); + WFIFOW(chrif->fd,0) = 0x2b17; + WFIFOL(chrif->fd,2) = char_id; + WFIFOL(chrif->fd,6) = account_id; + WFIFOSET(chrif->fd,10); - return 0; + return true; } /*========================================= * Tell char-server to reset all chars offline [Wizputer] *-----------------------------------------*/ -int chrif_flush_fifo(void) { - chrif_check(-1); +bool chrif_flush(void) { + chrif_check(false); - set_nonblocking(char_fd, 0); + set_nonblocking(chrif->fd, 0); flush_fifos(); - set_nonblocking(char_fd, 1); + set_nonblocking(chrif->fd, 1); - return 0; + return true; } /*========================================= * Tell char-server to reset all chars offline [Wizputer] *-----------------------------------------*/ -int chrif_char_reset_offline(void) { - chrif_check(-1); +bool chrif_char_reset_offline(void) { + chrif_check(false); - WFIFOHEAD(char_fd,2); - WFIFOW(char_fd,0) = 0x2b18; - WFIFOSET(char_fd,2); + WFIFOHEAD(chrif->fd,2); + WFIFOW(chrif->fd,0) = 0x2b18; + WFIFOSET(chrif->fd,2); - return 0; + return true; } /*========================================= - * Tell char-server charcter is online [Wizputer] + * Tell char-server character is online [Wizputer] *-----------------------------------------*/ +bool chrif_char_online(struct map_session_data *sd) { + chrif_check(false); -int chrif_char_online(struct map_session_data *sd) { - chrif_check(-1); - - WFIFOHEAD(char_fd,10); - WFIFOW(char_fd,0) = 0x2b19; - WFIFOL(char_fd,2) = sd->status.char_id; - WFIFOL(char_fd,6) = sd->status.account_id; - WFIFOSET(char_fd,10); + WFIFOHEAD(chrif->fd,10); + WFIFOW(chrif->fd,0) = 0x2b19; + WFIFOL(chrif->fd,2) = sd->status.char_id; + WFIFOL(chrif->fd,6) = sd->status.account_id; + WFIFOSET(chrif->fd,10); - return 0; + return true; } - /// Called when the connection to Char Server is disconnected. void chrif_on_disconnect(void) { - if( chrif_connected != 1 ) + if( chrif->connected != 1 ) ShowWarning("Connection to Char Server lost.\n\n"); - chrif_connected = 0; + chrif->connected = 0; - other_mapserver_count = 0; //Reset counter. We receive ALL maps from all map-servers on reconnect. - iMap->eraseallipport(); + chrif->other_mapserver_count = 0; //Reset counter. We receive ALL maps from all map-servers on reconnect. + map->eraseallipport(); //Attempt to reconnect in a second. [Skotlex] - iTimer->add_timer(iTimer->gettick() + 1000, check_connect_char_server, 0, 0); + timer->add(timer->gettick() + 1000, chrif->check_connect_char_server, 0, 0); } @@ -1350,10 +1280,10 @@ void chrif_update_ip(int fd) { WFIFOHEAD(fd,6); - new_ip = host2ip(char_ip_str); + new_ip = host2ip(chrif->ip_str); - if (new_ip && new_ip != char_ip) - char_ip = new_ip; //Update char_ip + if (new_ip && new_ip != chrif->ip) + chrif->ip = new_ip; //Update chrif->ip new_ip = clif->refresh_ip(); @@ -1365,7 +1295,7 @@ void chrif_update_ip(int fd) { WFIFOSET(fd,6); } -// pings the charserver +// pings the charserver ( since on-demand flag.ping was introduced, shouldn't this be dropped? only wasting traffic and processing [Ind]) void chrif_keepalive(int fd) { WFIFOHEAD(fd,2); WFIFOW(fd,0) = 0x2b23; @@ -1377,13 +1307,16 @@ void chrif_keepalive_ack(int fd) { void chrif_skillid2idx(int fd) { int i, count = 0; - if( fd == 0 ) fd = char_fd; + if( fd == 0 ) fd = chrif->fd; + + if( !session_isValid(fd) ) + return; WFIFOHEAD(fd,4 + (MAX_SKILL * 4)); WFIFOW(fd,0) = 0x2b0b; for(i = 0; i < MAX_SKILL; i++) { - if( skill_db[i].nameid ) { - WFIFOW(fd, 4 + (count*4)) = skill_db[i].nameid; + if( skill->db[i].nameid ) { + WFIFOW(fd, 4 + (count*4)) = skill->db[i].nameid; WFIFOW(fd, 6 + (count*4)) = i; count++; } @@ -1396,10 +1329,10 @@ void chrif_skillid2idx(int fd) { * *------------------------------------------*/ int chrif_parse(int fd) { - int packet_len, cmd; + int packet_len, cmd, r; // only process data from the char-server - if ( fd != char_fd ) { + if ( fd != chrif->fd ) { ShowDebug("chrif_parse: Disconnecting invalid session #%d (is not the char-server)\n", fd); do_close(fd); return 0; @@ -1407,33 +1340,42 @@ int chrif_parse(int fd) { if ( session[fd]->flag.eof ) { do_close(fd); - char_fd = -1; - chrif_on_disconnect(); + chrif->fd = -1; + chrif->on_disconnect(); return 0; } else if ( session[fd]->flag.ping ) {/* we've reached stall time */ - if( DIFF_TICK(last_tick, session[fd]->rdata_tick) > (stall_time * 2) ) {/* we can't wait any longer */ + if( DIFF_TICK(sockt->last_tick, session[fd]->rdata_tick) > (sockt->stall_time * 2) ) {/* we can't wait any longer */ set_eof(fd); return 0; } else if( session[fd]->flag.ping != 2 ) { /* we haven't sent ping out yet */ - chrif_keepalive(fd); + chrif->keepalive(fd); session[fd]->flag.ping = 2; } } while ( RFIFOREST(fd) >= 2 ) { + + if( HPM->packetsc[hpChrif_Parse] ) { + if( (r = HPM->parse_packets(fd,hpChrif_Parse)) ) { + if( r == 1 ) continue; + if( r == 2 ) return 0; + } + } + cmd = RFIFOW(fd,0); - if (cmd < 0x2af8 || cmd >= 0x2af8 + ARRAYLENGTH(packet_len_table) || packet_len_table[cmd-0x2af8] == 0) { - int r = intif_parse(fd); // Passed on to the intif + + if (cmd < 0x2af8 || cmd >= 0x2af8 + ARRAYLENGTH(chrif->packet_len_table) || chrif->packet_len_table[cmd-0x2af8] == 0) { + r = intif->parse(fd); // Passed on to the intif - if (r == 1) continue; // Treated in intif + if (r == 1) continue; // Treated in intif if (r == 2) return 0; // Didn't have enough data (len==-1) - ShowWarning("chrif_parse: session #%d, intif_parse failed (unrecognized command 0x%.4x).\n", fd, cmd); + ShowWarning("chrif_parse: session #%d, intif->parse failed (unrecognized command 0x%.4x).\n", fd, cmd); set_eof(fd); return 0; } - if ( ( packet_len = packet_len_table[cmd-0x2af8] ) == -1) { // dynamic-length packet, second WORD holds the length + if ( ( packet_len = chrif->packet_len_table[cmd-0x2af8] ) == -1) { // dynamic-length packet, second WORD holds the length if (RFIFOREST(fd) < 4) return 0; packet_len = RFIFOW(fd,2); @@ -1445,49 +1387,48 @@ int chrif_parse(int fd) { //ShowDebug("Received packet 0x%4x (%d bytes) from char-server (connection %d)\n", RFIFOW(fd,0), packet_len, fd); switch(cmd) { - case 0x2af9: chrif_connectack(fd); break; - case 0x2afb: chrif_sendmapack(fd); break; - case 0x2afd: chrif_authok(fd); break; - case 0x2b00: iMap->setusers(RFIFOL(fd,2)); chrif_keepalive(fd); break; + case 0x2af9: chrif->connectack(fd); break; + case 0x2afb: chrif->sendmapack(fd); break; + case 0x2afd: chrif->authok(fd); break; + case 0x2b00: map->setusers(RFIFOL(fd,2)); chrif->keepalive(fd); break; case 0x2b03: clif->charselectok(RFIFOL(fd,2), RFIFOB(fd,6)); break; - case 0x2b04: chrif_recvmap(fd); break; - case 0x2b06: chrif_changemapserverack(RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10), RFIFOL(fd,14), RFIFOW(fd,18), RFIFOW(fd,20), RFIFOW(fd,22), RFIFOL(fd,24), RFIFOW(fd,28)); break; - case 0x2b09: iMap->addnickdb(RFIFOL(fd,2), (char*)RFIFOP(fd,6)); break; - case 0x2b0a: socket_datasync(fd, false); break; - case 0x2b0d: chrif_changedsex(fd); break; - case 0x2b0f: chrif_char_ask_name_answer(RFIFOL(fd,2), (char*)RFIFOP(fd,6), RFIFOW(fd,30), RFIFOW(fd,32)); break; - case 0x2b12: chrif_divorceack(RFIFOL(fd,2), RFIFOL(fd,6)); break; - case 0x2b14: chrif_accountban(fd); break; - case 0x2b1b: chrif_recvfamelist(fd); break; - case 0x2b1d: chrif_load_scdata(fd); break; - case 0x2b1e: chrif_update_ip(fd); break; - case 0x2b1f: chrif_disconnectplayer(fd); break; - case 0x2b20: chrif_removemap(fd); break; - case 0x2b21: chrif_save_ack(fd); break; - case 0x2b22: chrif_updatefamelist_ack(fd); break; - case 0x2b24: chrif_keepalive_ack(fd); break; - case 0x2b25: chrif_deadopt(RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10)); break; - case 0x2b27: chrif_authfail(fd); break; + case 0x2b04: chrif->recvmap(fd); break; + case 0x2b06: chrif->changemapserverack(RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10), RFIFOL(fd,14), RFIFOW(fd,18), RFIFOW(fd,20), RFIFOW(fd,22), RFIFOL(fd,24), RFIFOW(fd,28)); break; + case 0x2b09: map->addnickdb(RFIFOL(fd,2), (char*)RFIFOP(fd,6)); break; + case 0x2b0a: sockt->datasync(fd, false); break; + case 0x2b0d: chrif->changedsex(fd); break; + case 0x2b0f: chrif->char_ask_name_answer(RFIFOL(fd,2), (char*)RFIFOP(fd,6), RFIFOW(fd,30), RFIFOW(fd,32)); break; + case 0x2b12: chrif->divorceack(RFIFOL(fd,2), RFIFOL(fd,6)); break; + case 0x2b14: chrif->idbanned(fd); break; + case 0x2b1b: chrif->recvfamelist(fd); break; + case 0x2b1d: chrif->load_scdata(fd); break; + case 0x2b1e: chrif->update_ip(fd); break; + case 0x2b1f: chrif->disconnectplayer(fd); break; + case 0x2b20: chrif->removemap(fd); break; + case 0x2b21: chrif->save_ack(fd); break; + case 0x2b22: chrif->updatefamelist_ack(fd); break; + case 0x2b24: chrif->keepalive_ack(fd); break; + case 0x2b25: chrif->deadopt(RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10)); break; + case 0x2b27: chrif->authfail(fd); break; default: ShowError("chrif_parse : unknown packet (session #%d): 0x%x. Disconnecting.\n", fd, cmd); set_eof(fd); return 0; } - if ( fd == char_fd ) //There's the slight chance we lost the connection during parse, in which case this would segfault if not checked [Skotlex] + if ( fd == chrif->fd ) //There's the slight chance we lost the connection during parse, in which case this would segfault if not checked [Skotlex] RFIFOSKIP(fd, packet_len); } return 0; } -// unused -int send_usercount_tochar(int tid, unsigned int tick, int id, intptr_t data) { +int send_usercount_tochar(int tid, int64 tick, int id, intptr_t data) { chrif_check(-1); - WFIFOHEAD(char_fd,4); - WFIFOW(char_fd,0) = 0x2afe; - WFIFOW(char_fd,2) = iMap->usercount(); - WFIFOSET(char_fd,4); + WFIFOHEAD(chrif->fd,4); + WFIFOW(chrif->fd,0) = 0x2afe; + WFIFOW(chrif->fd,2) = map->usercount(); + WFIFOSET(chrif->fd,4); return 0; } @@ -1495,66 +1436,66 @@ int send_usercount_tochar(int tid, unsigned int tick, int id, intptr_t data) { * timerFunction * Send to char the number of client connected to map *------------------------------------------*/ -int send_users_tochar(void) { +bool send_users_tochar(void) { int users = 0, i = 0; struct map_session_data* sd; struct s_mapiterator* iter; - chrif_check(-1); + chrif_check(false); - users = iMap->usercount(); + users = map->usercount(); - WFIFOHEAD(char_fd, 6+8*users); - WFIFOW(char_fd,0) = 0x2aff; + WFIFOHEAD(chrif->fd, 6+8*users); + WFIFOW(chrif->fd,0) = 0x2aff; iter = mapit_getallusers(); for( sd = (TBL_PC*)mapit->first(iter); mapit->exists(iter); sd = (TBL_PC*)mapit->next(iter) ) { - WFIFOL(char_fd,6+8*i) = sd->status.account_id; - WFIFOL(char_fd,6+8*i+4) = sd->status.char_id; + WFIFOL(chrif->fd,6+8*i) = sd->status.account_id; + WFIFOL(chrif->fd,6+8*i+4) = sd->status.char_id; i++; } mapit->free(iter); - WFIFOW(char_fd,2) = 6 + 8*users; - WFIFOW(char_fd,4) = users; - WFIFOSET(char_fd, 6+8*users); + WFIFOW(chrif->fd,2) = 6 + 8*users; + WFIFOW(chrif->fd,4) = users; + WFIFOSET(chrif->fd, 6+8*users); - return 0; + return true; } /*========================================== * timerFunction - * Chk the connection to char server, (if it down) + * Check the connection to char server, (if it down) *------------------------------------------*/ -static int check_connect_char_server(int tid, unsigned int tick, int id, intptr_t data) { +int check_connect_char_server(int tid, int64 tick, int id, intptr_t data) { static int displayed = 0; - if ( char_fd <= 0 || session[char_fd] == NULL ) { + if ( chrif->fd <= 0 || session[chrif->fd] == NULL ) { if ( !displayed ) { ShowStatus("Attempting to connect to Char Server. Please wait.\n"); displayed = 1; } - chrif_state = 0; + chrif->state = 0; - if ( ( char_fd = make_connection(char_ip, char_port,NULL) ) == -1) //Attempt to connect later. [Skotlex] + if ( ( chrif->fd = make_connection(chrif->ip, chrif->port,NULL) ) == -1) //Attempt to connect later. [Skotlex] return 0; - session[char_fd]->func_parse = chrif_parse; - session[char_fd]->flag.server = 1; - realloc_fifo(char_fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK); + session[chrif->fd]->func_parse = chrif->parse; + session[chrif->fd]->flag.server = 1; + realloc_fifo(chrif->fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK); - chrif_connect(char_fd); - chrif_connected = (chrif_state == 2); - srvinfo = 0; + chrif->connect(chrif->fd); + chrif->connected = (chrif->state == 2); + chrif->srvinfo = 0; } else { - if (srvinfo == 0) { - chrif_ragsrvinfo(battle_config.base_exp_rate, battle_config.job_exp_rate, battle_config.item_rate_common); - srvinfo = 1; + if (chrif->srvinfo == 0) { + chrif->ragsrvinfo(battle_config.base_exp_rate, battle_config.job_exp_rate, battle_config.item_rate_common); + chrif->srvinfo = 1; } } - if ( chrif_isconnected() ) + if ( chrif->isconnected() ) displayed = 0; return 0; } @@ -1562,89 +1503,254 @@ static int check_connect_char_server(int tid, unsigned int tick, int id, intptr_ /*========================================== * Asks char server to remove friend_id from the friend list of char_id *------------------------------------------*/ -int chrif_removefriend(int char_id, int friend_id) { +bool chrif_removefriend(int char_id, int friend_id) { - chrif_check(-1); + chrif_check(false); - WFIFOHEAD(char_fd,10); - WFIFOW(char_fd,0) = 0x2b07; - WFIFOL(char_fd,2) = char_id; - WFIFOL(char_fd,6) = friend_id; - WFIFOSET(char_fd,10); + WFIFOHEAD(chrif->fd,10); + WFIFOW(chrif->fd,0) = 0x2b07; + WFIFOL(chrif->fd,2) = char_id; + WFIFOL(chrif->fd,6) = friend_id; + WFIFOSET(chrif->fd,10); - return 0; + return true; } void chrif_send_report(char* buf, int len) { #ifndef STATS_OPT_OUT - if( char_fd ) { - WFIFOHEAD(char_fd,len + 2); + if( chrif->fd > 0 ) { + WFIFOHEAD(chrif->fd,len + 2); - WFIFOW(char_fd,0) = 0x3008; + WFIFOW(chrif->fd,0) = 0x3008; - memcpy(WFIFOP(char_fd,2), buf, len); + memcpy(WFIFOP(chrif->fd,2), buf, len); - WFIFOSET(char_fd,len + 2); + WFIFOSET(chrif->fd,len + 2); - flush_fifo(char_fd); /* ensure it's sent now. */ + flush_fifo(chrif->fd); /* ensure it's sent now. */ } #endif } /** + * Sends a single scdata for saving into char server, meant to ensure integrity of duration-less conditions + **/ +void chrif_save_scdata_single(int account_id, int char_id, short type, struct status_change_entry *sce) { + + if( !chrif->isconnected() ) + return; + + WFIFOHEAD(chrif->fd, 28); + + WFIFOW(chrif->fd, 0) = 0x2740; + WFIFOL(chrif->fd, 2) = account_id; + WFIFOL(chrif->fd, 6) = char_id; + WFIFOW(chrif->fd, 10) = type; + WFIFOL(chrif->fd, 12) = sce->val1; + WFIFOL(chrif->fd, 16) = sce->val2; + WFIFOL(chrif->fd, 20) = sce->val3; + WFIFOL(chrif->fd, 24) = sce->val4; + + WFIFOSET(chrif->fd, 28); + +} +/** + * Sends a single scdata deletion request into char server, meant to ensure integrity of duration-less conditions + **/ +void chrif_del_scdata_single(int account_id, int char_id, short type) { + + if( !chrif->isconnected() ) { + ShowError("MAYDAY! failed to delete status %d from CID:%d/AID:%d\n",type,char_id,account_id); + return; + } + + + WFIFOHEAD(chrif->fd, 12); + + WFIFOW(chrif->fd, 0) = 0x2741; + WFIFOL(chrif->fd, 2) = account_id; + WFIFOL(chrif->fd, 6) = char_id; + WFIFOW(chrif->fd, 10) = type; + + WFIFOSET(chrif->fd, 12); + +} + +/** ` * @see DBApply */ int auth_db_final(DBKey key, DBData *data, va_list ap) { struct auth_node *node = DB->data2ptr(data); - if (node->char_dat) - aFree(node->char_dat); - - if (node->sd) + if (node->sd) { + + if( node->sd->regs.vars ) + node->sd->regs.vars->destroy(node->sd->regs.vars, script->reg_destroy); + + if( node->sd->regs.arrays ) + node->sd->regs.arrays->destroy(node->sd->regs.arrays, script->array_free_db); + aFree(node->sd); - - ers_free(auth_db_ers, node); - + } + ers_free(chrif->auth_db_ers, node); + return 0; } /*========================================== * Destructor *------------------------------------------*/ -int do_final_chrif(void) { +void do_final_chrif(void) { - if( char_fd != -1 ) { - do_close(char_fd); - char_fd = -1; + if( chrif->fd != -1 ) { + do_close(chrif->fd); + chrif->fd = -1; } - auth_db->destroy(auth_db, auth_db_final); + chrif->auth_db->destroy(chrif->auth_db, chrif->auth_db_final); - ers_destroy(auth_db_ers); - - return 0; + ers_destroy(chrif->auth_db_ers); } /*========================================== * *------------------------------------------*/ -int do_init_chrif(void) { - - auth_db = idb_alloc(DB_OPT_BASE); - auth_db_ers = ers_new(sizeof(struct auth_node),"chrif.c::auth_db_ers",ERS_OPT_NONE); +void do_init_chrif(bool minimal) { + if (minimal) + return; + + chrif->auth_db = idb_alloc(DB_OPT_BASE); + chrif->auth_db_ers = ers_new(sizeof(struct auth_node),"chrif.c::auth_db_ers",ERS_OPT_NONE); - iTimer->add_timer_func_list(check_connect_char_server, "check_connect_char_server"); - iTimer->add_timer_func_list(auth_db_cleanup, "auth_db_cleanup"); + timer->add_func_list(chrif->check_connect_char_server, "check_connect_char_server"); + timer->add_func_list(chrif->auth_db_cleanup, "auth_db_cleanup"); + timer->add_func_list(chrif->send_usercount_tochar, "send_usercount_tochar"); // establish map-char connection if not present - iTimer->add_timer_interval(iTimer->gettick() + 1000, check_connect_char_server, 0, 0, 10 * 1000); + timer->add_interval(timer->gettick() + 1000, chrif->check_connect_char_server, 0, 0, 10 * 1000); // wipe stale data for timed-out client connection requests - iTimer->add_timer_interval(iTimer->gettick() + 1000, auth_db_cleanup, 0, 0, 30 * 1000); + timer->add_interval(timer->gettick() + 1000, chrif->auth_db_cleanup, 0, 0, 30 * 1000); // send the user count every 10 seconds, to hide the charserver's online counting problem - iTimer->add_timer_interval(iTimer->gettick() + 1000, send_usercount_tochar, 0, 0, UPDATE_INTERVAL); - - return 0; + timer->add_interval(timer->gettick() + 1000, chrif->send_usercount_tochar, 0, 0, UPDATE_INTERVAL); +} + + +/*===================================== +* Default Functions : chrif.h +* Generated by HerculesInterfaceMaker +* created by Susu +*-------------------------------------*/ +void chrif_defaults(void) { + const int packet_len_table[CHRIF_PACKET_LEN_TABLE_SIZE] = { // U - used, F - free + 60, 3,-1,27,10,-1, 6,-1, // 2af8-2aff: U->2af8, U->2af9, U->2afa, U->2afb, U->2afc, U->2afd, U->2afe, U->2aff + 6,-1,18, 7,-1,39,30, 10, // 2b00-2b07: U->2b00, U->2b01, U->2b02, U->2b03, U->2b04, U->2b05, U->2b06, U->2b07 + 6,30, -1, 0,86, 7,44,34, // 2b08-2b0f: U->2b08, U->2b09, U->2b0a, F->2b0b, U->2b0c, U->2b0d, U->2b0e, U->2b0f + 11,10,10, 0,11, 0,266,10, // 2b10-2b17: U->2b10, U->2b11, U->2b12, F->2b13, U->2b14, F->2b15, U->2b16, U->2b17 + 2,10, 2,-1,-1,-1, 2, 7, // 2b18-2b1f: U->2b18, U->2b19, U->2b1a, U->2b1b, U->2b1c, U->2b1d, U->2b1e, U->2b1f + -1,10, 8, 2, 2,14,19,19, // 2b20-2b27: U->2b20, U->2b21, U->2b22, U->2b23, U->2b24, U->2b25, U->2b26, U->2b27 + }; + + chrif = &chrif_s; + + /* vars */ + chrif->connected = 0; + chrif->other_mapserver_count = 0; + + memcpy(chrif->packet_len_table,&packet_len_table,sizeof(chrif->packet_len_table)); + chrif->fd = -1; + chrif->srvinfo = 0; + memset(chrif->ip_str,0,sizeof(chrif->ip_str)); + chrif->ip = 0; + chrif->port = 6121; + memset(chrif->userid,0,sizeof(chrif->userid)); + memset(chrif->passwd,0,sizeof(chrif->passwd)); + chrif->state = 0; + + /* */ + chrif->auth_db = NULL; + chrif->auth_db_ers = NULL; + /* */ + chrif->init = do_init_chrif; + chrif->final = do_final_chrif; + + /* funcs */ + chrif->setuserid = chrif_setuserid; + chrif->setpasswd = chrif_setpasswd; + chrif->checkdefaultlogin = chrif_checkdefaultlogin; + chrif->setip = chrif_setip; + chrif->setport = chrif_setport; + + chrif->isconnected = chrif_isconnected; + chrif->check_shutdown = chrif_check_shutdown; + + chrif->search = chrif_search; + chrif->auth_check = chrif_auth_check; + chrif->auth_delete = chrif_auth_delete; + chrif->auth_finished = chrif_auth_finished; + + chrif->authreq = chrif_authreq; + chrif->authok = chrif_authok; + chrif->scdata_request = chrif_scdata_request; + chrif->save = chrif_save; + chrif->charselectreq = chrif_charselectreq; + chrif->changemapserver = chrif_changemapserver; + + chrif->searchcharid = chrif_searchcharid; + chrif->changeemail = chrif_changeemail; + chrif->char_ask_name = chrif_char_ask_name; + chrif->updatefamelist = chrif_updatefamelist; + chrif->buildfamelist = chrif_buildfamelist; + chrif->save_scdata = chrif_save_scdata; + chrif->ragsrvinfo = chrif_ragsrvinfo; + chrif->char_offline_nsd = chrif_char_offline_nsd; + chrif->char_reset_offline = chrif_char_reset_offline; + chrif->send_users_tochar = send_users_tochar; + chrif->char_online = chrif_char_online; + chrif->changesex = chrif_changesex; + //chrif->chardisconnect = chrif_chardisconnect; + chrif->divorce = chrif_divorce; + + chrif->removefriend = chrif_removefriend; + chrif->send_report = chrif_send_report; + + chrif->flush = chrif_flush; + chrif->skillid2idx = chrif_skillid2idx; + + chrif->sd_to_auth = chrif_sd_to_auth; + chrif->check_connect_char_server = check_connect_char_server; + chrif->auth_logout = chrif_auth_logout; + chrif->save_ack = chrif_save_ack; + chrif->reconnect = chrif_reconnect; + chrif->auth_db_cleanup_sub = auth_db_cleanup_sub; + chrif->char_ask_name_answer = chrif_char_ask_name_answer; + chrif->auth_db_final = auth_db_final; + chrif->send_usercount_tochar = send_usercount_tochar; + chrif->auth_db_cleanup = auth_db_cleanup; + + chrif->connect = chrif_connect; + chrif->connectack = chrif_connectack; + chrif->sendmap = chrif_sendmap; + chrif->sendmapack = chrif_sendmapack; + chrif->recvmap = chrif_recvmap; + chrif->changemapserverack = chrif_changemapserverack; + chrif->changedsex = chrif_changedsex; + chrif->divorceack = chrif_divorceack; + chrif->idbanned = chrif_idbanned; + chrif->recvfamelist = chrif_recvfamelist; + chrif->load_scdata = chrif_load_scdata; + chrif->update_ip = chrif_update_ip; + chrif->disconnectplayer = chrif_disconnectplayer; + chrif->removemap = chrif_removemap; + chrif->updatefamelist_ack = chrif_updatefamelist_ack; + chrif->keepalive = chrif_keepalive; + chrif->keepalive_ack = chrif_keepalive_ack; + chrif->deadopt = chrif_deadopt; + chrif->authfail = chrif_authfail; + chrif->on_ready = chrif_on_ready; + chrif->on_disconnect = chrif_on_disconnect; + chrif->parse = chrif_parse; + chrif->save_scdata_single = chrif_save_scdata_single; + chrif->del_scdata_single = chrif_del_scdata_single; } - diff --git a/src/map/chrif.h b/src/map/chrif.h index 9c7142905..11baaf5ff 100644 --- a/src/map/chrif.h +++ b/src/map/chrif.h @@ -2,70 +2,156 @@ // See the LICENSE file // Portions Copyright (c) Athena Dev Teams -#ifndef _CHRIF_H_ -#define _CHRIF_H_ +#ifndef MAP_CHRIF_H +#define MAP_CHRIF_H -#include "../common/cbasetypes.h" #include <time.h> +#include "map.h" //TBL_stuff +#include "../common/cbasetypes.h" +#include "../common/db.h" + +struct status_change_entry; + +/** + * Defines + **/ +//Interval at which map server updates online listing. [Valaris] +#define CHECK_INTERVAL 3600000 +//Interval at which map server sends number of connected users. [Skotlex] +#define UPDATE_INTERVAL 10000 + +#define CHRIF_PACKET_LEN_TABLE_SIZE 0x3d + +/** + * Enumerations + **/ enum sd_state { ST_LOGIN, ST_LOGOUT, ST_MAPCHANGE }; + +/** + * Structures + **/ struct auth_node { int account_id, char_id; int login_id1, login_id2, sex, fd; - time_t expiration_time; // # of seconds 1/1/1970 (timestamp): Validity limit of the account (0 = unlimited) - struct map_session_data *sd; //Data from logged on char. - struct mmo_charstatus *char_dat; //Data from char server. - unsigned int node_created; //timestamp for node timeouts - enum sd_state state; //To track whether player was login in/out or changing maps. + time_t expiration_time; // # of seconds 1/1/1970 (timestamp): Validity limit of the account (0 = unlimited) + struct map_session_data *sd; //Data from logged on char. + int64 node_created; //timestamp for node timeouts + enum sd_state state; //To track whether player was login in/out or changing maps. }; -void chrif_setuserid(char* id); -void chrif_setpasswd(char* pwd); -void chrif_checkdefaultlogin(void); -int chrif_setip(const char* ip); -void chrif_setport(uint16 port); - -int chrif_isconnected(void); -void chrif_check_shutdown(void); - -extern int chrif_connected; -extern int other_mapserver_count; +/*===================================== +* Interface : chrif.h +* Generated by HerculesInterfaceMaker +* created by Susu +*-------------------------------------*/ +struct chrif_interface { -struct auth_node* chrif_search(int account_id); -struct auth_node* chrif_auth_check(int account_id, int char_id, enum sd_state state); -bool chrif_auth_delete(int account_id, int char_id, enum sd_state state); -bool chrif_auth_finished(struct map_session_data* sd); + /* vars */ + + int connected; + int other_mapserver_count; //Holds count of how many other map servers are online (apart of this instance) [Skotlex] -void chrif_authreq(struct map_session_data* sd); -void chrif_authok(int fd); -int chrif_scdata_request(int account_id, int char_id); -int chrif_save(struct map_session_data* sd, int flag); -int chrif_charselectreq(struct map_session_data* sd, uint32 s_ip); -int chrif_changemapserver(struct map_session_data* sd, uint32 ip, uint16 port); + /* */ + struct eri *auth_db_ers; //For re-utilizing player login structures. + DBMap* auth_db; // int id -> struct auth_node* + /* */ + int packet_len_table[CHRIF_PACKET_LEN_TABLE_SIZE]; + int fd; + int srvinfo; + char ip_str[128]; + uint32 ip; + uint16 port; + char userid[NAME_LENGTH], passwd[NAME_LENGTH]; + int state; + /* */ + void (*init) (bool minimal); + void (*final) (void); + /* funcs */ + void (*setuserid) (char* id); + void (*setpasswd) (char* pwd); + void (*checkdefaultlogin) (void); + bool (*setip) (const char* ip); + void (*setport) (uint16 port); + + int (*isconnected) (void); + void (*check_shutdown) (void); + + struct auth_node* (*search) (int account_id); + struct auth_node* (*auth_check) (int account_id, int char_id, enum sd_state state); + bool (*auth_delete) (int account_id, int char_id, enum sd_state state); + bool (*auth_finished) (struct map_session_data* sd); + + void (*authreq) (struct map_session_data* sd, bool hstandalone); + void (*authok) (int fd); + bool (*scdata_request) (int account_id, int char_id); + bool (*save) (struct map_session_data* sd, int flag); + bool (*charselectreq) (struct map_session_data* sd, uint32 s_ip); + bool (*changemapserver) (struct map_session_data* sd, uint32 ip, uint16 port); + + bool (*searchcharid) (int char_id); + bool (*changeemail) (int id, const char *actual_email, const char *new_email); + bool (*char_ask_name) (int acc, const char* character_name, unsigned short operation_type, int year, int month, int day, int hour, int minute, int second); + int (*updatefamelist) (struct map_session_data *sd); + bool (*buildfamelist) (void); + bool (*save_scdata) (struct map_session_data *sd); + bool (*ragsrvinfo) (int base_rate,int job_rate, int drop_rate); + //int (*char_offline) (struct map_session_data *sd); + bool (*char_offline_nsd) (int account_id, int char_id); + bool (*char_reset_offline) (void); + bool (*send_users_tochar) (void); + bool (*char_online) (struct map_session_data *sd); + bool (*changesex) (struct map_session_data *sd); + //int (*chardisconnect) (struct map_session_data *sd); // FIXME: Commented out in clif.c, function does not exist + bool (*divorce) (int partner_id1, int partner_id2); + + bool (*removefriend) (int char_id, int friend_id); + void (*send_report) (char* buf, int len); + + bool (*flush) (void); + void (*skillid2idx) (int fd); + + bool (*sd_to_auth) (TBL_PC* sd, enum sd_state state); + int (*check_connect_char_server) (int tid, int64 tick, int id, intptr_t data); + bool (*auth_logout) (TBL_PC* sd, enum sd_state state); + void (*save_ack) (int fd); + int (*reconnect) (DBKey key, DBData *data, va_list ap); + int (*auth_db_cleanup_sub) (DBKey key, DBData *data, va_list ap); + bool (*char_ask_name_answer) (int acc, const char* player_name, uint16 type, uint16 answer); + int (*auth_db_final) (DBKey key, DBData *data, va_list ap); + int (*send_usercount_tochar) (int tid, int64 tick, int id, intptr_t data); + int (*auth_db_cleanup) (int tid, int64 tick, int id, intptr_t data); -int chrif_searchcharid(int char_id); -int chrif_changeemail(int id, const char *actual_email, const char *new_email); -int chrif_char_ask_name(int acc, const char* character_name, unsigned short operation_type, int year, int month, int day, int hour, int minute, int second); -int chrif_updatefamelist(struct map_session_data *sd); -int chrif_buildfamelist(void); -int chrif_save_scdata(struct map_session_data *sd); -int chrif_ragsrvinfo(int base_rate,int job_rate, int drop_rate); -int chrif_char_offline(struct map_session_data *sd); -int chrif_char_offline_nsd(int account_id, int char_id); -int chrif_char_reset_offline(void); -int send_users_tochar(void); -int chrif_char_online(struct map_session_data *sd); -int chrif_changesex(struct map_session_data *sd); -int chrif_chardisconnect(struct map_session_data *sd); -int chrif_divorce(int partner_id1, int partner_id2); - -int chrif_removefriend(int char_id, int friend_id); -void chrif_send_report(char* buf, int len); + void (*connect) (int fd); + void (*connectack) (int fd); + void (*sendmap) (int fd); + void (*sendmapack) (int fd); + void (*recvmap) (int fd); + bool (*changemapserverack) (int account_id, int login_id1, int login_id2, int char_id, short map_index, short x, short y, uint32 ip, uint16 port); + void (*changedsex) (int fd); + bool (*divorceack) (int char_id, int partner_id); + void (*idbanned) (int fd); + void (*recvfamelist) (int fd); + bool (*load_scdata) (int fd); + void (*update_ip) (int fd); + int (*disconnectplayer) (int fd); + void (*removemap) (int fd); + int (*updatefamelist_ack) (int fd); + void (*keepalive)(int fd); + void (*keepalive_ack) (int fd); + void (*deadopt) (int father_id, int mother_id, int child_id); + void (*authfail) (int fd); + void (*on_ready) (void); + void (*on_disconnect) (void); + int (*parse) (int fd); + void (*save_scdata_single) (int account_id, int char_id, short type, struct status_change_entry *sce); + void (*del_scdata_single) (int account_id, int char_id, short type); +}; -int do_final_chrif(void); -int do_init_chrif(void); +struct chrif_interface *chrif; -int chrif_flush_fifo(void); -void chrif_skillid2idx(int fd); +void chrif_defaults(void); +// There's no need for another function when a simple macro can do exactly the same effect +#define chrif_char_offline(x) chrif->char_offline_nsd((x)->status.account_id,(x)->status.char_id) -#endif /* _CHRIF_H_ */ +#endif /* MAP_CHRIF_H */ diff --git a/src/map/clif.c b/src/map/clif.c index 73d4b6666..d9acf0792 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -2,63 +2,87 @@ // See the LICENSE file // Portions Copyright (c) Athena Dev Teams -#include "../common/cbasetypes.h" -#include "../common/socket.h" -#include "../common/timer.h" -#include "../common/grfio.h" -#include "../common/malloc.h" -#include "../common/nullpo.h" -#include "../common/random.h" -#include "../common/showmsg.h" -#include "../common/strlib.h" -#include "../common/utils.h" -#include "../common/ers.h" -#include "../common/conf.h" +#define HERCULES_CORE + +#include "../config/core.h" // ANTI_MAYAP_CHEAT, RENEWAL, SECURE_NPCTIMEOUT +#include "clif.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#include <time.h> -#include "map.h" -#include "chrif.h" -#include "pc.h" -#include "status.h" -#include "npc.h" -#include "itemdb.h" -#include "chat.h" -#include "trade.h" -#include "storage.h" -#include "script.h" -#include "skill.h" #include "atcommand.h" -#include "intif.h" #include "battle.h" #include "battleground.h" -#include "mob.h" -#include "party.h" -#include "unit.h" +#include "chat.h" +#include "chrif.h" +#include "elemental.h" #include "guild.h" -#include "vending.h" -#include "pet.h" #include "homunculus.h" #include "instance.h" -#include "mercenary.h" -#include "elemental.h" +#include "intif.h" +#include "irc-bot.h" +#include "itemdb.h" #include "log.h" -#include "clif.h" #include "mail.h" +#include "map.h" +#include "mercenary.h" +#include "mob.h" +#include "npc.h" +#include "party.h" +#include "pc.h" +#include "pet.h" #include "quest.h" -#include "packets_struct.h" -#include "irc-bot.h" - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <stdarg.h> -#include <time.h> +#include "script.h" +#include "skill.h" +#include "status.h" +#include "storage.h" +#include "trade.h" +#include "unit.h" +#include "vending.h" +#include "../common/HPM.h" +#include "../common/cbasetypes.h" +#include "../common/conf.h" +#include "../common/ers.h" +#include "../common/grfio.h" +#include "../common/malloc.h" +#include "../common/mmo.h" // NEW_CARTS +#include "../common/nullpo.h" +#include "../common/random.h" +#include "../common/showmsg.h" +#include "../common/socket.h" +#include "../common/strlib.h" +#include "../common/timer.h" +#include "../common/utils.h" +struct clif_interface clif_s; + +/* re-usable */ +static struct packet_itemlist_normal itemlist_normal; +static struct packet_itemlist_equip itemlist_equip; +static struct packet_storelist_normal storelist_normal; +static struct packet_storelist_equip storelist_equip; +static struct packet_viewequip_ack viewequip_list; +#if PACKETVER >= 20131223 +static struct packet_npc_market_result_ack npcmarket_result; +static struct packet_npc_market_open npcmarket_open; +#endif //#define DUMP_UNKNOWN_PACKET //#define DUMP_INVALID_PACKET //Converts item type in case of pet eggs. static inline int itemtype(int type) { - return ( type == IT_PETEGG ) ? IT_WEAPON : type; + switch( type ) { +#if PACKETVER >= 20080827 + case IT_WEAPON: return IT_ARMOR; + case IT_ARMOR: + case IT_PETARMOR: +#endif + case IT_PETEGG: return IT_WEAPON; + default: return type; + } } @@ -81,17 +105,16 @@ static inline void WBUFPOS2(uint8* p, unsigned short pos, short x0, short y0, sh p[5] = (uint8)((sx0<<4) | (sy0&0x0f)); } - +#if 0 // Currently unused static inline void WFIFOPOS(int fd, unsigned short pos, short x, short y, unsigned char dir) { WBUFPOS(WFIFOP(fd,pos), 0, x, y, dir); } - +#endif // 0 static inline void WFIFOPOS2(int fd, unsigned short pos, short x0, short y0, short x1, short y1, unsigned char sx0, unsigned char sy0) { WBUFPOS2(WFIFOP(fd,pos), 0, x0, y0, x1, y1, sx0, sy0); } - static inline void RBUFPOS(const uint8* p, unsigned short pos, short* x, short* y, unsigned char* dir) { p += pos; @@ -108,7 +131,11 @@ static inline void RBUFPOS(const uint8* p, unsigned short pos, short* x, short* } } +static inline void RFIFOPOS(int fd, unsigned short pos, short* x, short* y, unsigned char* dir) { + RBUFPOS(RFIFOP(fd,pos), 0, x, y, dir); +} +#if 0 // currently unused static inline void RBUFPOS2(const uint8* p, unsigned short pos, short* x0, short* y0, short* x1, short* y1, unsigned char* sx0, unsigned char* sy0) { p += pos; @@ -136,19 +163,12 @@ static inline void RBUFPOS2(const uint8* p, unsigned short pos, short* x0, short sy0[0] = ( p[5] & 0x0f ) >> 0; } } - - -static inline void RFIFOPOS(int fd, unsigned short pos, short* x, short* y, unsigned char* dir) { - RBUFPOS(RFIFOP(fd,pos), 0, x, y, dir); -} - - static inline void RFIFOPOS2(int fd, unsigned short pos, short* x0, short* y0, short* x1, short* y1, unsigned char* sx0, unsigned char* sy0) { RBUFPOS2(WFIFOP(fd,pos), 0, x0, y0, x1, y1, sx0, sy0); } +#endif // 0 - -//To idenfity disguised characters. +//To identify disguised characters. static inline bool disguised(struct block_list* bl) { return (bool)( bl->type == BL_PC && ((TBL_PC*)bl)->disguise != -1 ); } @@ -167,27 +187,28 @@ static inline unsigned int mes_len_check(char* mes, unsigned int len, unsigned i /*========================================== * Ip setting of map-server *------------------------------------------*/ -int clif_setip(const char* ip) { +bool clif_setip(const char* ip) { char ip_str[16]; clif->map_ip = host2ip(ip); - if (!clif->map_ip) { + if ( !clif->map_ip ) { ShowWarning("Failed to Resolve Map Server Address! (%s)\n", ip); - return 0; + return false; } safestrncpy(clif->map_ip_str, ip, sizeof(clif->map_ip_str)); ShowInfo("Map Server IP Address : '"CL_WHITE"%s"CL_RESET"' -> '"CL_WHITE"%s"CL_RESET"'.\n", ip, ip2str(clif->map_ip, ip_str)); - return 1; + return true; } -void clif_setbindip(const char* ip) { +bool clif_setbindip(const char* ip) { clif->bind_ip = host2ip(ip); - if (clif->bind_ip) { + if ( clif->bind_ip ) { char ip_str[16]; ShowInfo("Map Server Bind IP Address : '"CL_WHITE"%s"CL_RESET"' -> '"CL_WHITE"%s"CL_RESET"'.\n", ip, ip2str(clif->bind_ip, ip_str)); - } else { - ShowWarning("Failed to Resolve Map Server Address! (%s)\n", ip); + return true; } + ShowWarning("Failed to Resolve Map Server Address! (%s)\n", ip); + return false; } /*========================================== @@ -214,28 +235,31 @@ uint16 clif_getport(void) { return clif->map_port; } - +/*========================================== + * Updates server ip resolution and returns it + *------------------------------------------*/ uint32 clif_refresh_ip(void) { uint32 new_ip; - + new_ip = host2ip(clif->map_ip_str); - if (new_ip && new_ip != clif->map_ip) { + if ( new_ip && new_ip != clif->map_ip ) { clif->map_ip = new_ip; ShowInfo("Updating IP resolution of [%s].\n", clif->map_ip_str); return clif->map_ip; } return 0; } + #if PACKETVER >= 20071106 static inline unsigned char clif_bl_type(struct block_list *bl) { switch (bl->type) { - case BL_PC: return (disguised(bl) && !pcdb_checkid(status_get_viewdata(bl)->class_))? 0x1:0x0; //PC_TYPE + case BL_PC: return (disguised(bl) && !pcdb_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 pcdb_checkid(status_get_viewdata(bl)->class_)?0x0:0x5; //NPC_MOB_TYPE - case BL_NPC: return 0x6; //NPC_EVT_TYPE - case BL_PET: return pcdb_checkid(status_get_viewdata(bl)->class_)?0x0:0x7; //NPC_PET_TYPE + case BL_MOB: return pcdb_checkid(status->get_viewdata(bl)->class_)?0x0:0x5; //NPC_MOB_TYPE + case BL_NPC: return pcdb_checkid(status->get_viewdata(bl)->class_)?0x0:0x6; //NPC_EVT_TYPE + case BL_PET: return pcdb_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 @@ -294,8 +318,19 @@ int clif_send_sub(struct block_list *bl, va_list ap) { } } break; +/* 0x120 crashes the client when warping for this packetver range [Ind/Hercules], thanks to Judas! */ +#if PACKETVER > 20120418 && PACKETVER < 20130000 + case AREA: + if( WBUFW(buf, 0) == 0x120 && sd->state.warping ) + return 0; + break; +#endif } + /* unless visible, hold it here */ + if( clif->ally_only && !sd->sc.data[SC_CLAIRVOYANCE] && !sd->special_state.intravision && battle->check_target( src_bl, &sd->bl, BCT_ENEMY ) > 0 ) + return 0; + WFIFOHEAD(fd, len); if (WFIFOP(fd,0) == buf) { ShowError("WARNING: Invalid use of clif->send function\n"); @@ -317,12 +352,12 @@ int clif_send_sub(struct block_list *bl, va_list ap) { * Packet Delegation (called on all packets that require data to be sent to more than one client) * functions that are sent solely to one use whose ID it posses use WFIFOSET *------------------------------------------*/ -int clif_send(const void* buf, int len, struct block_list* bl, enum send_target type) { +bool clif_send(const void* buf, int len, struct block_list* bl, enum send_target type) { int i; struct map_session_data *sd, *tsd; struct party_data *p = NULL; struct guild *g = NULL; - struct battleground_data *bg = NULL; + struct battleground_data *bgd = NULL; int x0 = 0, x1 = 0, y0 = 0, y1 = 0, fd; struct s_mapiterator* iter; @@ -361,12 +396,12 @@ int clif_send(const void* buf, int len, struct block_list* bl, enum send_target clif->send (buf, len, bl, SELF); case AREA_WOC: case AREA_WOS: - iMap->foreachinarea(clif->send_sub, bl->m, bl->x-AREA_SIZE, bl->y-AREA_SIZE, bl->x+AREA_SIZE, bl->y+AREA_SIZE, + map->foreachinarea(clif->send_sub, bl->m, bl->x-AREA_SIZE, bl->y-AREA_SIZE, bl->x+AREA_SIZE, bl->y+AREA_SIZE, BL_PC, buf, len, bl, type); break; case AREA_CHAT_WOC: - iMap->foreachinarea(clif->send_sub, bl->m, bl->x-(AREA_SIZE-5), bl->y-(AREA_SIZE-5), - bl->x+(AREA_SIZE-5), bl->y+(AREA_SIZE-5), BL_PC, buf, len, bl, AREA_WOC); + map->foreachinarea(clif->send_sub, bl->m, bl->x-(AREA_SIZE-5), bl->y-(AREA_SIZE-5), + bl->x+(AREA_SIZE-5), bl->y+(AREA_SIZE-5), BL_PC, buf, len, bl, AREA_WOC); break; case CHAT: @@ -374,7 +409,7 @@ int clif_send(const void* buf, int len, struct block_list* bl, enum send_target { struct chat_data *cd; if (sd) { - cd = (struct chat_data*)iMap->id2bl(sd->chatID); + cd = (struct chat_data*)map->id2bl(sd->chatID); } else if (bl->type == BL_CHAT) { cd = (struct chat_data*)bl; } else break; @@ -426,7 +461,7 @@ int clif_send(const void* buf, int len, struct block_list* bl, enum send_target memcpy(WFIFOP(fd,0), buf, len); WFIFOSET(fd,len); } - if (!iMap->enable_spy) //Skip unnecessary parsing. [Skotlex] + if (!map->enable_spy) //Skip unnecessary parsing. [Skotlex] break; iter = mapit_getallusers(); @@ -503,7 +538,7 @@ int clif_send(const void* buf, int len, struct block_list* bl, enum send_target WFIFOSET(fd,len); } } - if (!iMap->enable_spy) //Skip unnecessary parsing. [Skotlex] + if (!map->enable_spy) //Skip unnecessary parsing. [Skotlex] break; iter = mapit_getallusers(); @@ -528,9 +563,9 @@ int clif_send(const void* buf, int len, struct block_list* bl, enum send_target case BG_SAMEMAP_WOS: case BG: case BG_WOS: - if( sd && sd->bg_id && (bg = bg_team_search(sd->bg_id)) != NULL ) { + if( sd && sd->bg_id && (bgd = bg->team_search(sd->bg_id)) != NULL ) { for( i = 0; i < MAX_BG_MEMBERS; i++ ) { - if( (sd = bg->members[i].sd) == NULL || !(fd = sd->fd) ) + if( (sd = bgd->members[i].sd) == NULL || !(fd = sd->fd) ) continue; if( sd->bl.id == bl->id && (type == BG_WOS || type == BG_SAMEMAP_WOS || type == BG_AREA_WOS) ) continue; @@ -545,12 +580,28 @@ int clif_send(const void* buf, int len, struct block_list* bl, enum send_target } break; + case BG_QUEUE: + if( sd && sd->bg_queue.arena ) { + struct hQueue *queue = &script->hq[sd->bg_queue.arena->queue_id]; + + for( i = 0; i < queue->size; i++ ) { + struct map_session_data *qsd = NULL; + + if( queue->item[i] > 0 && ( qsd = map->id2sd(queue->item[i]) ) ) { + WFIFOHEAD(qsd->fd,len); + memcpy(WFIFOP(qsd->fd,0), buf, len); + WFIFOSET(qsd->fd,len); + } + } + } + break; + default: - ShowError("clif->send: Unrecognized type %d\n",type); - return -1; + ShowError("clif_send: Unrecognized type %d\n",type); + return false; } - return 0; + return true; } /// Notifies the client, that it's connection attempt was accepted. @@ -559,16 +610,16 @@ int clif_send(const void* buf, int len, struct block_list* bl, enum send_target void clif_authok(struct map_session_data *sd) { struct packet_authok p; - + p.PacketType = authokType; - p.startTime = iTimer->gettick(); + p.startTime = (unsigned int)timer->gettick(); WBUFPOS(&p.PosDir[0],0,sd->bl.x,sd->bl.y,sd->ud.dir); /* do the stupid client math */ p.xSize = p.ySize = 5; /* not-used */ #if PACKETVER >= 20080102 - p.font = sd->user_font; // FIXME: Font is currently not saved. + p.font = sd->status.font; #endif - + clif->send(&p,sizeof(p),&sd->bl,SELF); } @@ -593,7 +644,7 @@ void clif_authrefuse(int fd, uint8 error_code) /// Notifies the client of a ban or forced disconnect (SC_NOTIFY_BAN). /// 0081 <error code>.B /// error code: -/// 0 = BAN_UNFAIR +/// 0 = BAN_UNFAIR -> "disconnected from server" -> MsgStringTable[3] /// 1 = server closed -> MsgStringTable[4] /// 2 = ID already logged in -> MsgStringTable[5] /// 3 = timeout/too much lag -> MsgStringTable[241] @@ -641,12 +692,11 @@ void clif_authfail_fd(int fd, int type) /// type: /// 1 = disconnect, char-select /// ? = nothing -void clif_charselectok(int id, uint8 ok) -{ +void clif_charselectok(int id, uint8 ok) { struct map_session_data* sd; int fd; - if ((sd = iMap->id2sd(id)) == NULL || !sd->fd) + if ((sd = map->id2sd(id)) == NULL || !sd->fd) return; fd = sd->fd; @@ -667,20 +717,20 @@ void clif_dropflooritem(struct flooritem_data* fitem) { if (fitem->item_data.nameid <= 0) return; - + p.PacketType = dropflooritemType; p.ITAID = fitem->bl.id; p.ITID = ((view = itemdb_viewid(fitem->item_data.nameid)) > 0) ? view : fitem->item_data.nameid; #if PACKETVER >= 20130000 /* not sure date */ p.type = itemtype(itemdb_type(fitem->item_data.nameid)); #endif - p.IsIdentified = fitem->item_data.identify; + p.IsIdentified = fitem->item_data.identify ? 1 : 0; p.xPos = fitem->bl.x; p.yPos = fitem->bl.y; p.subX = fitem->subx; p.subY = fitem->suby; p.count = fitem->item_data.amount; - + clif->send(&p, sizeof(p), &fitem->bl, AREA); } @@ -754,22 +804,23 @@ void clif_clearunit_area(struct block_list* bl, clr_type type) /// Used to make monsters with player-sprites disappear after dying /// like normal monsters, because the client does not remove those /// automatically. -int clif_clearunit_delayed_sub(int tid, unsigned int tick, int id, intptr_t data) { +int clif_clearunit_delayed_sub(int tid, int64 tick, int id, intptr_t data) { struct block_list *bl = (struct block_list *)data; clif->clearunit_area(bl, (clr_type) id); ers_free(clif->delay_clearunit_ers,bl); return 0; } -void clif_clearunit_delayed(struct block_list* bl, clr_type type, unsigned int tick) -{ + +void clif_clearunit_delayed(struct block_list* bl, clr_type type, int64 tick) { struct block_list *tbl = ers_alloc(clif->delay_clearunit_ers, struct block_list); memcpy (tbl, bl, sizeof (struct block_list)); - iTimer->add_timer(tick, clif->clearunit_delayed_sub, (int)type, (intptr_t)tbl); + timer->add(tick, clif->clearunit_delayed_sub, (int)type, (intptr_t)tbl); } +/// Gets weapon view info from sd's inventory_data and points (*rhand,*lhand) void clif_get_weapon_view(struct map_session_data* sd, unsigned short *rhand, unsigned short *lhand) { - if(sd->sc.option&(OPTION_WEDDING|OPTION_XMAS|OPTION_SUMMER|OPTION_HANBOK)) { + if(sd->sc.option&OPTION_COSTUME) { *rhand = *lhand = 0; return; } @@ -817,7 +868,7 @@ static int clif_setlevel_sub(int lv) { } static int clif_setlevel(struct block_list* bl) { - int lv = status_get_lv(bl); + int lv = status->get_lv(bl); if( battle_config.client_limit_unit_lv&bl->type ) return clif_setlevel_sub(lv); switch( bl->type ) { @@ -828,26 +879,85 @@ static int clif_setlevel(struct block_list* bl) { } return lv; } +/* for 'packetver < 20091103' 0x78 non-pc-looking unit handling */ +void clif_set_unit_idle2(struct block_list* bl, struct map_session_data *tsd, enum send_target target) { +#if PACKETVER < 20091103 + struct map_session_data* sd; + struct status_change* sc = status->get_sc(bl); + struct view_data* vd = status->get_viewdata(bl); + struct packet_idle_unit2 p; + int g_id = status->get_guild_id(bl); + + sd = BL_CAST(BL_PC, bl); + p.PacketType = idle_unit2Type; +#if PACKETVER >= 20071106 + p.objecttype = clif_bl_type(bl); +#endif + p.GID = bl->id; + p.speed = status->get_speed(bl); + p.bodyState = (sc) ? sc->opt1 : 0; + p.healthState = (sc) ? sc->opt2 : 0; + p.effectState = (sc) ? sc->option : bl->type == BL_NPC ? ((TBL_NPC*)bl)->option : 0; + p.job = vd->class_; + p.head = vd->hair_style; + p.weapon = vd->weapon; + p.accessory = vd->head_bottom; + p.shield = vd->shield; + p.accessory2 = vd->head_top; + p.accessory3 = vd->head_mid; + if( bl->type == BL_NPC && vd->class_ == FLAG_CLASS ) { //The hell, why flags work like this? + p.shield = status->get_emblem_id(bl); + p.accessory2 = GetWord(g_id, 1); + p.accessory3 = GetWord(g_id, 0); + } + p.headpalette = vd->hair_color; + p.bodypalette = vd->cloth_color; + p.headDir = (sd)? sd->head_dir : 0; + p.GUID = g_id; + p.GEmblemVer = status->get_emblem_id(bl); + p.honor = (sd) ? sd->status.manner : 0; + p.virtue = (sc) ? sc->opt3 : 0; + p.isPKModeON = (sd && sd->status.karma) ? 1 : 0; + p.sex = vd->sex; + WBUFPOS(&p.PosDir[0],0,bl->x,bl->y,unit->getdir(bl)); + p.xSize = p.ySize = (sd) ? 5 : 0; + p.state = vd->dead_sit; + p.clevel = clif_setlevel(bl); + + clif->send(&p,sizeof(p),tsd?&tsd->bl:bl,target); +#else + return; +#endif +} /*========================================== * Prepares 'unit standing' packet *------------------------------------------*/ void clif_set_unit_idle(struct block_list* bl, struct map_session_data *tsd, enum send_target target) { struct map_session_data* sd; - struct status_change* sc = status_get_sc(bl); - struct view_data* vd = status_get_viewdata(bl); + struct status_change* sc = status->get_sc(bl); + struct view_data* vd = status->get_viewdata(bl); struct packet_idle_unit p; - int g_id = status_get_guild_id(bl); + int g_id = status->get_guild_id(bl); + + nullpo_retv(bl); +#if PACKETVER < 20091103 + if( !pcdb_checkid(vd->class_) ) { + clif->set_unit_idle2(bl,tsd,target); + return; + } +#endif + sd = BL_CAST(BL_PC, bl); - + p.PacketType = idle_unitType; #if PACKETVER >= 20091103 p.PacketLength = sizeof(p); p.objecttype = clif_bl_type(bl); #endif p.GID = bl->id; - p.speed = status_get_speed(bl); + p.speed = status->get_speed(bl); p.bodyState = (sc) ? sc->opt1 : 0; p.healthState = (sc) ? sc->opt2 : 0; p.effectState = (sc) ? sc->option : bl->type == BL_NPC ? ((TBL_NPC*)bl)->option : 0; @@ -861,7 +971,7 @@ void clif_set_unit_idle(struct block_list* bl, struct map_session_data *tsd, enu p.accessory2 = vd->head_top; p.accessory3 = vd->head_mid; if( bl->type == BL_NPC && vd->class_ == FLAG_CLASS ) { //The hell, why flags work like this? - p.accessory = g_id; + p.accessory = status->get_emblem_id(bl); p.accessory2 = GetWord(g_id, 1); p.accessory3 = GetWord(g_id, 0); } @@ -872,19 +982,19 @@ void clif_set_unit_idle(struct block_list* bl, struct map_session_data *tsd, enu p.robe = vd->robe; #endif p.GUID = g_id; - p.GEmblemVer = status_get_emblem_id(bl); + p.GEmblemVer = status->get_emblem_id(bl); p.honor = (sd) ? sd->status.manner : 0; p.virtue = (sc) ? sc->opt3 : 0; - p.isPKModeON = (sd) ? sd->status.karma : 0; + p.isPKModeON = (sd && sd->status.karma) ? 1 : 0; p.sex = vd->sex; - WBUFPOS(&p.PosDir[0],0,bl->x,bl->y,unit_getdir(bl)); + WBUFPOS(&p.PosDir[0],0,bl->x,bl->y,unit->getdir(bl)); p.xSize = p.ySize = (sd) ? 5 : 0; p.state = vd->dead_sit; p.clevel = clif_setlevel(bl); #if PACKETVER >= 20080102 - p.font = (sd) ? sd->user_font : 0; + p.font = (sd) ? sd->status.font : 0; #endif -#if PACKETVER >= 20140000 //actual 20120221 +#if PACKETVER >= 20150000 //actual 20120221 if( bl->type == BL_MOB ) { p.maxHP = status_get_max_hp(bl); p.HP = status_get_hp(bl); @@ -895,201 +1005,90 @@ void clif_set_unit_idle(struct block_list* bl, struct map_session_data *tsd, enu p.isBoss = 0; } #endif - + clif->send(&p,sizeof(p),tsd?&tsd->bl:bl,target); if( disguised(bl) ) { -#if PACKETVER >= 20071106 - p.objecttype = pcdb_checkid(status_get_viewdata(bl)->class_) ? 0x0 : 0x5; //PC_TYPE : NPC_MOB_TYPE +#if PACKETVER >= 20091103 + p.objecttype = pcdb_checkid(status->get_viewdata(bl)->class_) ? 0x0 : 0x5; //PC_TYPE : NPC_MOB_TYPE p.GID = -bl->id; #else p.GID = -bl->id; #endif - clif->send(&p,sizeof(p),tsd?&tsd->bl:bl,SELF); + clif->send(&p,sizeof(p),bl,SELF); } - + } -/* todo for packetver 20091103 0x7c non-pc-looking unit handling */ -int clif_spawn_unit2(struct block_list* bl, enum send_target target) { - return 0; - /*struct map_session_data* sd; - struct status_change* sc = status_get_sc(bl); - struct view_data* vd = status_get_viewdata(bl); - unsigned char *buf = WBUFP(buffer,0); +/* for 'packetver < 20091103' 0x7c non-pc-looking unit handling */ +void clif_spawn_unit2(struct block_list* bl, enum send_target target) { #if PACKETVER < 20091103 - bool type = !pcdb_checkid(vd->class_); -#endif - unsigned short offset = 0; -#if PACKETVER >= 20091103 - const char *name; -#endif + struct map_session_data* sd; + struct status_change* sc = status->get_sc(bl); + struct view_data* vd = status->get_viewdata(bl); + struct packet_spawn_unit2 p; + int g_id = status->get_guild_id(bl); + sd = BL_CAST(BL_PC, bl); - -#if PACKETVER < 20091103 - if(type) - WBUFW(buf,0) = 0x7c; - else -#endif -#if PACKETVER < 4 - WBUFW(buf,0) = 0x79; -#elif PACKETVER < 7 - WBUFW(buf,0) = 0x1d9; -#elif PACKETVER < 20080102 - WBUFW(buf,0) = 0x22b; -#elif PACKETVER < 20091103 - WBUFW(buf,0) = 0x2ed; -#elif PACKETVER < 20101124 - WBUFW(buf,0) = 0x7f8; -#else - WBUFW(buf,0) = 0x858; -#endif - -#if PACKETVER >= 20091103 - name = status_get_name(bl); -#if PACKETVER < 20110111 - WBUFW(buf,2) = (spawn?62:63)+strlen(name); -#else - WBUFW(buf,2) = (spawn?64:65)+strlen(name); -#endif - WBUFB(buf,4) = clif_bl_type(bl); - offset+=3; - buf = WBUFP(buffer,offset); -#elif PACKETVER >= 20071106 - if (type) { //Non-player packets - WBUFB(buf,2) = clif_bl_type(bl); - offset++; - buf = WBUFP(buffer,offset); - } -#endif - WBUFL(buf, 2) = bl->id; - WBUFW(buf, 6) = status_get_speed(bl); - WBUFW(buf, 8) = (sc)? sc->opt1 : 0; - WBUFW(buf,10) = (sc)? sc->opt2 : 0; -#if PACKETVER < 20091103 - if (type&&spawn) { //uses an older and different packet structure - WBUFW(buf,12) = (sc)? sc->option : 0; - WBUFW(buf,14) = vd->hair_style; - WBUFW(buf,16) = vd->weapon; - WBUFW(buf,18) = vd->head_bottom; - WBUFW(buf,20) = vd->class_; //Pet armor (ignored by client) - WBUFW(buf,22) = vd->shield; - } else { -#endif -#if PACKETVER >= 20091103 - WBUFL(buf,12) = (sc)? sc->option : 0; - offset+=2; - buf = WBUFP(buffer,offset); -#elif PACKETVER >= 7 - if (!type) { - WBUFL(buf,12) = (sc)? sc->option : 0; - offset+=2; - buf = WBUFP(buffer,offset); - } else - WBUFW(buf,12) = (sc)? sc->option : 0; -#else - WBUFW(buf,12) = (sc)? sc->option : 0; -#endif - WBUFW(buf,14) = vd->class_; - WBUFW(buf,16) = vd->hair_style; - WBUFW(buf,18) = vd->weapon; -#if PACKETVER < 4 - WBUFW(buf,20) = vd->head_bottom; - WBUFW(buf,22) = vd->shield; -#else - WBUFW(buf,20) = vd->shield; - WBUFW(buf,22) = vd->head_bottom; -#endif -#if PACKETVER < 20091103 - } + + p.PacketType = spawn_unit2Type; +#if PACKETVER >= 20071106 + p.objecttype = clif_bl_type(bl); #endif - WBUFW(buf,24) = vd->head_top; - WBUFW(buf,26) = vd->head_mid; - - if( bl->type == BL_NPC && vd->class_ == FLAG_CLASS ) - { //The hell, why flags work like this? - WBUFW(buf,22) = status_get_emblem_id(bl); - WBUFW(buf,24) = GetWord(status_get_guild_id(bl), 1); - WBUFW(buf,26) = GetWord(status_get_guild_id(bl), 0); - } - - WBUFW(buf,28) = vd->hair_color; - WBUFW(buf,30) = vd->cloth_color; - WBUFW(buf,32) = (sd)? sd->head_dir : 0; -#if PACKETVER < 20091103 - if (type&&spawn) { //End of packet 0x7c - WBUFB(buf,34) = (sd)?sd->status.karma:0; // karma - WBUFB(buf,35) = vd->sex; - WBUFPOS(buf,36,bl->x,bl->y,unit_getdir(bl)); - WBUFB(buf,39) = 0; - WBUFB(buf,40) = 0; - return packet_len(0x7c); + p.GID = bl->id; + p.speed = status->get_speed(bl); + p.bodyState = (sc) ? sc->opt1 : 0; + p.healthState = (sc) ? sc->opt2 : 0; + p.effectState = (sc) ? sc->option : bl->type == BL_NPC ? ((TBL_NPC*)bl)->option : 0; + p.head = vd->hair_style; + p.weapon = vd->weapon; + p.accessory = vd->head_bottom; + p.job = vd->class_; + p.shield = vd->shield; + p.accessory2 = vd->head_top; + p.accessory3 = vd->head_mid; + if( bl->type == BL_NPC && vd->class_ == FLAG_CLASS ) { //The hell, why flags work like this? + p.shield = status->get_emblem_id(bl); + p.accessory2 = GetWord(g_id, 1); + p.accessory3 = GetWord(g_id, 0); } -#endif -#if PACKETVER >= 20110111 - WBUFW(buf,34) = vd->robe; - offset+= 2; - buf = WBUFP(buffer,offset); -#endif - WBUFL(buf,34) = status_get_guild_id(bl); - WBUFW(buf,38) = status_get_emblem_id(bl); - WBUFW(buf,40) = (sd)? sd->status.manner : 0; -#if PACKETVER >= 20091103 - WBUFL(buf,42) = (sc)? sc->opt3 : 0; - offset+=2; - buf = WBUFP(buffer,offset); -#elif PACKETVER >= 7 - if (!type) { - WBUFL(buf,42) = (sc)? sc->opt3 : 0; - offset+=2; - buf = WBUFP(buffer,offset); - } else - WBUFW(buf,42) = (sc)? sc->opt3 : 0; -#else - WBUFW(buf,42) = (sc)? sc->opt3 : 0; -#endif - WBUFB(buf,44) = (sd)? sd->status.karma : 0; - WBUFB(buf,45) = vd->sex; - WBUFPOS(buf,46,bl->x,bl->y,unit_getdir(bl)); - WBUFB(buf,49) = (sd)? 5 : 0; - WBUFB(buf,50) = (sd)? 5 : 0; - if (!spawn) { - WBUFB(buf,51) = vd->dead_sit; - offset++; - buf = WBUFP(buffer,offset); - } - WBUFW(buf,51) = clif_setlevel(bl); -#if PACKETVER < 20091103 - if (type) //End for non-player packet - return packet_len(WBUFW(buffer,0)); -#endif -#if PACKETVER >= 20080102 - WBUFW(buf,53) = sd?sd->user_font:0; -#endif -#if PACKETVER >= 20091103 - memcpy((char*)WBUFP(buf,55), name, NAME_LENGTH); - return WBUFW(buffer,2); + p.headpalette = vd->hair_color; + p.bodypalette = vd->cloth_color; + p.headDir = (sd)? sd->head_dir : 0; + p.isPKModeON = (sd && sd->status.karma) ? 1 : 0; + p.sex = vd->sex; + WBUFPOS(&p.PosDir[0],0,bl->x,bl->y,unit->getdir(bl)); + p.xSize = p.ySize = (sd) ? 5 : 0; + + clif->send(&p,sizeof(p),bl,target); #else - return packet_len(WBUFW(buffer,0)); + return; #endif - */ } - void clif_spawn_unit(struct block_list* bl, enum send_target target) { struct map_session_data* sd; - struct status_change* sc = status_get_sc(bl); - struct view_data* vd = status_get_viewdata(bl); + struct status_change* sc = status->get_sc(bl); + struct view_data* vd = status->get_viewdata(bl); struct packet_spawn_unit p; - int g_id = status_get_guild_id(bl); + int g_id = status->get_guild_id(bl); + + nullpo_retv(bl); + +#if PACKETVER < 20091103 + if( !pcdb_checkid(vd->class_) ) { + clif->spawn_unit2(bl,target); + return; + } +#endif sd = BL_CAST(BL_PC, bl); - + p.PacketType = spawn_unitType; #if PACKETVER >= 20091103 p.PacketLength = sizeof(p); p.objecttype = clif_bl_type(bl); #endif p.GID = bl->id; - p.speed = status_get_speed(bl); + p.speed = status->get_speed(bl); p.bodyState = (sc) ? sc->opt1 : 0; p.healthState = (sc) ? sc->opt2 : 0; p.effectState = (sc) ? sc->option : bl->type == BL_NPC ? ((TBL_NPC*)bl)->option : 0; @@ -1103,10 +1102,10 @@ void clif_spawn_unit(struct block_list* bl, enum send_target target) { p.accessory2 = vd->head_top; p.accessory3 = vd->head_mid; if( bl->type == BL_NPC && vd->class_ == FLAG_CLASS ) { //The hell, why flags work like this? - p.accessory = g_id; + p.accessory = status->get_emblem_id(bl); p.accessory2 = GetWord(g_id, 1); p.accessory3 = GetWord(g_id, 0); - } + } p.headpalette = vd->hair_color; p.bodypalette = vd->cloth_color; p.headDir = (sd)? sd->head_dir : 0; @@ -1114,18 +1113,18 @@ void clif_spawn_unit(struct block_list* bl, enum send_target target) { p.robe = vd->robe; #endif p.GUID = g_id; - p.GEmblemVer = status_get_emblem_id(bl); + p.GEmblemVer = status->get_emblem_id(bl); p.honor = (sd) ? sd->status.manner : 0; p.virtue = (sc) ? sc->opt3 : 0; - p.isPKModeON = (sd) ? sd->status.karma : 0; + p.isPKModeON = (sd && sd->status.karma) ? 1 : 0; p.sex = vd->sex; - WBUFPOS(&p.PosDir[0],0,bl->x,bl->y,unit_getdir(bl)); + WBUFPOS(&p.PosDir[0],0,bl->x,bl->y,unit->getdir(bl)); p.xSize = p.ySize = (sd) ? 5 : 0; p.clevel = clif_setlevel(bl); #if PACKETVER >= 20080102 - p.font = (sd) ? sd->user_font : 0; + p.font = (sd) ? sd->status.font : 0; #endif -#if PACKETVER >= 20140000 //actual 20120221 +#if PACKETVER >= 20150000 //actual 20120221 if( bl->type == BL_MOB ) { p.maxHP = status_get_max_hp(bl); p.HP = status_get_hp(bl); @@ -1137,10 +1136,11 @@ void clif_spawn_unit(struct block_list* bl, enum send_target target) { } #endif if( disguised(bl) ) { + nullpo_retv(sd); if( sd->status.class_ != sd->disguise ) clif->send(&p,sizeof(p),bl,target); -#if PACKETVER >= 20071106 - p.objecttype = pcdb_checkid(status_get_viewdata(bl)->class_) ? 0x0 : 0x5; //PC_TYPE : NPC_MOB_TYPE +#if PACKETVER >= 20091103 + p.objecttype = pcdb_checkid(status->get_viewdata(bl)->class_) ? 0x0 : 0x5; //PC_TYPE : NPC_MOB_TYPE p.GID = -bl->id; #else p.GID = -bl->id; @@ -1156,20 +1156,24 @@ void clif_spawn_unit(struct block_list* bl, enum send_target target) { *------------------------------------------*/ void clif_set_unit_walking(struct block_list* bl, struct map_session_data *tsd, struct unit_data* ud, enum send_target target) { struct map_session_data* sd; - struct status_change* sc = status_get_sc(bl); - struct view_data* vd = status_get_viewdata(bl); + struct status_change* sc = status->get_sc(bl); + struct view_data* vd = status->get_viewdata(bl); struct packet_unit_walking p; - int g_id = status_get_guild_id(bl); - + int g_id = status->get_guild_id(bl); + + nullpo_retv(bl); + sd = BL_CAST(BL_PC, bl); - + p.PacketType = unit_walkingType; #if PACKETVER >= 20091103 p.PacketLength = sizeof(p); +#endif +#if PACKETVER >= 20071106 p.objecttype = clif_bl_type(bl); #endif p.GID = bl->id; - p.speed = status_get_speed(bl); + p.speed = status->get_speed(bl); p.bodyState = (sc) ? sc->opt1 : 0; p.healthState = (sc) ? sc->opt2 : 0; p.effectState = (sc) ? sc->option : bl->type == BL_NPC ? ((TBL_NPC*)bl)->option : 0; @@ -1177,7 +1181,7 @@ void clif_set_unit_walking(struct block_list* bl, struct map_session_data *tsd, p.head = vd->hair_style; p.weapon = vd->weapon; p.accessory = vd->head_bottom; - p.moveStartTime = iTimer->gettick(); + p.moveStartTime = (unsigned int)timer->gettick(); #if PACKETVER < 7 p.shield = vd->shield; #endif @@ -1190,18 +1194,18 @@ void clif_set_unit_walking(struct block_list* bl, struct map_session_data *tsd, p.robe = vd->robe; #endif p.GUID = g_id; - p.GEmblemVer = status_get_emblem_id(bl); + p.GEmblemVer = status->get_emblem_id(bl); p.honor = (sd) ? sd->status.manner : 0; p.virtue = (sc) ? sc->opt3 : 0; - p.isPKModeON = (sd) ? sd->status.karma : 0; + p.isPKModeON = (sd && sd->status.karma) ? 1 : 0; p.sex = vd->sex; WBUFPOS2(&p.MoveData[0],0,bl->x,bl->y,ud->to_x,ud->to_y,8,8); p.xSize = p.ySize = (sd) ? 5 : 0; p.clevel = clif_setlevel(bl); #if PACKETVER >= 20080102 - p.font = (sd) ? sd->user_font : 0; + p.font = (sd) ? sd->status.font : 0; #endif -#if PACKETVER >= 20140000 //actual 20120221 +#if PACKETVER >= 20150000 //actual 20120221 if( bl->type == BL_MOB ) { p.maxHP = status_get_max_hp(bl); p.HP = status_get_hp(bl); @@ -1212,17 +1216,17 @@ void clif_set_unit_walking(struct block_list* bl, struct map_session_data *tsd, p.isBoss = 0; } #endif - + clif->send(&p,sizeof(p),tsd?&tsd->bl:bl,target); if( disguised(bl) ) { -#if PACKETVER >= 20071106 - p.objecttype = pcdb_checkid(status_get_viewdata(bl)->class_) ? 0x0 : 0x5; //PC_TYPE : NPC_MOB_TYPE +#if PACKETVER >= 20091103 + p.objecttype = pcdb_checkid(status->get_viewdata(bl)->class_) ? 0x0 : 0x5; //PC_TYPE : NPC_MOB_TYPE p.GID = -bl->id; #else p.GID = -bl->id; -#endif - clif->send(&p,sizeof(p),tsd?&tsd->bl:bl,SELF); +#endif + clif->send(&p,sizeof(p),bl,SELF); } } @@ -1277,31 +1281,23 @@ void clif_weather_check(struct map_session_data *sd) { int16 m = sd->bl.m; int fd = sd->fd; - if (map[m].flag.snow - || map[m].flag.clouds - || map[m].flag.fog - || map[m].flag.fireworks - || map[m].flag.sakura - || map[m].flag.leaves - || map[m].flag.clouds2) { - if (map[m].flag.snow) - clif->specialeffect_single(&sd->bl, 162, fd); - if (map[m].flag.clouds) - clif->specialeffect_single(&sd->bl, 233, fd); - if (map[m].flag.clouds2) - clif->specialeffect_single(&sd->bl, 516, fd); - if (map[m].flag.fog) - clif->specialeffect_single(&sd->bl, 515, fd); - if (map[m].flag.fireworks) { - clif->specialeffect_single(&sd->bl, 297, fd); - clif->specialeffect_single(&sd->bl, 299, fd); - clif->specialeffect_single(&sd->bl, 301, fd); - } - if (map[m].flag.sakura) - clif->specialeffect_single(&sd->bl, 163, fd); - if (map[m].flag.leaves) - clif->specialeffect_single(&sd->bl, 333, fd); - } + if (map->list[m].flag.snow) + clif->specialeffect_single(&sd->bl, 162, fd); + if (map->list[m].flag.clouds) + clif->specialeffect_single(&sd->bl, 233, fd); + if (map->list[m].flag.clouds2) + clif->specialeffect_single(&sd->bl, 516, fd); + if (map->list[m].flag.fog) + clif->specialeffect_single(&sd->bl, 515, fd); + if (map->list[m].flag.fireworks) { + clif->specialeffect_single(&sd->bl, 297, fd); + clif->specialeffect_single(&sd->bl, 299, fd); + clif->specialeffect_single(&sd->bl, 301, fd); + } + if (map->list[m].flag.sakura) + clif->specialeffect_single(&sd->bl, 163, fd); + if (map->list[m].flag.leaves) + clif->specialeffect_single(&sd->bl, 333, fd); } /** * Run when the weather on a map changes, throws all players in map id 'm' to clif_weather_check function @@ -1322,19 +1318,20 @@ void clif_weather(int16 m) /** * Main function to spawn a unit on the client (player/mob/pet/etc) **/ -int clif_spawn(struct block_list *bl) +bool clif_spawn(struct block_list *bl) { struct view_data *vd; - vd = status_get_viewdata(bl); - if( !vd || vd->class_ == INVISIBLE_CLASS ) - return 0; + vd = status->get_viewdata(bl); + if( !vd ) + return false; - /** - * Hide NPC from maya purple card. - **/ - if(bl->type == BL_NPC && !((TBL_NPC*)bl)->chat_id && (((TBL_NPC*)bl)->option&OPTION_INVISIBLE)) - return 0; + if( ( bl->type == BL_NPC + && !((TBL_NPC*)bl)->chat_id + && (((TBL_NPC*)bl)->option&OPTION_INVISIBLE) ) // Hide NPC from maya purple card. + || ( vd->class_ == INVISIBLE_CLASS ) + ) + return true; // Doesn't need to be spawned, so everything is alright clif->spawn_unit(bl,AREA_WOS); @@ -1351,12 +1348,12 @@ int clif_spawn(struct block_list *bl) clif->spiritball(&sd->bl); if(sd->state.size==SZ_BIG) // tiny/big players [Valaris] clif->specialeffect(bl,423,AREA); - else if(sd->state.size==SZ_MEDIUM) + else if(sd->state.size==SZ_SMALL) clif->specialeffect(bl,421,AREA); - if( sd->bg_id && map[sd->bl.m].flag.battleground ) + if( sd->bg_id && map->list[sd->bl.m].flag.battleground ) clif->sendbgemblem_area(sd); for( i = 0; i < sd->sc_display_count; i++ ) { - clif->sc_load(&sd->bl, sd->bl.id,AREA,StatusIconChangeTable[sd->sc_display[i]->type],sd->sc_display[i]->val1,sd->sc_display[i]->val2,sd->sc_display[i]->val3); + clif->sc_load(&sd->bl, sd->bl.id,AREA,status->IconChangeTable[sd->sc_display[i]->type],sd->sc_display[i]->val1,sd->sc_display[i]->val2,sd->sc_display[i]->val3); } for(i = 1; i < 5; i++){ if( sd->charm[i] > 0 ) @@ -1371,7 +1368,7 @@ int clif_spawn(struct block_list *bl) TBL_MOB *md = ((TBL_MOB*)bl); if(md->special_state.size==SZ_BIG) // tiny/big mobs [Valaris] clif->specialeffect(&md->bl,423,AREA); - else if(md->special_state.size==SZ_MEDIUM) + else if(md->special_state.size==SZ_SMALL) clif->specialeffect(&md->bl,421,AREA); } break; @@ -1380,7 +1377,7 @@ int clif_spawn(struct block_list *bl) TBL_NPC *nd = ((TBL_NPC*)bl); if( nd->size == SZ_BIG ) clif->specialeffect(&nd->bl,423,AREA); - else if( nd->size == SZ_MEDIUM ) + else if( nd->size == SZ_SMALL ) clif->specialeffect(&nd->bl,421,AREA); } break; @@ -1389,54 +1386,54 @@ int clif_spawn(struct block_list *bl) clif->send_petdata(NULL, (TBL_PET*)bl, 3, vd->head_bottom); // needed to display pet equip properly break; } - return 0; + return true; } /// Sends information about owned homunculus to the client (ZC_PROPERTY_HOMUN). [orn] /// 022e <name>.24B <modified>.B <level>.W <hunger>.W <intimacy>.W <equip id>.W <atk>.W <matk>.W <hit>.W <crit>.W <def>.W <mdef>.W <flee>.W <aspd>.W <hp>.W <max hp>.W <sp>.W <max sp>.W <exp>.L <max exp>.L <skill points>.W <atk range>.W void clif_hominfo(struct map_session_data *sd, struct homun_data *hd, int flag) { - struct status_data *status; + struct status_data *hstatus; unsigned char buf[128]; enum homun_type htype; nullpo_retv(hd); - status = &hd->battle_status; + hstatus = &hd->battle_status; htype = homun->class2type(hd->homunculus.class_); memset(buf,0,packet_len(0x22e)); WBUFW(buf,0)=0x22e; memcpy(WBUFP(buf,2),hd->homunculus.name,NAME_LENGTH); // Bit field, bit 0 : rename_flag (1 = already renamed), bit 1 : homunc vaporized (1 = true), bit 2 : homunc dead (1 = true) - WBUFB(buf,26)=(battle_config.hom_rename?0:hd->homunculus.rename_flag) | (hd->homunculus.vaporize << 1) | (hd->homunculus.hp?0:4); + WBUFB(buf,26)=(battle_config.hom_rename && hd->homunculus.rename_flag ? 0x1 : 0x0) | (hd->homunculus.vaporize == HOM_ST_REST ? 0x2 : 0) | (hd->homunculus.hp > 0 ? 0x4 : 0); WBUFW(buf,27)=hd->homunculus.level; WBUFW(buf,29)=hd->homunculus.hunger; WBUFW(buf,31)=(unsigned short) (hd->homunculus.intimacy / 100) ; WBUFW(buf,33)=0; // equip id - WBUFW(buf,35)=cap_value(status->rhw.atk2+status->batk, 0, INT16_MAX); - WBUFW(buf,37)=cap_value(status->matk_max, 0, INT16_MAX); - WBUFW(buf,39)=status->hit; + WBUFW(buf,35)=cap_value(hstatus->rhw.atk2+hstatus->batk, 0, INT16_MAX); + WBUFW(buf,37)=cap_value(hstatus->matk_max, 0, INT16_MAX); + WBUFW(buf,39)=hstatus->hit; if (battle_config.hom_setting&0x10) - WBUFW(buf,41)=status->luk/3 + 1; //crit is a +1 decimal value! Just display purpose.[Vicious] + WBUFW(buf,41)=hstatus->luk/3 + 1; //crit is a +1 decimal value! Just display purpose.[Vicious] else - WBUFW(buf,41)=status->cri/10; - WBUFW(buf,43)=status->def + status->vit ; - WBUFW(buf,45)=status->mdef; - WBUFW(buf,47)=status->flee; - WBUFW(buf,49)=(flag)?0:status->amotion; - if (status->max_hp > INT16_MAX) { - WBUFW(buf,51) = status->hp/(status->max_hp/100); + WBUFW(buf,41)=hstatus->cri/10; + WBUFW(buf,43)=hstatus->def + hstatus->vit ; + WBUFW(buf,45)=hstatus->mdef; + WBUFW(buf,47)=hstatus->flee; + WBUFW(buf,49)=(flag)?0:hstatus->amotion; + if (hstatus->max_hp > INT16_MAX) { + WBUFW(buf,51) = hstatus->hp/(hstatus->max_hp/100); WBUFW(buf,53) = 100; } else { - WBUFW(buf,51)=status->hp; - WBUFW(buf,53)=status->max_hp; + WBUFW(buf,51)=hstatus->hp; + WBUFW(buf,53)=hstatus->max_hp; } - if (status->max_sp > INT16_MAX) { - WBUFW(buf,55) = status->sp/(status->max_sp/100); + if (hstatus->max_sp > INT16_MAX) { + WBUFW(buf,55) = hstatus->sp/(hstatus->max_sp/100); WBUFW(buf,57) = 100; } else { - WBUFW(buf,55)=status->sp; - WBUFW(buf,57)=status->max_sp; + WBUFW(buf,55)=hstatus->sp; + WBUFW(buf,57)=hstatus->max_sp; } WBUFL(buf,59)=hd->homunculus.exp; WBUFL(buf,63)=hd->exp_next; @@ -1483,18 +1480,23 @@ void clif_send_homdata(struct map_session_data *sd, int state, int param) WFIFOSET(fd,packet_len(0x230)); } - -int clif_homskillinfoblock(struct map_session_data *sd) { //[orn] +/// Prepares and sends homun related information [orn] +void clif_homskillinfoblock(struct map_session_data *sd) { struct homun_data *hd; - int fd = sd->fd; - int i,j,len=4,id; - WFIFOHEAD(fd, 4+37*MAX_HOMUNSKILL); + int fd; + int i,j; + int len=4,id; + nullpo_retv(sd); + fd = sd->fd; hd = sd->hd; + if ( !hd ) - return 0 ; + return; + WFIFOHEAD(fd, 4+37*MAX_HOMUNSKILL); WFIFOW(fd,0)=0x235; + for ( i = 0; i < MAX_HOMUNSKILL; i++){ if( (id = hd->homunculus.hskill[i].id) != 0 ){ j = id - HM_SKILLBASE; @@ -1512,7 +1514,7 @@ int clif_homskillinfoblock(struct map_session_data *sd) { //[orn] WFIFOW(fd,2)=len; WFIFOSET(fd,len); - return 0; + return; } void clif_homskillup(struct map_session_data *sd, uint16 skill_id) { //[orn] @@ -1534,16 +1536,19 @@ void clif_homskillup(struct map_session_data *sd, uint16 skill_id) { //[orn] WFIFOSET(fd,packet_len(0x239)); } -int clif_hom_food(struct map_session_data *sd,int foodid,int fail) //[orn] +void clif_hom_food(struct map_session_data *sd,int foodid,int fail) //[orn] { - int fd=sd->fd; + int fd; + nullpo_retv(sd); + + fd = sd->fd; WFIFOHEAD(fd,packet_len(0x22f)); WFIFOW(fd,0)=0x22f; WFIFOB(fd,2)=fail; WFIFOW(fd,3)=foodid; WFIFOSET(fd,packet_len(0x22f)); - return 0; + return; } @@ -1555,14 +1560,19 @@ void clif_walkok(struct map_session_data *sd) WFIFOHEAD(fd, packet_len(0x87)); WFIFOW(fd,0)=0x87; - WFIFOL(fd,2)=iTimer->gettick(); + WFIFOL(fd,2)=(unsigned int)timer->gettick(); WFIFOPOS2(fd,6,sd->bl.x,sd->bl.y,sd->ud.to_x,sd->ud.to_y,8,8); WFIFOSET(fd,packet_len(0x87)); } void clif_move2(struct block_list *bl, struct view_data *vd, struct unit_data *ud) { +#ifdef ANTI_MAYAP_CHEAT + struct status_change *sc = NULL; + if( (sc = status->get_sc(bl)) && sc->option&(OPTION_HIDE|OPTION_CLOAK|OPTION_INVISIBLE|OPTION_CHASEWALK) ) + clif->ally_only = true; +#endif clif->set_unit_walking(bl,NULL,ud,AREA_WOS); if(vd->cloth_color) @@ -1575,7 +1585,7 @@ void clif_move2(struct block_list *bl, struct view_data *vd, struct unit_data *u // clif_movepc(sd); if(sd->state.size==SZ_BIG) // tiny/big players [Valaris] clif->specialeffect(&sd->bl,423,AREA); - else if(sd->state.size==SZ_MEDIUM) + else if(sd->state.size==SZ_SMALL) clif->specialeffect(&sd->bl,421,AREA); } break; @@ -1584,7 +1594,7 @@ void clif_move2(struct block_list *bl, struct view_data *vd, struct unit_data *u TBL_MOB *md = ((TBL_MOB*)bl); if(md->special_state.size==SZ_BIG) // tiny/big mobs [Valaris] clif->specialeffect(&md->bl,423,AREA); - else if(md->special_state.size==SZ_MEDIUM) + else if(md->special_state.size==SZ_SMALL) clif->specialeffect(&md->bl,421,AREA); } break; @@ -1593,6 +1603,9 @@ void clif_move2(struct block_list *bl, struct view_data *vd, struct unit_data *u clif->send_petdata(NULL, (TBL_PET*)bl, 3, vd->head_bottom); break; } +#ifdef ANTI_MAYAP_CHEAT + clif->ally_only = false; +#endif } @@ -1602,10 +1615,12 @@ void clif_move2(struct block_list *bl, struct view_data *vd, struct unit_data *u void clif_move(struct unit_data *ud) { unsigned char buf[16]; - struct view_data* vd; - struct block_list* bl = ud->bl; - - vd = status_get_viewdata(bl); + struct view_data *vd; + struct block_list *bl = ud->bl; +#ifdef ANTI_MAYAP_CHEAT + struct status_change *sc = NULL; +#endif + vd = status->get_viewdata(bl); if (!vd || vd->class_ == INVISIBLE_CLASS) return; //This performance check is needed to keep GM-hidden objects from being notified to bots. @@ -1622,28 +1637,37 @@ void clif_move(struct unit_data *ud) clif->move2(bl, vd, ud); return; } +#ifdef ANTI_MAYAP_CHEAT + if( (sc = status->get_sc(bl)) && sc->option&(OPTION_HIDE|OPTION_CLOAK|OPTION_INVISIBLE) ) + clif->ally_only = true; +#endif WBUFW(buf,0)=0x86; WBUFL(buf,2)=bl->id; WBUFPOS2(buf,6,bl->x,bl->y,ud->to_x,ud->to_y,8,8); - WBUFL(buf,12)=iTimer->gettick(); + WBUFL(buf,12)=(unsigned int)timer->gettick(); + clif->send(buf, packet_len(0x86), bl, AREA_WOS); + if (disguised(bl)) { WBUFL(buf,2)=-bl->id; clif->send(buf, packet_len(0x86), bl, SELF); } +#ifdef ANTI_MAYAP_CHEAT + clif->ally_only = false; +#endif } /*========================================== - * Delays the iMap->quit of a player after they are disconnected. [Skotlex] + * Delays the map->quit of a player after they are disconnected. [Skotlex] *------------------------------------------*/ -int clif_delayquit(int tid, unsigned int tick, int id, intptr_t data) { +int clif_delayquit(int tid, int64 tick, int id, intptr_t data) { struct map_session_data *sd = NULL; //Remove player from map server - if ((sd = iMap->id2sd(id)) != NULL && sd->fd == 0) //Should be a disconnected player. - iMap->quit(sd); + if ((sd = map->id2sd(id)) != NULL && sd->fd == 0) //Should be a disconnected player. + map->quit(sd); return 0; } @@ -1652,14 +1676,14 @@ int clif_delayquit(int tid, unsigned int tick, int id, intptr_t data) { *------------------------------------------*/ void clif_quitsave(int fd,struct map_session_data *sd) { if (!battle_config.prevent_logout || - DIFF_TICK(iTimer->gettick(), sd->canlog_tick) > battle_config.prevent_logout) - iMap->quit(sd); + DIFF_TICK(timer->gettick(), sd->canlog_tick) > battle_config.prevent_logout) + map->quit(sd); else if (sd->fd) { //Disassociate session from player (session is deleted after this function was called) //And set a timer to make him quit later. session[sd->fd]->session_data = NULL; sd->fd = 0; - iTimer->add_timer(iTimer->gettick() + 10000, clif->delayquit, sd->bl.id, 0); + timer->add(timer->gettick() + 10000, clif->delayquit, sd->bl.id, 0); } } @@ -1672,7 +1696,7 @@ void clif_changemap(struct map_session_data *sd, short m, int x, int y) { WFIFOHEAD(fd,packet_len(0x91)); WFIFOW(fd,0) = 0x91; - mapindex_getmapname_ext(map[m].cName ? map[m].cName : map[m].name, (char*)WFIFOP(fd,2)); + mapindex->getmapname_ext(map->list[m].custom_name ? map->list[map->list[m].instance_src_map].name : map->list[m].name, (char*)WFIFOP(fd,2)); WFIFOW(fd,18) = x; WFIFOW(fd,20) = y; WFIFOSET(fd,packet_len(0x91)); @@ -1688,7 +1712,7 @@ void clif_changemapserver(struct map_session_data* sd, unsigned short map_index, WFIFOHEAD(fd,packet_len(0x92)); WFIFOW(fd,0) = 0x92; - mapindex_getmapname_ext(mapindex_id2name(map_index), (char*)WFIFOP(fd,2)); + mapindex->getmapname_ext(mapindex_id2name(map_index), (char*)WFIFOP(fd,2)); WFIFOW(fd,18) = x; WFIFOW(fd,20) = y; WFIFOL(fd,22) = htonl(ip); @@ -1700,7 +1724,7 @@ void clif_changemapserver(struct map_session_data* sd, unsigned short map_index, void clif_blown(struct block_list *bl) { //Aegis packets says fixpos, but it's unsure whether slide works better or not. -// clif_fixpos(bl); + clif->fixpos(bl); clif->slide(bl, bl->x, bl->y); } @@ -1709,9 +1733,9 @@ void clif_blown(struct block_list *bl) /// isn't walkable, the char doesn't move at all. If the char is /// sitting it will stand up (ZC_STOPMOVE). /// 0088 <id>.L <x>.W <y>.W -void clif_fixpos(struct block_list *bl) -{ +void clif_fixpos(struct block_list *bl) { unsigned char buf[10]; + nullpo_retv(bl); WBUFW(buf,0) = 0x88; @@ -1745,29 +1769,40 @@ void clif_npcbuysell(struct map_session_data* sd, int id) /// Presents list of items, that can be bought in an NPC shop (ZC_PC_PURCHASE_ITEMLIST). /// 00c6 <packet len>.W { <price>.L <discount price>.L <item type>.B <name id>.W }* -void clif_buylist(struct map_session_data *sd, struct npc_data *nd) -{ +void clif_buylist(struct map_session_data *sd, struct npc_data *nd) { + struct npc_item_list *shop = NULL; + unsigned short shop_size = 0; int fd,i,c; nullpo_retv(sd); nullpo_retv(nd); + if( nd->subtype == SCRIPT ) { + shop = nd->u.scr.shop->item; + shop_size = nd->u.scr.shop->items; + } else { + shop = nd->u.shop.shop_item; + shop_size = nd->u.shop.count; + } + fd = sd->fd; - WFIFOHEAD(fd, 4 + nd->u.shop.count * 11); + + WFIFOHEAD(fd, 4 + shop_size * 11); WFIFOW(fd,0) = 0xc6; c = 0; - for( i = 0; i < nd->u.shop.count; i++ ) - { - struct item_data* id = itemdb_exists(nd->u.shop.shop_item[i].nameid); - int val = nd->u.shop.shop_item[i].value; - if( id == NULL ) - continue; - WFIFOL(fd, 4+c*11) = val; - WFIFOL(fd, 8+c*11) = pc->modifybuyvalue(sd,val); - WFIFOB(fd,12+c*11) = itemtype(id->type); - WFIFOW(fd,13+c*11) = ( id->view_id > 0 ) ? id->view_id : id->nameid; - c++; + for( i = 0; i < shop_size; i++ ) { + if( shop[i].nameid ) { + struct item_data* id = itemdb->exists(shop[i].nameid); + int val = shop[i].value; + if( id == NULL ) + continue; + WFIFOL(fd, 4+c*11) = val; + WFIFOL(fd, 8+c*11) = pc->modifybuyvalue(sd,val); + WFIFOB(fd,12+c*11) = itemtype(id->type); + WFIFOW(fd,13+c*11) = ( id->view_id > 0 ) ? id->view_id : id->nameid; + c++; + } } WFIFOW(fd,2) = 4 + c*11; @@ -1782,12 +1817,12 @@ void clif_hercules_chsys_create(struct hChSysCh *channel, char *name, char *pass channel->pass[0] = '\0'; else safestrncpy(channel->pass, pass, HCHSYS_NAME_LENGTH); - + channel->opt = hChSys_OPT_BASE; channel->banned = NULL; - + channel->msg_delay = 0; - + if( channel->type != hChSys_MAP && channel->type != hChSys_ALLY ) strdb_put(clif->channel_db, channel->name, channel); } @@ -1807,11 +1842,14 @@ void clif_selllist(struct map_session_data *sd) { if( sd->status.inventory[i].nameid > 0 && sd->inventory_data[i] ) { - if( !itemdb_cansell(&sd->status.inventory[i], pc->get_group_level(sd)) ) + if( !itemdb_cansell(&sd->status.inventory[i], pc_get_group_level(sd)) ) continue; if( sd->status.inventory[i].expire_time ) continue; // Cannot Sell Rental Items + + if( sd->status.inventory[i].bound && !pc_can_give_bound_items(sd)) + continue; // Don't allow sale of bound items val=sd->inventory_data[i]->value_sell; if( val < 0 ) @@ -1837,10 +1875,10 @@ void clif_selllist(struct map_session_data *sd) /// - append this text void clif_scriptmes(struct map_session_data *sd, int npcid, const char *mes) { int fd = sd->fd; - int slen = strlen(mes) + 9; + size_t slen = strlen(mes) + 9; sd->state.dialog = 1; - + WFIFOHEAD(fd, slen); WFIFOW(fd,0)=0xb4; WFIFOW(fd,2)=slen; @@ -1947,16 +1985,15 @@ 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) -{ +void clif_scriptmenu(struct map_session_data* sd, int npcid, const char* mes) { int fd = sd->fd; - int slen = strlen(mes) + 9; + size_t slen = strlen(mes) + 9; struct block_list *bl = NULL; - if (!sd->state.using_fake_npc && (npcid == fake_nd->bl.id || ((bl = iMap->id2bl(npcid)) && (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); + if (!sd->state.using_fake_npc && (npcid == npc->fake_nd->bl.id || ((bl = map->id2bl(npcid)) && (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; @@ -1978,17 +2015,16 @@ void clif_scriptmenu(struct map_session_data* sd, int npcid, const char* mes) /// - if npcid exists in the client: /// - 0143 <npcid of inputnum window>.L <atoi(text)>.L /// - close inputnum window -void clif_scriptinput(struct map_session_data *sd, int npcid) -{ +void clif_scriptinput(struct map_session_data *sd, int npcid) { int fd; struct block_list *bl = NULL; nullpo_retv(sd); - if (!sd->state.using_fake_npc && (npcid == fake_nd->bl.id || ((bl = iMap->id2bl(npcid)) && (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); + if (!sd->state.using_fake_npc && (npcid == npc->fake_nd->bl.id || ((bl = map->id2bl(npcid)) && (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); fd=sd->fd; WFIFOHEAD(fd, packet_len(0x142)); @@ -2009,17 +2045,16 @@ void clif_scriptinput(struct map_session_data *sd, int npcid) /// - if npcid is 0 or npcid exists in the client: /// - 01d5 <packetlen>.W <npcid of inputstr window>.L <text>.?B /// - close inputstr window -void clif_scriptinputstr(struct map_session_data *sd, int npcid) -{ +void clif_scriptinputstr(struct map_session_data *sd, int npcid) { int fd; struct block_list *bl = NULL; nullpo_retv(sd); - if (!sd->state.using_fake_npc && (npcid == fake_nd->bl.id || ((bl = iMap->id2bl(npcid)) && (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); + if (!sd->state.using_fake_npc && (npcid == npc->fake_nd->bl.id || ((bl = map->id2bl(npcid)) && (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); fd=sd->fd; WFIFOHEAD(fd, packet_len(0x1d4)); @@ -2059,10 +2094,10 @@ void clif_viewpoint(struct map_session_data *sd, int npc_id, int type, int x, in void clif_hercules_chsys_join(struct hChSysCh *channel, struct map_session_data *sd) { if( idb_put(channel->users, sd->status.char_id, sd) ) return; - + RECREATE(sd->channels, struct hChSysCh *, ++sd->channel_count); sd->channels[ sd->channel_count - 1 ] = channel; - + if( sd->stealth ) { sd->stealth = false; } else if( channel->opt & hChSys_OPT_ANNOUNCE_JOIN ) { @@ -2070,12 +2105,12 @@ void clif_hercules_chsys_join(struct hChSysCh *channel, struct map_session_data sprintf(message, "#%s '%s' joined",channel->name,sd->status.name); clif->chsys_msg(channel,sd,message); } - + /* someone is cheating, we kindly disconnect the bastard */ if( sd->channel_count > 200 ) { set_eof(sd->fd); } - + } /// Displays an illustration image. /// 0145 <image name>.16B <type>.B (ZC_SHOW_IMAGE) @@ -2179,23 +2214,23 @@ void clif_addcards2(unsigned short *cards, struct item* item) { //Client only receives four cards.. so randomly send them a set of cards. [Skotlex] if( MAX_SLOTS > 4 && (j = itemdb_slot(item->nameid)) > 4 ) i = rnd()%(j-3); //eg: 6 slots, possible i values: 0->3, 1->4, 2->5 => i = rnd()%3; - + //Normal items. if( item->card[i] > 0 && (j=itemdb_viewid(item->card[i])) > 0 ) cards[0] = j; else cards[0] = item->card[i]; - + if( item->card[++i] > 0 && (j=itemdb_viewid(item->card[i])) > 0 ) cards[1] = j; else cards[1] = item->card[i]; - + if( item->card[++i] > 0 && (j=itemdb_viewid(item->card[i])) > 0 ) cards[2] = j; else cards[2] = item->card[i]; - + if( item->card[++i] > 0 && (j=itemdb_viewid(item->card[i])) > 0 ) cards[3] = j; else @@ -2220,18 +2255,18 @@ void clif_additem(struct map_session_data *sd, int n, int amount, int fail) { p.PacketType = additemType; p.Index = n+2; p.count = amount; - + if( !fail ) { if( n < 0 || n >= MAX_INVENTORY || sd->status.inventory[n].nameid <=0 || sd->inventory_data[n] == NULL ) return; - + if (sd->inventory_data[n]->view_id > 0) p.nameid = sd->inventory_data[n]->view_id; else p.nameid = sd->status.inventory[n].nameid; - - p.IsIdentified = sd->status.inventory[n].identify; - p.IsDamaged = sd->status.inventory[n].attribute; + + p.IsIdentified = sd->status.inventory[n].identify ? 1 : 0; + p.IsDamaged = sd->status.inventory[n].attribute ? 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); @@ -2240,7 +2275,10 @@ void clif_additem(struct map_session_data *sd, int n, int amount, int fail) { p.HireExpireDate = sd->status.inventory[n].expire_time; #endif #if PACKETVER >= 20071002 - p.bindOnEquipType = 0; // unused + /* why restrict the flag to non-stackable? because this is the only packet allows stackable to, + * show the color, and therefore it'd be inconsistent with the rest (aka it'd show yellow, you relog/refresh and boom its gone) + */ + p.bindOnEquipType = sd->status.inventory[n].bound && !itemdb->isstackable2(sd->inventory_data[n]) ? 2 : sd->inventory_data[n]->flag.bindonequip ? 1 : 0; #endif } p.result = (unsigned char)fail; @@ -2322,91 +2360,112 @@ void clif_item_sub(unsigned char *buf, int n, struct item *i, struct item_data * } } -//Unified inventory function which sends all of the inventory (requires two packets, one for equipable items and one for stackable ones. [Skotlex] -void clif_inventorylist(struct map_session_data *sd) { - int i,n,ne,arrow=-1; - unsigned char *buf; - unsigned char *bufe; +void clif_item_equip(short idx, struct EQUIPITEM_INFO *p, struct item *i, struct item_data *id, int eqp_pos) { -#if PACKETVER < 5 - const int s = 10; //Entry size. -#elif PACKETVER < 20080102 - const int s = 18; -#else - const int s = 22; -#endif -#if PACKETVER < 20071002 - const int se = 20; -#elif PACKETVER < 20100629 - const int se = 26; -#else - const int se = 28; + p->index = idx; + + if (id->view_id > 0) + p->ITID = id->view_id; + else + p->ITID = i->nameid; + + p->type = itemtype(id->type); + +#if PACKETVER < 20120925 + p->IsIdentified = i->identify ? 1 : 0; #endif - buf = (unsigned char*)aMalloc(MAX_INVENTORY * s + 4); - bufe = (unsigned char*)aMalloc(MAX_INVENTORY * se + 4); + p->location = eqp_pos; + p->WearState = i->equip; + +#if PACKETVER < 20120925 + p->IsDamaged = i->attribute ? 1 : 0; +#endif + p->RefiningLevel = i->refine; - for( i = 0, n = 0, ne = 0; i < MAX_INVENTORY; i++ ) - { - if( sd->status.inventory[i].nameid <=0 || sd->inventory_data[i] == NULL ) - continue; + clif->addcards2(&p->slot.card[0], i); - if( !itemdb_isstackable2(sd->inventory_data[i]) ) - { //Non-stackable (Equippable) - WBUFW(bufe,ne*se+4)=i+2; - clif->item_sub(bufe, ne*se+6, &sd->status.inventory[i], sd->inventory_data[i], pc->equippoint(sd,i)); - clif->addcards(WBUFP(bufe, ne*se+16), &sd->status.inventory[i]); #if PACKETVER >= 20071002 - WBUFL(bufe,ne*se+24)=sd->status.inventory[i].expire_time; - WBUFW(bufe,ne*se+28)=0; //Unknown + p->HireExpireDate = i->expire_time; #endif + +#if PACKETVER >= 20080102 + p->bindOnEquipType = i->bound ? 2 : id->flag.bindonequip ? 1 : 0; +#endif + #if PACKETVER >= 20100629 - if (sd->inventory_data[i]->equip&EQP_VISIBLE) - WBUFW(bufe,ne*se+30)= sd->inventory_data[i]->look; - else - WBUFW(bufe,ne*se+30)=0; + p->wItemSpriteNumber = id->equip&EQP_VISIBLE ? id->look : 0; #endif - ne++; - } - else - { //Stackable. - WBUFW(buf,n*s+4)=i+2; - clif->item_sub(buf, n*s+6, &sd->status.inventory[i], sd->inventory_data[i], -2); - if( sd->inventory_data[i]->equip == EQP_AMMO && sd->status.inventory[i].equip ) - arrow=i; + +#if PACKETVER >= 20120925 + p->Flag.IsIdentified = i->identify ? 1 : 0; + p->Flag.IsDamaged = i->attribute ? 1 : 0; + p->Flag.PlaceETCTab = i->favorite ? 1 : 0; + p->Flag.SpareBits = 0; +#endif +} +void clif_item_normal(short idx, struct NORMALITEM_INFO *p, struct item *i, struct item_data *id) { + p->index = idx; + + if (id->view_id > 0) + p->ITID = id->view_id; + else + p->ITID = i->nameid; + + p->type = itemtype(id->type); + +#if PACKETVER < 20120925 + p->IsIdentified = i->identify ? 1 : 0; +#endif + + p->count = i->amount; + p->WearState = id->equip; + #if PACKETVER >= 5 - clif->addcards(WBUFP(buf, n*s+14), &sd->status.inventory[i]); + clif->addcards2(&p->slot.card[0], i); #endif + #if PACKETVER >= 20080102 - WBUFL(buf,n*s+22)=sd->status.inventory[i].expire_time; + p->HireExpireDate = i->expire_time; #endif - n++; - } - } - if( n ) { -#if PACKETVER < 5 - WBUFW(buf,0)=0xa3; -#elif PACKETVER < 20080102 - WBUFW(buf,0)=0x1ee; -#else - WBUFW(buf,0)=0x2e8; + +#if PACKETVER >= 20120925 + p->Flag.IsIdentified = i->identify ? 1 : 0; + p->Flag.PlaceETCTab = i->favorite ? 1 : 0; + p->Flag.SpareBits = 0; #endif - WBUFW(buf,2)=4+n*s; - clif->send(buf, WBUFW(buf,2), &sd->bl, SELF); +} +void clif_inventorylist(struct map_session_data *sd) { + int i, normal = 0, equip = 0; + + for( i = 0; i < MAX_INVENTORY; i++ ) { + + if( sd->status.inventory[i].nameid <= 0 || sd->inventory_data[i] == NULL ) + continue; + if( !itemdb->isstackable2(sd->inventory_data[i]) ) //Non-stackable (Equippable) + clif_item_equip(i+2,&itemlist_equip.list[equip++],&sd->status.inventory[i],sd->inventory_data[i],pc->equippoint(sd,i)); + else //Stackable (Normal) + clif_item_normal(i+2,&itemlist_normal.list[normal++],&sd->status.inventory[i],sd->inventory_data[i]); } - if( arrow >= 0 ) - clif->arrowequip(sd,arrow); - if( ne ) { -#if PACKETVER < 20071002 - WBUFW(bufe,0)=0xa4; -#else - WBUFW(bufe,0)=0x2d0; -#endif - WBUFW(bufe,2)=4+ne*se; - clif->send(bufe, WBUFW(bufe,2), &sd->bl, SELF); + if( normal ) { + itemlist_normal.PacketType = inventorylistnormalType; + itemlist_normal.PacketLength = 4 + (sizeof(struct NORMALITEM_INFO) * normal); + + clif->send(&itemlist_normal, itemlist_normal.PacketLength, &sd->bl, SELF); } -#if PACKETVER >= 20111122 + + if( sd->equip_index[EQI_AMMO] >= 0 ) + clif->arrowequip(sd,sd->equip_index[EQI_AMMO]); + + if( equip ) { + itemlist_equip.PacketType = inventorylistequipType; + itemlist_equip.PacketLength = 4 + (sizeof(struct EQUIPITEM_INFO) * equip); + + clif->send(&itemlist_equip, itemlist_equip.PacketLength, &sd->bl, SELF); + } +/* on 20120925 onwards this is a field on clif_item_equip/normal */ +#if PACKETVER >= 20111122 && PACKETVER < 20120925 for( i = 0; i < MAX_INVENTORY; i++ ) { if( sd->status.inventory[i].nameid <= 0 || sd->inventory_data[i] == NULL ) continue; @@ -2415,224 +2474,121 @@ void clif_inventorylist(struct map_session_data *sd) { clif->favorite_item(sd, i); } #endif - - if( buf ) aFree(buf); - if( bufe ) aFree(bufe); } //Required when items break/get-repaired. Only sends equippable item list. -void clif_equiplist(struct map_session_data *sd) -{ - int i,n,fd = sd->fd; - unsigned char *buf; -#if PACKETVER < 20071002 - const int cmd = 20; -#elif PACKETVER < 20100629 - const int cmd = 26; -#else - const int cmd = 28; -#endif +void clif_equiplist(struct map_session_data *sd) { + int i, equip = 0; - WFIFOHEAD(fd, MAX_INVENTORY * cmd + 4); - buf = WFIFOP(fd,0); + for( i = 0; i < MAX_INVENTORY; i++ ) { - for(i=0,n=0;i<MAX_INVENTORY;i++){ - if (sd->status.inventory[i].nameid <=0 || sd->inventory_data[i] == NULL) + if( sd->status.inventory[i].nameid <= 0 || sd->inventory_data[i] == NULL ) continue; + if( !itemdb->isstackable2(sd->inventory_data[i]) ) //Non-stackable (Equippable) + clif_item_equip(i+2,&itemlist_equip.list[equip++],&sd->status.inventory[i],sd->inventory_data[i],pc->equippoint(sd,i)); + } + + if( equip ) { + itemlist_equip.PacketType = inventorylistequipType; + itemlist_equip.PacketLength = 4 + (sizeof(struct EQUIPITEM_INFO) * equip); - if(itemdb_isstackable2(sd->inventory_data[i])) + clif->send(&itemlist_equip, itemlist_equip.PacketLength, &sd->bl, SELF); + } + + /* on 20120925 onwards this is a field on clif_item_equip */ +#if PACKETVER >= 20111122 && PACKETVER < 20120925 + for( i = 0; i < MAX_INVENTORY; i++ ) { + if( sd->status.inventory[i].nameid <= 0 || sd->inventory_data[i] == NULL ) continue; - //Equippable - WBUFW(buf,n*cmd+4)=i+2; - clif->item_sub(buf, n*cmd+6, &sd->status.inventory[i], sd->inventory_data[i], pc->equippoint(sd,i)); - clif->addcards(WBUFP(buf, n*cmd+16), &sd->status.inventory[i]); -#if PACKETVER >= 20071002 - WBUFL(buf,n*cmd+24)=sd->status.inventory[i].expire_time; - WBUFW(buf,n*cmd+28)=0; //Unknown -#endif -#if PACKETVER >= 20100629 - if (sd->inventory_data[i]->equip&EQP_VISIBLE) - WBUFW(buf,n*cmd+30)= sd->inventory_data[i]->look; - else - WBUFW(buf,n*cmd+30)=0; -#endif - n++; + + if ( sd->status.inventory[i].favorite ) + clif->favorite_item(sd, i); } - if (n) { -#if PACKETVER < 20071002 - WBUFW(buf,0)=0xa4; -#else - WBUFW(buf,0)=0x2d0; #endif - WBUFW(buf,2)=4+n*cmd; - WFIFOSET(fd,WFIFOW(fd,2)); - } } -void clif_storagelist(struct map_session_data* sd, struct item* items, int items_length) -{ +void clif_storagelist(struct map_session_data* sd, struct item* items, int items_length) { + int i = 0; struct item_data *id; - int i,n,ne; - unsigned char *buf; - unsigned char *bufe; -#if PACKETVER < 5 - const int s = 10; //Entry size. -#elif PACKETVER < 20080102 - const int s = 18; -#else - const int s = 22; -#endif -#if PACKETVER < 20071002 - const int cmd = 20; -#elif PACKETVER < 20100629 - const int cmd = 26; -#else - const int cmd = 28; -#endif - buf = (unsigned char*)aMalloc(items_length * s + 4); - bufe = (unsigned char*)aMalloc(items_length * cmd + 4); + do { + int normal = 0, equip = 0, k = 0; - for( i = 0, n = 0, ne = 0; i < items_length; i++ ) - { - if( items[i].nameid <= 0 ) - continue; - id = itemdb_search(items[i].nameid); - if( !itemdb_isstackable2(id) ) - { //Equippable - WBUFW(bufe,ne*cmd+4)=i+1; - clif->item_sub(bufe, ne*cmd+6, &items[i], id, id->equip); - clif->addcards(WBUFP(bufe, ne*cmd+16), &items[i]); -#if PACKETVER >= 20071002 - WBUFL(bufe,ne*cmd+24)=items[i].expire_time; - WBUFW(bufe,ne*cmd+28)=0; //Unknown -#endif - ne++; + for( ; i < items_length && k < 500; i++, k++ ) { + + if( items[i].nameid <= 0 ) + continue; + + id = itemdb->search(items[i].nameid); + + if( !itemdb->isstackable2(id) ) //Non-stackable (Equippable) + clif_item_equip(i+1,&storelist_equip.list[equip++],&items[i],id,id->equip); + else //Stackable (Normal) + clif_item_normal(i+1,&storelist_normal.list[normal++],&items[i],id); } - else - { //Stackable - WBUFW(buf,n*s+4)=i+1; - clif->item_sub(buf, n*s+6, &items[i], id,-1); -#if PACKETVER >= 5 - clif->addcards(WBUFP(buf,n*s+14), &items[i]); -#endif -#if PACKETVER >= 20080102 - WBUFL(buf,n*s+22)=items[i].expire_time; + + if( normal ) { + storelist_normal.PacketType = storagelistnormalType; + storelist_normal.PacketLength = ( sizeof( storelist_normal ) - sizeof( storelist_normal.list ) ) + (sizeof(struct NORMALITEM_INFO) * normal); + +#if PACKETVER >= 20120925 + safestrncpy(storelist_normal.name, "Storage", NAME_LENGTH); #endif - n++; + + clif->send(&storelist_normal, storelist_normal.PacketLength, &sd->bl, SELF); } - } - if( n ) - { -#if PACKETVER < 5 - WBUFW(buf,0)=0xa5; -#elif PACKETVER < 20080102 - WBUFW(buf,0)=0x1f0; -#else - WBUFW(buf,0)=0x2ea; -#endif - WBUFW(buf,2)=4+n*s; - clif->send(buf, WBUFW(buf,2), &sd->bl, SELF); - } - if( ne ) - { -#if PACKETVER < 20071002 - WBUFW(bufe,0)=0xa6; -#else - WBUFW(bufe,0)=0x2d1; + + if( equip ) { + storelist_equip.PacketType = storagelistequipType; + storelist_equip.PacketLength = ( sizeof( storelist_equip ) - sizeof( storelist_equip.list ) ) + (sizeof(struct EQUIPITEM_INFO) * equip); + +#if PACKETVER >= 20120925 + safestrncpy(storelist_equip.name, "Storage", NAME_LENGTH); #endif - WBUFW(bufe,2)=4+ne*cmd; - clif->send(bufe, WBUFW(bufe,2), &sd->bl, SELF); - } - if( buf ) aFree(buf); - if( bufe ) aFree(bufe); + clif->send(&storelist_equip, storelist_equip.PacketLength, &sd->bl, SELF); + } + + } while ( i < items_length ); + } -void clif_cartlist(struct map_session_data *sd) -{ +void clif_cartlist(struct map_session_data *sd) { + int i, normal = 0, equip = 0; struct item_data *id; - int i,n,ne; - unsigned char *buf; - unsigned char *bufe; -#if PACKETVER < 5 - const int s = 10; //Entry size. -#elif PACKETVER < 20080102 - const int s = 18; -#else - const int s = 22; -#endif -#if PACKETVER < 20071002 - const int cmd = 20; -#elif PACKETVER < 20100629 - const int cmd = 26; -#else - const int cmd = 28; -#endif - buf = (unsigned char*)aMalloc(MAX_CART * s + 4); - bufe = (unsigned char*)aMalloc(MAX_CART * cmd + 4); + for( i = 0; i < MAX_CART; i++ ) { - for( i = 0, n = 0, ne = 0; i < MAX_CART; i++ ) - { if( sd->status.cart[i].nameid <= 0 ) continue; - id = itemdb_search(sd->status.cart[i].nameid); - if( !itemdb_isstackable2(id) ) - { //Equippable - WBUFW(bufe,ne*cmd+4)=i+2; - clif->item_sub(bufe, ne*cmd+6, &sd->status.cart[i], id, id->equip); - clif->addcards(WBUFP(bufe, ne*cmd+16), &sd->status.cart[i]); -#if PACKETVER >= 20071002 - WBUFL(bufe,ne*cmd+24)=sd->status.cart[i].expire_time; - WBUFW(bufe,ne*cmd+28)=0; //Unknown -#endif - ne++; - } - else - { //Stackable - WBUFW(buf,n*s+4)=i+2; - clif->item_sub(buf, n*s+6, &sd->status.cart[i], id,-1); -#if PACKETVER >= 5 - clif->addcards(WBUFP(buf,n*s+14), &sd->status.cart[i]); -#endif -#if PACKETVER >= 20080102 - WBUFL(buf,n*s+22)=sd->status.cart[i].expire_time; -#endif - n++; - } - } - if( n ) - { -#if PACKETVER < 5 - WBUFW(buf,0)=0x123; -#elif PACKETVER < 20080102 - WBUFW(buf,0)=0x1ef; -#else - WBUFW(buf,0)=0x2e9; -#endif - WBUFW(buf,2)=4+n*s; - clif->send(buf, WBUFW(buf,2), &sd->bl, SELF); + + id = itemdb->search(sd->status.cart[i].nameid); + + if( !itemdb->isstackable2(id) ) //Non-stackable (Equippable) + clif_item_equip(i+2,&itemlist_equip.list[equip++],&sd->status.cart[i],id,id->equip); + else //Stackable (Normal) + clif_item_normal(i+2,&itemlist_normal.list[normal++],&sd->status.cart[i],id); } - if( ne ) - { -#if PACKETVER < 20071002 - WBUFW(bufe,0)=0x122; -#else - WBUFW(bufe,0)=0x2d2; -#endif - WBUFW(bufe,2)=4+ne*cmd; - clif->send(bufe, WBUFW(bufe,2), &sd->bl, SELF); + + if( normal ) { + itemlist_normal.PacketType = cartlistnormalType; + itemlist_normal.PacketLength = 4 + (sizeof(struct NORMALITEM_INFO) * normal); + + clif->send(&itemlist_normal, itemlist_normal.PacketLength, &sd->bl, SELF); } - if( buf ) aFree(buf); - if( bufe ) aFree(bufe); + if( equip ) { + itemlist_equip.PacketType = cartlistequipType; + itemlist_equip.PacketLength = 4 + (sizeof(struct EQUIPITEM_INFO) * equip); + + clif->send(&itemlist_equip, itemlist_equip.PacketLength, &sd->bl, SELF); + } } /// Removes cart (ZC_CARTOFF). /// 012b -/// Client behaviour: +/// Client behavior: /// Closes the cart storage and removes all it's items from memory. /// The Num & Weight values of the cart are left untouched and the cart is NOT removed. void clif_clearcart(int fd) @@ -2692,14 +2648,14 @@ void read_channels_config(void) { config_t channels_conf; config_setting_t *chsys = NULL; const char *config_filename = "conf/channels.conf"; // FIXME hardcoded name - - if (conf_read_file(&channels_conf, config_filename)) + + if (libconfig->read_file(&channels_conf, config_filename)) return; - - chsys = config_lookup(&channels_conf, "chsys"); - + + chsys = libconfig->lookup(&channels_conf, "chsys"); + if (chsys != NULL) { - config_setting_t *settings = config_setting_get_elem(chsys, 0); + config_setting_t *settings = libconfig->setting_get_elem(chsys, 0); config_setting_t *channels; config_setting_t *colors; int i,k; @@ -2710,45 +2666,46 @@ void read_channels_config(void) { local_autojoin = 0, ally_autojoin = 0, allow_user_channel_creation = 0, irc_enabled = 0; - - if( !config_setting_lookup_string(settings, "map_local_channel_name", &local_name) ) + + if( !libconfig->setting_lookup_string(settings, "map_local_channel_name", &local_name) ) local_name = "map"; safestrncpy(hChSys.local_name, local_name, HCHSYS_NAME_LENGTH); - - if( !config_setting_lookup_string(settings, "ally_channel_name", &ally_name) ) + + if( !libconfig->setting_lookup_string(settings, "ally_channel_name", &ally_name) ) ally_name = "ally"; safestrncpy(hChSys.ally_name, ally_name, HCHSYS_NAME_LENGTH); - - if( !config_setting_lookup_string(settings, "irc_channel_name", &irc_name) ) + + if( !libconfig->setting_lookup_string(settings, "irc_channel_name", &irc_name) ) irc_name = "irc"; safestrncpy(hChSys.irc_name, irc_name, HCHSYS_NAME_LENGTH); - - config_setting_lookup_bool(settings, "map_local_channel", &local_enabled); - config_setting_lookup_bool(settings, "ally_channel_enabled", &ally_enabled); - config_setting_lookup_bool(settings, "irc_channel_enabled", &irc_enabled); - + + libconfig->setting_lookup_bool(settings, "map_local_channel", &local_enabled); + libconfig->setting_lookup_bool(settings, "ally_channel_enabled", &ally_enabled); + libconfig->setting_lookup_bool(settings, "irc_channel_enabled", &irc_enabled); + if( local_enabled ) hChSys.local = true; if( ally_enabled ) hChSys.ally = true; if( irc_enabled ) hChSys.irc = true; - + hChSys.irc_server[0] = hChSys.irc_channel[0] = hChSys.irc_nick[0] = hChSys.irc_nick_pw[0] = '\0'; - + if( hChSys.irc ) { const char *irc_server, *irc_channel, *irc_nick, *irc_nick_pw; - if( config_setting_lookup_string(settings, "irc_channel_network", &irc_server) ) { + int irc_use_ghost = 0; + if( libconfig->setting_lookup_string(settings, "irc_channel_network", &irc_server) ) { if( !strstr(irc_server,":") ) { hChSys.irc = false; ShowWarning("channels.conf : network port wasn't found in 'irc_channel_network', disabling irc channel...\n"); } else { unsigned char d = 0, dlen = strlen(irc_server); char server[40]; - + memset(server, '\0', sizeof(server)); - + for(d = 0; d < dlen; d++) { if(irc_server[d] == ':') { memcpy(server, irc_server, d); @@ -2763,13 +2720,13 @@ void read_channels_config(void) { hChSys.irc = false; ShowWarning("channels.conf : irc channel enabled but irc_channel_network wasn't found, disabling irc channel...\n"); } - if( config_setting_lookup_string(settings, "irc_channel_channel", &irc_channel) ) + if( libconfig->setting_lookup_string(settings, "irc_channel_channel", &irc_channel) ) safestrncpy(hChSys.irc_channel, irc_channel, 50); else { hChSys.irc = false; ShowWarning("channels.conf : irc channel enabled but irc_channel_channel wasn't found, disabling irc channel...\n"); } - if( config_setting_lookup_string(settings, "irc_channel_nick", &irc_nick) ) { + if( libconfig->setting_lookup_string(settings, "irc_channel_nick", &irc_nick) ) { if( strcmpi(irc_nick,"Hercules_chSysBot") == 0 ) { sprintf(hChSys.irc_nick, "Hercules_chSysBot%d",rand()%777); } else @@ -2778,103 +2735,106 @@ void read_channels_config(void) { hChSys.irc = false; ShowWarning("channels.conf : irc channel enabled but irc_channel_nick wasn't found, disabling irc channel...\n"); } - if( config_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(hChSys.irc_nick_pw, irc_nick_pw, 30); + config_setting_lookup_bool(settings, "irc_channel_use_ghost", &irc_use_ghost); + hChSys.irc_use_ghost = irc_use_ghost; + } } - - config_setting_lookup_bool(settings, "map_local_channel_autojoin", &local_autojoin); - config_setting_lookup_bool(settings, "ally_channel_autojoin", &ally_autojoin); + + libconfig->setting_lookup_bool(settings, "map_local_channel_autojoin", &local_autojoin); + libconfig->setting_lookup_bool(settings, "ally_channel_autojoin", &ally_autojoin); if( local_autojoin ) hChSys.local_autojoin = true; if( ally_autojoin ) hChSys.ally_autojoin = true; - - config_setting_lookup_bool(settings, "allow_user_channel_creation", &allow_user_channel_creation); + + libconfig->setting_lookup_bool(settings, "allow_user_channel_creation", &allow_user_channel_creation); if( allow_user_channel_creation ) hChSys.allow_user_channel_creation = true; - if( (colors = config_setting_get_member(settings, "colors")) != NULL ) { - int color_count = config_setting_length(colors); - CREATE( hChSys.colors, unsigned long, color_count ); + if( (colors = libconfig->setting_get_member(settings, "colors")) != NULL ) { + int color_count = libconfig->setting_length(colors); + CREATE( hChSys.colors, unsigned int, color_count ); CREATE( hChSys.colors_name, char *, color_count ); for(i = 0; i < color_count; i++) { - config_setting_t *color = config_setting_get_elem(colors, i); + config_setting_t *color = libconfig->setting_get_elem(colors, i); CREATE( hChSys.colors_name[i], char, HCHSYS_NAME_LENGTH ); - + safestrncpy(hChSys.colors_name[i], config_setting_name(color), HCHSYS_NAME_LENGTH); - hChSys.colors[i] = strtoul(config_setting_get_string_elem(colors,i),NULL,0); + hChSys.colors[i] = (unsigned int)strtoul(libconfig->setting_get_string_elem(colors,i),NULL,0); hChSys.colors[i] = (hChSys.colors[i] & 0x0000FF) << 16 | (hChSys.colors[i] & 0x00FF00) | (hChSys.colors[i] & 0xFF0000) >> 16;//RGB to BGR } hChSys.colors_count = color_count; } - - config_setting_lookup_string(settings, "map_local_channel_color", &local_color); - + + libconfig->setting_lookup_string(settings, "map_local_channel_color", &local_color); + for (k = 0; k < hChSys.colors_count; k++) { if( strcmpi(hChSys.colors_name[k],local_color) == 0 ) break; } - + if( k < hChSys.colors_count ) { hChSys.local_color = k; } else { ShowError("channels.conf: unknown color '%s' for 'map_local_channel_color', disabling '#%s'...\n",local_color,local_name); hChSys.local = false; } - - config_setting_lookup_string(settings, "ally_channel_color", &ally_color); - + + libconfig->setting_lookup_string(settings, "ally_channel_color", &ally_color); + for (k = 0; k < hChSys.colors_count; k++) { if( strcmpi(hChSys.colors_name[k],ally_color) == 0 ) break; } - + if( k < hChSys.colors_count ) { hChSys.ally_color = k; } else { ShowError("channels.conf: unknown color '%s' for 'ally_channel_color', disabling '#%s'...\n",ally_color,ally_name); hChSys.ally = false; } - - config_setting_lookup_string(settings, "irc_channel_color", &irc_color); - + + libconfig->setting_lookup_string(settings, "irc_channel_color", &irc_color); + for (k = 0; k < hChSys.colors_count; k++) { if( strcmpi(hChSys.colors_name[k],irc_color) == 0 ) break; } - + if( k < hChSys.colors_count ) { hChSys.irc_color = k; } else { ShowError("channels.conf: unknown color '%s' for 'irc_channel_color', disabling '#%s'...\n",irc_color,irc_name); hChSys.irc = false; } - + if( hChSys.irc ) { struct hChSysCh *chd; CREATE( chd, struct hChSysCh, 1 ); - + safestrncpy(chd->name, hChSys.irc_name, HCHSYS_NAME_LENGTH); chd->type = hChSys_IRC; - + clif->chsys_create(chd,NULL,NULL,hChSys.irc_color); ircbot->channel = chd; } - - if( (channels = config_setting_get_member(settings, "default_channels")) != NULL ) { - int channel_count = config_setting_length(channels); - + + if( (channels = libconfig->setting_get_member(settings, "default_channels")) != NULL ) { + int channel_count = libconfig->setting_length(channels); + for(i = 0; i < channel_count; i++) { - config_setting_t *channel = config_setting_get_elem(channels, i); + config_setting_t *channel = libconfig->setting_get_elem(channels, i); const char *name = config_setting_name(channel); - const char *color = config_setting_get_string_elem(channels,i); + const char *color = libconfig->setting_get_string_elem(channels,i); struct hChSysCh *chd; - + for (k = 0; k < hChSys.colors_count; k++) { if( strcmpi(hChSys.colors_name[k],color) == 0 ) break; @@ -2889,16 +2849,16 @@ void read_channels_config(void) { } CREATE( chd, struct hChSysCh, 1 ); - + safestrncpy(chd->name, name, HCHSYS_NAME_LENGTH); chd->type = hChSys_PUBLIC; - + clif->chsys_create(chd,NULL,NULL,k); } } - + ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' channels in '"CL_WHITE"%s"CL_RESET"'.\n", db_size(clif->channel_db), config_filename); - config_destroy(&channels_conf); + libconfig->destroy(&channels_conf); } } @@ -2951,7 +2911,7 @@ int clif_hpmeter_sub(struct block_list *bl, va_list ap) { *------------------------------------------*/ int clif_hpmeter(struct map_session_data *sd) { nullpo_ret(sd); - iMap->foreachinarea(clif->hpmeter_sub, sd->bl.m, sd->bl.x-AREA_SIZE, sd->bl.y-AREA_SIZE, sd->bl.x+AREA_SIZE, sd->bl.y+AREA_SIZE, BL_PC, sd); + map->foreachinarea(clif->hpmeter_sub, sd->bl.m, sd->bl.x-AREA_SIZE, sd->bl.y-AREA_SIZE, sd->bl.x+AREA_SIZE, sd->bl.y+AREA_SIZE, BL_PC, sd); return 0; } @@ -2963,10 +2923,9 @@ int clif_hpmeter(struct map_session_data *sd) { /// 013a <atk range>.W (ZC_ATTACK_RANGE) /// 0141 <status id>.L <base status>.L <plus status>.L (ZC_COUPLESTATUS) /// TODO: Extract individual packets. -/// FIXME: Packet lengths from packet_len(cmd) void clif_updatestatus(struct map_session_data *sd,int type) { - int fd,len=8; + int fd,len; nullpo_retv(sd); @@ -2978,6 +2937,7 @@ void clif_updatestatus(struct map_session_data *sd,int type) WFIFOHEAD(fd, 14); WFIFOW(fd,0)=0xb0; WFIFOW(fd,2)=type; + len = packet_len(0xb0); switch(type){ // 00b0 case SP_WEIGHT: @@ -3029,7 +2989,8 @@ void clif_updatestatus(struct map_session_data *sd,int type) case SP_HP: WFIFOL(fd,4)=sd->battle_status.hp; // TODO: Won't these overwrite the current packet? - clif->hpmeter(sd); + if( map->list[sd->bl.m].hpmeter_visible ) + clif->hpmeter(sd); if( !battle_config.party_hp_mode && sd->status.party_id ) clif->party_hp(sd); if( sd->bg_id ) @@ -3082,22 +3043,27 @@ void clif_updatestatus(struct map_session_data *sd,int type) case SP_ZENY: WFIFOW(fd,0)=0xb1; WFIFOL(fd,4)=sd->status.zeny; + len = packet_len(0xb1); break; case SP_BASEEXP: WFIFOW(fd,0)=0xb1; WFIFOL(fd,4)=sd->status.base_exp; + len = packet_len(0xb1); break; case SP_JOBEXP: WFIFOW(fd,0)=0xb1; WFIFOL(fd,4)=sd->status.job_exp; + len = packet_len(0xb1); break; case SP_NEXTBASEEXP: WFIFOW(fd,0)=0xb1; WFIFOL(fd,4)=pc->nextbaseexp(sd); + len = packet_len(0xb1); break; case SP_NEXTJOBEXP: WFIFOW(fd,0)=0xb1; WFIFOL(fd,4)=pc->nextjobexp(sd); + len = packet_len(0xb1); break; /** @@ -3111,7 +3077,7 @@ void clif_updatestatus(struct map_session_data *sd,int type) case SP_ULUK: WFIFOW(fd,0)=0xbe; WFIFOB(fd,4)=pc->need_status_point(sd,type-SP_USTR+SP_STR,1); - len=5; + len = packet_len(0xbe); break; /** @@ -3120,7 +3086,7 @@ void clif_updatestatus(struct map_session_data *sd,int type) case SP_ATTACKRANGE: WFIFOW(fd,0)=0x13a; WFIFOW(fd,2)=sd->battle_status.rhw.range; - len=4; + len = packet_len(0x13a); break; case SP_STR: @@ -3128,42 +3094,42 @@ void clif_updatestatus(struct map_session_data *sd,int type) WFIFOL(fd,2)=type; WFIFOL(fd,6)=sd->status.str; WFIFOL(fd,10)=sd->battle_status.str - sd->status.str; - len=14; + len = packet_len(0x141); break; case SP_AGI: WFIFOW(fd,0)=0x141; WFIFOL(fd,2)=type; WFIFOL(fd,6)=sd->status.agi; WFIFOL(fd,10)=sd->battle_status.agi - sd->status.agi; - len=14; + len = packet_len(0x141); break; case SP_VIT: WFIFOW(fd,0)=0x141; WFIFOL(fd,2)=type; WFIFOL(fd,6)=sd->status.vit; WFIFOL(fd,10)=sd->battle_status.vit - sd->status.vit; - len=14; + len = packet_len(0x141); break; case SP_INT: WFIFOW(fd,0)=0x141; WFIFOL(fd,2)=type; WFIFOL(fd,6)=sd->status.int_; WFIFOL(fd,10)=sd->battle_status.int_ - sd->status.int_; - len=14; + len = packet_len(0x141); break; case SP_DEX: WFIFOW(fd,0)=0x141; WFIFOL(fd,2)=type; WFIFOL(fd,6)=sd->status.dex; WFIFOL(fd,10)=sd->battle_status.dex - sd->status.dex; - len=14; + len = packet_len(0x141); break; case SP_LUK: WFIFOW(fd,0)=0x141; WFIFOL(fd,2)=type; WFIFOL(fd,6)=sd->status.luk; WFIFOL(fd,10)=sd->battle_status.luk - sd->status.luk; - len=14; + len = packet_len(0x141); break; case SP_CARTINFO: @@ -3172,7 +3138,7 @@ void clif_updatestatus(struct map_session_data *sd,int type) WFIFOW(fd,4)=MAX_CART; WFIFOL(fd,6)=sd->cart_weight; WFIFOL(fd,10)=sd->cart_weight_max; - len=14; + len = packet_len(0x121); break; default: @@ -3182,7 +3148,6 @@ void clif_updatestatus(struct map_session_data *sd,int type) WFIFOSET(fd,len); } - /// Notifies client of a parameter change of an another player (ZC_PAR_CHANGE_USER). /// 01ab <account id>.L <var id>.W <value>.L void clif_changestatus(struct map_session_data* sd,int type,int val) @@ -3222,9 +3187,9 @@ void clif_changelook(struct block_list *bl,int type,int val) nullpo_retv(bl); sd = BL_CAST(BL_PC, bl); - sc = status_get_sc(bl); - vd = status_get_viewdata(bl); - //nullpo_ret(vd); + sc = status->get_sc(bl); + vd = status->get_viewdata(bl); + if( vd ) //temp hack to let Warp Portal change appearance switch(type) { case LOOK_WEAPON: @@ -3245,13 +3210,19 @@ void clif_changelook(struct block_list *bl,int type,int val) break; case LOOK_BASE: if( !sd ) break; - - if( sd->sc.option&(OPTION_WEDDING|OPTION_XMAS|OPTION_SUMMER|OPTION_HANBOK) ) + // We shouldn't update LOOK_BASE if the player is disguised + // if we do so the client will think that the player class + // is really a mob and issues like 7725 will happen in every + // SC_ that alters class_ in any way [Panikon] + if( sd->disguise != -1 ) + return; + + if( sd->sc.option&OPTION_COSTUME ) vd->weapon = vd->shield = 0; - + if( !vd->cloth_color ) break; - + if( sd ) { if( sd->sc.option&OPTION_WEDDING && battle_config.wedding_ignorepalette ) vd->cloth_color = 0; @@ -3261,6 +3232,8 @@ void clif_changelook(struct block_list *bl,int type,int val) vd->cloth_color = 0; if( sd->sc.option&OPTION_HANBOK && battle_config.hanbok_ignorepalette ) vd->cloth_color = 0; + if( sd->sc.option&OPTION_OKTOBERFEST /* TODO: config? */ ) + vd->cloth_color = 0; } break; case LOOK_HAIR: @@ -3288,6 +3261,8 @@ void clif_changelook(struct block_list *bl,int type,int val) val = 0; if( sd->sc.option&OPTION_HANBOK && battle_config.hanbok_ignorepalette ) val = 0; + if( sd->sc.option&OPTION_OKTOBERFEST /* TODO: config? */ ) + val = 0; } vd->cloth_color = val; break; @@ -3333,6 +3308,7 @@ void clif_changelook(struct block_list *bl,int type,int val) WBUFW(buf,0)=0x1d7; WBUFL(buf,2)=bl->id; if(type == LOOK_WEAPON || type == LOOK_SHIELD) { + nullpo_retv(vd); WBUFB(buf,6)=LOOK_WEAPON; WBUFW(buf,7)=vd->weapon; WBUFW(buf,9)=vd->shield; @@ -3341,7 +3317,7 @@ void clif_changelook(struct block_list *bl,int type,int val) WBUFL(buf,7)=val; } clif->send(buf,packet_len(0x1d7),bl,target); - if( disguised(bl) && ((TBL_PC*)sd)->fontcolor ) { + if( disguised(bl) && sd && sd->fontcolor ) { WBUFL(buf,2)=-bl->id; clif->send(buf,packet_len(0x1d7),bl,SELF); } @@ -3510,14 +3486,14 @@ void clif_arrow_create_list(struct map_session_data *sd) WFIFOW(fd,0) = 0x1ad; for (i = 0, c = 0; i < MAX_SKILL_ARROW_DB; i++) { - if (skill_arrow_db[i].nameid > 0 && - (j = pc->search_inventory(sd, skill_arrow_db[i].nameid)) >= 0 && - !sd->status.inventory[j].equip && sd->status.inventory[j].identify) - { - if ((j = itemdb_viewid(skill_arrow_db[i].nameid)) > 0) + if (skill->arrow_db[i].nameid > 0 + && (j = pc->search_inventory(sd, skill->arrow_db[i].nameid)) != INDEX_NOT_FOUND + && !sd->status.inventory[j].equip && sd->status.inventory[j].identify + ) { + if ((j = itemdb_viewid(skill->arrow_db[i].nameid)) > 0) WFIFOW(fd,c*2+4) = j; else - WFIFOW(fd,c*2+4) = skill_arrow_db[i].nameid; + WFIFOW(fd,c*2+4) = skill->arrow_db[i].nameid; c++; } } @@ -3556,52 +3532,39 @@ void clif_statusupack(struct map_session_data *sd,int type,int ok,int val) /// Notifies the client about the result of a request to equip an item (ZC_REQ_WEAR_EQUIP_ACK). /// 00aa <index>.W <equip location>.W <result>.B /// 00aa <index>.W <equip location>.W <view id>.W <result>.B (PACKETVER >= 20100629) -/// result: -/// 0 = failure -/// 1 = success -/// 2 = failure due to low level -void clif_equipitemack(struct map_session_data *sd,int n,int pos,int ok) -{ - int fd; +void clif_equipitemack(struct map_session_data *sd,int n,int pos,enum e_EQUIP_ITEM_ACK result) { + struct packet_equipitem_ack p; nullpo_retv(sd); - fd=sd->fd; - WFIFOHEAD(fd,packet_len(0xaa)); - WFIFOW(fd,0)=0xaa; - WFIFOW(fd,2)=n+2; - WFIFOW(fd,4)=pos; -#if PACKETVER < 20100629 - WFIFOB(fd,6)=ok; -#else - if (ok && sd->inventory_data[n]->equip&EQP_VISIBLE) - WFIFOW(fd,6)=sd->inventory_data[n]->look; + p.PacketType = equipitemackType; + p.index = n+2; + p.wearLocation = pos; +#if PACKETVER >= 20100629 + if (result == EIA_SUCCESS && sd->inventory_data[n]->equip&EQP_VISIBLE) + p.wItemSpriteNumber = sd->inventory_data[n]->look; else - WFIFOW(fd,6)=0; - WFIFOB(fd,8)=ok; + p.wItemSpriteNumber = 0; #endif - WFIFOSET(fd,packet_len(0xaa)); + p.result = (unsigned char)result; + + clif->send(&p, sizeof(p), &sd->bl, SELF); } /// Notifies the client about the result of a request to take off an item (ZC_REQ_TAKEOFF_EQUIP_ACK). /// 00ac <index>.W <equip location>.W <result>.B -/// result: -/// 0 = failure -/// 1 = success -void clif_unequipitemack(struct map_session_data *sd,int n,int pos,int ok) -{ - int fd; +void clif_unequipitemack(struct map_session_data *sd,int n,int pos,enum e_UNEQUIP_ITEM_ACK result) { + struct packet_unequipitem_ack p; nullpo_retv(sd); - fd=sd->fd; - WFIFOHEAD(fd,packet_len(0xac)); - WFIFOW(fd,0)=0xac; - WFIFOW(fd,2)=n+2; - WFIFOW(fd,4)=pos; - WFIFOB(fd,6)=ok; - WFIFOSET(fd,packet_len(0xac)); + p.PacketType = unequipitemackType; + p.index = n+2; + p.wearLocation = pos; + p.result = (unsigned char)result; + + clif->send(&p, sizeof(p), &sd->bl, SELF); } @@ -3642,9 +3605,9 @@ void clif_changeoption(struct block_list* bl) struct map_session_data* sd; nullpo_retv(bl); - - if ( !(sc = status_get_sc(bl)) && bl->type != BL_NPC ) return; //How can an option change if there's no sc? - + + if ( !(sc = status->get_sc(bl)) && bl->type != BL_NPC ) return; //How can an option change if there's no sc? + sd = BL_CAST(BL_PC, bl); #if PACKETVER >= 7 @@ -3689,7 +3652,7 @@ void clif_changeoption2(struct block_list* bl) { unsigned char buf[20]; struct status_change *sc; - if ( !(sc = status_get_sc(bl)) && bl->type != BL_NPC ) return; //How can an option change if there's no sc? + if ( !(sc = status->get_sc(bl)) && bl->type != BL_NPC ) return; //How can an option change if there's no sc? WBUFW(buf,0) = 0x28a; WBUFL(buf,2) = bl->id; @@ -3750,8 +3713,8 @@ void clif_useitemack(struct map_session_data *sd,int index,int amount,bool ok) } } -void clif_hercules_chsys_send(struct hChSysCh *channel, struct map_session_data *sd, char *msg) { - if( channel->msg_delay != 0 && DIFF_TICK(sd->hchsysch_tick + ( channel->msg_delay * 1000 ), iTimer->gettick()) > 0 && !pc_has_permission(sd, PC_PERM_HCHSYS_ADMIN) ) { +void clif_hercules_chsys_send(struct hChSysCh *channel, struct map_session_data *sd, const char *msg) { + if( channel->msg_delay != 0 && DIFF_TICK(sd->hchsysch_tick + ( channel->msg_delay * 1000 ), timer->gettick()) > 0 && !pc_has_permission(sd, PC_PERM_HCHSYS_ADMIN) ) { clif->colormes(sd->fd,COLOR_RED,msg_txt(1455)); return; } else { @@ -3761,7 +3724,7 @@ void clif_hercules_chsys_send(struct hChSysCh *channel, struct map_session_data if( channel->type == hChSys_IRC ) ircbot->relay(sd->status.name,msg); if( channel->msg_delay != 0 ) - sd->hchsysch_tick = iTimer->gettick(); + sd->hchsysch_tick = timer->gettick(); } } @@ -4004,8 +3967,7 @@ void clif_leavechat(struct chat_data* cd, struct map_session_data* sd, bool flag /// Opens a trade request window from char 'name'. /// 00e5 <nick>.24B (ZC_REQ_EXCHANGE_ITEM) /// 01f4 <nick>.24B <charid>.L <baselvl>.W (ZC_REQ_EXCHANGE_ITEM2) -void clif_traderequest(struct map_session_data* sd, const char* name) -{ +void clif_traderequest(struct map_session_data* sd, const char* name) { int fd = sd->fd; #if PACKETVER < 6 @@ -4013,8 +3975,8 @@ void clif_traderequest(struct map_session_data* sd, const char* name) WFIFOW(fd,0) = 0xe5; safestrncpy((char*)WFIFOP(fd,2), name, NAME_LENGTH); WFIFOSET(fd,packet_len(0xe5)); -#else - struct map_session_data* tsd = iMap->id2sd(sd->trade_partner); +#else // PACKETVER >= 6 + struct map_session_data* tsd = map->id2sd(sd->trade_partner); if( !tsd ) return; WFIFOHEAD(fd,packet_len(0x1f4)); @@ -4023,7 +3985,7 @@ void clif_traderequest(struct map_session_data* sd, const char* name) WFIFOL(fd,26) = tsd->status.char_id; WFIFOW(fd,30) = tsd->status.base_level; WFIFOSET(fd,packet_len(0x1f4)); -#endif +#endif // PACKETVER < 6 } @@ -4037,23 +3999,24 @@ void clif_traderequest(struct map_session_data* sd, const char* name) /// 3 = Accept /// 4 = Cancel /// 5 = Busy -void clif_tradestart(struct map_session_data* sd, uint8 type) -{ +void clif_tradestart(struct map_session_data* sd, uint8 type) { int fd = sd->fd; - struct map_session_data* tsd = iMap->id2sd(sd->trade_partner); - if( PACKETVER < 6 || !tsd ) { - WFIFOHEAD(fd,packet_len(0xe7)); - WFIFOW(fd,0) = 0xe7; - WFIFOB(fd,2) = type; - WFIFOSET(fd,packet_len(0xe7)); - } else { +#if PACKETVER >= 6 + struct map_session_data* tsd = map->id2sd(sd->trade_partner); + if( tsd ) { WFIFOHEAD(fd,packet_len(0x1f5)); WFIFOW(fd,0) = 0x1f5; WFIFOB(fd,2) = type; WFIFOL(fd,3) = tsd->status.char_id; WFIFOW(fd,7) = tsd->status.base_level; WFIFOSET(fd,packet_len(0x1f5)); + return; } +#endif // PACKETVER >= 6 + WFIFOHEAD(fd,packet_len(0xe7)); + WFIFOW(fd,0) = 0xe7; + WFIFOB(fd,2) = type; + WFIFOSET(fd,packet_len(0xe7)); } @@ -4252,7 +4215,7 @@ void clif_storageitemadded(struct map_session_data* sd, struct item* i, int inde WFIFOW(fd, 2) = index+1; // index WFIFOL(fd, 4) = amount; // amount WFIFOW(fd, 8) = ( view > 0 ) ? view : i->nameid; // id - WFIFOB(fd,10) = itemdb_type(i->nameid); //type + WFIFOB(fd,10) = itemtype(itemdb_type(i->nameid)); //type WFIFOB(fd,11) = i->identify; //identify flag WFIFOB(fd,12) = i->attribute; // attribute WFIFOB(fd,13) = i->refine; //refine @@ -4302,7 +4265,7 @@ void clif_getareachar_pc(struct map_session_data* sd,struct map_session_data* ds if( dstsd->chatID ) { struct chat_data *cd = NULL; - if( (cd = (struct chat_data*)iMap->id2bl(dstsd->chatID)) && cd->usersd[0]==dstsd) + if( (cd = (struct chat_data*)map->id2bl(dstsd->chatID)) && cd->usersd[0]==dstsd) clif->dispchat(cd,sd->fd); } else if( dstsd->state.vending ) clif->showvendingboard(&dstsd->bl,dstsd->message,sd->fd); @@ -4316,7 +4279,7 @@ void clif_getareachar_pc(struct map_session_data* sd,struct map_session_data* ds clif->charm_single(sd->fd, dstsd, i); } for( i = 0; i < dstsd->sc_display_count; i++ ) { - clif->sc_load(&sd->bl,dstsd->bl.id,SELF,StatusIconChangeTable[dstsd->sc_display[i]->type],dstsd->sc_display[i]->val1,dstsd->sc_display[i]->val2,dstsd->sc_display[i]->val3); + clif->sc_load(&sd->bl,dstsd->bl.id,SELF,status->IconChangeTable[dstsd->sc_display[i]->type],dstsd->sc_display[i]->val1,dstsd->sc_display[i]->val2,dstsd->sc_display[i]->val3); } if( (sd->status.party_id && dstsd->status.party_id == sd->status.party_id) || //Party-mate, or hpdisp setting. (sd->bg_id && sd->bg_id == dstsd->bg_id) || //BattleGround @@ -4331,7 +4294,7 @@ void clif_getareachar_pc(struct map_session_data* sd,struct map_session_data* ds ARR_FIND( 0, 5, i, dstsd->devotion[i] > 0 ); if( i < 5 ) clif->devotion(&dstsd->bl, sd); // display link (dstsd - crusader) to sd - if( dstsd->sc.data[SC_DEVOTION] && (d_bl = iMap->id2bl(dstsd->sc.data[SC_DEVOTION]->val1)) != NULL ) + if( dstsd->sc.data[SC_DEVOTION] && (d_bl = map->id2bl(dstsd->sc.data[SC_DEVOTION]->val1)) != NULL ) clif->devotion(d_bl, sd); } @@ -4339,7 +4302,7 @@ void clif_getareachar_unit(struct map_session_data* sd,struct block_list *bl) { struct unit_data *ud; struct view_data *vd; - vd = status_get_viewdata(bl); + vd = status->get_viewdata(bl); if (!vd || vd->class_ == INVISIBLE_CLASS) return; @@ -4349,7 +4312,7 @@ void clif_getareachar_unit(struct map_session_data* sd,struct block_list *bl) { if(bl->type == BL_NPC && !((TBL_NPC*)bl)->chat_id && (((TBL_NPC*)bl)->option&OPTION_INVISIBLE)) return; - if ( ( ud = unit_bl2ud(bl) ) && ud->walktimer != INVALID_TIMER ) + if ( ( ud = unit->bl2ud(bl) ) && ud->walktimer != INVALID_TIMER ) clif->set_unit_walking(bl,sd,ud,SELF); else clif->set_unit_idle(bl,sd,SELF); @@ -4363,9 +4326,9 @@ void clif_getareachar_unit(struct map_session_data* sd,struct block_list *bl) { clif->getareachar_pc(sd, tsd); if(tsd->state.size==SZ_BIG) // tiny/big players [Valaris] clif->specialeffect_single(bl,423,sd->fd); - else if(tsd->state.size==SZ_MEDIUM) + else if(tsd->state.size==SZ_SMALL) clif->specialeffect_single(bl,421,sd->fd); - if( tsd->bg_id && map[tsd->bl.m].flag.battleground ) + if( tsd->bg_id && map->list[tsd->bl.m].flag.battleground ) clif->sendbgemblem_single(sd->fd,tsd); if ( tsd->status.robe ) clif->refreshlook(&sd->bl,bl->id,LOOK_ROBE,tsd->status.robe,SELF); @@ -4379,10 +4342,10 @@ void clif_getareachar_unit(struct map_session_data* sd,struct block_list *bl) { { TBL_NPC* nd = (TBL_NPC*)bl; if( nd->chat_id ) - clif->dispchat((struct chat_data*)iMap->id2bl(nd->chat_id),sd->fd); + clif->dispchat((struct chat_data*)map->id2bl(nd->chat_id),sd->fd); if( nd->size == SZ_BIG ) clif->specialeffect_single(bl,423,sd->fd); - else if( nd->size == SZ_MEDIUM ) + else if( nd->size == SZ_SMALL ) clif->specialeffect_single(bl,421,sd->fd); } break; @@ -4391,7 +4354,7 @@ void clif_getareachar_unit(struct map_session_data* sd,struct block_list *bl) { TBL_MOB* md = (TBL_MOB*)bl; if(md->special_state.size==SZ_BIG) // tiny/big mobs [Valaris] clif->specialeffect_single(bl,423,sd->fd); - else if(md->special_state.size==SZ_MEDIUM) + else if(md->special_state.size==SZ_SMALL) clif->specialeffect_single(bl,421,sd->fd); #if PACKETVER >= 20120404 if( !(md->status.mode&MD_BOSS) ){ @@ -4458,79 +4421,74 @@ int clif_calc_walkdelay(struct block_list *bl,int delay, int type, int damage, i /// 10 = critical hit /// 11 = lucky dodge /// 12 = (touch skill?) -int clif_damage(struct block_list* src, struct block_list* dst, unsigned int tick, int sdelay, int ddelay, int damage, int div, int type, int damage2) -{ - unsigned char buf[33]; +int clif_damage(struct block_list* src, struct block_list* dst, int sdelay, int ddelay, int64 in_damage, short div, unsigned char type, int64 in_damage2) { + struct packet_damage p; struct status_change *sc; #if PACKETVER < 20071113 - const int cmd = 0x8a; + short damage,damage2; #else - const int cmd = 0x2e1; + int damage,damage2; #endif nullpo_ret(src); nullpo_ret(dst); - type = clif_calc_delay(type,div,damage+damage2,ddelay); - sc = status_get_sc(dst); - if(sc && sc->count) { - if(sc->data[SC_ILLUSION]) { - if(damage) damage = damage*(sc->data[SC_ILLUSION]->val2) + rnd()%100; - if(damage2) damage2 = damage2*(sc->data[SC_ILLUSION]->val2) + rnd()%100; - } - } + sc = status->get_sc(dst); - WBUFW(buf,0)=cmd; - WBUFL(buf,2)=src->id; - WBUFL(buf,6)=dst->id; - WBUFL(buf,10)=tick; - WBUFL(buf,14)=sdelay; - WBUFL(buf,18)=ddelay; -#if PACKETVER < 20071113 - if (battle_config.hide_woe_damage && map_flag_gvg(src->m)) { - WBUFW(buf,22)=damage?div:0; - WBUFW(buf,27)=damage2?div:0; - } else { - WBUFW(buf,22)=min(damage, INT16_MAX); - WBUFW(buf,27)=damage2; + if(sc && sc->count && sc->data[SC_ILLUSION]) { + if(in_damage) in_damage = in_damage*(sc->data[SC_ILLUSION]->val2) + rnd()%100; + if(in_damage2) in_damage2 = in_damage2*(sc->data[SC_ILLUSION]->val2) + rnd()%100; } - WBUFW(buf,24)=div; - WBUFB(buf,26)=type; + +#if PACKETVER < 20071113 + damage = (short)min(in_damage,INT16_MAX); + damage2 = (short)min(in_damage2,INT16_MAX); #else - if (battle_config.hide_woe_damage && map_flag_gvg(src->m)) { - WBUFL(buf,22)=damage?div:0; - WBUFL(buf,29)=damage2?div:0; + damage = (int)min(in_damage,INT_MAX); + damage2 = (int)min(in_damage2,INT_MAX); +#endif + + type = clif_calc_delay(type,div,damage+damage2,ddelay); + + p.PacketType = damageType; + p.GID = src->id; + p.targetGID = dst->id; + p.startTime = (uint32)timer->gettick(); + p.attackMT = sdelay; + p.attackedMT = ddelay; + p.count = div; + p.action = type; + + if( battle_config.hide_woe_damage && map_flag_gvg2(src->m) ) { + p.damage = damage?div:0; + p.leftDamage = damage2?div:0; } else { - WBUFL(buf,22)=damage; - WBUFL(buf,29)=damage2; + p.damage = damage; + p.leftDamage = damage2; } - WBUFW(buf,26)=div; - WBUFB(buf,28)=type; -#endif + if(disguised(dst)) { - clif->send(buf,packet_len(cmd),dst,AREA_WOS); - WBUFL(buf,6) = -dst->id; - clif->send(buf,packet_len(cmd),dst,SELF); + clif->send(&p,sizeof(p),dst,AREA_WOS); + p.targetGID = -dst->id; + clif->send(&p,sizeof(p),dst,SELF); } else - clif->send(buf,packet_len(cmd),dst,AREA); + clif->send(&p,sizeof(p),dst,AREA); if(disguised(src)) { - WBUFL(buf,2) = -src->id; + p.GID = -src->id; if (disguised(dst)) - WBUFL(buf,6) = dst->id; -#if PACKETVER < 20071113 - if(damage > 0) WBUFW(buf,22) = -1; - if(damage2 > 0) WBUFW(buf,27) = -1; -#else - if(damage > 0) WBUFL(buf,22) = -1; - if(damage2 > 0) WBUFL(buf,29) = -1; -#endif - clif->send(buf,packet_len(cmd),src,SELF); + p.targetGID = dst->id; + + if(damage > 0) p.damage = -1; + if(damage2 > 0) p.leftDamage = -1; + + clif->send(&p,sizeof(p),src,SELF); } if(src == dst) { - unit_setdir(src,unit_getdir(src)); + unit->setdir(src,unit->getdir(src)); } + //Return adjusted can't walk delay for further processing. return clif->calc_walkdelay(dst,ddelay,type,damage+damage2,div); } @@ -4540,7 +4498,7 @@ int clif_damage(struct block_list* src, struct block_list* dst, unsigned int tic *------------------------------------------*/ void clif_takeitem(struct block_list* src, struct block_list* dst) { - //clif_damage(src,dst,0,0,0,0,0,1,0); + //clif->damage(src,dst,0,0,0,0,1,0); unsigned char buf[32]; nullpo_retv(src); @@ -4595,15 +4553,14 @@ void clif_standing(struct block_list* bl) /// Inform client(s) about a map-cell change (ZC_UPDATE_MAPINFO). /// 0192 <x>.W <y>.W <type>.W <map name>.16B -void clif_changemapcell(int fd, int16 m, int x, int y, int type, enum send_target target) -{ +void clif_changemapcell(int fd, int16 m, int x, int y, int type, enum send_target target) { unsigned char buf[32]; WBUFW(buf,0) = 0x192; WBUFW(buf,2) = x; WBUFW(buf,4) = y; WBUFW(buf,6) = type; - mapindex_getmapname_ext(map[m].cName ? map[m].cName : map[m].name,(char*)WBUFP(buf,8)); + mapindex->getmapname_ext(map->list[m].custom_name ? map->list[map->list[m].instance_src_map].name : map->list[m].name,(char*)WBUFP(buf,8)); if( fd ) { WFIFOHEAD(fd,packet_len(0x192)); @@ -4642,94 +4599,103 @@ void clif_getareachar_item(struct map_session_data* sd,struct flooritem_data* fi WFIFOSET(fd,packet_len(0x9d)); } +void clif_graffiti_entry(struct block_list *bl, struct skill_unit *su, enum send_target target) { + struct packet_graffiti_entry p; + + p.PacketType = graffiti_entryType; + p.AID = su->bl.id; + p.creatorAID = su->group->src_id; + p.xPos = su->bl.x; + p.yPos = su->bl.y; + p.job = su->group->unit_id; + p.isContens = 1; + p.isVisible = 1; + safestrncpy(p.msg, su->group->valstr, 80); + + clif->send(&p,sizeof(p),bl,target); +} /// Notifies the client of a skill unit. /// 011f <id>.L <creator id>.L <x>.W <y>.W <unit id>.B <visible>.B (ZC_SKILL_ENTRY) /// 01c9 <id>.L <creator id>.L <x>.W <y>.W <unit id>.B <visible>.B <has msg>.B <msg>.80B (ZC_SKILL_ENTRY2) /// 08c7 <lenght>.W <id> L <creator id>.L <x>.W <y>.W <unit id>.B <range>.W <visible>.B (ZC_SKILL_ENTRY3) /// 099f <lenght>.W <id> L <creator id>.L <x>.W <y>.W <unit id>.L <range>.W <visible>.B (ZC_SKILL_ENTRY4) -void clif_getareachar_skillunit(struct map_session_data *sd, struct skill_unit *unit) { - int fd = sd->fd, header = 0x11f, pos=0; +void clif_getareachar_skillunit(struct block_list *bl, struct skill_unit *su, enum send_target target) { + struct packet_skill_entry p; + nullpo_retv(bl); + nullpo_retv(su); - if( unit->group->state.guildaura ) + if( su->group->state.guildaura ) return; -#if PACKETVER >= 20130320 - if(unit->group->unit_id > UCHAR_MAX){ - header = 0x99f; - pos = 2; - } -#endif - #if PACKETVER >= 3 - if(unit->group->unit_id==UNT_GRAFFITI) { // Graffiti [Valaris] - WFIFOHEAD(fd,packet_len(0x1c9)); - WFIFOW(fd, 0)=0x1c9; - WFIFOL(fd, 2)=unit->bl.id; - WFIFOL(fd, 6)=unit->group->src_id; - WFIFOW(fd,10)=unit->bl.x; - WFIFOW(fd,12)=unit->bl.y; - WFIFOB(fd,14)=unit->group->unit_id; - WFIFOB(fd,15)=1; - WFIFOB(fd,16)=1; - safestrncpy((char*)WFIFOP(fd,17),unit->group->valstr,MESSAGE_SIZE); - WFIFOSET(fd,packet_len(0x1c9)); + if(su->group->unit_id == UNT_GRAFFITI) { + clif->graffiti_entry(bl,su,target); return; } #endif - WFIFOHEAD(fd,packet_len(header)); - WFIFOW(fd, 0)=header; - if(pos > 0) - WFIFOL(fd, pos)=packet_len(header); - WFIFOL(fd, 2 + pos)=unit->bl.id; - WFIFOL(fd, 6 + pos)=unit->group->src_id; - WFIFOW(fd,10 + pos)=unit->bl.x; - WFIFOW(fd,12 + pos)=unit->bl.y; - if (battle_config.traps_setting&1 && skill->get_inf2(unit->group->skill_id)&INF2_TRAP) - WFIFOB(fd,14)=UNT_DUMMYSKILL; //Use invisible unit id for traps. - else if (skill->get_unit_flag(unit->group->skill_id) & UF_RANGEDSINGLEUNIT && !(unit->val2 & UF_RANGEDSINGLEUNIT)) - WFIFOB(fd,14)=UNT_DUMMYSKILL; //Use invisible unit id for traps. - else if(pos > 0){ - WFIFOL(fd,16)=unit->group->unit_id; - WFIFOW(fd,20)=unit->range; - pos += 5; - }else - WFIFOB(fd,14)=unit->group->unit_id; - WFIFOB(fd,15 + pos)=1; // ignored by client (always gets set to 1) - WFIFOSET(fd,packet_len(header)); - if(unit->group->skill_id == WZ_ICEWALL) - clif->changemapcell(fd,unit->bl.m,unit->bl.x,unit->bl.y,5,SELF); + p.PacketType = skill_entryType; + +#if PACKETVER >= 20110718 + p.PacketLength = sizeof(p); +#endif + + p.AID = su->bl.id; + p.creatorAID = su->group->src_id; + p.xPos = su->bl.x; + p.yPos = su->bl.y; + + //Use invisible unit id for traps. + if ((battle_config.traps_setting&1 && skill->get_inf2(su->group->skill_id)&INF2_TRAP) || + (skill->get_unit_flag(su->group->skill_id) & UF_RANGEDSINGLEUNIT && !(su->val2 & UF_RANGEDSINGLEUNIT))) + p.job = UNT_DUMMYSKILL; + else + p.job = su->group->unit_id; + +#if PACKETVER >= 20110718 + p.RadiusRange = (unsigned char)su->range; +#endif + + p.isVisible = 1; + +#if PACKETVER >= 20130731 + p.level = (unsigned char)su->group->skill_lv; +#endif + + clif->send(&p,sizeof(p),bl,target); + + if(su->group->skill_id == WZ_ICEWALL) + clif->changemapcell(bl->type == BL_PC ? ((TBL_PC*)bl)->fd : 0,su->bl.m,su->bl.x,su->bl.y,5,SELF); } /*========================================== * Server tells client to remove unit of id 'unit->bl.id' *------------------------------------------*/ -void clif_clearchar_skillunit(struct skill_unit *unit, int fd) { - nullpo_retv(unit); +void clif_clearchar_skillunit(struct skill_unit *su, int fd) { + nullpo_retv(su); WFIFOHEAD(fd,packet_len(0x120)); WFIFOW(fd, 0)=0x120; - WFIFOL(fd, 2)=unit->bl.id; + WFIFOL(fd, 2)=su->bl.id; WFIFOSET(fd,packet_len(0x120)); - if(unit->group && unit->group->skill_id == WZ_ICEWALL) - clif->changemapcell(fd,unit->bl.m,unit->bl.x,unit->bl.y,unit->val2,SELF); + if(su->group && su->group->skill_id == WZ_ICEWALL) + clif->changemapcell(fd,su->bl.m,su->bl.x,su->bl.y,su->val2,SELF); } /// Removes a skill unit (ZC_SKILL_DISAPPEAR). /// 0120 <id>.L -void clif_skill_delunit(struct skill_unit *unit) -{ +void clif_skill_delunit(struct skill_unit *su) { unsigned char buf[16]; - nullpo_retv(unit); + nullpo_retv(su); WBUFW(buf, 0)=0x120; - WBUFL(buf, 2)=unit->bl.id; - clif->send(buf,packet_len(0x120),&unit->bl,AREA); + WBUFL(buf, 2)=su->bl.id; + clif->send(buf,packet_len(0x120),&su->bl,AREA); } @@ -4766,7 +4732,7 @@ int clif_getareachar(struct block_list* bl,va_list ap) { clif->getareachar_item(sd,(struct flooritem_data*) bl); break; case BL_SKILL: - clif->getareachar_skillunit(sd,(TBL_SKILL*)bl); + clif->getareachar_skillunit(&sd->bl,(TBL_SKILL*)bl,SELF); break; default: if(&sd->bl == bl) @@ -4791,13 +4757,14 @@ int clif_outsight(struct block_list *bl,va_list ap) tsd = BL_CAST(BL_PC, tbl); if (tsd && tsd->fd) { //tsd has lost sight of the bl object. + nullpo_ret(bl); switch(bl->type){ 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; - cd=(struct chat_data*)iMap->id2bl(sd->chatID); + cd=(struct chat_data*)map->id2bl(sd->chatID); if(cd->usersd[0]==sd) clif->dispchat(cd,tsd->fd); } @@ -4817,13 +4784,14 @@ int clif_outsight(struct block_list *bl,va_list ap) clif->clearunit_single(bl->id,CLR_OUTSIGHT,tsd->fd); break; default: - if ((vd=status_get_viewdata(bl)) && vd->class_ != INVISIBLE_CLASS) + if ((vd=status->get_viewdata(bl)) && vd->class_ != INVISIBLE_CLASS) clif->clearunit_single(bl->id,CLR_OUTSIGHT,tsd->fd); break; } } if (sd && sd->fd) { //sd is watching tbl go out of view. - if (((vd=status_get_viewdata(tbl)) && vd->class_ != INVISIBLE_CLASS) && + nullpo_ret(tbl); + if (((vd=status->get_viewdata(tbl)) && vd->class_ != INVISIBLE_CLASS) && !(tbl->type == BL_NPC && (((TBL_NPC*)tbl)->option&OPTION_INVISIBLE))) clif->clearunit_single(tbl->id,CLR_OUTSIGHT,sd->fd); } @@ -4845,12 +4813,13 @@ int clif_insight(struct block_list *bl,va_list ap) tsd = BL_CAST(BL_PC, tbl); if (tsd && tsd->fd) { //Tell tsd that bl entered into his view - switch(bl->type){ + nullpo_ret(bl); + switch(bl->type) { case BL_ITEM: clif->getareachar_item(tsd,(struct flooritem_data*)bl); break; case BL_SKILL: - clif->getareachar_skillunit(tsd,(TBL_SKILL*)bl); + clif->getareachar_skillunit(&tsd->bl,(TBL_SKILL*)bl,SELF); break; default: clif->getareachar_unit(tsd,bl); @@ -4961,23 +4930,31 @@ void clif_deleteskill(struct map_session_data *sd, int id) clif->skillinfoblock(sd); } - /// Updates a skill in the skill tree (ZC_SKILLINFO_UPDATE). /// 010e <skill id>.W <level>.W <sp cost>.W <attack range>.W <upgradable>.B -void clif_skillup(struct map_session_data *sd,uint16 skill_id) { - int fd, idx = skill->get_index(skill_id); - +/// Merged clif_skillup and clif_guild_skillup, same packet was used [panikon] +/// flag: +/// 0: guild call +/// 1: player call +void clif_skillup(struct map_session_data *sd, uint16 skill_id, int skill_lv, int flag) +{ + int fd; nullpo_retv(sd); - fd=sd->fd; - WFIFOHEAD(fd,packet_len(0x10e)); - WFIFOW(fd,0) = 0x10e; - WFIFOW(fd,2) = skill_id; - WFIFOW(fd,4) = sd->status.skill[idx].lv; - WFIFOW(fd,6) = skill->get_sp(skill_id,sd->status.skill[idx].lv); - WFIFOW(fd,8) = skill->get_range2(&sd->bl,skill_id,sd->status.skill[idx].lv); - WFIFOB(fd,10) = (sd->status.skill[idx].lv < skill->tree_get_max(sd->status.skill[idx].id, sd->status.class_)) ? 1 : 0; - WFIFOSET(fd,packet_len(0x10e)); + fd = sd->fd; + + WFIFOHEAD(fd, packet_len(0x10e)); + WFIFOW(fd, 0) = 0x10e; + WFIFOW(fd, 2) = skill_id; + WFIFOW(fd, 4) = skill_lv; + WFIFOW(fd, 6) = skill->get_sp(skill_id, skill_lv); + WFIFOW(fd, 8) = (flag)?skill->get_range2(&sd->bl, skill_id, skill_lv) : skill->get_range(skill_id, skill_lv); + if( flag ) + WFIFOB(fd,10) = (skill_lv < skill->tree_get_max(skill_id, sd->status.class_)) ? 1 : 0; + else + WFIFOB(fd,10) = 1; + + WFIFOSET(fd, packet_len(0x10e)); } @@ -5072,7 +5049,7 @@ void clif_skillcastcancel(struct block_list* bl) /// 4 = "no party" MsgStringTable[163] /// 5 = "no shout" MsgStringTable[164] /// 6 = "no PKing" MsgStringTable[165] -/// 7 = "no alligning" MsgStringTable[383] +/// 7 = "no aligning" MsgStringTable[383] /// ? = ignored /// cause: /// 0 = "not enough skill level" MsgStringTable[214] (AL_WARP) @@ -5121,7 +5098,7 @@ void clif_skill_fail(struct map_session_data *sd,uint16 skill_id,enum useskill_f /// Skill cooldown display icon (ZC_SKILL_POSTDELAY). /// 043d <skill ID>.W <tick>.L -void clif_skill_cooldown(struct map_session_data *sd, uint16 skill_id, unsigned int tick) +void clif_skill_cooldown(struct map_session_data *sd, uint16 skill_id, unsigned int duration) { #if PACKETVER>=20081112 int fd; @@ -5132,7 +5109,7 @@ void clif_skill_cooldown(struct map_session_data *sd, uint16 skill_id, unsigned WFIFOHEAD(fd,packet_len(0x43d)); WFIFOW(fd,0) = 0x43d; WFIFOW(fd,2) = skill_id; - WFIFOL(fd,4) = tick; + WFIFOL(fd,4) = duration; WFIFOSET(fd,packet_len(0x43d)); #endif } @@ -5141,16 +5118,17 @@ void clif_skill_cooldown(struct map_session_data *sd, uint16 skill_id, unsigned /// Skill attack effect and damage. /// 0114 <skill id>.W <src id>.L <dst id>.L <tick>.L <src delay>.L <dst delay>.L <damage>.W <level>.W <div>.W <type>.B (ZC_NOTIFY_SKILL) /// 01de <skill id>.W <src id>.L <dst id>.L <tick>.L <src delay>.L <dst delay>.L <damage>.L <level>.W <div>.W <type>.B (ZC_NOTIFY_SKILL2) -int clif_skill_damage(struct block_list *src,struct block_list *dst,unsigned int tick,int sdelay,int ddelay,int damage,int div,uint16 skill_id,uint16 skill_lv,int type) -{ +int clif_skill_damage(struct block_list *src, struct block_list *dst, int64 tick, int sdelay, int ddelay, int64 in_damage, int div, uint16 skill_id, uint16 skill_lv, int type) { unsigned char buf[64]; struct status_change *sc; + int damage; nullpo_ret(src); nullpo_ret(dst); + damage = (int)cap_value(in_damage,INT_MIN,INT_MAX); type = clif_calc_delay(type,div,damage,ddelay); - sc = status_get_sc(dst); + sc = status->get_sc(dst); if(sc && sc->count) { if(sc->data[SC_ILLUSION] && damage) damage = damage*(sc->data[SC_ILLUSION]->val2) + rnd()%100; @@ -5161,10 +5139,10 @@ int clif_skill_damage(struct block_list *src,struct block_list *dst,unsigned int WBUFW(buf,2)=skill_id; WBUFL(buf,4)=src->id; WBUFL(buf,8)=dst->id; - WBUFL(buf,12)=tick; + WBUFL(buf,12)=(uint32)tick; WBUFL(buf,16)=sdelay; WBUFL(buf,20)=ddelay; - if (battle_config.hide_woe_damage && map_flag_gvg(src->m)) { + if (battle_config.hide_woe_damage && map_flag_gvg2(src->m)) { WBUFW(buf,24)=damage?div:0; } else { WBUFW(buf,24)=damage; @@ -5192,10 +5170,10 @@ int clif_skill_damage(struct block_list *src,struct block_list *dst,unsigned int WBUFW(buf,2)=skill_id; WBUFL(buf,4)=src->id; WBUFL(buf,8)=dst->id; - WBUFL(buf,12)=tick; + WBUFL(buf,12)=(uint32)tick; WBUFL(buf,16)=sdelay; WBUFL(buf,20)=ddelay; - if (battle_config.hide_woe_damage && map_flag_gvg(src->m)) { + if (battle_config.hide_woe_damage && map_flag_gvg2(src->m)) { WBUFL(buf,24)=damage?div:0; } else { WBUFL(buf,24)=damage; @@ -5227,9 +5205,8 @@ int clif_skill_damage(struct block_list *src,struct block_list *dst,unsigned int /// Ground skill attack effect and damage (ZC_NOTIFY_SKILL_POSITION). /// 0115 <skill id>.W <src id>.L <dst id>.L <tick>.L <src delay>.L <dst delay>.L <x>.W <y>.W <damage>.W <level>.W <div>.W <type>.B -/* -int clif_skill_damage2(struct block_list *src,struct block_list *dst,unsigned int tick,int sdelay,int ddelay,int damage,int div,uint16 skill_id,uint16 skill_lv,int type) -{ +#if 0 +int clif_skill_damage2(struct block_list *src, struct block_list *dst, int64 tick, int sdelay, int ddelay, int damage, int div, uint16 skill_id, uint16 skill_lv, int type) { unsigned char buf[64]; struct status_change *sc; @@ -5238,7 +5215,7 @@ int clif_skill_damage2(struct block_list *src,struct block_list *dst,unsigned in type = (type>0)?type:skill_get_hit(skill_id); type = clif_calc_delay(type,div,damage,ddelay); - sc = status_get_sc(dst); + sc = status->get_sc(dst); if(sc && sc->count) { if(sc->data[SC_ILLUSION] && damage) @@ -5249,7 +5226,7 @@ int clif_skill_damage2(struct block_list *src,struct block_list *dst,unsigned in WBUFW(buf,2)=skill_id; WBUFL(buf,4)=src->id; WBUFL(buf,8)=dst->id; - WBUFL(buf,12)=tick; + WBUFL(buf,12)=(uint32)tick; WBUFL(buf,16)=sdelay; WBUFL(buf,20)=ddelay; WBUFW(buf,24)=dst->x; @@ -5281,7 +5258,7 @@ int clif_skill_damage2(struct block_list *src,struct block_list *dst,unsigned in //Because the damage delay must be synced with the client, here is where the can-walk tick must be updated. [Skotlex] return clif_calc_walkdelay(dst,ddelay,type,damage,div); } -*/ +#endif // 0 /// Non-damaging skill effect (ZC_USE_SKILL). @@ -5319,8 +5296,7 @@ int clif_skill_nodamage(struct block_list *src,struct block_list *dst,uint16 ski /// Non-damaging ground skill effect (ZC_NOTIFY_GROUNDSKILL). /// 0117 <skill id>.W <src id>.L <level>.W <x>.W <y>.W <tick>.L -void clif_skill_poseffect(struct block_list *src,uint16 skill_id,int val,int x,int y,int tick) -{ +void clif_skill_poseffect(struct block_list *src, uint16 skill_id, int val, int x, int y, int64 tick) { unsigned char buf[32]; nullpo_retv(src); @@ -5331,7 +5307,7 @@ void clif_skill_poseffect(struct block_list *src,uint16 skill_id,int val,int x,i WBUFW(buf,8)=val; WBUFW(buf,10)=x; WBUFW(buf,12)=y; - WBUFL(buf,14)=tick; + WBUFL(buf,14)=(uint32)tick; if(disguised(src)) { clif->send(buf,packet_len(0x117),src,AREA_WOS); WBUFL(buf,4)=-src->id; @@ -5340,65 +5316,6 @@ void clif_skill_poseffect(struct block_list *src,uint16 skill_id,int val,int x,i clif->send(buf,packet_len(0x117),src,AREA); } - -/*========================================== - * Tells all client's nearby 'unit' sight range that it spawned - *------------------------------------------*/ -//FIXME: this is just an AREA version of clif_getareachar_skillunit() -void clif_skill_setunit(struct skill_unit *unit) -{ - unsigned char buf[128]; - int header = 0x11f, pos = 0; - - nullpo_retv(unit); - - if( unit->group->state.guildaura ) - return; - -#if PACKETVER >= 20130320 - if(unit->group->unit_id > UCHAR_MAX){ - header = 0x99f; - pos = 2; - } -#endif - -#if PACKETVER >= 3 - if(unit->group->unit_id==UNT_GRAFFITI) { // Graffiti [Valaris] - WBUFW(buf, 0)=0x1c9; - WBUFL(buf, 2)=unit->bl.id; - WBUFL(buf, 6)=unit->group->src_id; - WBUFW(buf,10)=unit->bl.x; - WBUFW(buf,12)=unit->bl.y; - WBUFB(buf,14)=unit->group->unit_id; - WBUFB(buf,15)=1; - WBUFB(buf,16)=1; - safestrncpy((char*)WBUFP(buf,17),unit->group->valstr,MESSAGE_SIZE); - clif->send(buf,packet_len(0x1c9),&unit->bl,AREA); - return; - } -#endif - WBUFW(buf, 0)=header; - if(pos > 0) - WBUFW(buf, pos)=packet_len(header); - WBUFL(buf, 2 + pos)=unit->bl.id; - WBUFL(buf, 6 + pos)=unit->group->src_id; - WBUFW(buf,10 + pos)=unit->bl.x; - WBUFW(buf,12 + pos)=unit->bl.y; - if (unit->group->state.song_dance&0x1 && unit->val2&UF_ENSEMBLE) - WBUFB(buf,14)=unit->val2&UF_SONG?UNT_DISSONANCE:UNT_UGLYDANCE; - else if (skill->get_unit_flag(unit->group->skill_id) & UF_RANGEDSINGLEUNIT && !(unit->val2 & UF_RANGEDSINGLEUNIT)) - WBUFB(buf, 14) = UNT_DUMMYSKILL; // Only display the unit at center. - else if(pos > 0){ - WBUFL(buf,16)=unit->group->unit_id; - WBUFW(buf,20)=unit->range; - pos += 5; - }else - WBUFB(buf,14)=unit->group->unit_id; - WBUFB(buf,15 + pos)=1; // ignored by client (always gets set to 1) - clif->send(buf,packet_len(header),&unit->bl,AREA); -} - - /// Presents a list of available warp destinations (ZC_WARPLIST). /// 011c <skill id>.W { <map name>.16B }*4 void clif_skill_warppoint(struct map_session_data* sd, uint16 skill_id, uint16 skill_lv, unsigned short map1, unsigned short map2, unsigned short map3, unsigned short map4) @@ -5413,10 +5330,10 @@ void clif_skill_warppoint(struct map_session_data* sd, uint16 skill_id, uint16 s memset(WFIFOP(fd,4), 0x00, 4*MAP_NAME_LENGTH_EXT); if (map1 == (unsigned short)-1) strcpy((char*)WFIFOP(fd,4), "Random"); else // normal map name - if (map1 > 0) mapindex_getmapname_ext(mapindex_id2name(map1), (char*)WFIFOP(fd,4)); - if (map2 > 0) mapindex_getmapname_ext(mapindex_id2name(map2), (char*)WFIFOP(fd,20)); - if (map3 > 0) mapindex_getmapname_ext(mapindex_id2name(map3), (char*)WFIFOP(fd,36)); - if (map4 > 0) mapindex_getmapname_ext(mapindex_id2name(map4), (char*)WFIFOP(fd,52)); + if (map1 > 0) mapindex->getmapname_ext(mapindex_id2name(map1), (char*)WFIFOP(fd,4)); + if (map2 > 0) mapindex->getmapname_ext(mapindex_id2name(map2), (char*)WFIFOP(fd,20)); + if (map3 > 0) mapindex->getmapname_ext(mapindex_id2name(map3), (char*)WFIFOP(fd,36)); + if (map4 > 0) mapindex->getmapname_ext(mapindex_id2name(map4), (char*)WFIFOP(fd,52)); WFIFOSET(fd,packet_len(0x11c)); sd->menuskill_id = skill_id; @@ -5477,9 +5394,8 @@ void clif_skill_mapinfomessage(struct map_session_data *sd, int type) /// Displays Sense (WZ_ESTIMATION) information window (ZC_MONSTER_INFO). /// 018c <class>.W <level>.W <size>.W <hp>.L <def>.W <race>.W <mdef>.W <element>.W /// <water%>.B <earth%>.B <fire%>.B <wind%>.B <poison%>.B <holy%>.B <shadow%>.B <ghost%>.B <undead%>.B -void clif_skill_estimation(struct map_session_data *sd,struct block_list *dst) -{ - struct status_data *status; +void clif_skill_estimation(struct map_session_data *sd,struct block_list *dst) { + struct status_data *dstatus; unsigned char buf[64]; int i;//, fix; @@ -5489,29 +5405,29 @@ void clif_skill_estimation(struct map_session_data *sd,struct block_list *dst) if( dst->type != BL_MOB ) return; - status = status_get_status_data(dst); + dstatus = status->get_status_data(dst); - WBUFW(buf, 0)=0x18c; - WBUFW(buf, 2)=status_get_class(dst); - WBUFW(buf, 4)=status_get_lv(dst); - WBUFW(buf, 6)=status->size; - WBUFL(buf, 8)=status->hp; - WBUFW(buf,12)= (battle_config.estimation_type&1?status->def:0) - +(battle_config.estimation_type&2?status->def2:0); - WBUFW(buf,14)=status->race; - WBUFW(buf,16)= (battle_config.estimation_type&1?status->mdef:0) - +(battle_config.estimation_type&2?status->mdef2:0); - WBUFW(buf,18)= status->def_ele; + WBUFW(buf, 0) = 0x18c; + WBUFW(buf, 2) = status->get_class(dst); + WBUFW(buf, 4) = status->get_lv(dst); + WBUFW(buf, 6) = dstatus->size; + WBUFL(buf, 8) = dstatus->hp; + WBUFW(buf,12) = (battle_config.estimation_type&1?dstatus->def:0) + + (battle_config.estimation_type&2?dstatus->def2:0); + WBUFW(buf,14) = dstatus->race; + WBUFW(buf,16) = (battle_config.estimation_type&1?dstatus->mdef:0) + + (battle_config.estimation_type&2?dstatus->mdef2:0); + WBUFW(buf,18) = dstatus->def_ele; for(i=0;i<9;i++) - WBUFB(buf,20+i)= (unsigned char)battle->attr_ratio(i+1,status->def_ele, status->ele_lv); + WBUFB(buf,20+i)= (unsigned char)battle->attr_ratio(i+1,dstatus->def_ele, dstatus->ele_lv); // The following caps negative attributes to 0 since the client displays them as 255-fix. [Skotlex] -// WBUFB(buf,20+i)= (unsigned char)((fix=battle_attr_ratio(i+1,status->def_ele, status->ele_lv))<0?0:fix); +// WBUFB(buf,20+i)= (unsigned char)((fix=battle_attr_ratio(i+1,dstatus->def_ele, dstatus->ele_lv))<0?0:fix); clif->send(buf,packet_len(0x18c),&sd->bl,sd->status.party_id>0?PARTY_SAMEMAP:SELF); } -/// Presents a textual list of producable items (ZC_MAKABLEITEMLIST). +/// Presents a textual list of producible items (ZC_MAKABLEITEMLIST). /// 018d <packet len>.W { <name id>.W { <material id>.W }*3 }* /// material id: /// unused by the client @@ -5530,13 +5446,13 @@ void clif_skill_produce_mix_list(struct map_session_data *sd, int skill_id , int WFIFOW(fd, 0)=0x18d; for(i=0,c=0;i<MAX_SKILL_PRODUCE_DB;i++){ - if( skill->can_produce_mix(sd,skill_produce_db[i].nameid, trigger, 1) && - ( ( skill_id > 0 && skill_produce_db[i].req_skill == skill_id ) || skill_id < 0 ) + if( skill->can_produce_mix(sd,skill->produce_db[i].nameid, trigger, 1) && + ( ( skill_id > 0 && skill->produce_db[i].req_skill == skill_id ) || skill_id < 0 ) ){ - if((view = itemdb_viewid(skill_produce_db[i].nameid)) > 0) + if((view = itemdb_viewid(skill->produce_db[i].nameid)) > 0) WFIFOW(fd,c*8+ 4)= view; else - WFIFOW(fd,c*8+ 4)= skill_produce_db[i].nameid; + WFIFOW(fd,c*8+ 4)= skill->produce_db[i].nameid; WFIFOW(fd,c*8+ 6)= 0; WFIFOW(fd,c*8+ 8)= 0; WFIFOW(fd,c*8+10)= 0; @@ -5553,7 +5469,7 @@ void clif_skill_produce_mix_list(struct map_session_data *sd, int skill_id , int } -/// Present a list of producable items (ZC_MAKINGITEM_LIST). +/// Present a list of producible items (ZC_MAKINGITEM_LIST). /// 025a <packet len>.W <mk type>.W { <name id>.W }* /// mk type: /// 1 = cooking @@ -5577,13 +5493,13 @@ void clif_cooking_list(struct map_session_data *sd, int trigger, uint16 skill_id c = 0; for( i = 0; i < MAX_SKILL_PRODUCE_DB; i++ ) { - if( !skill->can_produce_mix(sd,skill_produce_db[i].nameid,trigger, qty) ) + if( !skill->can_produce_mix(sd,skill->produce_db[i].nameid,trigger, qty) ) continue; - if( (view = itemdb_viewid(skill_produce_db[i].nameid)) > 0 ) + if( (view = itemdb_viewid(skill->produce_db[i].nameid)) > 0 ) WFIFOW(fd, 6 + 2 * c) = view; else - WFIFOW(fd, 6 + 2 * c) = skill_produce_db[i].nameid; + WFIFOW(fd, 6 + 2 * c) = skill->produce_db[i].nameid; c++; } @@ -5618,22 +5534,22 @@ void clif_cooking_list(struct map_session_data *sd, int trigger, uint16 skill_id void clif_status_change_notick(struct block_list *bl,int type,int flag,int tick,int val1, int val2, int val3) { struct packet_sc_notick p; struct map_session_data *sd; - + nullpo_retv(bl); - - if (!(status_type2relevant_bl_types(type)&bl->type)) // only send status changes that actually matter to the client - return; - + if (type == SI_BLANK) //It shows nothing on the client... return; - + + if (!(status->type2relevant_bl_types(type)&bl->type)) // only send status changes that actually matter to the client + return; + sd = BL_CAST(BL_PC, bl); - + p.PacketType = sc_notickType; p.index = type; p.AID = bl->id; p.state = (unsigned char)flag; - + clif->send(&p,packet_len(p.PacketType), bl, (sd && sd->status.option&OPTION_INVISIBLE) ? SELF : AREA); } @@ -5652,7 +5568,7 @@ void clif_status_change(struct block_list *bl,int type,int flag,int tick,int val nullpo_retv(bl); - if (!(status_type2relevant_bl_types(type)&bl->type)) // only send status changes that actually matter to the client + if (!(status->type2relevant_bl_types(type)&bl->type)) // only send status changes that actually matter to the client return; if ( tick < 0 ) @@ -5681,15 +5597,15 @@ void clif_status_change(struct block_list *bl,int type,int flag,int tick,int val void clif_displaymessage(const int fd, const char* mes) { nullpo_retv(mes); - if( fd == -2 ) { + if( map->cpsd_active && fd == 0 ) { ShowInfo("HCP: %s\n",mes); } else if ( fd > 0 ) { - int len; - + size_t len; + 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. WFIFOHEAD(fd, 5 + len); WFIFOW(fd,0) = 0x8e; - WFIFOW(fd,2) = 5 + len; // 4 + len + NULL teminate + WFIFOW(fd,2) = 5 + len; // 4 + len + NULL terminate safestrncpy((char *)WFIFOP(fd,4), mes, len + 1); WFIFOSET(fd, 5 + len); } @@ -5698,49 +5614,81 @@ void clif_displaymessage(const int fd, const char* mes) { void clif_displaymessage2(const int fd, const char* mes) { // invalid pointer? nullpo_retv(mes); - + //Scrapped, as these are shared by disconnected players =X [Skotlex] if (fd == 0) ; else { // Limit message to 255+1 characters (otherwise it causes a buffer overflow in the client) char *message, *line; - + message = aStrdup(mes); line = strtok(message, "\n"); while(line != NULL) { // Limit message to 255+1 characters (otherwise it causes a buffer overflow in the client) - int len = strnlen(line, 255); - + size_t len = 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( fd == -2 ) { + if( map->cpsd_active && fd == 0 ) { ShowInfo("HCP: %s\n",line); } else { WFIFOHEAD(fd, 5 + len); WFIFOW(fd,0) = 0x8e; - WFIFOW(fd,2) = 5 + len; // 4 + len + NULL teminate + WFIFOW(fd,2) = 5 + len; // 4 + len + NULL terminate safestrncpy((char *)WFIFOP(fd,4), line, len + 1); WFIFOSET(fd, 5 + len); } } line = strtok(NULL, "\n"); } - aFree(message); + aFree(message); } } +/* oh noo! another version of 0x8e! */ +void clif_displaymessage_sprintf(const int fd, const char *mes, ...) __attribute__((format(printf, 2, 3))); +void clif_displaymessage_sprintf(const int fd, const char *mes, ...) { + va_list ap; + + if (map->cpsd_active && fd == 0) { + ShowInfo("HCP: "); + va_start(ap,mes); + vShowMessage_(MSG_NONE,mes,ap); + va_end(ap); + ShowMessage("\n"); + } else if (fd > 0) { + int len = 1; + char *ptr; + + WFIFOHEAD(fd, 5 + 255);/* ensure the maximum */ + + /* process */ + va_start(ap,mes); + len += vsnprintf((char *)WFIFOP(fd,4), 255, mes, ap); + va_end(ap); + /* adjusting */ + ptr = (char *)WFIFOP(fd,4); + ptr[len - 1] = '\0'; + + /* */ + WFIFOW(fd,0) = 0x8e; + WFIFOW(fd,2) = 5 + len; // 4 + len + NULL terminate + + WFIFOSET(fd, 5 + len); + } +} /// 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, int len, int type, enum send_target target) +void clif_broadcast(struct block_list* bl, const char* mes, size_t len, int type, enum send_target target) { - int lp = type ? 4 : 0; + int lp = (type&BC_COLOR_MASK) ? 4 : 0; unsigned char *buf = (unsigned char*)aMalloc((4 + lp + len)*sizeof(unsigned char)); WBUFW(buf,0) = 0x9a; WBUFW(buf,2) = 4 + lp + len; - if (type == 0x10) // bc_blue + if( type&BC_BLUE ) WBUFL(buf,4) = 0x65756c62; //If there's "blue" at the beginning of the message, game client will display it in blue instead of yellow. - else if (type == 0x20) // bc_woe + else if( type&BC_WOE ) WBUFL(buf,4) = 0x73737373; //If there's "ssss", game client will recognize message as 'WoE broadcast'. memcpy(WBUFP(buf, 4 + lp), mes, len); clif->send(buf, WBUFW(buf,2), bl, target); @@ -5754,8 +5702,8 @@ void clif_broadcast(struct block_list* bl, const char* mes, int len, int type, e * Used by npc_globalmessage *------------------------------------------*/ void clif_GlobalMessage(struct block_list* bl, const char* message) { - char buf[100]; - int len; + char buf[256]; + size_t len; nullpo_retv(bl); if(!message) @@ -5763,8 +5711,8 @@ void clif_GlobalMessage(struct block_list* bl, const char* message) { len = strlen(message)+1; - if( len > sizeof(buf)-8 ) { - ShowWarning("clif_GlobalMessage: Truncating too long message '%s' (len=%d).\n", message, len); + if (len > sizeof(buf)-8) { + ShowWarning("clif_GlobalMessage: Truncating too long message '%s' (len=%"PRIuS").\n", message, len); len = sizeof(buf)-8; } @@ -5778,7 +5726,7 @@ void clif_GlobalMessage(struct block_list* bl, const char* message) { /// 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, int len, unsigned long fontColor, short fontType, short fontSize, short fontAlign, short fontY, enum send_target target) +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) { unsigned char *buf = (unsigned char*)aMalloc((16 + len)*sizeof(unsigned char)); @@ -5822,7 +5770,7 @@ void clif_resurrection(struct block_list *bl,int type) unsigned char buf[16]; nullpo_retv(bl); - + WBUFW(buf,0)=0x148; WBUFL(buf,2)=bl->id; WBUFW(buf,6)=0; @@ -5845,7 +5793,7 @@ void clif_map_property(struct map_session_data* sd, enum map_property property) int fd; nullpo_retv(sd); - + fd=sd->fd; WFIFOHEAD(fd,packet_len(0x199)); WFIFOW(fd,0)=0x199; @@ -5903,14 +5851,14 @@ void clif_pvpset(struct map_session_data *sd,int pvprank,int pvpnum,int type) /*========================================== * *------------------------------------------*/ -void clif_map_property_mapall(int map, enum map_property property) +void clif_map_property_mapall(int mapid, enum map_property property) { struct block_list bl; unsigned char buf[16]; - + bl.id = 0; bl.type = BL_NUL; - bl.m = map; + bl.m = mapid; WBUFW(buf,0)=0x199; WBUFW(buf,2)=property; clif->send(buf,packet_len(0x199),&bl,ALL_SAMEMAP); @@ -5954,8 +5902,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, int mes_len) -{ +void clif_wis_message(int fd, const char* nick, const char* mes, size_t mes_len) { #if PACKETVER < 20091104 WFIFOHEAD(fd, mes_len + NAME_LENGTH + 4); WFIFOW(fd,0) = 0x97; @@ -5964,13 +5911,13 @@ void clif_wis_message(int fd, const char* nick, const char* mes, int mes_len) safestrncpy((char*)WFIFOP(fd,28), mes, mes_len); WFIFOSET(fd,WFIFOW(fd,2)); #else - struct map_session_data *ssd = iMap->nick2sd(nick); + struct map_session_data *ssd = map->nick2sd(nick); WFIFOHEAD(fd, mes_len + NAME_LENGTH + 8); WFIFOW(fd,0) = 0x97; WFIFOW(fd,2) = mes_len + NAME_LENGTH + 8; safestrncpy((char*)WFIFOP(fd,4), nick, NAME_LENGTH); - WFIFOL(fd,28) = (pc->get_group_level(ssd) == 99) ? 1 : 0; // isAdmin; if nonzero, also displays text above char + WFIFOL(fd,28) = (ssd && pc_get_group_level(ssd) == 99) ? 1 : 0; // isAdmin; if nonzero, also displays text above char safestrncpy((char*)WFIFOP(fd,32), mes, mes_len); WFIFOSET(fd,WFIFOW(fd,2)); #endif @@ -5980,16 +5927,24 @@ void clif_wis_message(int fd, const char* nick, const char* mes, int mes_len) /// Inform the player about the result of his whisper action (ZC_ACK_WHISPER). /// 0098 <result>.B /// result: -/// 0 = success to send wisper -/// 1 = target character is not loged in +/// 0 = success to send whisper +/// 1 = target character is not logged in /// 2 = ignored by target /// 3 = everyone ignored by target -void clif_wis_end(int fd, int flag) -{ - WFIFOHEAD(fd,packet_len(0x98)); - WFIFOW(fd,0) = 0x98; - WFIFOW(fd,2) = flag; - WFIFOSET(fd,packet_len(0x98)); +void clif_wis_end(int fd, int flag) { + struct map_session_data *sd = session_isValid(fd) ? session[fd]->session_data : NULL; + struct packet_wis_end p; + + if( !sd ) + return; + + p.PacketType = wisendType; + p.result = (char)flag; +#if PACKETVER >= 20131223 + p.unknown = 0; +#endif + + clif->send(&p, sizeof(p), &sd->bl, SELF); } @@ -6046,9 +6001,15 @@ void clif_use_card(struct map_session_data *sd,int idx) if( j == sd->inventory_data[i]->slot ) // No room continue; + if( sd->status.inventory[i].equip > 0 ) // Do not check items that are already equipped + continue; + WFIFOW(fd,4+c*2)=i+2; c++; } + + if( !c ) return; // no item is available for card insertion + WFIFOW(fd,2)=4+c*2; WFIFOSET(fd,WFIFOW(fd,2)); } @@ -6208,11 +6169,11 @@ void clif_item_refine_list(struct map_session_data *sd) skill_lv = pc->checkskill(sd,WS_WEAPONREFINE); fd=sd->fd; - + WFIFOHEAD(fd, MAX_INVENTORY * 13 + 4); WFIFOW(fd,0)=0x221; for(i=c=0;i<MAX_INVENTORY;i++){ - if(sd->status.inventory[i].nameid > 0 && sd->status.inventory[i].identify + if(sd->status.inventory[i].nameid > 0 && sd->status.inventory[i].identify && (wlv=itemdb_wlv(sd->status.inventory[i].nameid)) >=1 && !sd->inventory_data[i]->flag.no_refine && !(sd->status.inventory[i].equip&EQP_ARMS)){ @@ -6233,7 +6194,7 @@ void clif_item_refine_list(struct map_session_data *sd) /// Notification of an auto-casted skill (ZC_AUTORUN_SKILL). -/// 0147 <skill id>.W <type>.L <level>.W <sp cost>.W <atk range>.W <skill name>.24B <upgradable>.B +/// 0147 <skill id>.W <type>.L <level>.W <sp cost>.W <atk range>.W <skill name>.24B <upgradeable>.B void clif_item_skill(struct map_session_data *sd,uint16 skill_id,uint16 skill_lv) { int fd; @@ -6385,8 +6346,7 @@ void clif_closevendingboard(struct block_list* bl, int fd) /// Sends a list of items in a shop. /// R 0133 <packet len>.W <owner id>.L { <price>.L <amount>.W <index>.W <type>.B <name id>.W <identified>.B <damaged>.B <refine>.B <card1>.W <card2>.W <card3>.W <card4>.W }* (ZC_PC_PURCHASE_ITEMLIST_FROMMC) /// R 0800 <packet len>.W <owner id>.L <unique id>.L { <price>.L <amount>.W <index>.W <type>.B <name id>.W <identified>.B <damaged>.B <refine>.B <card1>.W <card2>.W <card3>.W <card4>.W }* (ZC_PC_PURCHASE_ITEMLIST_FROMMC2) -void clif_vendinglist(struct map_session_data* sd, unsigned int id, struct s_vending* vending) -{ +void clif_vendinglist(struct map_session_data* sd, unsigned int id, struct s_vending* vending_items) { int i,fd; int count; struct map_session_data* vsd; @@ -6399,8 +6359,8 @@ void clif_vendinglist(struct map_session_data* sd, unsigned int id, struct s_ven #endif nullpo_retv(sd); - nullpo_retv(vending); - nullpo_retv(vsd=iMap->id2sd(id)); + nullpo_retv(vending_items); + nullpo_retv(vsd=map->id2sd(id)); fd = sd->fd; count = vsd->vend_num; @@ -6413,13 +6373,12 @@ void clif_vendinglist(struct map_session_data* sd, unsigned int id, struct s_ven WFIFOL(fd,8) = vsd->vender_id; #endif - for( i = 0; i < count; i++ ) - { - int index = vending[i].index; - struct item_data* data = itemdb_search(vsd->status.cart[index].nameid); - WFIFOL(fd,offset+ 0+i*22) = vending[i].value; - WFIFOW(fd,offset+ 4+i*22) = vending[i].amount; - WFIFOW(fd,offset+ 6+i*22) = vending[i].index + 2; + for( i = 0; i < count; i++ ) { + int index = vending_items[i].index; + struct item_data* data = itemdb->search(vsd->status.cart[index].nameid); + WFIFOL(fd,offset+ 0+i*22) = vending_items[i].value; + WFIFOW(fd,offset+ 4+i*22) = vending_items[i].amount; + WFIFOW(fd,offset+ 6+i*22) = vending_items[i].index + 2; WFIFOB(fd,offset+ 8+i*22) = itemtype(data->type); WFIFOW(fd,offset+ 9+i*22) = ( data->view_id > 0 ) ? data->view_id : vsd->status.cart[index].nameid; WFIFOB(fd,offset+11+i*22) = vsd->status.cart[index].identify; @@ -6459,8 +6418,7 @@ void clif_buyvending(struct map_session_data* sd, int index, int amount, int fai /// Shop creation success (ZC_PC_PURCHASE_MYITEMLIST). /// 0136 <packet len>.W <owner id>.L { <price>.L <index>.W <amount>.W <type>.B <name id>.W <identified>.B <damaged>.B <refine>.B <card1>.W <card2>.W <card3>.W <card4>.W }* -void clif_openvending(struct map_session_data* sd, int id, struct s_vending* vending) -{ +void clif_openvending(struct map_session_data* sd, int id, struct s_vending* vending_items) { int i,fd; int count; @@ -6474,11 +6432,11 @@ void clif_openvending(struct map_session_data* sd, int id, struct s_vending* ven WFIFOW(fd,2) = 8+count*22; WFIFOL(fd,4) = id; for( i = 0; i < count; i++ ) { - int index = vending[i].index; - struct item_data* data = itemdb_search(sd->status.cart[index].nameid); - WFIFOL(fd, 8+i*22) = vending[i].value; - WFIFOW(fd,12+i*22) = vending[i].index + 2; - WFIFOW(fd,14+i*22) = vending[i].amount; + int index = vending_items[i].index; + struct item_data* data = itemdb->search(sd->status.cart[index].nameid); + WFIFOL(fd, 8+i*22) = vending_items[i].value; + WFIFOW(fd,12+i*22) = vending_items[i].index + 2; + WFIFOW(fd,14+i*22) = vending_items[i].amount; WFIFOB(fd,16+i*22) = itemtype(data->type); WFIFOW(fd,17+i*22) = ( data->view_id > 0 ) ? data->view_id : sd->status.cart[index].nameid; WFIFOB(fd,19+i*22) = sd->status.cart[index].identify; @@ -6559,7 +6517,7 @@ void clif_party_member_info(struct party_data *p, struct map_session_data *sd) WBUFB(buf,14) = (p->party.member[i].online)?0:1; memcpy(WBUFP(buf,15), p->party.name, NAME_LENGTH); memcpy(WBUFP(buf,39), sd->status.name, NAME_LENGTH); - mapindex_getmapname_ext(map[sd->bl.m].cName ? map[sd->bl.m].cName : map[sd->bl.m].name, (char*)WBUFP(buf,63)); + mapindex->getmapname_ext(map->list[sd->bl.m].custom_name ? map->list[map->list[sd->bl.m].instance_src_map].name : map->list[sd->bl.m].name, (char*)WBUFP(buf,63)); WBUFB(buf,79) = (p->party.item&1)?1:0; WBUFB(buf,80) = (p->party.item&2)?1:0; clif->send(buf,packet_len(0x1e9),&sd->bl,PARTY); @@ -6593,7 +6551,7 @@ void clif_party_info(struct party_data* p, struct map_session_data *sd) WBUFL(buf,28+c*46) = m->account_id; memcpy(WBUFP(buf,28+c*46+4), m->name, NAME_LENGTH); - mapindex_getmapname_ext(mapindex_id2name(m->map), (char*)WBUFP(buf,28+c*46+28)); + mapindex->getmapname_ext(mapindex_id2name(m->map), (char*)WBUFP(buf,28+c*46+28)); WBUFB(buf,28+c*46+44) = (m->leader) ? 0 : 1; WBUFB(buf,28+c*46+45) = (m->online) ? 0 : 1; c++; @@ -6786,9 +6744,9 @@ void clif_party_message(struct party_data* p, int account_id, const char* mes, i if(i < MAX_PARTY){ unsigned char buf[1024]; - if( len > sizeof(buf)-8 ) - { - ShowWarning("clif_party_message: Truncated message '%s' (len=%d, max=%d, party_id=%d).\n", mes, len, sizeof(buf)-8, p->party.party_id); + 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; } @@ -6983,8 +6941,8 @@ void clif_sendegg(struct map_session_data *sd) nullpo_retv(sd); fd=sd->fd; - if (battle_config.pet_no_gvg && map_flag_gvg(sd->bl.m)) { //Disable pet hatching in GvG grounds during Guild Wars [Skotlex] - clif->message(fd, msg_txt(666)); + if (battle_config.pet_no_gvg && map_flag_gvg2(sd->bl.m)) { //Disable pet hatching in GvG grounds during Guild Wars [Skotlex] + clif->message(fd, msg_txt(866)); // "Pets are not allowed in Guild Wars." return; } WFIFOHEAD(fd, MAX_INVENTORY * 2 + 4); @@ -7037,23 +6995,23 @@ void clif_send_petdata(struct map_session_data* sd, struct pet_data* pd, int typ void clif_send_petstatus(struct map_session_data *sd) { int fd; - struct s_pet *pet; + struct s_pet *p; nullpo_retv(sd); nullpo_retv(sd->pd); fd=sd->fd; - pet = &sd->pd->pet; + p = &sd->pd->pet; WFIFOHEAD(fd,packet_len(0x1a2)); WFIFOW(fd,0)=0x1a2; - memcpy(WFIFOP(fd,2),pet->name,NAME_LENGTH); - WFIFOB(fd,26)=battle_config.pet_rename?0:pet->rename_flag; - WFIFOW(fd,27)=pet->level; - WFIFOW(fd,29)=pet->hungry; - WFIFOW(fd,31)=pet->intimate; - WFIFOW(fd,33)=pet->equip; + memcpy(WFIFOP(fd,2),p->name,NAME_LENGTH); + WFIFOB(fd,26)=battle_config.pet_rename?0:p->rename_flag; + WFIFOW(fd,27)=p->level; + WFIFOW(fd,29)=p->hungry; + WFIFOW(fd,31)=p->intimate; + WFIFOW(fd,33)=p->equip; #if PACKETVER >= 20081126 - WFIFOW(fd,35)=pet->class_; + WFIFOW(fd,35)=p->class_; #endif WFIFOSET(fd,packet_len(0x1a2)); } @@ -7172,7 +7130,7 @@ void clif_devotion(struct block_list *src, struct map_session_data *tsd) if( md && md->master && md->devotion_flag ) WBUFL(buf,6) = md->master->bl.id; - WBUFW(buf,26) = skill->get_range2(src, ML_DEVOTION, mercenary_checkskill(md, ML_DEVOTION)); + WBUFW(buf,26) = skill->get_range2(src, ML_DEVOTION, mercenary->checkskill(md, ML_DEVOTION)); } else { @@ -7321,7 +7279,7 @@ void clif_mvp_noitem(struct map_session_data* sd) /// 0 = "Guild has been created." /// 1 = "You are already in a Guild." /// 2 = "That Guild Name already exists." -/// 3 = "You need the neccessary item to create a Guild." +/// 3 = "You need the necessary item to create a Guild." void clif_guild_created(struct map_session_data *sd,int flag) { int fd; @@ -7354,7 +7312,7 @@ void clif_guild_belonginfo(struct map_session_data *sd, struct guild *g) WFIFOL(fd,2)=g->guild_id; WFIFOL(fd,6)=g->emblem_id; WFIFOL(fd,10)=g->position[ps].mode; - WFIFOB(fd,14)=(bool)(sd->state.gmaster_flag==g); + WFIFOB(fd,14)=(bool)(sd->state.gmaster_flag == 1); WFIFOL(fd,15)=0; // InterSID (unknown purpose) memcpy(WFIFOP(fd,19),g->name,NAME_LENGTH); WFIFOSET(fd,packet_len(0x16c)); @@ -7707,14 +7665,14 @@ void clif_guild_emblem_area(struct block_list* bl) // (emblem in the flag npcs and emblem over the head in agit maps) [FlavioJS] WBUFW(buf,0) = 0x1b4; WBUFL(buf,2) = bl->id; - WBUFL(buf,6) = status_get_guild_id(bl); - WBUFW(buf,10) = status_get_emblem_id(bl); + WBUFL(buf,6) = status->get_guild_id(bl); + WBUFW(buf,10) = status->get_emblem_id(bl); clif->send(buf, 12, bl, AREA_WOS); } /// Sends guild skills (ZC_GUILD_SKILLINFO). -/// 0162 <packet len>.W <skill points>.W { <skill id>.W <type>.L <level>.W <sp cost>.W <atk range>.W <skill name>.24B <upgradable>.B }* +/// 0162 <packet len>.W <skill points>.W { <skill id>.W <type>.L <level>.W <sp cost>.W <atk range>.W <skill name>.24B <upgradeable>.B }* void clif_guild_skillinfo(struct map_session_data* sd) { int fd; @@ -7901,13 +7859,11 @@ void clif_guild_message(struct guild *g,int account_id,const char *mes,int len) struct map_session_data *sd; uint8 buf[256]; - if( len == 0 ) - { + if (len == 0) return; - } - else if( len > sizeof(buf)-5 ) - { - ShowWarning("clif_guild_message: Truncated message '%s' (len=%d, max=%d, guild_id=%d).\n", mes, len, sizeof(buf)-5, g->guild_id); + + if (len > sizeof(buf)-5) { + ShowWarning("clif_guild_message: Truncated message '%s' (len=%d, max=%"PRIuS", guild_id=%d).\n", mes, len, sizeof(buf)-5, g->guild_id); len = sizeof(buf)-5; } @@ -7919,29 +7875,6 @@ void clif_guild_message(struct guild *g,int account_id,const char *mes,int len) clif->send(buf, WBUFW(buf,2), &sd->bl, GUILD_NOBG); } - -/*========================================== - * Server tells client 'sd' that his guild skill 'skill_id' gone to level 'lv' - *------------------------------------------*/ -int clif_guild_skillup(struct map_session_data *sd,uint16 skill_id,int lv) -{// TODO: Merge with clif_skillup (same packet). - int fd; - - nullpo_ret(sd); - - fd=sd->fd; - WFIFOHEAD(fd,11); - WFIFOW(fd,0) = 0x10e; - WFIFOW(fd,2) = skill_id; - WFIFOW(fd,4) = lv; - WFIFOW(fd,6) = skill->get_sp(skill_id,lv); - WFIFOW(fd,8) = skill->get_range(skill_id,lv); - WFIFOB(fd,10) = 1; - WFIFOSET(fd,11); - return 0; -} - - /// Request for guild alliance (ZC_REQ_ALLY_GUILD). /// 0171 <inviter account id>.L <guild name>.24B void clif_guild_reqalliance(struct map_session_data *sd,int account_id,const char *name) @@ -8106,28 +8039,22 @@ void clif_wedding_effect(struct block_list *bl) /// Notifies the client of the name of the partner character (ZC_COUPLENAME). /// 01e6 <partner name>.24B -void clif_callpartner(struct map_session_data *sd) -{ +void clif_callpartner(struct map_session_data *sd) { unsigned char buf[26]; nullpo_retv(sd); WBUFW(buf,0) = 0x1e6; - if( sd->status.partner_id ) - { + if( sd->status.partner_id ) { const char *p; - if( ( p = iMap->charid2nick(sd->status.partner_id) ) != NULL ) - { + if( ( p = map->charid2nick(sd->status.partner_id) ) != NULL ) { memcpy(WBUFP(buf,2), p, NAME_LENGTH); - } - else - { + } else { WBUFB(buf,2) = 0; } - } - else - {// Send zero-length name if no partner, to initialize the client buffer. + } else { + // Send zero-length name if no partner, to initialize the client buffer. WBUFB(buf,2) = 0; } @@ -8184,25 +8111,18 @@ void clif_marriage_proposal(int fd, struct map_session_data *sd, struct map_sess } */ - -/*========================================== - * - *------------------------------------------*/ -void clif_disp_onlyself(struct map_session_data *sd, const char *mes, int len) { - clif->disp_message(&sd->bl, mes, len, SELF); -} - /*========================================== * Displays a message using the guild-chat colors to the specified targets. [Skotlex] *------------------------------------------*/ -void clif_disp_message(struct block_list* src, const char* mes, int len, enum send_target target) +void clif_disp_message(struct block_list* src, const char* mes, size_t len, enum send_target target) { unsigned char buf[256]; - if( len == 0 ) { + if (len == 0) return; - } else if( len > sizeof(buf)-5 ) { - ShowWarning("clif_disp_message: Truncated message '%s' (len=%d, max=%d, aid=%d).\n", mes, len, sizeof(buf)-5, src->id); + + 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; } @@ -8219,7 +8139,7 @@ void clif_disp_message(struct block_list* src, const char* mes, int len, enum se /// result: /// 0 = failure /// 1 = success -void clif_GM_kickack(struct map_session_data *sd, int id) +void clif_GM_kickack(struct map_session_data *sd, int result) { int fd; @@ -8228,22 +8148,21 @@ void clif_GM_kickack(struct map_session_data *sd, int id) fd = sd->fd; WFIFOHEAD(fd,packet_len(0xcd)); WFIFOW(fd,0) = 0xcd; - WFIFOB(fd,2) = id; // FIXME: this is not account id + WFIFOB(fd,2) = result; WFIFOSET(fd, packet_len(0xcd)); } -void clif_GM_kick(struct map_session_data *sd,struct map_session_data *tsd) -{ +void clif_GM_kick(struct map_session_data *sd,struct map_session_data *tsd) { int fd = tsd->fd; if( fd > 0 ) clif->authfail_fd(fd, 15); else - iMap->quit(tsd); + map->quit(tsd); if( sd ) - clif->GM_kickack(sd,tsd->status.account_id); + clif->GM_kickack(sd, 1); } @@ -8269,7 +8188,7 @@ void clif_manner_message(struct map_session_data* sd, uint32 type) } -/// Followup to 0x14a type 3/5, informs who did the manner adjustment action (ZC_NOTIFY_MANNER_POINT_GIVEN). +/// Follow-up to 0x14a type 3/5, informs who did the manner adjustment action (ZC_NOTIFY_MANNER_POINT_GIVEN). /// 014b <type>.B <GM name>.24B /// type: /// 0 = positive (unmute) @@ -8360,7 +8279,7 @@ void clif_playBGM(struct map_session_data* sd, const char* name) /// term: /// unknown purpose, only relevant to act = 1 /// npc id: -/// The accustic direction of the sound is determined by the +/// The acoustic direction of the sound is determined by the /// relative position of the NPC to the player (3D sound). void clif_soundeffect(struct map_session_data* sd, struct block_list* bl, const char* name, int type) { @@ -8453,7 +8372,7 @@ void clif_specialeffect_value(struct block_list* bl, int effect_id, int num, sen // Modification of clif_messagecolor to send colored messages to players to chat log only (doesn't display overhead) /// 02c1 <packet len>.W <id>.L <color>.L <message>.?B int clif_colormes(int fd, enum clif_colors color, const char* msg) { - unsigned short msg_len = strlen(msg) + 1; + size_t msg_len = strlen(msg) + 1; WFIFOHEAD(fd,msg_len + 12); WFIFOW(fd,0) = 0x2C1; @@ -8468,15 +8387,15 @@ int clif_colormes(int fd, enum clif_colors color, const char* msg) { /// Monster/NPC color chat [SnakeDrak] (ZC_NPC_CHAT). /// 02c1 <packet len>.W <id>.L <color>.L <message>.?B -void clif_messagecolor(struct block_list* bl, unsigned long color, const char* msg) { - unsigned short msg_len = strlen(msg) + 1; +void clif_messagecolor(struct block_list* bl, unsigned int color, const char* msg) { + size_t msg_len = strlen(msg) + 1; uint8 buf[256]; color = (color & 0x0000FF) << 16 | (color & 0x00FF00) | (color & 0xFF0000) >> 16; // RGB to BGR nullpo_retv(bl); - if( msg_len > sizeof(buf)-12 ) { - ShowWarning("clif_messagecolor: Truncating too long message '%s' (len=%u).\n", msg, msg_len); + 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; } @@ -8509,6 +8428,34 @@ void clif_message(struct block_list* bl, const char* msg) { clif->send(buf, WBUFW(buf,2), bl, AREA_CHAT_WOC); } +/** + * Notifies the client that the storage window is still open + * + * Should only be used in cases where the client closed the + * storage window without server's consent + **/ +void clif_refresh_storagewindow( struct map_session_data *sd ) { + // Notify the client that the storage is open + if( sd->state.storage_flag == 1 ) { + storage->sortitem(sd->status.storage.items, ARRAYLENGTH(sd->status.storage.items)); + clif->storagelist(sd, sd->status.storage.items, ARRAYLENGTH(sd->status.storage.items)); + clif->updatestorageamount(sd, sd->status.storage.storage_amount, MAX_STORAGE); + } + // Notify the client that the gstorage is open otherwise it will + // remain locked forever and nobody will be able to access it + if( sd->state.storage_flag == 2 ) { + struct guild_storage *gstor; + if( (gstor = gstorage->id2storage2(sd->status.guild_id)) == NULL) { + // Shouldn't happen... The information should already be at the map-server + intif->request_guild_storage(sd->status.account_id,sd->status.guild_id); + } else { + storage->sortitem(gstor->items, ARRAYLENGTH(gstor->items)); + clif->storagelist(sd, gstor->items, ARRAYLENGTH(gstor->items)); + clif->updatestorageamount(sd, gstor->storage_amount, MAX_GUILD_STORAGE); + } + } +} + // refresh the client's screen, getting rid of any effects void clif_refresh(struct map_session_data *sd) { @@ -8545,10 +8492,10 @@ void clif_refresh(struct map_session_data *sd) } if( sd->ed ) clif->elemental_info(sd); - iMap->foreachinrange(clif->getareachar,&sd->bl,AREA_SIZE,BL_ALL,sd); + map->foreachinrange(clif->getareachar,&sd->bl,AREA_SIZE,BL_ALL,sd); clif->weather_check(sd); if( sd->chatID ) - chat_leavechat(sd,0); + chat->leave(sd,0); if( sd->state.vending ) clif->openvending(sd, sd->bl.id, sd->vending); if( pc_issit(sd) ) @@ -8562,13 +8509,14 @@ void clif_refresh(struct map_session_data *sd) buyingstore->close(sd); mail->clear(sd); - + if( disguised(&sd->bl) ) {/* refresh-da */ short disguise = sd->disguise; pc->disguise(sd, -1); pc->disguise(sd, disguise); } - + + clif->refresh_storagewindow(sd); } @@ -8656,11 +8604,11 @@ void clif_charnameack (int fd, struct block_list *bl) nullpo_retv(md); memcpy(WBUFP(buf,6), md->name, NAME_LENGTH); - if( md->guardian_data && md->guardian_data->guild_id ) + if( md->guardian_data && md->guardian_data->g ) { WBUFW(buf, 0) = cmd = 0x195; WBUFB(buf,30) = 0; - memcpy(WBUFP(buf,54), md->guardian_data->guild_name, NAME_LENGTH); + memcpy(WBUFP(buf,54), md->guardian_data->g->name, NAME_LENGTH); memcpy(WBUFP(buf,78), md->guardian_data->castle->castle_name, NAME_LENGTH); } else if( battle_config.show_mob_info ) @@ -8697,7 +8645,7 @@ void clif_charnameack (int fd, struct block_list *bl) return; } - // if no receipient specified just update nearby clients + // if no recipient specified just update nearby clients if (fd == 0) clif->send(buf, packet_len(cmd), bl, AREA); else { @@ -8792,11 +8740,11 @@ void clif_slide(struct block_list *bl, int x, int y) /// 008d <packet len>.W <id>.L <message>.?B void clif_disp_overhead(struct block_list *bl, const char* mes) { - unsigned char buf[256]; //This should be more than sufficient, the theorical max is CHAT_SIZE + 8 (pads and extra inserted crap) - int len_mes = strlen(mes)+1; //Account for \0 + 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 = strlen(mes)+1; //Account for \0 if (len_mes > sizeof(buf)-8) { - ShowError("clif_disp_overhead: Message too long (length %d)\n", len_mes); + ShowError("clif_disp_overhead: Message too long (length %"PRIuS")\n", len_mes); len_mes = sizeof(buf)-8; //Trunk it to avoid problems. } // send message to others @@ -8813,7 +8761,7 @@ void clif_disp_overhead(struct block_list *bl, const char* mes) safestrncpy((char*)WBUFP(buf,4), mes, len_mes); clif->send(buf, WBUFW(buf,2), bl, SELF); } - + } /*========================== @@ -8900,27 +8848,27 @@ void clif_starskill(struct map_session_data* sd, const char* mapname, int monste } /*========================================== - * Info about Star Glaldiator save map [Komurka] + * Info about Star Gladiator save map [Komurka] * type: 1: Information, 0: Map registered *------------------------------------------*/ void clif_feel_info(struct map_session_data* sd, unsigned char feel_level, unsigned char type) { char mapname[MAP_NAME_LENGTH_EXT]; - mapindex_getmapname_ext(mapindex_id2name(sd->feel_map[feel_level].index), mapname); + mapindex->getmapname_ext(mapindex_id2name(sd->feel_map[feel_level].index), mapname); clif->starskill(sd, mapname, 0, feel_level, type ? 1 : 0); } /*========================================== - * Info about Star Glaldiator hate mob [Komurka] + * Info about Star Gladiator hate mob [Komurka] * type: 1: Register mob, 0: Information. *------------------------------------------*/ void clif_hate_info(struct map_session_data *sd, unsigned char hate_level,int class_, unsigned char type) { if( pcdb_checkid(class_) ) { clif->starskill(sd, pc->job_name(class_), class_, hate_level, type ? 10 : 11); - } else if( mobdb_checkid(class_) ) { - clif->starskill(sd, mob_db(class_)->jname, class_, hate_level, type ? 10 : 11); + } else if( mob->db_checkid(class_) ) { + clif->starskill(sd, mob->db(class_)->jname, class_, hate_level, type ? 10 : 11); } else { ShowWarning("clif_hate_info: Received invalid class %d for this packet (char_id=%d, hate_level=%u, type=%u).\n", class_, sd->status.char_id, (unsigned int)hate_level, (unsigned int)type); } @@ -8931,7 +8879,7 @@ void clif_hate_info(struct map_session_data *sd, unsigned char hate_level,int cl *------------------------------------------*/ void clif_mission_info(struct map_session_data *sd, int mob_id, unsigned char progress) { - clif->starskill(sd, mob_db(mob_id)->jname, mob_id, progress, 20); + clif->starskill(sd, mob->db(mob_id)->jname, mob_id, progress, 20); } /*========================================== @@ -8987,69 +8935,41 @@ void clif_equpcheckbox(struct map_session_data* sd) /// 02d7 <packet len>.W <name>.24B <class>.W <hairstyle>.W <bottom-viewid>.W <mid-viewid>.W <up-viewid>.W <haircolor>.W <cloth-dye>.W <gender>.B {equip item}.28B* (ZC_EQUIPWIN_MICROSCOPE, PACKETVER >= 20100629) /// 0859 <packet len>.W <name>.24B <class>.W <hairstyle>.W <bottom-viewid>.W <mid-viewid>.W <up-viewid>.W <haircolor>.W <cloth-dye>.W <gender>.B {equip item}.28B* (ZC_EQUIPWIN_MICROSCOPE2, PACKETVER >= 20101124) /// 0859 <packet len>.W <name>.24B <class>.W <hairstyle>.W <bottom-viewid>.W <mid-viewid>.W <up-viewid>.W <robe>.W <haircolor>.W <cloth-dye>.W <gender>.B {equip item}.28B* (ZC_EQUIPWIN_MICROSCOPE2, PACKETVER >= 20110111) -void clif_viewequip_ack(struct map_session_data* sd, struct map_session_data* tsd) -{ - uint8* buf; - int i, n, fd, offset = 0; -#if PACKETVER < 20100629 - const int s = 26; -#else - const int s = 28; -#endif +void clif_viewequip_ack(struct map_session_data* sd, struct map_session_data* tsd) { + int i, k, equip = 0; + nullpo_retv(sd); nullpo_retv(tsd); - fd = sd->fd; - WFIFOHEAD(fd, MAX_INVENTORY * s + 43); - buf = WFIFOP(fd,0); + for( i = 0; i < EQI_MAX; i++ ) { + if( (k = tsd->equip_index[i]) >= 0 ) { -#if PACKETVER < 20101124 - WBUFW(buf, 0) = 0x2d7; -#else - WBUFW(buf, 0) = 0x859; -#endif - safestrncpy((char*)WBUFP(buf, 4), tsd->status.name, NAME_LENGTH); - WBUFW(buf,28) = tsd->status.class_; - WBUFW(buf,30) = tsd->vd.hair_style; - WBUFW(buf,32) = tsd->vd.head_bottom; - WBUFW(buf,34) = tsd->vd.head_mid; - WBUFW(buf,36) = tsd->vd.head_top; -#if PACKETVER >= 20110111 - WBUFW(buf,38) = tsd->vd.robe; - offset+= 2; - buf = WBUFP(buf,2); -#endif - WBUFW(buf,38) = tsd->vd.hair_color; - WBUFW(buf,40) = tsd->vd.cloth_color; - WBUFB(buf,42) = tsd->vd.sex; + if (tsd->status.inventory[k].nameid <= 0 || tsd->inventory_data[k] == NULL) // Item doesn't exist + continue; - for(i=0,n=0; i < MAX_INVENTORY; i++) - { - if (tsd->status.inventory[i].nameid <= 0 || tsd->inventory_data[i] == NULL) // Item doesn't exist - continue; - if (!itemdb_isequip2(tsd->inventory_data[i])) // Is not equippable - continue; + clif_item_equip(k+2,&viewequip_list.list[equip++],&tsd->status.inventory[k],tsd->inventory_data[k],pc->equippoint(tsd,k)); - // Inventory position - WBUFW(buf, n*s+43) = i + 2; - // Add refine, identify flag, element, etc. - clif->item_sub(WBUFP(buf,0), n*s+45, &tsd->status.inventory[i], tsd->inventory_data[i], pc->equippoint(tsd, i)); - // Add cards - clif->addcards(WBUFP(buf, n*s+55), &tsd->status.inventory[i]); - // Expiration date stuff, if all of those are set to 0 then the client doesn't show anything related (6 bytes) - WBUFL(buf, n*s+63) = tsd->status.inventory[i].expire_time; - WBUFW(buf, n*s+67) = 0; -#if PACKETVER >= 20100629 - if (tsd->inventory_data[i]->equip&EQP_VISIBLE) - WBUFW(buf, n*s+69) = tsd->inventory_data[i]->look; - else - WBUFW(buf, n*s+69) = 0; -#endif - n++; + } } - WFIFOW(fd, 2) = 43+offset+n*s; // Set length - WFIFOSET(fd, WFIFOW(fd, 2)); + viewequip_list.PacketType = viewequipackType; + viewequip_list.PacketLength = ( sizeof( viewequip_list ) - sizeof( viewequip_list.list ) ) + ( sizeof(struct EQUIPITEM_INFO) * equip ); + + safestrncpy(viewequip_list.characterName, tsd->status.name, NAME_LENGTH); + + viewequip_list.job = tsd->status.class_; + viewequip_list.head = tsd->vd.hair_style; + viewequip_list.accessory = tsd->vd.head_bottom; + viewequip_list.accessory2 = tsd->vd.head_mid; + viewequip_list.accessory3 = tsd->vd.head_top; +#if PACKETVER >= 20110111 + viewequip_list.robe = tsd->vd.robe; +#endif + viewequip_list.headpalette = tsd->vd.hair_color; + viewequip_list.bodypalette = tsd->vd.cloth_color; + viewequip_list.sex = tsd->vd.sex; + + clif->send(&viewequip_list, viewequip_list.PacketLength, &sd->bl, SELF); } @@ -9098,21 +9018,14 @@ void clif_msg_skill(struct map_session_data* sd, uint16 skill_id, int msg_id) WFIFOSET(fd, packet_len(0x7e6)); } - -/// View player equip request denied -void clif_viewequip_fail(struct map_session_data* sd) -{ - clif_msg(sd, 0x54d); -} - - /// 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, char** name_, int* namelen_, char** message_, int* messagelen_) { +bool clif_process_message(struct map_session_data *sd, int format, char **name_, size_t *namelen_, char **message_, size_t *messagelen_) { char *text, *name, *message; - unsigned int packetlen, textlen, namelen, messagelen; + unsigned int packetlen, textlen; + size_t namelen, messagelen; int fd = sd->fd; *name_ = NULL; @@ -9141,7 +9054,7 @@ bool clif_process_message(struct map_session_data* sd, int format, char** name_, 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 desynch" issue where they pick one char while loading another. + //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); set_eof(fd); // Just kick them out to correct it. return false; @@ -9204,14 +9117,14 @@ void clif_hercules_chsys_msg(struct hChSysCh *channel, struct map_session_data * DBIterator *iter = db_iterator(channel->users); struct map_session_data *user; unsigned short msg_len = strlen(msg) + 1; - + WFIFOHEAD(sd->fd,msg_len + 12); WFIFOW(sd->fd,0) = 0x2C1; WFIFOW(sd->fd,2) = msg_len + 12; WFIFOL(sd->fd,4) = 0; WFIFOL(sd->fd,8) = hChSys.colors[channel->color]; safestrncpy((char*)WFIFOP(sd->fd,12), msg, msg_len); - + for( user = dbi_first(iter); dbi_exists(iter); user = dbi_next(iter) ) { if( user->fd == sd->fd ) continue; @@ -9219,9 +9132,9 @@ void clif_hercules_chsys_msg(struct hChSysCh *channel, struct map_session_data * memcpy(WFIFOP(user->fd,0), WFIFOP(sd->fd,0), msg_len + 12); WFIFOSET(user->fd, msg_len + 12); } - + WFIFOSET(sd->fd, msg_len + 12); - + dbi_destroy(iter); } @@ -9230,19 +9143,19 @@ void clif_hercules_chsys_msg2(struct hChSysCh *channel, char *msg) { struct map_session_data *user; unsigned char buf[210]; unsigned short msg_len = strlen(msg) + 1; - + WBUFW(buf,0) = 0x2C1; WBUFW(buf,2) = msg_len + 12; WBUFL(buf,4) = 0; WBUFL(buf,8) = hChSys.colors[channel->color]; safestrncpy((char*)WBUFP(buf,12), msg, msg_len); - + for( user = dbi_first(iter); dbi_exists(iter); user = dbi_next(iter) ) { WFIFOHEAD(user->fd,msg_len + 12); memcpy(WFIFOP(user->fd,0), WBUFP(buf,0), msg_len + 12); WFIFOSET(user->fd, msg_len + 12); } - + dbi_destroy(iter); } @@ -9282,7 +9195,7 @@ void clif_parse_WantToConnection(int fd, struct map_session_data* sd) { } //Check for double login. - bl = iMap->id2bl(account_id); + bl = map->id2bl(account_id); if(bl && bl->type != BL_PC) { ShowError("clif_parse_WantToConnection: a non-player object already has id %d, please increase the starting account number\n", account_id); WFIFOHEAD(fd,packet_len(0x6a)); @@ -9295,7 +9208,7 @@ void clif_parse_WantToConnection(int fd, struct map_session_data* sd) { } if (bl || - ((node=chrif_search(account_id)) && //An already existing node is valid only if it is for this login. + ((node=chrif->search(account_id)) && //An already existing node is valid only if it is for this login. !(node->account_id == account_id && node->char_id == char_id && node->state == ST_LOGIN))) { clif->authfail_fd(fd, 8); //Still recognizes last connection @@ -9304,8 +9217,11 @@ void clif_parse_WantToConnection(int fd, struct map_session_data* sd) { CREATE(sd, TBL_PC, 1); sd->fd = fd; - sd->cryptKey = (( clif->cryptKey[0] * clif->cryptKey[1] ) + clif->cryptKey[2]) & 0xFFFFFFFF; - + + sd->cryptKey = (( ((( clif->cryptKey[0] * clif->cryptKey[1] ) + clif->cryptKey[2]) & 0xFFFFFFFF) + * clif->cryptKey[1] ) + clif->cryptKey[2]) & 0xFFFFFFFF; + sd->parse_cmd_func = clif->parse_cmd; + session[fd]->session_data = sd; pc->setnewpc(sd, account_id, char_id, login_id1, client_tick, sex, fd); @@ -9321,35 +9237,45 @@ void clif_parse_WantToConnection(int fd, struct map_session_data* sd) { WFIFOSET(fd,packet_len(0x283)); #endif - chrif_authreq(sd); + chrif->authreq(sd,false); } void clif_hercules_chsys_mjoin(struct map_session_data *sd) { - if( !map[sd->bl.m].channel ) { - CREATE(map[sd->bl.m].channel, struct hChSysCh , 1); - safestrncpy(map[sd->bl.m].channel->name, hChSys.local_name, HCHSYS_NAME_LENGTH); - map[sd->bl.m].channel->type = hChSys_MAP; - map[sd->bl.m].channel->m = sd->bl.m; - - clif->chsys_create(map[sd->bl.m].channel,NULL,NULL,hChSys.local_color); + if( sd->state.autotrade || sd->state.standalone ) + return; + if( !map->list[sd->bl.m].channel ) { + + if (map->list[sd->bl.m].flag.chsysnolocalaj || (map->list[sd->bl.m].instance_id >= 0 && instance->list[map->list[sd->bl.m].instance_id].owner_type != IOT_NONE) ) + return; + + CREATE(map->list[sd->bl.m].channel, struct hChSysCh , 1); + safestrncpy(map->list[sd->bl.m].channel->name, hChSys.local_name, HCHSYS_NAME_LENGTH); + map->list[sd->bl.m].channel->type = hChSys_MAP; + map->list[sd->bl.m].channel->m = sd->bl.m; + + clif->chsys_create(map->list[sd->bl.m].channel,NULL,NULL,hChSys.local_color); } - - if( map[sd->bl.m].channel->banned && idb_exists(map[sd->bl.m].channel->banned, sd->status.account_id) ) { + + if( map->list[sd->bl.m].channel->banned && idb_exists(map->list[sd->bl.m].channel->banned, sd->status.account_id) ) { return; } - - clif->chsys_join(map[sd->bl.m].channel,sd); - - if( !( map[sd->bl.m].channel->opt & hChSys_OPT_ANNOUNCE_JOIN ) ) { + + clif->chsys_join(map->list[sd->bl.m].channel,sd); + + if( !( map->list[sd->bl.m].channel->opt & hChSys_OPT_ANNOUNCE_JOIN ) ) { char mout[60]; - sprintf(mout, msg_txt(1435),hChSys.local_name,map[sd->bl.m].name); // You're now in the '#%s' channel for '%s' + sprintf(mout, msg_txt(1435),hChSys.local_name,map->list[sd->bl.m].name); // You're now in the '#%s' channel for '%s' clif->colormes(sd->fd, COLOR_DEFAULT, mout); } } /// Notification from the client, that it has finished map loading and is about to display player's character (CZ_NOTIFY_ACTORINIT). /// 007d -void clif_parse_LoadEndAck(int fd,struct map_session_data *sd) -{ +void clif_parse_LoadEndAck(int fd,struct map_session_data *sd) { +#if PACKETVER >= 20090218 + int i; +#endif + bool first_time = false; + if(sd->bl.prev != NULL) return; @@ -9401,21 +9327,29 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd) pc->setinvincibletimer(sd,battle_config.pc_invincible_time); } - if( map[sd->bl.m].users++ == 0 && battle_config.dynamic_mobs ) - iMap->spawnmobs(sd->bl.m); - if( !(sd->sc.option&OPTION_INVISIBLE) ) { // increment the number of pvp players on the map - map[sd->bl.m].users_pvp++; + if( map->list[sd->bl.m].users++ == 0 && battle_config.dynamic_mobs ) + map->spawnmobs(sd->bl.m); + + if( map->list[sd->bl.m].instance_id >= 0 ) { + instance->list[map->list[sd->bl.m].instance_id].users++; + instance->check_idle(map->list[sd->bl.m].instance_id); + } + + if( pc_has_permission(sd,PC_PERM_VIEW_HPMETER) ) { + map->list[sd->bl.m].hpmeter_visible++; + sd->state.hpmeter_visible = 1; } - if( map[sd->bl.m].instance_id >= 0 ) { - instances[map[sd->bl.m].instance_id].users++; - instance->check_idle(map[sd->bl.m].instance_id); + + if( !(sd->sc.option&OPTION_INVISIBLE) ) { // increment the number of pvp players on the map + map->list[sd->bl.m].users_pvp++; } + sd->state.debug_remove_map = 0; // temporary state to track double remove_map's [FlavioJS] // reset the callshop flag if the player changes map sd->state.callshop = 0; - iMap->addblock(&sd->bl); + map->addblock(&sd->bl); clif->spawn(&sd->bl); // Party @@ -9427,10 +9361,10 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd) if( sd->bg_id ) clif->bg_hp(sd); // BattleGround System - if(map[sd->bl.m].flag.pvp && !(sd->sc.option&OPTION_INVISIBLE)) { + if(map->list[sd->bl.m].flag.pvp && !(sd->sc.option&OPTION_INVISIBLE)) { if(!battle_config.pk_mode) { // remove pvp stuff for pk_mode [Valaris] - if (!map[sd->bl.m].flag.pvp_nocalcrank) - sd->pvp_timer = iTimer->add_timer(iTimer->gettick()+200, pc->calc_pvprank_timer, sd->bl.id, 0); + if (!map->list[sd->bl.m].flag.pvp_nocalcrank) + sd->pvp_timer = timer->add(timer->gettick()+200, pc->calc_pvprank_timer, sd->bl.id, 0); sd->pvp_rank = 0; sd->pvp_lastusers = 0; sd->pvp_point = 5; @@ -9443,32 +9377,33 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd) if(sd->duel_group) clif->map_property(sd, MAPPROPERTY_FREEPVPZONE); - if (map[sd->bl.m].flag.gvg_dungeon) + if (map->list[sd->bl.m].flag.gvg_dungeon) clif->map_property(sd, MAPPROPERTY_FREEPVPZONE); //TODO: Figure out the real packet to send here. - if( map_flag_gvg(sd->bl.m) ) + if( map_flag_gvg2(sd->bl.m) ) clif->map_property(sd, MAPPROPERTY_AGITZONE); + // info about nearby objects // must use foreachinarea (CIRCULAR_AREA interferes with foreachinrange) - iMap->foreachinarea(clif->getareachar, sd->bl.m, sd->bl.x-AREA_SIZE, sd->bl.y-AREA_SIZE, sd->bl.x+AREA_SIZE, sd->bl.y+AREA_SIZE, BL_ALL, sd); + map->foreachinarea(clif->getareachar, sd->bl.m, sd->bl.x-AREA_SIZE, sd->bl.y-AREA_SIZE, sd->bl.x+AREA_SIZE, sd->bl.y+AREA_SIZE, BL_ALL, sd); // pet if( sd->pd ) { - if( battle_config.pet_no_gvg && map_flag_gvg(sd->bl.m) ) { //Return the pet to egg. [Skotlex] - clif->message(sd->fd, msg_txt(666)); - pet_menu(sd, 3); //Option 3 is return to egg. + if( battle_config.pet_no_gvg && map_flag_gvg2(sd->bl.m) ) { //Return the pet to egg. [Skotlex] + clif->message(sd->fd, msg_txt(866)); // "Pets are not allowed in Guild Wars." + pet->menu(sd, 3); //Option 3 is return to egg. } else { - iMap->addblock(&sd->pd->bl); + map->addblock(&sd->pd->bl); clif->spawn(&sd->pd->bl); clif->send_petdata(sd,sd->pd,0,0); clif->send_petstatus(sd); -// skill->unit_move(&sd->pd->bl,gettick(),1); +// skill->unit_move(&sd->pd->bl,timer->gettick(),1); } } //homunculus [blackhole89] if( homun_alive(sd->hd) ) { - iMap->addblock(&sd->hd->bl); + map->addblock(&sd->hd->bl); clif->spawn(&sd->hd->bl); clif->send_homdata(sd,SP_ACK,0); clif->hominfo(sd,sd->hd,1); @@ -9477,11 +9412,11 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd) if( battle_config.hom_setting&0x8 ) status_calc_bl(&sd->hd->bl, SCB_SPEED); //Homunc mimic their master's speed on each map change if( !(battle_config.hom_setting&0x2) ) - skill->unit_move(&sd->hd->bl,iTimer->gettick(),1); // apply land skills immediately + skill->unit_move(&sd->hd->bl,timer->gettick(),1); // apply land skills immediately } if( sd->md ) { - iMap->addblock(&sd->md->bl); + map->addblock(&sd->md->bl); clif->spawn(&sd->md->bl); clif->mercenary_info(sd); clif->mercenary_skillblock(sd); @@ -9489,7 +9424,7 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd) } if( sd->ed ) { - iMap->addblock(&sd->ed->bl); + map->addblock(&sd->ed->bl); clif->spawn(&sd->ed->bl); clif->elemental_info(sd); clif->elemental_updatestatus(sd,SP_HP); @@ -9500,6 +9435,7 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd) if(sd->state.connect_new) { int lv; + first_time = true; sd->state.connect_new = 0; clif->skillinfoblock(sd); clif->hotkeys(sd); @@ -9512,38 +9448,38 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd) if (sd->sc.option&OPTION_FALCON) clif->status_change(&sd->bl, SI_FALCON, 1, 0, 0, 0, 0); - if (sd->sc.option&OPTION_RIDING) + if (sd->sc.option&(OPTION_RIDING|OPTION_DRAGON)) clif->status_change(&sd->bl, SI_RIDING, 1, 0, 0, 0, 0); else if (sd->sc.option&OPTION_WUGRIDER) clif->status_change(&sd->bl, SI_WUGRIDER, 1, 0, 0, 0, 0); if(sd->status.manner < 0) - sc_start(&sd->bl,SC_NOCHAT,100,0,0); + sc_start(NULL,&sd->bl,SC_NOCHAT,100,0,0); //Auron reported that This skill only triggers when you logon on the map o.O [Skotlex] if ((lv = pc->checkskill(sd,SG_KNOWLEDGE)) > 0) { if(sd->bl.m == sd->feel_map[0].m || sd->bl.m == sd->feel_map[1].m || sd->bl.m == sd->feel_map[2].m) - sc_start(&sd->bl, SC_KNOWLEDGE, 100, lv, skill->get_time(SG_KNOWLEDGE, lv)); + sc_start(NULL,&sd->bl, SC_KNOWLEDGE, 100, lv, skill->get_time(SG_KNOWLEDGE, lv)); } if(sd->pd && sd->pd->pet.intimate > 900) - clif->pet_emotion(sd->pd,(sd->pd->pet.class_ - 100)*100 + 50 + pet_hungry_val(sd->pd)); + clif->pet_emotion(sd->pd,(sd->pd->pet.class_ - 100)*100 + 50 + pet->hungry_val(sd->pd)); if(homun_alive(sd->hd)) homun->init_timers(sd->hd); - if (iMap->night_flag && map[sd->bl.m].flag.nightenabled) { + if (map->night_flag && map->list[sd->bl.m].flag.nightenabled) { sd->state.night = 1; clif->status_change(&sd->bl, SI_SKE, 1, 0, 0, 0, 0); } // Notify everyone that this char logged in [Skotlex]. - iMap->map_foreachpc(clif->friendslist_toggle_sub, sd->status.account_id, sd->status.char_id, 1); + map->foreachpc(clif->friendslist_toggle_sub, sd->status.account_id, sd->status.char_id, 1); //Login Event - npc_script_event(sd, NPCE_LOGIN); + npc->script_event(sd, NPCE_LOGIN); } else { //For some reason the client "loses" these on warp/map-change. clif->updatestatus(sd,SP_STR); @@ -9559,7 +9495,10 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd) sd->npc_menu = 0; if(sd->npc_id) - npc_event_dequeue(sd); + npc->event_dequeue(sd); + + if( sd->guild && ( battle_config.guild_notice_changemap == 2 || ( battle_config.guild_notice_changemap == 1 && sd->state.changemap ) ) ) + clif->guild_notice(sd,sd->guild); } if( sd->state.changemap ) {// restore information that gets lost on map-change @@ -9567,37 +9506,39 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd) clif->partyinvitationstate(sd); clif->equpcheckbox(sd); #endif - if( (battle_config.bg_flee_penalty != 100 || battle_config.gvg_flee_penalty != 100) && - (map_flag_gvg(sd->state.pmap) || map_flag_gvg(sd->bl.m) || map[sd->state.pmap].flag.battleground || map[sd->bl.m].flag.battleground) ) + if( (battle_config.bg_flee_penalty != 100 || battle_config.gvg_flee_penalty != 100) + && (map_flag_gvg2(sd->state.pmap) || map_flag_gvg2(sd->bl.m) + || map->list[sd->state.pmap].flag.battleground || map->list[sd->bl.m].flag.battleground) ) status_calc_bl(&sd->bl, SCB_FLEE); //Refresh flee penalty - if( iMap->night_flag && map[sd->bl.m].flag.nightenabled ) { //Display night. + if( map->night_flag && map->list[sd->bl.m].flag.nightenabled ) { + //Display night. if( !sd->state.night ) { sd->state.night = 1; - clif->sc_end(&sd->bl, sd->bl.id, SELF, SI_SKE); + clif->status_change(&sd->bl, SI_SKE, 1, 0, 0, 0, 0); } } else if( sd->state.night ) { //Clear night display. sd->state.night = 0; clif->sc_end(&sd->bl, sd->bl.id, SELF, SI_SKE); } - if( map[sd->bl.m].flag.battleground ) { + if( map->list[sd->bl.m].flag.battleground ) { clif->map_type(sd, MAPTYPE_BATTLEFIELD); // Battleground Mode - if( map[sd->bl.m].flag.battleground == 2 ) + if( map->list[sd->bl.m].flag.battleground == 2 ) clif->bg_updatescore_single(sd); } - if( map[sd->bl.m].flag.allowks && !map_flag_ks(sd->bl.m) ) { + if( map->list[sd->bl.m].flag.allowks && !map_flag_ks(sd->bl.m) ) { char output[128]; - sprintf(output, "[ Kill Steal Protection Disable. KS is allowed in this map ]"); - clif->broadcast(&sd->bl, output, strlen(output) + 1, 0x10, SELF); + sprintf(output, "[ Kill Steal Protection Disabled. KS is allowed in this map ]"); + clif->broadcast(&sd->bl, output, strlen(output) + 1, BC_BLUE, SELF); } - iMap->iwall_get(sd); // Updates Walls Info on this Map to Client - status_calc_pc(sd, false);/* some conditions are map-dependent so we must recalculate */ + map->iwall_get(sd); // Updates Walls Info on this Map to Client + status_calc_pc(sd, SCO_NONE);/* some conditions are map-dependent so we must recalculate */ sd->state.changemap = false; - - if( hChSys.local && hChSys.local_autojoin && !map[sd->bl.m].flag.chsysnolocalaj ) { + + if( hChSys.local && hChSys.local_autojoin ) { clif->chsys_mjoin(sd); } } @@ -9605,13 +9546,13 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd) mail->clear(sd); clif->maptypeproperty2(&sd->bl,SELF); - + /* Guild Aura Init */ if( sd->state.gmaster_flag ) { - guild->aura_refresh(sd,GD_LEADERSHIP,guild->checkskill(sd->state.gmaster_flag,GD_LEADERSHIP)); - guild->aura_refresh(sd,GD_GLORYWOUNDS,guild->checkskill(sd->state.gmaster_flag,GD_GLORYWOUNDS)); - guild->aura_refresh(sd,GD_SOULCOLD,guild->checkskill(sd->state.gmaster_flag,GD_SOULCOLD)); - guild->aura_refresh(sd,GD_HAWKEYES,guild->checkskill(sd->state.gmaster_flag,GD_HAWKEYES)); + guild->aura_refresh(sd,GD_LEADERSHIP,guild->checkskill(sd->guild,GD_LEADERSHIP)); + guild->aura_refresh(sd,GD_GLORYWOUNDS,guild->checkskill(sd->guild,GD_GLORYWOUNDS)); + guild->aura_refresh(sd,GD_SOULCOLD,guild->checkskill(sd->guild,GD_SOULCOLD)); + guild->aura_refresh(sd,GD_HAWKEYES,guild->checkskill(sd->guild,GD_HAWKEYES)); } if( sd->state.vending ) { /* show we have a vending */ @@ -9619,8 +9560,8 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd) clif->showvendingboard(&sd->bl,sd->message,0); } - if(map[sd->bl.m].flag.loadevent) // Lance - npc_script_event(sd, NPCE_LOADMAP); + if(map->list[sd->bl.m].flag.loadevent) // Lance + npc->script_event(sd, NPCE_LOADMAP); if (pc->checkskill(sd, SG_DEVIL) && !pc->nextjobexp(sd)) //blindness [Komurka] clif->sc_end(&sd->bl, sd->bl.id, SELF, SI_DEVIL1); @@ -9628,16 +9569,25 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd) if (sd->sc.opt2) //Client loses these on warp. clif->changeoption(&sd->bl); + if( sd->sc.data[SC_MONSTER_TRANSFORM] && battle_config.mon_trans_disable_in_gvg && map_flag_gvg2(sd->bl.m) ){ + status_change_end(&sd->bl, SC_MONSTER_TRANSFORM, INVALID_TIMER); + clif->message(sd->fd, msg_txt(1488)); // Transforming into monster is not allowed in Guild Wars. + } + clif->weather_check(sd); + // This should be displayed last + if( sd->guild && first_time ) + clif->guild_notice(sd, sd->guild); + // For automatic triggering of NPCs after map loading (so you don't need to walk 1 step first) - if (iMap->getcell(sd->bl.m,sd->bl.x,sd->bl.y,CELL_CHKNPC)) - npc_touch_areanpc(sd,sd->bl.m,sd->bl.x,sd->bl.y); + if (map->getcell(sd->bl.m,sd->bl.x,sd->bl.y,CELL_CHKNPC)) + npc->touch_areanpc(sd,sd->bl.m,sd->bl.x,sd->bl.y); else sd->areanpc_id = 0; /* it broke at some point (e.g. during a crash), so we make it visibly dead again. */ - if( !sd->status.hp && !pc_isdead(sd) && status_isdead(&sd->bl) ) + if( !sd->status.hp && !pc_isdead(sd) && status->isdead(&sd->bl) ) pc_setdead(sd); // If player is dead, and is spawned (such as @refresh) send death packet. [Valaris] @@ -9645,23 +9595,38 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd) clif->clearunit_area(&sd->bl, CLR_DEAD); else { skill->usave_trigger(sd); - clif->changed_dir(&sd->bl, SELF); + sd->ud.dir = 0;/* enforce north-facing (not visually, virtually) */ } -// Trigger skill effects if you appear standing on them + // Trigger skill effects if you appear standing on them if(!battle_config.pc_invincible_time) - skill->unit_move(&sd->bl,iTimer->gettick(),1); + skill->unit_move(&sd->bl,timer->gettick(),1); + + // NPC Quest / Event Icon Check [Kisuka] +#if PACKETVER >= 20090218 + for(i = 0; i < map->list[sd->bl.m].qi_count; i++) { + struct questinfo *qi = &map->list[sd->bl.m].qi_data[i]; + if( quest->check(sd, qi->quest_id, HAVEQUEST) == -1 ) {// Check if quest is not started + if( qi->hasJob ) { // Check if quest is job-specific, check is user is said job class. + if( sd->class_ == qi->job ) + clif->quest_show_event(sd, &qi->nd->bl, qi->icon, qi->color); + } else { + clif->quest_show_event(sd, &qi->nd->bl, qi->icon, qi->color); + } + } + } +#endif } /// Server's tick (ZC_NOTIFY_TIME). /// 007f <time>.L -void clif_notify_time(struct map_session_data* sd, unsigned long time) { +void clif_notify_time(struct map_session_data* sd, int64 time) { int fd = sd->fd; WFIFOHEAD(fd,packet_len(0x7f)); WFIFOW(fd,0) = 0x7f; - WFIFOL(fd,2) = time; + WFIFOL(fd,2) = (uint32)time; WFIFOSET(fd,packet_len(0x7f)); } @@ -9674,7 +9639,7 @@ void clif_parse_TickSend(int fd, struct map_session_data *sd) { sd->client_tick = RFIFOL(fd,packet_db[RFIFOW(fd,0)].pos[0]); - clif->notify_time(sd, iTimer->gettick()); + clif->notify_time(sd, timer->gettick()); } @@ -9724,7 +9689,8 @@ void clif_parse_Hotkey(int fd, struct map_session_data *sd) { /// Displays cast-like progress bar (ZC_PROGRESS). /// 02f0 <color>.L <time>.L -void clif_progressbar(struct map_session_data * sd, unsigned long color, unsigned int second) +/* TODO ZC_PROGRESS_ACTOR <account_id>.L */ +void clif_progressbar(struct map_session_data * sd, unsigned int color, unsigned int second) { int fd = sd->fd; @@ -9754,11 +9720,11 @@ void clif_parse_progressbar(int fd, struct map_session_data * sd) { int npc_id = sd->progressbar.npc_id; - if( iTimer->gettick() < sd->progressbar.timeout && sd->st ) + if( timer->gettick() < sd->progressbar.timeout && sd->st ) sd->st->state = END; - sd->state.workinprogress = sd->progressbar.npc_id = sd->progressbar.timeout = 0; - npc_scriptcont(sd, npc_id, false); + sd->progressbar.timeout = sd->state.workinprogress = sd->progressbar.npc_id = 0; + npc->scriptcont(sd, npc_id, false); } @@ -9790,9 +9756,10 @@ void clif_parse_WalkToXY(int fd, struct map_session_data *sd) RFIFOPOS(fd, packet_db[RFIFOW(fd,0)].pos[0], &x, &y, NULL); //Set last idle time... [Skotlex] - sd->idletime = last_tick; + if( battle_config.idletime_criteria & BCIDLE_WALK ) + sd->idletime = sockt->last_tick; - unit_walktoxy(&sd->bl, x, y, 4); + unit->walktoxy(&sd->bl, x, y, 4); } @@ -9820,8 +9787,8 @@ void clif_disconnect_ack(struct map_session_data* sd, short result) void clif_parse_QuitGame(int fd, struct map_session_data *sd) { /* Rovert's prevent logout option fixed [Valaris] */ - if( !sd->sc.data[SC_CLOAKING] && !sd->sc.data[SC_HIDING] && !sd->sc.data[SC_CHASEWALK] && !sd->sc.data[SC_CLOAKINGEXCEED] && - (!battle_config.prevent_logout || DIFF_TICK(iTimer->gettick(), sd->canlog_tick) > battle_config.prevent_logout) ) + if( !sd->sc.data[SC_CLOAKING] && !sd->sc.data[SC_HIDING] && !sd->sc.data[SC_CHASEWALK] && !sd->sc.data[SC_CLOAKINGEXCEED] && !sd->sc.data[SC__INVISIBILITY] && + (!battle_config.prevent_logout || DIFF_TICK(timer->gettick(), sd->canlog_tick) > battle_config.prevent_logout) ) { set_eof(fd); @@ -9836,8 +9803,7 @@ void clif_parse_QuitGame(int fd, struct map_session_data *sd) /// 0094 <id>.L (CZ_REQNAME) /// 0368 <id>.L (CZ_REQNAME2) /// There are various variants of this packet, some of them have padding between fields. -void clif_parse_GetCharNameRequest(int fd, struct map_session_data *sd) -{ +void clif_parse_GetCharNameRequest(int fd, struct map_session_data *sd) { int id = RFIFOL(fd,packet_db[RFIFOW(fd,0)].pos[0]); struct block_list* bl; //struct status_change *sc; @@ -9845,7 +9811,7 @@ void clif_parse_GetCharNameRequest(int fd, struct map_session_data *sd) if( id < 0 && -id == sd->bl.id ) // for disguises [Valaris] id = sd->bl.id; - bl = iMap->id2bl(id); + bl = map->id2bl(id); if( bl == NULL ) return; // Lagged clients could request names of already gone mobs/players. [Skotlex] @@ -9853,26 +9819,26 @@ void clif_parse_GetCharNameRequest(int fd, struct map_session_data *sd) return; // Block namerequests past view range // 'see people in GM hide' cheat detection - /* disabled due to false positives (network lag + request name of char that's about to hide = race condition) - sc = status_get_sc(bl); +#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) && 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 + pc_get_group_level(sd) < battle_config.hack_info_GM_level ) { char gm_msg[256]; sprintf(gm_msg, "Hack on NameRequest: character '%s' (account: %d) requested the name of an invisible target (id: %d).\n", sd->status.name, sd->status.account_id, id); ShowWarning(gm_msg); // information is sent to all online GMs - intif_wis_message_to_gm(iMap->wisp_server_name, battle_config.hack_info_GM_level, gm_msg); + intif->wis_message_to_gm(map->wisp_server_name, battle_config.hack_info_GM_level, gm_msg); return; } - */ +#endif // 0 clif->charnameack(fd, bl); } -int clif_undisguise_timer(int tid, unsigned int tick, int id, intptr_t data) { +int clif_undisguise_timer(int tid, int64 tick, int id, intptr_t data) { struct map_session_data * sd; - if( (sd = iMap->id2sd(id)) ) { + if( (sd = map->id2sd(id)) ) { sd->fontcolor_tid = INVALID_TIMER; if( sd->fontcolor && sd->disguise == sd->status.class_ ) pc->disguise(sd,-1); @@ -9886,10 +9852,10 @@ int clif_undisguise_timer(int tid, unsigned int tick, int id, intptr_t data) { void clif_parse_GlobalMessage(int fd, struct map_session_data* sd) { const char* text = (char*)RFIFOP(fd,4); - int textlen = RFIFOW(fd,2) - 4; + size_t textlen = RFIFOW(fd,2) - 4; char *name, *message, *fakename = NULL; - int namelen, messagelen; + size_t namelen, messagelen; bool is_fake; @@ -9897,18 +9863,53 @@ void clif_parse_GlobalMessage(int fd, struct map_session_data* sd) if( !clif->process_message(sd, 0, &name, &namelen, &message, &messagelen) ) return; - if( atcommand->parse(fd, sd, message, 1) ) + if( atcommand->exec(fd, sd, message, true) ) return; - if( sd->sc.data[SC_BERSERK] || sd->sc.data[SC__BLOODYLUST] || sd->sc.data[SC_DEEP_SLEEP] || (sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOCHAT) ) + if( !pc->can_talk(sd) ) return; if( battle_config.min_chat_delay ) { //[Skotlex] - if (DIFF_TICK(sd->cantalk_tick, iTimer->gettick()) > 0) + if (DIFF_TICK(sd->cantalk_tick, timer->gettick()) > 0) return; - sd->cantalk_tick = iTimer->gettick() + battle_config.min_chat_delay; + 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( battle_config.idletime_criteria & BCIDLE_CHAT ) + sd->idletime = sockt->last_tick; + if( sd->gcbind ) { clif->chsys_send(sd->gcbind,sd,message); return; @@ -9917,21 +9918,21 @@ void clif_parse_GlobalMessage(int fd, struct map_session_data* sd) unsigned char mylen = 1; if( sd->disguise == -1 ) { - sd->fontcolor_tid = iTimer->add_timer(iTimer->gettick()+5000, clif->undisguise_timer, sd->bl.id, 0); + 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) ) 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 ) { - const struct TimerData *timer; - if( (timer = iTimer->get_timer(sd->fontcolor_tid)) ) { - iTimer->settick_timer(sd->fontcolor_tid, timer->tick+5000); + const struct TimerData *td; + if( (td = timer->get(sd->fontcolor_tid)) ) { + timer->settick(sd->fontcolor_tid, td->tick+5000); } } - + mylen += snprintf(mout, 200, "%s : %s",sd->fakename[0]?sd->fakename:sd->status.name,message); - + WFIFOHEAD(fd,mylen + 12); WFIFOW(fd,0) = 0x2C1; WFIFOW(fd,2) = mylen + 12; @@ -9943,7 +9944,7 @@ void clif_parse_GlobalMessage(int fd, struct map_session_data* sd) WFIFOSET(fd, mylen + 12); return; } - + /** * Fake Name Design by FatalEror (bug report #9) **/ @@ -9974,13 +9975,14 @@ void clif_parse_GlobalMessage(int fd, struct map_session_data* sd) WFIFOW(fd,0) = 0x8e; } 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); + #ifdef PCRE_SUPPORT // trigger listening npcs - iMap->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, text, textlen, &sd->bl); #endif - - // 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); } @@ -9995,7 +9997,7 @@ void clif_parse_MapMove(int fd, struct map_session_data *sd) map_name = (char*)RFIFOP(fd,2); map_name[MAP_NAME_LENGTH_EXT-1]='\0'; sprintf(command, "%cmapmove %s %d %d", atcommand->at_symbol, map_name, RFIFOW(fd,18), RFIFOW(fd,20)); - atcommand->parse(fd, sd, command, 1); + atcommand->exec(fd, sd, command, true); } @@ -10021,7 +10023,7 @@ void clif_changed_dir(struct block_list *bl, enum send_target target) WBUFW(buf,0) = 0x9c; WBUFL(buf,2) = bl->id; WBUFW(buf,6) = bl->type==BL_PC?((TBL_PC*)bl)->head_dir:0; - WBUFB(buf,8) = unit_getdir(bl); + WBUFB(buf,8) = unit->getdir(bl); clif->send(buf, packet_len(0x9c), bl, target); @@ -10070,6 +10072,9 @@ void clif_parse_Emotion(int fd, struct map_session_data *sd) } sd->emotionlasttime = time(NULL); + if( battle_config.idletime_criteria & BCIDLE_EMOTION ) + sd->idletime = sockt->last_tick; + if(battle_config.client_reshuffle_dice && emoticon>=E_DICE1 && emoticon<=E_DICE6) {// re-roll dice emoticon = rnd()%6+E_DICE1; } @@ -10095,26 +10100,27 @@ void clif_user_count(struct map_session_data* sd, int count) { /// /w /who (CZ_REQ_USER_COUNT). /// Request to display amount of currently connected players. /// 00c1 -void clif_parse_HowManyConnections(int fd, struct map_session_data *sd) -{ - clif->user_count(sd, iMap->getusers()); +void clif_parse_HowManyConnections(int fd, struct map_session_data *sd) { + clif->user_count(sd, map->getusers()); } -void clif_parse_ActionRequest_sub(struct map_session_data *sd, int action_type, int target_id, unsigned int tick) -{ +void clif_parse_ActionRequest_sub(struct map_session_data *sd, int action_type, int target_id, int64 tick) { + struct block_list *target = NULL; + if (pc_isdead(sd)) { clif->clearunit_area(&sd->bl, CLR_DEAD); return; } - if (sd->sc.count && - (sd->sc.data[SC_TRICKDEAD] || - sd->sc.data[SC_AUTOCOUNTER] || - sd->sc.data[SC_BLADESTOP] || - sd->sc.data[SC__MANHOLE] || - sd->sc.data[SC_CURSEDCIRCLE_ATKER] || - sd->sc.data[SC_CURSEDCIRCLE_TARGET] )) + // Statuses that don't let the player sit / attack / talk with NPCs(targeted) + // (not all are included in pc_can_attack) + if( sd->sc.count && ( + sd->sc.data[SC_TRICKDEAD] || + (sd->sc.data[SC_AUTOCOUNTER] && action_type != 0x07) || + sd->sc.data[SC_BLADESTOP] || + sd->sc.data[SC_DEEP_SLEEP] ) + ) return; pc_stop_walking(sd, 1); @@ -10127,13 +10133,15 @@ void clif_parse_ActionRequest_sub(struct map_session_data *sd, int action_type, case 0x00: // once attack case 0x07: // continuous attack - if( pc_cant_act(sd) || sd->sc.option&OPTION_HIDE ) + if( (target = map->id2bl(target_id)) && target->type == BL_NPC ) { + npc->click(sd,(TBL_NPC*)target); return; - - if( sd->sc.option&(OPTION_WEDDING|OPTION_XMAS|OPTION_SUMMER|OPTION_HANBOK) ) + } + + if( pc_cant_act(sd) || pc_issit(sd) || sd->sc.option&OPTION_HIDE ) return; - if( sd->sc.data[SC_BASILICA] || sd->sc.data[SC__SHADOWFORM] ) + if( sd->sc.option&OPTION_COSTUME ) return; if (!battle_config.sdelay_attack_enable && pc->checkskill(sd, SA_FREECAST) <= 0) { @@ -10144,8 +10152,9 @@ void clif_parse_ActionRequest_sub(struct map_session_data *sd, int action_type, } pc->delinvincibletimer(sd); - sd->idletime = last_tick; - unit_attack(&sd->bl, target_id, action_type != 0); + if( battle_config.idletime_criteria & BCIDLE_ATTACK ) + sd->idletime = sockt->last_tick; + unit->attack(&sd->bl, target_id, action_type != 0); break; case 0x02: // sitdown if (battle_config.basic_skill_check && pc->checkskill(sd, NV_BASIC) < 3) { @@ -10168,6 +10177,9 @@ void clif_parse_ActionRequest_sub(struct map_session_data *sd, int action_type, )) //No sitting during these states either. break; + if( battle_config.idletime_criteria & BCIDLE_SIT ) + sd->idletime = sockt->last_tick; + pc_setsit(sd); skill->sit(sd,1); clif->sitting(&sd->bl); @@ -10178,6 +10190,10 @@ void clif_parse_ActionRequest_sub(struct map_session_data *sd, int action_type, clif->standing(&sd->bl); return; } + + if( battle_config.idletime_criteria & BCIDLE_SIT ) + sd->idletime = sockt->last_tick; + pc->setstand(sd); skill->sit(sd,0); clif->standing(&sd->bl); @@ -10187,13 +10203,13 @@ void clif_parse_ActionRequest_sub(struct map_session_data *sd, int action_type, void clif_hercules_chsys_left(struct hChSysCh *channel, struct map_session_data *sd) { unsigned char i; - + if ( !idb_remove(channel->users,sd->status.char_id) ) return; - + if( channel == sd->gcbind ) sd->gcbind = NULL; - + if( !db_size(channel->users) && channel->type == hChSys_PRIVATE ) { clif->chsys_delete(channel); } else if( !hChSys.closing && (channel->opt & hChSys_OPT_ANNOUNCE_JOIN) ) { @@ -10201,14 +10217,14 @@ void clif_hercules_chsys_left(struct hChSysCh *channel, struct map_session_data sprintf(message, "#%s '%s' left",channel->name,sd->status.name); clif->chsys_msg(channel,sd,message); } - + for( i = 0; i < sd->channel_count; i++ ) { if( sd->channels[i] == channel ) { sd->channels[i] = NULL; break; } } - + if( i < sd->channel_count ) { unsigned char cursor = 0; for( i = 0; i < sd->channel_count; i++ ) { @@ -10230,16 +10246,16 @@ void clif_hercules_chsys_left(struct hChSysCh *channel, struct map_session_data void clif_hercules_chsys_quitg(struct map_session_data *sd) { unsigned char i; struct hChSysCh *channel = NULL; - + for( i = 0; i < sd->channel_count; i++ ) { if( (channel = sd->channels[i] ) != NULL && channel->type == hChSys_ALLY ) { - + if ( !idb_remove(channel->users,sd->status.char_id) ) continue; - + if( channel == sd->gcbind ) sd->gcbind = NULL; - + if( !db_size(channel->users) && channel->type == hChSys_PRIVATE ) { clif->chsys_delete(channel); } else if( !hChSys.closing && (channel->opt & hChSys_OPT_ANNOUNCE_JOIN) ) { @@ -10250,7 +10266,7 @@ void clif_hercules_chsys_quitg(struct map_session_data *sd) { sd->channels[i] = NULL; } } - + if( i < sd->channel_count ) { unsigned char cursor = 0; for( i = 0; i < sd->channel_count; i++ ) { @@ -10266,21 +10282,21 @@ void clif_hercules_chsys_quitg(struct map_session_data *sd) { sd->channels = NULL; } } - + } void clif_hercules_chsys_quit(struct map_session_data *sd) { unsigned char i; struct hChSysCh *channel = NULL; - + for( i = 0; i < sd->channel_count; i++ ) { if( (channel = sd->channels[i] ) != NULL ) { idb_remove(channel->users,sd->status.char_id); - + if( channel == sd->gcbind ) sd->gcbind = NULL; - + if( !db_size(channel->users) && channel->type == hChSys_PRIVATE ) { clif->chsys_delete(channel); } else if( !hChSys.closing && (channel->opt & hChSys_OPT_ANNOUNCE_JOIN) ) { @@ -10288,13 +10304,13 @@ void clif_hercules_chsys_quit(struct map_session_data *sd) { sprintf(message, "#%s '%s' left",channel->name,sd->status.name); clif->chsys_msg(channel,sd,message); } - + } } sd->channel_count = 0; aFree(sd->channels); - sd->channels = NULL; + sd->channels = NULL; } /// Request for an action. @@ -10305,7 +10321,7 @@ void clif_hercules_chsys_quit(struct map_session_data *sd) { /// 1 = pick up item /// 2 = sit down /// 3 = stand up -/// 7 = continous attack +/// 7 = continuous attack /// 12 = (touch skill?) /// There are various variants of this packet, some of them have padding between fields. void clif_parse_ActionRequest(int fd, struct map_session_data *sd) @@ -10313,7 +10329,7 @@ void clif_parse_ActionRequest(int fd, struct map_session_data *sd) clif->pActionRequest_sub(sd, RFIFOB(fd,packet_db[RFIFOW(fd,0)].pos[1]), RFIFOL(fd,packet_db[RFIFOW(fd,0)].pos[0]), - iTimer->gettick() + timer->gettick() ); } @@ -10326,14 +10342,14 @@ void clif_parse_ActionRequest(int fd, struct map_session_data *sd) void clif_parse_Restart(int fd, struct map_session_data *sd) { switch(RFIFOB(fd,2)) { case 0x00: - pc->respawn(sd,CLR_RESPAWN); + pc->respawn(sd,CLR_OUTSIGHT); break; case 0x01: /* Rovert's Prevent logout option - Fixed [Valaris] */ - if( !sd->sc.data[SC_CLOAKING] && !sd->sc.data[SC_HIDING] && !sd->sc.data[SC_CHASEWALK] && !sd->sc.data[SC_CLOAKINGEXCEED] && - (!battle_config.prevent_logout || DIFF_TICK(iTimer->gettick(), sd->canlog_tick) > battle_config.prevent_logout) ) + if( !sd->sc.data[SC_CLOAKING] && !sd->sc.data[SC_HIDING] && !sd->sc.data[SC_CHASEWALK] && !sd->sc.data[SC_CLOAKINGEXCEED] && !sd->sc.data[SC__INVISIBILITY] && + (!battle_config.prevent_logout || DIFF_TICK(timer->gettick(), sd->canlog_tick) > battle_config.prevent_logout) ) { //Send to char-server for character selection. - chrif_charselectreq(sd, session[fd]->client_addr); + chrif->charselectreq(sd, session[fd]->client_addr); } else { clif->disconnect_ack(sd, 1); } @@ -10350,25 +10366,29 @@ void clif_parse_WisMessage(int fd, struct map_session_data* sd) int i; char *target, *message; - int namelen, messagelen; + size_t namelen, messagelen; // validate packet and retrieve name and message if( !clif->process_message(sd, 1, &target, &namelen, &message, &messagelen) ) return; - if ( atcommand->parse(fd, sd, message, 1) ) + if ( atcommand->exec(fd, sd, message, true) ) return; - if (sd->sc.data[SC_BERSERK] || sd->sc.data[SC__BLOODYLUST] || sd->sc.data[SC_DEEP_SLEEP] || (sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOCHAT)) + // 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, iTimer->gettick()) > 0) { + if (DIFF_TICK(sd->cantalk_tick, timer->gettick()) > 0) { return; } - sd->cantalk_tick = iTimer->gettick() + battle_config.min_chat_delay; + sd->cantalk_tick = timer->gettick() + battle_config.min_chat_delay; } + if( battle_config.idletime_criteria & BCIDLE_CHAT ) + sd->idletime = sockt->last_tick; + // 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); @@ -10377,8 +10397,8 @@ void clif_parse_WisMessage(int fd, struct map_session_data* sd) //-------------------------------------------------------// if (target[0] && (strncasecmp(target,"NPC:",4) == 0) && (strlen(target) > 4)) { char* str = target+4; //Skip the NPC: string part. - struct npc_data* npc; - if ((npc = npc_name2id(str))) { + struct npc_data *nd; + if ((nd = npc->name2id(str))) { char split_data[NUM_WHISPER_VAR][CHAT_SIZE_MAX]; char *split; char output[256]; @@ -10402,11 +10422,11 @@ void clif_parse_WisMessage(int fd, struct map_session_data* sd) for( i = 0; i < NUM_WHISPER_VAR; ++i ) { sprintf(output, "@whispervar%d$", i); - set_var(sd,output,(char *) split_data[i]); + script->set_var(sd,output,(char *) split_data[i]); } - sprintf(output, "%s::OnWhisperGlobal", npc->exname); - npc_event(sd,output,0); // Calls the NPC label + sprintf(output, "%s::OnWhisperGlobal", nd->exname); + npc->event(sd,output,0); // Calls the NPC label return; } @@ -10415,19 +10435,19 @@ void clif_parse_WisMessage(int fd, struct map_session_data* sd) char* chname = target; chname++; - + if( hChSys.local && strcmpi(chname, hChSys.local_name) == 0 ) { - if( !map[sd->bl.m].channel ) { + if( !map->list[sd->bl.m].channel ) { clif->chsys_mjoin(sd); } - channel = map[sd->bl.m].channel; + channel = map->list[sd->bl.m].channel; } else if( hChSys.ally && sd->status.guild_id && strcmpi(chname, hChSys.ally_name) == 0 ) { struct guild *g = sd->guild; if( !g ) return; - channel = (struct hChSysCh *)g->channel; + channel = g->channel; } if( channel || (channel = strdb_get(clif->channel_db,chname)) ) { - unsigned char k; + int k; for( k = 0; k < sd->channel_count; k++ ) { if( sd->channels[k] == channel ) break; @@ -10437,11 +10457,10 @@ void clif_parse_WisMessage(int fd, struct map_session_data* sd) } else if( channel->pass[0] == '\0' && !(channel->banned && idb_exists(channel->banned, sd->status.account_id)) ) { if( channel->type == hChSys_ALLY ) { struct guild *g = sd->guild, *sg = NULL; - int k; for (k = 0; k < MAX_GUILDALLIANCE; k++) { if( g->alliance[k].opposition == 0 && g->alliance[k].guild_id && (sg = guild->search(g->alliance[k].guild_id) ) ) { - if( !(((struct hChSysCh*)sg->channel)->banned && idb_exists(((struct hChSysCh*)sg->channel)->banned, sd->status.account_id))) - clif->chsys_join((struct hChSysCh *)sg->channel,sd); + if( !(sg->channel->banned && idb_exists(sg->channel->banned, sd->status.account_id))) + clif->chsys_join(sg->channel,sd); } } } @@ -10455,7 +10474,7 @@ void clif_parse_WisMessage(int fd, struct map_session_data* sd) } // searching destination character - dstsd = iMap->nick2sd(target); + dstsd = map->nick2sd(target); if (dstsd == NULL || strcmp(dstsd->status.name, target) != 0) { // player is not on this map-server @@ -10463,14 +10482,14 @@ 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, messagelen); return; } // if player ignores everyone - if (dstsd->state.ignoreAll) { - if (dstsd->sc.option & OPTION_INVISIBLE && pc->get_group_level(sd) < pc->get_group_level(dstsd)) - clif->wis_end(fd, 1); // 1: target character is not loged in + if (dstsd->state.ignoreAll && pc_get_group_level(sd) <= pc_get_group_level(dstsd)) { + if (dstsd->sc.option & OPTION_INVISIBLE && pc_get_group_level(sd) < pc_get_group_level(dstsd)) + clif->wis_end(fd, 1); // 1: target character is not logged in else clif->wis_end(fd, 3); // 3: everyone ignored by target return; @@ -10480,15 +10499,17 @@ void clif_parse_WisMessage(int fd, struct map_session_data* sd) if( dstsd->state.autotrade == 1 ) { char output[256]; sprintf(output, "%s is in autotrade mode and cannot receive whispered messages.", dstsd->status.name); - clif->wis_message(fd, iMap->wisp_server_name, output, strlen(output) + 1); + clif->wis_message(fd, map->wisp_server_name, output, strlen(output) + 1); return; } - // if player ignores the source character - ARR_FIND(0, MAX_IGNORE_LIST, i, dstsd->ignore[i].name[0] == '\0' || strcmp(dstsd->ignore[i].name, sd->status.name) == 0); - if(i < MAX_IGNORE_LIST && dstsd->ignore[i].name[0] != '\0') { // source char present in ignore list - clif->wis_end(fd, 2); // 2: ignored by target - return; + if( pc_get_group_level(sd) <= pc_get_group_level(dstsd) ) { + // if player ignores the source character + ARR_FIND(0, MAX_IGNORE_LIST, i, dstsd->ignore[i].name[0] == '\0' || strcmp(dstsd->ignore[i].name, sd->status.name) == 0); + if(i < MAX_IGNORE_LIST && dstsd->ignore[i].name[0] != '\0') { // source char present in ignore list + clif->wis_end(fd, 2); // 2: ignored by target + return; + } } // notify sender of success @@ -10511,7 +10532,7 @@ void clif_parse_Broadcast(int fd, struct map_session_data* sd) { mes_len_check(msg, len, CHAT_SIZE_MAX); sprintf(command, "%ckami %s", atcommand->at_symbol, msg); - atcommand->parse(fd, sd, command, 1); + atcommand->exec(fd, sd, command, true); } @@ -10519,14 +10540,13 @@ void clif_parse_Broadcast(int fd, struct map_session_data* sd) { /// 009f <id>.L (CZ_ITEM_PICKUP) /// 0362 <id>.L (CZ_ITEM_PICKUP2) /// There are various variants of this packet, some of them have padding between fields. -void clif_parse_TakeItem(int fd, struct map_session_data *sd) -{ +void clif_parse_TakeItem(int fd, struct map_session_data *sd) { struct flooritem_data *fitem; int map_object_id; map_object_id = RFIFOL(fd,packet_db[RFIFOW(fd,0)].pos[0]); - fitem = (struct flooritem_data*)iMap->id2bl(map_object_id); + fitem = (struct flooritem_data*)map->id2bl(map_object_id); do { if (pc_isdead(sd)) { @@ -10586,6 +10606,9 @@ void clif_parse_DropItem(int fd, struct map_session_data *sd) if (!pc->dropitem(sd, item_index, item_amount)) break; + if( battle_config.idletime_criteria & BCIDLE_DROPITEM ) + sd->idletime = sockt->last_tick; + return; } @@ -10611,7 +10634,8 @@ void clif_parse_UseItem(int fd, struct map_session_data *sd) return; //Whether the item is used or not is irrelevant, the char ain't idle. [Skotlex] - sd->idletime = last_tick; + if( battle_config.idletime_criteria & BCIDLE_USEITEM ) + sd->idletime = sockt->last_tick; n = RFIFOW(fd,packet_db[RFIFOW(fd,0)].pos[0])-2; if(n <0 || n >= MAX_INVENTORY) @@ -10623,16 +10647,17 @@ void clif_parse_UseItem(int fd, struct map_session_data *sd) /// Request to equip an item (CZ_REQ_WEAR_EQUIP). /// 00a9 <index>.W <position>.W -void clif_parse_EquipItem(int fd,struct map_session_data *sd) -{ - int index; +/// 0998 <index>.W <position>.L +void clif_parse_EquipItem(int fd,struct map_session_data *sd) { + struct packet_equip_item *p = P2PTR(fd); if(pc_isdead(sd)) { clif->clearunit_area(&sd->bl,CLR_DEAD); return; } - index = RFIFOW(fd,2)-2; - if (index < 0 || index >= MAX_INVENTORY) + + p->index = p->index - 2; + if (p->index >= MAX_INVENTORY) return; //Out of bounds check. if( sd->npc_id ) { @@ -10643,24 +10668,27 @@ void clif_parse_EquipItem(int fd,struct map_session_data *sd) else if ( pc_cant_act2(sd) || sd->state.prerefining ) return; - if(!sd->status.inventory[index].identify) { - clif->equipitemack(sd,index,0,0); // fail + if(!sd->status.inventory[p->index].identify) { + clif->equipitemack(sd,p->index,0,EIA_FAIL);// fail return; } - if(!sd->inventory_data[index]) + if(!sd->inventory_data[p->index]) return; - if(sd->inventory_data[index]->type == IT_PETARMOR){ - pet_equipitem(sd,index); + if(sd->inventory_data[p->index]->type == IT_PETARMOR){ + pet->equipitem(sd,p->index); return; } + if( battle_config.idletime_criteria & BCIDLE_USEITEM ) + sd->idletime = sockt->last_tick; + //Client doesn't send the position for ammo. - if(sd->inventory_data[index]->type == IT_AMMO) - pc->equipitem(sd,index,EQP_AMMO); + if(sd->inventory_data[p->index]->type == IT_AMMO) + pc->equipitem(sd,p->index,EQP_AMMO); else - pc->equipitem(sd,index,RFIFOW(fd,4)); + pc->equipitem(sd,p->index,p->wearLocation); } void clif_hercules_chsys_delete(struct hChSysCh *channel) { @@ -10700,7 +10728,7 @@ void clif_hercules_chsys_delete(struct hChSysCh *channel) { } db_destroy(channel->users); if( channel->m ) { - map[channel->m].channel = NULL; + map->list[channel->m].channel = NULL; aFree(channel); } else if ( channel->type == hChSys_ALLY ) aFree(channel); @@ -10711,20 +10739,20 @@ void clif_hercules_chsys_gjoin(struct guild *g1,struct guild *g2) { struct map_session_data *sd; struct hChSysCh *channel; int j; - - if( (channel = (struct hChSysCh*)g1->channel) ) { + + if( (channel = g1->channel) ) { for(j = 0; j < g2->max_member; j++) { if( (sd = g2->member[j].sd) != NULL ) { - if( !(((struct hChSysCh*)g1->channel)->banned && idb_exists(((struct hChSysCh*)g1->channel)->banned, sd->status.account_id))) + if( !(g1->channel->banned && idb_exists(g1->channel->banned, sd->status.account_id))) clif->chsys_join(channel,sd); } } } - - if( (channel = (struct hChSysCh*)g2->channel) ) { + + if( (channel = g2->channel) ) { for(j = 0; j < g1->max_member; j++) { if( (sd = g1->member[j].sd) != NULL ) { - if( !(((struct hChSysCh*)g2->channel)->banned && idb_exists(((struct hChSysCh*)g2->channel)->banned, sd->status.account_id))) + if( !(g2->channel->banned && idb_exists(g2->channel->banned, sd->status.account_id))) clif->chsys_join(channel,sd); } } @@ -10734,16 +10762,16 @@ void clif_hercules_chsys_gleave(struct guild *g1,struct guild *g2) { struct map_session_data *sd; struct hChSysCh *channel; int j; - - if( (channel = (struct hChSysCh*)g1->channel) ) { + + if( (channel = g1->channel) ) { for(j = 0; j < g2->max_member; j++) { if( (sd = g2->member[j].sd) != NULL ) { clif->chsys_left(channel,sd); } } } - - if( (channel = (struct hChSysCh*)g2->channel) ) { + + if( (channel = g2->channel) ) { for(j = 0; j < g1->max_member; j++) { if( (sd = g1->member[j].sd) != NULL ) { clif->chsys_left(channel,sd); @@ -10773,6 +10801,9 @@ void clif_parse_UnequipItem(int fd,struct map_session_data *sd) index = RFIFOW(fd,2)-2; + if( battle_config.idletime_criteria & BCIDLE_USEITEM ) + sd->idletime = sockt->last_tick; + pc->unequipitem(sd,index,1); } @@ -10795,13 +10826,13 @@ void clif_parse_NpcClicked(int fd,struct map_session_data *sd) #endif return; } - if ( pc_cant_act2(sd) || !(bl = iMap->id2bl(RFIFOL(fd,2))) || sd->state.vending ) + if ( pc_cant_act2(sd) || !(bl = map->id2bl(RFIFOL(fd,2))) || sd->state.vending ) return; - + switch (bl->type) { case BL_MOB: case BL_PC: - clif->pActionRequest_sub(sd, 0x07, bl->id, iTimer->gettick()); + clif->pActionRequest_sub(sd, 0x07, bl->id, timer->gettick()); break; case BL_NPC: if( sd->ud.skill_id < RK_ENCHANTBLADE && sd->ud.skilltimer != INVALID_TIMER ) {// TODO: should only work with none 3rd job skills @@ -10811,7 +10842,7 @@ void clif_parse_NpcClicked(int fd,struct map_session_data *sd) break; } if( bl->m != -1 )// the user can't click floating npcs directly (hack attempt) - npc_click(sd,(TBL_NPC*)bl); + npc->click(sd,(TBL_NPC*)bl); break; } } @@ -10826,7 +10857,7 @@ void clif_parse_NpcBuySellSelected(int fd,struct map_session_data *sd) { if (sd->state.trading) return; - npc_buysellsel(sd,RFIFOL(fd,2),RFIFOB(fd,6)); + npc->buysellsel(sd,RFIFOL(fd,2),RFIFOB(fd,6)); } @@ -10858,7 +10889,7 @@ void clif_parse_NpcBuyListSend(int fd, struct map_session_data* sd) if( sd->state.trading || !sd->npc_shopid ) result = 1; else - result = npc_buylist(sd,n,item_list); + result = npc->buylist(sd,n,item_list); sd->npc_shopid = 0; //Clear shop data. @@ -10894,7 +10925,7 @@ void clif_parse_NpcSellListSend(int fd,struct map_session_data *sd) if (sd->state.trading || !sd->npc_shopid) fail = 1; else - fail = npc_selllist(sd,n,item_list); + fail = npc->selllist(sd,n,item_list); sd->npc_shopid = 0; //Clear shop data. @@ -10923,10 +10954,10 @@ void clif_parse_CreateChatRoom(int fd, struct map_session_data* sd) clif->skill_fail(sd,1,USESKILL_FAIL_LEVEL,3); return; } - if( npc_isnear(&sd->bl) ) { + if( npc->isnear(&sd->bl) ) { // uncomment for more verbose message. //char output[150]; - //sprintf(output, msg_txt(662), battle_config.min_npc_vendchat_distance); + //sprintf(output, msg_txt(862), battle_config.min_npc_vendchat_distance); // "You're too close to a NPC, you must be at least %d cells away from any NPC." //clif_displaymessage(sd->fd, output); clif->skill_fail(sd,1,USESKILL_FAIL_THERE_ARE_NPC_AROUND,0); return; @@ -10938,7 +10969,7 @@ void clif_parse_CreateChatRoom(int fd, struct map_session_data* sd) safestrncpy(s_password, password, CHATROOM_PASS_SIZE); safestrncpy(s_title, title, min(len+1,CHATROOM_TITLE_SIZE)); //NOTE: assumes that safestrncpy will not access the len+1'th byte - chat_createpcchat(sd, s_title, s_password, limit, pub); + chat->create_pc_chat(sd, s_title, s_password, limit, pub); } @@ -10949,7 +10980,7 @@ void clif_parse_ChatAddMember(int fd, struct map_session_data* sd) int chatid = RFIFOL(fd,2); const char* password = (char*)RFIFOP(fd,6); // not zero-terminated - chat_joinchat(sd,chatid,password); + chat->join(sd,chatid,password); } @@ -10974,7 +11005,7 @@ void clif_parse_ChatRoomStatusChange(int fd, struct map_session_data* sd) safestrncpy(s_password, password, CHATROOM_PASS_SIZE); safestrncpy(s_title, title, min(len+1,CHATROOM_TITLE_SIZE)); //NOTE: assumes that safestrncpy will not access the len+1'th byte - chat_changechatstatus(sd, s_title, s_password, limit, pub); + chat->change_status(sd, s_title, s_password, limit, pub); } @@ -10985,7 +11016,7 @@ void clif_parse_ChatRoomStatusChange(int fd, struct map_session_data* sd) /// 1 = normal void clif_parse_ChangeChatOwner(int fd, struct map_session_data* sd) { - chat_changechatowner(sd,(char*)RFIFOP(fd,6)); + chat->change_owner(sd,(char*)RFIFOP(fd,6)); } @@ -10993,7 +11024,7 @@ void clif_parse_ChangeChatOwner(int fd, struct map_session_data* sd) /// 00e2 <name>.24B void clif_parse_KickFromChat(int fd,struct map_session_data *sd) { - chat_kickchat(sd,(char*)RFIFOP(fd,2)); + chat->kick(sd,(char*)RFIFOP(fd,2)); } @@ -11001,11 +11032,11 @@ void clif_parse_KickFromChat(int fd,struct map_session_data *sd) /// 00e3 void clif_parse_ChatLeave(int fd, struct map_session_data* sd) { - chat_leavechat(sd,0); + chat->leave(sd,0); } -//Handles notifying asker and rejecter of what has just ocurred. +//Handles notifying asker and rejecter of what has just occurred. //Type is used to determine the correct msg_txt to use: //0: void clif_noask_sub(struct map_session_data *src, struct map_session_data *target, int type) { @@ -11013,20 +11044,19 @@ void clif_noask_sub(struct map_session_data *src, struct map_session_data *targe char output[256]; // Your request has been rejected by autoreject option. msg = msg_txt(392); - clif->disp_onlyself(src, msg, strlen(msg)); + clif_disp_onlyself(src, msg, strlen(msg)); //Notice that a request was rejected. snprintf(output, 256, msg_txt(393+type), src->status.name, 256); - clif->disp_onlyself(target, output, strlen(output)); + clif_disp_onlyself(target, output, strlen(output)); } /// Request to begin a trade (CZ_REQ_EXCHANGE_ITEM). /// 00e4 <account id>.L -void clif_parse_TradeRequest(int fd,struct map_session_data *sd) -{ +void clif_parse_TradeRequest(int fd,struct map_session_data *sd) { struct map_session_data *t_sd; - t_sd = iMap->id2sd(RFIFOL(fd,2)); + t_sd = map->id2sd(RFIFOL(fd,2)); if(!sd->chatID && pc_cant_act(sd)) return; //You can trade while in a chatroom. @@ -11105,13 +11135,16 @@ void clif_parse_StopAttack(int fd,struct map_session_data *sd) /// Request to move an item from inventory to cart (CZ_MOVE_ITEM_FROM_BODY_TO_CART). /// 0126 <index>.W <amount>.L -void clif_parse_PutItemToCart(int fd,struct map_session_data *sd) -{ +void clif_parse_PutItemToCart(int fd,struct map_session_data *sd) { + int flag = 0; if (pc_istrading(sd)) return; if (!pc_iscarton(sd)) return; - pc->putitemtocart(sd,RFIFOW(fd,2)-2,RFIFOL(fd,4)); + if ( (flag = pc->putitemtocart(sd,RFIFOW(fd,2)-2,RFIFOL(fd,4))) ) { + clif->dropitem(sd, RFIFOW(fd,2)-2,0); + clif->cart_additem_ack(sd,flag == 1?0x0:0x1); + } } @@ -11129,16 +11162,16 @@ void clif_parse_GetItemFromCart(int fd,struct map_session_data *sd) /// 012a void clif_parse_RemoveOption(int fd,struct map_session_data *sd) { - /** - * Attempts to remove these options when this function is called (will remove all available) - **/ + if( !(sd->sc.option&(OPTION_RIDING|OPTION_FALCON|OPTION_DRAGON|OPTION_MADOGEAR)) #ifdef NEW_CARTS - pc->setoption(sd,sd->sc.option&~(OPTION_RIDING|OPTION_FALCON|OPTION_DRAGON|OPTION_MADOGEAR)); - if( sd->sc.data[SC_PUSH_CART] ) + && sd->sc.data[SC_PUSH_CART] ){ pc->setcart(sd,0); #else - pc->setoption(sd,sd->sc.option&~(OPTION_CART|OPTION_RIDING|OPTION_FALCON|OPTION_DRAGON|OPTION_MADOGEAR)); + ){ + pc->setoption(sd,sd->sc.option&~OPTION_CART); #endif + }else // priority to remove this option before we can clear cart + pc->setoption(sd,sd->sc.option&~(OPTION_RIDING|OPTION_FALCON|OPTION_DRAGON|OPTION_MADOGEAR)); } @@ -11148,8 +11181,17 @@ void clif_parse_ChangeCart(int fd,struct map_session_data *sd) {// TODO: State tracking? int type; - if( sd && pc->checkskill(sd, MC_CHANGECART) < 1 ) + nullpo_retv(sd); + + if( pc->checkskill(sd, MC_CHANGECART) < 1 ) + return; + +#ifdef RENEWAL + if( sd->npc_id || sd->state.workinprogress&1 ){ + clif->msg(sd, 0x783); return; + } +#endif type = (int)RFIFOW(fd,2); #ifdef NEW_CARTS @@ -11178,11 +11220,18 @@ void clif_parse_ChangeCart(int fd,struct map_session_data *sd) /// status id: /// SP_STR ~ SP_LUK /// amount: -/// client sends always 1 for this, even when using /str+ and -/// the like -void clif_parse_StatusUp(int fd,struct map_session_data *sd) -{ - pc->statusup(sd,RFIFOW(fd,2)); +/// Old clients send always 1 for this, even when using /str+ and the like. +/// Newer clients (2013-12-23 and newer) send the correct amount. +void clif_parse_StatusUp(int fd,struct map_session_data *sd) { + int increase_amount; + + increase_amount = RFIFOB(fd,4); + if( increase_amount < 0 ) + { + ShowDebug("clif_parse_StatusUp: Negative 'increase' value sent by client! (fd: %d, value: %d)\n", + fd, increase_amount); + } + pc->statusup(sd, RFIFOW(fd,2), increase_amount); } @@ -11193,8 +11242,7 @@ void clif_parse_SkillUp(int fd,struct map_session_data *sd) pc->skillup(sd,RFIFOW(fd,2)); } -void clif_parse_UseSkillToId_homun(struct homun_data *hd, struct map_session_data *sd, unsigned int tick, uint16 skill_id, uint16 skill_lv, int target_id) -{ +void clif_parse_UseSkillToId_homun(struct homun_data *hd, struct map_session_data *sd, int64 tick, uint16 skill_id, uint16 skill_lv, int target_id) { int lv; if( !hd ) @@ -11212,11 +11260,10 @@ void clif_parse_UseSkillToId_homun(struct homun_data *hd, struct map_session_dat if( skill_lv > lv ) skill_lv = lv; if( skill_lv ) - unit_skilluse_id(&hd->bl, target_id, skill_id, skill_lv); + unit->skilluse_id(&hd->bl, target_id, skill_id, skill_lv); } -void clif_parse_UseSkillToPos_homun(struct homun_data *hd, struct map_session_data *sd, unsigned int tick, uint16 skill_id, uint16 skill_lv, short x, short y, int skillmoreinfo) -{ +void clif_parse_UseSkillToPos_homun(struct homun_data *hd, struct map_session_data *sd, int64 tick, uint16 skill_id, uint16 skill_lv, short x, short y, int skillmoreinfo) { int lv; if( !hd ) return; @@ -11233,11 +11280,10 @@ void clif_parse_UseSkillToPos_homun(struct homun_data *hd, struct map_session_da if( skill_lv > lv ) skill_lv = lv; if( skill_lv ) - unit_skilluse_pos(&hd->bl, x, y, skill_id, skill_lv); + unit->skilluse_pos(&hd->bl, x, y, skill_id, skill_lv); } -void clif_parse_UseSkillToId_mercenary(struct mercenary_data *md, struct map_session_data *sd, unsigned int tick, uint16 skill_id, uint16 skill_lv, int target_id) -{ +void clif_parse_UseSkillToId_mercenary(struct mercenary_data *md, struct map_session_data *sd, int64 tick, uint16 skill_id, uint16 skill_lv, int target_id) { int lv; if( !md ) @@ -11251,15 +11297,14 @@ void clif_parse_UseSkillToId_mercenary(struct mercenary_data *md, struct map_ses } else if( DIFF_TICK(tick, md->ud.canact_tick) < 0 ) return; - lv = mercenary_checkskill(md, skill_id); + lv = mercenary->checkskill(md, skill_id); if( skill_lv > lv ) skill_lv = lv; if( skill_lv ) - unit_skilluse_id(&md->bl, target_id, skill_id, skill_lv); + unit->skilluse_id(&md->bl, target_id, skill_id, skill_lv); } -void clif_parse_UseSkillToPos_mercenary(struct mercenary_data *md, struct map_session_data *sd, unsigned int tick, uint16 skill_id, uint16 skill_lv, short x, short y, int skillmoreinfo) -{ +void clif_parse_UseSkillToPos_mercenary(struct mercenary_data *md, struct map_session_data *sd, int64 tick, uint16 skill_id, uint16 skill_lv, short x, short y, int skillmoreinfo) { int lv; if( !md ) return; @@ -11274,11 +11319,11 @@ void clif_parse_UseSkillToPos_mercenary(struct mercenary_data *md, struct map_se if( md->sc.data[SC_BASILICA] ) return; - lv = mercenary_checkskill(md, skill_id); + lv = mercenary->checkskill(md, skill_id); if( skill_lv > lv ) skill_lv = lv; if( skill_lv ) - unit_skilluse_pos(&md->bl, x, y, skill_id, skill_lv); + unit->skilluse_pos(&md->bl, x, y, skill_id, skill_lv); } @@ -11290,7 +11335,7 @@ void clif_parse_UseSkillToId(int fd, struct map_session_data *sd) { uint16 skill_id, skill_lv; int tmp, target_id; - unsigned int tick = iTimer->gettick(); + int64 tick = timer->gettick(); skill_lv = RFIFOW(fd,packet_db[RFIFOW(fd,0)].pos[0]); skill_id = RFIFOW(fd,packet_db[RFIFOW(fd,0)].pos[1]); @@ -11313,7 +11358,8 @@ void clif_parse_UseSkillToId(int fd, struct map_session_data *sd) } // Whether skill fails or not is irrelevant, the char ain't idle. [Skotlex] - sd->idletime = last_tick; + if( battle_config.idletime_criteria & BCIDLE_USESKILLTOID ) + sd->idletime = sockt->last_tick; if( sd->npc_id || sd->state.workinprogress&1 ){ #ifdef RENEWAL @@ -11321,8 +11367,14 @@ void clif_parse_UseSkillToId(int fd, struct map_session_data *sd) #endif return; } - if( pc_cant_act(sd) && skill_id != RK_REFRESH && !(skill_id == SR_GENTLETOUCH_CURE && (sd->sc.opt1 == OPT1_STONE || sd->sc.opt1 == OPT1_FREEZE || sd->sc.opt1 == OPT1_STUN)) ) + + if( pc_cant_act(sd) + && skill_id != RK_REFRESH + && !(skill_id == SR_GENTLETOUCH_CURE && (sd->sc.opt1 == OPT1_STONE || sd->sc.opt1 == OPT1_FREEZE || sd->sc.opt1 == OPT1_STUN)) + && ( sd->state.storage_flag && !(tmp&INF_SELF_SKILL) ) // SELF skills can be used with the storage open, issue: 8027 + ) return; + if( pc_issit(sd) ) return; @@ -11345,7 +11397,7 @@ void clif_parse_UseSkillToId(int fd, struct map_session_data *sd) } } - if( sd->sc.option&(OPTION_WEDDING|OPTION_XMAS|OPTION_SUMMER|OPTION_HANBOK) ) + if( sd->sc.option&OPTION_COSTUME ) return; if( sd->sc.data[SC_BASILICA] && (skill_id != HP_BASILICA || sd->sc.data[SC_BASILICA]->val4 != sd->bl.id) ) @@ -11362,7 +11414,7 @@ void clif_parse_UseSkillToId(int fd, struct map_session_data *sd) skill_lv = sd->skillitemlv; if( !(tmp&INF_SELF_SKILL) ) pc->delinvincibletimer(sd); // Target skills thru items cancel invincibility. [Inkfish] - unit_skilluse_id(&sd->bl, target_id, skill_id, skill_lv); + unit->skilluse_id(&sd->bl, target_id, skill_id, skill_lv); return; } @@ -11370,7 +11422,7 @@ void clif_parse_UseSkillToId(int fd, struct map_session_data *sd) if( skill_id >= GD_SKILLBASE ) { if( sd->state.gmaster_flag ) - skill_lv = guild->checkskill(sd->state.gmaster_flag, skill_id); + skill_lv = guild->checkskill(sd->guild, skill_id); else skill_lv = 0; } else { @@ -11382,7 +11434,7 @@ void clif_parse_UseSkillToId(int fd, struct map_session_data *sd) pc->delinvincibletimer(sd); if( skill_lv ) - unit_skilluse_id(&sd->bl, target_id, skill_id, skill_lv); + unit->skilluse_id(&sd->bl, target_id, skill_id, skill_lv); } /*========================================== @@ -11390,7 +11442,7 @@ void clif_parse_UseSkillToId(int fd, struct map_session_data *sd) *------------------------------------------*/ void clif_parse_UseSkillToPosSub(int fd, struct map_session_data *sd, uint16 skill_lv, uint16 skill_id, short x, short y, int skillmoreinfo) { - unsigned int tick = iTimer->gettick(); + int64 tick = timer->gettick(); if( !(skill->get_inf(skill_id)&INF_GROUND_SKILL) ) return; //Using a target skill on the ground? WRONG. @@ -11404,9 +11456,17 @@ void clif_parse_UseSkillToPosSub(int fd, struct map_session_data *sd, uint16 ski clif->pUseSkillToPos_mercenary(sd->md, sd, tick, skill_id, skill_lv, x, y, skillmoreinfo); return; } + +#ifdef RENEWAL + if( sd->state.workinprogress&1 ){ + clif->msg(sd, 0x783); // TODO look for the client date that has this message. + return; + } +#endif //Whether skill fails or not is irrelevant, the char ain't idle. [Skotlex] - sd->idletime = last_tick; + if( battle_config.idletime_criteria & BCIDLE_USESKILLTOPOS ) + sd->idletime = sockt->last_tick; if( skill->not_ok(skill_id, sd) ) return; @@ -11429,7 +11489,7 @@ void clif_parse_UseSkillToPosSub(int fd, struct map_session_data *sd, uint16 ski } } - if( sd->sc.option&(OPTION_WEDDING|OPTION_XMAS|OPTION_SUMMER|OPTION_HANBOK) ) + if( sd->sc.option&OPTION_COSTUME ) return; if( sd->sc.data[SC_BASILICA] && (skill_id != HP_BASILICA || sd->sc.data[SC_BASILICA]->val4 != sd->bl.id) ) @@ -11447,14 +11507,14 @@ void clif_parse_UseSkillToPosSub(int fd, struct map_session_data *sd, uint16 ski if( sd->skillitem == skill_id ) { if( skill_lv != sd->skillitemlv ) skill_lv = sd->skillitemlv; - unit_skilluse_pos(&sd->bl, x, y, skill_id, skill_lv); + unit->skilluse_pos(&sd->bl, x, y, skill_id, skill_lv); } else { int lv; sd->skillitem = sd->skillitemlv = 0; if( (lv = pc->checkskill(sd, skill_id)) > 0 ) { if( skill_lv > lv ) skill_lv = lv; - unit_skilluse_pos(&sd->bl, x, y, skill_id,skill_lv); + unit->skilluse_pos(&sd->bl, x, y, skill_id,skill_lv); } } } @@ -11508,12 +11568,15 @@ void clif_parse_UseSkillMap(int fd, struct map_session_data* sd) { uint16 skill_id = RFIFOW(fd,2); char map_name[MAP_NAME_LENGTH]; - mapindex_getmapname((char*)RFIFOP(fd,4), map_name); + + mapindex->getmapname((char*)RFIFOP(fd,4), map_name); + sd->state.workinprogress = 0; if(skill_id != sd->menuskill_id) return; - if( pc_cant_act(sd) ) { + // It is possible to use teleport with the storage window open issue:8027 + if( pc_cant_act(sd) && (!sd->state.storage_flag && skill_id != AL_TELEPORT) ) { clif_menuskill_clear(sd); return; } @@ -11640,7 +11703,7 @@ void clif_parse_NpcSelectMenu(int fd,struct map_session_data *sd) #ifdef SECURE_NPCTIMEOUT if( sd->npc_idle_timer != INVALID_TIMER ) { #endif - TBL_NPC* nd = iMap->id2nd(npc_id); + TBL_NPC* nd = map->id2nd(npc_id); ShowWarning("Invalid menu selection on npc %d:'%s' - got %d, valid range is [%d..%d] (player AID:%d, CID:%d, name:'%s')!\n", npc_id, (nd)?nd->name:"invalid npc id", select, 1, sd->npc_menu, sd->bl.id, sd->status.char_id, sd->status.name); clif->GM_kick(NULL,sd); #ifdef SECURE_NPCTIMEOUT @@ -11650,7 +11713,7 @@ void clif_parse_NpcSelectMenu(int fd,struct map_session_data *sd) } sd->npc_menu = select; - npc_scriptcont(sd,npc_id, false); + npc->scriptcont(sd,npc_id, false); } @@ -11658,7 +11721,7 @@ void clif_parse_NpcSelectMenu(int fd,struct map_session_data *sd) /// 00b9 <npc id>.L void clif_parse_NpcNextClicked(int fd,struct map_session_data *sd) { - npc_scriptcont(sd,RFIFOL(fd,2), false); + npc->scriptcont(sd,RFIFOL(fd,2), false); } @@ -11670,7 +11733,7 @@ void clif_parse_NpcAmountInput(int fd,struct map_session_data *sd) int amount = (int)RFIFOL(fd,6); sd->npc_amount = amount; - npc_scriptcont(sd, npcid, false); + npc->scriptcont(sd, npcid, false); } @@ -11686,7 +11749,7 @@ void clif_parse_NpcStringInput(int fd, struct map_session_data* sd) return; // invalid input safestrncpy(sd->npc_str, message, min(message_len,CHATBOX_SIZE)); - npc_scriptcont(sd, npcid, false); + npc->scriptcont(sd, npcid, false); } @@ -11696,7 +11759,7 @@ void clif_parse_NpcCloseClicked(int fd,struct map_session_data *sd) { if (!sd->npc_id) //Avoid parsing anything when the script was done with. [Skotlex] return; - npc_scriptcont(sd, RFIFOL(fd,2), true); + npc->scriptcont(sd, RFIFOL(fd,2), true); } @@ -11757,9 +11820,17 @@ void clif_parse_SelectArrow(int fd,struct map_session_data *sd) /// 01ce <skill id>.L void clif_parse_AutoSpell(int fd,struct map_session_data *sd) { - if (sd->menuskill_id != SA_AUTOSPELL) + uint16 skill_id = RFIFOL(fd,2); + + sd->state.workinprogress = 0; + + if( sd->menuskill_id != SA_AUTOSPELL ) + return; + + if( !skill_id ) return; - skill->autospell(sd,RFIFOL(fd,2)); + + skill->autospell(sd, skill_id); clif_menuskill_clear(sd); } @@ -11788,12 +11859,11 @@ void clif_parse_InsertCard(int fd,struct map_session_data *sd) /// 0193 <char id>.L (CZ_REQNAME_BYGID) /// 0369 <char id>.L (CZ_REQNAME_BYGID2) /// There are various variants of this packet, some of them have padding between fields. -void clif_parse_SolveCharName(int fd, struct map_session_data *sd) -{ +void clif_parse_SolveCharName(int fd, struct map_session_data *sd) { int charid; charid = RFIFOL(fd,packet_db[RFIFOW(fd,0)].pos[0]); - iMap->reqnickdb(sd, charid); + map->reqnickdb(sd, charid); } @@ -11807,11 +11877,11 @@ void clif_parse_ResetChar(int fd, struct map_session_data *sd) { char cmd[15]; if( RFIFOW(fd,2) ) - sprintf(cmd,"%cresetskill",atcommand->at_symbol); + sprintf(cmd,"%cskreset",atcommand->at_symbol); else - sprintf(cmd,"%cresetstat",atcommand->at_symbol); + sprintf(cmd,"%cstreset",atcommand->at_symbol); - atcommand->parse(fd, sd, cmd, 1); + atcommand->exec(fd, sd, cmd, true); } @@ -11828,7 +11898,7 @@ void clif_parse_LocalBroadcast(int fd, struct map_session_data* sd) mes_len_check(msg, len, CHAT_SIZE_MAX); sprintf(command, "%clkami %s", atcommand->at_symbol, msg); - atcommand->parse(fd, sd, command, 1); + atcommand->exec(fd, sd, command, true); } @@ -11849,10 +11919,9 @@ void clif_parse_MoveToKafra(int fd, struct map_session_data *sd) return; if (sd->state.storage_flag == 1) - storage_storageadd(sd, item_index, item_amount); - else - if (sd->state.storage_flag == 2) - storage_guild_storageadd(sd, item_index, item_amount); + storage->add(sd, item_index, item_amount); + else if (sd->state.storage_flag == 2) + gstorage->add(sd, item_index, item_amount); } @@ -11868,9 +11937,9 @@ void clif_parse_MoveFromKafra(int fd,struct map_session_data *sd) item_amount = RFIFOL(fd,packet_db[RFIFOW(fd,0)].pos[1]); if (sd->state.storage_flag == 1) - storage_storageget(sd, item_index, item_amount); + storage->get(sd, item_index, item_amount); else if(sd->state.storage_flag == 2) - storage_guild_storageget(sd, item_index, item_amount); + gstorage->get(sd, item_index, item_amount); } @@ -11884,10 +11953,9 @@ void clif_parse_MoveToKafraFromCart(int fd, struct map_session_data *sd) return; if (sd->state.storage_flag == 1) - storage_storageaddfromcart(sd, RFIFOW(fd,2) - 2, RFIFOL(fd,4)); - else - if (sd->state.storage_flag == 2) - storage_guild_storageaddfromcart(sd, RFIFOW(fd,2) - 2, RFIFOL(fd,4)); + storage->addfromcart(sd, RFIFOW(fd,2) - 2, RFIFOL(fd,4)); + else if (sd->state.storage_flag == 2) + gstorage->addfromcart(sd, RFIFOW(fd,2) - 2, RFIFOL(fd,4)); } @@ -11901,10 +11969,9 @@ void clif_parse_MoveFromKafraToCart(int fd, struct map_session_data *sd) return; if (sd->state.storage_flag == 1) - storage_storagegettocart(sd, RFIFOW(fd,2)-1, RFIFOL(fd,4)); - else - if (sd->state.storage_flag == 2) - storage_guild_storagegettocart(sd, RFIFOW(fd,2)-1, RFIFOL(fd,4)); + storage->gettocart(sd, RFIFOW(fd,2)-1, RFIFOL(fd,4)); + else if (sd->state.storage_flag == 2) + gstorage->gettocart(sd, RFIFOW(fd,2)-1, RFIFOL(fd,4)); } @@ -11913,9 +11980,9 @@ void clif_parse_MoveFromKafraToCart(int fd, struct map_session_data *sd) void clif_parse_CloseKafra(int fd, struct map_session_data *sd) { if( sd->state.storage_flag == 1 ) - storage_storageclose(sd); + storage->close(sd); else if( sd->state.storage_flag == 2 ) - storage_guild_storageclose(sd); + gstorage->close(sd); } @@ -11975,12 +12042,12 @@ void clif_storagepassword_result(struct map_session_data* sd, short result, shor /// Party creation request /// 00f9 <party name>.24B (CZ_MAKE_GROUP) /// 01e8 <party name>.24B <item pickup rule>.B <item share rule>.B (CZ_MAKE_GROUP2) -void clif_parse_CreateParty(int fd, struct map_session_data *sd) -{ +void clif_parse_CreateParty(int fd, struct map_session_data *sd) { char* name = (char*)RFIFOP(fd,2); name[NAME_LENGTH-1] = '\0'; - if( map[sd->bl.m].flag.partylock ) { // Party locked. + if( map->list[sd->bl.m].flag.partylock ) { + // Party locked. clif->message(fd, msg_txt(227)); return; } @@ -11992,14 +12059,14 @@ void clif_parse_CreateParty(int fd, struct map_session_data *sd) party->create(sd,name,0,0); } -void clif_parse_CreateParty2(int fd, struct map_session_data *sd) -{ +void clif_parse_CreateParty2(int fd, struct map_session_data *sd) { char* name = (char*)RFIFOP(fd,2); int item1 = RFIFOB(fd,26); int item2 = RFIFOB(fd,27); name[NAME_LENGTH-1] = '\0'; - if( map[sd->bl.m].flag.partylock ) {// Party locked. + if( map->list[sd->bl.m].flag.partylock ) { + // Party locked. clif->message(fd, msg_txt(227)); return; } @@ -12015,16 +12082,16 @@ void clif_parse_CreateParty2(int fd, struct map_session_data *sd) /// Party invitation request /// 00fc <account id>.L (CZ_REQ_JOIN_GROUP) /// 02c4 <char name>.24B (CZ_PARTY_JOIN_REQ) -void clif_parse_PartyInvite(int fd, struct map_session_data *sd) -{ +void clif_parse_PartyInvite(int fd, struct map_session_data *sd) { struct map_session_data *t_sd; - if(map[sd->bl.m].flag.partylock) {// Party locked. + if(map->list[sd->bl.m].flag.partylock) { + // Party locked. clif->message(fd, msg_txt(227)); return; } - t_sd = iMap->id2sd(RFIFOL(fd,2)); + t_sd = map->id2sd(RFIFOL(fd,2)); if(t_sd && t_sd->state.noask) {// @noask [LuzZza] clif->noask_sub(sd, t_sd, 1); @@ -12034,18 +12101,18 @@ void clif_parse_PartyInvite(int fd, struct map_session_data *sd) party->invite(sd, t_sd); } -void clif_parse_PartyInvite2(int fd, struct map_session_data *sd) -{ +void clif_parse_PartyInvite2(int fd, struct map_session_data *sd) { struct map_session_data *t_sd; char *name = (char*)RFIFOP(fd,2); name[NAME_LENGTH-1] = '\0'; - if(map[sd->bl.m].flag.partylock) { // Party locked. + if(map->list[sd->bl.m].flag.partylock) { + // Party locked. clif->message(fd, msg_txt(227)); return; } - t_sd = iMap->nick2sd(name); + t_sd = map->nick2sd(name); if(t_sd && t_sd->state.noask) { // @noask [LuzZza] clif->noask_sub(sd, t_sd, 1); @@ -12075,9 +12142,9 @@ void clif_parse_ReplyPartyInvite2(int fd,struct map_session_data *sd) /// Request to leave party (CZ_REQ_LEAVE_GROUP). /// 0100 -void clif_parse_LeaveParty(int fd, struct map_session_data *sd) -{ - if(map[sd->bl.m].flag.partylock) { //Guild locked. +void clif_parse_LeaveParty(int fd, struct map_session_data *sd) { + if(map->list[sd->bl.m].flag.partylock) { + // Party locked. clif->message(fd, msg_txt(227)); return; } @@ -12087,9 +12154,9 @@ void clif_parse_LeaveParty(int fd, struct map_session_data *sd) /// Request to expel a party member (CZ_REQ_EXPEL_GROUP_MEMBER). /// 0103 <account id>.L <char name>.24B -void clif_parse_RemovePartyMember(int fd, struct map_session_data *sd) -{ - if(map[sd->bl.m].flag.partylock) { //Guild locked. +void clif_parse_RemovePartyMember(int fd, struct map_session_data *sd) { + if(map->list[sd->bl.m].flag.partylock) { + // Party locked. clif->message(fd, msg_txt(227)); return; } @@ -12136,44 +12203,46 @@ void clif_parse_PartyMessage(int fd, struct map_session_data* sd) int textlen = RFIFOW(fd,2) - 4; char *name, *message; - int namelen, messagelen; + size_t namelen, messagelen; // validate packet and retrieve name and message if( !clif->process_message(sd, 0, &name, &namelen, &message, &messagelen) ) return; - if( atcommand->parse(fd, sd, message, 1) ) + if( atcommand->exec(fd, sd, message, true) ) return; - if( sd->sc.data[SC_BERSERK] || sd->sc.data[SC__BLOODYLUST] || sd->sc.data[SC_DEEP_SLEEP] || (sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOCHAT) ) + if( sd->sc.data[SC_BERSERK] || (sd->sc.data[SC_DEEP_SLEEP] && sd->sc.data[SC_DEEP_SLEEP]->val2) || (sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOCHAT) ) return; if( battle_config.min_chat_delay ) { //[Skotlex] - if (DIFF_TICK(sd->cantalk_tick, iTimer->gettick()) > 0) + if (DIFF_TICK(sd->cantalk_tick, timer->gettick()) > 0) return; - sd->cantalk_tick = iTimer->gettick() + battle_config.min_chat_delay; + sd->cantalk_tick = timer->gettick() + battle_config.min_chat_delay; } + if( battle_config.idletime_criteria & BCIDLE_CHAT ) + sd->idletime = sockt->last_tick; + party->send_message(sd, text, textlen); } /// Changes Party Leader (CZ_CHANGE_GROUP_MASTER). /// 07da <account id>.L -void clif_parse_PartyChangeLeader(int fd, struct map_session_data* sd) -{ - party->changeleader(sd, iMap->id2sd(RFIFOL(fd,2))); +void clif_parse_PartyChangeLeader(int fd, struct map_session_data* sd) { + party->changeleader(sd, map->id2sd(RFIFOL(fd,2))); } -#ifndef PARTY_RECRUIT /// Party Booking in KRO [Spiria] /// -/// Request to register a party booking advertisment (CZ_PARTY_BOOKING_REQ_REGISTER). +/// Request to register a party booking advertisement (CZ_PARTY_BOOKING_REQ_REGISTER). /// 0802 <level>.W <map id>.W { <job>.W }*6 void clif_parse_PartyBookingRegisterReq(int fd, struct map_session_data* sd) { +#ifndef PARTY_RECRUIT short level = RFIFOW(fd,2); short mapid = RFIFOW(fd,4); short job[PARTY_BOOKING_JOBS]; @@ -12183,10 +12252,13 @@ void clif_parse_PartyBookingRegisterReq(int fd, struct map_session_data* sd) job[i] = RFIFOB(fd,6+i*2); party->booking_register(sd, level, mapid, job); +#else + return; +#endif } -/// Result of request to register a party booking advertisment (ZC_PARTY_BOOKING_ACK_REGISTER). +/// Result of request to register a party booking advertisement (ZC_PARTY_BOOKING_ACK_REGISTER). /// 0803 <result>.W /// result: /// 0 = success @@ -12194,19 +12266,24 @@ void clif_parse_PartyBookingRegisterReq(int fd, struct map_session_data* sd) /// 2 = already registered void clif_PartyBookingRegisterAck(struct map_session_data *sd, int flag) { +#ifndef PARTY_RECRUIT int fd = sd->fd; WFIFOHEAD(fd,packet_len(0x803)); WFIFOW(fd,0) = 0x803; WFIFOW(fd,2) = flag; WFIFOSET(fd,packet_len(0x803)); +#else + return; +#endif } -/// Request to search for party booking advertisments (CZ_PARTY_BOOKING_REQ_SEARCH). +/// Request to search for party booking advertisement (CZ_PARTY_BOOKING_REQ_SEARCH). /// 0804 <level>.W <map id>.W <job>.W <last index>.L <result count>.W void clif_parse_PartyBookingSearchReq(int fd, struct map_session_data* sd) { +#ifndef PARTY_RECRUIT short level = RFIFOW(fd,2); short mapid = RFIFOW(fd,4); short job = RFIFOW(fd,6); @@ -12214,6 +12291,9 @@ void clif_parse_PartyBookingSearchReq(int fd, struct map_session_data* sd) short resultcount = RFIFOW(fd,12); party->booking_search(sd, level, mapid, job, lastindex, resultcount); +#else + return; +#endif } @@ -12224,6 +12304,7 @@ void clif_parse_PartyBookingSearchReq(int fd, struct map_session_data* sd) /// 1 = yes void clif_PartyBookingSearchAck(int fd, struct party_booking_ad_info** results, int count, bool more_result) { +#ifndef PARTY_RECRUIT int i, j; int size = sizeof(struct party_booking_ad_info); // structure size (48) struct party_booking_ad_info *pb_ad; @@ -12243,19 +12324,26 @@ void clif_PartyBookingSearchAck(int fd, struct party_booking_ad_info** results, WFIFOW(fd,i*size+41+j*2) = pb_ad->p_detail.job[j]; } WFIFOSET(fd,WFIFOW(fd,2)); +#else + return; +#endif } -/// Request to delete own party booking advertisment (CZ_PARTY_BOOKING_REQ_DELETE). +/// Request to delete own party booking advertisement (CZ_PARTY_BOOKING_REQ_DELETE). /// 0806 void clif_parse_PartyBookingDeleteReq(int fd, struct map_session_data* sd) { +#ifndef PARTY_RECRUIT if(party->booking_delete(sd)) clif->PartyBookingDeleteAck(sd, 0); +#else + return; +#endif } -/// Result of request to delete own party booking advertisment (ZC_PARTY_BOOKING_ACK_DELETE). +/// Result of request to delete own party booking advertisement (ZC_PARTY_BOOKING_ACK_DELETE). /// 0807 <result>.W /// result: /// 0 = success @@ -12264,19 +12352,24 @@ void clif_parse_PartyBookingDeleteReq(int fd, struct map_session_data* sd) /// 3 = nothing registered void clif_PartyBookingDeleteAck(struct map_session_data* sd, int flag) { +#ifndef PARTY_RECRUIT int fd = sd->fd; WFIFOHEAD(fd,packet_len(0x807)); WFIFOW(fd,0) = 0x807; WFIFOW(fd,2) = flag; WFIFOSET(fd,packet_len(0x807)); +#else + return; +#endif } -/// Request to update party booking advertisment (CZ_PARTY_BOOKING_REQ_UPDATE). +/// Request to update party booking advertisement (CZ_PARTY_BOOKING_REQ_UPDATE). /// 0808 { <job>.W }*6 void clif_parse_PartyBookingUpdateReq(int fd, struct map_session_data* sd) { +#ifndef PARTY_RECRUIT short job[PARTY_BOOKING_JOBS]; int i; @@ -12284,13 +12377,17 @@ void clif_parse_PartyBookingUpdateReq(int fd, struct map_session_data* sd) job[i] = RFIFOW(fd,2+i*2); party->booking_update(sd, job); +#else + return; +#endif } -/// Notification about new party booking advertisment (ZC_PARTY_BOOKING_NOTIFY_INSERT). +/// Notification about new party booking advertisement (ZC_PARTY_BOOKING_NOTIFY_INSERT). /// 0809 <index>.L <char name>.24B <expire time>.L <level>.W <map id>.W { <job>.W }*6 void clif_PartyBookingInsertNotify(struct map_session_data* sd, struct party_booking_ad_info* pb_ad) { +#ifndef PARTY_RECRUIT int i; uint8 buf[38+PARTY_BOOKING_JOBS*2]; @@ -12306,13 +12403,17 @@ void clif_PartyBookingInsertNotify(struct map_session_data* sd, struct party_boo WBUFW(buf,38+i*2) = pb_ad->p_detail.job[i]; clif->send(buf, packet_len(0x809), &sd->bl, ALL_CLIENT); +#else + return; +#endif } -/// Notification about updated party booking advertisment (ZC_PARTY_BOOKING_NOTIFY_UPDATE). +/// Notification about updated party booking advertisement (ZC_PARTY_BOOKING_NOTIFY_UPDATE). /// 080a <index>.L { <job>.W }*6 void clif_PartyBookingUpdateNotify(struct map_session_data* sd, struct party_booking_ad_info* pb_ad) { +#ifndef PARTY_RECRUIT int i; uint8 buf[6+PARTY_BOOKING_JOBS*2]; @@ -12323,33 +12424,43 @@ void clif_PartyBookingUpdateNotify(struct map_session_data* sd, struct party_boo for(i=0; i<PARTY_BOOKING_JOBS; i++) WBUFW(buf,6+i*2) = pb_ad->p_detail.job[i]; clif->send(buf,packet_len(0x80a),&sd->bl,ALL_CLIENT); // Now UPDATE all client. +#else + return; +#endif } -/// Notification about deleted party booking advertisment (ZC_PARTY_BOOKING_NOTIFY_DELETE). +/// Notification about deleted party booking advertisement (ZC_PARTY_BOOKING_NOTIFY_DELETE). /// 080b <index>.L void clif_PartyBookingDeleteNotify(struct map_session_data* sd, int index) { +#ifndef PARTY_RECRUIT uint8 buf[6]; WBUFW(buf,0) = 0x80b; WBUFL(buf,2) = index; clif->send(buf, packet_len(0x80b), &sd->bl, ALL_CLIENT); // Now UPDATE all client. +#else + return; +#endif } -#else /// Modified version of Party Booking System for 2012-04-10 or 2012-04-18 (RagexeRE). /// Code written by mkbu95, Spiria, Yommy and Ind -/// Request to register a party booking advertisment (CZ_PARTY_RECRUIT_REQ_REGISTER). +/// Request to register a party booking advertisement (CZ_PARTY_RECRUIT_REQ_REGISTER). /// 08e5 <level>.W <notice>.37B -void clif_parse_PartyBookingRegisterReq(int fd, struct map_session_data* sd) +void clif_parse_PartyRecruitRegisterReq(int fd, struct map_session_data* sd) { +#ifdef PARTY_RECRUIT short level = RFIFOW(fd,2); const char *notice = (const char*)RFIFOP(fd, 4); - party->booking_register(sd, level, notice); + party->recruit_register(sd, level, notice); +#else + return; +#endif } /// Party booking search results (ZC_PARTY_RECRUIT_ACK_SEARCH). @@ -12357,8 +12468,9 @@ void clif_parse_PartyBookingRegisterReq(int fd, struct map_session_data* sd) /// more results: /// 0 = no /// 1 = yes -void clif_PartyBookingSearchAck(int fd, struct party_booking_ad_info** results, int count, bool more_result) +void clif_PartyRecruitSearchAck(int fd, struct party_booking_ad_info** results, int count, bool more_result) { +#ifdef PARTY_RECRUIT int i; int size = sizeof(struct party_booking_ad_info); struct party_booking_ad_info *pb_ad; @@ -12379,76 +12491,100 @@ void clif_PartyBookingSearchAck(int fd, struct party_booking_ad_info** results, } WFIFOSET(fd,WFIFOW(fd,2)); +#else + return; +#endif } -/// Result of request to register a party booking advertisment (ZC_PARTY_RECRUIT_ACK_REGISTER). +/// Result of request to register a party booking advertisement (ZC_PARTY_RECRUIT_ACK_REGISTER). /// 08e6 <result>.W /// result: /// 0 = success /// 1 = failure /// 2 = already registered -void clif_PartyBookingRegisterAck(struct map_session_data *sd, int flag) +void clif_PartyRecruitRegisterAck(struct map_session_data *sd, int flag) { +#ifdef PARTY_RECRUIT int fd = sd->fd; WFIFOHEAD(fd, packet_len(0x8e6)); WFIFOW(fd, 0) = 0x8e6; WFIFOW(fd, 2) = flag; WFIFOSET(fd, packet_len(0x8e6)); +#else + return; +#endif } -/// Request to search for party booking advertisments (CZ_PARTY_RECRUIT_REQ_SEARCH). +/// Request to search for party booking advertisement (CZ_PARTY_RECRUIT_REQ_SEARCH). /// 08e7 <level>.W <map id>.W <last index>.L <result count>.W -void clif_parse_PartyBookingSearchReq(int fd, struct map_session_data* sd) +void clif_parse_PartyRecruitSearchReq(int fd, struct map_session_data* sd) { +#ifdef PARTY_RECRUIT short level = RFIFOW(fd, 2); short mapid = RFIFOW(fd, 4); unsigned long lastindex = RFIFOL(fd, 6); short resultcount = RFIFOW(fd, 10); - party->booking_search(sd, level, mapid, lastindex, resultcount); + party->recruit_search(sd, level, mapid, lastindex, resultcount); +#else + return; +#endif } -/// Request to delete own party booking advertisment (CZ_PARTY_RECRUIT_REQ_DELETE). +/// Request to delete own party booking advertisement (CZ_PARTY_RECRUIT_REQ_DELETE). /// 08e9 -void clif_parse_PartyBookingDeleteReq(int fd, struct map_session_data* sd) +void clif_parse_PartyRecruitDeleteReq(int fd, struct map_session_data* sd) { +#ifdef PARTY_RECRUIT if(party->booking_delete(sd)) - clif->PartyBookingDeleteAck(sd, 0); + clif->PartyRecruitDeleteAck(sd, 0); +#else + return; +#endif } -/// Result of request to delete own party booking advertisment (ZC_PARTY_RECRUIT_ACK_DELETE). +/// Result of request to delete own party booking advertisement (ZC_PARTY_RECRUIT_ACK_DELETE). /// 08ea <result>.W /// result: /// 0 = success /// 1 = success (auto-removed expired ad) /// 2 = failure /// 3 = nothing registered -void clif_PartyBookingDeleteAck(struct map_session_data* sd, int flag) +void clif_PartyRecruitDeleteAck(struct map_session_data* sd, int flag) { +#ifdef PARTY_RECRUIT int fd = sd->fd; WFIFOHEAD(fd, packet_len(0x8ea)); WFIFOW(fd, 0) = 0x8ea; WFIFOW(fd, 2) = flag; WFIFOSET(fd, packet_len(0x8ea)); +#else + return; +#endif } -/// Request to update party booking advertisment (CZ_PARTY_RECRUIT_REQ_UPDATE). +/// Request to update party booking advertisement (CZ_PARTY_RECRUIT_REQ_UPDATE). /// 08eb <notice>.37B -void clif_parse_PartyBookingUpdateReq(int fd, struct map_session_data *sd) +void clif_parse_PartyRecruitUpdateReq(int fd, struct map_session_data *sd) { +#ifdef PARTY_RECRUIT const char *notice; notice = (const char*)RFIFOP(fd, 2); - - party->booking_update(sd, notice); + + party->recruit_update(sd, notice); +#else + return; +#endif } -/// Notification about new party booking advertisment (ZC_PARTY_RECRUIT_NOTIFY_INSERT). +/// Notification about new party booking advertisement (ZC_PARTY_RECRUIT_NOTIFY_INSERT). /// 08ec <index>.L <expire time>.L <char name>.24B <level>.W <notice>.37B -void clif_PartyBookingInsertNotify(struct map_session_data* sd, struct party_booking_ad_info* pb_ad) +void clif_PartyRecruitInsertNotify(struct map_session_data* sd, struct party_booking_ad_info* pb_ad) { +#ifdef PARTY_RECRUIT unsigned char buf[2+6+6+24+4+37+1]; if (pb_ad == NULL) @@ -12461,73 +12597,100 @@ void clif_PartyBookingInsertNotify(struct map_session_data* sd, struct party_boo WBUFW(buf,34) = pb_ad->p_detail.level; memcpy(WBUFP(buf, 36), pb_ad->p_detail.notice, PB_NOTICE_LENGTH); clif->send(buf, packet_len(0x8ec), &sd->bl, ALL_CLIENT); +#else + return; +#endif } -/// Notification about updated party booking advertisment (ZC_PARTY_RECRUIT_NOTIFY_UPDATE). +/// Notification about updated party booking advertisement (ZC_PARTY_RECRUIT_NOTIFY_UPDATE). /// 08ed <index>.L <notice>.37B -void clif_PartyBookingUpdateNotify(struct map_session_data *sd, struct party_booking_ad_info* pb_ad) +void clif_PartyRecruitUpdateNotify(struct map_session_data *sd, struct party_booking_ad_info* pb_ad) { +#ifdef PARTY_RECRUIT unsigned char buf[2+6+37+1]; - + WBUFW(buf, 0) = 0x8ed; WBUFL(buf, 2) = pb_ad->index; memcpy(WBUFP(buf, 6), pb_ad->p_detail.notice, PB_NOTICE_LENGTH); clif->send(buf, packet_len(0x8ed), &sd->bl, ALL_CLIENT); +#else + return; +#endif } -/// Notification about deleted party booking advertisment (ZC_PARTY_RECRUIT_NOTIFY_DELETE). +/// Notification about deleted party booking advertisement (ZC_PARTY_RECRUIT_NOTIFY_DELETE). /// 08ee <index>.L -void clif_PartyBookingDeleteNotify(struct map_session_data* sd, int index) +void clif_PartyRecruitDeleteNotify(struct map_session_data* sd, int index) { +#ifdef PARTY_RECRUIT unsigned char buf[2+6+1]; WBUFW(buf, 0) = 0x8ee; WBUFL(buf, 2) = index; clif->send(buf, packet_len(0x8ee), &sd->bl, ALL_CLIENT); +#else + return; +#endif } /// Request to add to filtering list (PARTY_RECRUIT_ADD_FILTERLINGLIST). /// 08ef <index>.L void clif_parse_PartyBookingAddFilteringList(int fd, struct map_session_data *sd) { +#ifdef PARTY_RECRUIT int index = RFIFOL(fd, 2); clif->PartyBookingAddFilteringList(index, sd); +#else + return; +#endif } /// Request to remove from filtering list (PARTY_RECRUIT_SUB_FILTERLINGLIST). /// 08f0 <GID>.L void clif_parse_PartyBookingSubFilteringList(int fd, struct map_session_data *sd) { +#ifdef PARTY_RECRUIT int gid = RFIFOL(fd, 2); clif->PartyBookingSubFilteringList(gid, sd); +#else + return; +#endif } /// Request to recruit volunteer (PARTY_RECRUIT_REQ_VOLUNTEER). /// 08f1 <index>.L void clif_parse_PartyBookingReqVolunteer(int fd, struct map_session_data *sd) { +#ifdef PARTY_RECRUIT int index = RFIFOL(fd, 2); clif->PartyBookingVolunteerInfo(index, sd); +#else + return; +#endif } /// Request volunteer information (PARTY_RECRUIT_VOLUNTEER_INFO). /// 08f2 <AID>.L <job>.L <level>.W <char name>.24B void clif_PartyBookingVolunteerInfo(int index, struct map_session_data *sd) { +#ifdef PARTY_RECRUIT unsigned char buf[2+4+4+2+24+1]; - + WBUFW(buf, 0) = 0x8f2; WBUFL(buf, 2) = sd->status.account_id; WBUFL(buf, 6) = sd->status.class_; WBUFW(buf, 10) = sd->status.base_level; memcpy(WBUFP(buf, 12), sd->status.name, NAME_LENGTH); - + clif->send(buf, packet_len(0x8f2), &sd->bl, ALL_CLIENT); +#else + return; +#endif } #if 0 //Disabled for now. Needs more info. @@ -12571,63 +12734,87 @@ void clif_PartyBookingFailedRecall(int fd, struct map_session_data *sd) /// 08f9 <refuse AID>.L void clif_parse_PartyBookingRefuseVolunteer(int fd, struct map_session_data *sd) { - unsigned long aid = RFIFOL(fd, 2); +#ifdef PARTY_RECRUIT + unsigned int aid = RFIFOL(fd, 2); clif->PartyBookingRefuseVolunteer(aid, sd); +#else + return; +#endif } /// 08fa <index>.L -void clif_PartyBookingRefuseVolunteer(unsigned long aid, struct map_session_data *sd) +void clif_PartyBookingRefuseVolunteer(unsigned int aid, struct map_session_data *sd) { +#ifdef PARTY_RECRUIT unsigned char buf[2+6]; - + WBUFW(buf, 0) = 0x8fa; WBUFL(buf, 2) = aid; - + clif->send(buf, packet_len(0x8fa), &sd->bl, ALL_CLIENT); +#else + return; +#endif } /// 08fb <index>.L void clif_parse_PartyBookingCancelVolunteer(int fd, struct map_session_data *sd) { +#ifdef PARTY_RECRUIT int index = RFIFOL(fd, 2); clif->PartyBookingCancelVolunteer(index, sd); +#else + return; +#endif } /// 0909 <index>.L void clif_PartyBookingCancelVolunteer(int index, struct map_session_data *sd) { +#ifdef PARTY_RECRUIT unsigned char buf[2+6+1]; - + WBUFW(buf, 0) = 0x909; WBUFL(buf, 2) = index; - + clif->send(buf, packet_len(0x909), &sd->bl, ALL_CLIENT); +#else + return; +#endif } /// 090b <gid>.L <char name>.24B void clif_PartyBookingAddFilteringList(int index, struct map_session_data *sd) { +#ifdef PARTY_RECRUIT unsigned char buf[2+6+24+1]; WBUFW(buf, 0) = 0x90b; WBUFL(buf, 2) = sd->bl.id; memcpy(WBUFP(buf, 6), sd->status.name, NAME_LENGTH); - + clif->send(buf, packet_len(0x90b), &sd->bl, ALL_CLIENT); +#else + return; +#endif } /// 090c <gid>.L <char name>.24B void clif_PartyBookingSubFilteringList(int gid, struct map_session_data *sd) { +#ifdef PARTY_RECRUIT unsigned char buf[2+6+24+1]; WBUFW(buf, 0) = 0x90c; WBUFL(buf, 2) = gid; memcpy(WBUFP(buf, 6), sd->status.name, NAME_LENGTH); - + clif->send(buf, packet_len(0x90c), &sd->bl, ALL_CLIENT); +#else + return; +#endif } #if 0 @@ -12641,7 +12828,6 @@ void clif_PartyBookingRefuseVolunteerToPM(struct map_session_data *sd) { } #endif //if 0 -#endif /// Request to close own vending (CZ_REQ_CLOSESTORE). /// 012e @@ -12699,23 +12885,22 @@ void clif_parse_PurchaseReq2(int fd, struct map_session_data* sd) /// result: /// 0 = canceled /// 1 = open -void clif_parse_OpenVending(int fd, struct map_session_data* sd) -{ +void clif_parse_OpenVending(int fd, struct map_session_data* sd) { short len = (short)RFIFOW(fd,2) - 85; const char* message = (char*)RFIFOP(fd,4); bool flag = (bool)RFIFOB(fd,84); const uint8* data = (uint8*)RFIFOP(fd,85); - + if( !flag ) sd->state.prevend = sd->state.workinprogress = 0; if( sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOROOM ) return; - if( map[sd->bl.m].flag.novending ) { + if( map->list[sd->bl.m].flag.novending ) { clif->message (sd->fd, msg_txt(276)); // "You can't open a shop on this map" return; } - if( iMap->getcell(sd->bl.m,sd->bl.x,sd->bl.y,CELL_CHKNOVENDING) ) { + if( map->getcell(sd->bl.m,sd->bl.x,sd->bl.y,CELL_CHKNOVENDING) ) { clif->message (sd->fd, msg_txt(204)); // "You can't open a shop on this cell." return; } @@ -12728,12 +12913,12 @@ void clif_parse_OpenVending(int fd, struct map_session_data* sd) /// Guild creation request (CZ_REQ_MAKE_GUILD). /// 0165 <char id>.L <guild name>.24B -void clif_parse_CreateGuild(int fd,struct map_session_data *sd) -{ +void clif_parse_CreateGuild(int fd,struct map_session_data *sd) { char* name = (char*)RFIFOP(fd,6); name[NAME_LENGTH-1] = '\0'; - if(map[sd->bl.m].flag.guildlock) { //Guild locked. + if(map->list[sd->bl.m].flag.guildlock) { + //Guild locked. clif->message(fd, msg_txt(228)); return; } @@ -12833,20 +13018,126 @@ void clif_parse_GuildRequestEmblem(int fd,struct map_session_data *sd) clif->guild_emblem(sd,g); } - /// Validates data of a guild emblem (compressed bitmap) -bool clif_validate_emblem(const uint8* emblem, unsigned long emblem_len) { - bool success; - uint8 buf[1800]; // no well-formed emblem bitmap is larger than 1782 (24 bit) / 1654 (8 bit) bytes +bool clif_validate_emblem(const uint8 *emblem, unsigned long emblem_len) { + enum e_bitmapconst { + RGBTRIPLE_SIZE = 3, // sizeof(RGBTRIPLE) + RGBQUAD_SIZE = 4, // sizeof(RGBQUAD) + BITMAPFILEHEADER_SIZE = 14, // sizeof(BITMAPFILEHEADER) + BITMAPINFOHEADER_SIZE = 40, // sizeof(BITMAPINFOHEADER) + BITMAP_WIDTH = 24, + BITMAP_HEIGHT = 24, + }; +#if !defined(sun) && (!defined(__NETBSD__) || __NetBSD_Version__ >= 600000000) // NetBSD 5 and Solaris don't like pragma pack but accept the packed attribute +#pragma pack(push, 1) +#endif // not NetBSD < 6 / Solaris + struct s_bitmaptripple { + //uint8 b; + //uint8 g; + //uint8 r; + unsigned int 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) +#endif // not NetBSD < 6 / Solaris + uint8 buf[1800]; // no well-formed emblem bitmap is larger than 1782 (24 bit) / 1654 (8 bit) bytes unsigned long buf_len = sizeof(buf); + int header = 0, bitmap = 0, offbits = 0, palettesize = 0, i = 0; + + if( decode_zip(buf, &buf_len, emblem, emblem_len) != 0 || buf_len < BITMAPFILEHEADER_SIZE + BITMAPINFOHEADER_SIZE + || RBUFW(buf,0) != 0x4d42 // BITMAPFILEHEADER.bfType (signature) + || RBUFL(buf,2) != buf_len // BITMAPFILEHEADER.bfSize (file size) + || RBUFL(buf,14) != BITMAPINFOHEADER_SIZE // BITMAPINFOHEADER.biSize (other headers are not supported) + || RBUFL(buf,18) != BITMAP_WIDTH // BITMAPINFOHEADER.biWidth + || RBUFL(buf,22) != BITMAP_HEIGHT // BITMAPINFOHEADER.biHeight (top-down bitmaps (-24) are not supported) + || RBUFL(buf,30) != 0 // BITMAPINFOHEADER.biCompression == BI_RGB (compression not supported) + ) { + // Invalid data + return false; + } - success = ( decode_zip(buf, &buf_len, emblem, emblem_len) == 0 && buf_len >= 18 ) // sizeof(BITMAPFILEHEADER) + sizeof(biSize) of the following info header struct - && RBUFW(buf,0) == 0x4d42 // BITMAPFILEHEADER.bfType (signature) - && RBUFL(buf,2) == buf_len // BITMAPFILEHEADER.bfSize (file size) - && RBUFL(buf,10) < buf_len // BITMAPFILEHEADER.bfOffBits (offset to bitmap bits) - ; + offbits = RBUFL(buf,10); // BITMAPFILEHEADER.bfOffBits (offset to bitmap bits) + + switch( RBUFW(buf,28) ) { // BITMAPINFOHEADER.biBitCount + case 8: + palettesize = RBUFL(buf,46); // BITMAPINFOHEADER.biClrUsed (number of colors in the palette) + if( palettesize == 0 ) + palettesize = 256; // Defaults to 2^n if set to zero + else if( palettesize > 256 ) + return false; + header = BITMAPFILEHEADER_SIZE + BITMAPINFOHEADER_SIZE + RGBQUAD_SIZE * palettesize; // headers + palette + bitmap = BITMAP_WIDTH * BITMAP_HEIGHT; + break; + case 24: + header = BITMAPFILEHEADER_SIZE + BITMAPINFOHEADER_SIZE; + bitmap = BITMAP_WIDTH * BITMAP_HEIGHT * RGBTRIPLE_SIZE; + break; + default: + return false; + } + + // NOTE: This check gives a little freedom for bitmap-producing implementations, + // that align the start of bitmap data, which is harmless but unnecessary. + // If you want it paranoidly strict, change the first condition from < to !=. + // This also allows files with trailing garbage at the end of the file. + // If you want to avoid that, change the last condition to !=. + if( offbits < header || buf_len <= bitmap || offbits > buf_len - bitmap ) { + return false; + } - return success; + if( battle_config.client_emblem_max_blank_percent < 100 ) { + int required_pixels = BITMAP_WIDTH * BITMAP_HEIGHT * (100 - battle_config.client_emblem_max_blank_percent) / 100; + int found_pixels = 0; + /// Checks what percentage of a guild emblem is blank. A blank emblem + /// consists solely of magenta pixels. Since the client uses 16-bit + /// colors, any magenta shade that reduces to #ff00ff passes off as + /// transparent color as well (down to #f807f8). + /// + /// Unlike real magenta, reduced magenta causes the guild window to + /// become see-through in the transparent parts of the emblem + /// background (glitch). + switch( RBUFW(buf,28) ) { + case 8: // palette indexes + { + const uint8 *indexes = (const uint8 *)RBUFP(buf,offbits); + const uint32 *palette = (const uint32 *)RBUFP(buf,BITMAPFILEHEADER_SIZE + BITMAPINFOHEADER_SIZE); + + for( i = 0; i < BITMAP_WIDTH * BITMAP_HEIGHT; i++ ) { + if( indexes[i] >= palettesize ) // Invalid color + return false; + + // if( color->r < 0xF8 || color->g > 0x07 || color->b < 0xF8 ) + if( ( palette[indexes[i]]&0x00F8F8F8 ) != 0x00F800F8 ) { + if( ++found_pixels >= required_pixels ) { + // Enough valid pixels were found + return true; + } + } + } + break; + } + case 24: // full colors + { + const struct s_bitmaptripple *pixels = (const struct s_bitmaptripple*)RBUFP(buf,offbits); + + for( i = 0; i < BITMAP_WIDTH * BITMAP_HEIGHT; i++ ) { + // if( pixels[i].r < 0xF8 || pixels[i].g > 0x07 || pixels[i].b < 0xF8 ) + if( ( pixels[i].rgb&0xF8F8F8 ) != 0xF800F8 ) { + if( ++found_pixels >= required_pixels ) { + // Enough valid pixels were found + return true; + } + } + } + break; + } + } + + // Not enough non-blank pixels found + return false; + } + + return true; } @@ -12854,14 +13145,15 @@ bool clif_validate_emblem(const uint8* emblem, unsigned long emblem_len) { /// 0153 <packet len>.W <emblem data>.?B void clif_parse_GuildChangeEmblem(int fd,struct map_session_data *sd) { - unsigned long emblem_len = RFIFOW(fd,2)-4; + unsigned int emblem_len = RFIFOW(fd,2)-4; const uint8* emblem = RFIFOP(fd,4); if( !emblem_len || !sd->state.gmaster_flag ) return; - if( !clif->validate_emblem(emblem, emblem_len) ) { - ShowWarning("clif_parse_GuildChangeEmblem: Rejected malformed guild emblem (size=%lu, accound_id=%d, char_id=%d, guild_id=%d).\n", emblem_len, sd->status.account_id, sd->status.char_id, sd->status.guild_id); + if (!clif->validate_emblem(emblem, emblem_len)) { + ShowWarning("clif_parse_GuildChangeEmblem: Rejected malformed guild emblem (size=%u, accound_id=%d, char_id=%d, guild_id=%d).\n", + emblem_len, sd->status.account_id, sd->status.char_id, sd->status.guild_id); return; } @@ -12880,7 +13172,7 @@ void clif_parse_GuildChangeNotice(int fd, struct map_session_data* sd) if(!sd->state.gmaster_flag) return; - // compensate for some client defects when using multilanguage mode + // compensate for some client defects when using multilingual mode if (msg1[0] == '|' && msg1[3] == '|') msg1+= 3; // skip duplicate marker if (msg2[0] == '|' && msg2[3] == '|') msg2+= 3; // skip duplicate marker if (msg2[0] == '|') msg2[strnlen(msg2, MAX_GUILDMES2)-1] = '\0'; // delete extra space at the end of string @@ -12889,43 +13181,40 @@ void clif_parse_GuildChangeNotice(int fd, struct map_session_data* sd) } // Helper function for guild invite functions -int -clif_sub_guild_invite(int fd, struct map_session_data *sd, struct map_session_data *t_sd) { - if (t_sd == NULL) {// not online or does not exist - return 1; - } - - if (map[sd->bl.m].flag.guildlock) { //Guild locked. +bool clif_sub_guild_invite(int fd, struct map_session_data *sd, struct map_session_data *t_sd) { + if ( t_sd == NULL )// not online or does not exist + return false; + + if ( map->list[sd->bl.m].flag.guildlock ) { + //Guild locked. clif->message(fd, msg_txt(228)); - return 1; + return false; } - - if (t_sd && t_sd->state.noask) {// @noask [LuzZza] + + if ( t_sd && t_sd->state.noask ) {// @noask [LuzZza] clif->noask_sub(sd, t_sd, 2); - return 1; + return false; } guild->invite(sd,t_sd); - return 0; + return true; } /// Guild invite request (CZ_REQ_JOIN_GUILD). /// 0168 <account id>.L <inviter account id>.L <inviter char id>.L -void clif_parse_GuildInvite(int fd,struct map_session_data *sd) -{ - struct map_session_data *t_sd = iMap->id2sd(RFIFOL(fd,2)); +void clif_parse_GuildInvite(int fd,struct map_session_data *sd) { + struct map_session_data *t_sd = map->id2sd(RFIFOL(fd,2)); - if (clif_sub_guild_invite(fd, sd, t_sd)) + if (!clif_sub_guild_invite(fd, sd, t_sd)) return; } /// Guild invite request (/guildinvite) (CZ_REQ_JOIN_GUILD2). /// 0916 <char name>.24B -void clif_parse_GuildInvite2(int fd, struct map_session_data *sd) -{ - struct map_session_data *t_sd = iMap->nick2sd((char *)RFIFOP(fd, 2)); - - if (clif_sub_guild_invite(fd, sd, t_sd)) +void clif_parse_GuildInvite2(int fd, struct map_session_data *sd) { + struct map_session_data *t_sd = map->nick2sd((char *)RFIFOP(fd, 2)); + + if (!clif_sub_guild_invite(fd, sd, t_sd)) return; } @@ -12942,14 +13231,14 @@ void clif_parse_GuildReplyInvite(int fd,struct map_session_data *sd) /// Request to leave guild (CZ_REQ_LEAVE_GUILD). /// 0159 <guild id>.L <account id>.L <char id>.L <reason>.40B -void clif_parse_GuildLeave(int fd,struct map_session_data *sd) -{ - if(map[sd->bl.m].flag.guildlock) { //Guild locked. +void clif_parse_GuildLeave(int fd,struct map_session_data *sd) { + if(map->list[sd->bl.m].flag.guildlock) { + //Guild locked. clif->message(fd, msg_txt(228)); return; } if( sd->bg_id ) { - clif->message(fd, msg_txt(670)); //"You can't leave battleground guilds." + clif->message(fd, msg_txt(870)); //"You can't leave battleground guilds." return; } @@ -12959,9 +13248,9 @@ void clif_parse_GuildLeave(int fd,struct map_session_data *sd) /// Request to expel a member of a guild (CZ_REQ_BAN_GUILD). /// 015b <guild id>.L <account id>.L <char id>.L <reason>.40B -void clif_parse_GuildExpulsion(int fd,struct map_session_data *sd) -{ - if( map[sd->bl.m].flag.guildlock || sd->bg_id ) { // Guild locked. +void clif_parse_GuildExpulsion(int fd,struct map_session_data *sd) { + if( map->list[sd->bl.m].flag.guildlock || sd->bg_id ) { + // Guild locked. clif->message(fd, msg_txt(228)); return; } @@ -12977,27 +13266,30 @@ void clif_parse_GuildMessage(int fd, struct map_session_data* sd) int textlen = RFIFOW(fd,2) - 4; char *name, *message; - int namelen, messagelen; + size_t namelen, messagelen; // validate packet and retrieve name and message if( !clif->process_message(sd, 0, &name, &namelen, &message, &messagelen) ) return; - if( atcommand->parse(fd, sd, message, 1) ) + if( atcommand->exec(fd, sd, message, true) ) return; - if( sd->sc.data[SC_BERSERK] || sd->sc.data[SC__BLOODYLUST] || sd->sc.data[SC_DEEP_SLEEP] || (sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOCHAT) ) + if( sd->sc.data[SC_BERSERK] || (sd->sc.data[SC_DEEP_SLEEP] && sd->sc.data[SC_DEEP_SLEEP]->val2) || (sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOCHAT) ) return; if( battle_config.min_chat_delay ) { //[Skotlex] - if (DIFF_TICK(sd->cantalk_tick, iTimer->gettick()) > 0) + if (DIFF_TICK(sd->cantalk_tick, timer->gettick()) > 0) return; - sd->cantalk_tick = iTimer->gettick() + battle_config.min_chat_delay; + sd->cantalk_tick = timer->gettick() + battle_config.min_chat_delay; } + if( battle_config.idletime_criteria & BCIDLE_CHAT ) + sd->idletime = sockt->last_tick; + if( sd->bg_id ) - bg_send_message(sd, text, textlen); + bg->send_message(sd, text, textlen); else guild->send_message(sd, text, textlen); } @@ -13005,19 +13297,19 @@ void clif_parse_GuildMessage(int fd, struct map_session_data* sd) /// Guild alliance request (CZ_REQ_ALLY_GUILD). /// 0170 <account id>.L <inviter account id>.L <inviter char id>.L -void clif_parse_GuildRequestAlliance(int fd, struct map_session_data *sd) -{ +void clif_parse_GuildRequestAlliance(int fd, struct map_session_data *sd) { struct map_session_data *t_sd; if(!sd->state.gmaster_flag) return; - if(map[sd->bl.m].flag.guildlock) { //Guild locked. + if(map->list[sd->bl.m].flag.guildlock) { + //Guild locked. clif->message(fd, msg_txt(228)); return; } - t_sd = iMap->id2sd(RFIFOL(fd,2)); + t_sd = map->id2sd(RFIFOL(fd,2)); // @noask [LuzZza] if(t_sd && t_sd->state.noask) { @@ -13045,12 +13337,12 @@ void clif_parse_GuildReplyAlliance(int fd, struct map_session_data *sd) /// relation: /// 0 = Ally /// 1 = Enemy -void clif_parse_GuildDelAlliance(int fd, struct map_session_data *sd) -{ +void clif_parse_GuildDelAlliance(int fd, struct map_session_data *sd) { if(!sd->state.gmaster_flag) return; - if(map[sd->bl.m].flag.guildlock) { //Guild locked. + if(map->list[sd->bl.m].flag.guildlock) { + //Guild locked. clif->message(fd, msg_txt(228)); return; } @@ -13060,19 +13352,19 @@ void clif_parse_GuildDelAlliance(int fd, struct map_session_data *sd) /// Request to set a guild as opposition (CZ_REQ_HOSTILE_GUILD). /// 0180 <account id>.L -void clif_parse_GuildOpposition(int fd, struct map_session_data *sd) -{ +void clif_parse_GuildOpposition(int fd, struct map_session_data *sd) { struct map_session_data *t_sd; if(!sd->state.gmaster_flag) return; - if(map[sd->bl.m].flag.guildlock) { //Guild locked. + if(map->list[sd->bl.m].flag.guildlock) { + //Guild locked. clif->message(fd, msg_txt(228)); return; } - t_sd = iMap->id2sd(RFIFOL(fd,2)); + t_sd = map->id2sd(RFIFOL(fd,2)); // @noask [LuzZza] if(t_sd && t_sd->state.noask) { @@ -13089,9 +13381,9 @@ void clif_parse_GuildOpposition(int fd, struct map_session_data *sd) /// key: /// now guild name; might have been (intended) email, since the /// field name and size is same as the one in CH_DELETE_CHAR. -void clif_parse_GuildBreak(int fd, struct map_session_data *sd) -{ - if( map[sd->bl.m].flag.guildlock ) { //Guild locked. +void clif_parse_GuildBreak(int fd, struct map_session_data *sd) { + if( map->list[sd->bl.m].flag.guildlock ) { + //Guild locked. clif->message(fd, msg_txt(228)); return; } @@ -13112,7 +13404,7 @@ void clif_parse_GuildBreak(int fd, struct map_session_data *sd) /// 4 = unequip accessory void clif_parse_PetMenu(int fd, struct map_session_data *sd) { - pet_menu(sd,RFIFOB(fd,2)); + pet->menu(sd,RFIFOB(fd,2)); } @@ -13120,7 +13412,7 @@ void clif_parse_PetMenu(int fd, struct map_session_data *sd) /// 019f <id>.L void clif_parse_CatchPet(int fd, struct map_session_data *sd) { - pet_catch_process2(sd,RFIFOL(fd,2)); + pet->catch_process2(sd,RFIFOL(fd,2)); } @@ -13129,11 +13421,9 @@ void clif_parse_CatchPet(int fd, struct map_session_data *sd) void clif_parse_SelectEgg(int fd, struct map_session_data *sd) { if (sd->menuskill_id != SA_TAMINGMONSTER || sd->menuskill_val != -1) { - //Forged packet, disconnect them [Kevin] - clif->authfail_fd(fd, 0); return; } - pet_select_egg(sd,RFIFOW(fd,2)-2); + pet->select_egg(sd,RFIFOW(fd,2)-2); clif_menuskill_clear(sd); } @@ -13173,7 +13463,7 @@ void clif_parse_SendEmotion(int fd, struct map_session_data *sd) /// 01a5 <name>.24B void clif_parse_ChangePetName(int fd, struct map_session_data *sd) { - pet_change_name(sd,(char*)RFIFOP(fd,2)); + pet->change_name(sd,(char*)RFIFOP(fd,2)); } @@ -13181,13 +13471,12 @@ void clif_parse_ChangePetName(int fd, struct map_session_data *sd) /// Request to disconnect a character. /// 00cc <account id>.L /// NOTE: Also sent when using GM right click menu "(name) force to quit" -void clif_parse_GMKick(int fd, struct map_session_data *sd) -{ +void clif_parse_GMKick(int fd, struct map_session_data *sd) { struct block_list *target; int tid; tid = RFIFOL(fd,2); - target = iMap->id2bl(tid); + target = map->id2bl(tid); if (!target) { clif->GM_kickack(sd, 0); return; @@ -13197,8 +13486,8 @@ void clif_parse_GMKick(int fd, struct map_session_data *sd) case BL_PC: { char command[NAME_LENGTH+6]; - sprintf(command, "%ckick %s", atcommand->at_symbol, status_get_name(target)); - atcommand->parse(fd, sd, command, 1); + sprintf(command, "%ckick %s", atcommand->at_symbol, status->get_name(target)); + atcommand->exec(fd, sd, command, true); } break; @@ -13212,7 +13501,7 @@ void clif_parse_GMKick(int fd, struct map_session_data *sd) clif->GM_kickack(sd, 0); return; } - sprintf(command, "/kick %s (%d)", status_get_name(target), status_get_class(target)); + sprintf(command, "/kick %s (%d)", status->get_name(target), status->get_class(target)); logs->atcommand(sd, command); status_percent_damage(&sd->bl, target, 100, 0, true); // can invalidate 'target' } @@ -13220,9 +13509,14 @@ void clif_parse_GMKick(int fd, struct map_session_data *sd) case BL_NPC: { - char command[NAME_LENGTH+11]; - sprintf(command, "%cunloadnpc %s", atcommand->at_symbol, status_get_name(target)); - atcommand->parse(fd, sd, command, 1); + struct npc_data* nd = (struct npc_data *)target; + if( !pc->can_use_command(sd, "@unloadnpc")) { + clif->GM_kickack(sd, 0); + return; + } + npc->unload_duplicates(nd); + npc->unload(nd,true); + npc->read_event_script(); } break; @@ -13238,7 +13532,7 @@ void clif_parse_GMKick(int fd, struct map_session_data *sd) void clif_parse_GMKickAll(int fd, struct map_session_data* sd) { char cmd[15]; sprintf(cmd,"%ckickall",atcommand->at_symbol); - atcommand->parse(fd, sd, cmd, 1); + atcommand->exec(fd, sd, cmd, true); } @@ -13258,23 +13552,22 @@ void clif_parse_GMShift(int fd, struct map_session_data *sd) player_name[NAME_LENGTH-1] = '\0'; sprintf(command, "%cjumpto %s", atcommand->at_symbol, player_name); - atcommand->parse(fd, sd, command, 1); + atcommand->exec(fd, sd, command, true); } /// /remove (CZ_REMOVE_AID_SSO). /// Request to warp to a character with given account ID. /// 0843 <account id>.L -void clif_parse_GMRemove2(int fd, struct map_session_data* sd) -{ +void clif_parse_GMRemove2(int fd, struct map_session_data* sd) { int account_id; struct map_session_data* pl_sd; account_id = RFIFOL(fd,packet_db[RFIFOW(fd,0)].pos[0]); - if( (pl_sd = iMap->id2sd(account_id)) != NULL ) { + if( (pl_sd = map->id2sd(account_id)) != NULL ) { char command[NAME_LENGTH+8]; sprintf(command, "%cjumpto %s", atcommand->at_symbol, pl_sd->status.name); - atcommand->parse(fd, sd, command, 1); + atcommand->exec(fd, sd, command, true); } } @@ -13295,52 +13588,92 @@ void clif_parse_GMRecall(int fd, struct map_session_data *sd) player_name[NAME_LENGTH-1] = '\0'; sprintf(command, "%crecall %s", atcommand->at_symbol, player_name); - atcommand->parse(fd, sd, command, 1); + atcommand->exec(fd, sd, command, true); } /// /recall (CZ_RECALL_SSO). /// Request to summon a player with given account ID to own position. /// 0842 <account id>.L -void clif_parse_GMRecall2(int fd, struct map_session_data* sd) -{ +void clif_parse_GMRecall2(int fd, struct map_session_data* sd) { int account_id; struct map_session_data* pl_sd; account_id = RFIFOL(fd,packet_db[RFIFOW(fd,0)].pos[0]); - if( (pl_sd = iMap->id2sd(account_id)) != NULL ) { + if( (pl_sd = map->id2sd(account_id)) != NULL ) { char command[NAME_LENGTH+8]; sprintf(command, "%crecall %s", atcommand->at_symbol, pl_sd->status.name); - atcommand->parse(fd, sd, command, 1); + atcommand->exec(fd, sd, command, true); } } /// /item /monster (CZ_ITEM_CREATE). -/// Request to make items or spawn monsters. +/// Request to execute GM commands. +/// usage: +/// /item n - summon n monster or acquire n item/s +/// /item money - grants 2147483647 Zeny +/// /item whereisboss - locate boss mob in current map.(not yet implemented) +/// /item regenboss_n t - regenerate n boss monster by t millisecond.(not yet implemented) +/// /item onekillmonster - toggle an ability to kill mobs in one hit.(not yet implemented) +/// /item bossinfo - display the information of a boss monster in current map.(not yet implemented) +/// /item cap_n - capture n monster as pet.(not yet implemented) +/// /item agitinvest - reset current global agit investments.(not yet implemented) /// 013f <item/mob name>.24B -void clif_parse_GM_Monster_Item(int fd, struct map_session_data *sd) -{ - char *monster_item_name; - char command[NAME_LENGTH+10]; +/// 09ce <item/mob name>.100B [Ind/Yommy<3] +void clif_parse_GM_Monster_Item(int fd, struct map_session_data *sd) { + struct packet_gm_monster_item *p = P2PTR(fd); + int i, count; + char *item_monster_name; + struct item_data *item_array[10]; + struct mob_db *mob_array[10]; + char command[256]; + + item_monster_name = p->str; + item_monster_name[(sizeof(struct packet_gm_monster_item)-2)-1] = '\0'; + + if ( (count=itemdb->search_name_array(item_array, 10, item_monster_name, 1)) > 0 ) { + for(i = 0; i < count; i++) { + if( !item_array[i] ) + continue; + // It only accepts aegis name + if( battle_config.case_sensitive_aegisnames && strcmp(item_array[i]->name, item_monster_name) == 0 ) + break; + if( !battle_config.case_sensitive_aegisnames && strcasecmp(item_array[i]->name, item_monster_name) == 0 ) + break; + } - monster_item_name = (char*)RFIFOP(fd,2); - monster_item_name[NAME_LENGTH-1] = '\0'; + if( i < count ) { + if( item_array[i]->type == IT_WEAPON || item_array[i]->type == IT_ARMOR ) // nonstackable + snprintf(command, sizeof(command)-1, "%citem2 %d 1 0 0 0 0 0 0 0", atcommand->at_symbol, item_array[i]->nameid); + else + snprintf(command, sizeof(command)-1, "%citem %d 20", atcommand->at_symbol, item_array[i]->nameid); + atcommand->exec(fd, sd, command, true); + return; + } + } - // FIXME: Should look for item first, then for monster. - // FIXME: /monster takes mob_db Sprite_Name as argument - if( mobdb_searchname(monster_item_name) ) { - snprintf(command, sizeof(command)-1, "%cmonster %s", atcommand->at_symbol, monster_item_name); - atcommand->parse(fd, sd, command, 1); + if( strcmp("money", item_monster_name) == 0 ){ + snprintf(command, sizeof(command)-1, "%czeny %d", atcommand->at_symbol, INT_MAX); + atcommand->exec(fd, sd, command, true); return; } - // FIXME: Stackables have a quantity of 20. - // FIXME: Equips are supposed to be unidentified. - if( itemdb_searchname(monster_item_name) ) { - snprintf(command, sizeof(command)-1, "%citem %s", atcommand->at_symbol, monster_item_name); - atcommand->parse(fd, sd, command, 1); - return; + if( (count=mob->db_searchname_array(mob_array, 10, item_monster_name, 1)) > 0) { + for(i = 0; i < count; i++) { + if( !mob_array[i] ) + continue; + // It only accepts sprite name + if( battle_config.case_sensitive_aegisnames && strcmp(mob_array[i]->sprite, item_monster_name) == 0 ) + break; + if( !battle_config.case_sensitive_aegisnames && strcasecmp(mob_array[i]->sprite, item_monster_name) == 0 ) + break; + } + + if( i < count ){ + snprintf(command, sizeof(command)-1, "%cmonster %s", atcommand->at_symbol, mob_array[i]->sprite); + atcommand->exec(fd, sd, command, true); + } } } @@ -13354,7 +13687,7 @@ void clif_parse_GMHide(int fd, struct map_session_data *sd) { sprintf(cmd,"%chide",atcommand->at_symbol); - atcommand->parse(fd, sd, cmd, 1); + atcommand->exec(fd, sd, cmd, true); } @@ -13364,8 +13697,7 @@ void clif_parse_GMHide(int fd, struct map_session_data *sd) { /// 0 = positive points /// 1 = negative points /// 2 = self mute (+10 minutes) -void clif_parse_GMReqNoChat(int fd,struct map_session_data *sd) -{ +void clif_parse_GMReqNoChat(int fd,struct map_session_data *sd) { int id, type, value; struct map_session_data *dstsd; char command[NAME_LENGTH+15]; @@ -13377,17 +13709,39 @@ void clif_parse_GMReqNoChat(int fd,struct map_session_data *sd) if( type == 0 ) value = -value; - //If type is 2 and the ids don't match, this is a crafted hacked packet! - //Disabled because clients keep self-muting when you give players public @ commands... [Skotlex] - if (type == 2 /* && (pc->get_group_level(sd) > 0 || sd->bl.id != id)*/) - return; + if (type == 2) { + if (!battle_config.client_accept_chatdori) + return; + if (pc_get_group_level(sd) > 0 || sd->bl.id != id) + return; - dstsd = iMap->id2sd(id); - if( dstsd == NULL ) - return; + value = battle_config.client_accept_chatdori; + dstsd = sd; + } else { + dstsd = map->id2sd(id); + if( dstsd == NULL ) + return; + } + + if (type == 2 || ( (pc_get_group_level(sd)) > pc_get_group_level(dstsd) && !pc->can_use_command(sd, "@mute"))) { + clif->manner_message(sd, 0); + clif->manner_message(dstsd, 5); + + if (dstsd->status.manner < value) { + dstsd->status.manner -= value; + sc_start(NULL,&dstsd->bl,SC_NOCHAT,100,0,0); + + } else { + dstsd->status.manner = 0; + status_change_end(&dstsd->bl, SC_NOCHAT, INVALID_TIMER); + } + + if( type != 2 ) + clif->GM_silence(sd, dstsd, type); + } sprintf(command, "%cmute %d %s", atcommand->at_symbol, value, dstsd->status.name); - atcommand->parse(fd, sd, command, 1); + atcommand->exec(fd, sd, command, true); } @@ -13401,7 +13755,7 @@ void clif_parse_GMRc(int fd, struct map_session_data* sd) name[NAME_LENGTH-1] = '\0'; sprintf(command, "%cmute %d %s", atcommand->at_symbol, 60, name); - atcommand->parse(fd, sd, command, 1); + atcommand->exec(fd, sd, command, true); } @@ -13435,18 +13789,17 @@ void clif_parse_GMReqAccountName(int fd, struct map_session_data *sd) /// type: /// 0 = not walkable /// 1 = walkable -void clif_parse_GMChangeMapType(int fd, struct map_session_data *sd) -{ +void clif_parse_GMChangeMapType(int fd, struct map_session_data *sd) { int x,y,type; - if( pc_has_permission(sd, PC_PERM_USE_CHANGEMAPTYPE) ) + if (!pc_has_permission(sd, PC_PERM_USE_CHANGEMAPTYPE)) return; x = RFIFOW(fd,2); y = RFIFOW(fd,4); type = RFIFOW(fd,6); - iMap->setgatcell(sd->bl.m,x,y,type); + map->setgatcell(sd->bl.m,x,y,type); clif->changemapcell(0,sd->bl.m,x,y,type,ALL_SAMEMAP); //FIXME: once players leave the map, the client 'forgets' this information. } @@ -13458,8 +13811,7 @@ void clif_parse_GMChangeMapType(int fd, struct map_session_data *sd) /// type: /// 0 = (/ex nick) deny speech from nick /// 1 = (/in nick) allow speech from nick -void clif_parse_PMIgnore(int fd, struct map_session_data* sd) -{ +void clif_parse_PMIgnore(int fd, struct map_session_data* sd) { char* nick; uint8 type; int i; @@ -13469,7 +13821,7 @@ void clif_parse_PMIgnore(int fd, struct map_session_data* sd) type = RFIFOB(fd,26); if( type == 0 ) { // Add name to ignore list (block) - if (strcmp(iMap->wisp_server_name, nick) == 0) { + if (strcmp(map->wisp_server_name, nick) == 0) { clif->wisexin(sd, type, 1); // fail return; } @@ -13595,6 +13947,10 @@ void clif_parse_NoviceDoriDori(int fd, struct map_session_data *sd) /// "Help me out~ Please~ T_T" void clif_parse_NoviceExplosionSpirits(int fd, struct map_session_data *sd) { + /* [Ind/Hercules] */ + /* game client is currently broken on this (not sure the packetver range) */ + /* it sends the request when the criteria doesn't match (and of course we let it fail) */ + /* so restoring the old parse_globalmes method. */ if( ( sd->class_&MAPID_UPPERMASK ) == MAPID_SUPER_NOVICE ) { unsigned int next = pc->nextbaseexp(sd); if( next == 0 ) next = pc->thisbaseexp(sd); @@ -13602,7 +13958,7 @@ void clif_parse_NoviceExplosionSpirits(int fd, struct map_session_data *sd) int percent = (int)( ( (float)sd->status.base_exp/(float)next )*1000. ); if( percent && ( percent%100 ) == 0 ) {// 10.0%, 20.0%, ..., 90.0% - sc_start(&sd->bl, status_skill2sc(MO_EXPLOSIONSPIRITS), 100, 17, skill->get_time(MO_EXPLOSIONSPIRITS, 5)); //Lv17-> +50 critical (noted by Poki) [Skotlex] + 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 } } @@ -13637,7 +13993,7 @@ void clif_friendslist_toggle(struct map_session_data *sd,int account_id, int cha } -//Subfunction called from clif_foreachclient to toggle friends on/off [Skotlex] +//Sub-function called from clif_foreachclient to toggle friends on/off [Skotlex] int clif_friendslist_toggle_sub(struct map_session_data *sd,va_list ap) { int account_id, char_id, online; @@ -13670,7 +14026,7 @@ void clif_friendslist_send(struct map_session_data *sd) } for (n = 0; n < i; n++) { //Sending the online players - if (iMap->charid2sd(sd->status.friends[n].char_id)) + if (map->charid2sd(sd->status.friends[n].char_id)) clif->friendslist_toggle(sd, sd->status.friends[n].account_id, sd->status.friends[n].char_id, 1); } } @@ -13717,12 +14073,11 @@ void clif_friendlist_req(struct map_session_data* sd, int account_id, int char_i /// Request to add a player as friend (CZ_ADD_FRIENDS). /// 0202 <name>.24B -void clif_parse_FriendsListAdd(int fd, struct map_session_data *sd) -{ +void clif_parse_FriendsListAdd(int fd, struct map_session_data *sd) { struct map_session_data *f_sd; int i; - f_sd = iMap->nick2sd((char*)RFIFOP(fd,2)); + f_sd = map->nick2sd((char*)RFIFOP(fd,2)); // ensure that the request player's friend list is not full ARR_FIND(0, MAX_FRIENDS, i, sd->status.friends[i].char_id == 0); @@ -13751,7 +14106,7 @@ void clif_parse_FriendsListAdd(int fd, struct map_session_data *sd) // Friend already exists for (i = 0; i < MAX_FRIENDS && sd->status.friends[i].char_id != 0; i++) { if (sd->status.friends[i].char_id == f_sd->status.char_id) { - clif->message(fd, msg_txt(671)); //"Friend already exists." + clif->message(fd, msg_txt(871)); //"Friend already exists." return; } } @@ -13787,7 +14142,7 @@ void clif_parse_FriendsListReply(int fd, struct map_session_data *sd) return; } - f_sd = iMap->id2sd(account_id); //The account id is the same as the bl.id of players. + f_sd = map->id2sd(account_id); //The account id is the same as the bl.id of players. if (f_sd == NULL) return; @@ -13847,12 +14202,12 @@ void clif_parse_FriendsListRemove(int fd, struct map_session_data *sd) (sd->status.friends[i].char_id != char_id || sd->status.friends[i].account_id != account_id); i++); if (i == MAX_FRIENDS) { - clif->message(fd, msg_txt(672)); //"Name not found in list." + clif->message(fd, msg_txt(872)); //"Name not found in list." return; } //remove from friend's list first - if( (f_sd = iMap->id2sd(account_id)) && f_sd->status.char_id == char_id) { + if( (f_sd = map->id2sd(account_id)) && f_sd->status.char_id == char_id) { for (i = 0; i < MAX_FRIENDS && (f_sd->status.friends[i].char_id != sd->status.char_id || f_sd->status.friends[i].account_id != sd->status.account_id); i++); @@ -13871,8 +14226,8 @@ void clif_parse_FriendsListRemove(int fd, struct map_session_data *sd) } } else { //friend not online -- ask char server to delete from his friendlist - if(chrif_removefriend(char_id,sd->status.char_id)) { // char-server offline, abort - clif->message(fd, msg_txt(673)); //"This action can't be performed at the moment. Please try again later." + if(!chrif->removefriend(char_id,sd->status.char_id)) { // char-server offline, abort + clif->message(fd, msg_txt(873)); //"This action can't be performed at the moment. Please try again later." return; } } @@ -13885,7 +14240,7 @@ void clif_parse_FriendsListRemove(int fd, struct map_session_data *sd) memcpy(&sd->status.friends[j-1], &sd->status.friends[j], sizeof(sd->status.friends[0])); memset(&sd->status.friends[MAX_FRIENDS-1], 0, sizeof(sd->status.friends[MAX_FRIENDS-1])); - clif->message(fd, msg_txt(674)); //"Friend removed" + clif->message(fd, msg_txt(874)); //"Friend removed" WFIFOHEAD(fd,packet_len(0x20a)); WFIFOW(fd,0) = 0x20a; @@ -13919,50 +14274,118 @@ void clif_parse_PVPInfo(int fd,struct map_session_data *sd) clif->PVPInfo(sd); } +/// Ranking list -/// /blacksmith list (ZC_BLACKSMITH_RANK). -/// 0219 { <name>.24B }*10 { <point>.L }*10 -void clif_blacksmith(struct map_session_data* sd) -{ - int i, fd = sd->fd; +/// ranking pointlist { <name>.24B <point>.L }*10 +void clif_ranklist_sub(unsigned char *buf, enum fame_list_type type) { const char* name; + struct fame_list* list; + int i; - WFIFOHEAD(fd,packet_len(0x219)); - WFIFOW(fd,0) = 0x219; - //Packet size limits this list to 10 elements. [Skotlex] - for (i = 0; i < 10 && i < MAX_FAME_LIST; i++) { - if (smith_fame_list[i].id > 0) { - if (strcmp(smith_fame_list[i].name, "-") == 0 && - (name = iMap->charid2nick(smith_fame_list[i].id)) != NULL) - { - strncpy((char *)(WFIFOP(fd, 2 + 24 * i)), name, NAME_LENGTH); - } else - strncpy((char *)(WFIFOP(fd, 2 + 24 * i)), smith_fame_list[i].name, NAME_LENGTH); - } else - strncpy((char *)(WFIFOP(fd, 2 + 24 * i)), "None", 5); - WFIFOL(fd, 242 + i * 4) = smith_fame_list[i].fame; + switch( type ) { + case RANKTYPE_BLACKSMITH: list = pc->smith_fame_list; break; + case RANKTYPE_ALCHEMIST: list = pc->chemist_fame_list; break; + case RANKTYPE_TAEKWON: list = pc->taekwon_fame_list; break; + default: return; // Unsupported + } + + // Packet size limits this list to 10 elements. [Skotlex] + for( i = 0; i < 10 && i < MAX_FAME_LIST; i++ ) { + if( list[i].id > 0 ) { + if( strcmp(list[i].name, "-") == 0 && (name = map->charid2nick(list[i].id)) != NULL ) { + strncpy((char *)(WBUFP(buf, 24 * i)), name, NAME_LENGTH); + } else { + strncpy((char *)(WBUFP(buf, 24 * i)), list[i].name, NAME_LENGTH); + } + } else { + strncpy((char *)(WBUFP(buf, 24 * i)), "None", 5); + } + WBUFL(buf, 24 * 10 + i * 4) = list[i].fame; //points } - for(;i < 10; i++) { //In case the MAX is less than 10. - strncpy((char *)(WFIFOP(fd, 2 + 24 * i)), "Unavailable", 12); - WFIFOL(fd, 242 + i * 4) = 0; + for( ;i < 10; i++ ) { // In case the MAX is less than 10. + strncpy((char *)(WBUFP(buf, 24 * i)), "Unavailable", 12); + WBUFL(buf, 24 * 10 + i * 4) = 0; } +} - WFIFOSET(fd, packet_len(0x219)); +/// 097d <RankingType>.W {<CharName>.24B <point>L}*10 <mypoint>L (ZC_ACK_RANKING) +void clif_ranklist(struct map_session_data *sd, enum fame_list_type type) { + int fd = sd->fd; + int mypoint = 0; + int upperMask = sd->class_&MAPID_UPPERMASK; + + WFIFOHEAD(fd, 288); + WFIFOW(fd, 0) = 0x97d; + WFIFOW(fd, 2) = type; + clif_ranklist_sub(WFIFOP(fd,4), type); + + if( (upperMask == MAPID_BLACKSMITH && type == RANKTYPE_BLACKSMITH) + || (upperMask == MAPID_ALCHEMIST && type == RANKTYPE_ALCHEMIST) + || (upperMask == MAPID_TAEKWON && type == RANKTYPE_TAEKWON) + ) { + mypoint = sd->status.fame; + } else { + mypoint = 0; + } + + WFIFOL(fd, 284) = mypoint; //mypoint + WFIFOSET(fd, 288); +} + +/* + * 097c <type> (CZ_REQ_RANKING) + * */ +void clif_parse_ranklist(int fd, struct map_session_data *sd) { + int16 type = RFIFOW(fd, 2); //type + + switch( type ) { + case RANKTYPE_BLACKSMITH: + case RANKTYPE_ALCHEMIST: + case RANKTYPE_TAEKWON: + clif->ranklist(sd, type); // pk_list unsupported atm + break; + } +} + +// 097e <RankingType>.W <point>.L <TotalPoint>.L (ZC_UPDATE_RANKING_POINT) +void clif_update_rankingpoint(struct map_session_data *sd, enum fame_list_type type, int points) { +#if PACKETVER < 20130710 + switch( type ) { + case RANKTYPE_BLACKSMITH: clif->fame_blacksmith(sd,points); break; + case RANKTYPE_ALCHEMIST: clif->fame_alchemist(sd,points); break; + case RANKTYPE_TAEKWON: clif->fame_taekwon(sd,points); break; + } +#else + int fd = sd->fd; + WFIFOHEAD(fd, 12); + WFIFOW(fd, 0) = 0x97e; + WFIFOW(fd, 2) = type; + WFIFOL(fd, 4) = points; + WFIFOL(fd, 8) = sd->status.fame; + WFIFOSET(fd, 12); +#endif } +/// /blacksmith list (ZC_BLACKSMITH_RANK). +/// 0219 { <name>.24B }*10 { <point>.L }*10 +void clif_blacksmith(struct map_session_data* sd) { + int fd = sd->fd; + + WFIFOHEAD(fd,packet_len(0x219)); + WFIFOW(fd,0) = 0x219; + clif_ranklist_sub(WFIFOP(fd, 2), RANKTYPE_BLACKSMITH); + WFIFOSET(fd, packet_len(0x219)); +} /// /blacksmith (CZ_BLACKSMITH_RANK). /// 0217 -void clif_parse_Blacksmith(int fd,struct map_session_data *sd) -{ +void clif_parse_Blacksmith(int fd,struct map_session_data *sd) { clif->blacksmith(sd); } - /// Notification about backsmith points (ZC_BLACKSMITH_POINT). /// 021b <points>.L <total points>.L -void clif_fame_blacksmith(struct map_session_data *sd, int points) -{ +void clif_fame_blacksmith(struct map_session_data *sd, int points) { int fd = sd->fd; WFIFOHEAD(fd,packet_len(0x21b)); @@ -13972,49 +14395,26 @@ void clif_fame_blacksmith(struct map_session_data *sd, int points) WFIFOSET(fd, packet_len(0x21b)); } - /// /alchemist list (ZC_ALCHEMIST_RANK). /// 021a { <name>.24B }*10 { <point>.L }*10 void clif_alchemist(struct map_session_data* sd) { - int i, fd = sd->fd; - const char* name; + int fd = sd->fd; WFIFOHEAD(fd,packet_len(0x21a)); WFIFOW(fd,0) = 0x21a; - //Packet size limits this list to 10 elements. [Skotlex] - for (i = 0; i < 10 && i < MAX_FAME_LIST; i++) { - if (chemist_fame_list[i].id > 0) { - if (strcmp(chemist_fame_list[i].name, "-") == 0 && - (name = iMap->charid2nick(chemist_fame_list[i].id)) != NULL) - { - memcpy(WFIFOP(fd, 2 + 24 * i), name, NAME_LENGTH); - } else - memcpy(WFIFOP(fd, 2 + 24 * i), chemist_fame_list[i].name, NAME_LENGTH); - } else - memcpy(WFIFOP(fd, 2 + 24 * i), "None", NAME_LENGTH); - WFIFOL(fd, 242 + i * 4) = chemist_fame_list[i].fame; - } - for(;i < 10; i++) { //In case the MAX is less than 10. - memcpy(WFIFOP(fd, 2 + 24 * i), "Unavailable", NAME_LENGTH); - WFIFOL(fd, 242 + i * 4) = 0; - } - + clif_ranklist_sub(WFIFOP(fd,2), RANKTYPE_ALCHEMIST); WFIFOSET(fd, packet_len(0x21a)); } - /// /alchemist (CZ_ALCHEMIST_RANK). /// 0218 -void clif_parse_Alchemist(int fd,struct map_session_data *sd) -{ +void clif_parse_Alchemist(int fd,struct map_session_data *sd) { clif->alchemist(sd); } - /// Notification about alchemist points (ZC_ALCHEMIST_POINT). /// 021c <points>.L <total points>.L -void clif_fame_alchemist(struct map_session_data *sd, int points) -{ +void clif_fame_alchemist(struct map_session_data *sd, int points) { int fd = sd->fd; WFIFOHEAD(fd,packet_len(0x21c)); @@ -14024,48 +14424,26 @@ void clif_fame_alchemist(struct map_session_data *sd, int points) WFIFOSET(fd, packet_len(0x21c)); } - /// /taekwon list (ZC_TAEKWON_RANK). /// 0226 { <name>.24B }*10 { <point>.L }*10 void clif_taekwon(struct map_session_data* sd) { - int i, fd = sd->fd; - const char* name; + int fd = sd->fd; WFIFOHEAD(fd,packet_len(0x226)); WFIFOW(fd,0) = 0x226; - //Packet size limits this list to 10 elements. [Skotlex] - for (i = 0; i < 10 && i < MAX_FAME_LIST; i++) { - if (taekwon_fame_list[i].id > 0) { - if (strcmp(taekwon_fame_list[i].name, "-") == 0 && - (name = iMap->charid2nick(taekwon_fame_list[i].id)) != NULL) - { - memcpy(WFIFOP(fd, 2 + 24 * i), name, NAME_LENGTH); - } else - memcpy(WFIFOP(fd, 2 + 24 * i), taekwon_fame_list[i].name, NAME_LENGTH); - } else - memcpy(WFIFOP(fd, 2 + 24 * i), "None", NAME_LENGTH); - WFIFOL(fd, 242 + i * 4) = taekwon_fame_list[i].fame; - } - for(;i < 10; i++) { //In case the MAX is less than 10. - memcpy(WFIFOP(fd, 2 + 24 * i), "Unavailable", NAME_LENGTH); - WFIFOL(fd, 242 + i * 4) = 0; - } + clif_ranklist_sub(WFIFOP(fd,2), RANKTYPE_TAEKWON); WFIFOSET(fd, packet_len(0x226)); } - /// /taekwon (CZ_TAEKWON_RANK). /// 0225 -void clif_parse_Taekwon(int fd,struct map_session_data *sd) -{ +void clif_parse_Taekwon(int fd,struct map_session_data *sd) { clif->taekwon(sd); } - /// Notification about taekwon points (ZC_TAEKWON_POINT). /// 0224 <points>.L <total points>.L -void clif_fame_taekwon(struct map_session_data *sd, int points) -{ +void clif_fame_taekwon(struct map_session_data *sd, int points) { int fd = sd->fd; WFIFOHEAD(fd,packet_len(0x224)); @@ -14075,7 +14453,6 @@ void clif_fame_taekwon(struct map_session_data *sd, int points) WFIFOSET(fd, packet_len(0x224)); } - /// /pk list (ZC_KILLER_RANK). /// 0238 { <name>.24B }*10 { <point>.L }*10 void clif_ranking_pk(struct map_session_data* sd) { @@ -14093,8 +14470,7 @@ void clif_ranking_pk(struct map_session_data* sd) { /// /pk (CZ_KILLER_RANK). /// 0237 -void clif_parse_RankingPk(int fd,struct map_session_data *sd) -{ +void clif_parse_RankingPk(int fd,struct map_session_data *sd) { clif->ranking_pk(sd); } @@ -14115,7 +14491,7 @@ void clif_parse_FeelSaveOk(int fd,struct map_session_data *sd) sd->feel_map[i].index = map_id2index(sd->bl.m); sd->feel_map[i].m = sd->bl.m; - pc_setglobalreg(sd,sg_info[i].feel_var,sd->feel_map[i].index); + pc_setglobalreg(sd,script->add_str(pc->sg_info[i].feel_var),sd->feel_map[i].index); //Are these really needed? Shouldn't they show up automatically from the feel save packet? // clif_misceffect2(&sd->bl, 0x1b0); @@ -14164,9 +14540,9 @@ void clif_parse_HomMoveToMaster(int fd, struct map_session_data *sd) else return; - unit_calc_pos(bl, sd->bl.x, sd->bl.y, sd->ud.dir); - ud = unit_bl2ud(bl); - unit_walktoxy(bl, ud->to_x, ud->to_y, 4); + unit->calc_pos(bl, sd->bl.x, sd->bl.y, sd->ud.dir); + ud = unit->bl2ud(bl); + unit->walktoxy(bl, ud->to_x, ud->to_y, 4); } @@ -14187,7 +14563,7 @@ void clif_parse_HomMoveTo(int fd, struct map_session_data *sd) else return; - unit_walktoxy(bl, x, y, 4); + unit->walktoxy(bl, x, y, 4); } @@ -14208,8 +14584,8 @@ void clif_parse_HomAttack(int fd,struct map_session_data *sd) bl = &sd->md->bl; else return; - unit_stop_attack(bl); - unit_attack(bl, target_id, action_type != 0); + unit->stop_attack(bl); + unit->attack(bl, target_id, action_type != 0); } @@ -14235,21 +14611,29 @@ void clif_parse_HomMenu(int fd, struct map_session_data *sd) { //[orn] /// Request to resurrect oneself using Token of Siegfried (CZ_STANDING_RESURRECTION). /// 0292 -void clif_parse_AutoRevive(int fd, struct map_session_data *sd) -{ +void clif_parse_AutoRevive(int fd, struct map_session_data *sd) { int item_position = pc->search_inventory(sd, ITEMID_TOKEN_OF_SIEGFRIED); + int hpsp = 100; - if (item_position < 0) - return; + if (item_position == INDEX_NOT_FOUND) { + if (sd->sc.data[SC_LIGHT_OF_REGENE]) + hpsp = 20 * sd->sc.data[SC_LIGHT_OF_REGENE]->val1; + else + return; + } if (sd->sc.data[SC_HELLPOWER]) //Cannot res while under the effect of SC_HELLPOWER. return; - if (!status_revive(&sd->bl, 100, 100)) + if (!status->revive(&sd->bl, hpsp, hpsp)) return; + if (item_position == INDEX_NOT_FOUND) + status_change_end(&sd->bl,SC_LIGHT_OF_REGENE,INVALID_TIMER); + else + pc->delitem(sd, item_position, 1, 0, 1, LOG_TYPE_CONSUME); + clif->skill_nodamage(&sd->bl,&sd->bl,ALL_RESURRECTION,4,1); - pc->delitem(sd, item_position, 1, 0, 1, LOG_TYPE_CONSUME); } @@ -14288,7 +14672,7 @@ void clif_check(int fd, struct map_session_data* pl_sd) { WFIFOW(fd,34) = pl_sd->battle_status.flee2/10; WFIFOW(fd,36) = pl_sd->battle_status.cri/10; WFIFOW(fd,38) = (2000-pl_sd->battle_status.amotion)/10; // aspd - WFIFOW(fd,40) = 0; // FIXME: What is 'plusASPD' supposed to be? Maybe adelay? + WFIFOW(fd,40) = 0; // FIXME: What is 'plusASPD' supposed to be? Maybe a delay? WFIFOSET(fd,packet_len(0x214)); } @@ -14306,7 +14690,7 @@ void clif_parse_Check(int fd, struct map_session_data *sd) safestrncpy(charname, (const char*)RFIFOP(fd,packet_db[RFIFOW(fd,0)].pos[0]), sizeof(charname)); - if( ( pl_sd = iMap->nick2sd(charname) ) == NULL || pc->get_group_level(sd) < pc->get_group_level(pl_sd) ) { + if( ( pl_sd = map->nick2sd(charname) ) == NULL || pc_get_group_level(sd) < pc_get_group_level(pl_sd) ) { return; } @@ -14353,7 +14737,7 @@ void clif_Mail_getattachment(int fd, uint8 flag) /// 0249 <result>.B /// result: /// 0 = success -/// 1 = recipinent does not exist +/// 1 = recipient does not exist void clif_Mail_send(int fd, bool fail) { WFIFOHEAD(fd,packet_len(0x249)); @@ -14456,7 +14840,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, strlen(output)); } } @@ -14468,7 +14852,7 @@ void clif_parse_Mail_refreshinbox(int fd, struct map_session_data *sd) struct mail_data* md = &sd->mail.inbox; if( md->amount < MAIL_MAX_INBOX && (md->full || sd->mail.changed) ) - intif_Mail_requestinbox(sd->status.char_id, 1); + intif->Mail_requestinbox(sd->status.char_id, 1); else clif->mail_refreshinbox(sd); @@ -14494,7 +14878,7 @@ 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; - int msg_len = strlen(msg->body), len; + size_t msg_len = strlen(msg->body), len; if( msg_len == 0 ) { strcpy(msg->body, "(no message)"); @@ -14512,7 +14896,7 @@ void clif_Mail_read(struct map_session_data *sd, int mail_id) WFIFOL(fd,72) = 0; WFIFOL(fd,76) = msg->zeny; - if( item->nameid && (data = itemdb_exists(item->nameid)) != NULL ) { + if( item->nameid && (data = itemdb->exists(item->nameid)) != NULL ) { WFIFOL(fd,80) = item->amount; WFIFOW(fd,84) = (data->view_id)?data->view_id:item->nameid; WFIFOW(fd,86) = data->type; @@ -14532,7 +14916,7 @@ void clif_Mail_read(struct map_session_data *sd, int mail_id) if (msg->status == MAIL_UNREAD) { msg->status = MAIL_READ; - intif_Mail_read(mail_id); + intif->Mail_read(mail_id); clif->pMail_refreshinbox(fd, sd); } } @@ -14562,7 +14946,7 @@ void clif_parse_Mail_getattach(int fd, struct map_session_data *sd) int i; bool fail = false; - if( !chrif_isconnected() ) + if( !chrif->isconnected() ) return; if( mail_id <= 0 ) return; @@ -14585,9 +14969,14 @@ void clif_parse_Mail_getattach(int fd, struct map_session_data *sd) struct item_data *data; unsigned int weight; - if ((data = itemdb_exists(sd->mail.inbox.msg[i].item.nameid)) == NULL) + if ((data = itemdb->exists(sd->mail.inbox.msg[i].item.nameid)) == NULL) return; + if( pc_is90overweight(sd) ) { + clif->mail_getattachment(fd, 2); + return; + } + switch( pc->checkadditem(sd, data->nameid, sd->mail.inbox.msg[i].item.amount) ) { case ADDITEM_NEW: fail = ( pc->inventoryblank(sd) == 0 ); @@ -14612,7 +15001,7 @@ void clif_parse_Mail_getattach(int fd, struct map_session_data *sd) memset(&sd->mail.inbox.msg[i].item, 0, sizeof(struct item)); clif->mail_read(sd, mail_id); - intif_Mail_getattach(sd->status.char_id, mail_id); + intif->Mail_getattach(sd->status.char_id, mail_id); } @@ -14623,7 +15012,7 @@ void clif_parse_Mail_delete(int fd, struct map_session_data *sd) int mail_id = RFIFOL(fd,2); int i; - if( !chrif_isconnected() ) + if( !chrif->isconnected() ) return; if( mail_id <= 0 ) return; @@ -14639,7 +15028,7 @@ void clif_parse_Mail_delete(int fd, struct map_session_data *sd) return; } - intif_Mail_delete(sd->status.char_id, mail_id); + intif->Mail_delete(sd->status.char_id, mail_id); } } @@ -14658,7 +15047,7 @@ void clif_parse_Mail_return(int fd, struct map_session_data *sd) ARR_FIND(0, MAIL_MAX_INBOX, i, sd->mail.inbox.msg[i].id == mail_id); if( i < MAIL_MAX_INBOX && sd->mail.inbox.msg[i].send_id != 0 ) - intif_Mail_return(sd->status.char_id, mail_id); + intif->Mail_return(sd->status.char_id, mail_id); else clif->mail_return(sd->fd, mail_id, 1); } @@ -14672,7 +15061,7 @@ void clif_parse_Mail_setattach(int fd, struct map_session_data *sd) int amount = RFIFOL(fd,4); unsigned char flag; - if( !chrif_isconnected() ) + if( !chrif->isconnected() ) return; if (idx < 0 || amount < 0) return; @@ -14706,7 +15095,7 @@ void clif_parse_Mail_send(int fd, struct map_session_data *sd) struct mail_message msg; int body_len; - if( !chrif_isconnected() ) + if( !chrif->isconnected() ) return; if( sd->state.trading ) return; @@ -14716,8 +15105,8 @@ void clif_parse_Mail_send(int fd, struct map_session_data *sd) return; } - if( DIFF_TICK(sd->cansendmail_tick, iTimer->gettick()) > 0 ) { - clif->message(sd->fd,msg_txt(675)); //"Cannot send mails too fast!!." + if( DIFF_TICK(sd->cansendmail_tick, timer->gettick()) > 0 ) { + clif->message(sd->fd,msg_txt(875)); //"Cannot send mails too fast!!." clif->mail_send(fd, true); // fail return; } @@ -14751,10 +15140,10 @@ void clif_parse_Mail_send(int fd, struct map_session_data *sd) memset(msg.body, 0x00, MAIL_BODY_LENGTH); msg.timestamp = time(NULL); - if( !intif_Mail_send(sd->status.account_id, &msg) ) + if( !intif->Mail_send(sd->status.account_id, &msg) ) mail->deliveryfail(sd, &msg); - sd->cansendmail_tick = iTimer->gettick() + 1000; // 1 Second flood Protection + sd->cansendmail_tick = timer->gettick() + 1000; // 1 Second flood Protection } @@ -14774,6 +15163,9 @@ void clif_Auction_openwindow(struct map_session_data *sd) if( sd->state.storage_flag || sd->state.vending || sd->state.buyingstore || sd->state.trading ) return; + if( !battle_config.feature_auction ) + return; + WFIFOHEAD(fd,packet_len(0x25f)); WFIFOW(fd,0) = 0x25f; WFIFOL(fd,2) = 0; @@ -14803,7 +15195,7 @@ void clif_Auction_results(struct map_session_data *sd, short count, short pages, WFIFOL(fd,k) = auction.auction_id; safestrncpy((char*)WFIFOP(fd,4+k), auction.seller_name, NAME_LENGTH); - if( (item = itemdb_exists(auction.item.nameid)) != NULL && item->view_id > 0 ) + if( (item = itemdb->exists(auction.item.nameid)) != NULL && item->view_id > 0 ) WFIFOW(fd,28+k) = item->view_id; else WFIFOW(fd,28+k) = auction.item.nameid; @@ -14863,6 +15255,9 @@ void clif_parse_Auction_setitem(int fd, struct map_session_data *sd) int amount = RFIFOL(fd,4); // Always 1 struct item_data *item; + if( !battle_config.feature_auction ) + return; + if( sd->auction.amount > 0 ) sd->auction.amount = 0; @@ -14876,16 +15271,17 @@ void clif_parse_Auction_setitem(int fd, struct map_session_data *sd) return; } - if( (item = itemdb_exists(sd->status.inventory[idx].nameid)) != NULL && !(item->type == IT_ARMOR || item->type == IT_PETARMOR || item->type == IT_WEAPON || item->type == IT_CARD || item->type == IT_ETC) ) + if( (item = itemdb->exists(sd->status.inventory[idx].nameid)) != NULL && !(item->type == IT_ARMOR || item->type == IT_PETARMOR || item->type == IT_WEAPON || item->type == IT_CARD || item->type == IT_ETC) ) { // Consumable or pets are not allowed clif->auction_setitem(sd->fd, idx, true); return; } - if( !pc->can_give_items(sd) || sd->status.inventory[idx].expire_time || + if( !pc_can_give_items(sd) || sd->status.inventory[idx].expire_time || !sd->status.inventory[idx].identify || - !itemdb_canauction(&sd->status.inventory[idx],pc->get_group_level(sd)) ) { // Quest Item or something else - clif->auction_setitem(sd->fd, idx, true); + !itemdb_canauction(&sd->status.inventory[idx],pc_get_group_level(sd)) || // Quest Item or something else + (sd->status.inventory[idx].bound && !pc_can_give_bound_items(sd)) ) { + clif->auction_setitem(sd->fd, idx, true); return; } @@ -14938,6 +15334,9 @@ void clif_parse_Auction_register(int fd, struct map_session_data *sd) struct auction_data auction; struct item_data *item; + if( !battle_config.feature_auction ) + return; + auction.price = RFIFOL(fd,2); auction.buynow = RFIFOL(fd,6); auction.hours = RFIFOW(fd,10); @@ -14958,9 +15357,8 @@ void clif_parse_Auction_register(int fd, struct map_session_data *sd) return; } - // Auction checks... if( sd->status.zeny < (auction.hours * battle_config.auction_feeperhour) ) { - clif->auction_message(fd, 5); // You do not have enough zeny to pay the Auction Fee. + clif_Auction_message(fd, 5); // You do not have enough zeny to pay the Auction Fee. return; } @@ -14983,19 +15381,26 @@ void clif_parse_Auction_register(int fd, struct map_session_data *sd) return; } - if( (item = itemdb_exists(sd->status.inventory[sd->auction.index].nameid)) == NULL ) + if( (item = itemdb->exists(sd->status.inventory[sd->auction.index].nameid)) == NULL ) { // Just in case clif->auction_message(fd, 2); // The auction has been canceled return; } + // Auction checks... + if( sd->status.inventory[sd->auction.index].bound && !pc_can_give_bound_items(sd) ) { + clif->message(sd->fd, msg_txt(293)); + clif->auction_message(fd, 2); // The auction has been canceled + return; + } + safestrncpy(auction.item_name, item->jname, sizeof(auction.item_name)); auction.type = item->type; memcpy(&auction.item, &sd->status.inventory[sd->auction.index], sizeof(struct item)); auction.item.amount = 1; auction.timestamp = 0; - if( !intif_Auction_register(&auction) ) + if( !intif->Auction_register(&auction) ) clif->auction_message(fd, 4); // No Char Server? lets say something to the client else { @@ -15015,7 +15420,7 @@ void clif_parse_Auction_cancel(int fd, struct map_session_data *sd) { unsigned int auction_id = RFIFOL(fd,2); - intif_Auction_cancel(sd->status.char_id, auction_id); + intif->Auction_cancel(sd->status.char_id, auction_id); } @@ -15025,7 +15430,7 @@ void clif_parse_Auction_close(int fd, struct map_session_data *sd) { unsigned int auction_id = RFIFOL(fd,2); - intif_Auction_close(sd->status.char_id, auction_id); + intif->Auction_close(sd->status.char_id, auction_id); } @@ -15036,7 +15441,7 @@ void clif_parse_Auction_bid(int fd, struct map_session_data *sd) unsigned int auction_id = RFIFOL(fd,2); int bid = RFIFOL(fd,6); - if( !pc->can_give_items(sd) ) { //They aren't supposed to give zeny [Inkfish] + if( !pc_can_give_items(sd) ) { //They aren't supposed to give zeny [Inkfish] clif->message(sd->fd, msg_txt(246)); return; } @@ -15045,11 +15450,11 @@ void clif_parse_Auction_bid(int fd, struct map_session_data *sd) clif->auction_message(fd, 0); // You have failed to bid into the auction else if( bid > sd->status.zeny ) clif->auction_message(fd, 8); // You do not have enough zeny - else if ( CheckForCharServer() ) // char server is down (bugreport:1138) + else if ( intif->CheckForCharServer() ) // char server is down (bugreport:1138) clif->auction_message(fd, 0); // You have failed to bid into the auction else { pc->payzeny(sd, bid, LOG_TYPE_AUCTION, NULL); - intif_Auction_bid(sd->status.char_id, sd->status.name, auction_id, bid); + intif->Auction_bid(sd->status.char_id, sd->status.name, auction_id, bid); } } @@ -15069,10 +15474,13 @@ void clif_parse_Auction_search(int fd, struct map_session_data* sd) short type = RFIFOW(fd,2), page = RFIFOW(fd,32); int price = RFIFOL(fd,4); // FIXME: bug #5071 + if( !battle_config.feature_auction ) + return; + clif->pAuction_cancelreg(fd, sd); safestrncpy(search_text, (char*)RFIFOP(fd,8), sizeof(search_text)); - intif_Auction_requestlist(sd->status.char_id, type, price, search_text, page); + intif->Auction_requestlist(sd->status.char_id, type, price, search_text, page); } @@ -15084,9 +15492,13 @@ void clif_parse_Auction_search(int fd, struct map_session_data* sd) void clif_parse_Auction_buysell(int fd, struct map_session_data* sd) { short type = RFIFOW(fd,2) + 6; + + if( !battle_config.feature_auction ) + return; + clif->pAuction_cancelreg(fd, sd); - intif_Auction_requestlist(sd->status.char_id, type, 0, "", 1); + intif->Auction_requestlist(sd->status.char_id, type, 0, "", 1); } @@ -15096,9 +15508,11 @@ void clif_parse_Auction_buysell(int fd, struct map_session_data* sd) /// List of items offered in a cash shop (ZC_PC_CASH_POINT_ITEMLIST). /// 0287 <packet len>.W <cash point>.L { <sell price>.L <discount price>.L <item type>.B <name id>.W }* /// 0287 <packet len>.W <cash point>.L <kafra point>.L { <sell price>.L <discount price>.L <item type>.B <name id>.W }* (PACKETVER >= 20070711) -void clif_cashshop_show(struct map_session_data *sd, struct npc_data *nd) -{ - int fd,i; +void clif_cashshop_show(struct map_session_data *sd, struct npc_data *nd) { + struct npc_item_list *shop = NULL; + unsigned short shop_size = 0; + int fd,i, c = 0; + int currency[2] = { 0,0 }; #if PACKETVER < 20070711 const int offset = 8; #else @@ -15108,50 +15522,71 @@ void clif_cashshop_show(struct map_session_data *sd, struct npc_data *nd) nullpo_retv(sd); nullpo_retv(nd); + if( nd->subtype == SCRIPT ) { + shop = nd->u.scr.shop->item; + shop_size = nd->u.scr.shop->items; + + npc->trader_count_funds(nd, sd); + + currency[0] = npc->trader_funds[0]; + currency[1] = npc->trader_funds[1]; + } else { + shop = nd->u.shop.shop_item; + shop_size = nd->u.shop.count; + + currency[0] = sd->cashPoints; + currency[1] = sd->kafraPoints; + } + fd = sd->fd; sd->npc_shopid = nd->bl.id; - WFIFOHEAD(fd,offset+nd->u.shop.count*11); + WFIFOHEAD(fd,offset+shop_size*11); WFIFOW(fd,0) = 0x287; - WFIFOW(fd,2) = offset+nd->u.shop.count*11; - WFIFOL(fd,4) = sd->cashPoints; // Cash Points + /* 0x2 = length, set after parsing */ + WFIFOL(fd,4) = currency[0]; // Cash Points #if PACKETVER >= 20070711 - WFIFOL(fd,8) = sd->kafraPoints; // Kafra Points + WFIFOL(fd,8) = currency[1]; // Kafra Points #endif - for( i = 0; i < nd->u.shop.count; i++ ) { - struct item_data* id = itemdb_search(nd->u.shop.shop_item[i].nameid); - WFIFOL(fd,offset+0+i*11) = nd->u.shop.shop_item[i].value; - WFIFOL(fd,offset+4+i*11) = nd->u.shop.shop_item[i].value; // Discount Price - WFIFOB(fd,offset+8+i*11) = itemtype(id->type); - WFIFOW(fd,offset+9+i*11) = ( id->view_id > 0 ) ? id->view_id : id->nameid; + for( i = 0; i < shop_size; i++ ) { + if( shop[i].nameid ) { + struct item_data* id = itemdb->search(shop[i].nameid); + WFIFOL(fd,offset+0+i*11) = shop[i].value; + WFIFOL(fd,offset+4+i*11) = shop[i].value; // Discount Price + WFIFOB(fd,offset+8+i*11) = itemtype(id->type); + WFIFOW(fd,offset+9+i*11) = ( id->view_id > 0 ) ? id->view_id : id->nameid; + c++; + } } + WFIFOW(fd,2) = offset+c*11; WFIFOSET(fd,WFIFOW(fd,2)); } - /// Cashshop Buy Ack (ZC_PC_CASH_POINT_UPDATE). /// 0289 <cash point>.L <error>.W /// 0289 <cash point>.L <kafra point>.L <error>.W (PACKETVER >= 20070711) -/// error: -/// 0 = The deal has successfully completed. (ERROR_TYPE_NONE) -/// 1 = The Purchase has failed because the NPC does not exist. (ERROR_TYPE_NPC) -/// 2 = The Purchase has failed because the Kafra Shop System is not working correctly. (ERROR_TYPE_SYSTEM) -/// 3 = You are over your Weight Limit. (ERROR_TYPE_INVENTORY_WEIGHT) -/// 4 = You cannot purchase items while you are in a trade. (ERROR_TYPE_EXCHANGE) -/// 5 = The Purchase has failed because the Item Information was incorrect. (ERROR_TYPE_ITEM_ID) -/// 6 = You do not have enough Kafra Credit Points. (ERROR_TYPE_MONEY) -/// 7 = You can purchase up to 10 items. -/// 8 = Some items could not be purchased. +/// For error return codes see enum cashshop_error@clif.h void clif_cashshop_ack(struct map_session_data* sd, int error) { - int fd = sd->fd; + struct npc_data *nd; + int fd = sd->fd; + int currency[2] = { 0,0 }; + + if( (nd = map->id2nd(sd->npc_shopid)) && nd->subtype == SCRIPT ) { + npc->trader_count_funds(nd,sd); + currency[0] = npc->trader_funds[0]; + currency[1] = npc->trader_funds[1]; + } else { + currency[0] = sd->cashPoints; + currency[1] = sd->kafraPoints; + } WFIFOHEAD(fd, packet_len(0x289)); WFIFOW(fd,0) = 0x289; - WFIFOL(fd,2) = sd->cashPoints; + WFIFOL(fd,2) = currency[0]; #if PACKETVER < 20070711 WFIFOW(fd,6) = TOW(error); #else - WFIFOL(fd,6) = sd->kafraPoints; + WFIFOL(fd,6) = currency[1]; WFIFOW(fd,10) = TOW(error); #endif WFIFOSET(fd, packet_len(0x289)); @@ -15175,7 +15610,7 @@ void clif_parse_cashshop_buy(int fd, struct map_session_data *sd) short amount = RFIFOW(fd,4); int points = RFIFOL(fd,6); - fail = npc_cashshop_buy(sd, nameid, amount, points); + fail = npc->cashshop_buy(sd, nameid, amount, points); #else int len = RFIFOW(fd,2); int points = RFIFOL(fd,4); @@ -15187,7 +15622,7 @@ void clif_parse_cashshop_buy(int fd, struct map_session_data *sd) ShowWarning("Player %u sent incorrect cash shop buy packet (len %u:%u)!\n", sd->status.char_id, len, 10 + count * 4); return; } - fail = npc_cashshop_buylist(sd,points,count,item_list); + fail = npc->cashshop_buylist(sd,points,count,item_list); #endif } @@ -15231,9 +15666,8 @@ void clif_Adopt_request(struct map_session_data *sd, struct map_session_data *sr /// Request to adopt a player (CZ_REQ_JOIN_BABY). /// 01f9 <account id>.L -void clif_parse_Adopt_request(int fd, struct map_session_data *sd) -{ - struct map_session_data *tsd = iMap->id2sd(RFIFOL(fd,2)), *p_sd = iMap->charid2sd(sd->status.partner_id); +void clif_parse_Adopt_request(int fd, struct map_session_data *sd) { + struct map_session_data *tsd = map->id2sd(RFIFOL(fd,2)), *p_sd = map->charid2sd(sd->status.partner_id); if( pc->can_Adopt(sd, p_sd, tsd) ) { tsd->adopt_invite = sd->status.account_id; @@ -15247,13 +15681,12 @@ void clif_parse_Adopt_request(int fd, struct map_session_data *sd) /// answer: /// 0 = rejected /// 1 = accepted -void clif_parse_Adopt_reply(int fd, struct map_session_data *sd) -{ +void clif_parse_Adopt_reply(int fd, struct map_session_data *sd) { int p1_id = RFIFOL(fd,2); int p2_id = RFIFOL(fd,6); int result = RFIFOL(fd,10); - struct map_session_data* p1_sd = iMap->id2sd(p1_id); - struct map_session_data* p2_sd = iMap->id2sd(p2_id); + struct map_session_data* p1_sd = map->id2sd(p1_id); + struct map_session_data* p2_sd = map->id2sd(p2_id); int pid = sd->adopt_invite; sd->adopt_invite = 0; @@ -15293,11 +15726,11 @@ void clif_bossmapinfo(int fd, struct mob_data *md, short flag) } else WFIFOB(fd,2) = 2; // First Time } else if (md->spawn_timer != INVALID_TIMER) { // Boss is Dead - const struct TimerData * timer_data = iTimer->get_timer(md->spawn_timer); + const struct TimerData * timer_data = timer->get(md->spawn_timer); unsigned int seconds; int hours, minutes; - seconds = DIFF_TICK(timer_data->tick, iTimer->gettick()) / 1000 + 60; + seconds = (unsigned int)(DIFF_TICK(timer_data->tick, timer->gettick()) / 1000 + 60); hours = seconds / (60 * 60); seconds = seconds - (60 * 60 * hours); minutes = seconds / 60; @@ -15315,10 +15748,9 @@ void clif_bossmapinfo(int fd, struct mob_data *md, short flag) /// Requesting equip of a player (CZ_EQUIPWIN_MICROSCOPE). /// 02d6 <account id>.L -void clif_parse_ViewPlayerEquip(int fd, struct map_session_data* sd) -{ +void clif_parse_ViewPlayerEquip(int fd, struct map_session_data* sd) { int charid = RFIFOL(fd, 2); - struct map_session_data* tsd = iMap->id2sd(charid); + struct map_session_data* tsd = map->id2sd(charid); if (!tsd) return; @@ -15326,7 +15758,7 @@ void clif_parse_ViewPlayerEquip(int fd, struct map_session_data* sd) if( tsd->status.show_equip || pc_has_permission(sd, PC_PERM_VIEW_EQUIPMENT) ) clif->viewequip_ack(sd, tsd); else - clif->viewequip_fail(sd); + clif_viewequip_fail(sd); } @@ -15360,8 +15792,7 @@ void clif_parse_PartyTick(int fd, struct map_session_data* sd) /// Sends list of all quest states (ZC_ALL_QUEST_LIST). /// 02b1 <packet len>.W <num>.L { <quest id>.L <active>.B }*num -void clif_quest_send_list(struct map_session_data * sd) -{ +void clif_quest_send_list(struct map_session_data *sd) { int fd = sd->fd; int i; int len = sd->avail_quests*5+8; @@ -15382,12 +15813,11 @@ void clif_quest_send_list(struct map_session_data * sd) /// Sends list of all quest missions (ZC_ALL_QUEST_MISSION). /// 02b2 <packet len>.W <num>.L { <quest id>.L <start time>.L <expire time>.L <mobs>.W { <mob id>.L <mob count>.W <mob name>.24B }*3 }*num -void clif_quest_send_mission(struct map_session_data * sd) -{ +void clif_quest_send_mission(struct map_session_data *sd) { int fd = sd->fd; int i, j; int len = sd->avail_quests*104+8; - struct mob_db *mob; + struct mob_db *monster; WFIFOHEAD(fd, len); WFIFOW(fd, 0) = 0x2b2; @@ -15395,17 +15825,17 @@ void clif_quest_send_mission(struct map_session_data * sd) WFIFOL(fd, 4) = sd->avail_quests; for( i = 0; i < sd->avail_quests; i++ ) { + struct quest_db *qi = quest->db(sd->quest_log[i].quest_id); WFIFOL(fd, i*104+8) = sd->quest_log[i].quest_id; - WFIFOL(fd, i*104+12) = sd->quest_log[i].time - quest_db[sd->quest_index[i]].time; + WFIFOL(fd, i*104+12) = sd->quest_log[i].time - qi->time; WFIFOL(fd, i*104+16) = sd->quest_log[i].time; - WFIFOW(fd, i*104+20) = quest_db[sd->quest_index[i]].num_objectives; + WFIFOW(fd, i*104+20) = qi->num_objectives; - for( j = 0 ; j < quest_db[sd->quest_index[i]].num_objectives; j++ ) - { - WFIFOL(fd, i*104+22+j*30) = quest_db[sd->quest_index[i]].mob[j]; + for( j = 0 ; j < qi->num_objectives; j++ ) { + WFIFOL(fd, i*104+22+j*30) = qi->mob[j]; WFIFOW(fd, i*104+26+j*30) = sd->quest_log[i].count[j]; - mob = mob_db(quest_db[sd->quest_index[i]].mob[j]); - memcpy(WFIFOP(fd, i*104+28+j*30), mob?mob->jname:"NULL", NAME_LENGTH); + monster = mob->db(qi->mob[j]); + memcpy(WFIFOP(fd, i*104+28+j*30), monster->jname, NAME_LENGTH); } } @@ -15415,25 +15845,25 @@ void clif_quest_send_mission(struct map_session_data * sd) /// Notification about a new quest (ZC_ADD_QUEST). /// 02b3 <quest id>.L <active>.B <start time>.L <expire time>.L <mobs>.W { <mob id>.L <mob count>.W <mob name>.24B }*3 -void clif_quest_add(struct map_session_data * sd, struct quest * qd, int index) -{ +void clif_quest_add(struct map_session_data *sd, struct quest *qd) { int fd = sd->fd; int i; - struct mob_db *mob; + struct mob_db *monster; + struct quest_db *qi = quest->db(qd->quest_id); WFIFOHEAD(fd, packet_len(0x2b3)); WFIFOW(fd, 0) = 0x2b3; WFIFOL(fd, 2) = qd->quest_id; WFIFOB(fd, 6) = qd->state; - WFIFOB(fd, 7) = qd->time - quest_db[index].time; + WFIFOB(fd, 7) = qd->time - qi->time; WFIFOL(fd, 11) = qd->time; - WFIFOW(fd, 15) = quest_db[index].num_objectives; + WFIFOW(fd, 15) = qi->num_objectives; - for( i = 0; i < quest_db[index].num_objectives; i++ ) { - WFIFOL(fd, i*30+17) = quest_db[index].mob[i]; + for( i = 0; i < qi->num_objectives; i++ ) { + WFIFOL(fd, i*30+17) = qi->mob[i]; WFIFOW(fd, i*30+21) = qd->count[i]; - mob = mob_db(quest_db[index].mob[i]); - memcpy(WFIFOP(fd, i*30+23), mob?mob->jname:"NULL", NAME_LENGTH); + monster = mob->db(qi->mob[i]); + memcpy(WFIFOP(fd, i*30+23), monster->jname, NAME_LENGTH); } WFIFOSET(fd, packet_len(0x2b3)); @@ -15442,8 +15872,7 @@ void clif_quest_add(struct map_session_data * sd, struct quest * qd, int index) /// Notification about a quest being removed (ZC_DEL_QUEST). /// 02b4 <quest id>.L -void clif_quest_delete(struct map_session_data * sd, int quest_id) -{ +void clif_quest_delete(struct map_session_data *sd, int quest_id) { int fd = sd->fd; WFIFOHEAD(fd, packet_len(0x2b4)); @@ -15455,21 +15884,21 @@ void clif_quest_delete(struct map_session_data * sd, int quest_id) /// Notification of an update to the hunting mission counter (ZC_UPDATE_MISSION_HUNT). /// 02b5 <packet len>.W <mobs>.W { <quest id>.L <mob id>.L <total count>.W <current count>.W }*3 -void clif_quest_update_objective(struct map_session_data * sd, struct quest * qd, int index) -{ +void clif_quest_update_objective(struct map_session_data *sd, struct quest *qd) { int fd = sd->fd; int i; - int len = quest_db[index].num_objectives*12+6; + struct quest_db *qi = quest->db(qd->quest_id); + int len = qi->num_objectives*12+6; WFIFOHEAD(fd, len); WFIFOW(fd, 0) = 0x2b5; WFIFOW(fd, 2) = len; - WFIFOW(fd, 4) = quest_db[index].num_objectives; + WFIFOW(fd, 4) = qi->num_objectives; - for( i = 0; i < quest_db[index].num_objectives; i++ ) { + for( i = 0; i < qi->num_objectives; i++ ) { WFIFOL(fd, i*12+6) = qd->quest_id; - WFIFOL(fd, i*12+10) = quest_db[index].mob[i]; - WFIFOW(fd, i*12+14) = quest_db[index].count[i]; + WFIFOL(fd, i*12+10) = qi->mob[i]; + WFIFOW(fd, i*12+14) = qi->count[i]; WFIFOW(fd, i*12+16) = qd->count[i]; } @@ -15479,16 +15908,14 @@ void clif_quest_update_objective(struct map_session_data * sd, struct quest * qd /// Request to change the state of a quest (CZ_ACTIVE_QUEST). /// 02b6 <quest id>.L <active>.B -void clif_parse_questStateAck(int fd, struct map_session_data * sd) -{ - quest_update_status(sd, RFIFOL(fd,2), RFIFOB(fd,6)?Q_ACTIVE:Q_INACTIVE); +void clif_parse_questStateAck(int fd, struct map_session_data *sd) { + quest->update_status(sd, RFIFOL(fd,2), RFIFOB(fd,6)?Q_ACTIVE:Q_INACTIVE); } /// Notification about the change of a quest state (ZC_ACTIVE_QUEST). /// 02b7 <quest id>.L <active>.B -void clif_quest_update_status(struct map_session_data * sd, int quest_id, bool active) -{ +void clif_quest_update_status(struct map_session_data *sd, int quest_id, bool active) { int fd = sd->fd; WFIFOHEAD(fd, packet_len(0x2b7)); @@ -15532,64 +15959,63 @@ void clif_quest_show_event(struct map_session_data *sd, struct block_list *bl, s /// Notification about a mercenary status parameter change (ZC_MER_PAR_CHANGE). /// 02a2 <var id>.W <value>.L -void clif_mercenary_updatestatus(struct map_session_data *sd, int type) -{ +void clif_mercenary_updatestatus(struct map_session_data *sd, int type) { struct mercenary_data *md; - struct status_data *status; + struct status_data *mstatus; int fd; if( sd == NULL || (md = sd->md) == NULL ) return; fd = sd->fd; - status = &md->battle_status; + mstatus = &md->battle_status; WFIFOHEAD(fd,packet_len(0x2a2)); WFIFOW(fd,0) = 0x2a2; WFIFOW(fd,2) = type; switch( type ) { case SP_ATK1: - { - int atk = rnd()%(status->rhw.atk2 - status->rhw.atk + 1) + status->rhw.atk; - WFIFOL(fd,4) = cap_value(atk, 0, INT16_MAX); - } + { + int atk = rnd()%(mstatus->rhw.atk2 - mstatus->rhw.atk + 1) + mstatus->rhw.atk; + WFIFOL(fd,4) = cap_value(atk, 0, INT16_MAX); + } break; case SP_MATK1: - WFIFOL(fd,4) = cap_value(status->matk_max, 0, INT16_MAX); + WFIFOL(fd,4) = cap_value(mstatus->matk_max, 0, INT16_MAX); break; case SP_HIT: - WFIFOL(fd,4) = status->hit; + WFIFOL(fd,4) = mstatus->hit; break; case SP_CRITICAL: - WFIFOL(fd,4) = status->cri/10; + WFIFOL(fd,4) = mstatus->cri/10; break; case SP_DEF1: - WFIFOL(fd,4) = status->def; + WFIFOL(fd,4) = mstatus->def; break; case SP_MDEF1: - WFIFOL(fd,4) = status->mdef; + WFIFOL(fd,4) = mstatus->mdef; break; case SP_MERCFLEE: - WFIFOL(fd,4) = status->flee; + WFIFOL(fd,4) = mstatus->flee; break; case SP_ASPD: - WFIFOL(fd,4) = status->amotion; + WFIFOL(fd,4) = mstatus->amotion; break; case SP_HP: - WFIFOL(fd,4) = status->hp; + WFIFOL(fd,4) = mstatus->hp; break; case SP_MAXHP: - WFIFOL(fd,4) = status->max_hp; + WFIFOL(fd,4) = mstatus->max_hp; break; case SP_SP: - WFIFOL(fd,4) = status->sp; + WFIFOL(fd,4) = mstatus->sp; break; case SP_MAXSP: - WFIFOL(fd,4) = status->max_sp; + WFIFOL(fd,4) = mstatus->max_sp; break; case SP_MERCKILLS: WFIFOL(fd,4) = md->mercenary.kill_count; break; case SP_MERCFAITH: - WFIFOL(fd,4) = mercenary_get_faith(md); + WFIFOL(fd,4) = mercenary->get_faith(md); break; } WFIFOSET(fd,packet_len(0x2a2)); @@ -15600,42 +16026,41 @@ void clif_mercenary_updatestatus(struct map_session_data *sd, int type) /// 029b <id>.L <atk>.W <matk>.W <hit>.W <crit>.W <def>.W <mdef>.W <flee>.W <aspd>.W /// <name>.24B <level>.W <hp>.L <maxhp>.L <sp>.L <maxsp>.L <expire time>.L <faith>.W /// <calls>.L <kills>.L <atk range>.W -void clif_mercenary_info(struct map_session_data *sd) -{ +void clif_mercenary_info(struct map_session_data *sd) { int fd; struct mercenary_data *md; - struct status_data *status; + struct status_data *mstatus; int atk; if( sd == NULL || (md = sd->md) == NULL ) return; fd = sd->fd; - status = &md->battle_status; + mstatus = &md->battle_status; WFIFOHEAD(fd,packet_len(0x29b)); WFIFOW(fd,0) = 0x29b; WFIFOL(fd,2) = md->bl.id; // Mercenary shows ATK as a random value between ATK ~ ATK2 - atk = rnd()%(status->rhw.atk2 - status->rhw.atk + 1) + status->rhw.atk; + atk = rnd()%(mstatus->rhw.atk2 - mstatus->rhw.atk + 1) + mstatus->rhw.atk; WFIFOW(fd,6) = cap_value(atk, 0, INT16_MAX); - WFIFOW(fd,8) = cap_value(status->matk_max, 0, INT16_MAX); - WFIFOW(fd,10) = status->hit; - WFIFOW(fd,12) = status->cri/10; - WFIFOW(fd,14) = status->def; - WFIFOW(fd,16) = status->mdef; - WFIFOW(fd,18) = status->flee; - WFIFOW(fd,20) = status->amotion; + WFIFOW(fd,8) = cap_value(mstatus->matk_max, 0, INT16_MAX); + WFIFOW(fd,10) = mstatus->hit; + WFIFOW(fd,12) = mstatus->cri/10; + WFIFOW(fd,14) = mstatus->def; + WFIFOW(fd,16) = mstatus->mdef; + WFIFOW(fd,18) = mstatus->flee; + WFIFOW(fd,20) = mstatus->amotion; safestrncpy((char*)WFIFOP(fd,22), md->db->name, NAME_LENGTH); WFIFOW(fd,46) = md->db->lv; - WFIFOL(fd,48) = status->hp; - WFIFOL(fd,52) = status->max_hp; - WFIFOL(fd,56) = status->sp; - WFIFOL(fd,60) = status->max_sp; - WFIFOL(fd,64) = (int)time(NULL) + (mercenary_get_lifetime(md) / 1000); - WFIFOW(fd,68) = mercenary_get_faith(md); - WFIFOL(fd,70) = mercenary_get_calls(md); + WFIFOL(fd,48) = mstatus->hp; + WFIFOL(fd,52) = mstatus->max_hp; + WFIFOL(fd,56) = mstatus->sp; + WFIFOL(fd,60) = mstatus->max_sp; + WFIFOL(fd,64) = (int)time(NULL) + (mercenary->get_lifetime(md) / 1000); + WFIFOW(fd,68) = mercenary->get_faith(md); + WFIFOL(fd,70) = mercenary->get_calls(md); WFIFOL(fd,74) = md->mercenary.kill_count; WFIFOW(fd,78) = md->battle_status.rhw.range; WFIFOSET(fd,packet_len(0x29b)); @@ -15643,7 +16068,7 @@ void clif_mercenary_info(struct map_session_data *sd) /// Mercenary skill tree (ZC_MER_SKILLINFO_LIST). -/// 029d <packet len>.W { <skill id>.W <type>.L <level>.W <sp cost>.W <attack range>.W <skill name>.24B <upgradable>.B }* +/// 029d <packet len>.W { <skill id>.W <type>.L <level>.W <sp cost>.W <attack range>.W <skill name>.24B <upgradeable>.B }* void clif_mercenary_skillblock(struct map_session_data *sd) { struct mercenary_data *md; @@ -15685,7 +16110,7 @@ void clif_parse_mercenary_action(int fd, struct map_session_data* sd) if( sd->md == NULL ) return; - if( option == 2 ) merc_delete(sd->md, 2); + if( option == 2 ) mercenary->delete(sd->md, 2); } @@ -15802,11 +16227,11 @@ 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 *bg, int src_id, const char *name, const char *mes, int len) +void clif_bg_message(struct battleground_data *bgd, int src_id, const char *name, const char *mes, size_t len) { struct map_session_data *sd; unsigned char *buf; - if( (sd = bg_getavailablesd(bg)) == NULL ) + if( !bgd->count || (sd = bg->getavailablesd(bgd)) == NULL ) return; buf = (unsigned char*)aMalloc((len + NAME_LENGTH + 8)*sizeof(unsigned char)); @@ -15831,31 +16256,33 @@ void clif_parse_BattleChat(int fd, struct map_session_data* sd) int textlen = RFIFOW(fd,2) - 4; char *name, *message; - int namelen, messagelen; + size_t namelen, messagelen; if( !clif->process_message(sd, 0, &name, &namelen, &message, &messagelen) ) return; - if( atcommand->parse(fd, sd, message, 1) ) + if( atcommand->exec(fd, sd, message, true) ) return; - if( sd->sc.data[SC_BERSERK] || sd->sc.data[SC__BLOODYLUST] || sd->sc.data[SC_DEEP_SLEEP] || (sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOCHAT) ) + if( sd->sc.data[SC_BERSERK] || (sd->sc.data[SC_DEEP_SLEEP] && sd->sc.data[SC_DEEP_SLEEP]->val2) || (sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOCHAT) ) return; if( battle_config.min_chat_delay ) { - if( DIFF_TICK(sd->cantalk_tick, iTimer->gettick()) > 0 ) + if( DIFF_TICK(sd->cantalk_tick, timer->gettick()) > 0 ) return; - sd->cantalk_tick = iTimer->gettick() + battle_config.min_chat_delay; + sd->cantalk_tick = timer->gettick() + battle_config.min_chat_delay; } - bg_send_message(sd, text, textlen); + if( battle_config.idletime_criteria & BCIDLE_CHAT ) + sd->idletime = sockt->last_tick; + + bg->send_message(sd, text, textlen); } /// Notifies client of a battleground score change (ZC_BATTLEFIELD_NOTIFY_POINT). /// 02de <camp A points>.W <camp B points>.W -void clif_bg_updatescore(int16 m) -{ +void clif_bg_updatescore(int16 m) { struct block_list bl; unsigned char buf[6]; @@ -15864,21 +16291,20 @@ void clif_bg_updatescore(int16 m) bl.m = m; WBUFW(buf,0) = 0x2de; - WBUFW(buf,2) = map[m].bgscore_lion; - WBUFW(buf,4) = map[m].bgscore_eagle; + WBUFW(buf,2) = map->list[m].bgscore_lion; + WBUFW(buf,4) = map->list[m].bgscore_eagle; clif->send(buf,packet_len(0x2de),&bl,ALL_SAMEMAP); } -void clif_bg_updatescore_single(struct map_session_data *sd) -{ +void clif_bg_updatescore_single(struct map_session_data *sd) { int fd; nullpo_retv(sd); fd = sd->fd; WFIFOHEAD(fd,packet_len(0x2de)); WFIFOW(fd,0) = 0x2de; - WFIFOW(fd,2) = map[sd->bl.m].bgscore_lion; - WFIFOW(fd,4) = map[sd->bl.m].bgscore_eagle; + WFIFOW(fd,2) = map->list[sd->bl.m].bgscore_lion; + WFIFOW(fd,4) = map->list[sd->bl.m].bgscore_eagle; WFIFOSET(fd,packet_len(0x2de)); } @@ -15918,7 +16344,7 @@ void clif_font(struct map_session_data *sd) nullpo_retv(sd); WBUFW(buf,0) = 0x2ef; WBUFL(buf,2) = sd->bl.id; - WBUFW(buf,6) = sd->user_font; + WBUFW(buf,6) = sd->status.font; clif->send(buf, packet_len(0x2ef), &sd->bl, AREA); #endif } @@ -15931,34 +16357,34 @@ int clif_instance(int instance_id, int type, int flag) { struct map_session_data *sd = NULL; unsigned char buf[255]; enum send_target target = PARTY; - - switch( instances[instance_id].owner_type ) { + + switch( instance->list[instance_id].owner_type ) { case IOT_NONE: return 0; case IOT_GUILD: target = GUILD; - sd = guild->getavailablesd(guild->search(instances[instance_id].owner_id)); + sd = guild->getavailablesd(guild->search(instance->list[instance_id].owner_id)); break; case IOT_PARTY: /* default is already PARTY */ - sd = party->getavailablesd(party->search(instances[instance_id].owner_id)); + sd = party->getavailablesd(party->search(instance->list[instance_id].owner_id)); break; case IOT_CHAR: target = SELF; - sd = iMap->id2sd(instances[instance_id].owner_id); + sd = map->id2sd(instance->list[instance_id].owner_id); break; } if( !sd ) return 0; - + switch( type ) { case 1: // S 0x2cb <Instance name>.61B <Standby Position>.W // Required to start the instancing information window on Client // This window re-appear each "refresh" of client automatically until type 4 is send to client. WBUFW(buf,0) = 0x02CB; - memcpy(WBUFP(buf,2),instances[instance_id].name,INSTANCE_NAME_LENGTH); + memcpy(WBUFP(buf,2),instance->list[instance_id].name,INSTANCE_NAME_LENGTH); WBUFW(buf,63) = flag; clif->send(buf,packet_len(0x02CB),&sd->bl,target); break; @@ -15973,13 +16399,13 @@ int clif_instance(int instance_id, int type, int flag) { case 4: // S 0x2cd <Instance Name>.61B <Instance Remaining Time>.L <Instance Noplayers close time>.L WBUFW(buf,0) = 0x02CD; - memcpy(WBUFP(buf,2),instances[instance_id].name,61); + memcpy(WBUFP(buf,2),instance->list[instance_id].name,61); if( type == 3 ) { - WBUFL(buf,63) = instances[instance_id].progress_timeout; + WBUFL(buf,63) = instance->list[instance_id].progress_timeout; WBUFL(buf,67) = 0; } else { WBUFL(buf,63) = 0; - WBUFL(buf,67) = instances[instance_id].idle_timeout; + WBUFL(buf,67) = instance->list[instance_id].idle_timeout; } clif->send(buf,packet_len(0x02CD),&sd->bl,target); break; @@ -16001,24 +16427,24 @@ int clif_instance(int instance_id, int type, int flag) { void clif_instance_join(int fd, int instance_id) { - if( instances[instance_id].idle_timer != INVALID_TIMER ) { + if( instance->list[instance_id].idle_timer != INVALID_TIMER ) { WFIFOHEAD(fd,packet_len(0x02CD)); WFIFOW(fd,0) = 0x02CD; - memcpy(WFIFOP(fd,2),instances[instance_id].name,61); + memcpy(WFIFOP(fd,2),instance->list[instance_id].name,61); WFIFOL(fd,63) = 0; - WFIFOL(fd,67) = instances[instance_id].idle_timeout; + WFIFOL(fd,67) = instance->list[instance_id].idle_timeout; WFIFOSET(fd,packet_len(0x02CD)); - } else if( instances[instance_id].progress_timer != INVALID_TIMER ) { + } else if( instance->list[instance_id].progress_timer != INVALID_TIMER ) { WFIFOHEAD(fd,packet_len(0x02CD)); WFIFOW(fd,0) = 0x02CD; - memcpy(WFIFOP(fd,2),instances[instance_id].name,61); - WFIFOL(fd,63) = instances[instance_id].progress_timeout; + memcpy(WFIFOP(fd,2),instance->list[instance_id].name,61); + WFIFOL(fd,63) = instance->list[instance_id].progress_timeout; WFIFOL(fd,67) = 0; WFIFOSET(fd,packet_len(0x02CD)); } else { WFIFOHEAD(fd,packet_len(0x02CB)); WFIFOW(fd,0) = 0x02CB; - memcpy(WFIFOP(fd,2),instances[instance_id].name,61); + memcpy(WFIFOP(fd,2),instance->list[instance_id].name,61); WFIFOW(fd,63) = 0; WFIFOSET(fd,packet_len(0x02CB)); } @@ -16039,7 +16465,7 @@ void clif_party_show_picker(struct map_session_data * sd, struct item * item_dat { #if PACKETVER >= 20071002 unsigned char buf[22]; - struct item_data* id = itemdb_search(item_data->nameid); + struct item_data* id = itemdb->search(item_data->nameid); WBUFW(buf,0) = 0x2b8; WBUFL(buf,2) = sd->status.account_id; @@ -16062,8 +16488,7 @@ void clif_party_show_picker(struct map_session_data * sd, struct item * item_dat /// exp type: /// 0 = normal exp gain/loss /// 1 = quest exp gain/loss -void clif_displayexp(struct map_session_data *sd, unsigned int exp, char type, bool quest) -{ +void clif_displayexp(struct map_session_data *sd, unsigned int exp, char type, bool is_quest) { int fd; nullpo_retv(sd); @@ -16075,7 +16500,7 @@ void clif_displayexp(struct map_session_data *sd, unsigned int exp, char type, b WFIFOL(fd,2) = sd->bl.id; WFIFOL(fd,6) = exp; WFIFOW(fd,10) = type; - WFIFOW(fd,12) = quest?1:0;// Normal exp is shown in yellow, quest exp is shown in purple. + WFIFOW(fd,12) = is_quest?1:0;// Normal exp is shown in yellow, quest exp is shown in purple. WFIFOSET(fd,packet_len(0x7f6)); } @@ -16156,29 +16581,29 @@ void clif_parse_ItemListWindowSelected(int fd, struct map_session_data* sd) { *==========================================*/ void clif_elemental_updatestatus(struct map_session_data *sd, int type) { struct elemental_data *ed; - struct status_data *status; + struct status_data *estatus; int fd; if( sd == NULL || (ed = sd->ed) == NULL ) return; fd = sd->fd; - status = &ed->battle_status; + estatus = &ed->battle_status; WFIFOHEAD(fd,8); WFIFOW(fd,0) = 0x81e; WFIFOW(fd,2) = type; switch( type ) { case SP_HP: - WFIFOL(fd,4) = status->hp; + WFIFOL(fd,4) = estatus->hp; break; case SP_MAXHP: - WFIFOL(fd,4) = status->max_hp; + WFIFOL(fd,4) = estatus->max_hp; break; case SP_SP: - WFIFOL(fd,4) = status->sp; + WFIFOL(fd,4) = estatus->sp; break; case SP_MAXSP: - WFIFOL(fd,4) = status->max_sp; + WFIFOL(fd,4) = estatus->max_sp; break; } WFIFOSET(fd,8); @@ -16187,21 +16612,21 @@ void clif_elemental_updatestatus(struct map_session_data *sd, int type) { void clif_elemental_info(struct map_session_data *sd) { int fd; struct elemental_data *ed; - struct status_data *status; + struct status_data *estatus; if( sd == NULL || (ed = sd->ed) == NULL ) return; fd = sd->fd; - status = &ed->battle_status; + estatus = &ed->battle_status; WFIFOHEAD(fd,22); WFIFOW(fd, 0) = 0x81d; WFIFOL(fd, 2) = ed->bl.id; - WFIFOL(fd, 6) = status->hp; - WFIFOL(fd,10) = status->max_hp; - WFIFOL(fd,14) = status->sp; - WFIFOL(fd,18) = status->max_sp; + WFIFOL(fd, 6) = estatus->hp; + WFIFOL(fd,10) = estatus->max_hp; + WFIFOL(fd,14) = estatus->sp; + WFIFOL(fd,18) = estatus->max_sp; WFIFOSET(fd,22); } @@ -16709,7 +17134,7 @@ void clif_parse_debug(int fd,struct map_session_data *sd) { } ShowDebug("Packet debug of 0x%04X (length %d), %s session #%d, %d/%d (AID/CID)\n", cmd, packet_len, sd->state.active ? "authed" : "unauthed", fd, sd->status.account_id, sd->status.char_id); } else { - packet_len = RFIFOREST(fd); + packet_len = (int)RFIFOREST(fd); ShowDebug("Packet debug of 0x%04X (length %d), session #%d\n", cmd, packet_len, fd); } @@ -16717,7 +17142,7 @@ void clif_parse_debug(int fd,struct map_session_data *sd) { } /*========================================== * Server tells client to display a window similar to Magnifier (item) one - * Server populates the window with avilable elemental converter options according to player's inventory + * Server populates the window with available elemental converter options according to player's inventory *------------------------------------------*/ int clif_elementalconverter_list(struct map_session_data *sd) { int i,c,view,fd; @@ -16731,11 +17156,11 @@ int clif_elementalconverter_list(struct map_session_data *sd) { WFIFOW(fd, 0)=0x1ad; for(i=0,c=0;i<MAX_SKILL_PRODUCE_DB;i++){ - if( skill->can_produce_mix(sd,skill_produce_db[i].nameid,23, 1) ){ - if((view = itemdb_viewid(skill_produce_db[i].nameid)) > 0) + if( skill->can_produce_mix(sd,skill->produce_db[i].nameid,23, 1) ){ + if((view = itemdb_viewid(skill->produce_db[i].nameid)) > 0) WFIFOW(fd,c*2+ 4)= view; else - WFIFOW(fd,c*2+ 4)= skill_produce_db[i].nameid; + WFIFOW(fd,c*2+ 4)= skill->produce_db[i].nameid; c++; } } @@ -16751,15 +17176,15 @@ int clif_elementalconverter_list(struct map_session_data *sd) { /** * Rune Knight **/ -void clif_millenniumshield(struct map_session_data *sd, short shields ) { +void clif_millenniumshield(struct block_list *bl, short shields ) { #if PACKETVER >= 20081217 unsigned char buf[10]; WBUFW(buf,0) = 0x440; - WBUFL(buf,2) = sd->bl.id; + WBUFL(buf,2) = bl->id; WBUFW(buf,6) = shields; WBUFW(buf,8) = 0; - clif->send(buf,packet_len(0x440),&sd->bl,AREA); + clif->send(buf,packet_len(0x440),bl,AREA); #endif } /** @@ -17021,73 +17446,68 @@ void clif_parse_MoveItem(int fd, struct map_session_data *sd) { /* [Ind/Hercules] */ void clif_cashshop_db(void) { config_t cashshop_conf; - config_setting_t *cashshop = NULL; + config_setting_t *cashshop = NULL, *cats = NULL; const char *config_filename = "db/cashshop_db.conf"; // FIXME hardcoded name - int i; + int i, item_count_t = 0; for( i = 0; i < CASHSHOP_TAB_MAX; i++ ) { CREATE(clif->cs.data[i], struct hCSData *, 1); clif->cs.item_count[i] = 0; } - - if (conf_read_file(&cashshop_conf, config_filename)) { + + if (libconfig->read_file(&cashshop_conf, config_filename)) { ShowError("can't read %s\n", config_filename); return; } - - cashshop = config_lookup(&cashshop_conf, "cash_shop"); - - if (cashshop != NULL) { - config_setting_t *cats = config_setting_get_elem(cashshop, 0); - config_setting_t *cat; - int k, item_count_t = 0; - + + cashshop = libconfig->lookup(&cashshop_conf, "cash_shop"); + + if( cashshop != NULL && (cats = libconfig->setting_get_elem(cashshop, 0)) != NULL ) { for(i = 0; i < CASHSHOP_TAB_MAX; i++) { + config_setting_t *cat; char entry_name[10]; - + sprintf(entry_name,"cat_%d",i); - - if( (cat = config_setting_get_member(cats, entry_name)) != NULL ) { - int item_count = config_setting_length(cat); - + + if( (cat = libconfig->setting_get_member(cats, entry_name)) != NULL ) { + int k, item_count = libconfig->setting_length(cat); + for(k = 0; k < item_count; k++) { - config_setting_t *entry = config_setting_get_elem(cat,k); + config_setting_t *entry = libconfig->setting_get_elem(cat,k); const char *name = config_setting_name(entry); - int price = config_setting_get_int(entry); + int price = libconfig->setting_get_int(entry); struct item_data * data = NULL; - + if( price < 1 ) { ShowWarning("cashshop_db: unsupported price '%d' for entry named '%s' in category '%s'\n", price, name, entry_name); continue; } - + if( name[0] == 'I' && name[1] == 'D' && strlen(name) <= 7 ) { - if( !( data = itemdb_exists(atoi(name+2))) ) { + if( !( data = itemdb->exists(atoi(name+2))) ) { ShowWarning("cashshop_db: unknown item id '%s' in category '%s'\n", name+2, entry_name); continue; } } else { - if( !( data = itemdb_searchname(name) ) ) { + if( !( data = itemdb->search_name(name) ) ) { ShowWarning("cashshop_db: unknown item name '%s' in category '%s'\n", name, entry_name); continue; } } - - + + RECREATE(clif->cs.data[i], struct hCSData *, ++clif->cs.item_count[i]); CREATE(clif->cs.data[i][ clif->cs.item_count[i] - 1 ], struct hCSData , 1); - + clif->cs.data[i][ clif->cs.item_count[i] - 1 ]->id = data->nameid; clif->cs.data[i][ clif->cs.item_count[i] - 1 ]->price = price; item_count_t++; } - } else { - ShowError("cashshop_db: category '%s' (%d) not found!!\n",entry_name,i); } } - - ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", item_count_t, config_filename); - config_destroy(&cashshop_conf); + + libconfig->destroy(&cashshop_conf); } + ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", item_count_t, config_filename); } /// Items that are in favorite tab of inventory (ZC_ITEM_FAVORITE). /// 0900 <index>.W <favorite>.B @@ -17114,25 +17534,30 @@ void clif_snap( struct block_list *bl, short x, short y ) { void clif_monster_hp_bar( struct mob_data* md, struct map_session_data *sd ) { struct packet_monster_hp p; - + p.PacketType = monsterhpType; p.GID = md->bl.id; p.HP = md->status.hp; p.MaxHP = md->status.max_hp; - + clif->send(&p,sizeof(p),&sd->bl,SELF); } /* [Ind/Hercules] placeholder for unsupported incoming packets (avoids server disconnecting client) */ void __attribute__ ((unused)) clif_parse_dull(int fd,struct map_session_data *sd) { return; } - void clif_parse_CashShopOpen(int fd, struct map_session_data *sd) { + + if( map->list[sd->bl.m].flag.nocashshop ) { + clif->colormes(fd,COLOR_RED,msg_txt(1489)); //Cash Shop is disabled in this map + return; + } + WFIFOHEAD(fd, 10); WFIFOW(fd, 0) = 0x845; WFIFOL(fd, 2) = sd->cashPoints; //[Ryuuzaki] - switched positions to reflect proper values WFIFOL(fd, 6) = sd->kafraPoints; - WFIFOSET(fd, 10); + WFIFOSET(fd, 10); } void clif_parse_CashShopClose(int fd, struct map_session_data *sd) { @@ -17141,35 +17566,43 @@ void clif_parse_CashShopClose(int fd, struct map_session_data *sd) { void clif_parse_CashShopSchedule(int fd, struct map_session_data *sd) { int i, j = 0; - + for( i = 0; i < CASHSHOP_TAB_MAX; i++ ) { + if( clif->cs.item_count[i] == 0 ) + continue; // Skip empty tabs, the client only expects filled ones + WFIFOHEAD(fd, 8 + ( clif->cs.item_count[i] * 6 ) ); WFIFOW(fd, 0) = 0x8ca; WFIFOW(fd, 2) = 8 + ( clif->cs.item_count[i] * 6 ); WFIFOW(fd, 4) = clif->cs.item_count[i]; WFIFOW(fd, 6) = i; - + for( j = 0; j < clif->cs.item_count[i]; j++ ) { WFIFOW(fd, 8 + ( 6 * j ) ) = clif->cs.data[i][j]->id; WFIFOL(fd, 10 + ( 6 * j ) ) = clif->cs.data[i][j]->price; } - + WFIFOSET(fd, 8 + ( clif->cs.item_count[i] * 6 )); } } void clif_parse_CashShopBuy(int fd, struct map_session_data *sd) { unsigned short limit = RFIFOW(fd, 4), i, j; - unsigned int kafra_pay = RFIFOL(fd, 6);// [Ryuuzaki] - These are free cash points (strangely #CASH = main cash curreny for us, confusing) + unsigned int kafra_pay = RFIFOL(fd, 6);// [Ryuuzaki] - These are free cash points (strangely #CASH = main cash currently for us, confusing) + + if( map->list[sd->bl.m].flag.nocashshop ) { + clif->colormes(fd,COLOR_RED,msg_txt(1489)); //Cash Shop is disabled in this map + return; + } for(i = 0; i < limit; i++) { int qty = RFIFOL(fd, 14 + ( i * 10 )); int id = RFIFOL(fd, 10 + ( i * 10 )); short tab = RFIFOW(fd, 18 + ( i * 10 )); enum CASH_SHOP_BUY_RESULT result = CSBR_UNKNOWN; - + if( tab < 0 || tab > CASHSHOP_TAB_MAX ) continue; - + for( j = 0; j < clif->cs.item_count[tab]; j++ ) { if( clif->cs.data[tab][j]->id == id ) break; @@ -17180,24 +17613,24 @@ void clif_parse_CashShopBuy(int fd, struct map_session_data *sd) { result = CSBR_SHORTTAGE_CASH; } else if( (sd->cashPoints+kafra_pay) < (clif->cs.data[tab][j]->price * qty) ) { result = CSBR_SHORTTAGE_CASH; - } else if ( !( data = itemdb_exists(clif->cs.data[tab][j]->id) ) ) { + } else if ( !( data = itemdb->exists(clif->cs.data[tab][j]->id) ) ) { result = CSBR_UNKONWN_ITEM; } else { struct item item_tmp; int k, get_count; - + get_count = qty; - - if (!itemdb_isstackable2(data)) + + if (!itemdb->isstackable2(data)) get_count = 1; - + pc->paycash(sd, clif->cs.data[tab][j]->price * qty, kafra_pay);// [Ryuuzaki] for (k = 0; k < qty; k += get_count) { - if (!pet_create_egg(sd, data->nameid)) { + if (!pet->create_egg(sd, data->nameid)) { memset(&item_tmp, 0, sizeof(item_tmp)); item_tmp.nameid = data->nameid; item_tmp.identify = 1; - + switch (pc->additem(sd, &item_tmp, get_count, LOG_TYPE_NPC)) { case 0: result = CSBR_SUCCESS; @@ -17218,16 +17651,17 @@ void clif_parse_CashShopBuy(int fd, struct map_session_data *sd) { result = CSBR_RUNE_OVERCOUNT; break; } - + if( result != CSBR_SUCCESS ) pc->getcash(sd, clif->cs.data[tab][j]->price * get_count,0); - } + } else /* create_egg succeeded so mark as success */ + result = CSBR_SUCCESS; } } } else { result = CSBR_UNKONWN_ITEM; } - + WFIFOHEAD(fd, 16); WFIFOW(fd, 0) = 0x849; WFIFOL(fd, 2) = id; @@ -17243,7 +17677,7 @@ void clif_parse_CashShopReqTab(int fd, struct map_session_data *sd) { short tab = RFIFOW(fd, 2); int j; - if( tab < 0 || tab > CASHSHOP_TAB_MAX ) + if( tab < 0 || tab > CASHSHOP_TAB_MAX || clif->cs.item_count[tab] == 0 ) return; WFIFOHEAD(fd, 10 + ( clif->cs.item_count[tab] * 6 ) ); @@ -17251,73 +17685,98 @@ void clif_parse_CashShopReqTab(int fd, struct map_session_data *sd) { WFIFOW(fd, 2) = 10 + ( clif->cs.item_count[tab] * 6 ); WFIFOL(fd, 4) = tab; WFIFOW(fd, 8) = clif->cs.item_count[tab]; - + for( j = 0; j < clif->cs.item_count[tab]; j++ ) { WFIFOW(fd, 10 + ( 6 * j ) ) = clif->cs.data[tab][j]->id; WFIFOL(fd, 12 + ( 6 * j ) ) = clif->cs.data[tab][j]->price; } - + WFIFOSET(fd, 10 + ( clif->cs.item_count[tab] * 6 )); } /* [Ind/Hercules] */ void clif_maptypeproperty2(struct block_list *bl,enum send_target t) { #if PACKETVER >= 20121010 struct packet_maptypeproperty2 p; - + p.PacketType = maptypeproperty2Type; p.type = 0x28; - p.flag.usecart = 1; - p.flag.party = 1; - p.flag.guild = 1; + p.flag.party = map->list[bl->m].flag.pvp ? 1 : 0; + p.flag.guild = map_flag_gvg(bl->m) ? 1 : 0; p.flag.siege = map_flag_gvg2(bl->m) ? 1: 0; - p.flag.mineffect = 1; - p.flag.nolockon = 0; - p.flag.countpk = map[bl->m].flag.pvp ? 1 : 0; - p.flag.nopartyformation = 0; - p.flag.noitemconsumption = 0; - p.flag.summonstarmiracle = 0; - p.flag.bg = map[bl->m].flag.battleground ? 1 : 0; - + p.flag.mineffect = map_flag_gvg(bl->m); // FIXME/CHECKME Forcing /mineffect in castles during WoE (probably redundant? I'm not sure) + p.flag.nolockon = 0; // TODO + p.flag.countpk = map->list[bl->m].flag.pvp ? 1 : 0; + p.flag.nopartyformation = map->list[bl->m].flag.partylock ? 1 : 0; + p.flag.bg = map->list[bl->m].flag.battleground ? 1 : 0; + p.flag.noitemconsumption = 0; // TODO + p.flag.summonstarmiracle = 0; // TODO + p.flag.usecart = 1; // TODO + p.flag.SpareBits = 0; + clif->send(&p,sizeof(p),bl,t); #endif } void clif_status_change2(struct block_list *bl, int tid, enum send_target target, int type, int val1, int val2, int val3) { struct packet_status_change2 p; - + p.PacketType = status_change2Type; p.index = type; p.AID = tid; p.state = 1; - p.Left = -1;// officially its 9999 but -1 is a explicit "no-duration" which behaves best [Ind/Hercules] + p.Left = 9999; p.val1 = val1; p.val2 = val2; p.val3 = val3; - + clif->send(&p,sizeof(p), bl, target); } void clif_partytickack(struct map_session_data* sd, bool flag) { - + WFIFOHEAD(sd->fd, packet_len(0x2c9)); WFIFOW(sd->fd, 0) = 0x2c9; WFIFOB(sd->fd, 2) = flag; WFIFOSET(sd->fd, packet_len(0x2c9)); } +void clif_ShowScript(struct block_list* bl, const char* message) { + char buf[256]; + size_t len; + nullpo_retv(bl); + + if(!message) + return; + + len = 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; + } + + WBUFW(buf,0)=0x8b3; + WBUFW(buf,2)=len+8; + WBUFL(buf,4)=bl->id; + safestrncpy((char *) WBUFP(buf,8),message,len); + clif->send((unsigned char *) buf,WBUFW(buf,2),bl,ALL_CLIENT); +} + void clif_status_change_end(struct block_list *bl, int tid, enum send_target target, int type) { struct packet_status_change_end p; - + + if( bl->type == BL_PC && !((TBL_PC*)bl)->state.active ) + return; + p.PacketType = status_change_endType; p.index = type; p.AID = tid; p.state = 0; - + clif->send(&p,sizeof(p), bl, target); } void clif_bgqueue_ack(struct map_session_data *sd, enum BATTLEGROUNDS_QUEUE_ACK response, unsigned char arena_id) { - switch (response) { case BGQA_FAIL_COOLDOWN: case BGQA_FAIL_DESERTER: @@ -17325,39 +17784,38 @@ void clif_bgqueue_ack(struct map_session_data *sd, enum BATTLEGROUNDS_QUEUE_ACK break; default: { struct packet_bgqueue_ack p; - + p.PacketType = bgqueue_ackType; p.type = response; safestrncpy(p.bg_name, bg->arena[arena_id]->name, sizeof(p.bg_name)); - + clif->send(&p,sizeof(p), &sd->bl, SELF); } break; - } + } } -void clif_bgqueue_notice_delete(struct map_session_data *sd, enum BATTLEGROUNDS_QUEUE_NOTICE_DELETED response, unsigned char arena_id) { +void clif_bgqueue_notice_delete(struct map_session_data *sd, enum BATTLEGROUNDS_QUEUE_NOTICE_DELETED response, char *name) { struct packet_bgqueue_notice_delete p; - + p.PacketType = bgqueue_notice_deleteType; p.type = response; - safestrncpy(p.bg_name, bg->arena[arena_id]->name, sizeof(p.bg_name)); - + safestrncpy(p.bg_name, name, sizeof(p.bg_name)); + clif->send(&p,sizeof(p), &sd->bl, SELF); } void clif_parse_bgqueue_register(int fd, struct map_session_data *sd) { - struct packet_bgqueue_register *p = P2PTR(fd, bgqueue_registerType); + struct packet_bgqueue_register *p = P2PTR(fd); struct bg_arena *arena = NULL; - if( !bg->queue_on ) return; /* temp, until feature is complete */ - + if( !(arena = bg->name2arena(p->bg_name)) ) { clif->bgqueue_ack(sd,BGQA_FAIL_BGNAME_INVALID,0); return; } - + switch( (enum bg_queue_types)p->type ) { case BGQT_INDIVIDUAL: case BGQT_PARTY: @@ -17366,51 +17824,57 @@ void clif_parse_bgqueue_register(int fd, struct map_session_data *sd) { default: clif->bgqueue_ack(sd,BGQA_FAIL_TYPE_INVALID, arena->id); return; - } - + } + bg->queue_add(sd, arena, (enum bg_queue_types)p->type); } void clif_bgqueue_update_info(struct map_session_data *sd, unsigned char arena_id, int position) { struct packet_bgqueue_update_info p; - + p.PacketType = bgqueue_updateinfoType; safestrncpy(p.bg_name, bg->arena[arena_id]->name, sizeof(p.bg_name)); p.position = position; - + sd->bg_queue.client_has_bg_data = true; // Client creates bg data when this packet arrives - + clif->send(&p,sizeof(p), &sd->bl, SELF); } void clif_parse_bgqueue_checkstate(int fd, struct map_session_data *sd) { - //struct packet_bgqueue_checkstate *p = P2PTR(fd, bgqueue_checkstateType); /* TODO: bgqueue_notice_delete should use this p->bg_name */ - if( !bg->queue_on ) return; /* temp, until feature is complete */ + struct packet_bgqueue_checkstate *p = P2PTR(fd); + if ( sd->bg_queue.arena && sd->bg_queue.type ) { - sd->bg_queue.client_has_bg_data = true; clif->bgqueue_update_info(sd,sd->bg_queue.arena->id,bg->id2pos(sd->bg_queue.arena->queue_id,sd->status.account_id)); } else - clif->bgqueue_notice_delete(sd, BGQND_FAIL_NOT_QUEUING,0);/* TODO: wrong response, should respond with p->bg_name not id 0 */ + clif->bgqueue_notice_delete(sd, BGQND_FAIL_NOT_QUEUING,p->bg_name); } void clif_parse_bgqueue_revoke_req(int fd, struct map_session_data *sd) { - //struct packet_bgqueue_revoke_req *p = P2PTR(fd, bgqueue_revokereqType); - return; - //bg->queue_leave(sd, p->bg_name); + struct packet_bgqueue_revoke_req *p = P2PTR(fd); + + if( sd->bg_queue.arena ) + bg->queue_pc_cleanup(sd); + else + clif->bgqueue_notice_delete(sd, BGQND_FAIL_NOT_QUEUING,p->bg_name); } void clif_parse_bgqueue_battlebegin_ack(int fd, struct map_session_data *sd) { - //struct packet_bgqueue_battlebegin_ack *p = P2PTR(fd, bgqueue_checkstateType); - return; - //if ( p->result == 1 ) - // bg->queue_pc_ready(sd); - //else - // bg->queue_leave(sd, p->bg_name); + struct packet_bgqueue_battlebegin_ack *p = P2PTR(fd); + struct bg_arena *arena; + + if( !bg->queue_on ) return; /* temp, until feature is complete */ + + if( ( arena = bg->name2arena(p->bg_name) ) ) { + bg->queue_ready_ack(arena,sd, ( p->result == 1 ) ? true : false); + } else { + clif->bgqueue_ack(sd,BGQA_FAIL_BGNAME_INVALID, 0); + } } void clif_bgqueue_joined(struct map_session_data *sd, int pos) { struct packet_bgqueue_notify_entry p; - + p.PacketType = bgqueue_notify_entryType; safestrncpy(p.name,sd->status.name,sizeof(p.name)); p.position = pos; @@ -17426,60 +17890,400 @@ void clif_bgqueue_pcleft(struct map_session_data *sd) { // Sends BG ready req to all with same bg arena/type as sd void clif_bgqueue_battlebegins(struct map_session_data *sd, unsigned char arena_id, enum send_target target) { struct packet_bgqueue_battlebegins p; - - p.PacketType = bgqueue_battlebegins; + + p.PacketType = bgqueue_battlebeginsType; safestrncpy(p.bg_name, bg->arena[arena_id]->name, sizeof(p.bg_name)); safestrncpy(p.game_name, bg->arena[arena_id]->name, sizeof(p.game_name)); - + clif->send(&p,sizeof(p), &sd->bl, target); } void clif_scriptclear(struct map_session_data *sd, int npcid) { struct packet_script_clear p; - + p.PacketType = script_clearType; p.NpcID = npcid; - + clif->send(&p,sizeof(p), &sd->bl, SELF); } +/* Made Possible Thanks to Yommy! */ +void clif_package_item_announce(struct map_session_data *sd, unsigned short nameid, unsigned short containerid) { + struct packet_package_item_announce p; + + p.PacketType = package_item_announceType; + p.PacketLength = 11+NAME_LENGTH; + p.type = 0x0; + p.ItemID = nameid; + p.len = NAME_LENGTH; + safestrncpy(p.Name, sd->status.name, sizeof(p.Name)); + p.unknown = 0x2; // some strange byte, IDA shows.. BYTE3(BoxItemIDLength) = 2; + p.BoxItemID = containerid; + + clif->send(&p,sizeof(p), &sd->bl, ALL_CLIENT); +} +/* Made Possible Thanks to Yommy! */ +void clif_item_drop_announce(struct map_session_data *sd, unsigned short nameid, char *monsterName) { + struct packet_item_drop_announce p; + + p.PacketType = item_drop_announceType; + p.PacketLength = sizeof(p); + p.type = 0x1; + p.ItemID = nameid; + p.len = NAME_LENGTH; + safestrncpy(p.Name, sd->status.name, sizeof(p.Name)); + p.monsterNameLen = NAME_LENGTH; + safestrncpy(p.monsterName, monsterName, sizeof(p.monsterName)); + + clif->send(&p,sizeof(p), &sd->bl, ALL_CLIENT); +} +/* [Ind/Hercules] special thanks to Yommy~! */ +void clif_skill_cooldown_list(int fd, struct skill_cd* cd) { +#if PACKETVER >= 20120604 + const int offset = 10; +#else + const int offset = 6; +#endif + int i, count = 0; + + WFIFOHEAD(fd,4+(offset*cd->cursor)); + +#if PACKETVER >= 20120604 + WFIFOW(fd,0) = 0x985; +#else + WFIFOW(fd,0) = 0x43e; +#endif + + for( i = 0; i < cd->cursor; i++ ) { + if( cd->entry[i]->duration < 1 ) continue; + + WFIFOW(fd, 4 + (count*offset)) = cd->entry[i]->skill_id; +#if PACKETVER >= 20120604 + WFIFOL(fd, 6 + (count*offset)) = cd->entry[i]->total; + WFIFOL(fd, 10 + (count*offset)) = cd->entry[i]->duration; +#else + WFIFOL(fd, 6 + (count*offset)) = cd->entry[i]->duration; +#endif + count++; + } + + WFIFOW(fd,2) = 4+(offset*count); + + WFIFOSET(fd,4+(offset*count)); +} +/* [Ind/Hercules] - Data Thanks to Yommy + * - ADDITEM_TO_CART_FAIL_WEIGHT = 0x0 + * - ADDITEM_TO_CART_FAIL_COUNT = 0x1 + */ +void clif_cart_additem_ack(struct map_session_data *sd, int flag) { + struct packet_cart_additem_ack p; + + p.PacketType = cart_additem_ackType; + p.result = (char)flag; + + clif->send(&p,sizeof(p), &sd->bl, SELF); +} +/* Bank System [Yommy/Hercules] */ +void clif_parse_BankDeposit(int fd, struct map_session_data* sd) { + struct packet_banking_deposit_req *p = P2PTR(fd); + int money; + + if( !battle_config.feature_banking ) { + clif->colormes(fd,COLOR_RED,msg_txt(1483)); + return; + } + + money = (int)cap_value(p->Money,0,INT_MAX); + + pc->bank_deposit(sd,money); +} + +void clif_parse_BankWithdraw(int fd, struct map_session_data* sd) { + struct packet_banking_withdraw_req *p = P2PTR(fd); + int money; + + if( !battle_config.feature_banking ) { + clif->colormes(fd,COLOR_RED,msg_txt(1483)); + return; + } + + money = (int)cap_value(p->Money,0,INT_MAX); + + pc->bank_withdraw(sd,money); +} + +void clif_parse_BankCheck(int fd, struct map_session_data* sd) { + struct packet_banking_check p; + + if( !battle_config.feature_banking ) { + clif->colormes(fd,COLOR_RED,msg_txt(1483)); + return; + } + + p.PacketType = banking_checkType; + p.Money = (int)sd->status.bank_vault; + p.Reason = (short)0; + + clif->send(&p,sizeof(p), &sd->bl, SELF); +} + +void clif_parse_BankOpen(int fd, struct map_session_data* sd) { + return; +} + +void clif_parse_BankClose(int fd, struct map_session_data* sd) { + return; +} + +void clif_bank_deposit(struct map_session_data *sd, enum e_BANKING_DEPOSIT_ACK reason) { + struct packet_banking_deposit_ack p; + + p.PacketType = banking_deposit_ackType; + p.Balance = sd->status.zeny;/* how much zeny char has after operation */ + p.Money = (int64)sd->status.bank_vault;/* money in the bank */ + p.Reason = (short)reason; + + clif->send(&p,sizeof(p), &sd->bl, SELF); +} +void clif_bank_withdraw(struct map_session_data *sd,enum e_BANKING_WITHDRAW_ACK reason) { + struct packet_banking_withdraw_ack p; + + p.PacketType = banking_withdraw_ackType; + p.Balance = sd->status.zeny;/* how much zeny char has after operation */ + p.Money = (int64)sd->status.bank_vault;/* money in the bank */ + p.Reason = (short)reason; + + clif->send(&p,sizeof(p), &sd->bl, SELF); +} +/* TODO: official response packet (tried 0x8cb/0x97b but the display was quite screwed up.) */ +/* currently mimicing */ +void clif_show_modifiers (struct map_session_data *sd) { + + if( sd->status.mod_exp != 100 || sd->status.mod_drop != 100 || sd->status.mod_death != 100 ) { + char output[128]; + + 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); + } + +} + +void clif_notify_bounditem(struct map_session_data *sd, unsigned short index) { + struct packet_notify_bounditem p; + + p.PacketType = notify_bounditemType; + p.index = index+2; + + clif->send(&p,sizeof(p), &sd->bl, SELF); +} + +/** + * Parses the (GM) right click option 'remove all equipment' + **/ +void clif_parse_GMFullStrip(int fd, struct map_session_data *sd) { + struct map_session_data *tsd = map->id2sd(RFIFOL(fd,2)); + int i; + + /* TODO maybe this could be a new permission? using gm level in the meantime */ + if( !tsd || pc_get_group_level(tsd) >= pc_get_group_level(sd) ) + return; + + for( i = 0; i < EQI_MAX; i++ ) { + if( tsd->equip_index[ i ] >= 0 ) + pc->unequipitem( tsd , tsd->equip_index[ i ] , 2 ); + } +} +/** + * clif_delay_damage timer, sends the stored data and clears the memory afterwards + **/ +int clif_delay_damage_sub(int tid, int64 tick, int id, intptr_t data) { + struct cdelayed_damage *dd = (struct cdelayed_damage *)data; + + clif->send(&dd->p,sizeof(struct packet_damage),&dd->bl,AREA_WOS); + + ers_free(clif->delayed_damage_ers,dd); + + return 0; +} +/** + * Delays sending a damage packet in order to avoid the visual display to overlap + * + * @param tick when to trigger the timer (e.g. timer->gettick() + 500) + * @param src block_list pointer of the src + * @param dst block_list pointer of the damage source + * @param sdelay attack motion usually status_get_amotion() + * @param ddelay damage motion usually status_get_dmotion() + * @param in_damage total damage to be sent + * @param div amount of hits + * @param type action type + * + * @return clif->calc_walkdelay used in further processing + **/ +int clif_delay_damage(int64 tick, struct block_list *src, struct block_list *dst, int sdelay, int ddelay, int64 in_damage, short div, unsigned char type) { + struct cdelayed_damage *dd; + struct status_change *sc; +#if PACKETVER < 20071113 + short damage; +#else + int damage; +#endif + + nullpo_ret(src); + nullpo_ret(dst); + + sc = status->get_sc(dst); + + if(sc && sc->count && sc->data[SC_ILLUSION]) { + if(in_damage) in_damage = in_damage*(sc->data[SC_ILLUSION]->val2) + rnd()%100; + } + +#if PACKETVER < 20071113 + damage = (short)min(in_damage,INT16_MAX); +#else + damage = (int)min(in_damage,INT_MAX); +#endif + + type = clif_calc_delay(type,div,damage,ddelay); + + dd = ers_alloc(clif->delayed_damage_ers, struct cdelayed_damage); + + dd->p.PacketType = damageType; + dd->p.GID = src->id; + dd->p.targetGID = dst->id; + dd->p.startTime = (uint32)timer->gettick(); + dd->p.attackMT = sdelay; + dd->p.attackedMT = ddelay; + dd->p.count = div; + dd->p.action = type; + dd->p.leftDamage = 0; + + if( battle_config.hide_woe_damage && map_flag_gvg2(src->m) ) + dd->p.damage = damage?div:0; + else + dd->p.damage = damage; + + dd->bl.m = dst->m; + dd->bl.x = dst->x; + dd->bl.y = dst->y; + dd->bl.type = BL_NUL; + + if( tick > timer->gettick() ) + timer->add(tick,clif->delay_damage_sub,0,(intptr_t)dd); + else { + clif->send(&dd->p,sizeof(struct packet_damage),&dd->bl,AREA_WOS); + + ers_free(clif->delayed_damage_ers,dd); + } + + return clif->calc_walkdelay(dst,ddelay,type,damage,div); +} +/* Thanks to Yommy */ +void clif_parse_NPCShopClosed(int fd, struct map_session_data *sd) { + /* TODO track the state <3~ */ + sd->npc_shopid = 0; +} +/* NPC Market (by Ind after an extensive debugging of the packet, only possible thanks to Yommy <3) */ +void clif_npc_market_open(struct map_session_data *sd, struct npc_data *nd) { +#if PACKETVER >= 20131223 + struct npc_item_list *shop = nd->u.scr.shop->item; + unsigned short shop_size = nd->u.scr.shop->items, i, c; + struct item_data *id = NULL; + + npcmarket_open.PacketType = npcmarketopenType; + + for(i = 0, c = 0; i < shop_size; i++) { + if( shop[i].nameid && (id = itemdb->exists(shop[i].nameid)) ) { + npcmarket_open.list[c].nameid = shop[i].nameid; + npcmarket_open.list[c].price = shop[i].value; + npcmarket_open.list[c].qty = shop[i].qty; + npcmarket_open.list[c].type = itemtype(id->type); + npcmarket_open.list[c].view = ( id->view_id > 0 ) ? id->view_id : id->nameid; + c++; + } + } + + npcmarket_open.PacketLength = 4 + ( sizeof(npcmarket_open.list[0]) * c ); + + clif->send(&npcmarket_open,npcmarket_open.PacketLength,&sd->bl,SELF); +#endif +} +void clif_parse_NPCMarketClosed(int fd, struct map_session_data *sd) { + /* TODO track the state <3~ */ + sd->npc_shopid = 0; +} +void clif_npc_market_purchase_ack(struct map_session_data *sd, struct packet_npc_market_purchase *req, unsigned char response) { +#if PACKETVER >= 20131223 + unsigned short c = 0; + + npcmarket_result.PacketType = npcmarketresultackType; + npcmarket_result.result = response == 0 ? 1 : 0;/* find other values */ + + if( npcmarket_result.result ) { + unsigned short i, list_size = (req->PacketLength - 4) / sizeof(req->list[0]), j; + struct npc_data* nd; + struct npc_item_list *shop = NULL; + unsigned short shop_size = 0; + + nd = map->id2nd(sd->npc_shopid); + + shop = nd->u.scr.shop->item; + shop_size = nd->u.scr.shop->items; + + for(i = 0; i < list_size; i++) { + + npcmarket_result.list[i].ITID = req->list[i].ITID; + npcmarket_result.list[i].qty = req->list[i].qty; + + ARR_FIND( 0, shop_size, j, req->list[i].ITID == shop[j].nameid ); + + npcmarket_result.list[i].price = (j != shop_size) ? shop[j].value : 0; + + c++; + } + } + + npcmarket_result.PacketLength = 5 + ( sizeof(npcmarket_result.list[0]) * c );; + + clif->send(&npcmarket_result,npcmarket_result.PacketLength,&sd->bl,SELF); +#endif +} +void clif_parse_NPCMarketPurchase(int fd, struct map_session_data *sd) { +#if PACKETVER >= 20131223 + struct packet_npc_market_purchase *p = P2PTR(fd); + + clif->npc_market_purchase_ack(sd,p,npc->market_buylist(sd,(p->PacketLength - 4) / sizeof(p->list[0]),p)); +#endif +} +/* */ unsigned short clif_decrypt_cmd( int cmd, struct map_session_data *sd ) { if( sd ) { - sd->cryptKey = (( sd->cryptKey * clif->cryptKey[1] ) + clif->cryptKey[2]) & 0xFFFFFFFF; return (cmd ^ ((sd->cryptKey >> 16) & 0x7FFF)); } return (cmd ^ (((( clif->cryptKey[0] * clif->cryptKey[1] ) + clif->cryptKey[2]) >> 16) & 0x7FFF)); } -unsigned short clif_parse_cmd_normal ( int fd, struct map_session_data *sd ) { +unsigned short clif_parse_cmd_normal( int fd, struct map_session_data *sd ) { unsigned short cmd = RFIFOW(fd,0); - // filter out invalid / unsupported packets - if (cmd > MAX_PACKET_DB || packet_db[cmd].len == 0) - return 0; return cmd; } -unsigned short clif_parse_cmd_optional ( int fd, struct map_session_data *sd ) { +unsigned short clif_parse_cmd_decrypt( int fd, struct map_session_data *sd ) { unsigned short cmd = RFIFOW(fd,0); - // filter out invalid / unsupported packets - if (cmd > MAX_PACKET_DB || packet_db[cmd].len == 0) { - cmd = clif->decrypt_cmd( cmd, sd ); - if( cmd > MAX_PACKET_DB || packet_db[cmd].len == 0 ) - return 0; - RFIFOW(fd, 0) = cmd; - } + cmd = clif->decrypt_cmd(cmd, sd); return cmd; } -unsigned short clif_parse_cmd_decrypt ( int fd, struct map_session_data *sd ) { +unsigned short clif_parse_cmd_optional( int fd, struct map_session_data *sd ) { unsigned short cmd = RFIFOW(fd,0); - cmd = clif->decrypt_cmd( cmd, sd ); - // filter out invalid / unsupported packets - if (cmd > MAX_PACKET_DB || packet_db[cmd].len == 0 ) - return 0; - - RFIFOW(fd, 0) = cmd; + if( cmd > MAX_PACKET_DB || cmd < MIN_PACKET_DB || packet_db[cmd].len == 0 ) { + if( sd ) + sd->parse_cmd_func = clif_parse_cmd_decrypt; + return clif_parse_cmd_decrypt(fd, sd); + } else if( sd ) { + sd->parse_cmd_func = clif_parse_cmd_normal; + } return cmd; } @@ -17491,14 +18295,16 @@ int clif_parse(int fd) { int cmd, packet_len; TBL_PC* sd; int pnum; - + //TODO apply delays or disconnect based on packet throughput [FlavioJS] // Note: "click masters" can do 80+ clicks in 10 seconds - + for( pnum = 0; pnum < 3; ++pnum ) { // Limit max packets per cycle to 3 (delay packet spammers) [FlavioJS] -- This actually aids packet spammers, but stuff like /str+ gets slow without it [Ai4rei] + unsigned short (*parse_cmd_func)(int fd, struct map_session_data *sd); // begin main client packet processing loop - + sd = (TBL_PC *)session[fd]->session_data; + if (session[fd]->flag.eof) { if (sd) { if (sd->state.autotrade) { @@ -17514,7 +18320,7 @@ int clif_parse(int fd) { } else { //Unusual logout (during log on/off/map-changer procedure) ShowInfo("Player AID:%d/CID:%d logged off.\n", sd->status.account_id, sd->status.char_id); - iMap->quit(sd); + map->quit(sd); } } else { ShowInfo("Closed connection from '"CL_WHITE"%s"CL_RESET"'.\n", ip2str(session[fd]->client_addr, NULL)); @@ -17522,25 +18328,42 @@ int clif_parse(int fd) { do_close(fd); return 0; } - + if (RFIFOREST(fd) < 2) return 0; - - if( !( cmd = clif->parse_cmd(fd,sd) ) ) { - ShowWarning("clif_parse: Received unsupported packet (packet 0x%04x, %d bytes received), disconnecting session #%d.\n", RFIFOW(fd,0), RFIFOREST(fd), fd); + + if( HPM->packetsc[hpClif_Parse] ) { + int r; + if( (r = HPM->parse_packets(fd,hpClif_Parse)) ) { + if( r == 1 ) continue; + if( r == 2 ) return 0; + } + } + + if( sd ) + parse_cmd_func = sd->parse_cmd_func; + else + parse_cmd_func = clif->parse_cmd; + + cmd = parse_cmd_func(fd,sd); + + // filter out invalid / unsupported packets + if (cmd > MAX_PACKET_DB || cmd < MIN_PACKET_DB || packet_db[cmd].len == 0) { + ShowWarning("clif_parse: Received unsupported packet (packet 0x%04x (0x%04x), %"PRIuS" bytes received), disconnecting session #%d.\n", + cmd, RFIFOW(fd,0), RFIFOREST(fd), fd); #ifdef DUMP_INVALID_PACKET ShowDump(RFIFOP(fd,0), RFIFOREST(fd)); #endif set_eof(fd); return 0; } - + // determine real packet length if ( ( packet_len = packet_db[cmd].len ) == -1) { // variable-length packet if (RFIFOREST(fd) < 4) return 0; - + packet_len = RFIFOW(fd,2); if (packet_len < 4 || packet_len > 32768) { ShowWarning("clif_parse: Received packet 0x%04x specifies invalid packet_len (%d), disconnecting session #%d.\n", cmd, packet_len, fd); @@ -17556,6 +18379,13 @@ int clif_parse(int fd) { if ((int)RFIFOREST(fd) < packet_len) return 0; // not enough data received to form the packet + if( battle_config.packet_obfuscation == 2 || cmd != RFIFOW(fd, 0) || (sd && sd->parse_cmd_func == clif_parse_cmd_decrypt) ) { + RFIFOW(fd, 0) = cmd; + if( sd ) { + sd->cryptKey = (( sd->cryptKey * clif->cryptKey[1] ) + clif->cryptKey[2]) & 0xFFFFFFFF; // Update key for the next packet + } + } + if( packet_db[cmd].func == clif->pDebug ) packet_db[cmd].func(fd, sd); else if( packet_db[cmd].func != NULL ) { @@ -17571,36 +18401,36 @@ int clif_parse(int fd) { else { const char* packet_txt = "save/packet.txt"; FILE* fp; - + if( ( fp = fopen( packet_txt , "a" ) ) != NULL ) { if( sd ) { fprintf(fp, "Unknown packet 0x%04X (length %d), %s session #%d, %d/%d (AID/CID)\n", cmd, packet_len, sd->state.active ? "authed" : "unauthed", fd, sd->status.account_id, sd->status.char_id); } else { fprintf(fp, "Unknown packet 0x%04X (length %d), session #%d\n", cmd, packet_len, fd); } - + WriteDump(fp, RFIFOP(fd,0), packet_len); fprintf(fp, "\n"); fclose(fp); } else { ShowError("Failed to write '%s'.\n", packet_txt); - + // Dump on console instead if( sd ) { ShowDebug("Unknown packet 0x%04X (length %d), %s session #%d, %d/%d (AID/CID)\n", cmd, packet_len, sd->state.active ? "authed" : "unauthed", fd, sd->status.account_id, sd->status.char_id); } else { ShowDebug("Unknown packet 0x%04X (length %d), session #%d\n", cmd, packet_len, fd); } - + ShowDump(RFIFOP(fd,0), packet_len); } } #endif - + RFIFOSKIP(fd, packet_len); - + }; // main loop end - + return 0; } @@ -17609,43 +18439,44 @@ static void __attribute__ ((unused)) packetdb_addpacket(short cmd, int len, ...) int i; int pos; pFunc func; - + if (cmd > MAX_PACKET_DB) { ShowError("Packet Error: packet 0x%x is greater than the maximum allowed (0x%x), skipping...\n", cmd, MAX_PACKET_DB); return; } - + packet_db[cmd].len = len; - + va_start(va,len); - + pos = va_arg(va, int); - + if( pos == 0xFFFF ) /* nothing more to do */ return; - + va_end(va); va_start(va,len); - + func = va_arg(va,pFunc); - + packet_db[cmd].func = func; - + for (i = 0; i < MAX_PACKET_POS; i++) { pos = va_arg(va, int); - + if (pos == 0xFFFF) break; - + packet_db[cmd].pos[i] = pos; } + va_end(va); } void packetdb_loaddb(void) { - + memset(packet_db,0,sizeof(packet_db)); - #define packet(id, size, ...) packetdb_addpacket(id, size, ##__VA_ARGS__, 0xFFFF) - #define packetKeys(a,b,c) { clif->cryptKey[0] = a; clif->cryptKey[1] = b; clif->cryptKey[2] = c; } + #define packet(id, size, ...) packetdb_addpacket((id), (size), ##__VA_ARGS__, 0xFFFF) + #define packetKeys(a,b,c) do { clif->cryptKey[0] = (a); clif->cryptKey[1] = (b); clif->cryptKey[2] = (c); } while(0) #include "packets.h" /* load structure data */ #undef packet #undef packetKeys @@ -17655,7 +18486,7 @@ void clif_bc_ready(void) { clif->status_change = clif_status_change; else clif->status_change = clif_status_change_notick; - + switch( battle_config.packet_obfuscation ) { case 0: clif->parse_cmd = clif_parse_cmd_normal; @@ -17672,35 +18503,39 @@ void clif_bc_ready(void) { /*========================================== * *------------------------------------------*/ -int do_init_clif(void) { +int do_init_clif(bool minimal) { const char* colors[COLOR_MAX] = { "0xFF0000", "0x00ff00", "0xffffff" }; int i; - + + if (minimal) + return 0; + /** * Setup Color Table (saves unnecessary load of strtoul on every call) **/ for(i = 0; i < COLOR_MAX; i++) { - color_table[i] = strtoul(colors[i],NULL,0); + color_table[i] = (unsigned int)strtoul(colors[i],NULL,0); color_table[i] = (color_table[i] & 0x0000FF) << 16 | (color_table[i] & 0x00FF00) | (color_table[i] & 0xFF0000) >> 16;//RGB to BGR } - + packetdb_loaddb(); - + set_defaultparse(clif->parse); if( make_listen_bind(clif->bind_ip,clif->map_port) == -1 ) { ShowFatalError("Failed to bind to port '"CL_WHITE"%d"CL_RESET"'\n",clif->map_port); exit(EXIT_FAILURE); } - iTimer->add_timer_func_list(clif->clearunit_delayed_sub, "clif_clearunit_delayed_sub"); - iTimer->add_timer_func_list(clif->delayquit, "clif_delayquit"); + timer->add_func_list(clif->clearunit_delayed_sub, "clif_clearunit_delayed_sub"); + timer->add_func_list(clif->delayquit, "clif_delayquit"); clif->delay_clearunit_ers = ers_new(sizeof(struct block_list),"clif.c::delay_clearunit_ers",ERS_OPT_CLEAR); + clif->delayed_damage_ers = ers_new(sizeof(struct cdelayed_damage),"clif.c::delayed_damage_ers",ERS_OPT_CLEAR); clif->channel_db = stridb_alloc(DB_OPT_DUP_KEY|DB_OPT_RELEASE_DATA, HCHSYS_NAME_LENGTH); hChSys.ally = hChSys.local = hChSys.irc = hChSys.ally_autojoin = hChSys.local_autojoin = false; clif->chann_config_read(); - + return 0; } @@ -17708,17 +18543,17 @@ void do_final_clif(void) { DBIterator *iter = db_iterator(clif->channel_db); struct hChSysCh *channel; unsigned char i; - + for( channel = dbi_first(iter); dbi_exists(iter); channel = dbi_next(iter) ) { clif->chsys_delete(channel); } - + dbi_destroy(iter); - + for(i = 0; i < hChSys.colors_count; i++) { aFree(hChSys.colors_name[i]); } - + if( hChSys.colors_count ) { aFree(hChSys.colors_name); aFree(hChSys.colors); @@ -17726,7 +18561,8 @@ void do_final_clif(void) { db_destroy(clif->channel_db); ers_destroy(clif->delay_clearunit_ers); - + ers_destroy(clif->delayed_damage_ers); + for(i = 0; i < CASHSHOP_TAB_MAX; i++) { int k; for( k = 0; k < clif->cs.item_count[i]; k++ ) { @@ -17741,6 +18577,8 @@ void clif_defaults(void) { /* vars */ clif->bind_ip = INADDR_ANY; clif->map_port = 5121; + clif->ally_only = false; + clif->delayed_damage_ers = NULL; /* core */ clif->init = do_init_clif; clif->final = do_final_clif; @@ -17777,6 +18615,10 @@ void clif_defaults(void) { clif->addcards2 = clif_addcards2; clif->item_sub = clif_item_sub; clif->getareachar_item = clif_getareachar_item; + clif->cart_additem_ack = clif_cart_additem_ack; + clif->cashshop_load = clif_cashshop_db; + clif->package_announce = clif_package_item_announce; + clif->item_drop_announce = clif_item_drop_announce; /* unit-related */ clif->clearunit_single = clif_clearunit_single; clif->clearunit_area = clif_clearunit_area; @@ -17791,18 +18633,20 @@ void clif_defaults(void) { clif->changetraplook = clif_changetraplook; clif->refreshlook = clif_refreshlook; clif->class_change = clif_class_change; - clif->skill_setunit = clif_skill_setunit; clif->skill_delunit = clif_skill_delunit; clif->skillunit_update = clif_skillunit_update; clif->clearunit_delayed_sub = clif_clearunit_delayed_sub; clif->set_unit_idle = clif_set_unit_idle; clif->spawn_unit = clif_spawn_unit; + clif->spawn_unit2 = clif_spawn_unit2; + clif->set_unit_idle2 = clif_set_unit_idle2; clif->set_unit_walking = clif_set_unit_walking; clif->calc_walkdelay = clif_calc_walkdelay; clif->getareachar_skillunit = clif_getareachar_skillunit; clif->getareachar_unit = clif_getareachar_unit; clif->clearchar_skillunit = clif_clearchar_skillunit; clif->getareachar = clif_getareachar; + clif->graffiti_entry = clif_graffiti_entry; /* main unit spawn */ clif->spawn = clif_spawn; /* map-related */ @@ -17840,10 +18684,14 @@ void clif_defaults(void) { clif->sitting = clif_sitting; clif->standing = clif_standing; clif->arrow_create_list = clif_arrow_create_list; + clif->refresh_storagewindow = clif_refresh_storagewindow; clif->refresh = clif_refresh; clif->fame_blacksmith = clif_fame_blacksmith; clif->fame_alchemist = clif_fame_alchemist; clif->fame_taekwon = clif_fame_taekwon; + clif->ranklist = clif_ranklist; + clif->pRanklist = clif_parse_ranklist; + clif->update_rankingpoint = clif_update_rankingpoint; clif->hotkeys = clif_hotkeys_send; clif->insight = clif_insight; clif->outsight = clif_outsight; @@ -17891,7 +18739,6 @@ void clif_defaults(void) { clif->partytickack = clif_partytickack; clif->equiptickack = clif_equiptickack; clif->viewequip_ack = clif_viewequip_ack; - clif->viewequip_fail = clif_viewequip_fail; clif->equpcheckbox = clif_equpcheckbox; clif->displayexp = clif_displayexp; clif->font = clif_font; @@ -17907,6 +18754,7 @@ void clif_defaults(void) { clif->sc_load = clif_status_change2; clif->sc_end = clif_status_change_end; clif->initialstatus = clif_initialstatus; + clif->cooldown_list = clif_skill_cooldown_list; /* player-unit-specific-related */ clif->updatestatus = clif_updatestatus; clif->changestatus = clif_changestatus; @@ -17973,7 +18821,6 @@ void clif_defaults(void) { clif->changechatstatus = clif_changechatstatus; clif->wis_message = clif_wis_message; clif->wis_end = clif_wis_end; - clif->disp_onlyself = clif_disp_onlyself; clif->disp_message = clif_disp_message; clif->broadcast = clif_broadcast; clif->broadcast2 = clif_broadcast2; @@ -17986,11 +18833,13 @@ void clif_defaults(void) { clif->msgtable_num = clif_msgtable_num; clif->message = clif_displaymessage; clif->messageln = clif_displaymessage2; + clif->messages = clif_displaymessage_sprintf; clif->colormes = clif_colormes; clif->process_message = clif_process_message; clif->wisexin = clif_wisexin; clif->wisall = clif_wisall; clif->PMIgnoreList = clif_PMIgnoreList; + clif->ShowScript = clif_ShowScript; /* trade handling */ clif->traderequest = clif_traderequest; clif->tradestart = clif_tradestart; @@ -18055,7 +18904,6 @@ void clif_defaults(void) { clif->guild_emblem_area = clif_guild_emblem_area; clif->guild_notice = clif_guild_notice; clif->guild_message = clif_guild_message; - clif->guild_skillup = clif_guild_skillup; clif->guild_reqalliance = clif_guild_reqalliance; clif->guild_allianceack = clif_guild_allianceack; clif->guild_delalliance = clif_guild_delalliance; @@ -18147,14 +18995,18 @@ void clif_defaults(void) { clif->PartyBookingUpdateNotify = clif_PartyBookingUpdateNotify; clif->PartyBookingDeleteNotify = clif_PartyBookingDeleteNotify; clif->PartyBookingInsertNotify = clif_PartyBookingInsertNotify; + clif->PartyRecruitRegisterAck = clif_PartyRecruitRegisterAck; + clif->PartyRecruitDeleteAck = clif_PartyRecruitDeleteAck; + clif->PartyRecruitSearchAck = clif_PartyRecruitSearchAck; + clif->PartyRecruitUpdateNotify = clif_PartyRecruitUpdateNotify; + clif->PartyRecruitDeleteNotify = clif_PartyRecruitDeleteNotify; + clif->PartyRecruitInsertNotify = clif_PartyRecruitInsertNotify; /* Group Search System Update */ -#ifdef PARTY_RECRUIT clif->PartyBookingVolunteerInfo = clif_PartyBookingVolunteerInfo; clif->PartyBookingRefuseVolunteer = clif_PartyBookingRefuseVolunteer; clif->PartyBookingCancelVolunteer = clif_PartyBookingCancelVolunteer; clif->PartyBookingAddFilteringList = clif_PartyBookingAddFilteringList; clif->PartyBookingSubFilteringList = clif_PartyBookingSubFilteringList; -#endif /* buying store-related */ clif->buyingstore_open = clif_buyingstore_open; clif->buyingstore_open_failed = clif_buyingstore_open_failed; @@ -18173,22 +19025,9 @@ void clif_defaults(void) { clif->search_store_info_failed = clif_search_store_info_failed; clif->open_search_store_info = clif_open_search_store_info; clif->search_store_info_click_ack = clif_search_store_info_click_ack; - /* elemental-related */ + /* elemental-related */ clif->elemental_info = clif_elemental_info; clif->elemental_updatestatus = clif_elemental_updatestatus; - /* Hercules Channel System */ - clif->chsys_create = clif_hercules_chsys_create; - clif->chsys_msg = clif_hercules_chsys_msg; - clif->chsys_msg2 = clif_hercules_chsys_msg2; - clif->chsys_send = clif_hercules_chsys_send; - clif->chsys_join = clif_hercules_chsys_join; - clif->chsys_left = clif_hercules_chsys_left; - clif->chsys_delete = clif_hercules_chsys_delete; - clif->chsys_mjoin = clif_hercules_chsys_mjoin; - clif->chsys_quit = clif_hercules_chsys_quit; - clif->chsys_quitg = clif_hercules_chsys_quitg; - clif->chsys_gjoin = clif_hercules_chsys_gjoin; - clif->chsys_gleave = clif_hercules_chsys_gleave; /* bgqueue */ clif->bgqueue_ack = clif_bgqueue_ack; clif->bgqueue_notice_delete = clif_bgqueue_notice_delete; @@ -18196,19 +19035,44 @@ void clif_defaults(void) { clif->bgqueue_joined = clif_bgqueue_joined; clif->bgqueue_pcleft = clif_bgqueue_pcleft; clif->bgqueue_battlebegins = clif_bgqueue_battlebegins; - /* misc-handling */ + /* misc-handling */ clif->adopt_reply = clif_Adopt_reply; clif->adopt_request = clif_Adopt_request; clif->readbook = clif_readbook; clif->notify_time = clif_notify_time; clif->user_count = clif_user_count; clif->noask_sub = clif_noask_sub; - clif->cashshop_load = clif_cashshop_db; clif->bc_ready = clif_bc_ready; clif->undisguise_timer = clif_undisguise_timer; + /* Hercules Channel System */ + clif->chsys_create = clif_hercules_chsys_create; + clif->chsys_msg = clif_hercules_chsys_msg; + clif->chsys_msg2 = clif_hercules_chsys_msg2; + clif->chsys_send = clif_hercules_chsys_send; + clif->chsys_join = clif_hercules_chsys_join; + clif->chsys_left = clif_hercules_chsys_left; + clif->chsys_delete = clif_hercules_chsys_delete; + clif->chsys_mjoin = clif_hercules_chsys_mjoin; + clif->chsys_quit = clif_hercules_chsys_quit; + clif->chsys_quitg = clif_hercules_chsys_quitg; + clif->chsys_gjoin = clif_hercules_chsys_gjoin; + clif->chsys_gleave = clif_hercules_chsys_gleave; + /* Bank System [Yommy/Hercules] */ + clif->bank_deposit = clif_bank_deposit; + clif->bank_withdraw = clif_bank_withdraw; + /* */ + clif->show_modifiers = clif_show_modifiers; + /* */ + clif->notify_bounditem = clif_notify_bounditem; + /* */ + clif->delay_damage = clif_delay_damage; + clif->delay_damage_sub = clif_delay_damage_sub; + /* NPC Market */ + clif->npc_market_open = clif_npc_market_open; + clif->npc_market_purchase_ack = clif_npc_market_purchase_ack; /*------------------------ *- Parse Incoming Packet - *------------------------*/ + *------------------------*/ clif->pWantToConnection = clif_parse_WantToConnection; clif->pLoadEndAck = clif_parse_LoadEndAck; clif->pTickSend = clif_parse_TickSend; @@ -18243,6 +19107,7 @@ void clif_defaults(void) { clif->pKickFromChat = clif_parse_KickFromChat; clif->pChatLeave = clif_parse_ChatLeave; clif->pTradeRequest = clif_parse_TradeRequest; + clif->chann_config_read = read_channels_config; clif->pTradeAck = clif_parse_TradeAck; clif->pTradeAddItem = clif_parse_TradeAddItem; clif->pTradeOk = clif_parse_TradeOk; @@ -18261,7 +19126,7 @@ void clif_defaults(void) { clif->pUseSkillToPos = clif_parse_UseSkillToPos; clif->pUseSkillToPosSub = clif_parse_UseSkillToPosSub; clif->pUseSkillToPos_homun = clif_parse_UseSkillToPos_homun; - clif->pUseSkillToPos_mercenary = clif_parse_UseSkillToPos_mercenary; + clif->pUseSkillToPos_mercenary = clif_parse_UseSkillToPos_mercenary; clif->pUseSkillToPosMoreInfo = clif_parse_UseSkillToPosMoreInfo; clif->pUseSkillMap = clif_parse_UseSkillMap; clif->pRequestMemo = clif_parse_RequestMemo; @@ -18297,13 +19162,16 @@ void clif_defaults(void) { clif->pLeaveParty = clif_parse_LeaveParty; clif->pRemovePartyMember = clif_parse_RemovePartyMember; clif->pPartyChangeOption = clif_parse_PartyChangeOption; - clif->chann_config_read = read_channels_config; clif->pPartyMessage = clif_parse_PartyMessage; clif->pPartyChangeLeader = clif_parse_PartyChangeLeader; clif->pPartyBookingRegisterReq = clif_parse_PartyBookingRegisterReq; clif->pPartyBookingSearchReq = clif_parse_PartyBookingSearchReq; clif->pPartyBookingDeleteReq = clif_parse_PartyBookingDeleteReq; clif->pPartyBookingUpdateReq = clif_parse_PartyBookingUpdateReq; + clif->pPartyRecruitRegisterReq = clif_parse_PartyRecruitRegisterReq; + clif->pPartyRecruitSearchReq = clif_parse_PartyRecruitSearchReq; + clif->pPartyRecruitDeleteReq = clif_parse_PartyRecruitDeleteReq; + clif->pPartyRecruitUpdateReq = clif_parse_PartyRecruitUpdateReq; clif->pCloseVending = clif_parse_CloseVending; clif->pVendingListReq = clif_parse_VendingListReq; clif->pPurchaseReq = clif_parse_PurchaseReq; @@ -18344,6 +19212,7 @@ void clif_defaults(void) { clif->pGMRc = clif_parse_GMRc; clif->pGMReqAccountName = clif_parse_GMReqAccountName; clif->pGMChangeMapType = clif_parse_GMChangeMapType; + clif->pGMFullStrip = clif_parse_GMFullStrip; clif->pPMIgnore = clif_parse_PMIgnore; clif->pPMIgnoreAll = clif_parse_PMIgnoreAll; clif->pPMIgnoreList = clif_parse_PMIgnoreList; @@ -18402,28 +19271,37 @@ void clif_defaults(void) { clif->pDebug = clif_parse_debug; clif->pSkillSelectMenu = clif_parse_SkillSelectMenu; clif->pMoveItem = clif_parse_MoveItem; + /* dull */ + clif->pDull = clif_parse_dull; + /* BGQueue */ + clif->pBGQueueRegister = clif_parse_bgqueue_register; + clif->pBGQueueCheckState = clif_parse_bgqueue_checkstate; + clif->pBGQueueRevokeReq = clif_parse_bgqueue_revoke_req; + clif->pBGQueueBattleBeginAck = clif_parse_bgqueue_battlebegin_ack; /* RagExe Cash Shop [Ind/Hercules] */ clif->pCashShopOpen = clif_parse_CashShopOpen; clif->pCashShopClose = clif_parse_CashShopClose; clif->pCashShopReqTab = clif_parse_CashShopReqTab; clif->pCashShopSchedule = clif_parse_CashShopSchedule; clif->pCashShopBuy = clif_parse_CashShopBuy; - /* BGQueue */ - clif->pBGQueueRegister = clif_parse_bgqueue_register; - clif->pBGQueueCheckState = clif_parse_bgqueue_checkstate; - clif->pBGQueueRevokeReq = clif_parse_bgqueue_revoke_req; - clif->pBGQueueBattleBeginAck = clif_parse_bgqueue_battlebegin_ack; /* */ clif->pPartyTick = clif_parse_PartyTick; clif->pGuildInvite2 = clif_parse_GuildInvite2; /* Group Search System Update */ -#ifdef PARTY_RECRUIT clif->pPartyBookingAddFilter = clif_parse_PartyBookingAddFilteringList; clif->pPartyBookingSubFilter = clif_parse_PartyBookingSubFilteringList; clif->pPartyBookingReqVolunteer = clif_parse_PartyBookingReqVolunteer; clif->pPartyBookingRefuseVolunteer = clif_parse_PartyBookingRefuseVolunteer; clif->pPartyBookingCancelVolunteer = clif_parse_PartyBookingCancelVolunteer; -#endif - /* dull */ - clif->pDull = clif_parse_dull; + /* Bank System [Yommy/Hercules] */ + clif->pBankDeposit = clif_parse_BankDeposit; + clif->pBankWithdraw = clif_parse_BankWithdraw; + clif->pBankCheck = clif_parse_BankCheck; + clif->pBankOpen = clif_parse_BankOpen; + clif->pBankClose = clif_parse_BankClose; + /* */ + clif->pNPCShopClosed = clif_parse_NPCShopClosed; + /* NPC Market */ + clif->pNPCMarketClosed = clif_parse_NPCMarketClosed; + clif->pNPCMarketPurchase = clif_parse_NPCMarketPurchase; } diff --git a/src/map/clif.h b/src/map/clif.h index 6e1fa81d3..e4de51a83 100644 --- a/src/map/clif.h +++ b/src/map/clif.h @@ -2,14 +2,16 @@ // See the LICENSE file // Portions Copyright (c) Athena Dev Teams -#ifndef _CLIF_H_ -#define _CLIF_H_ +#ifndef MAP_CLIF_H +#define MAP_CLIF_H +#include <stdarg.h> + +#include "map.h" +#include "packets_struct.h" #include "../common/cbasetypes.h" #include "../common/db.h" #include "../common/mmo.h" -#include "../common/socket.h" -#include <stdarg.h> /** * Declarations @@ -18,7 +20,6 @@ struct item; struct item_data; struct storage_data; struct guild_storage; -struct block_list; struct unit_data; struct map_session_data; struct homun_data; @@ -38,33 +39,37 @@ struct quest; struct party_booking_ad_info; struct view_data; struct eri; +struct skill_cd; /** * Defines **/ #define packet_len(cmd) packet_db[cmd].len -#define P2PTR(fd,cmd) RFIFO2PTR(fd,packet_db[cmd].len) -#define clif_menuskill_clear(sd) (sd)->menuskill_id = (sd)->menuskill_val = (sd)->menuskill_val2 = 0; +#define P2PTR(fd) RFIFO2PTR(fd) +#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_viewequip_fail( sd ) clif_msg( (sd), 0x54d ); #define HCHSYS_NAME_LENGTH 20 /** * Enumerations **/ enum {// packet DB - MAX_PACKET_DB = 0xF00, + MIN_PACKET_DB = 0x0064, + MAX_PACKET_DB = 0x0F00, MAX_PACKET_POS = 20, }; typedef enum send_target { ALL_CLIENT, ALL_SAMEMAP, - AREA, // area - AREA_WOS, // area, without self - AREA_WOC, // area, without chatrooms - AREA_WOSC, // area, without own chatroom - AREA_CHAT_WOC, // hearable area, without chatrooms - CHAT, // current chatroom - CHAT_WOS, // current chatroom, without self + AREA, // area + AREA_WOS, // area, without self + AREA_WOC, // area, without chatrooms + AREA_WOSC, // area, without own chatrooms + AREA_CHAT_WOC, // hearable area, without chatrooms + CHAT, // current chatroom + CHAT_WOS, // current chatroom, without self PARTY, PARTY_WOS, PARTY_SAMEMAP, @@ -82,7 +87,7 @@ typedef enum send_target { DUEL_WOS, SELF, - BG, // BattleGround System + BG, // BattleGround System BG_WOS, BG_SAMEMAP, BG_SAMEMAP_WOS, @@ -92,6 +97,25 @@ typedef enum send_target { BG_QUEUE, } send_target; +typedef enum broadcast_flags { + BC_ALL = 0, + BC_MAP = 1, + BC_AREA = 2, + BC_SELF = 3, + BC_TARGET_MASK = 0x07, + + BC_PC = 0x00, + BC_NPC = 0x08, + BC_SOURCE_MASK = 0x08, // BC_PC|BC_NPC + + BC_YELLOW = 0x00, + BC_BLUE = 0x10, + BC_WOE = 0x20, + BC_COLOR_MASK = 0x30, // BC_YELLOW|BC_BLUE|BC_WOE + + BC_DEFAULT = BC_ALL|BC_PC|BC_YELLOW +} broadcast_flags; + typedef enum emotion_type { E_GASP = 0, // /! E_WHAT, // /? @@ -319,7 +343,25 @@ typedef enum useskill_fail_cause { // clif_skill_fail }useskill_fail_cause; enum clif_messages { + ITEM_CANT_OBTAIN_WEIGHT = 0x34, /* you cannot carry more items because you are overweight. */ SKILL_CANT_USE_AREA = 0x536, + ITEM_CANT_USE_AREA = 0x537, +}; + +/** + * Used to answer CZ_PC_BUY_CASH_POINT_ITEM (clif_parse_cashshop_buy) + **/ +enum cashshop_error { + ERROR_TYPE_NONE = 0, // The deal has successfully completed. (ERROR_TYPE_NONE) + ERROR_TYPE_NPC, // The Purchase has failed because the NPC does not exist. (ERROR_TYPE_NPC) + ERROR_TYPE_SYSTEM, // The Purchase has failed because the Kafra Shop System is not working correctly. (ERROR_TYPE_SYSTEM) + ERROR_TYPE_INVENTORY_WEIGHT, // You are over your Weight Limit. (ERROR_TYPE_INVENTORY_WEIGHT) + ERROR_TYPE_EXCHANGE, // You cannot purchase items while you are in a trade. (ERROR_TYPE_EXCHANGE) + ERROR_TYPE_ITEM_ID, // The Purchase has failed because the Item Information was incorrect. (ERROR_TYPE_ITEM_ID) + ERROR_TYPE_MONEY, // You do not have enough Kafra Credit Points. (ERROR_TYPE_MONEY) + // Unofficial type names + ERROR_TYPE_QUANTITY, // You can purchase up to 10 items. (ERROR_TYPE_QUANTITY) + ERROR_TYPE_NOT_ALL, // Some items could not be purchased. (ERROR_TYPE_NOT_ALL) }; /** @@ -392,6 +434,50 @@ enum BATTLEGROUNDS_QUEUE_NOTICE_DELETED { BGQND_FAIL_NOT_QUEUING = 11, }; +enum e_BANKING_DEPOSIT_ACK { + BDA_SUCCESS = 0x0, + BDA_ERROR = 0x1, + BDA_NO_MONEY = 0x2, + BDA_OVERFLOW = 0x3, +}; +enum e_BANKING_WITHDRAW_ACK { + BWA_SUCCESS = 0x0, + BWA_NO_MONEY = 0x1, + BWA_UNKNOWN_ERROR = 0x2, +}; + +/* because the client devs were replaced by monkeys. */ +enum e_EQUIP_ITEM_ACK { +#if PACKETVER >= 20120925 + EIA_SUCCESS = 0x0, + EIA_FAIL_LV = 0x1, + EIA_FAIL = 0x2, +#else + EIA_SUCCESS = 0x1, + EIA_FAIL_LV = 0x2, + EIA_FAIL = 0x0, +#endif +}; + +/* and again. because the client devs were replaced by monkeys. */ +enum e_UNEQUIP_ITEM_ACK { +#if PACKETVER >= 20120925 + UIA_SUCCESS = 0x0, + UIA_FAIL = 0x1, +#else + UIA_SUCCESS = 0x1, + UIA_FAIL = 0x0, +#endif +}; + +enum e_trade_item_ok { + TIO_SUCCESS = 0x0, + TIO_OVERWEIGHT = 0x1, + TIO_CANCEL = 0x2, + /* feedback-friendly code that causes the client not to display a error message */ + TIO_INDROCKS = 0x9, +}; + /** * Structures **/ @@ -403,7 +489,7 @@ struct s_packet_db { }; struct { - unsigned long *colors; + unsigned int *colors; char **colors_name; unsigned char colors_count; bool local, ally, irc; @@ -414,6 +500,7 @@ struct { bool allow_user_channel_creation; char irc_server[40], irc_channel[50], irc_nick[40], irc_nick_pw[30]; unsigned short irc_server_port; + bool irc_use_ghost; } hChSys; struct hChSysBanEntry { @@ -438,11 +525,16 @@ struct hCSData { unsigned int price; }; +struct cdelayed_damage { + struct packet_damage p; + struct block_list bl; +}; + /** * Vars **/ struct s_packet_db packet_db[MAX_PACKET_DB + 1]; -unsigned long color_table[COLOR_MAX]; +unsigned int color_table[COLOR_MAX]; /** * Clif.c Interface @@ -464,14 +556,18 @@ struct clif_interface { } cs; /* */ unsigned int cryptKey[3]; + /* */ + bool ally_only; + /* */ + struct eri *delayed_damage_ers; /* core */ - int (*init) (void); + int (*init) (bool minimal); void (*final) (void); - int (*setip) (const char* ip); - void (*setbindip) (const char* ip); + bool (*setip) (const char* ip); + bool (*setbindip) (const char* ip); void (*setport) (uint16 port); uint32 (*refresh_ip) (void); - int (*send) (const void* buf, int len, struct block_list* bl, enum send_target type); + bool (*send) (const void* buf, int len, struct block_list* bl, enum send_target type); int (*send_sub) (struct block_list *bl, va_list ap); int (*parse) (int fd); unsigned short (*parse_cmd) ( int fd, struct map_session_data *sd ); @@ -493,18 +589,21 @@ struct clif_interface { void (*use_card) (struct map_session_data *sd,int idx); void (*cart_additem) (struct map_session_data *sd,int n,int amount,int fail); void (*cart_delitem) (struct map_session_data *sd,int n,int amount); - void (*equipitemack) (struct map_session_data *sd,int n,int pos,int ok); - void (*unequipitemack) (struct map_session_data *sd,int n,int pos,int ok); + void (*equipitemack) (struct map_session_data *sd,int n,int pos,enum e_EQUIP_ITEM_ACK result); + void (*unequipitemack) (struct map_session_data *sd,int n,int pos,enum e_UNEQUIP_ITEM_ACK result); void (*useitemack) (struct map_session_data *sd,int index,int amount,bool ok); void (*addcards) (unsigned char* buf, struct item* item); void (*addcards2) (unsigned short *cards, struct item* item); void (*item_sub) (unsigned char *buf, int n, struct item *i, struct item_data *id, int equip); void (*getareachar_item) (struct map_session_data* sd,struct flooritem_data* fitem); + void (*cart_additem_ack) (struct map_session_data *sd, int flag); void (*cashshop_load) (void); + void (*package_announce) (struct map_session_data *sd, unsigned short nameid, unsigned short containerid); + void (*item_drop_announce) (struct map_session_data *sd, unsigned short nameid, char *monsterName); /* unit-related */ void (*clearunit_single) (int id, clr_type type, int fd); void (*clearunit_area) (struct block_list* bl, clr_type type); - void (*clearunit_delayed) (struct block_list* bl, clr_type type, unsigned int tick); + void (*clearunit_delayed) (struct block_list* bl, clr_type type, int64 tick); void (*walkok) (struct map_session_data *sd); void (*move) (struct unit_data *ud); void (*move2) (struct block_list *bl, struct view_data *vd, struct unit_data *ud); @@ -515,26 +614,28 @@ struct clif_interface { void (*changetraplook) (struct block_list *bl,int val); void (*refreshlook) (struct block_list *bl,int id,int type,int val,enum send_target target); void (*class_change) (struct block_list *bl,int class_,int type); - void (*skill_setunit) (struct skill_unit *unit); - void (*skill_delunit) (struct skill_unit *unit); + void (*skill_delunit) (struct skill_unit *su); void (*skillunit_update) (struct block_list* bl); - int (*clearunit_delayed_sub) (int tid, unsigned int tick, int id, intptr_t data); + int (*clearunit_delayed_sub) (int tid, int64 tick, int id, intptr_t data); void (*set_unit_idle) (struct block_list* bl, struct map_session_data *tsd,enum send_target target); - void (*spawn_unit) (struct block_list* bl,enum send_target target); + void (*spawn_unit) (struct block_list* bl, enum send_target target); + void (*spawn_unit2) (struct block_list* bl, enum send_target target); + void (*set_unit_idle2) (struct block_list* bl, struct map_session_data *tsd, enum send_target target); void (*set_unit_walking) (struct block_list* bl, struct map_session_data *tsd,struct unit_data* ud, enum send_target target); int (*calc_walkdelay) (struct block_list *bl,int delay, int type, int damage, int div_); - void (*getareachar_skillunit) (struct map_session_data *sd, struct skill_unit *unit); + void (*getareachar_skillunit) (struct block_list *bl, struct skill_unit *su, enum send_target target); void (*getareachar_unit) (struct map_session_data* sd,struct block_list *bl); - void (*clearchar_skillunit) (struct skill_unit *unit, int fd); + void (*clearchar_skillunit) (struct skill_unit *su, int fd); int (*getareachar) (struct block_list* bl,va_list ap); + void (*graffiti_entry) (struct block_list *bl, struct skill_unit *su, enum send_target target); /* main unit spawn */ - int (*spawn) (struct block_list *bl); + bool (*spawn) (struct block_list *bl); /* map-related */ void (*changemap) (struct map_session_data *sd, short m, int x, int y); void (*changemapcell) (int fd, int16 m, int x, int y, int type, enum send_target target); void (*map_property) (struct map_session_data* sd, enum map_property property); void (*pvpset) (struct map_session_data *sd, int pvprank, int pvpnum,int type); - void (*map_property_mapall) (int map, enum map_property property); + void (*map_property_mapall) (int mapid, enum map_property property); void (*bossmapinfo) (int fd, struct mob_data *md, short flag); void (*map_type) (struct map_session_data* sd, enum map_type type); void (*maptypeproperty2) (struct block_list *bl,enum send_target t); @@ -560,20 +661,24 @@ struct clif_interface { void (*scriptclear) (struct map_session_data *sd, int npcid); /* client-user-interface-related */ void (*viewpoint) (struct map_session_data *sd, int npc_id, int type, int x, int y, int id, int color); - int (*damage) (struct block_list* src, struct block_list* dst, unsigned int tick, int sdelay, int ddelay, int damage, int div, int type, int damage2); + int (*damage) (struct block_list* src, struct block_list* dst, int sdelay, int ddelay, int64 damage, short div, unsigned char type, int64 damage2); void (*sitting) (struct block_list* bl); void (*standing) (struct block_list* bl); void (*arrow_create_list) (struct map_session_data *sd); + void (*refresh_storagewindow) (struct map_session_data *sd); void (*refresh) (struct map_session_data *sd); void (*fame_blacksmith) (struct map_session_data *sd, int points); void (*fame_alchemist) (struct map_session_data *sd, int points); void (*fame_taekwon) (struct map_session_data *sd, int points); + void (*ranklist) (struct map_session_data *sd, enum fame_list_type type); + void (*update_rankingpoint) (struct map_session_data *sd, enum fame_list_type type, int points); + void (*pRanklist) (int fd, struct map_session_data *sd); void (*hotkeys) (struct map_session_data *sd); int (*insight) (struct block_list *bl,va_list ap); int (*outsight) (struct block_list *bl,va_list ap); void (*skillcastcancel) (struct block_list* bl); void (*skill_fail) (struct map_session_data *sd,uint16 skill_id,enum useskill_fail_cause cause,int btype); - void (*skill_cooldown) (struct map_session_data *sd, uint16 skill_id, unsigned int tick); + void (*skill_cooldown) (struct map_session_data *sd, uint16 skill_id, unsigned int duration); void (*skill_memomessage) (struct map_session_data* sd, int type); void (*skill_mapinfomessage) (struct map_session_data *sd, int type); void (*skill_produce_mix_list) (struct map_session_data *sd, int skill_id, int trigger); @@ -615,11 +720,10 @@ struct clif_interface { void (*partytickack) (struct map_session_data* sd, bool flag); void (*equiptickack) (struct map_session_data* sd, int flag); void (*viewequip_ack) (struct map_session_data* sd, struct map_session_data* tsd); - void (*viewequip_fail) (struct map_session_data* sd); void (*equpcheckbox) (struct map_session_data* sd); - void (*displayexp) (struct map_session_data *sd, unsigned int exp, char type, bool quest); + void (*displayexp) (struct map_session_data *sd, unsigned int exp, char type, bool is_quest); void (*font) (struct map_session_data *sd); - void (*progressbar) (struct map_session_data * sd, unsigned long color, unsigned int second); + void (*progressbar) (struct map_session_data * sd, unsigned int color, unsigned int second); void (*progressbar_abort) (struct map_session_data * sd); void (*showdigit) (struct map_session_data* sd, unsigned char type, int value); int (*elementalconverter_list) (struct map_session_data *sd); @@ -631,6 +735,7 @@ struct clif_interface { void (*sc_load) (struct block_list *bl, int tid, enum send_target target, int type, int val1, int val2, int val3); void (*sc_end) (struct block_list *bl, int tid, enum send_target target, int type); void (*initialstatus) (struct map_session_data *sd); + void (*cooldown_list) (int fd, struct skill_cd* cd); /* player-unit-specific-related */ void (*updatestatus) (struct map_session_data *sd,int type); void (*changestatus) (struct map_session_data* sd,int type,int val); @@ -638,7 +743,7 @@ struct clif_interface { void (*movetoattack) (struct map_session_data *sd,struct block_list *bl); void (*solved_charname) (int fd, int charid, const char* name); void (*charnameupdate) (struct map_session_data *ssd); - int (*delayquit) (int tid, unsigned int tick, int id, intptr_t data); + int (*delayquit) (int tid, int64 tick, int id, intptr_t data); void (*getareachar_pc) (struct map_session_data* sd,struct map_session_data* dstsd); void (*disconnect_ack) (struct map_session_data* sd, short result); void (*PVPInfo) (struct map_session_data* sd); @@ -656,9 +761,9 @@ struct clif_interface { void (*wedding_effect) (struct block_list *bl); void (*divorced) (struct map_session_data* sd, const char* name); void (*callpartner) (struct map_session_data *sd); - int (*skill_damage) (struct block_list *src,struct block_list *dst,unsigned int tick,int sdelay,int ddelay,int damage,int div,uint16 skill_id,uint16 skill_lv,int type); + int (*skill_damage) (struct block_list *src, struct block_list *dst, int64 tick, int sdelay, int ddelay, int64 damage, int div, uint16 skill_id, uint16 skill_lv, int type); int (*skill_nodamage) (struct block_list *src,struct block_list *dst,uint16 skill_id,int heal,int fail); - void (*skill_poseffect) (struct block_list *src,uint16 skill_id,int val,int x,int y,int tick); + void (*skill_poseffect) (struct block_list *src, uint16 skill_id, int val, int x, int y, int64 tick); void (*skill_estimation) (struct map_session_data *sd,struct block_list *dst); void (*skill_warppoint) (struct map_session_data* sd, uint16 skill_id, uint16 skill_lv, unsigned short map1, unsigned short map2, unsigned short map3, unsigned short map4); void (*skillcasting) (struct block_list* bl, int src_id, int dst_id, int dst_x, int dst_y, uint16 skill_id, int property, int casttime); @@ -675,7 +780,7 @@ struct clif_interface { void (*specialeffect) (struct block_list* bl, int type, enum send_target target); void (*specialeffect_single) (struct block_list* bl, int type, int fd); void (*specialeffect_value) (struct block_list* bl, int effect_id, int num, send_target target); - void (*millenniumshield) (struct map_session_data *sd, short shields ); + void (*millenniumshield) (struct block_list *bl, short shields ); void (*charm) (struct map_session_data *sd, short type); void (*charm_single) (int fd, struct map_session_data *sd, short type); void (*snap) ( struct block_list *bl, short x, short y ); @@ -695,13 +800,12 @@ 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, int mes_len); + void (*wis_message) (int fd, const char* nick, const char* mes, size_t mes_len); void (*wis_end) (int fd, int flag); - void (*disp_onlyself) (struct map_session_data *sd, const char *mes, int len); - void (*disp_message) (struct block_list* src, const char* mes, int len, 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 long fontColor, short fontType, short fontSize, short fontAlign, short fontY, enum send_target target); - void (*messagecolor) (struct block_list* bl, unsigned long color, const char* msg); + 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 (*messagecolor) (struct block_list* bl, unsigned int color, const char* msg); void (*disp_overhead) (struct block_list *bl, const char* mes); void (*msg) (struct map_session_data* sd, unsigned short id); void (*msg_value) (struct map_session_data* sd, unsigned short id, int value); @@ -710,11 +814,14 @@ struct clif_interface { void (*msgtable_num) (int fd, int line, int num); void (*message) (const int fd, const char* mes); void (*messageln) (const int fd, const char* mes); + /* message+s(printf) */ + void (*messages) (const int fd, const char *mes, ...) __attribute__((format(printf, 2, 3))); int (*colormes) (int fd, enum clif_colors color, const char* msg); - bool (*process_message) (struct map_session_data* sd, int format, char** name_, int* namelen_, char** message_, int* messagelen_); + bool (*process_message) (struct map_session_data *sd, int format, char **name_, size_t *namelen_, char **message_, size_t *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); + void (*ShowScript) (struct block_list* bl, const char* message); /* trade handling */ void (*traderequest) (struct map_session_data* sd, const char* name); void (*tradestart) (struct map_session_data* sd, uint8 type); @@ -728,9 +835,9 @@ struct clif_interface { void (*openvendingreq) (struct map_session_data* sd, int num); void (*showvendingboard) (struct block_list* bl, const char* message, int fd); void (*closevendingboard) (struct block_list* bl, int fd); - void (*vendinglist) (struct map_session_data* sd, unsigned int id, struct s_vending* vending); + void (*vendinglist) (struct map_session_data* sd, unsigned int id, struct s_vending* vending_list); void (*buyvending) (struct map_session_data* sd, int index, int amount, int fail); - void (*openvending) (struct map_session_data* sd, int id, struct s_vending* vending); + void (*openvending) (struct map_session_data* sd, int id, struct s_vending* vending_list); void (*vendingreport) (struct map_session_data* sd, int index, int amount); /* storage handling */ void (*storagelist) (struct map_session_data* sd, struct item* items, int items_length); @@ -740,8 +847,8 @@ struct clif_interface { void (*storageclose) (struct map_session_data* sd); /* skill-list handling */ void (*skillinfoblock) (struct map_session_data *sd); - void (*skillup) (struct map_session_data *sd,uint16 skill_id); - void (*skillinfo) (struct map_session_data *sd,int skill, int inf); + void (*skillup) (struct map_session_data *sd, uint16 skill_id, int skill_lv, int flag); + void (*skillinfo) (struct map_session_data *sd,int skill_id, int inf); void (*addskill) (struct map_session_data *sd, int id); void (*deleteskill) (struct map_session_data *sd, int id); /* party-specific */ @@ -779,7 +886,6 @@ struct clif_interface { void (*guild_emblem_area) (struct block_list* bl); void (*guild_notice) (struct map_session_data* sd, struct guild* g); void (*guild_message) (struct guild *g,int account_id,const char *mes,int len); - int (*guild_skillup) (struct map_session_data *sd,uint16 skill_id,int lv); void (*guild_reqalliance) (struct map_session_data *sd,int account_id,const char *name); void (*guild_allianceack) (struct map_session_data *sd,int flag); void (*guild_delalliance) (struct map_session_data *sd,int guild_id,int flag); @@ -796,7 +902,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 *bg, int src_id, const char *name, const char *mes, int len); + void (*bg_message) (struct battleground_data *bgd, int src_id, const char *name, const char *mes, size_t len); void (*bg_updatescore) (int16 m); void (*bg_updatescore_single) (struct map_session_data *sd); void (*sendbgemblem_area) (struct map_session_data *sd); @@ -820,7 +926,7 @@ struct clif_interface { void (*friendslist_toggle) (struct map_session_data *sd,int account_id, int char_id, int online); void (*friendlist_req) (struct map_session_data* sd, int account_id, int char_id, const char* name); /* gm-related */ - void (*GM_kickack) (struct map_session_data *sd, int id); + void (*GM_kickack) (struct map_session_data *sd, int result); void (*GM_kick) (struct map_session_data *sd,struct map_session_data *tsd); void (*manner_message) (struct map_session_data* sd, uint32 type); void (*GM_silence) (struct map_session_data* sd, struct map_session_data* tsd, uint8 type); @@ -828,17 +934,17 @@ struct clif_interface { void (*check) (int fd, struct map_session_data* pl_sd); /* hom-related */ void (*hominfo) (struct map_session_data *sd, struct homun_data *hd, int flag); - int (*homskillinfoblock) (struct map_session_data *sd); + void (*homskillinfoblock) (struct map_session_data *sd); void (*homskillup) (struct map_session_data *sd, uint16 skill_id); - int (*hom_food) (struct map_session_data *sd,int foodid,int fail); + void (*hom_food) (struct map_session_data *sd,int foodid,int fail); void (*send_homdata) (struct map_session_data *sd, int state, int param); /* questlog-related */ - void (*quest_send_list) (struct map_session_data * sd); - void (*quest_send_mission) (struct map_session_data * sd); - void (*quest_add) (struct map_session_data * sd, struct quest * qd, int index); - void (*quest_delete) (struct map_session_data * sd, int quest_id); - void (*quest_update_status) (struct map_session_data * sd, int quest_id, bool active); - void (*quest_update_objective) (struct map_session_data * sd, struct quest * qd, int index); + void (*quest_send_list) (struct map_session_data *sd); + void (*quest_send_mission) (struct map_session_data *sd); + void (*quest_add) (struct map_session_data *sd, struct quest *qd); + void (*quest_delete) (struct map_session_data *sd, int quest_id); + void (*quest_update_status) (struct map_session_data *sd, int quest_id, bool active); + void (*quest_update_objective) (struct map_session_data *sd, struct quest *qd); void (*quest_show_event) (struct map_session_data *sd, struct block_list *bl, short state, short color); /* mail-related */ void (*mail_window) (int fd, int flag); @@ -871,14 +977,18 @@ struct clif_interface { void (*PartyBookingUpdateNotify) (struct map_session_data* sd, struct party_booking_ad_info* pb_ad); void (*PartyBookingDeleteNotify) (struct map_session_data* sd, int index); void (*PartyBookingInsertNotify) (struct map_session_data* sd, struct party_booking_ad_info* pb_ad); + void (*PartyRecruitRegisterAck) (struct map_session_data *sd, int flag); + void (*PartyRecruitDeleteAck) (struct map_session_data* sd, int flag); + void (*PartyRecruitSearchAck) (int fd, struct party_booking_ad_info** results, int count, bool more_result); + void (*PartyRecruitUpdateNotify) (struct map_session_data* sd, struct party_booking_ad_info* pb_ad); + void (*PartyRecruitDeleteNotify) (struct map_session_data* sd, int index); + void (*PartyRecruitInsertNotify) (struct map_session_data* sd, struct party_booking_ad_info* pb_ad); /* Group Search System Update */ -#ifdef PARTY_RECRUIT void (*PartyBookingVolunteerInfo) (int index, struct map_session_data *sd); - void (*PartyBookingRefuseVolunteer) (unsigned long aid, struct map_session_data *sd); + void (*PartyBookingRefuseVolunteer) (unsigned int aid, struct map_session_data *sd); void (*PartyBookingCancelVolunteer) (int index, struct map_session_data *sd); void (*PartyBookingAddFilteringList) (int index, struct map_session_data *sd); void (*PartyBookingSubFilteringList) (int gid, struct map_session_data *sd); -#endif /* buying store-related */ void (*buyingstore_open) (struct map_session_data* sd); void (*buyingstore_open_failed) (struct map_session_data* sd, unsigned short result, unsigned int weight); @@ -902,7 +1012,7 @@ struct clif_interface { void (*elemental_updatestatus) (struct map_session_data *sd, int type); /* bgqueue */ void (*bgqueue_ack) (struct map_session_data *sd, enum BATTLEGROUNDS_QUEUE_ACK response, unsigned char arena_id); - void (*bgqueue_notice_delete) (struct map_session_data *sd, enum BATTLEGROUNDS_QUEUE_NOTICE_DELETED response, unsigned char arena_id); + void (*bgqueue_notice_delete) (struct map_session_data *sd, enum BATTLEGROUNDS_QUEUE_NOTICE_DELETED response, char *name); void (*bgqueue_update_info) (struct map_session_data *sd, unsigned char arena_id, int position); void (*bgqueue_joined) (struct map_session_data *sd, int pos); void (*bgqueue_pcleft) (struct map_session_data *sd); @@ -911,13 +1021,16 @@ struct clif_interface { void (*adopt_reply) (struct map_session_data *sd, int type); void (*adopt_request) (struct map_session_data *sd, struct map_session_data *src, int p_id); void (*readbook) (int fd, int book_id, int page); - void (*notify_time) (struct map_session_data* sd, unsigned long time); + void (*notify_time) (struct map_session_data* sd, int64 time); void (*user_count) (struct map_session_data* sd, int count); void (*noask_sub) (struct map_session_data *src, struct map_session_data *target, int type); + void (*bc_ready) (void); + int (*undisguise_timer) (int tid, int64 tick, int id, intptr_t data); + /* Hercules Channel System */ void (*chsys_create) (struct hChSysCh *channel, char *name, char *pass, unsigned char color); void (*chsys_msg) (struct hChSysCh *channel, struct map_session_data *sd, char *msg); void (*chsys_msg2) (struct hChSysCh *channel, char *msg); - void (*chsys_send) (struct hChSysCh *channel, struct map_session_data *sd, char *msg); + void (*chsys_send) (struct hChSysCh *channel, struct map_session_data *sd, const char *msg); void (*chsys_join) (struct hChSysCh *channel, struct map_session_data *sd); void (*chsys_left) (struct hChSysCh *channel, struct map_session_data *sd); void (*chsys_delete) (struct hChSysCh *channel); @@ -926,8 +1039,19 @@ struct clif_interface { void (*chsys_quitg) (struct map_session_data *sd); void (*chsys_gjoin) (struct guild *g1,struct guild *g2); void (*chsys_gleave) (struct guild *g1,struct guild *g2); - void (*bc_ready) (void); - int (*undisguise_timer) (int tid, unsigned int tick, int id, intptr_t data); + /* Bank System [Yommy/Hercules] */ + void (*bank_deposit) (struct map_session_data *sd, enum e_BANKING_DEPOSIT_ACK reason); + void (*bank_withdraw) (struct map_session_data *sd,enum e_BANKING_WITHDRAW_ACK reason); + /* */ + void (*show_modifiers) (struct map_session_data *sd); + /* */ + void (*notify_bounditem) (struct map_session_data *sd, unsigned short index); + /* */ + int (*delay_damage) (int64 tick, struct block_list *src, struct block_list *dst, int sdelay, int ddelay, int64 in_damage, short div, unsigned char type); + int (*delay_damage_sub) (int tid, int64 tick, int id, intptr_t data); + /* NPC Market */ + void (*npc_market_open) (struct map_session_data *sd, struct npc_data *nd); + void (*npc_market_purchase_ack) (struct map_session_data *sd, struct packet_npc_market_purchase *req, unsigned char response); /*------------------------ *- Parse Incoming Packet *------------------------*/ @@ -945,7 +1069,7 @@ struct clif_interface { void (*pEmotion) (int fd, struct map_session_data *sd); void (*pHowManyConnections) (int fd, struct map_session_data *sd); void (*pActionRequest) (int fd, struct map_session_data *sd); - void (*pActionRequest_sub) (struct map_session_data *sd, int action_type, int target_id, unsigned int tick); + void (*pActionRequest_sub) (struct map_session_data *sd, int action_type, int target_id, int64 tick); void (*pRestart) (int fd, struct map_session_data *sd); void (*pWisMessage) (int fd, struct map_session_data* sd); void (*pBroadcast) (int fd, struct map_session_data* sd); @@ -979,12 +1103,12 @@ struct clif_interface { void (*pStatusUp) (int fd,struct map_session_data *sd); void (*pSkillUp) (int fd,struct map_session_data *sd); void (*pUseSkillToId) (int fd, struct map_session_data *sd); - void (*pUseSkillToId_homun) (struct homun_data *hd, struct map_session_data *sd, unsigned int tick, uint16 skill_id, uint16 skill_lv, int target_id); - void (*pUseSkillToId_mercenary) (struct mercenary_data *md, struct map_session_data *sd, unsigned int tick, uint16 skill_id, uint16 skill_lv, int target_id); + void (*pUseSkillToId_homun) (struct homun_data *hd, struct map_session_data *sd, int64 tick, uint16 skill_id, uint16 skill_lv, int target_id); + void (*pUseSkillToId_mercenary) (struct mercenary_data *md, struct map_session_data *sd, int64 tick, uint16 skill_id, uint16 skill_lv, int target_id); void (*pUseSkillToPos) (int fd, struct map_session_data *sd); void (*pUseSkillToPosSub) (int fd, struct map_session_data *sd, uint16 skill_lv, uint16 skill_id, short x, short y, int skillmoreinfo); - void (*pUseSkillToPos_homun) (struct homun_data *hd, struct map_session_data *sd, unsigned int tick, uint16 skill_id, uint16 skill_lv, short x, short y, int skillmoreinfo); - void (*pUseSkillToPos_mercenary) (struct mercenary_data *md, struct map_session_data *sd, unsigned int tick, uint16 skill_id, uint16 skill_lv, short x, short y, int skillmoreinfo); + void (*pUseSkillToPos_homun) (struct homun_data *hd, struct map_session_data *sd, int64 tick, uint16 skill_id, uint16 skill_lv, short x, short y, int skillmoreinfo); + void (*pUseSkillToPos_mercenary) (struct mercenary_data *md, struct map_session_data *sd, int64 tick, uint16 skill_id, uint16 skill_lv, short x, short y, int skillmoreinfo); void (*pUseSkillToPosMoreInfo) (int fd, struct map_session_data *sd); void (*pUseSkillMap) (int fd, struct map_session_data* sd); void (*pRequestMemo) (int fd,struct map_session_data *sd); @@ -1026,6 +1150,10 @@ struct clif_interface { void (*pPartyBookingSearchReq) (int fd, struct map_session_data* sd); void (*pPartyBookingDeleteReq) (int fd, struct map_session_data* sd); void (*pPartyBookingUpdateReq) (int fd, struct map_session_data* sd); + void (*pPartyRecruitRegisterReq) (int fd, struct map_session_data* sd); + void (*pPartyRecruitSearchReq) (int fd, struct map_session_data* sd); + void (*pPartyRecruitDeleteReq) (int fd, struct map_session_data* sd); + void (*pPartyRecruitUpdateReq) (int fd, struct map_session_data* sd); void (*pCloseVending) (int fd, struct map_session_data* sd); void (*pVendingListReq) (int fd, struct map_session_data* sd); void (*pPurchaseReq) (int fd, struct map_session_data* sd); @@ -1066,6 +1194,7 @@ struct clif_interface { void (*pGMRc) (int fd, struct map_session_data* sd); void (*pGMReqAccountName) (int fd, struct map_session_data *sd); void (*pGMChangeMapType) (int fd, struct map_session_data *sd); + void (*pGMFullStrip) (int fd, struct map_session_data *sd); void (*pPMIgnore) (int fd, struct map_session_data* sd); void (*pPMIgnoreAll) (int fd, struct map_session_data *sd); void (*pPMIgnoreList) (int fd,struct map_session_data *sd); @@ -1139,17 +1268,26 @@ struct clif_interface { void (*pPartyTick) (int fd, struct map_session_data *sd); void (*pGuildInvite2) (int fd, struct map_session_data *sd); /* Group Search System Update */ -#ifdef PARTY_RECRUIT void (*pPartyBookingAddFilter) (int fd, struct map_session_data *sd); void (*pPartyBookingSubFilter) (int fd, struct map_session_data *sd); void (*pPartyBookingReqVolunteer) (int fd, struct map_session_data *sd); void (*pPartyBookingRefuseVolunteer) (int fd, struct map_session_data *sd); void (*pPartyBookingCancelVolunteer) (int fd, struct map_session_data *sd); -#endif -} clif_s; + /* Bank System [Yommy/Hercules] */ + void (*pBankDeposit) (int fd, struct map_session_data *sd); + void (*pBankWithdraw) (int fd, struct map_session_data *sd); + void (*pBankCheck) (int fd, struct map_session_data *sd); + void (*pBankOpen) (int fd, struct map_session_data *sd); + void (*pBankClose) (int fd, struct map_session_data *sd); + /* */ + void (*pNPCShopClosed) (int fd, struct map_session_data *sd); + /* NPC Market (by Ind after an extensive debugging of the packet, only possible thanks to Yommy <3) */ + void (*pNPCMarketClosed) (int fd, struct map_session_data *sd); + void (*pNPCMarketPurchase) (int fd, struct map_session_data *sd); +}; struct clif_interface *clif; void clif_defaults(void); -#endif /* _CLIF_H_ */ +#endif /* MAP_CLIF_H */ diff --git a/src/map/date.c b/src/map/date.c index 9f2bc4bee..975a00c50 100644 --- a/src/map/date.c +++ b/src/map/date.c @@ -1,9 +1,14 @@ // Copyright (c) Athena Dev Teams - Licensed under GNU GPL // For more information, see LICENCE in the main folder +#define HERCULES_CORE + #include "date.h" + #include <time.h> +#include "../common/cbasetypes.h" + int date_get_year(void) { time_t t; @@ -55,17 +60,21 @@ int date_get_sec(void) return lt->tm_sec; } -int is_day_of_sun(void) +/*========================================== + * Star gladiator related checks + *------------------------------------------*/ + +bool is_day_of_sun(void) { return date_get_day()%2 == 0; } -int is_day_of_moon(void) +bool is_day_of_moon(void) { return date_get_day()%2 == 1; } -int is_day_of_star(void) +bool is_day_of_star(void) { return date_get_day()%5 == 0; } diff --git a/src/map/date.h b/src/map/date.h index cc19d88d1..c3f353f64 100644 --- a/src/map/date.h +++ b/src/map/date.h @@ -1,8 +1,10 @@ // Copyright (c) Athena Dev Teams - Licensed under GNU GPL // For more information, see LICENCE in the main folder -#ifndef _DATE_H_ -#define _DATE_H_ +#ifndef MAP_DATE_H +#define MAP_DATE_H + +#include "../common/cbasetypes.h" int date_get_year(void); int date_get_month(void); @@ -11,8 +13,8 @@ int date_get_hour(void); int date_get_min(void); int date_get_sec(void); -int is_day_of_sun(void); -int is_day_of_moon(void); -int is_day_of_star(void); +bool is_day_of_sun(void); +bool is_day_of_moon(void); +bool is_day_of_star(void); -#endif /* _DATE_H_ */ +#endif /* MAP_DATE_H */ diff --git a/src/map/duel.c b/src/map/duel.c index 9a8b6d12b..4e4eeef1f 100644 --- a/src/map/duel.c +++ b/src/map/duel.c @@ -2,45 +2,42 @@ // See the LICENSE file // Portions Copyright (c) Athena Dev Teams -#include "../common/cbasetypes.h" +#define HERCULES_CORE -#include "atcommand.h" // msg_txt -#include "clif.h" #include "duel.h" -#include "pc.h" #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> -struct duel duel_list[MAX_DUEL]; -int duel_count = 0; +#include "atcommand.h" // msg_txt +#include "clif.h" +#include "pc.h" +#include "../common/cbasetypes.h" /*========================================== * Duel organizing functions [LuzZza] *------------------------------------------*/ -void duel_savetime(struct map_session_data* sd) -{ - time_t timer; +void duel_savetime(struct map_session_data* sd) { + time_t clock; struct tm *t; - time(&timer); - t = localtime(&timer); + time(&clock); + t = localtime(&clock); - pc_setglobalreg(sd, "PC_LAST_DUEL_TIME", t->tm_mday*24*60 + t->tm_hour*60 + t->tm_min); + pc_setglobalreg(sd, script->add_str("PC_LAST_DUEL_TIME"), t->tm_mday*24*60 + t->tm_hour*60 + t->tm_min); } -int duel_checktime(struct map_session_data* sd) -{ +int duel_checktime(struct map_session_data* sd) { int diff; - time_t timer; + time_t clock; struct tm *t; - time(&timer); - t = localtime(&timer); + time(&clock); + t = localtime(&clock); - diff = t->tm_mday*24*60 + t->tm_hour*60 + t->tm_min - pc_readglobalreg(sd, "PC_LAST_DUEL_TIME"); + diff = t->tm_mday*24*60 + t->tm_hour*60 + t->tm_min - pc_readglobalreg(sd, script->add_str("PC_LAST_DUEL_TIME") ); return !(diff >= 0 && diff < battle_config.duel_time_interval); } @@ -53,55 +50,52 @@ 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, strlen(output)); return 1; } -void duel_showinfo(const unsigned int did, struct map_session_data* sd) -{ +void duel_showinfo(const unsigned int did, struct map_session_data* sd) { int p=0; char output[256]; - if(duel_list[did].max_players_limit > 0) + if(duel->list[did].max_players_limit > 0) sprintf(output, msg_txt(370), //" -- Duels: %d/%d, Members: %d/%d, Max players: %d --" - did, duel_count, - duel_list[did].members_count, - duel_list[did].members_count + duel_list[did].invites_count, - duel_list[did].max_players_limit); + did, duel->count, + duel->list[did].members_count, + duel->list[did].members_count + duel->list[did].invites_count, + duel->list[did].max_players_limit); else sprintf(output, msg_txt(371), //" -- Duels: %d/%d, Members: %d/%d --" - did, duel_count, - duel_list[did].members_count, - duel_list[did].members_count + duel_list[did].invites_count); + did, duel->count, + duel->list[did].members_count, + duel->list[did].members_count + duel->list[did].invites_count); - clif->disp_onlyself(sd, output, strlen(output)); - iMap->map_foreachpc(duel_showinfo_sub, sd, &p); + clif_disp_onlyself(sd, output, strlen(output)); + map->foreachpc(duel_showinfo_sub, sd, &p); } -int duel_create(struct map_session_data* sd, const unsigned int maxpl) -{ +int duel_create(struct map_session_data* sd, const unsigned int maxpl) { int i=1; char output[256]; - while(duel_list[i].members_count > 0 && i < MAX_DUEL) i++; + while(duel->list[i].members_count > 0 && i < MAX_DUEL) i++; if(i == MAX_DUEL) return 0; - duel_count++; + duel->count++; sd->duel_group = i; - duel_list[i].members_count++; - duel_list[i].invites_count = 0; - duel_list[i].max_players_limit = maxpl; + duel->list[i].members_count++; + duel->list[i].invites_count = 0; + duel->list[i].max_players_limit = maxpl; strcpy(output, msg_txt(372)); // " -- Duel has been created (@invite/@leave) --" - clif->disp_onlyself(sd, output, strlen(output)); + clif_disp_onlyself(sd, output, strlen(output)); clif->map_property(sd, MAPPROPERTY_FREEPVPZONE); clif->maptypeproperty2(&sd->bl,SELF); return i; } -void duel_invite(const unsigned int did, struct map_session_data* sd, struct map_session_data* target_sd) -{ +void duel_invite(const unsigned int did, struct map_session_data* sd, struct map_session_data* target_sd) { char output[256]; // " -- Player %s invites %s to duel --" @@ -109,11 +103,11 @@ void duel_invite(const unsigned int did, struct map_session_data* sd, struct map clif->disp_message(&sd->bl, output, strlen(output), DUEL_WOS); target_sd->duel_invite = did; - duel_list[did].invites_count++; + duel->list[did].invites_count++; // "Blue -- Player %s invites you to PVP duel (@accept/@reject) --" sprintf(output, msg_txt(374), sd->status.name); - clif->broadcast((struct block_list *)target_sd, output, strlen(output)+1, 0x10, SELF); + clif->broadcast((struct block_list *)target_sd, output, strlen(output)+1, BC_BLUE, SELF); } static int duel_leave_sub(struct map_session_data* sd, va_list va) @@ -124,19 +118,18 @@ static int duel_leave_sub(struct map_session_data* sd, va_list va) return 0; } -void duel_leave(const unsigned int did, struct map_session_data* sd) -{ +void duel_leave(const unsigned int did, struct map_session_data* sd) { char output[256]; // " <- Player %s has left duel --" sprintf(output, msg_txt(375), sd->status.name); clif->disp_message(&sd->bl, output, strlen(output), DUEL_WOS); - duel_list[did].members_count--; + duel->list[did].members_count--; - if(duel_list[did].members_count == 0) { - iMap->map_foreachpc(duel_leave_sub, did); - duel_count--; + if(duel->list[did].members_count == 0) { + map->foreachpc(duel_leave_sub, did); + duel->count--; } sd->duel_group = 0; @@ -145,13 +138,12 @@ void duel_leave(const unsigned int did, struct map_session_data* sd) clif->maptypeproperty2(&sd->bl,SELF); } -void duel_accept(const unsigned int did, struct map_session_data* sd) -{ +void duel_accept(const unsigned int did, struct map_session_data* sd) { char output[256]; - duel_list[did].members_count++; + duel->list[did].members_count++; sd->duel_group = sd->duel_invite; - duel_list[did].invites_count--; + duel->list[did].invites_count--; sd->duel_invite = 0; // " -> Player %s has accepted duel --" @@ -162,23 +154,46 @@ void duel_accept(const unsigned int did, struct map_session_data* sd) clif->maptypeproperty2(&sd->bl,SELF); } -void duel_reject(const unsigned int did, struct map_session_data* sd) -{ +void duel_reject(const unsigned int did, struct map_session_data* sd) { char output[256]; // " -- Player %s has rejected duel --" sprintf(output, msg_txt(377), sd->status.name); clif->disp_message(&sd->bl, output, strlen(output), DUEL_WOS); - duel_list[did].invites_count--; + duel->list[did].invites_count--; sd->duel_invite = 0; } -void do_final_duel(void) -{ +void do_final_duel(void) { } -void do_init_duel(void) -{ - memset(&duel_list[0], 0, sizeof(duel_list)); +void do_init_duel(bool minimal) { + if (minimal) + return; + + memset(&duel->list[0], 0, sizeof(duel->list)); +} + +/*===================================== +* Default Functions : duel.h +* Generated by HerculesInterfaceMaker +* created by Susu +*-------------------------------------*/ +void duel_defaults(void) { + duel = &duel_s; + /* vars */ + duel->count = 0; + /* funcs */ + //Duel functions // [LuzZza] + duel->create = duel_create; + duel->invite = duel_invite; + duel->accept = duel_accept; + duel->reject = duel_reject; + duel->leave = duel_leave; + duel->showinfo = duel_showinfo; + duel->checktime = duel_checktime; + + duel->init = do_init_duel; + duel->final = do_final_duel; } diff --git a/src/map/duel.h b/src/map/duel.h index 04d8e4e84..de2bd1bf6 100644 --- a/src/map/duel.h +++ b/src/map/duel.h @@ -1,8 +1,13 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder +// Copyright (c) Hercules Dev Team, licensed under GNU GPL. +// See the LICENSE file +// Portions Copyright (c) Athena Dev Teams -#ifndef _DUEL_H_ -#define _DUEL_H_ +#ifndef MAP_DUEL_H +#define MAP_DUEL_H + +#include "../common/cbasetypes.h" + +struct map_session_data; struct duel { int members_count; @@ -11,19 +16,34 @@ struct duel { }; #define MAX_DUEL 1024 -extern struct duel duel_list[MAX_DUEL]; -extern int duel_count; - -//Duel functions // [LuzZza] -int duel_create(struct map_session_data* sd, const unsigned int maxpl); -void duel_invite(const unsigned int did, struct map_session_data* sd, struct map_session_data* target_sd); -void duel_accept(const unsigned int did, struct map_session_data* sd); -void duel_reject(const unsigned int did, struct map_session_data* sd); -void duel_leave(const unsigned int did, struct map_session_data* sd); -void duel_showinfo(const unsigned int did, struct map_session_data* sd); -int duel_checktime(struct map_session_data* sd); - -void do_init_duel(void); -void do_final_duel(void); - -#endif /* _DUEL_H_ */ + +/*===================================== +* Interface : duel.h +* Generated by HerculesInterfaceMaker +* created by Susu +*-------------------------------------*/ +struct duel_interface { + + /* vars */ + struct duel list[MAX_DUEL]; + int count; + + /* funcs */ + //Duel functions // [LuzZza] + int (*create) (struct map_session_data* sd, const unsigned int maxpl); + void (*invite) (const unsigned int did, struct map_session_data* sd, struct map_session_data* target_sd); + void (*accept) (const unsigned int did, struct map_session_data* sd); + void (*reject) (const unsigned int did, struct map_session_data* sd); + void (*leave) (const unsigned int did, struct map_session_data* sd); + void (*showinfo) (const unsigned int did, struct map_session_data* sd); + int (*checktime) (struct map_session_data* sd); + + void (*init) (bool minimal); + void (*final) (void); +} duel_s; + +struct duel_interface *duel; + +void duel_defaults(void); + +#endif /* MAP_DUEL_H */ diff --git a/src/map/elemental.c b/src/map/elemental.c index 53c85577b..caba02692 100644 --- a/src/map/elemental.c +++ b/src/map/elemental.c @@ -2,142 +2,148 @@ // See the LICENSE file // Portions Copyright (c) Athena Dev Teams -#include "../common/cbasetypes.h" -#include "../common/malloc.h" -#include "../common/socket.h" -#include "../common/timer.h" -#include "../common/nullpo.h" -#include "../common/mmo.h" -#include "../common/showmsg.h" -#include "../common/utils.h" -#include "../common/random.h" -#include "../common/strlib.h" +#define HERCULES_CORE -#include "log.h" -#include "clif.h" +#include "elemental.h" + +#include <math.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "atcommand.h" +#include "battle.h" #include "chrif.h" +#include "clif.h" +#include "guild.h" #include "intif.h" #include "itemdb.h" +#include "log.h" #include "map.h" -#include "pc.h" -#include "status.h" -#include "skill.h" #include "mob.h" -#include "pet.h" -#include "battle.h" +#include "npc.h" #include "party.h" -#include "guild.h" -#include "atcommand.h" +#include "pc.h" +#include "pet.h" #include "script.h" -#include "npc.h" +#include "skill.h" +#include "status.h" #include "trade.h" #include "unit.h" -#include "elemental.h" - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <math.h> +#include "../common/cbasetypes.h" +#include "../common/malloc.h" +#include "../common/mmo.h" +#include "../common/nullpo.h" +#include "../common/random.h" +#include "../common/showmsg.h" +#include "../common/socket.h" +#include "../common/strlib.h" +#include "../common/timer.h" +#include "../common/utils.h" -struct s_elemental_db elemental_db[MAX_ELEMENTAL_CLASS]; // Elemental Database +struct elemental_interface elemental_s; int elemental_search_index(int class_) { int i; - ARR_FIND(0, MAX_ELEMENTAL_CLASS, i, elemental_db[i].class_ == class_); + ARR_FIND(0, MAX_ELEMENTAL_CLASS, i, elemental->db[i].class_ == class_); return (i == MAX_ELEMENTAL_CLASS)?-1:i; } bool elemental_class(int class_) { - return (bool)(elemental_search_index(class_) > -1); + return (bool)(elemental->search_index(class_) > -1); } struct view_data * elemental_get_viewdata(int class_) { - int i = elemental_search_index(class_); + int i = elemental->search_index(class_); if( i < 0 ) return 0; - return &elemental_db[i].vd; + return &elemental->db[i].vd; } int elemental_create(struct map_session_data *sd, int class_, unsigned int lifetime) { struct s_elemental ele; struct s_elemental_db *db; - int i; + int i, summon_level, skill_level; nullpo_retr(1,sd); - if( (i = elemental_search_index(class_)) < 0 ) + if( (i = elemental->search_index(class_)) < 0 ) return 0; - db = &elemental_db[i]; + db = &elemental->db[i]; memset(&ele,0,sizeof(struct s_elemental)); ele.char_id = sd->status.char_id; ele.class_ = class_; ele.mode = EL_MODE_PASSIVE; // Initial mode - i = db->status.size+1; // summon level + summon_level = db->status.size+1; // summon level - //[(Casterソスs Max HP/ 3 ) + (Casterソスs INT x 10 )+ (Casterソスs Job Level x 20 )] x [(Elemental Summon Level + 2) / 3] - ele.hp = ele.max_hp = (sd->battle_status.max_hp/3 + sd->battle_status.int_*10 + sd->status.job_level) * ((i + 2) / 3); - //Casterソスs Max SP /4 + //[(Caster's Max HP/ 3 ) + (Caster's INT x 10 )+ (Caster's Job Level x 20 )] x [(Elemental Summon Level + 2) / 3] + ele.hp = ele.max_hp = (sd->battle_status.max_hp/3 + sd->battle_status.int_*10 + sd->status.job_level) * ((summon_level + 2) / 3); + //Caster's Max SP /4 ele.sp = ele.max_sp = sd->battle_status.max_sp/4; - //Casterソスs [ Max SP / (18 / Elemental Summon Skill Level) 1- 100 ] - ele.atk = (sd->battle_status.max_sp / (18 / i) * 1 - 100); - //Casterソスs [ Max SP / (18 / Elemental Summon Skill Level) ] + //Caster's [ Max SP / (18 / Elemental Summon Skill Level) 1- 100 ] + ele.atk = (sd->battle_status.max_sp / (18 / summon_level) * 1 - 100); + //Caster's [ Max SP / (18 / Elemental Summon Skill Level) ] ele.atk2 = sd->battle_status.max_sp / 18; - //Casterソスs HIT + (Casterソスs Base Level ) + //Caster's HIT + (Caster's Base Level) ele.hit = sd->battle_status.hit + sd->status.base_level; - //[Elemental Summon Skill Level x (Casterソスs INT / 2 + Casterソスs DEX / 4)] - ele.matk = i * (sd->battle_status.int_ / 2 + sd->battle_status.dex / 4); - //150 + [Casterソスs DEX / 10] + [Elemental Summon Skill Level x 3 ] - ele.amotion = 150 + sd->battle_status.dex / 10 + i * 3; - //Casterソスs DEF + (Casterソスs Base Level / (5 ソス Elemental Summon Skill Level) - ele.def = sd->battle_status.def + sd->status.base_level / (5-i); - //Casterソスs MDEF + (Casterソスs INT / (5 - Elemental Summon Skill Level) - ele.mdef = sd->battle_status.mdef + sd->battle_status.int_ / (5-i); - //Casterソスs FLEE + (Casterソスs Base Level / (5 ソス Elemental Summon Skill Level) - ele.flee = sd->status.base_level / (5-i); - //Casterソスs HIT + (Casterソスs Base Level ) + //[Elemental Summon Skill Level x (Caster's INT / 2 + Caster's DEX / 4)] + ele.matk = summon_level * (sd->battle_status.int_ / 2 + sd->battle_status.dex / 4); + //150 + [Caster's DEX / 10] + [Elemental Summon Skill Level x 3 ] + ele.amotion = 150 + sd->battle_status.dex / 10 + summon_level * 3; + //Caster's DEF + (Caster's Base Level / (5 - Elemental Summon Skill Level) + ele.def = sd->battle_status.def + sd->status.base_level / (5-summon_level); + //Caster's MDEF + (Caster's INT / (5 - Elemental Summon Skill Level) + ele.mdef = sd->battle_status.mdef + sd->battle_status.int_ / (5-summon_level); + //Caster's FLEE + (Caster's Base Level / (5 - Elemental Summon Skill Level) + ele.flee = sd->status.base_level / (5-summon_level); + //Caster's HIT + (Caster's Base Level) ele.hit = sd->battle_status.hit + sd->status.base_level; //per individual bonuses switch(db->class_){ - case 2114: case 2115: + case 2114: + case 2115: case 2116: //ATK + (Summon Agni Skill Level x 20) / HIT + (Summon Agni Skill Level x 10) - ele.atk += i * 20; - ele.atk2 += i * 20; - ele.hit += i * 10; + ele.atk += summon_level * 20; + ele.atk2 += summon_level * 20; + ele.hit += summon_level * 10; break; - case 2117: case 2118: + case 2117: + case 2118: case 2119: //MDEF + (Summon Aqua Skill Level x 10) / MATK + (Summon Aqua Skill Level x 20) - ele.mdef += i * 10; - ele.matk += i * 20; + ele.mdef += summon_level * 10; + ele.matk += summon_level * 20; break; - case 2120: case 2121: + case 2120: + case 2121: case 2122: //FLEE + (Summon Ventus Skill Level x 20) / MATK + (Summon Ventus Skill Level x 10) - ele.flee += i * 20; - ele.matk += i * 10; + ele.flee += summon_level * 20; + ele.matk += summon_level * 10; break; - case 2123: case 2124: + case 2123: + case 2124: case 2125: //DEF + (Summon Tera Skill Level x 25) / ATK + (Summon Tera Skill Level x 5) - ele.def += i * 25; - ele.atk += i * 5; - ele.atk2 += i * 5; + ele.def += summon_level * 25; + ele.atk += summon_level * 5; + ele.atk2 += summon_level * 5; break; } - if( (i=pc->checkskill(sd,SO_EL_SYMPATHY)) > 0 ){ - ele.hp = ele.max_hp = ele.max_hp * 5 * i / 100; - ele.sp = ele.max_sp = ele.max_sp * 5 * i / 100; - ele.atk += 25 * i; - ele.atk2 += 25 * i; - ele.matk += 25 * i; + if ((skill_level=pc->checkskill(sd,SO_EL_SYMPATHY)) > 0) { + ele.hp = ele.max_hp += ele.max_hp * 5 * skill_level / 100; + ele.sp = ele.max_sp += ele.max_sp * 5 * skill_level / 100; + ele.atk += 25 * skill_level; + ele.atk2 += 25 * skill_level; + ele.matk += 25 * skill_level; } ele.life_time = lifetime; // Request Char Server to create this elemental - intif_elemental_create(&ele); + intif->elemental_create(&ele); return 1; } @@ -147,8 +153,8 @@ int elemental_get_lifetime(struct elemental_data *ed) { if( ed == NULL || ed->summon_timer == INVALID_TIMER ) return 0; - td = iTimer->get_timer(ed->summon_timer); - return (td != NULL) ? DIFF_TICK(td->tick, iTimer->gettick()) : 0; + td = timer->get(ed->summon_timer); + return (td != NULL) ? DIFF_TICK32(td->tick, timer->gettick()) : 0; } int elemental_save(struct elemental_data *ed) { @@ -164,27 +170,27 @@ int elemental_save(struct elemental_data *ed) { ed->elemental.mdef = ed->battle_status.mdef; ed->elemental.flee = ed->battle_status.flee; ed->elemental.hit = ed->battle_status.hit; - ed->elemental.life_time = elemental_get_lifetime(ed); - intif_elemental_save(&ed->elemental); + ed->elemental.life_time = elemental->get_lifetime(ed); + intif->elemental_save(&ed->elemental); return 1; } -static int elemental_summon_end(int tid, unsigned int tick, int id, intptr_t data) { +int elemental_summon_end_timer(int tid, int64 tick, int id, intptr_t data) { struct map_session_data *sd; struct elemental_data *ed; - if( (sd = iMap->id2sd(id)) == NULL ) + if( (sd = map->id2sd(id)) == NULL ) return 1; if( (ed = sd->ed) == NULL ) return 1; if( ed->summon_timer != tid ) { - ShowError("elemental_summon_end %d != %d.\n", ed->summon_timer, tid); + ShowError("elemental_summon_end_timer %d != %d.\n", ed->summon_timer, tid); return 0; } ed->summon_timer = INVALID_TIMER; - elemental_delete(ed, 0); // Elemental's summon time is over. + elemental->delete(ed, 0); // Elemental's summon time is over. return 0; } @@ -192,7 +198,7 @@ static int elemental_summon_end(int tid, unsigned int tick, int id, intptr_t dat void elemental_summon_stop(struct elemental_data *ed) { nullpo_retv(ed); if( ed->summon_timer != INVALID_TIMER ) - iTimer->delete_timer(ed->summon_timer, elemental_summon_end); + timer->delete(ed->summon_timer, elemental->summon_end_timer); ed->summon_timer = INVALID_TIMER; } @@ -203,21 +209,21 @@ int elemental_delete(struct elemental_data *ed, int reply) { sd = ed->master; ed->elemental.life_time = 0; - elemental_clean_effect(ed); - elemental_summon_stop(ed); + elemental->clean_effect(ed); + elemental->summon_stop(ed); if( !sd ) - return unit_free(&ed->bl, 0); + return unit->free(&ed->bl, 0); sd->ed = NULL; sd->status.ele_id = 0; - return unit_remove_map(&ed->bl, 0); + return unit->remove_map(&ed->bl, 0, ALC_MARK); } void elemental_summon_init(struct elemental_data *ed) { if( ed->summon_timer == INVALID_TIMER ) - ed->summon_timer = iTimer->add_timer(iTimer->gettick() + ed->elemental.life_time, elemental_summon_end, ed->master->bl.id, 0); + ed->summon_timer = timer->add(timer->gettick() + ed->elemental.life_time, elemental->summon_end_timer, ed->master->bl.id, 0); ed->regen.state.block = 0; } @@ -226,9 +232,9 @@ int elemental_data_received(struct s_elemental *ele, bool flag) { struct map_session_data *sd; struct elemental_data *ed; struct s_elemental_db *db; - int i = elemental_search_index(ele->class_); + int i = elemental->search_index(ele->class_); - if( (sd = iMap->charid2sd(ele->char_id)) == NULL ) + if( (sd = map->charid2sd(ele->char_id)) == NULL ) return 0; if( !flag || i < 0 ) { // Not created - loaded - DB info @@ -236,32 +242,32 @@ int elemental_data_received(struct s_elemental *ele, bool flag) { return 0; } - db = &elemental_db[i]; + db = &elemental->db[i]; if( !sd->ed ) { // Initialize it after first summon. sd->ed = ed = (struct elemental_data*)aCalloc(1,sizeof(struct elemental_data)); ed->bl.type = BL_ELEM; - ed->bl.id = npc_get_new_npc_id(); + ed->bl.id = npc->get_new_npc_id(); ed->master = sd; ed->db = db; memcpy(&ed->elemental, ele, sizeof(struct s_elemental)); - status_set_viewdata(&ed->bl, ed->elemental.class_); + status->set_viewdata(&ed->bl, ed->elemental.class_); ed->vd->head_mid = 10; // Why? - status_change_init(&ed->bl); - unit_dataset(&ed->bl); + status->change_init(&ed->bl); + unit->dataset(&ed->bl); ed->ud.dir = sd->ud.dir; ed->bl.m = sd->bl.m; ed->bl.x = sd->bl.x; ed->bl.y = sd->bl.y; - unit_calc_pos(&ed->bl, sd->bl.x, sd->bl.y, sd->ud.dir); + unit->calc_pos(&ed->bl, sd->bl.x, sd->bl.y, sd->ud.dir); ed->bl.x = ed->ud.to_x; ed->bl.y = ed->ud.to_y; - iMap->addiddb(&ed->bl); - status_calc_elemental(ed,1); - ed->last_spdrain_time = ed->last_thinktime = iTimer->gettick(); + map->addiddb(&ed->bl); + status_calc_elemental(ed,SCO_FIRST); + ed->last_spdrain_time = ed->last_thinktime = timer->gettick(); ed->summon_timer = INVALID_TIMER; - elemental_summon_init(ed); + elemental->summon_init(ed); } else { memcpy(&sd->ed->elemental, ele, sizeof(struct s_elemental)); ed = sd->ed; @@ -270,7 +276,7 @@ int elemental_data_received(struct s_elemental *ele, bool flag) { sd->status.ele_id = ele->elemental_id; if( ed->bl.prev == NULL && sd->bl.prev != NULL ) { - iMap->addblock(&ed->bl); + map->addblock(&ed->bl); clif->spawn(&ed->bl); clif->elemental_info(sd); clif->elemental_updatestatus(sd,SP_HP); @@ -283,7 +289,7 @@ int elemental_data_received(struct s_elemental *ele, bool flag) { int elemental_clean_single_effect(struct elemental_data *ed, uint16 skill_id) { struct block_list *bl; - sc_type type = status_skill2sc(skill_id); + sc_type type = status->skill2sc(skill_id); nullpo_ret(ed); @@ -388,7 +394,7 @@ int elemental_clean_effect(struct elemental_data *ed) { return 1; } -int elemental_action(struct elemental_data *ed, struct block_list *bl, unsigned int tick) { +int elemental_action(struct elemental_data *ed, struct block_list *bl, int64 tick) { struct skill_condition req; uint16 skill_id, skill_lv; int i; @@ -400,7 +406,7 @@ int elemental_action(struct elemental_data *ed, struct block_list *bl, unsigned return 0; if( ed->target_id ) - elemental_unlocktarget(ed); // Remove previous target. + elemental->unlocktarget(ed); // Remove previous target. ARR_FIND(0, MAX_ELESKILLTREE, i, ed->db->skill[i].id && (ed->db->skill[i].mode&EL_SKILLMODE_AGGRESSIVE)); if( i == MAX_ELESKILLTREE ) @@ -409,7 +415,7 @@ int elemental_action(struct elemental_data *ed, struct block_list *bl, unsigned skill_id = ed->db->skill[i].id; skill_lv = ed->db->skill[i].lv; - if( elemental_skillnotok(skill_id, ed) ) + if( elemental->skillnotok(skill_id, ed) ) return 0; if( ed->ud.skilltimer != INVALID_TIMER ) @@ -423,8 +429,8 @@ int elemental_action(struct elemental_data *ed, struct block_list *bl, unsigned // Not in skill range. if( !battle->check_range(&ed->bl,bl,skill->get_range(skill_id,skill_lv)) ) { // Try to walk to the target. - if( !unit_walktobl(&ed->bl, bl, skill->get_range(skill_id,skill_lv), 2) ) - elemental_unlocktarget(ed); + if( !unit->walktobl(&ed->bl, bl, skill->get_range(skill_id,skill_lv), 2) ) + elemental->unlocktarget(ed); else { // Walking, waiting to be in range. Client don't handle it, then we must handle it here. int walk_dist = distance_bl(&ed->bl,bl) - skill->get_range(skill_id,skill_lv); @@ -432,15 +438,15 @@ int elemental_action(struct elemental_data *ed, struct block_list *bl, unsigned ed->ud.skill_lv = skill_lv; if( skill->get_inf(skill_id) & INF_GROUND_SKILL ) - ed->ud.skilltimer = iTimer->add_timer( tick+status_get_speed(&ed->bl)*walk_dist, skill->castend_pos, ed->bl.id, 0 ); + ed->ud.skilltimer = timer->add( tick+status->get_speed(&ed->bl)*walk_dist, skill->castend_pos, ed->bl.id, 0 ); else - ed->ud.skilltimer = iTimer->add_timer( tick+status_get_speed(&ed->bl)*walk_dist, skill->castend_id, ed->bl.id, 0 ); + ed->ud.skilltimer = timer->add( tick+status->get_speed(&ed->bl)*walk_dist, skill->castend_id, ed->bl.id, 0 ); } return 1; } - req = elemental_skill_get_requirements(skill_id, skill_lv); + req = elemental->skill_get_requirements(skill_id, skill_lv); if(req.hp || req.sp){ struct map_session_data *sd = BL_CAST(BL_PC, battle->get_master(&ed->bl)); @@ -455,9 +461,9 @@ int elemental_action(struct elemental_data *ed, struct block_list *bl, unsigned //Otherwise, just cast the skill. if( skill->get_inf(skill_id) & INF_GROUND_SKILL ) - unit_skilluse_pos(&ed->bl, bl->x, bl->y, skill_id, skill_lv); + unit->skilluse_pos(&ed->bl, bl->x, bl->y, skill_id, skill_lv); else - unit_skilluse_id(&ed->bl, bl->id, skill_id, skill_lv); + unit->skilluse_id(&ed->bl, bl->id, skill_id, skill_lv); // Reset target. ed->target_id = 0; @@ -487,23 +493,23 @@ int elemental_change_mode_ack(struct elemental_data *ed, int mode) { skill_id = ed->db->skill[i].id; skill_lv = ed->db->skill[i].lv; - if( elemental_skillnotok(skill_id, ed) ) + if( elemental->skillnotok(skill_id, ed) ) return 0; if( ed->ud.skilltimer != INVALID_TIMER ) return 0; - else if( DIFF_TICK(iTimer->gettick(), ed->ud.canact_tick) < 0 ) + else if( DIFF_TICK(timer->gettick(), ed->ud.canact_tick) < 0 ) return 0; ed->target_id = bl->id; // Set new target - ed->last_thinktime = iTimer->gettick(); + ed->last_thinktime = timer->gettick(); if( skill->get_inf(skill_id) & INF_GROUND_SKILL ) - unit_skilluse_pos(&ed->bl, bl->x, bl->y, skill_id, skill_lv); + unit->skilluse_pos(&ed->bl, bl->x, bl->y, skill_id, skill_lv); else - unit_skilluse_id(&ed->bl,bl->id,skill_id,skill_lv); + unit->skilluse_id(&ed->bl,bl->id,skill_id,skill_lv); - ed->target_id = 0; // Reset target after casting the skill to avoid continious attack. + ed->target_id = 0; // Reset target after casting the skill to avoid continuous attack. return 1; } @@ -515,10 +521,10 @@ int elemental_change_mode(struct elemental_data *ed, int mode) { nullpo_ret(ed); // Remove target - elemental_unlocktarget(ed); + elemental->unlocktarget(ed); // Removes the effects of the previous mode. - if(ed->elemental.mode != mode ) elemental_clean_effect(ed); + if(ed->elemental.mode != mode ) elemental->clean_effect(ed); ed->battle_status.mode = ed->elemental.mode = mode; @@ -527,9 +533,9 @@ int elemental_change_mode(struct elemental_data *ed, int mode) { else if( mode == EL_MODE_ASSIST ) mode = EL_SKILLMODE_ASSIST; // Assist spirit mode -> Assist spirit skill. else mode = EL_SKILLMODE_PASIVE; // Passive spirit mode -> Passive spirit skill. - // Use a skill inmediately after every change mode. + // Use a skill immediately after every change mode. if( mode != EL_SKILLMODE_AGGRESSIVE ) - elemental_change_mode_ack(ed,mode); + elemental->change_mode_ack(ed,mode); return 1; } @@ -541,7 +547,7 @@ void elemental_heal(struct elemental_data *ed, int hp, int sp) { } int elemental_dead(struct elemental_data *ed) { - elemental_delete(ed, 1); + elemental->delete(ed, 1); return 0; } @@ -576,8 +582,8 @@ struct skill_condition elemental_skill_get_requirements(uint16 skill_id, uint16 if( skill_lv < 1 || skill_lv > MAX_SKILL_LEVEL ) return req; - req.hp = skill_db[idx].hp[skill_lv-1]; - req.sp = skill_db[idx].sp[skill_lv-1]; + req.hp = skill->db[idx].hp[skill_lv-1]; + req.sp = skill->db[idx].sp[skill_lv-1]; return req; } @@ -591,7 +597,7 @@ int elemental_set_target( struct map_session_data *sd, struct block_list *bl ) { if( ed->bl.m != bl->m || !check_distance_bl(&ed->bl, bl, ed->db->range2) ) return 0; - if( !status_check_skilluse(&ed->bl, bl, 0, 0) ) + if( !status->check_skilluse(&ed->bl, bl, 0, 0) ) return 0; if( ed->target_id == 0 ) @@ -600,7 +606,7 @@ int elemental_set_target( struct map_session_data *sd, struct block_list *bl ) { return 1; } -static int elemental_ai_sub_timer_activesearch(struct block_list *bl, va_list ap) { +int elemental_ai_sub_timer_activesearch(struct block_list *bl, va_list ap) { struct elemental_data *ed; struct block_list **target; int dist; @@ -611,7 +617,7 @@ static int elemental_ai_sub_timer_activesearch(struct block_list *bl, va_list ap target = va_arg(ap,struct block_list**); //If can't seek yet, not an enemy, or you can't attack it, skip. - if( (*target) == bl || !status_check_skilluse(&ed->bl, bl, 0, 0) ) + if( (*target) == bl || !status->check_skilluse(&ed->bl, bl, 0, 0) ) return 0; if( battle->check_target(&ed->bl,bl,BCT_ENEMY) <= 0 ) @@ -636,7 +642,7 @@ static int elemental_ai_sub_timer_activesearch(struct block_list *bl, va_list ap return 0; } -static int elemental_ai_sub_timer(struct elemental_data *ed, struct map_session_data *sd, unsigned int tick) { +int elemental_ai_sub_timer(struct elemental_data *ed, struct map_session_data *sd, int64 tick) { struct block_list *target = NULL; int master_dist, view_range, mode; @@ -662,7 +668,7 @@ static int elemental_ai_sub_timer(struct elemental_data *ed, struct map_session_ } if( status_get_sp(&sd->bl) < sp ){ // Can't sustain delete it. - elemental_delete(sd->ed,0); + elemental->delete(sd->ed,0); return 0; } @@ -693,37 +699,37 @@ static int elemental_ai_sub_timer(struct elemental_data *ed, struct map_session_ master_dist = distance_bl(&sd->bl, &ed->bl); if( master_dist > AREA_SIZE ) { // Master out of vision range. - elemental_unlocktarget(ed); - unit_warp(&ed->bl,sd->bl.m,sd->bl.x,sd->bl.y,CLR_TELEPORT); + elemental->unlocktarget(ed); + unit->warp(&ed->bl,sd->bl.m,sd->bl.x,sd->bl.y,CLR_TELEPORT); clif->elemental_updatestatus(sd,SP_HP); clif->elemental_updatestatus(sd,SP_SP); return 0; } else if( master_dist > MAX_ELEDISTANCE ) { // Master too far, chase. short x = sd->bl.x, y = sd->bl.y; if( ed->target_id ) - elemental_unlocktarget(ed); + elemental->unlocktarget(ed); if( ed->ud.walktimer != INVALID_TIMER && ed->ud.target == sd->bl.id ) return 0; //Already walking to him if( DIFF_TICK(tick, ed->ud.canmove_tick) < 0 ) return 0; //Can't move yet. - if( iMap->search_freecell(&ed->bl, sd->bl.m, &x, &y, MIN_ELEDISTANCE, MIN_ELEDISTANCE, 1) - && unit_walktoxy(&ed->bl, x, y, 0) ) + if( map->search_freecell(&ed->bl, sd->bl.m, &x, &y, MIN_ELEDISTANCE, MIN_ELEDISTANCE, 1) + && unit->walktoxy(&ed->bl, x, y, 0) ) return 0; } if( mode == EL_MODE_AGGRESSIVE ) { - target = iMap->id2bl(ed->ud.target); + target = map->id2bl(ed->ud.target); if( !target ) - iMap->foreachinrange(elemental_ai_sub_timer_activesearch, &ed->bl, view_range, BL_CHAR, ed, &target, status_get_mode(&ed->bl)); + map->foreachinrange(elemental->ai_sub_timer_activesearch, &ed->bl, view_range, BL_CHAR, ed, &target, status_get_mode(&ed->bl)); if( !target ) { //No targets available. - elemental_unlocktarget(ed); + elemental->unlocktarget(ed); return 1; } if( battle->check_range(&ed->bl,target,view_range) && rnd()%100 < 2 ) { // 2% chance to cast attack skill. - if( elemental_action(ed,target,tick) ) + if( elemental->action(ed,target,tick) ) return 1; } @@ -733,28 +739,28 @@ static int elemental_ai_sub_timer(struct elemental_data *ed, struct map_session_ return 1; if( battle->check_range(&ed->bl, target, ed->base_status.rhw.range) ) {//Target within range, engage - unit_attack(&ed->bl,target->id,1); + unit->attack(&ed->bl,target->id,1); return 1; } //Follow up if possible. - if( !unit_walktobl(&ed->bl, target, ed->base_status.rhw.range, 2) ) - elemental_unlocktarget(ed); + if( !unit->walktobl(&ed->bl, target, ed->base_status.rhw.range, 2) ) + elemental->unlocktarget(ed); } return 0; } -static int elemental_ai_sub_foreachclient(struct map_session_data *sd, va_list ap) { - unsigned int tick = va_arg(ap,unsigned int); +int elemental_ai_sub_foreachclient(struct map_session_data *sd, va_list ap) { + int64 tick = va_arg(ap,int64); if(sd->status.ele_id && sd->ed) - elemental_ai_sub_timer(sd->ed,sd,tick); + elemental->ai_sub_timer(sd->ed,sd,tick); return 0; } -static int elemental_ai_timer(int tid, unsigned int tick, int id, intptr_t data) { - iMap->map_foreachpc(elemental_ai_sub_foreachclient,tick); +int elemental_ai_timer(int tid, int64 tick, int id, intptr_t data) { + map->foreachpc(elemental->ai_sub_foreachclient,tick); return 0; } @@ -764,10 +770,12 @@ int read_elementaldb(void) { char *str[26]; int i, j = 0, k = 0, ele; struct s_elemental_db *db; - struct status_data *status; + struct status_data *estatus; - sprintf(line, "%s/%s", iMap->db_path, "elemental_db.txt"); - memset(elemental_db,0,sizeof(elemental_db)); + sprintf(line, "%s/%s", map->db_path, "elemental_db.txt"); + + if( runflag == MAPSERVER_ST_RUNNING ) //only necessary after we're up + memset(elemental->db,0,sizeof(elemental->db)); fp = fopen(line, "r"); if( !fp ) { @@ -794,50 +802,50 @@ int read_elementaldb(void) { continue; } - db = &elemental_db[j]; + db = &elemental->db[j]; db->class_ = atoi(str[0]); safestrncpy(db->sprite, str[1], NAME_LENGTH); safestrncpy(db->name, str[2], NAME_LENGTH); db->lv = atoi(str[3]); - status = &db->status; + estatus = &db->status; db->vd.class_ = db->class_; - status->max_hp = atoi(str[4]); - status->max_sp = atoi(str[5]); - status->rhw.range = atoi(str[6]); - status->rhw.atk = atoi(str[7]); - status->rhw.atk2 = atoi(str[8]); - status->def = atoi(str[9]); - status->mdef = atoi(str[10]); - status->str = atoi(str[11]); - status->agi = atoi(str[12]); - status->vit = atoi(str[13]); - status->int_ = atoi(str[14]); - status->dex = atoi(str[15]); - status->luk = atoi(str[16]); + estatus->max_hp = atoi(str[4]); + estatus->max_sp = atoi(str[5]); + estatus->rhw.range = atoi(str[6]); + estatus->rhw.atk = atoi(str[7]); + estatus->rhw.atk2 = atoi(str[8]); + estatus->def = atoi(str[9]); + estatus->mdef = atoi(str[10]); + estatus->str = atoi(str[11]); + estatus->agi = atoi(str[12]); + estatus->vit = atoi(str[13]); + estatus->int_ = atoi(str[14]); + estatus->dex = atoi(str[15]); + estatus->luk = atoi(str[16]); db->range2 = atoi(str[17]); db->range3 = atoi(str[18]); - status->size = atoi(str[19]); - status->race = atoi(str[20]); + estatus->size = atoi(str[19]); + estatus->race = atoi(str[20]); ele = atoi(str[21]); - status->def_ele = ele%10; - status->ele_lv = ele/20; - if( status->def_ele >= ELE_MAX ) { - ShowWarning("Elemental %d has invalid element type %d (max element is %d)\n", db->class_, status->def_ele, ELE_MAX - 1); - status->def_ele = ELE_NEUTRAL; + estatus->def_ele = ele%10; + estatus->ele_lv = ele/20; + if( estatus->def_ele >= ELE_MAX ) { + ShowWarning("Elemental %d has invalid element type %d (max element is %d)\n", db->class_, estatus->def_ele, ELE_MAX - 1); + estatus->def_ele = ELE_NEUTRAL; } - if( status->ele_lv < 1 || status->ele_lv > 4 ) { - ShowWarning("Elemental %d has invalid element level %d (max is 4)\n", db->class_, status->ele_lv); - status->ele_lv = 1; + if( estatus->ele_lv < 1 || estatus->ele_lv > 4 ) { + ShowWarning("Elemental %d has invalid element level %d (max is 4)\n", db->class_, estatus->ele_lv); + estatus->ele_lv = 1; } - status->aspd_rate = 1000; - status->speed = atoi(str[22]); - status->adelay = atoi(str[23]); - status->amotion = atoi(str[24]); - status->dmotion = atoi(str[25]); + estatus->aspd_rate = 1000; + estatus->speed = atoi(str[22]); + estatus->adelay = atoi(str[23]); + estatus->amotion = atoi(str[24]); + estatus->dmotion = atoi(str[25]); j++; } @@ -857,7 +865,7 @@ int read_elemental_skilldb(void) { uint16 skill_id, skill_lv; int skillmode; - sprintf(line, "%s/%s", iMap->db_path, "elemental_skill_db.txt"); + sprintf(line, "%s/%s", map->db_path, "elemental_skill_db.txt"); fp = fopen(line, "r"); if( !fp ) { ShowError("read_elemental_skilldb : can't read elemental_skill_db.txt\n"); @@ -884,7 +892,7 @@ int read_elemental_skilldb(void) { } class_ = atoi(str[0]); - ARR_FIND(0, MAX_ELEMENTAL_CLASS, i, class_ == elemental_db[i].class_); + ARR_FIND(0, MAX_ELEMENTAL_CLASS, i, class_ == elemental->db[i].class_); if( i == MAX_ELEMENTAL_CLASS ) { ShowError("read_elemental_skilldb : Class not found in elemental_db for skill entry, line %d.\n", k); continue; @@ -896,7 +904,7 @@ int read_elemental_skilldb(void) { continue; } - db = &elemental_db[i]; + db = &elemental->db[i]; skill_lv = atoi(str[2]); skillmode = atoi(str[3]); @@ -921,20 +929,23 @@ int read_elemental_skilldb(void) { } void reload_elementaldb(void) { - read_elementaldb(); - reload_elemental_skilldb(); + elemental->read_db(); + elemental->reload_skilldb(); } void reload_elemental_skilldb(void) { - read_elemental_skilldb(); + elemental->read_skilldb(); } -int do_init_elemental(void) { - read_elementaldb(); - read_elemental_skilldb(); +int do_init_elemental(bool minimal) { + if (minimal) + return 0; - iTimer->add_timer_func_list(elemental_ai_timer,"elemental_ai_timer"); - iTimer->add_timer_interval(iTimer->gettick()+MIN_ELETHINKTIME,elemental_ai_timer,0,0,MIN_ELETHINKTIME); + elemental->read_db(); + elemental->read_skilldb(); + + timer->add_func_list(elemental->ai_timer,"elemental_ai_timer"); + timer->add_interval(timer->gettick()+MIN_ELETHINKTIME,elemental->ai_timer,0,0,MIN_ELETHINKTIME); return 0; } @@ -942,3 +953,60 @@ int do_init_elemental(void) { void do_final_elemental(void) { return; } + +/*===================================== +* Default Functions : elemental.h +* Generated by HerculesInterfaceMaker +* created by Susu +*-------------------------------------*/ +void elemental_defaults(void) { + elemental = &elemental_s; + + /* */ + elemental->init = do_init_elemental; + elemental->final = do_final_elemental; + + /* */ + memset(elemental->db,0,sizeof(elemental->db)); + + /* funcs */ + + elemental->class = elemental_class; + elemental->get_viewdata = elemental_get_viewdata; + + elemental->create = elemental_create; + elemental->data_received = elemental_data_received; + elemental->save = elemental_save; + + elemental->change_mode_ack = elemental_change_mode_ack; + elemental->change_mode = elemental_change_mode; + + elemental->heal = elemental_heal; + elemental->dead = elemental_dead; + + elemental->delete = elemental_delete; + elemental->summon_stop = elemental_summon_stop; + + elemental->get_lifetime = elemental_get_lifetime; + + elemental->unlocktarget = elemental_unlocktarget; + elemental->skillnotok = elemental_skillnotok; + elemental->set_target = elemental_set_target; + elemental->clean_single_effect = elemental_clean_single_effect; + elemental->clean_effect = elemental_clean_effect; + elemental->action = elemental_action; + elemental->skill_get_requirements = elemental_skill_get_requirements; + + elemental->read_skilldb = read_elemental_skilldb; + elemental->reload_db = reload_elementaldb; + elemental->reload_skilldb = reload_elemental_skilldb; + + elemental->search_index = elemental_search_index; + elemental->summon_init = elemental_summon_init; + elemental->summon_end_timer = elemental_summon_end_timer; + elemental->ai_sub_timer_activesearch = elemental_ai_sub_timer_activesearch; + elemental->ai_sub_timer = elemental_ai_sub_timer; + elemental->ai_sub_foreachclient = elemental_ai_sub_foreachclient; + elemental->ai_timer = elemental_ai_timer; + elemental->read_db = read_elementaldb; +} diff --git a/src/map/elemental.h b/src/map/elemental.h index f941f3dfd..0c8fff8b3 100644 --- a/src/map/elemental.h +++ b/src/map/elemental.h @@ -1,24 +1,33 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder +// Copyright (c) Hercules Dev Team, licensed under GNU GPL. +// See the LICENSE file +// Portions Copyright (c) Athena Dev Teams -#ifndef _ELEMENTAL_H_ -#define _ELEMENTAL_H_ +#ifndef MAP_ELEMENTAL_H +#define MAP_ELEMENTAL_H #include "status.h" // struct status_data, struct status_change #include "unit.h" // struct unit_data +#include "../common/mmo.h" // NAME_LENGTH +/** + * Defines + **/ #define MIN_ELETHINKTIME 100 #define MIN_ELEDISTANCE 2 #define MAX_ELEDISTANCE 5 - #define EL_MODE_AGGRESSIVE (MD_CANMOVE|MD_AGGRESSIVE|MD_CANATTACK) #define EL_MODE_ASSIST (MD_CANMOVE|MD_ASSIST) #define EL_MODE_PASSIVE MD_CANMOVE - #define EL_SKILLMODE_PASIVE 0x1 #define EL_SKILLMODE_ASSIST 0x2 #define EL_SKILLMODE_AGGRESSIVE 0x4 +#define elemental_stop_walking(ed, type) (unit->stop_walking(&(ed)->bl, (type))) +#define elemental_stop_attack(ed) (unit->stop_attack(&(ed)->bl)) + +/** + * Structures + **/ struct elemental_skill { unsigned short id, lv; short mode; @@ -34,8 +43,6 @@ struct s_elemental_db { struct elemental_skill skill[MAX_ELESKILLTREE]; }; -extern struct s_elemental_db elemental_db[MAX_ELEMENTAL_CLASS]; - struct elemental_data { struct block_list bl; struct unit_data ud; @@ -51,44 +58,67 @@ struct elemental_data { int summon_timer; int skill_timer; - unsigned last_thinktime, last_linktime, last_spdrain_time; + int64 last_thinktime, last_linktime, last_spdrain_time; short min_chase; int target_id, attacked_id; }; -bool elemental_class(int class_); -struct view_data * elemental_get_viewdata(int class_); - -int elemental_create(struct map_session_data *sd, int class_, unsigned int lifetime); -int elemental_data_received(struct s_elemental *ele, bool flag); -int elemental_save(struct elemental_data *ed); - -int elemental_change_mode_ack(struct elemental_data *ed, int mode); -int elemental_change_mode(struct elemental_data *ed, int mode); - -void elemental_heal(struct elemental_data *ed, int hp, int sp); -int elemental_dead(struct elemental_data *ed); - -int elemental_delete(struct elemental_data *ed, int reply); -void elemental_summon_stop(struct elemental_data *ed); - -int elemental_get_lifetime(struct elemental_data *ed); - -int elemental_unlocktarget(struct elemental_data *ed); -int elemental_skillnotok(uint16 skill_id, struct elemental_data *ed); -int elemental_set_target( struct map_session_data *sd, struct block_list *bl ); -int elemental_clean_single_effect(struct elemental_data *ed, uint16 skill_id); -int elemental_clean_effect(struct elemental_data *ed); -int elemental_action(struct elemental_data *ed, struct block_list *bl, unsigned int tick); -struct skill_condition elemental_skill_get_requirements(uint16 skill_id, uint16 skill_lv); +/*===================================== +* Interface : elemental.h +* Generated by HerculesInterfaceMaker +* created by Susu +*-------------------------------------*/ +struct elemental_interface { + + /* vars */ + struct s_elemental_db db[MAX_ELEMENTAL_CLASS]; // Elemental Database + + /* */ + int (*init) (bool minimal); + void (*final) (void); + /* funcs */ + bool (*class) (int class_); + struct view_data * (*get_viewdata) (int class_); + + int (*create) (struct map_session_data *sd, int class_, unsigned int lifetime); + int (*data_received) (struct s_elemental *ele, bool flag); + int (*save) (struct elemental_data *ed); + + int (*change_mode_ack) (struct elemental_data *ed, int mode); + int (*change_mode) (struct elemental_data *ed, int mode); + + void (*heal) (struct elemental_data *ed, int hp, int sp); + int (*dead) (struct elemental_data *ed); + + int (*delete) (struct elemental_data *ed, int reply); + void (*summon_stop) (struct elemental_data *ed); + + int (*get_lifetime) (struct elemental_data *ed); + + int (*unlocktarget) (struct elemental_data *ed); + int (*skillnotok) (uint16 skill_id, struct elemental_data *ed); + int (*set_target) (struct map_session_data *sd, struct block_list *bl); + int (*clean_single_effect) (struct elemental_data *ed, uint16 skill_id); + int (*clean_effect) (struct elemental_data *ed); + int (*action) (struct elemental_data *ed, struct block_list *bl, int64 tick); + struct skill_condition (*skill_get_requirements) (uint16 skill_id, uint16 skill_lv); + + int (*read_skilldb) (void); + void (*reload_db) (void); + void (*reload_skilldb) (void); + + int (*search_index) (int class_); + void (*summon_init) (struct elemental_data *ed); + int (*summon_end_timer) (int tid, int64 tick, int id, intptr_t data); + int (*ai_sub_timer_activesearch) (struct block_list *bl, va_list ap); + int (*ai_sub_timer) (struct elemental_data *ed, struct map_session_data *sd, int64 tick); + int (*ai_sub_foreachclient) (struct map_session_data *sd, va_list ap); + int (*ai_timer) (int tid, int64 tick, int id, intptr_t data); + int (*read_db) (void); +}; -#define elemental_stop_walking(ed, type) unit_stop_walking(&(ed)->bl, type) -#define elemental_stop_attack(ed) unit_stop_attack(&(ed)->bl) +struct elemental_interface *elemental; -int read_elemental_skilldb(void); -void reload_elementaldb(void); -void reload_elemental_skilldb(void); -int do_init_elemental(void); -void do_final_elemental(void); +void elemental_defaults(void); -#endif /* _ELEMENTAL_H_ */ +#endif /* MAP_ELEMENTAL_H */ diff --git a/src/map/guild.c b/src/map/guild.c index b28c14db7..ac24edeab 100644 --- a/src/map/guild.c +++ b/src/map/guild.c @@ -2,103 +2,66 @@ // See the LICENSE file // Portions Copyright (c) Athena Dev Teams -#include "../common/cbasetypes.h" -#include "../common/timer.h" -#include "../common/nullpo.h" -#include "../common/malloc.h" -#include "../common/mapindex.h" -#include "../common/showmsg.h" -#include "../common/ers.h" -#include "../common/strlib.h" -#include "../common/utils.h" +#define HERCULES_CORE -#include "map.h" +#include "../config/core.h" // GP_BOUND_ITEMS #include "guild.h" -#include "storage.h" -#include "battle.h" -#include "npc.h" -#include "pc.h" -#include "status.h" -#include "mob.h" -#include "intif.h" -#include "clif.h" -#include "skill.h" -#include "log.h" -#include "instance.h" #include <stdio.h> #include <stdlib.h> #include <string.h> +#include "battle.h" +#include "clif.h" +#include "instance.h" +#include "intif.h" +#include "log.h" +#include "map.h" +#include "mob.h" +#include "npc.h" +#include "pc.h" +#include "skill.h" +#include "status.h" +#include "storage.h" +#include "../common/HPM.h" +#include "../common/cbasetypes.h" +#include "../common/ers.h" +#include "../common/malloc.h" +#include "../common/mapindex.h" +#include "../common/nullpo.h" +#include "../common/showmsg.h" +#include "../common/strlib.h" +#include "../common/timer.h" +#include "../common/utils.h" -static DBMap* guild_db; // int guild_id -> struct guild* -static DBMap* castle_db; // int castle_id -> struct guild_castle* -static DBMap* guild_expcache_db; // int char_id -> struct guild_expcache* -static DBMap* guild_infoevent_db; // int guild_id -> struct eventlist* - -struct eventlist { - char name[EVENT_NAME_LENGTH]; - struct eventlist *next; -}; - -//Constant related to the flash of the Guild EXP cache -#define GUILD_SEND_XY_INVERVAL 5000 // Interval of sending coordinates and HP -#define GUILD_PAYEXP_INVERVAL 10000 //Interval (maximum survival time of the cache, in milliseconds) -#define GUILD_PAYEXP_LIST 8192 //The maximum number of cache - -//Guild EXP cache - -struct guild_expcache { - int guild_id, account_id, char_id; - uint64 exp; -}; -static struct eri *expcache_ers; //For handling of guild exp payment. - -#define MAX_GUILD_SKILL_REQUIRE 5 -struct{ - int id; - int max; - struct{ - short id; - short lv; - }need[MAX_GUILD_SKILL_REQUIRE]; -} guild_skill_tree[MAX_GUILDSKILL]; - -int guild_payexp_timer(int tid, unsigned int tick, int id, intptr_t data); -static int guild_send_xy_timer(int tid, unsigned int tick, int id, intptr_t data); - -/* guild flags cache */ -struct npc_data **guild_flags; -unsigned short guild_flags_count; +struct guild_interface guild_s; /*========================================== * Retrieves and validates the sd pointer for this guild member [Skotlex] *------------------------------------------*/ -static TBL_PC* guild_sd_check(int guild_id, int account_id, int char_id) -{ - TBL_PC* sd = iMap->id2sd(account_id); +TBL_PC* guild_sd_check(int guild_id, int account_id, int char_id) { + TBL_PC* sd = map->id2sd(account_id); if (!(sd && sd->status.char_id == char_id)) return NULL; - if (sd->status.guild_id != guild_id) - { //If player belongs to a different guild, kick him out. - intif_guild_leave(guild_id,account_id,char_id,0,"** Guild Mismatch **"); + if (sd->status.guild_id != guild_id) { + //If player belongs to a different guild, kick him out. + intif->guild_leave(guild_id,account_id,char_id,0,"** Guild Mismatch **"); return NULL; } return sd; } - // Modified [Komurka] +// Modified [Komurka] int guild_skill_get_max (int id) { if (id < GD_SKILLBASE || id >= GD_SKILLBASE+MAX_GUILDSKILL) return 0; - return guild_skill_tree[id-GD_SKILLBASE].max; + return guild->skill_tree[id-GD_SKILLBASE].max; } -// Retrive skill_lv learned by guild - +// Retrieve skill_lv learned by guild int guild_checkskill(struct guild *g, int id) { int idx = id - GD_SKILLBASE; if (idx < 0 || idx >= MAX_GUILDSKILL) @@ -109,7 +72,7 @@ int guild_checkskill(struct guild *g, int id) { /*========================================== * guild_skill_tree.txt reading - from jA [Komurka] *------------------------------------------*/ -static bool guild_read_guildskill_tree_db(char* split[], int columns, int current) +bool guild_read_guildskill_tree_db(char* split[], int columns, int current) {// <skill id>,<max lv>,<req id1>,<req lv1>,<req id2>,<req lv2>,<req id3>,<req lv3>,<req id4>,<req lv4>,<req id5>,<req lv5> int k, id, skill_id; @@ -122,18 +85,18 @@ static bool guild_read_guildskill_tree_db(char* split[], int columns, int curren return false; } - guild_skill_tree[id].id = skill_id; - guild_skill_tree[id].max = atoi(split[1]); + guild->skill_tree[id].id = skill_id; + guild->skill_tree[id].max = atoi(split[1]); - if( guild_skill_tree[id].id == GD_GLORYGUILD && battle_config.require_glory_guild && guild_skill_tree[id].max == 0 ) + if( guild->skill_tree[id].id == GD_GLORYGUILD && battle_config.require_glory_guild && guild->skill_tree[id].max == 0 ) {// enable guild's glory when required for emblems - guild_skill_tree[id].max = 1; + guild->skill_tree[id].max = 1; } for( k = 0; k < MAX_GUILD_SKILL_REQUIRE; k++ ) { - guild_skill_tree[id].need[k].id = atoi(split[k*2+2]); - guild_skill_tree[id].need[k].lv = atoi(split[k*2+3]); + guild->skill_tree[id].need[k].id = atoi(split[k*2+2]); + guild->skill_tree[id].need[k].lv = atoi(split[k*2+3]); } return true; @@ -155,30 +118,30 @@ int guild_check_skill_require(struct guild *g,int id) for(i=0;i<MAX_GUILD_SKILL_REQUIRE;i++) { - if(guild_skill_tree[idx].need[i].id == 0) break; - if(guild_skill_tree[idx].need[i].lv > guild->checkskill(g,guild_skill_tree[idx].need[i].id)) + if(guild->skill_tree[idx].need[i].id == 0) break; + if(guild->skill_tree[idx].need[i].lv > guild->checkskill(g,guild->skill_tree[idx].need[i].id)) return 0; } return 1; } -static bool guild_read_castledb(char* str[], int columns, int current) +bool guild_read_castledb(char* str[], int columns, int current) {// <castle id>,<map name>,<castle name>,<castle event>[,<reserved/unused switch flag>] struct guild_castle *gc; - int mapindex = mapindex_name2id(str[1]); + int index = mapindex->name2id(str[1]); - if (iMap->mapindex2mapid(mapindex) < 0) // Map not found or on another map-server + if (map->mapindex2mapid(index) < 0) // Map not found or on another map-server return false; CREATE(gc, struct guild_castle, 1); gc->castle_id = atoi(str[0]); - gc->mapindex = mapindex; + gc->mapindex = index; safestrncpy(gc->castle_name, str[2], sizeof(gc->castle_name)); safestrncpy(gc->castle_event, str[3], sizeof(gc->castle_event)); - idb_put(castle_db,gc->castle_id,gc); + idb_put(guild->castle_db,gc->castle_id,gc); - //intif_guild_castle_info(gc->castle_id); + //intif->guild_castle_info(gc->castle_id); return true; } @@ -186,14 +149,14 @@ static bool guild_read_castledb(char* str[], int columns, int current) /// lookup: guild id -> guild* struct guild* guild_search(int guild_id) { - return (struct guild*)idb_get(guild_db,guild_id); + return (struct guild*)idb_get(guild->db,guild_id); } /// lookup: guild name -> guild* struct guild* guild_searchname(char* str) { struct guild* g; - DBIterator *iter = db_iterator(guild_db); + DBIterator *iter = db_iterator(guild->db); for( g = dbi_first(iter); dbi_exists(iter); g = dbi_next(iter) ) { @@ -208,18 +171,18 @@ struct guild* guild_searchname(char* str) /// lookup: castle id -> castle* struct guild_castle* guild_castle_search(int gcid) { - return (struct guild_castle*)idb_get(castle_db,gcid); + return (struct guild_castle*)idb_get(guild->castle_db,gcid); } /// lookup: map index -> castle* -struct guild_castle* guild_mapindex2gc(short mapindex) +struct guild_castle* guild_mapindex2gc(short map_index) { struct guild_castle* gc; - DBIterator *iter = db_iterator(castle_db); + DBIterator *iter = db_iterator(guild->castle_db); for( gc = dbi_first(iter); dbi_exists(iter); gc = dbi_next(iter) ) { - if( gc->mapindex == mapindex ) + if( gc->mapindex == map_index ) break; } dbi_destroy(iter); @@ -230,7 +193,7 @@ struct guild_castle* guild_mapindex2gc(short mapindex) /// lookup: map name -> castle* struct guild_castle* guild_mapname2gc(const char* mapname) { - return guild->mapindex2gc(mapindex_name2id(mapname)); + return guild->mapindex2gc(mapindex->name2id(mapname)); } struct map_session_data* guild_getavailablesd(struct guild* g) @@ -303,7 +266,7 @@ int guild_payexp_timer_sub(DBKey key, DBData *data, va_list ap) { (g = guild->search(c->guild_id)) == NULL || (i = guild->getindex(g, c->account_id, c->char_id)) < 0 ) { - ers_free(expcache_ers, c); + ers_free(guild->expcache_ers, c); return 0; } @@ -312,17 +275,16 @@ int guild_payexp_timer_sub(DBKey key, DBData *data, va_list ap) { else g->member[i].exp+= c->exp; - intif_guild_change_memberinfo(g->guild_id,c->account_id,c->char_id, + intif->guild_change_memberinfo(g->guild_id,c->account_id,c->char_id, GMI_EXP,&g->member[i].exp,sizeof(g->member[i].exp)); c->exp=0; - ers_free(expcache_ers, c); + ers_free(guild->expcache_ers, c); return 0; } -int guild_payexp_timer(int tid, unsigned int tick, int id, intptr_t data) -{ - guild_expcache_db->clear(guild_expcache_db,guild_payexp_timer_sub); +int guild_payexp_timer(int tid, int64 tick, int id, intptr_t data) { + guild->expcache_db->clear(guild->expcache_db,guild->payexp_timer_sub); return 0; } @@ -355,9 +317,8 @@ int guild_send_xy_timer_sub(DBKey key, DBData *data, va_list ap) } //Code from party_send_xy_timer [Skotlex] -static int guild_send_xy_timer(int tid, unsigned int tick, int id, intptr_t data) -{ - guild_db->foreach(guild_db,guild_send_xy_timer_sub,tick); +int guild_send_xy_timer(int tid, int64 tick, int id, intptr_t data) { + guild->db->foreach(guild->db,guild->send_xy_timer_sub,tick); return 0; } @@ -386,21 +347,21 @@ int guild_create(struct map_session_data *sd, const char *name) clif->guild_created(sd,1); return 0; } - if( battle_config.guild_emperium_check && pc->search_inventory(sd,714) == -1 ) - {// item required + if (battle_config.guild_emperium_check && pc->search_inventory(sd, ITEMID_EMPERIUM) == INDEX_NOT_FOUND) { + // item required clif->guild_created(sd,3); return 0; } - guild_makemember(&m,sd); + guild->makemember(&m,sd); m.position=0; - intif_guild_create(name,&m); + intif->guild_create(name,&m); return 1; } //Whether or not to create guild int guild_created(int account_id,int guild_id) { - struct map_session_data *sd=iMap->id2sd(account_id); + struct map_session_data *sd=map->id2sd(account_id); if(sd==NULL) return 0; @@ -419,7 +380,7 @@ int guild_created(int account_id,int guild_id) { //Information request int guild_request_info(int guild_id) { - return intif_guild_request_info(guild_id); + return intif->guild_request_info(guild_id); } //Information request with event @@ -428,7 +389,7 @@ int guild_npc_request_info(int guild_id,const char *event) if( guild->search(guild_id) ) { if( event && *event ) - npc_event_do(event); + npc->event_do(event); return 0; } @@ -440,7 +401,7 @@ int guild_npc_request_info(int guild_id,const char *event) ev=(struct eventlist *)aCalloc(sizeof(struct eventlist),1); memcpy(ev->name,event,strlen(event)); //The one in the db (if present) becomes the next event from this. - if (guild_infoevent_db->put(guild_infoevent_db, DB->i2key(guild_id), DB->ptr2data(ev), &prev)) + if (guild->infoevent_db->put(guild->infoevent_db, DB->i2key(guild_id), DB->ptr2data(ev), &prev)) ev->next = DB->data2ptr(&prev); } @@ -497,16 +458,16 @@ int guild_recv_info(struct guild *sg) { DBData data; struct map_session_data *sd; bool guild_new = false; - void *aChSysSave = NULL; + struct hChSysCh *aChSysSave = NULL; nullpo_ret(sg); - if((g = (struct guild*)idb_get(guild_db,sg->guild_id))==NULL) { + if((g = (struct guild*)idb_get(guild->db,sg->guild_id))==NULL) { guild_new = true; g=(struct guild *)aCalloc(1,sizeof(struct guild)); g->instance = NULL; g->instances = 0; - idb_put(guild_db,sg->guild_id,g); + idb_put(guild->db,sg->guild_id,g); if( hChSys.ally ) { struct hChSysCh *channel; @@ -526,21 +487,27 @@ int guild_recv_info(struct guild *sg) { } for( sd = (TBL_PC*)mapit->first(iter); mapit->exists(iter); sd = (TBL_PC*)mapit->next(iter) ) { - if( sd->status.guild_id ) { - if( sd->status.guild_id == sg->guild_id ) { - clif->chsys_join(channel,sd); - sd->guild = g; - } - + if (!sd->status.guild_id) + continue; // Not interested in guildless users + + if (sd->status.guild_id == sg->guild_id) { + // Guild member + clif->chsys_join(channel,sd); + sd->guild = g; + for (i = 0; i < MAX_GUILDALLIANCE; i++) { - if( sg->alliance[i].opposition == 0 && sg->alliance[i].guild_id ) { - if( sg->alliance[i].guild_id == sd->status.guild_id ) { - clif->chsys_join(channel,sd); - } else if( tg[i] != NULL ) { - if( !(((struct hChSysCh*)tg[i]->channel)->banned && idb_exists(((struct hChSysCh*)tg[i]->channel)->banned, sd->status.account_id))) - clif->chsys_join((struct hChSysCh*)tg[i]->channel,sd); - } - } + // Join channels from allied guilds + if (tg[i] && !(tg[i]->channel->banned && idb_exists(tg[i]->channel->banned, sd->status.account_id))) + clif->chsys_join(tg[i]->channel, sd); + } + continue; + } + + for (i = 0; i < MAX_GUILDALLIANCE; i++) { + if (tg[i] && sd->status.guild_id == tg[i]->guild_id) { // Shortcut to skip the alliance checks again + // Alliance member + if( !(channel->banned && idb_exists(channel->banned, sd->status.account_id))) + clif->chsys_join(channel, sd); } } } @@ -549,13 +516,13 @@ int guild_recv_info(struct guild *sg) { } - aChSysSave = (void*)channel; + aChSysSave = channel; } before=*sg; - //Perform the check on the user because the first load - guild_check_member(sg); - if ((sd = iMap->nick2sd(sg->master)) != NULL) { + //Perform the check on the user because the first load + guild->check_member(sg); + if ((sd = map->nick2sd(sg->master)) != NULL) { //If the guild master is online the first time the guild_info is received, //that means he was the first to join, so apply guild skill blocking here. if( battle_config.guild_skill_relog_delay ) @@ -563,7 +530,7 @@ int guild_recv_info(struct guild *sg) { //Also set the guild master flag. sd->guild = g; - sd->state.gmaster_flag = g; + sd->state.gmaster_flag = 1; clif->charnameupdate(sd); // [LuzZza] clif->guild_masterormember(sd); } @@ -583,7 +550,7 @@ int guild_recv_info(struct guild *sg) { for(i=bm=m=0;i<g->max_member;i++){ if(g->member[i].account_id>0){ - sd = g->member[i].sd = guild_sd_check(g->guild_id, g->member[i].account_id, g->member[i].char_id); + sd = g->member[i].sd = guild->sd_check(g->guild_id, g->member[i].account_id, g->member[i].char_id); if (sd) clif->charnameupdate(sd); // [LuzZza] m++; }else @@ -610,18 +577,18 @@ int guild_recv_info(struct guild *sg) { if (before.skill_point != g->skill_point) clif->guild_skillinfo(sd); //Submit information skills - if (guild_new) { // Send information and affiliation if unsent + if (guild_new) { // Send information and affiliation if unsent clif->guild_belonginfo(sd, g); - clif->guild_notice(sd, g); + //clif->guild_notice(sd, g); Is already sent in clif_parse_LoadEndAck sd->guild_emblem_id = g->emblem_id; } } //Occurrence of an event - if (guild_infoevent_db->remove(guild_infoevent_db, DB->i2key(sg->guild_id), &data)) { + if (guild->infoevent_db->remove(guild->infoevent_db, DB->i2key(sg->guild_id), &data)) { struct eventlist *ev = DB->data2ptr(&data), *ev2; while(ev) { - npc_event_do(ev->name); + npc->event_do(ev->name); ev2=ev->next; aFree(ev); ev=ev2; @@ -660,15 +627,19 @@ int guild_invite(struct map_session_data *sd, struct map_session_data *tsd) { return 0; } - if(tsd->status.guild_id>0 || - tsd->guild_invite>0 || - ((iMap->agit_flag || iMap->agit2_flag) && map[tsd->bl.m].flag.gvg_castle)) - { //Can't invite people inside castles. [Skotlex] + if( tsd->status.guild_id > 0 + || tsd->guild_invite > 0 + || ( (map->agit_flag || map->agit2_flag) + && map->list[tsd->bl.m].flag.gvg_castle + && !battle_config.guild_castle_invite + ) + ) { + //Can't invite people inside castles. [Skotlex] clif->guild_inviteack(sd,0); return 0; } - //search an empty spot in guild + //search an empty spot in guild ARR_FIND( 0, g->max_member, i, g->member[i].account_id == 0 ); if(i==g->max_member){ clif->guild_inviteack(sd,3); @@ -684,8 +655,7 @@ int guild_invite(struct map_session_data *sd, struct map_session_data *tsd) { /// Guild invitation reply. /// flag: 0:rejected, 1:accepted -int guild_reply_invite(struct map_session_data* sd, int guild_id, int flag) -{ +int guild_reply_invite(struct map_session_data* sd, int guild_id, int flag) { struct map_session_data* tsd; nullpo_ret(sd); @@ -696,10 +666,10 @@ int guild_reply_invite(struct map_session_data* sd, int guild_id, int flag) // look up the person who sent the invite //NOTE: this can be NULL because the person might have logged off in the meantime - tsd = iMap->id2sd(sd->guild_invite_account); + tsd = map->id2sd(sd->guild_invite_account); - if ( sd->status.guild_id > 0 ) // [Paradox924X] - { // Already in another guild. + if ( sd->status.guild_id > 0 ) { + // Already in another guild. [Paradox924X] if ( tsd ) clif->guild_inviteack(tsd,0); return 0; } @@ -731,8 +701,8 @@ int guild_reply_invite(struct map_session_data* sd, int guild_id, int flag) return 0; } - guild_makemember(&m,sd); - intif_guild_addmember(guild_id, &m); + guild->makemember(&m,sd); + intif->guild_addmember(guild_id, &m); //TODO: send a minimap update to this player } @@ -753,7 +723,7 @@ void guild_member_joined(struct map_session_data *sd) return; } if (strcmp(sd->status.name,g->master) == 0) { // set the Guild Master flag - sd->state.gmaster_flag = g; + sd->state.gmaster_flag = 1; // prevent Guild Skills from being used directly after relog if( battle_config.guild_skill_relog_delay ) guild->block_skill(sd, 300000); @@ -768,14 +738,14 @@ void guild_member_joined(struct map_session_data *sd) if( hChSys.ally && hChSys.ally_autojoin ) { struct guild* sg = NULL; - struct hChSysCh *channel = (struct hChSysCh*)g->channel; + struct hChSysCh *channel = g->channel; if( !(channel->banned && idb_exists(channel->banned, sd->status.account_id) ) ) clif->chsys_join(channel,sd); for (i = 0; i < MAX_GUILDALLIANCE; i++) { if( g->alliance[i].opposition == 0 && g->alliance[i].guild_id && (sg = guild->search(g->alliance[i].guild_id) ) ) { - if( !(((struct hChSysCh*)sg->channel)->banned && idb_exists(((struct hChSysCh*)sg->channel)->banned, sd->status.account_id))) - clif->chsys_join((struct hChSysCh*)sg->channel,sd); + if( !(sg->channel->banned && idb_exists(sg->channel->banned, sd->status.account_id))) + clif->chsys_join(sg->channel,sd); } } } @@ -786,33 +756,32 @@ void guild_member_joined(struct map_session_data *sd) /*========================================== * Add a player to a given guild_id *----------------------------------------*/ -int guild_member_added(int guild_id,int account_id,int char_id,int flag) -{ - struct map_session_data *sd= iMap->id2sd(account_id),*sd2; +int guild_member_added(int guild_id,int account_id,int char_id,int flag) { + struct map_session_data *sd = map->id2sd(account_id),*sd2; struct guild *g; if( (g=guild->search(guild_id))==NULL ) return 0; if(sd==NULL || sd->guild_invite==0){ - // cancel if player not present or invalide guild_id invitation + // cancel if player not present or invalid guild_id invitation if (flag == 0) { ShowError("guild: member added error %d is not online\n",account_id); - intif_guild_leave(guild_id,account_id,char_id,0,"** Data Error **"); + intif->guild_leave(guild_id,account_id,char_id,0,"** Data Error **"); } return 0; } - sd2 = iMap->id2sd(sd->guild_invite_account); + sd2 = map->id2sd(sd->guild_invite_account); sd->guild_invite = 0; sd->guild_invite_account = 0; - if (flag == 1) { //failure + if (flag == 1) { //failure if( sd2!=NULL ) clif->guild_inviteack(sd2,3); return 0; } - //if all ok add player to guild + //if all ok add player to guild sd->status.guild_id = g->guild_id; sd->guild_emblem_id = g->emblem_id; sd->guild = g; @@ -845,20 +814,24 @@ int guild_leave(struct map_session_data* sd, int guild_id, int account_id, int c if(g==NULL) return 0; - if(sd->status.account_id!=account_id || - sd->status.char_id!=char_id || sd->status.guild_id!=guild_id || - ((iMap->agit_flag || iMap->agit2_flag) && map[sd->bl.m].flag.gvg_castle)) + if( sd->status.account_id != account_id + || sd->status.char_id != char_id + || sd->status.guild_id != guild_id + // Can't leave inside castles + || ((map->agit_flag || map->agit2_flag) + && map->list[sd->bl.m].flag.gvg_castle + && !battle_config.guild_castle_expulsion) + ) return 0; - intif_guild_leave(sd->status.guild_id, sd->status.account_id, sd->status.char_id,0,mes); + intif->guild_leave(sd->status.guild_id, sd->status.account_id, sd->status.char_id,0,mes); return 0; } /*========================================== * Request remove a player to a given guild_id *----------------------------------------*/ -int guild_expulsion(struct map_session_data* sd, int guild_id, int account_id, int char_id, const char* mes) -{ +int guild_expulsion(struct map_session_data* sd, int guild_id, int account_id, int char_id, const char* mes) { struct map_session_data *tsd; struct guild *g; int i,ps; @@ -876,16 +849,19 @@ int guild_expulsion(struct map_session_data* sd, int guild_id, int account_id, i if( (ps=guild->getposition(g,sd))<0 || !(g->position[ps].mode&0x0010) ) return 0; //Expulsion permission - //Can't leave inside guild castles. - if ((tsd = iMap->id2sd(account_id)) && - tsd->status.char_id == char_id && - ((iMap->agit_flag || iMap->agit2_flag) && map[tsd->bl.m].flag.gvg_castle)) + //Can't leave inside guild castles. + if ((tsd = map->id2sd(account_id)) + && tsd->status.char_id == char_id + && ((map->agit_flag || map->agit2_flag) + && map->list[sd->bl.m].flag.gvg_castle + && !battle_config.guild_castle_expulsion) + ) return 0; // find the member and perform expulsion i = guild->getindex(g, account_id, char_id); if( i != -1 && strcmp(g->member[i].name,g->master) != 0 ) //Can't expel the GL! - intif_guild_leave(g->guild_id,account_id,char_id,1,mes); + intif->guild_leave(g->guild_id,account_id,char_id,1,mes); return 0; } @@ -894,7 +870,7 @@ int guild_member_withdraw(int guild_id, int account_id, int char_id, int flag, c { int i; struct guild* g = guild->search(guild_id); - struct map_session_data* sd = iMap->charid2sd(char_id); + struct map_session_data* sd = map->charid2sd(char_id); struct map_session_data* online_member_sd; if(g == NULL) @@ -906,7 +882,12 @@ int guild_member_withdraw(int guild_id, int account_id, int char_id, int flag, c online_member_sd = guild->getavailablesd(g); if(online_member_sd == NULL) - return 0; // noone online to inform + return 0; // no one online to inform + +#ifdef GP_BOUND_ITEMS + //Guild bound item check + guild->retrieveitembound(char_id,account_id,guild_id); +#endif if(!flag) clif->guild_leave(online_member_sd, name, mes); @@ -921,7 +902,7 @@ int guild_member_withdraw(int guild_id, int account_id, int char_id, int flag, c if(sd != NULL && sd->status.guild_id == guild_id) { // do stuff that needs the guild_id first, BEFORE we wipe it if (sd->state.storage_flag == 2) //Close the guild storage. - storage_guild_storageclose(sd); + gstorage->close(sd); guild->send_dot_remove(sd); if( hChSys.ally ) { clif->chsys_quitg(sd); @@ -932,11 +913,37 @@ int guild_member_withdraw(int guild_id, int account_id, int char_id, int flag, c if( g->instances ) instance->check_kick(sd); clif->charnameupdate(sd); //Update display name [Skotlex] + status_change_end(&sd->bl, SC_LEADERSHIP, INVALID_TIMER); + status_change_end(&sd->bl, SC_GLORYWOUNDS, INVALID_TIMER); + status_change_end(&sd->bl, SC_SOULCOLD, INVALID_TIMER); + status_change_end(&sd->bl, SC_HAWKEYES, INVALID_TIMER); //TODO: send emblem update to self and people around } return 0; } +void guild_retrieveitembound(int char_id,int aid,int guild_id) { +#ifdef GP_BOUND_ITEMS + TBL_PC *sd = map->charid2sd(char_id); + if(sd){ //Character is online + pc->bound_clear(sd,IBT_GUILD); + } else { //Character is offline, ask char server to do the job + struct guild_storage *gstor = gstorage->id2storage2(guild_id); + if(gstor && gstor->storage_status == 1) { //Someone is in guild storage, close them + struct s_mapiterator* iter = mapit_getallusers(); + for( sd = (TBL_PC*)mapit->first(iter); mapit->exists(iter); sd = (TBL_PC*)mapit->next(iter) ) { + if(sd->status.guild_id == guild_id && sd->state.storage_flag == 2) { + gstorage->close(sd); + break; + } + } + mapit->free(iter); + } + intif->itembound_req(char_id,aid,guild_id); + } +#endif +} + int guild_send_memberinfoshort(struct map_session_data *sd,int online) { // cleaned up [LuzZza] struct guild *g; @@ -949,7 +956,7 @@ int guild_send_memberinfoshort(struct map_session_data *sd,int online) if(!(g = sd->guild)) return 0; - intif_guild_memberinfoshort(g->guild_id, + intif->guild_memberinfoshort(g->guild_id, sd->status.account_id,sd->status.char_id,online,sd->status.base_level,sd->status.class_); if(!online){ @@ -964,7 +971,6 @@ int guild_send_memberinfoshort(struct map_session_data *sd,int online) if(sd->state.connect_new) { //Note that this works because it is invoked in parse_LoadEndAck before connect_new is cleared. clif->guild_belonginfo(sd,g); - clif->guild_notice(sd,g); sd->guild_emblem_id = g->emblem_id; } return 0; @@ -996,13 +1002,13 @@ int guild_recv_memberinfoshort(int guild_id,int account_id,int char_id,int onlin } if(idx == -1 || c == 0) { - //Treat char_id who doesn't match guild_id (not found as member) - struct map_session_data *sd = iMap->id2sd(account_id); + //Treat char_id who doesn't match guild_id (not found as member) + struct map_session_data *sd = map->id2sd(account_id); if(sd && sd->status.char_id == char_id) { sd->status.guild_id=0; sd->guild_emblem_id=0; } - ShowWarning("guild: not found member %d,%d on %d[%s]\n", account_id,char_id,guild_id,g->name); + ShowWarning("guild: not found member %d,%d on %d[%s]\n", account_id,char_id,guild_id,g->name); return 0; } @@ -1010,9 +1016,9 @@ int guild_recv_memberinfoshort(int guild_id,int account_id,int char_id,int onlin g->connect_member=om; //Ensure validity of pointer (ie: player logs in/out, changes map-server) - g->member[idx].sd = guild_sd_check(guild_id, account_id, char_id); + g->member[idx].sd = guild->sd_check(guild_id, account_id, char_id); - if(oldonline!=online) + if(oldonline!=online) clif->guild_memberlogin_notice(g, idx, online); if(!g->member[idx].sd) @@ -1042,7 +1048,7 @@ int guild_send_message(struct map_session_data *sd,const char *mes,int len) if(sd->status.guild_id==0) return 0; - intif_guild_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 @@ -1068,7 +1074,7 @@ int guild_recv_message(int guild_id,int account_id,const char *mes,int len) *---------------------------------------------------*/ int guild_change_memberposition(int guild_id,int account_id,int char_id,short idx) { - return intif_guild_change_memberinfo(guild_id,account_id,char_id,GMI_POSITION,&idx,sizeof(idx)); + return intif->guild_change_memberinfo(guild_id,account_id,char_id,GMI_POSITION,&idx,sizeof(idx)); } /*==================================================== @@ -1090,8 +1096,7 @@ int guild_memberposition_changed(struct guild *g,int idx,int pos) /*==================================================== * Change guild title or member *---------------------------------------------------*/ -int guild_change_position(int guild_id,int idx, - int mode,int exp_mode,const char *name) +int guild_change_position(int guild_id,int idx,int mode,int exp_mode,const char *name) { struct guild_position p; @@ -1101,7 +1106,7 @@ int guild_change_position(int guild_id,int idx, p.mode=mode&0x11; p.exp_mode=exp_mode; safestrncpy(p.name,name,NAME_LENGTH); - return intif_guild_position(guild_id,idx,&p); + return intif->guild_position(guild_id,idx,&p); } /*==================================================== @@ -1132,7 +1137,7 @@ int guild_change_notice(struct map_session_data *sd,int guild_id,const char *mes if(guild_id!=sd->status.guild_id) return 0; - return intif_guild_notice(guild_id,mes1,mes2); + return intif->guild_notice(guild_id,mes1,mes2); } /*==================================================== @@ -1170,7 +1175,7 @@ int guild_change_emblem(struct map_session_data *sd,int len,const char *data) return 0; } - return intif_guild_emblem(sd->status.guild_id,len,data); + return intif->guild_emblem(sd->status.guild_id,len,data); } /*==================================================== @@ -1197,37 +1202,35 @@ int guild_emblem_changed(int len,int guild_id,int emblem_id,const char *data) } } {// update guardians (mobs) - DBIterator* iter = db_iterator(castle_db); + DBIterator* iter = db_iterator(guild->castle_db); struct guild_castle* gc; for( gc = (struct guild_castle*)dbi_first(iter) ; dbi_exists(iter); gc = (struct guild_castle*)dbi_next(iter) ) { if( gc->guild_id != guild_id ) continue; // update permanent guardians - for( i = 0; i < ARRAYLENGTH(gc->guardian); ++i ) - { - TBL_MOB* md = (gc->guardian[i].id ? iMap->id2md(gc->guardian[i].id) : NULL); + for( i = 0; i < ARRAYLENGTH(gc->guardian); ++i ) { + TBL_MOB* md = (gc->guardian[i].id ? map->id2md(gc->guardian[i].id) : NULL); if( md == NULL || md->guardian_data == NULL ) continue; - md->guardian_data->emblem_id = emblem_id; + clif->guild_emblem_area(&md->bl); } // update temporary guardians - for( i = 0; i < gc->temp_guardians_max; ++i ) - { - TBL_MOB* md = (gc->temp_guardians[i] ? iMap->id2md(gc->temp_guardians[i]) : NULL); + for( i = 0; i < gc->temp_guardians_max; ++i ) { + TBL_MOB* md = (gc->temp_guardians[i] ? map->id2md(gc->temp_guardians[i]) : NULL); if( md == NULL || md->guardian_data == NULL ) continue; - md->guardian_data->emblem_id = emblem_id; + clif->guild_emblem_area(&md->bl); } } dbi_destroy(iter); } {// update npcs (flags or other npcs that used flagemblem to attach to this guild) - for( i = 0; i < guild_flags_count; i++ ) { - if( guild_flags[i] && guild_flags[i]->u.scr.guild_id == guild_id ) { - clif->guild_emblem_area(&guild_flags[i]->bl); + for( i = 0; i < guild->flags_count; i++ ) { + if( guild->flags[i] && guild->flags[i]->u.scr.guild_id == guild_id ) { + clif->guild_emblem_area(&guild->flags[i]->bl); } } } @@ -1237,12 +1240,12 @@ int guild_emblem_changed(int len,int guild_id,int emblem_id,const char *data) /** * @see DBCreateData */ -static DBData create_expcache(DBKey key, va_list args) +DBData create_expcache(DBKey key, va_list args) { struct guild_expcache *c; struct map_session_data *sd = va_arg(args, struct map_session_data*); - c = ers_alloc(expcache_ers, struct guild_expcache); + c = ers_alloc(guild->expcache_ers, struct guild_expcache); c->guild_id = sd->status.guild_id; c->account_id = sd->status.account_id; c->char_id = sd->status.char_id; @@ -1273,7 +1276,7 @@ unsigned int guild_payexp(struct map_session_data *sd,unsigned int exp) { exp = exp * per / 100; //Otherwise tax everything. - c = DB->data2ptr(guild_expcache_db->ensure(guild_expcache_db, DB->i2key(sd->status.char_id), create_expcache, sd)); + c = DB->data2ptr(guild->expcache_db->ensure(guild->expcache_db, DB->i2key(sd->status.char_id), guild->create_expcache, sd)); if (c->exp > UINT64_MAX - exp) c->exp = UINT64_MAX; @@ -1296,7 +1299,7 @@ int guild_getexp(struct map_session_data *sd,int exp) if (sd->status.guild_id == 0 || sd->guild == NULL) return 0; - c = DB->data2ptr(guild_expcache_db->ensure(guild_expcache_db, DB->i2key(sd->status.char_id), create_expcache, sd)); + c = DB->data2ptr(guild->expcache_db->ensure(guild->expcache_db, DB->i2key(sd->status.char_id), guild->create_expcache, sd)); if (c->exp > UINT64_MAX - exp) c->exp = UINT64_MAX; else @@ -1323,7 +1326,7 @@ int guild_skillup(TBL_PC* sd, uint16 skill_id) if( g->skill_point > 0 && g->skill[idx].id != 0 && g->skill[idx].lv < max ) - intif_guild_skillup(g->guild_id, skill_id, sd->status.account_id, max); + intif->guild_skillup(g->guild_id, skill_id, sd->status.account_id, max); return 0; } @@ -1331,15 +1334,14 @@ int guild_skillup(TBL_PC* sd, uint16 skill_id) /*==================================================== * Notification of guildskill skill_id increase request *---------------------------------------------------*/ -int guild_skillupack(int guild_id,uint16 skill_id,int account_id) -{ - struct map_session_data *sd=iMap->id2sd(account_id); +int guild_skillupack(int guild_id,uint16 skill_id,int account_id) { + struct map_session_data *sd=map->id2sd(account_id); struct guild *g=guild->search(guild_id); int i; if(g==NULL) return 0; if( sd != NULL ) { - clif->guild_skillup(sd,skill_id,g->skill[skill_id-GD_SKILLBASE].lv); + clif->skillup(sd,skill_id,g->skill[skill_id-GD_SKILLBASE].lv, 0); /* Guild Aura handling */ switch( skill_id ) { @@ -1347,7 +1349,7 @@ int guild_skillupack(int guild_id,uint16 skill_id,int account_id) case GD_GLORYWOUNDS: case GD_SOULCOLD: case GD_HAWKEYES: - guild->aura_refresh(sd,skill_id,g->skill[skill_id-GD_SKILLBASE].lv); + guild->aura_refresh(sd,skill_id,g->skill[skill_id-GD_SKILLBASE].lv); break; } } @@ -1362,9 +1364,9 @@ int guild_skillupack(int guild_id,uint16 skill_id,int account_id) void guild_guildaura_refresh(struct map_session_data *sd, uint16 skill_id, uint16 skill_lv) { struct skill_unit_group* group = NULL; - int type = status_skill2sc(skill_id); - if( !(battle_config.guild_aura&((iMap->agit_flag || iMap->agit2_flag)?2:1)) && - !(battle_config.guild_aura&(map_flag_gvg2(sd->bl.m)?8:4)) ) + int type = status->skill2sc(skill_id); + if( !(battle_config.guild_aura&((map->agit_flag || map->agit2_flag)?2:1)) + && !(battle_config.guild_aura&(map_flag_gvg2(sd->bl.m)?8:4)) ) return; if( !skill_lv ) return; @@ -1374,7 +1376,7 @@ void guild_guildaura_refresh(struct map_session_data *sd, uint16 skill_id, uint1 } group = skill->unitsetting(&sd->bl,skill_id,skill_lv,sd->bl.x,sd->bl.y,0); if( group ) { - sc_start4(&sd->bl,type,100,(battle_config.guild_aura&16)?0:skill_lv,0,0,group->group_id,600000);//duration doesn't matter these status never end with val4 + sc_start4(NULL,&sd->bl,type,100,(battle_config.guild_aura&16)?0:skill_lv,0,0,group->group_id,600000);//duration doesn't matter these status never end with val4 } return; } @@ -1405,7 +1407,7 @@ void guild_block_skill(struct map_session_data *sd, int time) uint16 skill_id[] = { GD_BATTLEORDER, GD_REGENERATION, GD_RESTORE, GD_EMERGENCYCALL }; int i; for (i = 0; i < 4; i++) - skill->blockpc_start(sd, skill_id[i], time , true); + skill->blockpc_start(sd, skill_id[i], time); } /*==================================================== @@ -1431,15 +1433,15 @@ int guild_check_alliance(int guild_id1, int guild_id2, int flag) /*==================================================== * Player sd, asking player tsd an alliance between their 2 guilds *---------------------------------------------------*/ -int guild_reqalliance(struct map_session_data *sd,struct map_session_data *tsd) -{ +int guild_reqalliance(struct map_session_data *sd,struct map_session_data *tsd) { struct guild *g[2]; int i; - if(iMap->agit_flag || iMap->agit2_flag) { // Disable alliance creation during woe [Valaris] - clif->message(sd->fd,msg_txt(676)); //"Alliances cannot be made during Guild Wars!" + if(map->agit_flag || map->agit2_flag) { + // Disable alliance creation during woe [Valaris] + clif->message(sd->fd,msg_txt(876)); //"Alliances cannot be made during Guild Wars!" return 0; - } // end addition [Valaris] + } nullpo_ret(sd); @@ -1457,11 +1459,11 @@ int guild_reqalliance(struct map_session_data *sd,struct map_session_data *tsd) if(sd->status.guild_id == tsd->status.guild_id) return 0; - if( guild_get_alliance_count(g[0],0) >= battle_config.max_guild_alliance ) { + if( guild->get_alliance_count(g[0],0) >= battle_config.max_guild_alliance ) { clif->guild_allianceack(sd,4); return 0; } - if( guild_get_alliance_count(g[1],0) >= battle_config.max_guild_alliance ) { + if( guild->get_alliance_count(g[1],0) >= battle_config.max_guild_alliance ) { clif->guild_allianceack(sd,3); return 0; } @@ -1489,12 +1491,11 @@ int guild_reqalliance(struct map_session_data *sd,struct map_session_data *tsd) /*==================================================== * Player sd, answer to player tsd (account_id) for an alliance request *---------------------------------------------------*/ -int guild_reply_reqalliance(struct map_session_data *sd,int account_id,int flag) -{ +int guild_reply_reqalliance(struct map_session_data *sd,int account_id,int flag) { struct map_session_data *tsd; nullpo_ret(sd); - tsd= iMap->id2sd( account_id ); + tsd = map->id2sd( account_id ); if (!tsd) { //Character left? Cancel alliance. clif->guild_allianceack(sd,3); return 0; @@ -1510,12 +1511,12 @@ int guild_reply_reqalliance(struct map_session_data *sd,int account_id,int flag) g=sd->guild; tg=tsd->guild; - if(g==NULL || guild_get_alliance_count(g,0) >= battle_config.max_guild_alliance){ + if(g==NULL || guild->get_alliance_count(g,0) >= battle_config.max_guild_alliance){ clif->guild_allianceack(sd,4); clif->guild_allianceack(tsd,3); return 0; } - if(tg==NULL || guild_get_alliance_count(tg,0) >= battle_config.max_guild_alliance){ + if(tg==NULL || guild->get_alliance_count(tg,0) >= battle_config.max_guild_alliance){ clif->guild_allianceack(sd,3); clif->guild_allianceack(tsd,4); return 0; @@ -1524,18 +1525,18 @@ int guild_reply_reqalliance(struct map_session_data *sd,int account_id,int flag) for(i=0;i<MAX_GUILDALLIANCE;i++){ if(g->alliance[i].guild_id==tsd->status.guild_id && g->alliance[i].opposition==1) - intif_guild_alliance( sd->status.guild_id,tsd->status.guild_id, + intif->guild_alliance( sd->status.guild_id,tsd->status.guild_id, sd->status.account_id,tsd->status.account_id,9 ); } for(i=0;i<MAX_GUILDALLIANCE;i++){ if(tg->alliance[i].guild_id==sd->status.guild_id && tg->alliance[i].opposition==1) - intif_guild_alliance( tsd->status.guild_id,sd->status.guild_id, + intif->guild_alliance( tsd->status.guild_id,sd->status.guild_id, tsd->status.account_id,sd->status.account_id,9 ); } // inform other servers - intif_guild_alliance( sd->status.guild_id,tsd->status.guild_id, + intif->guild_alliance( sd->status.guild_id,tsd->status.guild_id, sd->status.account_id,tsd->status.account_id,0 ); return 0; } else { // deny @@ -1550,16 +1551,16 @@ int guild_reply_reqalliance(struct map_session_data *sd,int account_id,int flag) /*==================================================== * Player sd asking to break alliance with guild guild_id *---------------------------------------------------*/ -int guild_delalliance(struct map_session_data *sd,int guild_id,int flag) -{ +int guild_delalliance(struct map_session_data *sd,int guild_id,int flag) { nullpo_ret(sd); - if(iMap->agit_flag || iMap->agit2_flag) { // Disable alliance breaking during woe [Valaris] - clif->message(sd->fd,msg_txt(677)); //"Alliances cannot be broken during Guild Wars!" + if(map->agit_flag || map->agit2_flag) { + // Disable alliance breaking during woe [Valaris] + clif->message(sd->fd,msg_txt(877)); //"Alliances cannot be broken during Guild Wars!" return 0; - } // end addition [Valaris] + } - intif_guild_alliance( sd->status.guild_id,guild_id,sd->status.account_id,0,flag|8 ); + intif->guild_alliance( sd->status.guild_id,guild_id,sd->status.account_id,0,flag|8 ); return 0; } @@ -1581,48 +1582,47 @@ int guild_opposition(struct map_session_data *sd,struct map_session_data *tsd) if(sd->status.guild_id == tsd->status.guild_id) return 0; - if( guild_get_alliance_count(g,1) >= battle_config.max_guild_alliance ) { + if( guild->get_alliance_count(g,1) >= battle_config.max_guild_alliance ) { clif->guild_oppositionack(sd,1); return 0; } - for (i = 0; i < MAX_GUILDALLIANCE; i++) { // checking relations + for (i = 0; i < MAX_GUILDALLIANCE; i++) { // checking relations if(g->alliance[i].guild_id==tsd->status.guild_id){ - if (g->alliance[i].opposition == 1) { // check if not already hostile + if (g->alliance[i].opposition == 1) { // check if not already hostile clif->guild_oppositionack(sd,2); return 0; } - if(iMap->agit_flag || iMap->agit2_flag) // Prevent the changing of alliances to oppositions during WoE. + if(map->agit_flag || map->agit2_flag) // Prevent the changing of alliances to oppositions during WoE. return 0; //Change alliance to opposition. - intif_guild_alliance( sd->status.guild_id,tsd->status.guild_id, - sd->status.account_id,tsd->status.account_id,8 ); + intif->guild_alliance(sd->status.guild_id,tsd->status.guild_id, + sd->status.account_id,tsd->status.account_id,8); } } - // inform other serv - intif_guild_alliance( sd->status.guild_id,tsd->status.guild_id, - sd->status.account_id,tsd->status.account_id,1 ); + // inform other serv + intif->guild_alliance(sd->status.guild_id,tsd->status.guild_id, + sd->status.account_id,tsd->status.account_id,1); return 0; } /*==================================================== * Notification of a relationship between 2 guilds *---------------------------------------------------*/ -int guild_allianceack(int guild_id1,int guild_id2,int account_id1,int account_id2,int flag,const char *name1,const char *name2) -{ - struct guild *g[2]; - int guild_id[2]; - const char *guild_name[2]; - struct map_session_data *sd[2]; +int guild_allianceack(int guild_id1,int guild_id2,int account_id1,int account_id2,int flag,const char *name1,const char *name2) { + struct guild *g[2] = { NULL }; + int guild_id[2] = { 0 }; + const char *guild_name[2] = { NULL }; + struct map_session_data *sd[2] = { NULL }; int j,i; guild_id[0] = guild_id1; guild_id[1] = guild_id2; guild_name[0] = name1; guild_name[1] = name2; - sd[0] = iMap->id2sd(account_id1); - sd[1] = iMap->id2sd(account_id2); + sd[0] = map->id2sd(account_id1); + sd[1] = map->id2sd(account_id2); g[0]=guild->search(guild_id1); g[1]=guild->search(guild_id2); @@ -1632,7 +1632,7 @@ int guild_allianceack(int guild_id1,int guild_id2,int account_id1,int account_id sd[0]->guild_alliance_account=0; } - if (flag & 0x70) { // failure + if (flag & 0x70) { // failure for(i=0;i<2-(flag&1);i++) if( sd[i]!=NULL ) clif->guild_allianceack(sd[i],((flag>>4)==i+1)?3:4); @@ -1648,7 +1648,7 @@ int guild_allianceack(int guild_id1,int guild_id2,int account_id1,int account_id } } - if (!(flag & 0x08)) { // new relationship + if (!(flag & 0x08)) { // new relationship for(i=0;i<2-(flag&1);i++) { if(g[i]!=NULL) { ARR_FIND( 0, MAX_GUILDALLIANCE, j, g[i]->alliance[j].guild_id == 0 ); @@ -1659,33 +1659,33 @@ int guild_allianceack(int guild_id1,int guild_id2,int account_id1,int account_id } } } - } else { // remove relationship + } else { // remove relationship for(i=0;i<2-(flag&1);i++) { if( g[i] != NULL ) { ARR_FIND( 0, MAX_GUILDALLIANCE, j, g[i]->alliance[j].guild_id == guild_id[1-i] && g[i]->alliance[j].opposition == (flag&1) ); if( j < MAX_GUILDALLIANCE ) g[i]->alliance[j].guild_id = 0; } - if (sd[i] != NULL) // notify players + if (sd[i] != NULL) // notify players clif->guild_delalliance(sd[i],guild_id[1-i],(flag&1)); } } - if ((flag & 0x0f) == 0) { // alliance notification + if ((flag & 0x0f) == 0) { // alliance notification if( sd[1]!=NULL ) clif->guild_allianceack(sd[1],2); - } else if ((flag & 0x0f) == 1) { // enemy notification + } else if ((flag & 0x0f) == 1) { // enemy notification if( sd[0]!=NULL ) clif->guild_oppositionack(sd[0],0); } - for (i = 0; i < 2 - (flag & 1); i++) { // Retransmission of the relationship list to all members - struct map_session_data *sd; + for (i = 0; i < 2 - (flag & 1); i++) { // Retransmission of the relationship list to all members + struct map_session_data *msd; if(g[i]!=NULL) for(j=0;j<g[i]->max_member;j++) - if((sd=g[i]->member[j].sd)!=NULL) - clif->guild_allianceinfo(sd); + if((msd=g[i]->member[j].sd)!=NULL) + clif->guild_allianceinfo(msd); } return 0; } @@ -1708,7 +1708,7 @@ int guild_broken_sub(DBKey key, DBData *data, va_list ap) for(j=0;j<g->max_member;j++) if( (sd=g->member[j].sd)!=NULL ) clif->guild_delalliance(sd,guild_id,g->alliance[i].opposition); - intif_guild_alliance(g->guild_id, guild_id,0,0,g->alliance[i].opposition|8); + intif->guild_alliance(g->guild_id, guild_id,0,0,g->alliance[i].opposition|8); g->alliance[i].guild_id=0; } } @@ -1731,7 +1731,7 @@ int castle_guild_broken_sub(DBKey key, DBData *data, va_list ap) // We call castle_event::OnGuildBreak of all castles of the guild // You can set all castle_events in the 'db/castle_db.txt' safestrncpy(name, gc->castle_event, sizeof(name)); - npc_event_do(strcat(name, "::OnGuildBreak")); + npc->event_do(strcat(name, "::OnGuildBreak")); //Save the new 'owner', this should invoke guardian clean up and other such things. guild->castledatasave(gc->castle_id, 1, 0); @@ -1752,23 +1752,40 @@ int guild_broken(int guild_id,int flag) for(i=0;i<g->max_member;i++){ // Destroy all relationships if((sd=g->member[i].sd)!=NULL){ if(sd->state.storage_flag == 2) - storage_guild_storage_quit(sd,1); + gstorage->pc_quit(sd,1); sd->status.guild_id=0; sd->guild = NULL; + sd->state.gmaster_flag = 0; clif->guild_broken(g->member[i].sd,0); clif->charnameupdate(sd); // [LuzZza] + status_change_end(&sd->bl, SC_LEADERSHIP, INVALID_TIMER); + status_change_end(&sd->bl, SC_GLORYWOUNDS, INVALID_TIMER); + status_change_end(&sd->bl, SC_SOULCOLD, INVALID_TIMER); + status_change_end(&sd->bl, SC_HAWKEYES, INVALID_TIMER); } } - guild_db->foreach(guild_db,guild_broken_sub,guild_id); - castle_db->foreach(castle_db,castle_guild_broken_sub,guild_id); - guild_storage_delete(guild_id); + guild->db->foreach(guild->db,guild->broken_sub,guild_id); + guild->castle_db->foreach(guild->castle_db,guild->castle_broken_sub,guild_id); + gstorage->delete(guild_id); if( hChSys.ally ) { if( g->channel != NULL ) { - clif->chsys_delete(( struct hChSysCh * )g->channel); + clif->chsys_delete(g->channel); } } - idb_remove(guild_db,guild_id); + if( g->instance ) + aFree(g->instance); + + for( i = 0; i < g->hdatac; i++ ) { + if( g->hdata[i]->flag.free ) { + aFree(g->hdata[i]->data); + } + aFree(g->hdata[i]); + } + if( g->hdata ) + aFree(g->hdata); + + idb_remove(guild->db,guild_id); return 0; } @@ -1789,7 +1806,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, strlen(sd->status.name)+1); return 1; } @@ -1821,13 +1838,13 @@ int guild_gm_changed(int guild_id, int account_id, int char_id) strcpy(g->master, g->member[0].name); if (g->member[pos].sd && g->member[pos].sd->fd) { - clif->message(g->member[pos].sd->fd, msg_txt(678)); //"You no longer are the Guild Master." + clif->message(g->member[pos].sd->fd, msg_txt(878)); //"You no longer are the Guild Master." g->member[pos].sd->state.gmaster_flag = 0; } if (g->member[0].sd && g->member[0].sd->fd) { - clif->message(g->member[0].sd->fd, msg_txt(679)); //"You have become the Guild Master!" - g->member[0].sd->state.gmaster_flag = g; + clif->message(g->member[0].sd->fd, msg_txt(879)); //"You have become the Guild Master!" + g->member[0].sd->state.gmaster_flag = 1; //Block his skills for 5 minutes to prevent abuse. guild->block_skill(g->member[0].sd, 300000); } @@ -1848,11 +1865,11 @@ int guild_gm_changed(int guild_id, int account_id, int char_id) /*==================================================== * Guild disbanded *---------------------------------------------------*/ -int guild_break(struct map_session_data *sd,char *name) -{ +int guild_break(struct map_session_data *sd,char *name) { struct guild *g; + struct unit_data *ud; int i; - + nullpo_ret(sd); if( (g=sd->guild)==NULL ) @@ -1871,8 +1888,35 @@ int guild_break(struct map_session_data *sd,char *name) clif->guild_broken(sd,2); return 0; } + + /* regardless of char server allowing it, we clear the guild master's auras */ + if( (ud = unit->bl2ud(&sd->bl)) ) { + int count = 0; + struct skill_unit_group *groups[4]; + for (i=0;i<MAX_SKILLUNITGROUP && ud->skillunit[i];i++) { + switch (ud->skillunit[i]->skill_id) { + case GD_LEADERSHIP: + case GD_GLORYWOUNDS: + case GD_SOULCOLD: + case GD_HAWKEYES: + if( count == 4 ) + ShowWarning("guild_break:'%s' got more than 4 guild aura instances! (%d)\n",sd->status.name,ud->skillunit[i]->skill_id); + else + groups[count++] = ud->skillunit[i]; + break; + } + + } + for(i = 0; i < count; i++) { + skill->del_unitgroup(groups[i],ALC_MARK); + } + } - intif_guild_break(g->guild_id); +#ifdef GP_BOUND_ITEMS + pc->bound_clear(sd,IBT_GUILD); +#endif + + intif->guild_break(g->guild_id); return 1; } @@ -1883,7 +1927,7 @@ int guild_break(struct map_session_data *sd,char *name) void guild_castle_map_init(void) { DBIterator* iter = NULL; - int num = db_size(castle_db); + int num = db_size(guild->castle_db); if (num > 0) { struct guild_castle* gc = NULL; @@ -1891,12 +1935,12 @@ void guild_castle_map_init(void) CREATE(castle_ids, int, num); cursor = castle_ids; - iter = db_iterator(castle_db); + iter = db_iterator(guild->castle_db); for (gc = dbi_first(iter); dbi_exists(iter); gc = dbi_next(iter)) { *(cursor++) = gc->castle_id; } dbi_destroy(iter); - if (intif_guild_castle_dataload(num, castle_ids)) + if (intif->guild_castle_dataload(num, castle_ids)) ShowStatus("Requested '"CL_WHITE"%d"CL_RESET"' guild castles from char-server...\n", num); aFree(castle_ids); } @@ -1926,8 +1970,8 @@ int guild_castledatasave(int castle_id, int index, int value) struct mob_data *gd; gc->guild_id = value; for (i = 0; i < MAX_GUARDIANS; i++) - if (gc->guardian[i].visible && (gd = iMap->id2md(gc->guardian[i].id)) != NULL) - mob_guardian_guildchange(gd); + if (gc->guardian[i].visible && (gd = map->id2md(gc->guardian[i].id)) != NULL) + mob->guardian_guildchange(gd); break; } case 2: @@ -1938,8 +1982,8 @@ int guild_castledatasave(int castle_id, int index, int value) struct mob_data *gd; gc->defense = value; for (i = 0; i < MAX_GUARDIANS; i++) - if (gc->guardian[i].visible && (gd = iMap->id2md(gc->guardian[i].id)) != NULL) - status_calc_mob(gd, 0); + if (gc->guardian[i].visible && (gd = map->id2md(gc->guardian[i].id)) != NULL) + status_calc_mob(gd, SCO_NONE); break; } case 4: @@ -1963,7 +2007,7 @@ int guild_castledatasave(int castle_id, int index, int value) return 0; } - if (!intif_guild_castle_datasave(castle_id, index, value)) { + if (!intif->guild_castle_datasave(castle_id, index, value)) { guild->castle_reconnect(castle_id, index, value); } return 0; @@ -1971,14 +2015,14 @@ int guild_castledatasave(int castle_id, int index, int value) void guild_castle_reconnect_sub(void *key, void *data, va_list ap) { - int castle_id = GetWord((int)__64BPTRSIZE(key), 0); - int index = GetWord((int)__64BPTRSIZE(key), 1); - intif_guild_castle_datasave(castle_id, index, *(int *)data); + int castle_id = GetWord((int)h64BPTRSIZE(key), 0); + int index = GetWord((int)h64BPTRSIZE(key), 1); + intif->guild_castle_datasave(castle_id, index, *(int *)data); aFree(data); } /** - * Saves pending guild castle data changes when char-server is + * Saves pending guild castle data changes when char-server is * disconnected. * On reconnect pushes all changes to char-server for saving. */ @@ -1987,13 +2031,13 @@ void guild_castle_reconnect(int castle_id, int index, int value) static struct linkdb_node *gc_save_pending = NULL; if (castle_id < 0) { // char-server reconnected - linkdb_foreach(&gc_save_pending, guild_castle_reconnect_sub); + linkdb_foreach(&gc_save_pending, guild->castle_reconnect_sub); linkdb_final(&gc_save_pending); } else { int *data; CREATE(data, int, 1); *data = value; - linkdb_replace(&gc_save_pending, (void*)__64BPTRSIZE((MakeDWord(castle_id, index))), data); + linkdb_replace(&gc_save_pending, (void*)h64BPTRSIZE((MakeDWord(castle_id, index))), data); } } @@ -2011,8 +2055,8 @@ int guild_castledataloadack(int len, struct guild_castle *gc) ev = i; // offset of castle or -1 if( ev < 0 ) { //No castles owned, invoke OnAgitInit as it is. - npc_event_doall("OnAgitInit"); - npc_event_doall("OnAgitInit2"); + npc->event_doall("OnAgitInit"); + npc->event_doall("OnAgitInit2"); } else { // load received castles into memory, one by one for( i = 0; i < n; i++, gc++ ) { struct guild_castle *c = guild->castle_search(gc->castle_id); @@ -2043,7 +2087,7 @@ int guild_castledataloadack(int len, struct guild_castle *gc) *---------------------------------------------------*/ void guild_agit_start(void) { // Run All NPC_Event[OnAgitStart] - int c = npc_event_doall("OnAgitStart"); + int c = npc->event_doall("OnAgitStart"); ShowStatus("NPC_Event:[OnAgitStart] Run (%d) Events by @AgitStart.\n",c); } @@ -2052,7 +2096,7 @@ void guild_agit_start(void) *---------------------------------------------------*/ void guild_agit_end(void) { // Run All NPC_Event[OnAgitEnd] - int c = npc_event_doall("OnAgitEnd"); + int c = npc->event_doall("OnAgitEnd"); ShowStatus("NPC_Event:[OnAgitEnd] Run (%d) Events by @AgitEnd.\n",c); } @@ -2061,7 +2105,7 @@ void guild_agit_end(void) *---------------------------------------------------*/ void guild_agit2_start(void) { // Run All NPC_Event[OnAgitStart2] - int c = npc_event_doall("OnAgitStart2"); + int c = npc->event_doall("OnAgitStart2"); ShowStatus("NPC_Event:[OnAgitStart2] Run (%d) Events by @AgitStart2.\n",c); } @@ -2070,7 +2114,7 @@ void guild_agit2_start(void) *---------------------------------------------------*/ void guild_agit2_end(void) { // Run All NPC_Event[OnAgitEnd2] - int c = npc_event_doall("OnAgitEnd2"); + int c = npc->event_doall("OnAgitEnd2"); ShowStatus("NPC_Event:[OnAgitEnd2] Run (%d) Events by @AgitEnd2.\n",c); } @@ -2079,7 +2123,7 @@ int guild_checkcastles(struct guild *g) { int nb_cas = 0; struct guild_castle* gc = NULL; - DBIterator *iter = db_iterator(castle_db); + DBIterator *iter = db_iterator(guild->castle_db); for (gc = dbi_first(iter); dbi_exists(iter); gc = dbi_next(iter)) { if (gc->guild_id == g->guild_id) { @@ -2105,38 +2149,38 @@ void guild_flag_add(struct npc_data *nd) { int i; /* check */ - for( i = 0; i < guild_flags_count; i++ ) { - if( guild_flags[i] && guild_flags[i]->bl.id == nd->bl.id ) { + for( i = 0; i < guild->flags_count; i++ ) { + if( guild->flags[i] && guild->flags[i]->bl.id == nd->bl.id ) { return;/* exists, most likely updated the id. */ } } - i = guild_flags_count;/* save the current slot */ + i = guild->flags_count;/* save the current slot */ /* add */ - RECREATE(guild_flags,struct npc_data*,++guild_flags_count); + RECREATE(guild->flags,struct npc_data*,++guild->flags_count); /* save */ - guild_flags[i] = nd; + guild->flags[i] = nd; } void guild_flag_remove(struct npc_data *nd) { int i, cursor; - if( guild_flags_count == 0 ) + if( guild->flags_count == 0 ) return; /* find it */ - for( i = 0; i < guild_flags_count; i++ ) { - if( guild_flags[i] && guild_flags[i]->bl.id == nd->bl.id ) {/* found */ - guild_flags[i] = NULL; + for( i = 0; i < guild->flags_count; i++ ) { + if( guild->flags[i] && guild->flags[i]->bl.id == nd->bl.id ) {/* found */ + guild->flags[i] = NULL; break; } } /* compact list */ - for( i = 0, cursor = 0; i < guild_flags_count; i++ ) { - if( guild_flags[i] == NULL ) + for( i = 0, cursor = 0; i < guild->flags_count; i++ ) { + if( guild->flags[i] == NULL ) continue; if( cursor != i ) { - memmove(&guild_flags[cursor], &guild_flags[i], sizeof(struct npc_data*)); + memmove(&guild->flags[cursor], &guild->flags[i], sizeof(struct npc_data*)); } cursor++; @@ -2147,7 +2191,7 @@ void guild_flag_remove(struct npc_data *nd) { /** * @see DBApply */ -static int eventlist_db_final(DBKey key, DBData *data, va_list ap) { +int eventlist_db_final(DBKey key, DBData *data, va_list ap) { struct eventlist *next = NULL; struct eventlist *current = DB->data2ptr(data); while (current != NULL) { @@ -2161,15 +2205,15 @@ static int eventlist_db_final(DBKey key, DBData *data, va_list ap) { /** * @see DBApply */ -static int guild_expcache_db_final(DBKey key, DBData *data, va_list ap) { - ers_free(expcache_ers, DB->data2ptr(data)); +int guild_expcache_db_final(DBKey key, DBData *data, va_list ap) { + ers_free(guild->expcache_ers, DB->data2ptr(data)); return 0; } /** * @see DBApply */ -static int guild_castle_db_final(DBKey key, DBData *data, va_list ap) { +int guild_castle_db_final(DBKey key, DBData *data, va_list ap) { struct guild_castle* gc = DB->data2ptr(data); if( gc->temp_guardians ) aFree(gc->temp_guardians); @@ -2180,56 +2224,66 @@ static int guild_castle_db_final(DBKey key, DBData *data, va_list ap) { /* called when scripts are reloaded/unloaded */ void guild_flags_clear(void) { int i; - for( i = 0; i < guild_flags_count; i++ ) { - if( guild_flags[i] ) - guild_flags[i] = NULL; + for( i = 0; i < guild->flags_count; i++ ) { + if( guild->flags[i] ) + guild->flags[i] = NULL; } - guild_flags_count = 0; + guild->flags_count = 0; } -void do_init_guild(void) { - guild_db = idb_alloc(DB_OPT_RELEASE_DATA); - castle_db = idb_alloc(DB_OPT_BASE); - guild_expcache_db = idb_alloc(DB_OPT_BASE); - guild_infoevent_db = idb_alloc(DB_OPT_BASE); - expcache_ers = ers_new(sizeof(struct guild_expcache),"guild.c::expcache_ers",ERS_OPT_NONE); - - guild_flags_count = 0; - - sv->readdb(iMap->db_path, "castle_db.txt", ',', 4, 5, -1, &guild_read_castledb); +void do_init_guild(bool minimal) { + if (minimal) + return; + + guild->db = idb_alloc(DB_OPT_RELEASE_DATA); + guild->castle_db = idb_alloc(DB_OPT_BASE); + guild->expcache_db = idb_alloc(DB_OPT_BASE); + guild->infoevent_db = idb_alloc(DB_OPT_BASE); + guild->expcache_ers = ers_new(sizeof(struct guild_expcache),"guild.c::expcache_ers",ERS_OPT_NONE); + + sv->readdb(map->db_path, "castle_db.txt", ',', 4, 5, -1, guild->read_castledb); - memset(guild_skill_tree,0,sizeof(guild_skill_tree)); - sv->readdb(iMap->db_path, "guild_skill_tree.txt", ',', 2+MAX_GUILD_SKILL_REQUIRE*2, 2+MAX_GUILD_SKILL_REQUIRE*2, -1, &guild_read_guildskill_tree_db); //guild skill tree [Komurka] + sv->readdb(map->db_path, "guild_skill_tree.txt", ',', 2+MAX_GUILD_SKILL_REQUIRE*2, 2+MAX_GUILD_SKILL_REQUIRE*2, -1, guild->read_guildskill_tree_db); //guild skill tree [Komurka] - iTimer->add_timer_func_list(guild_payexp_timer,"guild_payexp_timer"); - iTimer->add_timer_func_list(guild_send_xy_timer, "guild_send_xy_timer"); - iTimer->add_timer_interval(iTimer->gettick()+GUILD_PAYEXP_INVERVAL,guild_payexp_timer,0,0,GUILD_PAYEXP_INVERVAL); - iTimer->add_timer_interval(iTimer->gettick()+GUILD_SEND_XY_INVERVAL,guild_send_xy_timer,0,0,GUILD_SEND_XY_INVERVAL); + timer->add_func_list(guild->payexp_timer,"guild_payexp_timer"); + timer->add_func_list(guild->send_xy_timer, "guild_send_xy_timer"); + timer->add_interval(timer->gettick()+GUILD_PAYEXP_INVERVAL,guild->payexp_timer,0,0,GUILD_PAYEXP_INVERVAL); + timer->add_interval(timer->gettick()+GUILD_SEND_XY_INVERVAL,guild->send_xy_timer,0,0,GUILD_SEND_XY_INVERVAL); } void do_final_guild(void) { - DBIterator *iter = db_iterator(guild_db); + DBIterator *iter = db_iterator(guild->db); struct guild *g; + int i; for( g = dbi_first(iter); dbi_exists(iter); g = dbi_next(iter) ) { if( g->channel != NULL ) - clif->chsys_delete((struct hChSysCh *)g->channel); + clif->chsys_delete(g->channel); if( g->instance != NULL ) { aFree(g->instance); g->instance = NULL; } + for( i = 0; i < g->hdatac; i++ ) { + if( g->hdata[i]->flag.free ) { + aFree(g->hdata[i]->data); + } + aFree(g->hdata[i]); + } + if( g->hdata ) + aFree(g->hdata); } dbi_destroy(iter); - db_destroy(guild_db); - castle_db->destroy(castle_db,guild_castle_db_final); - guild_expcache_db->destroy(guild_expcache_db,guild_expcache_db_final); - guild_infoevent_db->destroy(guild_infoevent_db,eventlist_db_final); - ers_destroy(expcache_ers); - - aFree(guild_flags);/* never empty; created on boot */ + db_destroy(guild->db); + guild->castle_db->destroy(guild->castle_db,guild->castle_db_final); + guild->expcache_db->destroy(guild->expcache_db,guild->expcache_db_final); + guild->infoevent_db->destroy(guild->infoevent_db,guild->eventlist_db_final); + ers_destroy(guild->expcache_ers); + + if( guild->flags ) + aFree(guild->flags); } void guild_defaults(void) { guild = &guild_s; @@ -2237,6 +2291,18 @@ void guild_defaults(void) { guild->init = do_init_guild; guild->final = do_final_guild; /* */ + guild->db = NULL; + guild->castle_db = NULL; + guild->expcache_db = NULL; + guild->infoevent_db = NULL; + /* */ + guild->expcache_ers = NULL; + /* */ + memset(guild->skill_tree, 0, sizeof(guild->skill_tree)); + /* guild flags cache */ + guild->flags = NULL; + guild->flags_count = 0; + /* */ guild->skill_get_max = guild_skill_get_max; /* */ guild->checkskill = guild_checkskill; @@ -2307,10 +2373,30 @@ void guild_defaults(void) { guild->agit_end = guild_agit_end; guild->agit2_start = guild_agit2_start; guild->agit2_end = guild_agit2_end; - /* guild flag cachin */ + /* guild flag caching */ guild->flag_add = guild_flag_add; guild->flag_remove = guild_flag_remove; guild->flags_clear = guild_flags_clear; - /* guild aura */ + /* guild aura */ guild->aura_refresh = guild_guildaura_refresh; + /* */ + guild->payexp_timer = guild_payexp_timer; + guild->sd_check = guild_sd_check; + guild->read_guildskill_tree_db = guild_read_guildskill_tree_db; + guild->read_castledb = guild_read_castledb; + guild->payexp_timer_sub = guild_payexp_timer_sub; + guild->send_xy_timer_sub = guild_send_xy_timer_sub; + guild->send_xy_timer = guild_send_xy_timer; + guild->create_expcache = create_expcache; + guild->eventlist_db_final = eventlist_db_final; + guild->expcache_db_final = guild_expcache_db_final; + guild->castle_db_final = guild_castle_db_final; + guild->broken_sub = guild_broken_sub; + guild->castle_broken_sub = castle_guild_broken_sub; + guild->makemember = guild_makemember; + guild->check_member = guild_check_member; + guild->get_alliance_count = guild_get_alliance_count; + guild->castle_reconnect_sub = guild_castle_reconnect_sub; + /* */ + guild->retrieveitembound = guild_retrieveitembound; } diff --git a/src/map/guild.h b/src/map/guild.h index 9841f5451..126325eef 100644 --- a/src/map/guild.h +++ b/src/map/guild.h @@ -2,32 +2,69 @@ // See the LICENSE file // Portions Copyright (c) Athena Dev Teams -#ifndef _GUILD_H_ -#define _GUILD_H_ +#ifndef MAP_GUILD_H +#define MAP_GUILD_H -//#include "../common/mmo.h" -struct guild; -struct guild_member; -struct guild_position; -struct guild_castle; -#include "map.h" // NAME_LENGTH -struct map_session_data; -struct mob_data; +#include "map.h" // EVENT_NAME_LENGTH, TBL_PC +#include "../common/cbasetypes.h" +#include "../common/db.h" +#include "../common/mmo.h" -//For quick linking to a guardian's info. [Skotlex] +/** + * Defines + **/ +#define GUILD_SEND_XY_INVERVAL 5000 // Interval of sending coordinates and HP +#define GUILD_PAYEXP_INVERVAL 10000 //Interval (maximum survival time of the cache, in milliseconds) +#define MAX_GUILD_SKILL_REQUIRE 5 + +/** + * Structures + **/ +struct eventlist { + char name[EVENT_NAME_LENGTH]; + struct eventlist *next; +}; + +/** + * Guardian data + * For quick linking to a guardian's info. [Skotlex] + **/ struct guardian_data { int number; //0-MAX_GUARDIANS-1 = Guardians. MAX_GUARDIANS = Emperium. - int guild_id; - int emblem_id; - int guardup_lv; //Level of GD_GUARDUP skill. - char guild_name[NAME_LENGTH]; + + struct guild *g; struct guild_castle* castle; }; +struct guild_expcache { + int guild_id, account_id, char_id; + uint64 exp; +}; +struct s_guild_skill_tree { + int id; + int max; + struct { + short id; + short lv; + } need[MAX_GUILD_SKILL_REQUIRE]; +}; + struct guild_interface { - void (*init) (void); + void (*init) (bool minimal); void (*final) (void); /* */ + DBMap* db; // int guild_id -> struct guild* + DBMap* castle_db; // int castle_id -> struct guild_castle* + DBMap* expcache_db; // int char_id -> struct guild_expcache* + DBMap* infoevent_db; // int guild_id -> struct eventlist* + /* */ + struct eri *expcache_ers; //For handling of guild exp payment. + /* */ + struct s_guild_skill_tree skill_tree[MAX_GUILDSKILL]; + /* guild flags cache */ + struct npc_data **flags; + unsigned short flags_count; + /* */ int (*skill_get_max) (int id); /* */ int (*checkskill) (struct guild *g,int id); @@ -40,7 +77,7 @@ struct guild_interface { struct guild_castle *(*castle_search) (int gcid); /* */ struct guild_castle *(*mapname2gc) (const char* mapname); - struct guild_castle *(*mapindex2gc) (short mapindex); + struct guild_castle *(*mapindex2gc) (short map_index); /* */ struct map_session_data *(*getavailablesd) (struct guild *g); int (*getindex) (struct guild *g,int account_id,int char_id); @@ -104,10 +141,30 @@ struct guild_interface { void (*flags_clear) (void); /* guild aura */ void (*aura_refresh) (struct map_session_data *sd, uint16 skill_id, uint16 skill_lv); -} guild_s; + /* item bound [Mhalicot]*/ + void (*retrieveitembound) (int char_id,int aid,int guild_id); + /* */ + int (*payexp_timer) (int tid, int64 tick, int id, intptr_t data); + TBL_PC* (*sd_check) (int guild_id, int account_id, int char_id); + bool (*read_guildskill_tree_db) (char* split[], int columns, int current); + bool (*read_castledb) (char* str[], int columns, int current); + int (*payexp_timer_sub) (DBKey key, DBData *data, va_list ap); + int (*send_xy_timer_sub) (DBKey key, DBData *data, va_list ap); + int (*send_xy_timer) (int tid, int64 tick, int id, intptr_t data); + DBData (*create_expcache) (DBKey key, va_list args); + int (*eventlist_db_final) (DBKey key, DBData *data, va_list ap); + int (*expcache_db_final) (DBKey key, DBData *data, va_list ap); + int (*castle_db_final) (DBKey key, DBData *data, va_list ap); + int (*broken_sub) (DBKey key, DBData *data, va_list ap); + int (*castle_broken_sub) (DBKey key, DBData *data, va_list ap); + void (*makemember) (struct guild_member *m,struct map_session_data *sd); + int (*check_member) (struct guild *g); + int (*get_alliance_count) (struct guild *g,int flag); + void (*castle_reconnect_sub) (void *key, void *data, va_list ap); +}; struct guild_interface *guild; void guild_defaults(void); -#endif /* _GUILD_H_ */ +#endif /* MAP_GUILD_H */ diff --git a/src/map/homunculus.c b/src/map/homunculus.c index efb5c0eb3..0f76fcf5f 100644 --- a/src/map/homunculus.c +++ b/src/map/homunculus.c @@ -2,43 +2,47 @@ // See the LICENSE file // Portions Copyright (c) Athena Dev Teams -#include "../common/cbasetypes.h" -#include "../common/malloc.h" -#include "../common/socket.h" -#include "../common/timer.h" -#include "../common/nullpo.h" -#include "../common/mmo.h" -#include "../common/random.h" -#include "../common/showmsg.h" -#include "../common/strlib.h" -#include "../common/utils.h" +#define HERCULES_CORE -#include "log.h" -#include "clif.h" +#include "../config/core.h" // DBPATH +#include "homunculus.h" + +#include <math.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "atcommand.h" +#include "battle.h" #include "chrif.h" +#include "clif.h" +#include "guild.h" #include "intif.h" #include "itemdb.h" +#include "log.h" #include "map.h" -#include "pc.h" -#include "status.h" -#include "skill.h" #include "mob.h" -#include "pet.h" -#include "battle.h" +#include "npc.h" #include "party.h" -#include "guild.h" -#include "atcommand.h" +#include "pc.h" +#include "pet.h" #include "script.h" -#include "npc.h" +#include "skill.h" +#include "status.h" #include "trade.h" #include "unit.h" +#include "../common/cbasetypes.h" +#include "../common/malloc.h" +#include "../common/mmo.h" +#include "../common/nullpo.h" +#include "../common/random.h" +#include "../common/showmsg.h" +#include "../common/socket.h" +#include "../common/strlib.h" +#include "../common/timer.h" +#include "../common/utils.h" -#include "homunculus.h" - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <math.h> +struct homunculus_interface homunculus_s; //Returns the viewdata for homunculus struct view_data* homunculus_get_viewdata(int class_) { @@ -69,7 +73,7 @@ enum homun_type homunculus_class2type(int class_) { case 6052: return HT_S; default: - return -1; + return HT_INVALID; } } @@ -132,30 +136,30 @@ int homunculus_dead(struct homun_data *hd) { } //Vaporize a character's homun. If flag, HP needs to be 80% or above. -int homunculus_vaporize(struct map_session_data *sd, int flag) { +int homunculus_vaporize(struct map_session_data *sd, enum homun_state flag) { struct homun_data *hd; nullpo_ret(sd); hd = sd->hd; - if (!hd || hd->homunculus.vaporize) + if (!hd || hd->homunculus.vaporize != HOM_ST_ACTIVE) return 0; - if (status_isdead(&hd->bl)) + if (status->isdead(&hd->bl)) return 0; //Can't vaporize a dead homun. - if (flag && get_percentage(hd->battle_status.hp, hd->battle_status.max_hp) < 80) + if (flag == HOM_ST_REST && get_percentage(hd->battle_status.hp, hd->battle_status.max_hp) < 80) return 0; hd->regen.state.block = 3; //Block regen while vaporized. //Delete timers when vaporized. homun->hunger_timer_delete(hd); - hd->homunculus.vaporize = 1; + hd->homunculus.vaporize = flag; if(battle_config.hom_setting&0x40) memset(hd->blockskill, 0, sizeof(hd->blockskill)); clif->hominfo(sd, sd->hd, 0); homun->save(hd); - return unit_remove_map(&hd->bl, CLR_OUTSIGHT); + return unit->remove_map(&hd->bl, CLR_OUTSIGHT, ALC_MARK); } //delete a homunculus, completely "killing it". @@ -166,7 +170,7 @@ int homunculus_delete(struct homun_data *hd, int emote) { sd = hd->master; if (!sd) - return unit_free(&hd->bl,CLR_DEAD); + return unit->free(&hd->bl,CLR_DEAD); if (emote >= 0) clif->emotion(&sd->bl, emote); @@ -176,7 +180,7 @@ int homunculus_delete(struct homun_data *hd, int emote) { // Send homunculus_dead to client hd->homunculus.hp = 0; clif->hominfo(sd, hd, 0); - return unit_remove_map(&hd->bl,CLR_OUTSIGHT); + return unit->remove_map(&hd->bl,CLR_OUTSIGHT, ALC_MARK); } int homunculus_calc_skilltree(struct homun_data *hd, int flag_evolve) { @@ -258,7 +262,7 @@ void homunculus_skillup(struct homun_data *hd,uint16 skill_id) { int i = 0 ; nullpo_retv(hd); - if(hd->homunculus.vaporize) + if(hd->homunculus.vaporize != HOM_ST_ACTIVE) return; i = skill_id - HM_SKILLBASE; @@ -270,7 +274,7 @@ void homunculus_skillup(struct homun_data *hd,uint16 skill_id) { { hd->homunculus.hskill[i].lv++; hd->homunculus.skillpts-- ; - status_calc_homunculus(hd,0); + status_calc_homunculus(hd,SCO_NONE); if (hd->master) { clif->homskillup(hd->master, skill_id); clif->hominfo(hd->master,hd,0); @@ -286,7 +290,7 @@ bool homunculus_levelup(struct homun_data *hd) { int growth_max_hp, growth_max_sp; enum homun_type htype; - if((htype = homun->class2type(hd->homunculus.class_)) == -1) { + if( (htype = homun->class2type(hd->homunculus.class_)) == HT_INVALID ) { ShowError("homunculus_levelup: Invalid class %d. \n", hd->homunculus.class_); return false; } @@ -350,7 +354,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,strlen(output)); } return true; } @@ -362,7 +366,7 @@ int homunculus_change_class(struct homun_data *hd, short class_) { return 0; hd->homunculusDB = &homun->db[i]; hd->homunculus.class_ = class_; - status_set_viewdata(&hd->bl, class_); + status->set_viewdata(&hd->bl, class_); homun->calc_skilltree(hd, 1); return 1; } @@ -401,8 +405,8 @@ bool homunculus_evolve(struct homun_data *hd) { hom->luk += 10*rnd_value(min->luk, max->luk); hom->intimacy = 500; - unit_remove_map(&hd->bl, CLR_OUTSIGHT); - iMap->addblock(&hd->bl); + unit->remove_map(&hd->bl, CLR_OUTSIGHT, ALC_MARK); + map->addblock(&hd->bl); clif->spawn(&hd->bl); clif->emotion(&sd->bl, E_NO1); @@ -411,10 +415,10 @@ bool homunculus_evolve(struct homun_data *hd) { //status_Calc flag&1 will make current HP/SP be reloaded from hom structure hom->hp = hd->battle_status.hp; hom->sp = hd->battle_status.sp; - status_calc_homunculus(hd,1); + status_calc_homunculus(hd,SCO_FIRST); if (!(battle_config.hom_setting&0x2)) - skill->unit_move(&sd->hd->bl,iTimer->gettick(),1); // apply land skills immediately + skill->unit_move(&sd->hd->bl,timer->gettick(),1); // apply land skills immediately return true; } @@ -433,20 +437,20 @@ bool homunculus_mutate(struct homun_data *hd, int homun_id) { m_class = homun->class2type(hd->homunculus.class_); m_id = homun->class2type(homun_id); - if( m_class == -1 || m_id == -1 || m_class != HT_EVO || m_id != HT_S ) { + if( m_class == HT_INVALID || m_id == HT_INVALID || m_class != HT_EVO || m_id != HT_S ) { clif->emotion(&hd->bl, E_SWT); return false; } prev_class = hd->homunculus.class_; - if (!homun->change_class(hd, homun_id)) { + if( !homun->change_class(hd, homun_id) ) { ShowError("homunculus_mutate: Can't evolve homunc from %d to %d", hd->homunculus.class_, homun_id); return false; } - unit_remove_map(&hd->bl, CLR_OUTSIGHT); - iMap->addblock(&hd->bl); + unit->remove_map(&hd->bl, CLR_OUTSIGHT, ALC_MARK); + map->addblock(&hd->bl); clif->spawn(&hd->bl); clif->emotion(&sd->bl, E_NO1); @@ -458,10 +462,10 @@ bool homunculus_mutate(struct homun_data *hd, int homun_id) { hom->hp = hd->battle_status.hp; hom->sp = hd->battle_status.sp; hom->prev_class = prev_class; - status_calc_homunculus(hd,1); + status_calc_homunculus(hd,SCO_FIRST); if (!(battle_config.hom_setting&0x2)) - skill->unit_move(&sd->hd->bl,iTimer->gettick(),1); // apply land skills immediately + skill->unit_move(&sd->hd->bl,timer->gettick(),1); // apply land skills immediately return true; } @@ -469,10 +473,10 @@ bool homunculus_mutate(struct homun_data *hd, int homun_id) { int homunculus_gainexp(struct homun_data *hd,unsigned int exp) { enum homun_type htype; - if(hd->homunculus.vaporize) + if(hd->homunculus.vaporize != HOM_ST_ACTIVE) return 1; - if((htype = homun->class2type(hd->homunculus.class_)) == -1) { + if( (htype = homun->class2type(hd->homunculus.class_)) == HT_INVALID ) { ShowError("homunculus_gainexp: Invalid class %d. \n", hd->homunculus.class_); return 0; } @@ -503,7 +507,7 @@ int homunculus_gainexp(struct homun_data *hd,unsigned int exp) { hd->homunculus.exp = 0; clif->specialeffect(&hd->bl,568,AREA); - status_calc_homunculus(hd,0); + status_calc_homunculus(hd,SCO_NONE); status_percent_heal(&hd->bl, 100, 100); return 0; } @@ -542,7 +546,7 @@ void homunculus_save(struct homun_data *hd) { //calculation on login) hd->homunculus.hp = hd->battle_status.hp; hd->homunculus.sp = hd->battle_status.sp; - intif_homunculus_requestsave(sd->status.account_id, &hd->homunculus); + intif->homunculus_requestsave(sd->status.account_id, &hd->homunculus); } unsigned char homunculus_menu(struct map_session_data *sd,unsigned char menu_num) { @@ -569,12 +573,12 @@ unsigned char homunculus_menu(struct map_session_data *sd,unsigned char menu_num bool homunculus_feed(struct map_session_data *sd, struct homun_data *hd) { int i, foodID, emotion; - if(hd->homunculus.vaporize) + if(hd->homunculus.vaporize == HOM_ST_REST) return false; foodID = hd->homunculusDB->foodID; i = pc->search_inventory(sd,foodID); - if(i < 0) { + if (i == INDEX_NOT_FOUND) { clif->hom_food(sd,foodID,0); return false; } @@ -613,11 +617,11 @@ bool homunculus_feed(struct map_session_data *sd, struct homun_data *hd) { return true; } -int homunculus_hunger_timer(int tid, unsigned int tick, int id, intptr_t data) { +int homunculus_hunger_timer(int tid, int64 tick, int id, intptr_t data) { struct map_session_data *sd; struct homun_data *hd; - if(!(sd=iMap->id2sd(id)) || !sd->status.hom_id || !(hd=sd->hd)) + if(!(sd=map->id2sd(id)) || !sd->status.hom_id || !(hd=sd->hd)) return 1; if(hd->hungry_timer != tid){ @@ -645,14 +649,14 @@ int homunculus_hunger_timer(int tid, unsigned int tick, int id, intptr_t data) { } clif->send_homdata(sd,SP_HUNGRY,hd->homunculus.hunger); - hd->hungry_timer = iTimer->add_timer(tick+hd->homunculusDB->hungryDelay,homun->hunger_timer,sd->bl.id,0); //simple Fix albator + hd->hungry_timer = timer->add(tick+hd->homunculusDB->hungryDelay,homun->hunger_timer,sd->bl.id,0); //simple Fix albator return 0; } void homunculus_hunger_timer_delete(struct homun_data *hd) { nullpo_retv(hd); if(hd->hungry_timer != INVALID_TIMER) { - iTimer->delete_timer(hd->hungry_timer,homun->hunger_timer); + timer->delete(hd->hungry_timer,homun->hunger_timer); hd->hungry_timer = INVALID_TIMER; } } @@ -729,33 +733,35 @@ bool homunculus_create(struct map_session_data *sd, struct s_homunculus *hom) { if(i < 0) { ShowError("homunculus_create: unknown class [%d] for homunculus '%s', requesting deletion.\n", hom->class_, hom->name); sd->status.hom_id = 0; - intif_homunculus_requestdelete(hom->hom_id); + intif->homunculus_requestdelete(hom->hom_id); return false; } sd->hd = hd = (struct homun_data*)aCalloc(1,sizeof(struct homun_data)); hd->bl.type = BL_HOM; - hd->bl.id = npc_get_new_npc_id(); + hd->bl.id = npc->get_new_npc_id(); hd->master = sd; hd->homunculusDB = &homun->db[i]; memcpy(&hd->homunculus, hom, sizeof(struct s_homunculus)); hd->exp_next = homun->exptable[hd->homunculus.level - 1]; - status_set_viewdata(&hd->bl, hd->homunculus.class_); - status_change_init(&hd->bl); - unit_dataset(&hd->bl); + status->set_viewdata(&hd->bl, hd->homunculus.class_); + status->change_init(&hd->bl); + unit->dataset(&hd->bl); hd->ud.dir = sd->ud.dir; // Find a random valid pos around the player hd->bl.m = sd->bl.m; hd->bl.x = sd->bl.x; hd->bl.y = sd->bl.y; - unit_calc_pos(&hd->bl, sd->bl.x, sd->bl.y, sd->ud.dir); + unit->calc_pos(&hd->bl, sd->bl.x, sd->bl.y, sd->ud.dir); hd->bl.x = hd->ud.to_x; hd->bl.y = hd->ud.to_y; - - iMap->addiddb(&hd->bl); - status_calc_homunculus(hd,1); + hd->masterteleport_timer = 0; + + map->addiddb(&hd->bl); + status_calc_homunculus(hd,SCO_FIRST); + status_percent_heal(&hd->bl, 100, 100); hd->hungry_timer = INVALID_TIMER; return true; @@ -763,7 +769,7 @@ bool homunculus_create(struct map_session_data *sd, struct s_homunculus *hom) { void homunculus_init_timers(struct homun_data * hd) { if (hd->hungry_timer == INVALID_TIMER) - hd->hungry_timer = iTimer->add_timer(iTimer->gettick()+hd->homunculusDB->hungryDelay,homun->hunger_timer,hd->master->bl.id,0); + hd->hungry_timer = timer->add(timer->gettick()+hd->homunculusDB->hungryDelay,homun->hunger_timer,hd->master->bl.id,0); hd->regen.state.block = 0; //Restore HP/SP block. } @@ -775,20 +781,20 @@ bool homunculus_call(struct map_session_data *sd) { // If homunc not yet loaded, load it if (!sd->hd) - return intif_homunculus_requestload(sd->status.account_id, sd->status.hom_id); + return intif->homunculus_requestload(sd->status.account_id, sd->status.hom_id); hd = sd->hd; - if (!hd->homunculus.vaporize) + if (hd->homunculus.vaporize != HOM_ST_REST) return false; //Can't use this if homun wasn't vaporized. homun->init_timers(hd); - hd->homunculus.vaporize = 0; + hd->homunculus.vaporize = HOM_ST_ACTIVE; if (hd->bl.prev == NULL) { //Spawn him hd->bl.x = sd->bl.x; hd->bl.y = sd->bl.y; hd->bl.m = sd->bl.m; - iMap->addblock(&hd->bl); + map->addblock(&hd->bl); clif->spawn(&hd->bl); clif->send_homdata(sd,SP_ACK,0); clif->hominfo(sd,hd,1); @@ -799,16 +805,16 @@ bool homunculus_call(struct map_session_data *sd) { homun->save(hd); } else //Warp him to master. - unit_warp(&hd->bl,sd->bl.m, sd->bl.x, sd->bl.y,CLR_OUTSIGHT); + unit->warp(&hd->bl,sd->bl.m, sd->bl.x, sd->bl.y,CLR_OUTSIGHT); return true; } -// Recv homunculus data from char server +// Receive homunculus data from char server bool homunculus_recv_data(int account_id, struct s_homunculus *sh, int flag) { struct map_session_data *sd; struct homun_data *hd; - sd = iMap->id2sd(account_id); + sd = map->id2sd(account_id); if(!sd) return false; if (sd->status.char_id != sh->char_id) { @@ -831,10 +837,10 @@ bool homunculus_recv_data(int account_id, struct s_homunculus *sh, int flag) { homun->create(sd, sh); hd = sd->hd; - if(hd && hd->homunculus.hp && !hd->homunculus.vaporize && hd->bl.prev == NULL && sd->bl.prev != NULL) { + if(hd && hd->homunculus.hp && hd->homunculus.vaporize == HOM_ST_ACTIVE && hd->bl.prev == NULL && sd->bl.prev != NULL) { enum homun_type htype = homun->class2type(hd->homunculus.class_); - iMap->addblock(&hd->bl); + map->addblock(&hd->bl); clif->spawn(&hd->bl); clif->send_homdata(sd,SP_ACK,0); clif->hominfo(sd,hd,1); @@ -890,7 +896,7 @@ bool homunculus_creation_request(struct map_session_data *sd, int class_) { hom.luk = base->luk *10; // Request homunculus creation - intif_homunculus_create(sd->status.account_id, &hom); + intif->homunculus_create(sd->status.account_id, &hom); return true; } @@ -902,14 +908,14 @@ bool homunculus_ressurect(struct map_session_data* sd, unsigned char per, short return false; // no homunculus if (!sd->hd) //Load homun data; - return intif_homunculus_requestload(sd->status.account_id, sd->status.hom_id); + return intif->homunculus_requestload(sd->status.account_id, sd->status.hom_id); hd = sd->hd; - if (hd->homunculus.vaporize) + if (hd->homunculus.vaporize != HOM_ST_ACTIVE) return false; // vaporized homunculi need to be 'called' - if (!status_isdead(&hd->bl)) + if (!status->isdead(&hd->bl)) return false; // already alive homun->init_timers(hd); @@ -919,10 +925,10 @@ bool homunculus_ressurect(struct map_session_data* sd, unsigned char per, short hd->bl.m = sd->bl.m; hd->bl.x = x; hd->bl.y = y; - iMap->addblock(&hd->bl); + map->addblock(&hd->bl); clif->spawn(&hd->bl); } - status_revive(&hd->bl, per, 0); + status->revive(&hd->bl, per, 0); return true; } @@ -1001,7 +1007,7 @@ bool homunculus_shuffle(struct homun_data *hd) { memcpy(&hd->homunculus.hskill, &b_skill, sizeof(b_skill)); hd->homunculus.skillpts = skillpts; clif->homskillinfoblock(sd); - status_calc_homunculus(hd,0); + status_calc_homunculus(hd,SCO_NONE); status_percent_heal(&hd->bl, 100, 100); clif->specialeffect(&hd->bl,568,AREA); @@ -1125,16 +1131,16 @@ void homunculus_read_db(void) { memset(homun->db,0,sizeof(homun->db)); for(i = 0; i<ARRAYLENGTH(filename); i++) { if( i > 0 ) { - char path[256]; + char filepath[256]; - sprintf(path, "%s/%s", iMap->db_path, filename[i]); + sprintf(filepath, "%s/%s", map->db_path, filename[i]); - if( !exists(path) ) { + if( !exists(filepath) ) { continue; } } - sv->readdb(iMap->db_path, filename[i], ',', 50, 50, MAX_HOMUNCULUS_CLASS, homun->read_db_sub); + sv->readdb(map->db_path, filename[i], ',', 50, 50, MAX_HOMUNCULUS_CLASS, homun->read_db_sub); } } @@ -1144,14 +1150,14 @@ bool homunculus_read_skill_db_sub(char* split[], int columns, int current) { int j; int minJobLevelPresent = 0; - if( columns == 14 ) - minJobLevelPresent = 1; // MinJobLvl has been added + if( columns == 15 ) + minJobLevelPresent = 1; // MinJobLvl has been added - FIXME: is this extra field even needed anymore? // check for bounds [celest] classid = atoi(split[0]) - HM_CLASS_BASE; if ( classid >= MAX_HOMUNCULUS_CLASS ) { - ShowWarning("homunculus_read_skill_db_sub: Invalud homunculus class %d.\n", atoi(split[0])); + ShowWarning("homunculus_read_skill_db_sub: Invalid homunculus class %d.\n", atoi(split[0])); return false; } @@ -1178,9 +1184,27 @@ bool homunculus_read_skill_db_sub(char* split[], int columns, int current) { return true; } +int8 homunculus_get_intimacy_grade(struct homun_data *hd) { + unsigned int val = hd->homunculus.intimacy / 100; + if( val > 100 ) { + if( val > 250 ) { + if( val > 750 ) { + if ( val > 900 ) + return 4; + else + return 3; + } else + return 2; + } else + return 1; + } + + return 0; +} + void homunculus_skill_db_read(void) { memset(homun->skill_tree,0,sizeof(homun->skill_tree)); - sv->readdb(iMap->db_path, "homun_skill_tree.txt", ',', 13, 15, -1, homun->read_skill_db_sub); + sv->readdb(map->db_path, "homun_skill_tree.txt", ',', 13, 15, -1, homun->read_skill_db_sub); } @@ -1194,7 +1218,7 @@ void homunculus_exp_db_read(void) { memset(homun->exptable,0,sizeof(homun->exptable)); for(i = 0; i < 2; i++) { - sprintf(line, "%s/%s", iMap->db_path, filename[i]); + sprintf(line, "%s/%s", map->db_path, filename[i]); if( (fp=fopen(line,"r")) == NULL) { if(i != 0) continue; @@ -1205,7 +1229,7 @@ void homunculus_exp_db_read(void) { if(line[0] == '/' && line[1] == '/') continue; - if (!(homun->exptable[j++] = strtoul(line, NULL, 10))) + if (!(homun->exptable[j++] = (unsigned int)strtoul(line, NULL, 10))) break; } // Last permitted level have to be 0! @@ -1227,13 +1251,17 @@ void homunculus_skill_reload(void) { homun->skill_db_read(); } -void do_init_homunculus(void) { +void do_init_homunculus(bool minimal) { int class_; + + if (minimal) + return; + homun->read_db(); homun->exp_db_read(); homun->skill_db_read(); // Add homunc timer function to timer func list [Toms] - iTimer->add_timer_func_list(homun->hunger_timer, "homunculus_hunger_timer"); + timer->add_func_list(homun->hunger_timer, "homunculus_hunger_timer"); //Stock view data for homuncs memset(&homun->viewdb, 0, sizeof(homun->viewdb)); @@ -1293,4 +1321,7 @@ void homunculus_defaults(void) { homun->read_skill_db_sub = homunculus_read_skill_db_sub; homun->skill_db_read = homunculus_skill_db_read; homun->exp_db_read = homunculus_exp_db_read; + homun->addspiritball = homunculus_addspiritball; + homun->delspiritball = homunculus_delspiritball; + homun->get_intimacy_grade = homunculus_get_intimacy_grade; } diff --git a/src/map/homunculus.h b/src/map/homunculus.h index 86d437e73..25ccabf48 100644 --- a/src/map/homunculus.h +++ b/src/map/homunculus.h @@ -2,16 +2,17 @@ // See the LICENSE file // Portions Copyright (c) Athena Dev Teams -#ifndef _HOMUNCULUS_H_ -#define _HOMUNCULUS_H_ +#ifndef MAP_HOMUNCULUS_H +#define MAP_HOMUNCULUS_H +#include "pc.h" #include "status.h" // struct status_data, struct status_change #include "unit.h" // struct unit_data -#include "pc.h" +#include "../common/mmo.h" #define MAX_HOM_SKILL_REQUIRE 5 -#define homdb_checkid(id) (id >= HM_CLASS_BASE && id <= HM_CLASS_MAX) -#define homun_alive(x) ((x) && (x)->homunculus.vaporize != 1 && (x)->battle_status.hp > 0) +#define homdb_checkid(id) ((id) >= HM_CLASS_BASE && (id) <= HM_CLASS_MAX) +#define homun_alive(x) ((x) && (x)->homunculus.vaporize == HOM_ST_ACTIVE && (x)->battle_status.hp > 0) struct h_stats { unsigned int HP, SP; @@ -28,8 +29,6 @@ struct s_homunculus_db { unsigned char element, race, base_size, evo_size; }; -extern struct s_homunculus_db homunculus_db[MAX_HOMUNCULUS_CLASS]; - enum { HOMUNCULUS_CLASS, HOMUNCULUS_FOOD @@ -46,6 +45,12 @@ enum { SP_HUNGRY = 0x2, }; +enum homun_state { + HOM_ST_ACTIVE = 0,/* either alive or dead */ + HOM_ST_REST = 1,/* is resting (vaporized) */ + HOM_ST_MORPH = 2,/* in morph state */ +}; + struct homun_data { struct block_list bl; struct unit_data ud; @@ -53,13 +58,15 @@ struct homun_data { struct status_data base_status, battle_status; struct status_change sc; struct regen_data regen; - struct s_homunculus_db *homunculusDB; //[orn] - struct s_homunculus homunculus; //[orn] + struct s_homunculus_db *homunculusDB; //[orn] + struct s_homunculus homunculus; //[orn] - struct map_session_data *master; //pointer back to its master - int hungry_timer; //[orn] + struct map_session_data *master; //pointer back to its master + int hungry_timer; //[orn] unsigned int exp_next; - char blockskill[MAX_SKILL]; // [orn] + char blockskill[MAX_SKILL]; // [orn] + + int64 masterteleport_timer; }; struct homun_skill_tree_entry { @@ -74,9 +81,10 @@ struct homun_skill_tree_entry { }; // Celest enum homun_type { - HT_REG = 0x1, - HT_EVO = 0x2, - HT_S = 0x4, + HT_REG, // Regular Homunculus + HT_EVO, // Evolved Homunculus + HT_S, // Homunculus S + HT_INVALID = -1, // Invalid Homunculus }; /* homunculus.c interface */ @@ -86,7 +94,7 @@ struct homunculus_interface { struct s_homunculus_db db[MAX_HOMUNCULUS_CLASS]; struct homun_skill_tree_entry skill_tree[MAX_HOMUNCULUS_CLASS][MAX_SKILL_TREE]; /* */ - void (*init) (void); + void (*init) (bool minimal); void (*final) (void); void (*reload) (void); void (*reload_skill) (void); @@ -95,7 +103,7 @@ struct homunculus_interface { enum homun_type (*class2type) (int class_); void (*damaged) (struct homun_data *hd); int (*dead) (struct homun_data *hd); - int (*vaporize) (struct map_session_data *sd, int flag); + int (*vaporize) (struct map_session_data *sd, enum homun_state flag); int (*delete) (struct homun_data *hd, int emote); int (*checkskill) (struct homun_data *hd, uint16 skill_id); int (*calc_skilltree) (struct homun_data *hd, int flag_evolve); @@ -112,7 +120,7 @@ struct homunculus_interface { void (*save) (struct homun_data *hd); unsigned char (*menu) (struct map_session_data *sd,unsigned char menu_num); bool (*feed) (struct map_session_data *sd, struct homun_data *hd); - int (*hunger_timer) (int tid, unsigned int tick, int id, intptr_t data); + int (*hunger_timer) (int tid, int64 tick, int id, intptr_t data); void (*hunger_timer_delete) (struct homun_data *hd); int (*change_name) (struct map_session_data *sd,char *name); bool (*change_name_ack) (struct map_session_data *sd, char* name, int flag); @@ -133,10 +141,11 @@ struct homunculus_interface { void (*exp_db_read) (void); void (*addspiritball) (struct homun_data *hd, int max); void (*delspiritball) (struct homun_data *hd, int count, int type); -} homunculus_s; + int8 (*get_intimacy_grade) (struct homun_data *hd); +}; struct homunculus_interface *homun; void homunculus_defaults(void); -#endif /* _HOMUNCULUS_H_ */ +#endif /* MAP_HOMUNCULUS_H */ diff --git a/src/map/instance.c b/src/map/instance.c index 690f14cfe..5789d7dd6 100644 --- a/src/map/instance.c +++ b/src/map/instance.c @@ -2,36 +2,41 @@ // See the LICENSE file // Portions Copyright (c) Athena Dev Teams -#include "../common/cbasetypes.h" -#include "../common/socket.h" -#include "../common/timer.h" -#include "../common/malloc.h" -#include "../common/nullpo.h" -#include "../common/showmsg.h" -#include "../common/strlib.h" -#include "../common/utils.h" -#include "../common/db.h" +#define HERCULES_CORE -#include "clif.h" #include "instance.h" -#include "map.h" -#include "npc.h" -#include "party.h" -#include "pc.h" +#include <stdarg.h> #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <stdarg.h> #include <time.h> +#include "clif.h" +#include "map.h" +#include "npc.h" +#include "party.h" +#include "pc.h" +#include "../common/HPM.h" +#include "../common/cbasetypes.h" +#include "../common/db.h" +#include "../common/malloc.h" +#include "../common/nullpo.h" +#include "../common/showmsg.h" +#include "../common/socket.h" +#include "../common/strlib.h" +#include "../common/timer.h" +#include "../common/utils.h" + +struct instance_interface instance_s; + /// Checks whether given instance id is valid or not. bool instance_is_valid(int instance_id) { if( instance_id < 0 || instance_id >= instance->instances ) {// out of range return false; } - if( instances[instance_id].state == INSTANCE_FREE ) {// uninitialized/freed instance slot + if( instance->list[instance_id].state == INSTANCE_FREE ) {// uninitialized/freed instance slot return false; } @@ -46,17 +51,18 @@ bool instance_is_valid(int instance_id) { * On success return instance_id *--------------------------------------*/ int instance_create(int owner_id, const char *name, enum instance_owner_type type) { - unsigned short *iptr = NULL, *icptr = NULL; struct map_session_data *sd = NULL; + unsigned short *icptr = NULL; struct party_data *p = NULL; struct guild *g = NULL; + short *iptr = NULL; int i, j; switch ( type ) { case IOT_NONE: break; case IOT_CHAR: - if( ( sd = iMap->id2sd(owner_id) ) == NULL ) { + if( ( sd = map->id2sd(owner_id) ) == NULL ) { ShowError("instance_create: character %d not found for instance '%s'.\n", owner_id, name); return -2; } @@ -85,46 +91,49 @@ int instance_create(int owner_id, const char *name, enum instance_owner_type typ } if( type != IOT_NONE && *icptr ) { - ARR_FIND(0, *icptr, i, strcmp(instances[iptr[i]].name,name) == 0 ); + ARR_FIND(0, *icptr, i, strcmp(instance->list[iptr[i]].name,name) == 0 ); if( i != *icptr ) return -4;/* already got this instance */ } - ARR_FIND(0, instance->instances, i, instances[i].state == INSTANCE_FREE); - + ARR_FIND(0, instance->instances, i, instance->list[i].state == INSTANCE_FREE); + if( i == instance->instances ) - RECREATE(instances, struct instance_data, ++instance->instances); - - instances[i].state = INSTANCE_IDLE; - instances[i].id = i; - instances[i].idle_timer = INVALID_TIMER; - instances[i].idle_timeout = instances[i].idle_timeoutval = 0; - instances[i].progress_timer = INVALID_TIMER; - instances[i].progress_timeout = 0; - instances[i].users = 0; - instances[i].map = NULL; - instances[i].num_map = 0; - instances[i].owner_id = owner_id; - instances[i].owner_type = type; - instances[i].vars = idb_alloc(DB_OPT_RELEASE_DATA); - - safestrncpy( instances[i].name, name, sizeof(instances[i].name) ); - instances[i].map = NULL; + RECREATE(instance->list, struct instance_data, ++instance->instances); + + instance->list[i].state = INSTANCE_IDLE; + instance->list[i].id = i; + instance->list[i].idle_timer = INVALID_TIMER; + instance->list[i].idle_timeout = instance->list[i].idle_timeoutval = 0; + instance->list[i].progress_timer = INVALID_TIMER; + instance->list[i].progress_timeout = 0; + instance->list[i].users = 0; + instance->list[i].map = NULL; + instance->list[i].num_map = 0; + instance->list[i].owner_id = owner_id; + instance->list[i].owner_type = type; + instance->list[i].regs.vars = i64db_alloc(DB_OPT_RELEASE_DATA); + instance->list[i].regs.arrays = NULL; + instance->list[i].respawn.map = 0; + instance->list[i].respawn.y = 0; + instance->list[i].respawn.x = 0; + + safestrncpy( instance->list[i].name, name, sizeof(instance->list[i].name) ); if( type != IOT_NONE ) { - ARR_FIND(0, *icptr, j, iptr[j] == 0); + ARR_FIND(0, *icptr, j, iptr[j] == -1); if( j == *icptr ) { switch( type ) { case IOT_CHAR: - RECREATE(sd->instance, unsigned short, ++*icptr); + RECREATE(sd->instance, short, ++*icptr); sd->instance[sd->instances-1] = i; break; case IOT_PARTY: - RECREATE(p->instance, unsigned short, ++*icptr); + RECREATE(p->instance, short, ++*icptr); p->instance[p->instances-1] = i; break; case IOT_GUILD: - RECREATE(g->instance, unsigned short, ++*icptr); + RECREATE(g->instance, short, ++*icptr); g->instance[g->instances-1] = i; break; } @@ -140,7 +149,7 @@ int instance_create(int owner_id, const char *name, enum instance_owner_type typ * Add a map to the instance using src map "name" *--------------------------------------*/ int instance_add_map(const char *name, int instance_id, bool usebasename, const char *map_name) { - int16 m = iMap->mapname2mapid(name); + int16 m = map->mapname2mapid(name); int i, im = -1; size_t num_cell, size; @@ -152,68 +161,108 @@ int instance_add_map(const char *name, int instance_id, bool usebasename, const return -1; } - if( map_name != NULL && strdb_iget(mapindex_db, map_name) ) { + if( map_name != NULL && strdb_iget(mapindex->db, map_name) ) { ShowError("instance_add_map: trying to create instanced map with existent name '%s'\n", map_name); return -2; } - if( map[m].instance_id >= 0 ) { // Source map already belong to a Instance. + if( map->list[m].instance_id >= 0 ) { + // Source map already belong to a Instance. ShowError("instance_add_map: trying to instance already instanced map %s.\n", name); return -4; } - ARR_FIND( instance->start_id, iMap->map_num, i, !map[i].name[0] ); // Searching for a Free Map - - if( i < iMap->map_num ) + ARR_FIND( instance->start_id, map->count, i, map->list[i].name[0] == 0 ); // Searching for a Free Map + + if( i < map->count ) im = i; // Unused map found (old instance) else { - im = iMap->map_num; // Using next map index - RECREATE(map,struct map_data,++iMap->map_num); + im = map->count; // Using next map index + RECREATE(map->list,struct map_data,++map->count); } - if( map[m].cell == (struct mapcell *)0xdeadbeaf ) - iMap->cellfromcache(&map[m]); + if( map->list[m].cell == (struct mapcell *)0xdeadbeaf ) + map->cellfromcache(&map->list[m]); - memcpy( &map[im], &map[m], sizeof(struct map_data) ); // Copy source map + memcpy( &map->list[im], &map->list[m], sizeof(struct map_data) ); // Copy source map if( map_name != NULL ) { - snprintf(map[im].name, MAP_NAME_LENGTH, "%s", map_name); - map[im].cName = map[m].name; + snprintf(map->list[im].name, MAP_NAME_LENGTH, "%s", map_name); + map->list[im].custom_name = true; } else - snprintf(map[im].name, MAP_NAME_LENGTH, (usebasename ? "%.3d#%s" : "%.3d%s"), instance_id, name); // Generate Name for Instance Map - map[im].index = mapindex_addmap(-1, map[im].name); // Add map index + snprintf(map->list[im].name, MAP_NAME_LENGTH, (usebasename ? "%.3d#%s" : "%.3d%s"), instance_id, name); // Generate Name for Instance Map + map->list[im].index = mapindex->addmap(-1, map->list[im].name); // Add map index - map[im].channel = NULL; + map->list[im].channel = NULL; - if( !map[im].index ) { - map[im].name[0] = '\0'; + if( !map->list[im].index ) { + map->list[im].name[0] = '\0'; ShowError("instance_add_map: no more free map indexes.\n"); return -3; // No free map index } // Reallocate cells - num_cell = map[im].xs * map[im].ys; - CREATE( map[im].cell, struct mapcell, num_cell ); - memcpy( map[im].cell, map[m].cell, num_cell * sizeof(struct mapcell) ); + num_cell = map->list[im].xs * map->list[im].ys; + CREATE( map->list[im].cell, struct mapcell, num_cell ); + memcpy( map->list[im].cell, map->list[m].cell, num_cell * sizeof(struct mapcell) ); - size = map[im].bxs * map[im].bys * sizeof(struct block_list*); - map[im].block = (struct block_list**)aCalloc(size, 1); - map[im].block_mob = (struct block_list**)aCalloc(size, 1); + size = map->list[im].bxs * map->list[im].bys * sizeof(struct block_list*); + map->list[im].block = (struct block_list**)aCalloc(size, 1); + map->list[im].block_mob = (struct block_list**)aCalloc(size, 1); - memset(map[im].npc, 0x00, sizeof(map[i].npc)); - map[im].npc_num = 0; + memset(map->list[im].npc, 0x00, sizeof(map->list[i].npc)); + map->list[im].npc_num = 0; - memset(map[im].moblist, 0x00, sizeof(map[im].moblist)); - map[im].mob_delete_timer = INVALID_TIMER; + memset(map->list[im].moblist, 0x00, sizeof(map->list[im].moblist)); + map->list[im].mob_delete_timer = INVALID_TIMER; - map[im].m = im; - map[im].instance_id = instance_id; - map[im].instance_src_map = m; - map[m].flag.src4instance = 1; // Flag this map as a src map for instances + //Mimic unit + if( map->list[m].unit_count ) { + map->list[im].unit_count = map->list[m].unit_count; + CREATE( map->list[im].units, struct mapflag_skill_adjust*, map->list[im].unit_count ); + + for(i = 0; i < map->list[im].unit_count; i++) { + CREATE( map->list[im].units[i], struct mapflag_skill_adjust, 1); + memcpy( map->list[im].units[i],map->list[m].units[i],sizeof(struct mapflag_skill_adjust)); + } + } + //Mimic skills + if( map->list[m].skill_count ) { + map->list[im].skill_count = map->list[m].skill_count; + CREATE( map->list[im].skills, struct mapflag_skill_adjust*, map->list[im].skill_count ); + + for(i = 0; i < map->list[im].skill_count; i++) { + CREATE( map->list[im].skills[i], struct mapflag_skill_adjust, 1); + memcpy( map->list[im].skills[i],map->list[m].skills[i],sizeof(struct mapflag_skill_adjust)); + } + } + //Mimic zone mf + if( map->list[m].zone_mf_count ) { + map->list[im].zone_mf_count = map->list[m].zone_mf_count; + CREATE( map->list[im].zone_mf, char *, map->list[im].zone_mf_count ); + + for(i = 0; i < map->list[im].zone_mf_count; i++) { + CREATE(map->list[im].zone_mf[i], char, MAP_ZONE_MAPFLAG_LENGTH); + safestrncpy(map->list[im].zone_mf[i],map->list[m].zone_mf[i],MAP_ZONE_MAPFLAG_LENGTH); + } + } + + //Mimic questinfo + if( map->list[m].qi_count ) { + map->list[im].qi_count = map->list[m].qi_count; + CREATE( map->list[im].qi_data, struct questinfo, map->list[im].qi_count ); + memcpy( map->list[im].qi_data, map->list[m].qi_data, map->list[im].qi_count * sizeof(struct questinfo) ); + } + + map->list[im].m = im; + map->list[im].instance_id = instance_id; + map->list[im].instance_src_map = m; + map->list[im].flag.src4instance = 0; //clear + map->list[m].flag.src4instance = 1; // Flag this map as a src map for instances - RECREATE(instances[instance_id].map, unsigned short, ++instances[instance_id].num_map); + RECREATE(instance->list[instance_id].map, unsigned short, ++instance->list[instance_id].num_map); - instances[instance_id].map[instances[instance_id].num_map - 1] = im; // Attach to actual instance - iMap->addmap2db(&map[im]); + instance->list[instance_id].map[instance->list[instance_id].num_map - 1] = im; // Attach to actual instance + map->addmap2db(&map->list[im]); return im; } @@ -230,22 +279,37 @@ int instance_map2imap(int16 m, int instance_id) { return -1; } - for( i = 0; i < instances[instance_id].num_map; i++ ) { - if( instances[instance_id].map[i] && map[instances[instance_id].map[i]].instance_src_map == m ) - return instances[instance_id].map[i]; + for( i = 0; i < instance->list[instance_id].num_map; i++ ) { + if( instance->list[instance_id].map[i] && map->list[instance->list[instance_id].map[i]].instance_src_map == m ) + return instance->list[instance_id].map[i]; } return -1; } +int instance_mapname2imap(const char *map_name, int instance_id) { + int i; + + if( !instance->valid(instance_id) ) { + return -1; + } + + for( i = 0; i < instance->list[instance_id].num_map; i++ ) { + if( instance->list[instance_id].map[i] && !strcmpi(map->list[map->list[instance->list[instance_id].map[i]].instance_src_map].name,map_name) ) + return instance->list[instance_id].map[i]; + } + return -1; +} + + /*-------------------------------------- * m : source map * instance_id : where to search * result : mapid of map "m" in this instance *--------------------------------------*/ int instance_mapid2imapid(int16 m, int instance_id) { - if( map[m].flag.src4instance == 0 ) + if( map->list[m].flag.src4instance == 0 ) return m; // not instances found for this map - else if( map[m].instance_id >= 0 ) { // This map is a instance, not a src map instance + else if( map->list[m].instance_id >= 0 ) { // This map is a instance, not a src map instance ShowError("map_instance_mapid2imapid: already instanced (%d / %d)\n", m, instance_id); return -1; } @@ -257,19 +321,31 @@ int instance_mapid2imapid(int16 m, int instance_id) { } /*-------------------------------------- - * map_instance_map_npcsub * Used on Init instance. Duplicates each script on source map *--------------------------------------*/ int instance_map_npcsub(struct block_list* bl, va_list args) { struct npc_data* nd = (struct npc_data*)bl; int16 m = va_arg(args, int); // Destination Map - if ( npc_duplicate4instance(nd, m) ) + if ( npc->duplicate4instance(nd, m) ) ShowDebug("instance_map_npcsub:npc_duplicate4instance failed (%s/%d)\n",nd->name,m); return 1; } +int instance_init_npc(struct block_list* bl, va_list args) { + struct npc_data *nd = (struct npc_data*)bl; + struct event_data *ev; + char evname[EVENT_NAME_LENGTH]; + + snprintf(evname, EVENT_NAME_LENGTH, "%s::OnInstanceInit", nd->exname); + + if( ( ev = strdb_get(npc->ev_db, evname) ) ) + script->run(ev->nd->u.scr.script, ev->pos, 0, ev->nd->bl.id); + + return 1; +} + /*-------------------------------------- * Init all map on the instance. Npcs are created here *--------------------------------------*/ @@ -279,10 +355,13 @@ void instance_init(int instance_id) { if( !instance->valid(instance_id) ) return; // nothing to do - for( i = 0; i < instances[instance_id].num_map; i++ ) - iMap->foreachinmap(instance_map_npcsub, map[instances[instance_id].map[i]].instance_src_map, BL_NPC, instances[instance_id].map[i]); + for( i = 0; i < instance->list[instance_id].num_map; i++ ) + map->foreachinmap(instance->map_npcsub, map->list[instance->list[instance_id].map[i]].instance_src_map, BL_NPC, instance->list[instance_id].map[i]); - instances[instance_id].state = INSTANCE_BUSY; + /* cant be together with the previous because it will rely on all of them being up */ + map->foreachininstance(instance->init_npc, instance_id, BL_NPC); + + instance->list[instance_id].state = INSTANCE_BUSY; } /*-------------------------------------- @@ -305,19 +384,19 @@ int instance_cleanup_sub(struct block_list *bl, va_list ap) { switch(bl->type) { case BL_PC: - iMap->quit((struct map_session_data *) bl); + map->quit((struct map_session_data *) bl); break; case BL_NPC: - npc_unload((struct npc_data *)bl,true); + npc->unload((struct npc_data *)bl,true); break; case BL_MOB: - unit_free(bl,CLR_OUTSIGHT); + unit->free(bl,CLR_OUTSIGHT); break; case BL_PET: //There is no need for this, the pet is removed together with the player. [Skotlex] break; case BL_ITEM: - iMap->clearflooritem(bl); + map->clearflooritem(bl); break; case BL_SKILL: skill->delunit((struct skill_unit *) bl); @@ -333,51 +412,79 @@ int instance_cleanup_sub(struct block_list *bl, va_list ap) { void instance_del_map(int16 m) { int i; - if( m <= 0 || map[m].instance_id == -1 ) { + if( m <= 0 || map->list[m].instance_id == -1 ) { ShowError("instance_del_map: tried to remove non-existing instance map (%d)\n", m); return; } - iMap->map_foreachpc(instance_del_load, m); - iMap->foreachinmap(instance_cleanup_sub, m, BL_ALL); + map->foreachpc(instance_del_load, m); + map->foreachinmap(instance_cleanup_sub, m, BL_ALL); - if( map[m].mob_delete_timer != INVALID_TIMER ) - iTimer->delete_timer(map[m].mob_delete_timer, iMap->removemobs_timer); + if( map->list[m].mob_delete_timer != INVALID_TIMER ) + timer->delete(map->list[m].mob_delete_timer, map->removemobs_timer); - mapindex_removemap( map[m].index ); + mapindex->removemap(map_id2index(m)); // Free memory - aFree(map[m].cell); - aFree(map[m].block); - aFree(map[m].block_mob); + aFree(map->list[m].cell); + aFree(map->list[m].block); + aFree(map->list[m].block_mob); + + if( map->list[m].unit_count ) { + for(i = 0; i < map->list[m].unit_count; i++) { + aFree(map->list[m].units[i]); + } + if( map->list[m].units ) + aFree(map->list[m].units); + } + + if( map->list[m].skill_count ) { + for(i = 0; i < map->list[m].skill_count; i++) { + aFree(map->list[m].skills[i]); + } + if( map->list[m].skills ) + aFree(map->list[m].skills); + } + + if( map->list[m].zone_mf_count ) { + for(i = 0; i < map->list[m].zone_mf_count; i++) { + aFree(map->list[m].zone_mf[i]); + } + if( map->list[m].zone_mf ) + aFree(map->list[m].zone_mf); + } + + if( map->list[m].qi_data ) + aFree(map->list[m].qi_data); // Remove from instance - for( i = 0; i < instances[map[m].instance_id].num_map; i++ ) { - if( instances[map[m].instance_id].map[i] == m ) { - instances[map[m].instance_id].num_map--; - for( ; i < instances[map[m].instance_id].num_map; i++ ) - instances[map[m].instance_id].map[i] = instances[map[m].instance_id].map[i+1]; + for( i = 0; i < instance->list[map->list[m].instance_id].num_map; i++ ) { + if( instance->list[map->list[m].instance_id].map[i] == m ) { + instance->list[map->list[m].instance_id].num_map--; + for( ; i < instance->list[map->list[m].instance_id].num_map; i++ ) + instance->list[map->list[m].instance_id].map[i] = instance->list[map->list[m].instance_id].map[i+1]; i = -1; break; } } - if( i == instances[map[m].instance_id].num_map ) - ShowError("map_instance_del: failed to remove %s from instance list (%s): %d\n", map[m].name, instances[map[m].instance_id].name, m); + if( i == instance->list[map->list[m].instance_id].num_map ) + ShowError("map_instance_del: failed to remove %s from instance list (%s): %d\n", map->list[m].name, instance->list[map->list[m].instance_id].name, m); - if( map[m].channel ) - clif->chsys_delete(map[m].channel); - - iMap->removemapdb(&map[m]); - memset(&map[m], 0x00, sizeof(map[0])); - map[m].instance_id = -1; - map[m].mob_delete_timer = INVALID_TIMER; + if( map->list[m].channel ) + clif->chsys_delete(map->list[m].channel); + + map->removemapdb(&map->list[m]); + memset(&map->list[m], 0x00, sizeof(map->list[0])); + map->list[m].name[0] = 0; + map->list[m].instance_id = -1; + map->list[m].mob_delete_timer = INVALID_TIMER; } /*-------------------------------------- * Timer to destroy instance by process or idle *--------------------------------------*/ -int instance_destroy_timer(int tid, unsigned int tick, int id, intptr_t data) { +int instance_destroy_timer(int tid, int64 tick, int id, intptr_t data) { instance->destroy(id); return 0; } @@ -386,79 +493,96 @@ int instance_destroy_timer(int tid, unsigned int tick, int id, intptr_t data) { * Removes a instance, all its maps and npcs. *--------------------------------------*/ void instance_destroy(int instance_id) { - unsigned short *iptr = NULL, *icptr = NULL; struct map_session_data *sd = NULL; + unsigned short *icptr = NULL; struct party_data *p = NULL; struct guild *g = NULL; - int last = 0, type, j; + short *iptr = NULL; + int type, j, last = 0; unsigned int now = (unsigned int)time(NULL); - + if( !instance->valid(instance_id) ) return; // nothing to do - if( instances[instance_id].progress_timeout && instances[instance_id].progress_timeout <= now ) + if( instance->list[instance_id].progress_timeout && instance->list[instance_id].progress_timeout <= now ) type = 1; - else if( instances[instance_id].idle_timeout && instances[instance_id].idle_timeout <= now ) + else if( instance->list[instance_id].idle_timeout && instance->list[instance_id].idle_timeout <= now ) type = 2; else type = 3; - + clif->instance(instance_id, 5, type); // Report users this instance has been destroyed - switch ( instances[instance_id].owner_type ) { + switch ( instance->list[instance_id].owner_type ) { case IOT_NONE: break; case IOT_CHAR: - if( ( sd = iMap->id2sd(instances[instance_id].owner_id) ) == NULL ) { + if( ( sd = map->id2sd(instance->list[instance_id].owner_id) ) == NULL ) { break; } iptr = sd->instance; icptr = &sd->instances; break; case IOT_PARTY: - if( ( p = party->search(instances[instance_id].owner_id) ) == NULL ) { + if( ( p = party->search(instance->list[instance_id].owner_id) ) == NULL ) { break; } iptr = p->instance; icptr = &p->instances; break; case IOT_GUILD: - if( ( g = guild->search(instances[instance_id].owner_id) ) == NULL ) { + if( ( g = guild->search(instance->list[instance_id].owner_id) ) == NULL ) { break; } iptr = g->instance; icptr = &g->instances; break; default: - ShowError("instance_destroy: unknown type %d for owner_id %d and name %s.\n", instances[instance_id].owner_type,instances[instance_id].owner_id,instances[instance_id].name); + ShowError("instance_destroy: unknown type %d for owner_id %d and name '%s'.\n", instance->list[instance_id].owner_type,instance->list[instance_id].owner_id,instance->list[instance_id].name); break; } if( iptr != NULL ) { ARR_FIND(0, *icptr, j, iptr[j] == instance_id); if( j != *icptr ) - iptr[j] = 0; + iptr[j] = -1; } - while( instances[instance_id].num_map && last != instances[instance_id].map[0] ) { // Remove all maps from instance - last = instances[instance_id].map[0]; - instance->del_map( instances[instance_id].map[0] ); + while( instance->list[instance_id].num_map && last != instance->list[instance_id].map[0] ) { // Remove all maps from instance + last = instance->list[instance_id].map[0]; + instance->del_map( instance->list[instance_id].map[0] ); } + + if( instance->list[instance_id].regs.vars ) + db_destroy(instance->list[instance_id].regs.vars); + if( instance->list[instance_id].regs.arrays ) + instance->list[instance_id].regs.arrays->destroy(instance->list[instance_id].regs.arrays, script->array_free_db); - if( instances[instance_id].vars ) - db_destroy(instances[instance_id].vars); - - if( instances[instance_id].progress_timer != INVALID_TIMER ) - iTimer->delete_timer( instances[instance_id].progress_timer, instance_destroy_timer); - if( instances[instance_id].idle_timer != INVALID_TIMER ) - iTimer->delete_timer( instances[instance_id].idle_timer, instance_destroy_timer); + if( instance->list[instance_id].progress_timer != INVALID_TIMER ) + timer->delete( instance->list[instance_id].progress_timer, instance->destroy_timer); + if( instance->list[instance_id].idle_timer != INVALID_TIMER ) + timer->delete( instance->list[instance_id].idle_timer, instance->destroy_timer); - instances[instance_id].vars = NULL; + instance->list[instance_id].regs.vars = NULL; - aFree(instances[instance_id].map); + if( instance->list[instance_id].map ) + aFree(instance->list[instance_id].map); - memset( &instances[instance_id], 0x00, sizeof(struct instance_data) ); - + instance->list[instance_id].map = NULL; + instance->list[instance_id].state = INSTANCE_FREE; + instance->list[instance_id].num_map = 0; + + for( j = 0; j < instance->list[instance_id].hdatac; j++ ) { + if( instance->list[instance_id].hdata[j]->flag.free ) { + aFree(instance->list[instance_id].hdata[j]->data); + } + aFree(instance->list[instance_id].hdata[j]); + } + if( instance->list[instance_id].hdata ) + aFree(instance->list[instance_id].hdata); + + instance->list[instance_id].hdata = NULL; + instance->list[instance_id].hdatac = 0; } /*-------------------------------------- @@ -468,20 +592,20 @@ void instance_check_idle(int instance_id) { bool idle = true; unsigned int now = (unsigned int)time(NULL); - if( !instance->valid(instance_id) || instances[instance_id].idle_timeoutval == 0 ) + if( !instance->valid(instance_id) || instance->list[instance_id].idle_timeoutval == 0 ) return; - if( instances[instance_id].users ) + if( instance->list[instance_id].users ) idle = false; - if( instances[instance_id].idle_timer != INVALID_TIMER && !idle ) { - iTimer->delete_timer(instances[instance_id].idle_timer, instance_destroy_timer); - instances[instance_id].idle_timer = INVALID_TIMER; - instances[instance_id].idle_timeout = 0; + if( instance->list[instance_id].idle_timer != INVALID_TIMER && !idle ) { + timer->delete(instance->list[instance_id].idle_timer, instance->destroy_timer); + instance->list[instance_id].idle_timer = INVALID_TIMER; + instance->list[instance_id].idle_timeout = 0; clif->instance(instance_id, 3, 0); // Notify instance users normal instance expiration - } else if( instances[instance_id].idle_timer == INVALID_TIMER && idle ) { - instances[instance_id].idle_timeout = now + instances[instance_id].idle_timeoutval; - instances[instance_id].idle_timer = iTimer->add_timer( iTimer->gettick() + instances[instance_id].idle_timeoutval * 1000, instance_destroy_timer, instance_id, 0); + } else if( instance->list[instance_id].idle_timer == INVALID_TIMER && idle ) { + instance->list[instance_id].idle_timeout = now + instance->list[instance_id].idle_timeoutval; + instance->list[instance_id].idle_timer = timer->add( timer->gettick() + instance->list[instance_id].idle_timeoutval * 1000, instance->destroy_timer, instance_id, 0); clif->instance(instance_id, 4, 0); // Notify instance users it will be destroyed of no user join it again in "X" time } } @@ -496,30 +620,32 @@ void instance_set_timeout(int instance_id, unsigned int progress_timeout, unsign if( !instance->valid(instance_id) ) return; - if( instances[instance_id].progress_timer != INVALID_TIMER ) - iTimer->delete_timer( instances[instance_id].progress_timer, instance_destroy_timer); - if( instances[instance_id].idle_timer != INVALID_TIMER ) - iTimer->delete_timer( instances[instance_id].idle_timer, instance_destroy_timer); + if( instance->list[instance_id].progress_timer != INVALID_TIMER ) + timer->delete( instance->list[instance_id].progress_timer, instance->destroy_timer); + if( instance->list[instance_id].idle_timer != INVALID_TIMER ) + timer->delete( instance->list[instance_id].idle_timer, instance->destroy_timer); if( progress_timeout ) { - instances[instance_id].progress_timeout = now + progress_timeout; - instances[instance_id].progress_timer = iTimer->add_timer( iTimer->gettick() + progress_timeout * 1000, instance_destroy_timer, instance_id, 0); + instance->list[instance_id].progress_timeout = now + progress_timeout; + instance->list[instance_id].progress_timer = timer->add( timer->gettick() + progress_timeout * 1000, instance->destroy_timer, instance_id, 0); + instance->list[instance_id].original_progress_timeout = progress_timeout; } else { - instances[instance_id].progress_timeout = 0; - instances[instance_id].progress_timer = INVALID_TIMER; + instance->list[instance_id].progress_timeout = 0; + instance->list[instance_id].progress_timer = INVALID_TIMER; + instance->list[instance_id].original_progress_timeout = 0; } if( idle_timeout ) { - instances[instance_id].idle_timeoutval = idle_timeout; - instances[instance_id].idle_timer = INVALID_TIMER; - instance_check_idle(instance_id); + instance->list[instance_id].idle_timeoutval = idle_timeout; + instance->list[instance_id].idle_timer = INVALID_TIMER; + instance->check_idle(instance_id); } else { - instances[instance_id].idle_timeoutval = 0; - instances[instance_id].idle_timeout = 0; - instances[instance_id].idle_timer = INVALID_TIMER; + instance->list[instance_id].idle_timeoutval = 0; + instance->list[instance_id].idle_timeout = 0; + instance->list[instance_id].idle_timer = INVALID_TIMER; } - if( instances[instance_id].idle_timer == INVALID_TIMER && instances[instance_id].progress_timer != INVALID_TIMER ) + if( instance->list[instance_id].idle_timer == INVALID_TIMER && instance->list[instance_id].progress_timer != INVALID_TIMER ) clif->instance(instance_id, 3, 0); } @@ -530,26 +656,64 @@ void instance_check_kick(struct map_session_data *sd) { int16 m = sd->bl.m; clif->instance_leave(sd->fd); - if( map[m].instance_id >= 0 ) { // User was on the instance map - if( map[m].save.map ) - pc->setpos(sd, map[m].save.map, map[m].save.x, map[m].save.y, CLR_TELEPORT); + if( map->list[m].instance_id >= 0 ) { // User was on the instance map + if( map->list[m].save.map ) + pc->setpos(sd, map->list[m].save.map, map->list[m].save.x, map->list[m].save.y, CLR_TELEPORT); else pc->setpos(sd, sd->status.save_point.map, sd->status.save_point.x, sd->status.save_point.y, CLR_TELEPORT); } } +void do_reload_instance(void) { + struct s_mapiterator *iter; + struct map_session_data *sd; + int i, k; + + for(i = 0; i < instance->instances; i++) { + for(k = 0; k < instance->list[i].num_map; k++) { + if( !map->list[map->list[instance->list[i].map[k]].instance_src_map].flag.src4instance ) + break; + } + + if( k != instance->list[i].num_map ) /* any (or all) of them were disabled, we destroy */ + instance->destroy(i); + else { + /* populate the instance again */ + instance->start(i); + /* restart timers */ + instance->set_timeout(i,instance->list[i].original_progress_timeout,instance->list[i].idle_timeoutval); + } + } + + iter = mapit_getallusers(); + for( sd = (TBL_PC*)mapit->first(iter); mapit->exists(iter); sd = (TBL_PC*)mapit->next(iter) ) { + if(sd && map->list[sd->bl.m].instance_id >= 0) { + pc->setpos(sd,instance->list[map->list[sd->bl.m].instance_id].respawn.map,instance->list[map->list[sd->bl.m].instance_id].respawn.x,instance->list[map->list[sd->bl.m].instance_id].respawn.y,CLR_TELEPORT); + } + } + mapit->free(iter); +} + + void do_final_instance(void) { int i; - + for(i = 0; i < instance->instances; i++) { - instance_destroy(i); + instance->destroy(i); } - aFree(instances); + if( instance->list ) + aFree(instance->list); + + instance->list = NULL; + instance->instances = 0; } -void do_init_instance(void) { - iTimer->add_timer_func_list(instance_destroy_timer, "instance_destroy_timer"); +void do_init_instance(bool minimal) { + if (minimal) + return; + + timer->add_func_list(instance->destroy_timer, "instance_destroy_timer"); } void instance_defaults(void) { @@ -557,22 +721,27 @@ void instance_defaults(void) { instance->init = do_init_instance; instance->final = do_final_instance; - + instance->reload = do_reload_instance; /* start point */ instance->start_id = 0; /* count */ instance->instances = 0; - + /* */ + instance->list = NULL; /* */ instance->create = instance_create; instance->add_map = instance_add_map; instance->del_map = instance_del_map; instance->map2imap = instance_map2imap; instance->mapid2imapid = instance_mapid2imapid; + instance->mapname2imap = instance_mapname2imap; + instance->map_npcsub = instance_map_npcsub; + instance->init_npc = instance_init_npc; instance->destroy = instance_destroy; instance->start = instance_init; instance->check_idle = instance_check_idle; instance->check_kick = instance_check_kick; instance->set_timeout = instance_set_timeout; instance->valid = instance_is_valid; + instance->destroy_timer = instance_destroy_timer; } diff --git a/src/map/instance.h b/src/map/instance.h index e86586e44..2ee77d3e3 100644 --- a/src/map/instance.h +++ b/src/map/instance.h @@ -2,8 +2,15 @@ // See the LICENSE file // Portions Copyright (c) Athena Dev Teams -#ifndef _INSTANCE_H_ -#define _INSTANCE_H_ +#ifndef MAP_INSTANCE_H +#define MAP_INSTANCE_H + +#include "script.h" // struct reg_db +#include "../common/cbasetypes.h" +#include "../common/mmo.h" // struct point + +struct block_list; +struct map_session_data; #define INSTANCE_NAME_LENGTH (60+1) @@ -24,7 +31,7 @@ enum instance_owner_type { struct instance_data { unsigned short id; - char name[INSTANCE_NAME_LENGTH]; // Instance Name - required for clif functions. + char name[INSTANCE_NAME_LENGTH]; ///< Instance Name - required for clif functions. instance_state state; enum instance_owner_type owner_type; int owner_id; @@ -33,39 +40,52 @@ struct instance_data { unsigned short num_map; unsigned short users; - struct DBMap* vars; // Instance Variable for scripts - + struct reg_db regs; ///< Instance variables for scripts + int progress_timer; unsigned int progress_timeout; int idle_timer; unsigned int idle_timeout, idle_timeoutval; + + unsigned int original_progress_timeout; + + struct point respawn; ///< reload spawn + + /** HPM Custom Struct */ + struct HPluginData **hdata; + unsigned int hdatac; }; -struct instance_data *instances; - struct instance_interface { - void (*init) (void); + void (*init) (bool minimal); void (*final) (void); + void (*reload) (void); /* start point */ unsigned short start_id; - unsigned short instances; + unsigned short instances;/* count */ + /* */ + struct instance_data *list;/* pointer to a chunk of consecutive memory, access via instance->list[0]..etc */ /* */ int (*create) (int party_id, const char *name, enum instance_owner_type type); int (*add_map) (const char *name, int instance_id, bool usebasename, const char *map_name); void (*del_map) (int16 m); int (*map2imap) (int16 m, int instance_id); int (*mapid2imapid) (int16 m, int instance_id); + int (*mapname2imap) (const char *map_name, int instance_id); + int (*map_npcsub) (struct block_list* bl, va_list args); + int (*init_npc) (struct block_list* bl, va_list args); void (*destroy) (int instance_id); void (*start) (int instance_id); void (*check_idle) (int instance_id); void (*check_kick) (struct map_session_data *sd); void (*set_timeout) (int instance_id, unsigned int progress_timeout, unsigned int idle_timeout); bool (*valid) (int instance_id); -} instance_s; + int (*destroy_timer) (int tid, int64 tick, int id, intptr_t data); +}; struct instance_interface *instance; void instance_defaults(void); -#endif +#endif /* MAP_INSTANCE_H */ diff --git a/src/map/intif.c b/src/map/intif.c index f3931e79e..be82a7583 100644 --- a/src/map/intif.c +++ b/src/map/intif.c @@ -1,67 +1,58 @@ // Copyright (c) Athena Dev Teams - Licensed under GNU GPL // For more information, see LICENCE in the main folder -#include "../common/showmsg.h" -#include "../common/socket.h" -#include "../common/timer.h" -#include "../common/nullpo.h" -#include "../common/malloc.h" -#include "../common/strlib.h" -#include "map.h" +#define HERCULES_CORE + +#include "../config/core.h" // GP_BOUND_ITEMS +#include "intif.h" + +#include <fcntl.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> + +#include "atcommand.h" #include "battle.h" #include "chrif.h" #include "clif.h" -#include "pc.h" -#include "intif.h" -#include "log.h" -#include "storage.h" -#include "party.h" +#include "elemental.h" #include "guild.h" -#include "pet.h" -#include "atcommand.h" -#include "mercenary.h" #include "homunculus.h" -#include "elemental.h" +#include "log.h" #include "mail.h" +#include "map.h" +#include "mercenary.h" +#include "party.h" +#include "pc.h" +#include "pet.h" #include "quest.h" +#include "storage.h" +#include "../common/malloc.h" +#include "../common/nullpo.h" +#include "../common/showmsg.h" +#include "../common/socket.h" +#include "../common/strlib.h" +#include "../common/timer.h" -#include <sys/types.h> -#include <stdio.h> -#include <stdlib.h> -#include <signal.h> -#include <fcntl.h> -#include <string.h> - - -static const int packet_len_table[]={ - -1,-1,27,-1, -1, 0,37,-1, 0, 0, 0, 0, 0, 0, 0, 0, //0x3800-0x380f - 0, 0, 0, 0, 0, 0, 0, 0, -1,11, 0, 0, 0, 0, 0, 0, //0x3810 - 39,-1,15,15, 14,19, 7,-1, 0, 0, 0, 0, 0, 0, 0, 0, //0x3820 - 10,-1,15, 0, 79,19, 7,-1, 0,-1,-1,-1, 14,67,186,-1, //0x3830 - -1, 0, 0,14, 0, 0, 0, 0, -1,74,-1,11, 11,-1, 0, 0, //0x3840 - -1,-1, 7, 7, 7,11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3850 Auctions [Zephyrus] - -1, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3860 Quests [Kevin] [Inkfish] - -1, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 3, 3, 0, //0x3870 Mercenaries [Zephyrus] / Elemental [pakpil] - 11,-1, 7, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3880 - -1,-1, 7, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3890 Homunculus [albator] -}; +struct intif_interface intif_s; -extern int char_fd; // inter server Fd used for char_fd -#define inter_fd char_fd // alias +#define inter_fd (chrif->fd) // alias //----------------------------------------------------------------- // Send to inter server int CheckForCharServer(void) { - return ((char_fd <= 0) || session[char_fd] == NULL || session[char_fd]->wdata == NULL); + return ((chrif->fd <= 0) || session[chrif->fd] == NULL || session[chrif->fd]->wdata == NULL); } // pet int intif_create_pet(int account_id,int char_id,short pet_class,short pet_lv,short pet_egg_id, - short pet_equip,short intimate,short hungry,char rename_flag,char incuvate,char *pet_name) + short pet_equip,short intimate,short hungry,char rename_flag,char incubate,char *pet_name) { - if (CheckForCharServer()) + if (intif->CheckForCharServer()) return 0; WFIFOHEAD(inter_fd, 24 + NAME_LENGTH); WFIFOW(inter_fd,0) = 0x3080; @@ -74,7 +65,7 @@ int intif_create_pet(int account_id,int char_id,short pet_class,short pet_lv,sho WFIFOW(inter_fd,18) = intimate; WFIFOW(inter_fd,20) = hungry; WFIFOB(inter_fd,22) = rename_flag; - WFIFOB(inter_fd,23) = incuvate; + WFIFOB(inter_fd,23) = incubate; memcpy(WFIFOP(inter_fd,24),pet_name,NAME_LENGTH); WFIFOSET(inter_fd,24+NAME_LENGTH); @@ -83,7 +74,7 @@ int intif_create_pet(int account_id,int char_id,short pet_class,short pet_lv,sho int intif_request_petdata(int account_id,int char_id,int pet_id) { - if (CheckForCharServer()) + if (intif->CheckForCharServer()) return 0; WFIFOHEAD(inter_fd, 14); WFIFOW(inter_fd,0) = 0x3081; @@ -97,7 +88,7 @@ int intif_request_petdata(int account_id,int char_id,int pet_id) int intif_save_petdata(int account_id,struct s_pet *p) { - if (CheckForCharServer()) + if (intif->CheckForCharServer()) return 0; WFIFOHEAD(inter_fd, sizeof(struct s_pet) + 8); WFIFOW(inter_fd,0) = 0x3082; @@ -111,7 +102,7 @@ int intif_save_petdata(int account_id,struct s_pet *p) int intif_delete_petdata(int pet_id) { - if (CheckForCharServer()) + if (intif->CheckForCharServer()) return 0; WFIFOHEAD(inter_fd,6); WFIFOW(inter_fd,0) = 0x3083; @@ -123,7 +114,7 @@ int intif_delete_petdata(int pet_id) int intif_rename(struct map_session_data *sd, int type, char *name) { - if (CheckForCharServer()) + if (intif->CheckForCharServer()) return 1; WFIFOHEAD(inter_fd,NAME_LENGTH+12); @@ -137,17 +128,17 @@ int intif_rename(struct map_session_data *sd, int type, char *name) } // GM Send a message -int intif_broadcast(const char* mes, int len, int type) +int intif_broadcast(const char* mes, size_t len, int type) { - int lp = type ? 4 : 0; + int lp = (type|BC_COLOR_MASK) ? 4 : 0; // Send to the local players clif->broadcast(NULL, mes, len, type, ALL_CLIENT); - if (CheckForCharServer()) + if (intif->CheckForCharServer()) return 0; - if (other_mapserver_count < 1) + if (chrif->other_mapserver_count < 1) return 0; //No need to send. WFIFOHEAD(inter_fd, 16 + lp + len); @@ -158,24 +149,24 @@ int intif_broadcast(const char* mes, int len, int type) WFIFOW(inter_fd,10) = 0; // fontSize not used with standard broadcast WFIFOW(inter_fd,12) = 0; // fontAlign not used with standard broadcast WFIFOW(inter_fd,14) = 0; // fontY not used with standard broadcast - if (type == 0x10) // bc_blue + if( type|BC_BLUE ) WFIFOL(inter_fd,16) = 0x65756c62; //If there's "blue" at the beginning of the message, game client will display it in blue instead of yellow. - else if (type == 0x20) // bc_woe + else if( type|BC_WOE ) WFIFOL(inter_fd,16) = 0x73737373; //If there's "ssss", game client will recognize message as 'WoE broadcast'. memcpy(WFIFOP(inter_fd,16 + lp), mes, len); WFIFOSET(inter_fd, WFIFOW(inter_fd,2)); return 0; } -int intif_broadcast2(const char* mes, int len, unsigned long fontColor, short fontType, short fontSize, short fontAlign, short fontY) +int intif_broadcast2(const char* mes, size_t len, unsigned int fontColor, short fontType, short fontSize, short fontAlign, short fontY) { // Send to the local players clif->broadcast2(NULL, mes, len, fontColor, fontType, fontSize, fontAlign, fontY, ALL_CLIENT); - if (CheckForCharServer()) + if (intif->CheckForCharServer()) return 0; - if (other_mapserver_count < 1) + if (chrif->other_mapserver_count < 1) return 0; //No need to send. WFIFOHEAD(inter_fd, 16 + len); @@ -204,7 +195,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, 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 ); @@ -213,13 +204,13 @@ 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, char *nick, char *mes, int mes_len) +int intif_wis_message(struct map_session_data *sd, char *nick, char *mes, size_t mes_len) { nullpo_ret(sd); - if (CheckForCharServer()) + if (intif->CheckForCharServer()) return 0; - if (other_mapserver_count < 1) + if (chrif->other_mapserver_count < 1) { //Character not found. clif->wis_end(sd->fd, 1); return 0; @@ -242,12 +233,12 @@ int intif_wis_message(struct map_session_data *sd, char *nick, char *mes, int me // The reply of Wisp/page int intif_wis_replay(int id, int flag) { - if (CheckForCharServer()) + if (intif->CheckForCharServer()) return 0; WFIFOHEAD(inter_fd,7); WFIFOW(inter_fd,0) = 0x3002; WFIFOL(inter_fd,2) = id; - WFIFOB(inter_fd,6) = flag; // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target + WFIFOB(inter_fd,6) = flag; // flag: 0: success to send whisper, 1: target character is not logged in?, 2: ignored by target WFIFOSET(inter_fd,7); if (battle_config.etc_log) @@ -259,8 +250,8 @@ 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) { - int mes_len; - if (CheckForCharServer()) + size_t mes_len; + if (intif->CheckForCharServer()) return 0; mes_len = strlen(mes) + 1; // + null WFIFOHEAD(inter_fd, mes_len + 32); @@ -277,60 +268,117 @@ int intif_wis_message_to_gm(char *wisp_name, int permission, char *mes) return 0; } -int intif_regtostr(char* str, struct global_reg *reg, int qty) -{ - int len =0, i; - - for (i = 0; i < qty; i++) { - len+= sprintf(str+len, "%s", reg[i].str)+1; //We add 1 to consider the '\0' in place. - len+= sprintf(str+len, "%s", reg[i].value)+1; - } - return len; -} - //Request for saving registry values. -int intif_saveregistry(struct map_session_data *sd, int type) -{ - struct global_reg *reg; - int count; - int i, p; - - if (CheckForCharServer()) +int intif_saveregistry(struct map_session_data *sd) { + DBIterator *iter; + DBKey key; + DBData *data; + int plen = 0; + size_t len; + + if (intif->CheckForCharServer() || !sd->regs.vars) return -1; + + WFIFOHEAD(inter_fd, 60000 + 300); + WFIFOW(inter_fd,0) = 0x3004; + /* 0x2 = length (set later) */ + WFIFOL(inter_fd,4) = sd->status.account_id; + WFIFOL(inter_fd,8) = sd->status.char_id; + WFIFOW(inter_fd,12) = 0;/* count */ + + plen = 14; + + iter = db_iterator(sd->regs.vars); + for( data = iter->first(iter,&key); iter->exists(iter); data = iter->next(iter,&key) ) { + const char *varname = NULL; + struct script_reg_state *src = NULL; + + if( data->type != DB_DATA_PTR ) /* its a @number */ + continue; + + varname = script->get_str(script_getvarid(key.i64)); + + if( varname[0] == '@' ) /* @string$ can get here, so we skip */ + continue; + + src = DB->data2ptr(data); - switch (type) { - case 3: //Character reg - reg = sd->save_reg.global; - count = sd->save_reg.global_num; - sd->state.reg_dirty &= ~0x4; - break; - case 2: //Account reg - reg = sd->save_reg.account; - count = sd->save_reg.account_num; - sd->state.reg_dirty &= ~0x2; - break; - case 1: //Account2 reg - reg = sd->save_reg.account2; - count = sd->save_reg.account2_num; - sd->state.reg_dirty &= ~0x1; - break; - default: //Broken code? - ShowError("intif_saveregistry: Invalid type %d\n", type); - return -1; - } - WFIFOHEAD(inter_fd, 288 * MAX_REG_NUM+13); - WFIFOW(inter_fd,0)=0x3004; - WFIFOL(inter_fd,4)=sd->status.account_id; - WFIFOL(inter_fd,8)=sd->status.char_id; - WFIFOB(inter_fd,12)=type; - for( p = 13, i = 0; i < count; i++ ) { - if (reg[i].str[0] != '\0' && reg[i].value[0] != '\0') { - p+= sprintf((char*)WFIFOP(inter_fd,p), "%s", reg[i].str)+1; //We add 1 to consider the '\0' in place. - p+= sprintf((char*)WFIFOP(inter_fd,p), "%s", reg[i].value)+1; + /* no need! */ + if( !src->update ) + continue; + + src->update = false; + + len = strlen(varname)+1; + + WFIFOB(inter_fd, plen) = (unsigned char)len;/* won't be higher; the column size is 32 */ + plen += 1; + + safestrncpy((char*)WFIFOP(inter_fd,plen), varname, len); + plen += len; + + WFIFOL(inter_fd, plen) = script_getvaridx(key.i64); + plen += 4; + + if( src->type ) { + struct script_reg_str *p = (struct script_reg_str *)src; + + WFIFOB(inter_fd, plen) = p->value ? 2 : 3; + plen += 1; + + if( p->value ) { + len = strlen(p->value)+1; + + WFIFOB(inter_fd, plen) = (unsigned char)len;/* won't be higher; the column size is 254 */ + plen += 1; + + safestrncpy((char*)WFIFOP(inter_fd,plen), p->value, len); + plen += len; + } else { + script->reg_destroy_single(sd,key.i64,&p->flag); + } + + } else { + struct script_reg_num *p = (struct script_reg_num *)src; + + WFIFOB(inter_fd, plen) = p->value ? 0 : 1; + plen += 1; + + if( p->value ) { + WFIFOL(inter_fd, plen) = p->value; + plen += 4; + } else { + script->reg_destroy_single(sd,key.i64,&p->flag); + } + + } + + WFIFOW(inter_fd,12) += 1; + + if( plen > 60000 ) { + WFIFOW(inter_fd, 2) = plen; + WFIFOSET(inter_fd, plen); + + /* prepare follow up */ + WFIFOHEAD(inter_fd, 60000 + 300); + WFIFOW(inter_fd,0) = 0x3004; + /* 0x2 = length (set later) */ + WFIFOL(inter_fd,4) = sd->status.account_id; + WFIFOL(inter_fd,8) = sd->status.char_id; + WFIFOW(inter_fd,12) = 0;/* count */ + + plen = 14; } + } - WFIFOW(inter_fd,2)=p; - WFIFOSET(inter_fd,WFIFOW(inter_fd,2)); + dbi_destroy(iter); + + /* mark & go. */ + WFIFOW(inter_fd, 2) = plen; + WFIFOSET(inter_fd, plen); + + sd->vars_dirty = false; + return 0; } @@ -339,11 +387,8 @@ int intif_request_registry(struct map_session_data *sd, int flag) { nullpo_ret(sd); - sd->save_reg.account2_num = -1; - sd->save_reg.account_num = -1; - sd->save_reg.global_num = -1; - - if (CheckForCharServer()) + /* if char server ain't online it doesn't load, shouldn't we kill the session then? */ + if (intif->CheckForCharServer()) return 0; WFIFOHEAD(inter_fd,6); @@ -360,7 +405,7 @@ int intif_request_registry(struct map_session_data *sd, int flag) int intif_request_guild_storage(int account_id,int guild_id) { - if (CheckForCharServer()) + if (intif->CheckForCharServer()) return 0; WFIFOHEAD(inter_fd,10); WFIFOW(inter_fd,0) = 0x3018; @@ -371,7 +416,7 @@ int intif_request_guild_storage(int account_id,int guild_id) } int intif_send_guild_storage(int account_id,struct guild_storage *gstor) { - if (CheckForCharServer()) + if (intif->CheckForCharServer()) return 0; WFIFOHEAD(inter_fd,sizeof(struct guild_storage)+12); WFIFOW(inter_fd,0) = 0x3019; @@ -386,7 +431,7 @@ int intif_send_guild_storage(int account_id,struct guild_storage *gstor) // Party creation request int intif_create_party(struct party_member *member,char *name,int item,int item2) { - if (CheckForCharServer()) + if (intif->CheckForCharServer()) return 0; nullpo_ret(member); @@ -404,7 +449,7 @@ int intif_create_party(struct party_member *member,char *name,int item,int item2 // Party information request int intif_request_partyinfo(int party_id, int char_id) { - if (CheckForCharServer()) + if (intif->CheckForCharServer()) return 0; WFIFOHEAD(inter_fd,10); WFIFOW(inter_fd,0) = 0x3021; @@ -417,7 +462,7 @@ int intif_request_partyinfo(int party_id, int char_id) // Request to add a member to party int intif_party_addmember(int party_id,struct party_member *member) { - if (CheckForCharServer()) + if (intif->CheckForCharServer()) return 0; WFIFOHEAD(inter_fd,42); WFIFOW(inter_fd,0)=0x3022; @@ -431,7 +476,7 @@ int intif_party_addmember(int party_id,struct party_member *member) // Request to change party configuration (exp,item share) int intif_party_changeoption(int party_id,int account_id,int exp,int item) { - if (CheckForCharServer()) + if (intif->CheckForCharServer()) return 0; WFIFOHEAD(inter_fd,14); WFIFOW(inter_fd,0)=0x3023; @@ -446,7 +491,7 @@ int intif_party_changeoption(int party_id,int account_id,int exp,int item) // Request to leave party int intif_party_leave(int party_id,int account_id, int char_id) { - if (CheckForCharServer()) + if (intif->CheckForCharServer()) return 0; WFIFOHEAD(inter_fd,14); WFIFOW(inter_fd,0)=0x3024; @@ -458,26 +503,25 @@ int intif_party_leave(int party_id,int account_id, int char_id) } // Request keeping party for new map ?? -int intif_party_changemap(struct map_session_data *sd,int online) -{ - int16 m, mapindex; +int intif_party_changemap(struct map_session_data *sd,int online) { + int16 m, map_index; - if (CheckForCharServer()) + if (intif->CheckForCharServer()) return 0; if(!sd) return 0; - if( (m=iMap->mapindex2mapid(sd->mapindex)) >= 0 && map[m].instance_id >= 0 ) - mapindex = map[map[m].instance_src_map].index; + if( (m=map->mapindex2mapid(sd->mapindex)) >= 0 && map->list[m].instance_id >= 0 ) + map_index = map_id2index(map->list[m].instance_src_map); else - mapindex = sd->mapindex; + map_index = sd->mapindex; WFIFOHEAD(inter_fd,19); WFIFOW(inter_fd,0)=0x3025; WFIFOL(inter_fd,2)=sd->status.party_id; WFIFOL(inter_fd,6)=sd->status.account_id; WFIFOL(inter_fd,10)=sd->status.char_id; - WFIFOW(inter_fd,14)=mapindex; + WFIFOW(inter_fd,14)=map_index; WFIFOB(inter_fd,16)=online; WFIFOW(inter_fd,17)=sd->status.base_level; WFIFOSET(inter_fd,19); @@ -487,7 +531,7 @@ int intif_party_changemap(struct map_session_data *sd,int online) // Request breaking party int intif_break_party(int party_id) { - if (CheckForCharServer()) + if (intif->CheckForCharServer()) return 0; WFIFOHEAD(inter_fd,6); WFIFOW(inter_fd,0)=0x3026; @@ -499,10 +543,10 @@ int intif_break_party(int party_id) // Sending party chat int intif_party_message(int party_id,int account_id,const char *mes,int len) { - if (CheckForCharServer()) + if (intif->CheckForCharServer()) return 0; - if (other_mapserver_count < 1) + if (chrif->other_mapserver_count < 1) return 0; //No need to send. WFIFOHEAD(inter_fd,len + 12); @@ -518,7 +562,7 @@ int intif_party_message(int party_id,int account_id,const char *mes,int len) // Request a new leader for party int intif_party_leaderchange(int party_id,int account_id,int char_id) { - if (CheckForCharServer()) + if (intif->CheckForCharServer()) return 0; WFIFOHEAD(inter_fd,14); WFIFOW(inter_fd,0)=0x3029; @@ -532,7 +576,7 @@ int intif_party_leaderchange(int party_id,int account_id,int char_id) // Request a Guild creation int intif_guild_create(const char *name,const struct guild_member *master) { - if (CheckForCharServer()) + if (intif->CheckForCharServer()) return 0; nullpo_ret(master); @@ -549,7 +593,7 @@ int intif_guild_create(const char *name,const struct guild_member *master) // Request Guild information int intif_guild_request_info(int guild_id) { - if (CheckForCharServer()) + if (intif->CheckForCharServer()) return 0; WFIFOHEAD(inter_fd,6); WFIFOW(inter_fd,0) = 0x3031; @@ -561,7 +605,7 @@ int intif_guild_request_info(int guild_id) // Request to add member to the guild int intif_guild_addmember(int guild_id,struct guild_member *m) { - if (CheckForCharServer()) + if (intif->CheckForCharServer()) return 0; WFIFOHEAD(inter_fd,sizeof(struct guild_member)+8); WFIFOW(inter_fd,0) = 0x3032; @@ -573,9 +617,9 @@ 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, int len) +int intif_guild_change_gm(int guild_id, const char* name, size_t len) { - if (CheckForCharServer()) + if (intif->CheckForCharServer()) return 0; WFIFOHEAD(inter_fd, len + 8); WFIFOW(inter_fd, 0)=0x3033; @@ -589,7 +633,7 @@ int intif_guild_change_gm(int guild_id, const char* name, int len) // Request to leave guild int intif_guild_leave(int guild_id,int account_id,int char_id,int flag,const char *mes) { - if (CheckForCharServer()) + if (intif->CheckForCharServer()) return 0; WFIFOHEAD(inter_fd, 55); WFIFOW(inter_fd, 0) = 0x3034; @@ -605,7 +649,7 @@ int intif_guild_leave(int guild_id,int account_id,int char_id,int flag,const cha //Update request / Lv online status of the guild members int intif_guild_memberinfoshort(int guild_id,int account_id,int char_id,int online,int lv,int class_) { - if (CheckForCharServer()) + if (intif->CheckForCharServer()) return 0; WFIFOHEAD(inter_fd, 19); WFIFOW(inter_fd, 0) = 0x3035; @@ -622,7 +666,7 @@ int intif_guild_memberinfoshort(int guild_id,int account_id,int char_id,int onli //Guild disbanded notification int intif_guild_break(int guild_id) { - if (CheckForCharServer()) + if (intif->CheckForCharServer()) return 0; WFIFOHEAD(inter_fd, 6); WFIFOW(inter_fd, 0) = 0x3036; @@ -634,10 +678,10 @@ int intif_guild_break(int guild_id) // Send a guild message int intif_guild_message(int guild_id,int account_id,const char *mes,int len) { - if (CheckForCharServer()) + if (intif->CheckForCharServer()) return 0; - if (other_mapserver_count < 1) + if (chrif->other_mapserver_count < 1) return 0; //No need to send. WFIFOHEAD(inter_fd, len + 12); @@ -651,10 +695,13 @@ int intif_guild_message(int guild_id,int account_id,const char *mes,int len) return 0; } -// Request a change of Guild basic information +/** + * Requests to change a basic guild information, it is parsed via mapif_parse_GuildBasicInfoChange + * To see the information types that can be changed see mmo.h::guild_basic_info + **/ int intif_guild_change_basicinfo(int guild_id,int type,const void *data,int len) { - if (CheckForCharServer()) + if (intif->CheckForCharServer()) return 0; WFIFOHEAD(inter_fd, len + 10); WFIFOW(inter_fd,0)=0x3039; @@ -670,7 +717,7 @@ int intif_guild_change_basicinfo(int guild_id,int type,const void *data,int len) int intif_guild_change_memberinfo(int guild_id,int account_id,int char_id, int type,const void *data,int len) { - if (CheckForCharServer()) + if (intif->CheckForCharServer()) return 0; WFIFOHEAD(inter_fd, len + 18); WFIFOW(inter_fd, 0)=0x303a; @@ -687,7 +734,7 @@ int intif_guild_change_memberinfo(int guild_id,int account_id,int char_id, // Request a change of Guild title int intif_guild_position(int guild_id,int idx,struct guild_position *p) { - if (CheckForCharServer()) + if (intif->CheckForCharServer()) return 0; WFIFOHEAD(inter_fd, sizeof(struct guild_position)+12); WFIFOW(inter_fd,0)=0x303b; @@ -702,7 +749,7 @@ int intif_guild_position(int guild_id,int idx,struct guild_position *p) // Request an update of Guildskill skill_id int intif_guild_skillup(int guild_id, uint16 skill_id, int account_id, int max) { - if( CheckForCharServer() ) + if( intif->CheckForCharServer() ) return 0; WFIFOHEAD(inter_fd, 18); WFIFOW(inter_fd, 0) = 0x303c; @@ -717,7 +764,7 @@ int intif_guild_skillup(int guild_id, uint16 skill_id, int account_id, int max) // Request a new guild relationship int intif_guild_alliance(int guild_id1,int guild_id2,int account_id1,int account_id2,int flag) { - if (CheckForCharServer()) + if (intif->CheckForCharServer()) return 0; WFIFOHEAD(inter_fd,19); WFIFOW(inter_fd, 0)=0x303d; @@ -733,7 +780,7 @@ int intif_guild_alliance(int guild_id1,int guild_id2,int account_id1,int account // Request to change guild notice int intif_guild_notice(int guild_id,const char *mes1,const char *mes2) { - if (CheckForCharServer()) + if (intif->CheckForCharServer()) return 0; WFIFOHEAD(inter_fd,186); WFIFOW(inter_fd,0)=0x303e; @@ -747,7 +794,7 @@ int intif_guild_notice(int guild_id,const char *mes1,const char *mes2) // Request to change guild emblem int intif_guild_emblem(int guild_id,int len,const char *data) { - if (CheckForCharServer()) + if (intif->CheckForCharServer()) return 0; if(guild_id<=0 || len<0 || len>2000) return 0; @@ -768,7 +815,7 @@ int intif_guild_emblem(int guild_id,int len,const char *data) */ int intif_guild_castle_dataload(int num, int *castle_ids) { - if (CheckForCharServer()) + if (intif->CheckForCharServer()) return 0; WFIFOHEAD(inter_fd, 4 + num * sizeof(int)); WFIFOW(inter_fd, 0) = 0x3040; @@ -782,7 +829,7 @@ int intif_guild_castle_dataload(int num, int *castle_ids) // Request change castle guild owner and save data int intif_guild_castle_datasave(int castle_id,int index, int value) { - if (CheckForCharServer()) + if (intif->CheckForCharServer()) return 0; WFIFOHEAD(inter_fd,9); WFIFOW(inter_fd,0)=0x3041; @@ -799,7 +846,7 @@ int intif_guild_castle_datasave(int castle_id,int index, int value) int intif_homunculus_create(int account_id, struct s_homunculus *sh) { - if (CheckForCharServer()) + if (intif->CheckForCharServer()) return 0; WFIFOHEAD(inter_fd, sizeof(struct s_homunculus)+8); WFIFOW(inter_fd,0) = 0x3090; @@ -811,7 +858,7 @@ int intif_homunculus_create(int account_id, struct s_homunculus *sh) } bool intif_homunculus_requestload(int account_id, int homun_id) { - if (CheckForCharServer()) + if (intif->CheckForCharServer()) return false; WFIFOHEAD(inter_fd, 10); WFIFOW(inter_fd,0) = 0x3091; @@ -823,7 +870,7 @@ bool intif_homunculus_requestload(int account_id, int homun_id) { int intif_homunculus_requestsave(int account_id, struct s_homunculus* sh) { - if (CheckForCharServer()) + if (intif->CheckForCharServer()) return 0; WFIFOHEAD(inter_fd, sizeof(struct s_homunculus)+8); WFIFOW(inter_fd,0) = 0x3092; @@ -837,7 +884,7 @@ int intif_homunculus_requestsave(int account_id, struct s_homunculus* sh) int intif_homunculus_requestdelete(int homun_id) { - if (CheckForCharServer()) + if (intif->CheckForCharServer()) return 0; WFIFOHEAD(inter_fd, 6); WFIFOW(inter_fd, 0) = 0x3093; @@ -852,8 +899,7 @@ int intif_homunculus_requestdelete(int homun_id) // Packets receive from inter server // Wisp/Page reception // rewritten by [Yor] -int intif_parse_WisMessage(int fd) -{ +void intif_parse_WisMessage(int fd) { struct map_session_data* sd; char *wisp_source; char name[NAME_LENGTH]; @@ -862,15 +908,15 @@ int intif_parse_WisMessage(int fd) id=RFIFOL(fd,4); safestrncpy(name, (char*)RFIFOP(fd,32), NAME_LENGTH); - sd = iMap->nick2sd(name); - if(sd == NULL || strcmp(sd->status.name, name) != 0) - { //Not found + sd = map->nick2sd(name); + if(sd == NULL || strcmp(sd->status.name, name) != 0) { + //Not found intif_wis_replay(id,1); - return 0; + return; } if(sd->state.ignoreAll) { intif_wis_replay(id, 2); - return 0; + return; } wisp_source = (char *) RFIFOP(fd,8); // speed up [Yor] for(i=0; i < MAX_IGNORE_LIST && @@ -881,30 +927,27 @@ int intif_parse_WisMessage(int fd) if (i < MAX_IGNORE_LIST && sd->ignore[i].name[0] != '\0') { //Ignored intif_wis_replay(id, 2); - return 0; + return; } //Success to send whisper. clif->wis_message(sd->fd, wisp_source, (char*)RFIFOP(fd,56),RFIFOW(fd,2)-56); - intif_wis_replay(id,0); // succes - return 0; + intif_wis_replay(id,0); // success } // Wisp/page transmission result reception -int intif_parse_WisEnd(int fd) -{ +void intif_parse_WisEnd(int fd) { struct map_session_data* sd; if (battle_config.etc_log) - ShowInfo("intif_parse_wisend: player: %s, flag: %d\n", RFIFOP(fd,2), RFIFOB(fd,26)); // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target - sd = (struct map_session_data *)iMap->nick2sd((char *) RFIFOP(fd,2)); + ShowInfo("intif_parse_wisend: player: %s, flag: %d\n", RFIFOP(fd,2), RFIFOB(fd,26)); // flag: 0: success to send whisper, 1: target character is not logged in?, 2: ignored by target + sd = (struct map_session_data *)map->nick2sd((char *) RFIFOP(fd,2)); if (sd != NULL) clif->wis_end(sd->fd, RFIFOB(fd,26)); - return 0; + return; } -static int mapif_parse_WisToGM_sub(struct map_session_data* sd,va_list va) -{ +int mapif_parse_WisToGM_sub(struct map_session_data* sd,va_list va) { int permission = va_arg(va, int); char *wisp_name; char *message; @@ -921,7 +964,7 @@ static 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 -int mapif_parse_WisToGM(int fd) +void mapif_parse_WisToGM(int fd) { int permission, mes_len; char Wisp_name[NAME_LENGTH]; @@ -935,238 +978,259 @@ int mapif_parse_WisToGM(int fd) safestrncpy(Wisp_name, (char*)RFIFOP(fd,4), NAME_LENGTH); safestrncpy(message, (char*)RFIFOP(fd,32), mes_len); // information is sent to all online GM - iMap->map_foreachpc(mapif_parse_WisToGM_sub, permission, Wisp_name, message, mes_len); + map->foreachpc(mapif_parse_WisToGM_sub, permission, Wisp_name, message, mes_len); if (message != mbuf) aFree(message); - return 0; } // Request player registre -int intif_parse_Registers(int fd) +void intif_parse_Registers(int fd) { - int j,p,len,max, flag; + int i, flag; struct map_session_data *sd; - struct global_reg *reg; - int *qty; int account_id = RFIFOL(fd,4), char_id = RFIFOL(fd,8); - struct auth_node *node = chrif_auth_check(account_id, char_id, ST_LOGIN); + struct auth_node *node = chrif->auth_check(account_id, char_id, ST_LOGIN); + char type = RFIFOB(fd, 13); + if (node) sd = node->sd; else { //Normally registries should arrive for in log-in chars. - sd = iMap->id2sd(account_id); - if (sd && RFIFOB(fd,12) == 3 && sd->status.char_id != char_id) - sd = NULL; //Character registry from another character. + sd = map->id2sd(account_id); } - if (!sd) return 1; - - flag = (sd->save_reg.global_num == -1 || sd->save_reg.account_num == -1 || sd->save_reg.account2_num == -1); - + + if (!sd || sd->status.char_id != char_id) { + return; //Character registry from another character. + } + + flag = ( sd->vars_received&PRL_ACCG && sd->vars_received&PRL_ACCL && sd->vars_received&PRL_CHAR ) ? 0 : 1; + switch (RFIFOB(fd,12)) { case 3: //Character Registry - reg = sd->save_reg.global; - qty = &sd->save_reg.global_num; - max = GLOBAL_REG_NUM; - break; + sd->vars_received |= PRL_CHAR; + break; case 2: //Account Registry - reg = sd->save_reg.account; - qty = &sd->save_reg.account_num; - max = ACCOUNT_REG_NUM; - break; + sd->vars_received |= PRL_ACCL; + break; case 1: //Account2 Registry - reg = sd->save_reg.account2; - qty = &sd->save_reg.account2_num; - max = ACCOUNT_REG2_NUM; - break; + sd->vars_received |= PRL_ACCG; + break; + case 0: + break; default: ShowError("intif_parse_Registers: Unrecognized type %d\n",RFIFOB(fd,12)); - return 0; + return; } - for(j=0,p=13;j<max && p<RFIFOW(fd,2);j++){ - sscanf((char*)RFIFOP(fd,p), "%31c%n", reg[j].str,&len); - reg[j].str[len]='\0'; - p += len+1; //+1 to skip the '\0' between strings. - sscanf((char*)RFIFOP(fd,p), "%255c%n", reg[j].value,&len); - reg[j].value[len]='\0'; - p += len+1; + /* have it not complain about insertion of vars before loading, and not set those vars as new or modified */ + pc->reg_load = true; + + if( RFIFOW(fd, 14) ) { + char key[32], sval[254]; + unsigned int index; + int max = RFIFOW(fd, 14), cursor = 16, ival; + + script->parser_current_file = "loading char/acc variables";//for script_add_str to refer to here in case errors occur + + /** + * Vessel!char_reg_num_db + * + * str type + * { keyLength(B), key(<keyLength>), index(L), valLength(B), val(<valLength>) } + **/ + if( type ) { + for(i = 0; i < max; i++) { + safestrncpy(key, (char*)RFIFOP(fd, cursor + 1), RFIFOB(fd, cursor)); + cursor += RFIFOB(fd, cursor) + 1; + + index = RFIFOL(fd, cursor); + cursor += 4; + + safestrncpy(sval, (char*)RFIFOP(fd, cursor + 1), RFIFOB(fd, cursor)); + cursor += RFIFOB(fd, cursor) + 1; + + script->set_reg(NULL,sd,reference_uid(script->add_str(key), index), key, (void*)sval, NULL); + } + /** + * Vessel! + * + * int type + * { keyLength(B), key(<keyLength>), index(L), value(L) } + **/ + } else { + for(i = 0; i < max; i++) { + safestrncpy(key, (char*)RFIFOP(fd, cursor + 1), RFIFOB(fd, cursor)); + cursor += RFIFOB(fd, cursor) + 1; + + index = RFIFOL(fd, cursor); + cursor += 4; + + ival = RFIFOL(fd, cursor); + cursor += 4; + + script->set_reg(NULL,sd,reference_uid(script->add_str(key), index), key, (void*)h64BPTRSIZE(ival), NULL); + } + } + + script->parser_current_file = NULL;/* reset */ } - *qty = j; - - if (flag && sd->save_reg.global_num > -1 && sd->save_reg.account_num > -1 && sd->save_reg.account2_num > -1) + + /* flag it back */ + pc->reg_load = false; + + if (flag && sd->vars_received&PRL_ACCG && sd->vars_received&PRL_ACCL && sd->vars_received&PRL_CHAR) pc->reg_received(sd); //Received all registry values, execute init scripts and what-not. [Skotlex] - return 1; } -int intif_parse_LoadGuildStorage(int fd) +void intif_parse_LoadGuildStorage(int fd) { struct guild_storage *gstor; struct map_session_data *sd; - int guild_id; + int guild_id, flag; guild_id = RFIFOL(fd,8); + flag = RFIFOL(fd,12); if(guild_id <= 0) - return 1; - sd=iMap->id2sd( RFIFOL(fd,4) ); - if(sd==NULL){ - ShowError("intif_parse_LoadGuildStorage: user not found %d\n",RFIFOL(fd,4)); - return 1; + return; + sd=map->id2sd( RFIFOL(fd,4) ); + if( flag ){ //If flag != 0, we attach a player and open the storage + if(sd==NULL){ + ShowError("intif_parse_LoadGuildStorage: user not found %d\n",RFIFOL(fd,4)); + return; + } } - gstor=guild2storage(guild_id); + gstor=gstorage->id2storage(guild_id); if(!gstor) { ShowWarning("intif_parse_LoadGuildStorage: error guild_id %d not exist\n",guild_id); - return 1; + return; } if (gstor->storage_status == 1) { // Already open.. lets ignore this update - ShowWarning("intif_parse_LoadGuildStorage: storage received for a client already open (User %d:%d)\n", sd->status.account_id, sd->status.char_id); - return 1; + ShowWarning("intif_parse_LoadGuildStorage: storage received for a client already open (User %d:%d)\n", flag?sd->status.account_id:0, flag?sd->status.char_id:0); + return; } if (gstor->dirty) { // Already have storage, and it has been modified and not saved yet! Exploit! [Skotlex] - ShowWarning("intif_parse_LoadGuildStorage: received storage for an already modified non-saved storage! (User %d:%d)\n", sd->status.account_id, sd->status.char_id); - return 1; + ShowWarning("intif_parse_LoadGuildStorage: received storage for an already modified non-saved storage! (User %d:%d)\n", flag?sd->status.account_id:0, flag?sd->status.char_id:0); + return; } - if( RFIFOW(fd,2)-12 != sizeof(struct guild_storage) ){ - ShowError("intif_parse_LoadGuildStorage: data size error %d %d\n",RFIFOW(fd,2)-12 , sizeof(struct guild_storage)); - gstor->storage_status = 0; - return 1; + if (RFIFOW(fd,2)-13 != sizeof(struct guild_storage)) { + ShowError("intif_parse_LoadGuildStorage: data size mismatch %d != %"PRIuS"\n", RFIFOW(fd,2)-13, sizeof(struct guild_storage)); + gstor->storage_status = 0; + return; } - memcpy(gstor,RFIFOP(fd,12),sizeof(struct guild_storage)); - storage_guild_storageopen(sd); - return 0; + memcpy(gstor,RFIFOP(fd,13),sizeof(struct guild_storage)); + if( flag ) + gstorage->open(sd); } // ACK guild_storage saved -int intif_parse_SaveGuildStorage(int fd) +void intif_parse_SaveGuildStorage(int fd) { - storage_guild_storagesaved(/*RFIFOL(fd,2), */RFIFOL(fd,6)); - return 0; + gstorage->saved(/*RFIFOL(fd,2), */RFIFOL(fd,6)); } // ACK party creation -int intif_parse_PartyCreated(int fd) +void intif_parse_PartyCreated(int fd) { if(battle_config.etc_log) ShowInfo("intif: party created by account %d\n\n", RFIFOL(fd,2)); party->created(RFIFOL(fd,2), RFIFOL(fd,6),RFIFOB(fd,10),RFIFOL(fd,11), (char *)RFIFOP(fd,15)); - return 0; } // Receive party info -int intif_parse_PartyInfo(int fd) -{ - if( RFIFOW(fd,2) == 12 ){ +void intif_parse_PartyInfo(int fd) { + if (RFIFOW(fd,2) == 12) { ShowWarning("intif: party noinfo (char_id=%d party_id=%d)\n", RFIFOL(fd,4), RFIFOL(fd,8)); party->recv_noinfo(RFIFOL(fd,8), RFIFOL(fd,4)); - return 0; + return; } - if( RFIFOW(fd,2) != 8+sizeof(struct party) ) - ShowError("intif: party info : data size error (char_id=%d party_id=%d packet_len=%d expected_len=%d)\n", RFIFOL(fd,4), RFIFOL(fd,8), RFIFOW(fd,2), 8+sizeof(struct party)); + if (RFIFOW(fd,2) != 8+sizeof(struct party)) + ShowError("intif: party info: data size mismatch (char_id=%d party_id=%d packet_len=%d expected_len=%"PRIuS")\n", + RFIFOL(fd,4), RFIFOL(fd,8), RFIFOW(fd,2), 8+sizeof(struct party)); party->recv_info((struct party *)RFIFOP(fd,8), RFIFOL(fd,4)); - return 0; } // ACK adding party member -int intif_parse_PartyMemberAdded(int fd) +void intif_parse_PartyMemberAdded(int fd) { if(battle_config.etc_log) ShowInfo("intif: party member added Party (%d), Account(%d), Char(%d)\n",RFIFOL(fd,2),RFIFOL(fd,6),RFIFOL(fd,10)); party->member_added(RFIFOL(fd,2),RFIFOL(fd,6),RFIFOL(fd,10), RFIFOB(fd, 14)); - return 0; } // ACK changing party option -int intif_parse_PartyOptionChanged(int fd) +void intif_parse_PartyOptionChanged(int fd) { party->optionchanged(RFIFOL(fd,2),RFIFOL(fd,6),RFIFOW(fd,10),RFIFOW(fd,12),RFIFOB(fd,14)); - return 0; } // ACK member leaving party -int intif_parse_PartyMemberWithdraw(int fd) +void intif_parse_PartyMemberWithdraw(int fd) { if(battle_config.etc_log) ShowInfo("intif: party member withdraw: Party(%d), Account(%d), Char(%d)\n",RFIFOL(fd,2),RFIFOL(fd,6),RFIFOL(fd,10)); party->member_withdraw(RFIFOL(fd,2),RFIFOL(fd,6),RFIFOL(fd,10)); - return 0; } // ACK party break -int intif_parse_PartyBroken(int fd) -{ +void intif_parse_PartyBroken(int fd) { party->broken(RFIFOL(fd,2)); - return 0; } // ACK party on new map -int intif_parse_PartyMove(int fd) +void intif_parse_PartyMove(int fd) { party->recv_movemap(RFIFOL(fd,2),RFIFOL(fd,6),RFIFOL(fd,10),RFIFOW(fd,14),RFIFOB(fd,16),RFIFOW(fd,17)); - return 0; } // ACK party messages -int intif_parse_PartyMessage(int fd) -{ +void intif_parse_PartyMessage(int fd) { party->recv_message(RFIFOL(fd,4),RFIFOL(fd,8),(char *) RFIFOP(fd,12),RFIFOW(fd,2)-12); - return 0; } // ACK guild creation -int intif_parse_GuildCreated(int fd) -{ +void intif_parse_GuildCreated(int fd) { guild->created(RFIFOL(fd,2),RFIFOL(fd,6)); - return 0; } // ACK guild infos -int intif_parse_GuildInfo(int fd) -{ - if(RFIFOW(fd,2) == 8) { +void intif_parse_GuildInfo(int fd) { + if (RFIFOW(fd,2) == 8) { ShowWarning("intif: guild noinfo %d\n",RFIFOL(fd,4)); guild->recv_noinfo(RFIFOL(fd,4)); - return 0; + return; } - if( RFIFOW(fd,2)!=sizeof(struct guild)+4 ) - ShowError("intif: guild info : data size error Gid: %d recv size: %d Expected size: %d\n",RFIFOL(fd,4),RFIFOW(fd,2),sizeof(struct guild)+4); + if (RFIFOW(fd,2)!=sizeof(struct guild)+4) + ShowError("intif: guild info: data size mismatch - Gid: %d recv size: %d Expected size: %"PRIuS"\n", + RFIFOL(fd,4),RFIFOW(fd,2),sizeof(struct guild)+4); guild->recv_info((struct guild *)RFIFOP(fd,4)); - return 0; } // ACK adding guild member -int intif_parse_GuildMemberAdded(int fd) -{ +void intif_parse_GuildMemberAdded(int fd) { if(battle_config.etc_log) ShowInfo("intif: guild member added %d %d %d %d\n",RFIFOL(fd,2),RFIFOL(fd,6),RFIFOL(fd,10),RFIFOB(fd,14)); guild->member_added(RFIFOL(fd,2),RFIFOL(fd,6),RFIFOL(fd,10),RFIFOB(fd,14)); - return 0; } // ACK member leaving guild -int intif_parse_GuildMemberWithdraw(int fd) -{ +void intif_parse_GuildMemberWithdraw(int fd) { guild->member_withdraw(RFIFOL(fd,2),RFIFOL(fd,6),RFIFOL(fd,10),RFIFOB(fd,14),(char *)RFIFOP(fd,55),(char *)RFIFOP(fd,15)); - return 0; } // ACK guild member basic info -int intif_parse_GuildMemberInfoShort(int fd) -{ +void intif_parse_GuildMemberInfoShort(int fd) { guild->recv_memberinfoshort(RFIFOL(fd,2),RFIFOL(fd,6),RFIFOL(fd,10),RFIFOB(fd,14),RFIFOW(fd,15),RFIFOW(fd,17)); - return 0; } // ACK guild break -int intif_parse_GuildBroken(int fd) -{ +void intif_parse_GuildBroken(int fd) { guild->broken(RFIFOL(fd,2),RFIFOB(fd,6)); - return 0; } // basic guild info change notice // 0x3839 <packet len>.w <guild id>.l <type>.w <data>.?b -int intif_parse_GuildBasicInfoChanged(int fd) -{ +void intif_parse_GuildBasicInfoChanged(int fd) { //int len = RFIFOW(fd,2) - 10; int guild_id = RFIFOL(fd,4); int type = RFIFOW(fd,8); @@ -1174,21 +1238,33 @@ int intif_parse_GuildBasicInfoChanged(int fd) struct guild* g = guild->search(guild_id); if( g == NULL ) - return 0; + return; switch(type) { - case GBI_EXP: g->exp = RFIFOQ(fd,10); break; - case GBI_GUILDLV: g->guild_lv = RFIFOW(fd,10); break; - case GBI_SKILLPOINT: g->skill_point = RFIFOL(fd,10); break; + case GBI_EXP: g->exp = RFIFOQ(fd,10); break; + case GBI_GUILDLV: g->guild_lv = RFIFOW(fd,10); break; + case GBI_SKILLPOINT: g->skill_point = RFIFOL(fd,10); break; + case GBI_SKILLLV: { + int idx, max; + struct guild_skill *gs = (struct guild_skill *)RFIFOP(fd,10); + + if( gs == NULL ) + return; + + idx = gs->id - GD_SKILLBASE; + max = guild->skill_get_max(gs->id); + if( gs->lv > max ) + gs->lv = max; + + memcpy(&(g->skill[idx]), gs, sizeof(g->skill[idx])); + break; + } } - - return 0; } // guild member info change notice // 0x383a <packet len>.w <guild id>.l <account id>.l <char id>.l <type>.w <data>.?b -int intif_parse_GuildMemberInfoChanged(int fd) -{ +void intif_parse_GuildMemberInfoChanged(int fd) { //int len = RFIFOW(fd,2) - 18; int guild_id = RFIFOL(fd,4); int account_id = RFIFOL(fd,8); @@ -1201,189 +1277,152 @@ int intif_parse_GuildMemberInfoChanged(int fd) g = guild->search(guild_id); if( g == NULL ) - return 0; + return; idx = guild->getindex(g,account_id,char_id); if( idx == -1 ) - return 0; + return; switch( type ) { - case GMI_POSITION: g->member[idx].position = RFIFOW(fd,18); guild->memberposition_changed(g,idx,RFIFOW(fd,18)); break; - case GMI_EXP: g->member[idx].exp = RFIFOQ(fd,18); break; - case GMI_HAIR: g->member[idx].hair = RFIFOW(fd,18); break; - case GMI_HAIR_COLOR: g->member[idx].hair_color = RFIFOW(fd,18); break; - case GMI_GENDER: g->member[idx].gender = RFIFOW(fd,18); break; - case GMI_CLASS: g->member[idx].class_ = RFIFOW(fd,18); break; - case GMI_LEVEL: g->member[idx].lv = RFIFOW(fd,18); break; + case GMI_POSITION: g->member[idx].position = RFIFOW(fd,18); guild->memberposition_changed(g,idx,RFIFOW(fd,18)); break; + case GMI_EXP: g->member[idx].exp = RFIFOQ(fd,18); break; + case GMI_HAIR: g->member[idx].hair = RFIFOW(fd,18); break; + case GMI_HAIR_COLOR: g->member[idx].hair_color = RFIFOW(fd,18); break; + case GMI_GENDER: g->member[idx].gender = RFIFOW(fd,18); break; + case GMI_CLASS: g->member[idx].class_ = RFIFOW(fd,18); break; + case GMI_LEVEL: g->member[idx].lv = RFIFOW(fd,18); break; } - return 0; } // ACK change of guild title -int intif_parse_GuildPosition(int fd) -{ - if( RFIFOW(fd,2)!=sizeof(struct guild_position)+12 ) - ShowError("intif: guild info : data size error\n %d %d %d",RFIFOL(fd,4),RFIFOW(fd,2),sizeof(struct guild_position)+12); +void intif_parse_GuildPosition(int fd) { + if (RFIFOW(fd,2)!=sizeof(struct guild_position)+12) + ShowError("intif: guild info: data size mismatch (%d) %d != %"PRIuS"\n", + RFIFOL(fd,4),RFIFOW(fd,2),sizeof(struct guild_position)+12); guild->position_changed(RFIFOL(fd,4),RFIFOL(fd,8),(struct guild_position *)RFIFOP(fd,12)); - return 0; } // ACK change of guild skill update -int intif_parse_GuildSkillUp(int fd) -{ +void intif_parse_GuildSkillUp(int fd) { guild->skillupack(RFIFOL(fd,2),RFIFOL(fd,6),RFIFOL(fd,10)); - return 0; } // ACK change of guild relationship -int intif_parse_GuildAlliance(int fd) -{ +void intif_parse_GuildAlliance(int fd) { guild->allianceack(RFIFOL(fd,2),RFIFOL(fd,6),RFIFOL(fd,10),RFIFOL(fd,14),RFIFOB(fd,18),(char *) RFIFOP(fd,19),(char *) RFIFOP(fd,43)); - return 0; } // ACK change of guild notice -int intif_parse_GuildNotice(int fd) -{ +void intif_parse_GuildNotice(int fd) { guild->notice_changed(RFIFOL(fd,2),(char *) RFIFOP(fd,6),(char *) RFIFOP(fd,66)); - return 0; } // ACK change of guild emblem -int intif_parse_GuildEmblem(int fd) -{ +void intif_parse_GuildEmblem(int fd) { guild->emblem_changed(RFIFOW(fd,2)-12,RFIFOL(fd,4),RFIFOL(fd,8), (char *)RFIFOP(fd,12)); - return 0; } // ACK guild message -int intif_parse_GuildMessage(int fd) -{ +void intif_parse_GuildMessage(int fd) { guild->recv_message(RFIFOL(fd,4),RFIFOL(fd,8),(char *) RFIFOP(fd,12),RFIFOW(fd,2)-12); - return 0; } // Reply guild castle data request -int intif_parse_GuildCastleDataLoad(int fd) -{ - return guild->castledataloadack(RFIFOW(fd,2), (struct guild_castle *)RFIFOP(fd,4)); +void intif_parse_GuildCastleDataLoad(int fd) { + guild->castledataloadack(RFIFOW(fd,2), (struct guild_castle *)RFIFOP(fd,4)); } // ACK change of guildmaster -int intif_parse_GuildMasterChanged(int fd) -{ - return guild->gm_changed(RFIFOL(fd,2),RFIFOL(fd,6),RFIFOL(fd,10)); +void intif_parse_GuildMasterChanged(int fd) { + guild->gm_changed(RFIFOL(fd,2),RFIFOL(fd,6),RFIFOL(fd,10)); } // Request pet creation -int intif_parse_CreatePet(int fd) -{ - pet_get_egg(RFIFOL(fd,2),RFIFOL(fd,7),RFIFOB(fd,6)); - return 0; +void intif_parse_CreatePet(int fd) { + pet->get_egg(RFIFOL(fd,2), RFIFOW(fd,6), RFIFOL(fd,8)); } // ACK pet data -int intif_parse_RecvPetData(int fd) -{ +void intif_parse_RecvPetData(int fd) { struct s_pet p; int len; len=RFIFOW(fd,2); - if(sizeof(struct s_pet)!=len-9) { - if(battle_config.etc_log) - ShowError("intif: pet data: data size error %d %d\n",sizeof(struct s_pet),len-9); - } - else{ + if (sizeof(struct s_pet) != len-9) { + if (battle_config.etc_log) + ShowError("intif: pet data: data size mismatch %d != %"PRIuS"\n", len-9, sizeof(struct s_pet)); + } else { memcpy(&p,RFIFOP(fd,9),sizeof(struct s_pet)); - pet_recv_petdata(RFIFOL(fd,4),&p,RFIFOB(fd,8)); + pet->recv_petdata(RFIFOL(fd,4),&p,RFIFOB(fd,8)); } - - return 0; } - +/* Really? Whats the point, shouldn't be sent when successful then [Ind] */ // ACK pet save data -int intif_parse_SavePetOk(int fd) -{ +void intif_parse_SavePetOk(int fd) { if(RFIFOB(fd,6) == 1) ShowError("pet data save failure\n"); - - return 0; } - +/* Really? Whats the point, shouldn't be sent when successful then [Ind] */ // ACK deleting pet -int intif_parse_DeletePetOk(int fd) -{ +void intif_parse_DeletePetOk(int fd) { if(RFIFOB(fd,2) == 1) ShowError("pet data delete failure\n"); - - return 0; } -// ACK changing name resquest, players,pets,hommon -int intif_parse_ChangeNameOk(int fd) +// ACK changing name request, players,pets,homun +void intif_parse_ChangeNameOk(int fd) { struct map_session_data *sd = NULL; - if((sd=iMap->id2sd(RFIFOL(fd,2)))==NULL || + if((sd=map->id2sd(RFIFOL(fd,2)))==NULL || sd->status.char_id != RFIFOL(fd,6)) - return 0; + return; switch (RFIFOB(fd,10)) { case 0: //Players [NOT SUPPORTED YET] break; case 1: //Pets - pet_change_name_ack(sd, (char*)RFIFOP(fd,12), RFIFOB(fd,11)); + pet->change_name_ack(sd, (char*)RFIFOP(fd,12), RFIFOB(fd,11)); break; case 2: //Hom homun->change_name_ack(sd, (char*)RFIFOP(fd,12), RFIFOB(fd,11)); break; } - return 0; + return; } //---------------------------------------------------------------- // Homunculus recv packets [albator] -int intif_parse_CreateHomunculus(int fd) -{ - int len; - len=RFIFOW(fd,2)-9; - if(sizeof(struct s_homunculus)!=len) { - if(battle_config.etc_log) - ShowError("intif: create homun data: data size error %d != %d\n",sizeof(struct s_homunculus),len); - return 0; +void intif_parse_CreateHomunculus(int fd) { + int len = RFIFOW(fd,2)-9; + if (sizeof(struct s_homunculus) != len) { + if (battle_config.etc_log) + ShowError("intif: create homun data: data size mismatch %d != %"PRIuS"\n", len, sizeof(struct s_homunculus)); + return; } homun->recv_data(RFIFOL(fd,4), (struct s_homunculus*)RFIFOP(fd,9), RFIFOB(fd,8)) ; - return 0; } -int intif_parse_RecvHomunculusData(int fd) -{ - int len; - - len=RFIFOW(fd,2)-9; +void intif_parse_RecvHomunculusData(int fd) { + int len = RFIFOW(fd,2)-9; - if(sizeof(struct s_homunculus)!=len) { - if(battle_config.etc_log) - ShowError("intif: homun data: data size error %d %d\n",sizeof(struct s_homunculus),len); - return 0; + if (sizeof(struct s_homunculus) != len) { + if (battle_config.etc_log) + ShowError("intif: homun data: data size mismatch %d != %"PRIuS"\n", len, sizeof(struct s_homunculus)); + return; } homun->recv_data(RFIFOL(fd,4), (struct s_homunculus*)RFIFOP(fd,9), RFIFOB(fd,8)); - return 0; } -int intif_parse_SaveHomunculusOk(int fd) -{ +/* Really? Whats the point, shouldn't be sent when successful then [Ind] */ +void intif_parse_SaveHomunculusOk(int fd) { if(RFIFOB(fd,6) != 1) ShowError("homunculus data save failure for account %d\n", RFIFOL(fd,2)); - - return 0; } -int intif_parse_DeleteHomunculusOk(int fd) -{ +/* Really? Whats the point, shouldn't be sent when successful then [Ind] */ +void intif_parse_DeleteHomunculusOk(int fd) { if(RFIFOB(fd,2) != 1) ShowError("Homunculus data delete failure\n"); - - return 0; } /************************************** @@ -1392,81 +1431,108 @@ QUESTLOG SYSTEM FUNCTIONS ***************************************/ -int intif_request_questlog(TBL_PC *sd) -{ +/** + * Requests a character's quest log entries to the inter server. + * + * @param sd Character's data + */ +void intif_request_questlog(TBL_PC *sd) { WFIFOHEAD(inter_fd,6); WFIFOW(inter_fd,0) = 0x3060; WFIFOL(inter_fd,2) = sd->status.char_id; WFIFOSET(inter_fd,6); - return 0; } -int intif_parse_questlog(int fd) -{ - int char_id = RFIFOL(fd, 4); - int i; - TBL_PC * sd = iMap->charid2sd(char_id); - - //User not online anymore - if(!sd) - return -1; - - sd->avail_quests = sd->num_quests = (RFIFOW(fd, 2)-8)/sizeof(struct quest); - - memset(&sd->quest_log, 0, sizeof(sd->quest_log)); +/** + * Parses the received quest log entries for a character from the inter server. + * + * Received in reply to the requests made by intif_request_questlog. + * + * @see intif_parse + */ +void intif_parse_QuestLog(int fd) { + int char_id = RFIFOL(fd, 4), num_received = (RFIFOW(fd, 2)-8)/sizeof(struct quest); + TBL_PC *sd = map->charid2sd(char_id); - for( i = 0; i < sd->num_quests; i++ ) - { - memcpy(&sd->quest_log[i], RFIFOP(fd, i*sizeof(struct quest)+8), sizeof(struct quest)); + if (!sd) // User not online anymore + return; - sd->quest_index[i] = quest_search_db(sd->quest_log[i].quest_id); + sd->num_quests = sd->avail_quests = 0; - if( sd->quest_index[i] < 0 ) - { - ShowError("intif_parse_questlog: quest %d not found in DB.\n",sd->quest_log[i].quest_id); - sd->avail_quests--; - sd->num_quests--; - i--; - continue; + if (num_received == 0) { + if (sd->quest_log) { + aFree(sd->quest_log); + sd->quest_log = NULL; + } + } else { + struct quest *received = (struct quest *)RFIFOP(fd, 8); + int i, k = num_received; + if (sd->quest_log) { + RECREATE(sd->quest_log, struct quest, num_received); + } else { + CREATE(sd->quest_log, struct quest, num_received); } - if( sd->quest_log[i].state == Q_COMPLETE ) - sd->avail_quests--; + for (i = 0; i < num_received; i++) { + if( quest->db(received[i].quest_id) == &quest->dummy ) { + ShowError("intif_parse_QuestLog: quest %d not found in DB.\n", received[i].quest_id); + continue; + } + if (received[i].state != Q_COMPLETE) { + // Insert at the beginning + memcpy(&sd->quest_log[sd->avail_quests++], &received[i], sizeof(struct quest)); + } else { + // Insert at the end + memcpy(&sd->quest_log[--k], &received[i], sizeof(struct quest)); + } + sd->num_quests++; + } + if (sd->avail_quests < k) { + // sd->avail_quests and k didn't meet in the middle: some entries were skipped + if (k < num_received) // Move the entries at the end to fill the gap + memmove(&sd->quest_log[k], &sd->quest_log[sd->avail_quests], sizeof(struct quest)*(num_received - k)); + sd->quest_log = aRealloc(sd->quest_log, sizeof(struct quest)*sd->num_quests); + } } - quest_pc_login(sd); - - return 0; + quest->pc_login(sd); } -int intif_parse_questsave(int fd) -{ +/** + * Parses the quest log save ack for a character from the inter server. + * + * Received in reply to the requests made by intif_quest_save. + * + * @see intif_parse + */ +void intif_parse_QuestSave(int fd) { int cid = RFIFOL(fd, 2); - TBL_PC *sd = iMap->id2sd(cid); + TBL_PC *sd = map->id2sd(cid); if( !RFIFOB(fd, 6) ) - ShowError("intif_parse_questsave: Failed to save quest(s) for character %d!\n", cid); + ShowError("intif_parse_QuestSave: Failed to save quest(s) for character %d!\n", cid); else if( sd ) sd->save_quest = false; - - return 0; } -int intif_quest_save(TBL_PC *sd) -{ - int len; - - if(CheckForCharServer()) - return 0; +/** + * Requests to the inter server to save a character's quest log entries. + * + * @param sd Character's data + * @return 0 in case of success, nonzero otherwise + */ +int intif_quest_save(TBL_PC *sd) { + int len = sizeof(struct quest)*sd->num_quests + 8; - len = sizeof(struct quest)*sd->num_quests + 8; + if(intif->CheckForCharServer()) + return 1; WFIFOHEAD(inter_fd, len); WFIFOW(inter_fd,0) = 0x3061; WFIFOW(inter_fd,2) = len; WFIFOL(inter_fd,4) = sd->status.char_id; if( sd->num_quests ) - memcpy(WFIFOP(inter_fd,8), &sd->quest_log, sizeof(struct quest)*sd->num_quests); + memcpy(WFIFOP(inter_fd,8), sd->quest_log, sizeof(struct quest)*sd->num_quests); WFIFOSET(inter_fd, len); return 0; @@ -1483,7 +1549,7 @@ int intif_quest_save(TBL_PC *sd) *------------------------------------------*/ int intif_Mail_requestinbox(int char_id, unsigned char flag) { - if (CheckForCharServer()) + if (intif->CheckForCharServer()) return 0; WFIFOHEAD(inter_fd,7); @@ -1495,23 +1561,20 @@ int intif_Mail_requestinbox(int char_id, unsigned char flag) return 0; } -int intif_parse_Mail_inboxreceived(int fd) -{ +void intif_parse_MailInboxReceived(int fd) { struct map_session_data *sd; unsigned char flag = RFIFOB(fd,8); - sd = iMap->charid2sd(RFIFOL(fd,4)); + sd = map->charid2sd(RFIFOL(fd,4)); - if (sd == NULL) - { - ShowError("intif_parse_Mail_inboxreceived: char not found %d\n",RFIFOL(fd,4)); - return 1; + if (sd == NULL) { + ShowError("intif_parse_MailInboxReceived: char not found %d\n",RFIFOL(fd,4)); + return; } - if (RFIFOW(fd,2) - 9 != sizeof(struct mail_data)) - { - ShowError("intif_parse_Mail_inboxreceived: data size error %d %d\n", RFIFOW(fd,2) - 9, sizeof(struct mail_data)); - return 1; + if (RFIFOW(fd,2) - 9 != sizeof(struct mail_data)) { + ShowError("intif_parse_MailInboxReceived: data size mismatch %d != %"PRIuS"\n", RFIFOW(fd,2) - 9, sizeof(struct mail_data)); + return; } //FIXME: this operation is not safe [ultramage] @@ -1520,20 +1583,18 @@ int intif_parse_Mail_inboxreceived(int fd) if (flag) clif->mail_refreshinbox(sd); - else if( battle_config.mail_show_status && ( battle_config.mail_show_status == 1 || sd->mail.inbox.unread ) ) - { + else if( battle_config.mail_show_status && ( battle_config.mail_show_status == 1 || sd->mail.inbox.unread ) ) { char output[128]; sprintf(output, msg_txt(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, strlen(output)); } - return 0; } /*------------------------------------------ * Mail Read *------------------------------------------*/ int intif_Mail_read(int mail_id) { - if (CheckForCharServer()) + if (intif->CheckForCharServer()) return 0; WFIFOHEAD(inter_fd,6); @@ -1548,7 +1609,7 @@ int intif_Mail_read(int mail_id) *------------------------------------------*/ int intif_Mail_getattach(int char_id, int mail_id) { - if (CheckForCharServer()) + if (intif->CheckForCharServer()) return 0; WFIFOHEAD(inter_fd,10); @@ -1560,37 +1621,33 @@ int intif_Mail_getattach(int char_id, int mail_id) return 0; } -int intif_parse_Mail_getattach(int fd) -{ +void intif_parse_MailGetAttach(int fd) { struct map_session_data *sd; struct item item; int zeny = RFIFOL(fd,8); - sd = iMap->charid2sd( RFIFOL(fd,4) ); + sd = map->charid2sd( RFIFOL(fd,4) ); - if (sd == NULL) - { - ShowError("intif_parse_Mail_getattach: char not found %d\n",RFIFOL(fd,4)); - return 1; + if (sd == NULL) { + ShowError("intif_parse_MailGetAttach: char not found %d\n",RFIFOL(fd,4)); + return; } - if (RFIFOW(fd,2) - 12 != sizeof(struct item)) - { - ShowError("intif_parse_Mail_getattach: data size error %d %d\n", RFIFOW(fd,2) - 16, sizeof(struct item)); - return 1; + if (RFIFOW(fd,2) - 12 != sizeof(struct item)) { + ShowError("intif_parse_MailGetAttach: data size mismatch %d != %"PRIuS"\n", RFIFOW(fd,2) - 16, sizeof(struct item)); + return; } memcpy(&item, RFIFOP(fd,12), sizeof(struct item)); mail->getattachment(sd, zeny, &item); - return 0; } /*------------------------------------------ * Delete Message *------------------------------------------*/ int intif_Mail_delete(int char_id, int mail_id) { - if (CheckForCharServer()) + if (intif->CheckForCharServer()) return 0; WFIFOHEAD(inter_fd,10); @@ -1602,42 +1659,37 @@ int intif_Mail_delete(int char_id, int mail_id) return 0; } -int intif_parse_Mail_delete(int fd) -{ +void intif_parse_MailDelete(int fd) { + struct map_session_data *sd; int char_id = RFIFOL(fd,2); int mail_id = RFIFOL(fd,6); bool failed = RFIFOB(fd,10); - - struct map_session_data *sd = iMap->charid2sd(char_id); - if (sd == NULL) - { - ShowError("intif_parse_Mail_delete: char not found %d\n", char_id); - return 1; + + if ( (sd = map->charid2sd(char_id)) == NULL) { + ShowError("intif_parse_MailDelete: char not found %d\n", char_id); + return; } - if (!failed) - { + if (!failed) { int i; ARR_FIND(0, MAIL_MAX_INBOX, i, sd->mail.inbox.msg[i].id == mail_id); - if( i < MAIL_MAX_INBOX ) - { + if( i < MAIL_MAX_INBOX ) { memset(&sd->mail.inbox.msg[i], 0, sizeof(struct mail_message)); sd->mail.inbox.amount--; } if( sd->mail.inbox.full ) - intif_Mail_requestinbox(sd->status.char_id, 1); // Free space is available for new mails + intif->Mail_requestinbox(sd->status.char_id, 1); // Free space is available for new mails } clif->mail_delete(sd->fd, mail_id, failed); - return 0; } /*------------------------------------------ * Return Message *------------------------------------------*/ int intif_Mail_return(int char_id, int mail_id) { - if (CheckForCharServer()) + if (intif->CheckForCharServer()) return 0; WFIFOHEAD(inter_fd,10); @@ -1649,34 +1701,29 @@ int intif_Mail_return(int char_id, int mail_id) return 0; } -int intif_parse_Mail_return(int fd) -{ - struct map_session_data *sd = iMap->charid2sd(RFIFOL(fd,2)); +void intif_parse_MailReturn(int fd) { + struct map_session_data *sd = map->charid2sd(RFIFOL(fd,2)); int mail_id = RFIFOL(fd,6); short fail = RFIFOB(fd,10); - if( sd == NULL ) - { - ShowError("intif_parse_Mail_return: char not found %d\n",RFIFOL(fd,2)); - return 1; + if( sd == NULL ) { + ShowError("intif_parse_MailReturn: char not found %d\n",RFIFOL(fd,2)); + return; } - if( !fail ) - { + if( !fail ) { int i; ARR_FIND(0, MAIL_MAX_INBOX, i, sd->mail.inbox.msg[i].id == mail_id); - if( i < MAIL_MAX_INBOX ) - { + if( i < MAIL_MAX_INBOX ) { memset(&sd->mail.inbox.msg[i], 0, sizeof(struct mail_message)); sd->mail.inbox.amount--; } if( sd->mail.inbox.full ) - intif_Mail_requestinbox(sd->status.char_id, 1); // Free space is available for new mails + intif->Mail_requestinbox(sd->status.char_id, 1); // Free space is available for new mails } clif->mail_return(sd->fd, mail_id, fail); - return 0; } /*------------------------------------------ * Send Mail @@ -1685,7 +1732,7 @@ int intif_Mail_send(int account_id, struct mail_message *msg) { int len = sizeof(struct mail_message) + 8; - if (CheckForCharServer()) + if (intif->CheckForCharServer()) return 0; WFIFOHEAD(inter_fd,len); @@ -1698,15 +1745,13 @@ int intif_Mail_send(int account_id, struct mail_message *msg) return 1; } -static void intif_parse_Mail_send(int fd) -{ +void intif_parse_MailSend(int fd) { struct mail_message msg; struct map_session_data *sd; bool fail; - if( RFIFOW(fd,2) - 4 != sizeof(struct mail_message) ) - { - ShowError("intif_parse_Mail_send: data size error %d %d\n", RFIFOW(fd,2) - 4, sizeof(struct mail_message)); + if( RFIFOW(fd,2) - 4 != sizeof(struct mail_message) ) { + ShowError("intif_parse_MailSend: data size mismatch %d != %"PRIuS"\n", RFIFOW(fd,2) - 4, sizeof(struct mail_message)); return; } @@ -1714,23 +1759,20 @@ static void intif_parse_Mail_send(int fd) fail = (msg.id == 0); // notify sender - sd = iMap->charid2sd(msg.send_id); - if( sd != NULL ) - { + sd = map->charid2sd(msg.send_id); + if( sd != NULL ) { if( fail ) mail->deliveryfail(sd, &msg); - else - { + else { clif->mail_send(sd->fd, false); - if( iMap->save_settings&16 ) - chrif_save(sd, 0); + if( map->save_settings&16 ) + chrif->save(sd, 0); } } } -static void intif_parse_Mail_new(int fd) -{ - struct map_session_data *sd = iMap->charid2sd(RFIFOL(fd,2)); +void intif_parse_MailNew(int fd) { + struct map_session_data *sd = map->charid2sd(RFIFOL(fd,2)); int mail_id = RFIFOL(fd,6); const char* sender_name = (char*)RFIFOP(fd,10); const char* title = (char*)RFIFOP(fd,34); @@ -1750,7 +1792,7 @@ int intif_Auction_requestlist(int char_id, short type, int price, const char* se { int len = NAME_LENGTH + 16; - if( CheckForCharServer() ) + if( intif->CheckForCharServer() ) return 0; WFIFOHEAD(inter_fd,len); @@ -1766,9 +1808,8 @@ int intif_Auction_requestlist(int char_id, short type, int price, const char* se return 0; } -static void intif_parse_Auction_results(int fd) -{ - struct map_session_data *sd = iMap->charid2sd(RFIFOL(fd,4)); +void intif_parse_AuctionResults(int fd) { + struct map_session_data *sd = map->charid2sd(RFIFOL(fd,4)); short count = RFIFOW(fd,8); short pages = RFIFOW(fd,10); uint8* data = RFIFOP(fd,12); @@ -1783,7 +1824,7 @@ int intif_Auction_register(struct auction_data *auction) { int len = sizeof(struct auction_data) + 4; - if( CheckForCharServer() ) + if( intif->CheckForCharServer() ) return 0; WFIFOHEAD(inter_fd,len); @@ -1795,29 +1836,24 @@ int intif_Auction_register(struct auction_data *auction) return 1; } -static void intif_parse_Auction_register(int fd) -{ +void intif_parse_AuctionRegister(int fd) { struct map_session_data *sd; struct auction_data auction; - if( RFIFOW(fd,2) - 4 != sizeof(struct auction_data) ) - { - ShowError("intif_parse_Auction_register: data size error %d %d\n", RFIFOW(fd,2) - 4, sizeof(struct auction_data)); + if (RFIFOW(fd,2) - 4 != sizeof(struct auction_data)) { + ShowError("intif_parse_AuctionRegister: data size mismatch %d != %"PRIuS"\n", RFIFOW(fd,2) - 4, sizeof(struct auction_data)); return; } memcpy(&auction, RFIFOP(fd,4), sizeof(struct auction_data)); - if( (sd = iMap->charid2sd(auction.seller_id)) == NULL ) + if( (sd = map->charid2sd(auction.seller_id)) == NULL ) return; - if( auction.auction_id > 0 ) - { + if( auction.auction_id > 0 ) { clif->auction_message(sd->fd, 1); // Confirmation Packet ?? - if( iMap->save_settings&32 ) - chrif_save(sd,0); - } - else - { + if( map->save_settings&32 ) + chrif->save(sd,0); + } else { int zeny = auction.hours*battle_config.auction_feeperhour; clif->auction_message(sd->fd, 4); @@ -1829,7 +1865,7 @@ static void intif_parse_Auction_register(int fd) int intif_Auction_cancel(int char_id, unsigned int auction_id) { - if( CheckForCharServer() ) + if( intif->CheckForCharServer() ) return 0; WFIFOHEAD(inter_fd,10); @@ -1841,26 +1877,24 @@ int intif_Auction_cancel(int char_id, unsigned int auction_id) return 0; } -static void intif_parse_Auction_cancel(int fd) -{ - struct map_session_data *sd = iMap->charid2sd(RFIFOL(fd,2)); +void intif_parse_AuctionCancel(int fd) { + struct map_session_data *sd = map->charid2sd(RFIFOL(fd,2)); int result = RFIFOB(fd,6); if( sd == NULL ) return; - switch( result ) - { - case 0: clif->auction_message(sd->fd, 2); break; - case 1: clif->auction_close(sd->fd, 2); break; - case 2: clif->auction_close(sd->fd, 1); break; - case 3: clif->auction_message(sd->fd, 3); break; + switch( result ) { + case 0: clif->auction_message(sd->fd, 2); break; + case 1: clif->auction_close(sd->fd, 2); break; + case 2: clif->auction_close(sd->fd, 1); break; + case 3: clif->auction_message(sd->fd, 3); break; } } int intif_Auction_close(int char_id, unsigned int auction_id) { - if( CheckForCharServer() ) + if( intif->CheckForCharServer() ) return 0; WFIFOHEAD(inter_fd,10); @@ -1872,20 +1906,18 @@ int intif_Auction_close(int char_id, unsigned int auction_id) return 0; } -static void intif_parse_Auction_close(int fd) -{ - struct map_session_data *sd = iMap->charid2sd(RFIFOL(fd,2)); +void intif_parse_AuctionClose(int fd) { + struct map_session_data *sd = map->charid2sd(RFIFOL(fd,2)); unsigned char result = RFIFOB(fd,6); if( sd == NULL ) return; clif->auction_close(sd->fd, result); - if( result == 0 ) - { + if( result == 0 ) { // FIXME: Leeching off a parse function clif->pAuction_cancelreg(fd, sd); - intif_Auction_requestlist(sd->status.char_id, 6, 0, "", 1); + intif->Auction_requestlist(sd->status.char_id, 6, 0, "", 1); } } @@ -1893,7 +1925,7 @@ int intif_Auction_bid(int char_id, const char* name, unsigned int auction_id, in { int len = 16 + NAME_LENGTH; - if( CheckForCharServer() ) + if( intif->CheckForCharServer() ) return 0; WFIFOHEAD(inter_fd,len); @@ -1908,9 +1940,8 @@ int intif_Auction_bid(int char_id, const char* name, unsigned int auction_id, in return 0; } -static void intif_parse_Auction_bid(int fd) -{ - struct map_session_data *sd = iMap->charid2sd(RFIFOL(fd,2)); +void intif_parse_AuctionBid(int fd) { + struct map_session_data *sd = map->charid2sd(RFIFOL(fd,2)); int bid = RFIFOL(fd,6); unsigned char result = RFIFOB(fd,10); @@ -1923,14 +1954,13 @@ static void intif_parse_Auction_bid(int fd) } if( result == 1 ) { // To update the list, display your buy list clif->pAuction_cancelreg(fd, sd); - intif_Auction_requestlist(sd->status.char_id, 7, 0, "", 1); + intif->Auction_requestlist(sd->status.char_id, 7, 0, "", 1); } } // Used to send 'You have won the auction' and 'You failed to won the auction' messages -static void intif_parse_Auction_message(int fd) -{ - struct map_session_data *sd = iMap->charid2sd(RFIFOL(fd,2)); +void intif_parse_AuctionMessage(int fd) { + struct map_session_data *sd = map->charid2sd(RFIFOL(fd,2)); unsigned char result = RFIFOB(fd,6); if( sd == NULL ) @@ -1946,7 +1976,7 @@ int intif_mercenary_create(struct s_mercenary *merc) { int size = sizeof(struct s_mercenary) + 4; - if( CheckForCharServer() ) + if( intif->CheckForCharServer() ) return 0; WFIFOHEAD(inter_fd,size); @@ -1957,23 +1987,21 @@ int intif_mercenary_create(struct s_mercenary *merc) return 0; } -int intif_parse_mercenary_received(int fd) -{ +void intif_parse_MercenaryReceived(int fd) { int len = RFIFOW(fd,2) - 5; - if( sizeof(struct s_mercenary) != len ) - { - if( battle_config.etc_log ) - ShowError("intif: create mercenary data size error %d != %d\n", sizeof(struct s_mercenary), len); - return 0; + + if (sizeof(struct s_mercenary) != len) { + if (battle_config.etc_log) + ShowError("intif: create mercenary data size mismatch %d != %"PRIuS"\n", len, sizeof(struct s_mercenary)); + return; } - merc_data_received((struct s_mercenary*)RFIFOP(fd,5), RFIFOB(fd,4)); - return 0; + mercenary->data_received((struct s_mercenary*)RFIFOP(fd,5), RFIFOB(fd,4)); } int intif_mercenary_request(int merc_id, int char_id) { - if (CheckForCharServer()) + if (intif->CheckForCharServer()) return 0; WFIFOHEAD(inter_fd,10); @@ -1986,7 +2014,7 @@ int intif_mercenary_request(int merc_id, int char_id) int intif_mercenary_delete(int merc_id) { - if (CheckForCharServer()) + if (intif->CheckForCharServer()) return 0; WFIFOHEAD(inter_fd,6); @@ -1995,20 +2023,17 @@ int intif_mercenary_delete(int merc_id) WFIFOSET(inter_fd,6); return 0; } - -int intif_parse_mercenary_deleted(int fd) -{ +/* Really? Whats the point, shouldn't be sent when successful then [Ind] */ +void intif_parse_MercenaryDeleted(int fd) { if( RFIFOB(fd,2) != 1 ) ShowError("Mercenary data delete failure\n"); - - return 0; } int intif_mercenary_save(struct s_mercenary *merc) { int size = sizeof(struct s_mercenary) + 4; - if( CheckForCharServer() ) + if( intif->CheckForCharServer() ) return 0; WFIFOHEAD(inter_fd,size); @@ -2018,13 +2043,10 @@ int intif_mercenary_save(struct s_mercenary *merc) WFIFOSET(inter_fd,size); return 0; } - -int intif_parse_mercenary_saved(int fd) -{ +/* Really? Whats the point, shouldn't be sent when successful then [Ind] */ +void intif_parse_MercenarySaved(int fd) { if( RFIFOB(fd,2) != 1 ) ShowError("Mercenary data save failure\n"); - - return 0; } /*========================================== @@ -2034,7 +2056,7 @@ int intif_elemental_create(struct s_elemental *ele) { int size = sizeof(struct s_elemental) + 4; - if( CheckForCharServer() ) + if( intif->CheckForCharServer() ) return 0; WFIFOHEAD(inter_fd,size); @@ -2045,23 +2067,21 @@ int intif_elemental_create(struct s_elemental *ele) return 0; } -int intif_parse_elemental_received(int fd) -{ +void intif_parse_ElementalReceived(int fd) { int len = RFIFOW(fd,2) - 5; - if( sizeof(struct s_elemental) != len ) - { - if( battle_config.etc_log ) - ShowError("intif: create elemental data size error %d != %d\n", sizeof(struct s_elemental), len); - return 0; + + if (sizeof(struct s_elemental) != len) { + if (battle_config.etc_log) + ShowError("intif: create elemental data size mismatch %d != %"PRIuS"\n", len, sizeof(struct s_elemental)); + return; } - elemental_data_received((struct s_elemental*)RFIFOP(fd,5), RFIFOB(fd,4)); - return 0; + elemental->data_received((struct s_elemental*)RFIFOP(fd,5), RFIFOB(fd,4)); } int intif_elemental_request(int ele_id, int char_id) { - if (CheckForCharServer()) + if (intif->CheckForCharServer()) return 0; WFIFOHEAD(inter_fd,10); @@ -2074,7 +2094,7 @@ int intif_elemental_request(int ele_id, int char_id) int intif_elemental_delete(int ele_id) { - if (CheckForCharServer()) + if (intif->CheckForCharServer()) return 0; WFIFOHEAD(inter_fd,6); @@ -2083,20 +2103,17 @@ int intif_elemental_delete(int ele_id) WFIFOSET(inter_fd,6); return 0; } - -int intif_parse_elemental_deleted(int fd) -{ +/* Really? Whats the point, shouldn't be sent when successful then [Ind] */ +void intif_parse_ElementalDeleted(int fd) { if( RFIFOB(fd,2) != 1 ) ShowError("Elemental data delete failure\n"); - - return 0; } int intif_elemental_save(struct s_elemental *ele) { int size = sizeof(struct s_elemental) + 4; - if( CheckForCharServer() ) + if( intif->CheckForCharServer() ) return 0; WFIFOHEAD(inter_fd,size); @@ -2106,13 +2123,10 @@ int intif_elemental_save(struct s_elemental *ele) WFIFOSET(inter_fd,size); return 0; } - -int intif_parse_elemental_saved(int fd) -{ +/* Really? Whats the point, shouldn't be sent when successful then [Ind] */ +void intif_parse_ElementalSaved(int fd) { if( RFIFOB(fd,2) != 1 ) ShowError("Elemental data save failure\n"); - - return 0; } void intif_request_accinfo( int u_fd, int aid, int group_lv, char* query ) { @@ -2138,7 +2152,7 @@ void intif_parse_MessageToFD(int fd) { int aid = RFIFOL(fd,8); struct map_session_data * sd = session[u_fd]->session_data; /* matching e.g. previous fd owner didn't dc during request or is still the same */ - if( sd->bl.id == aid ) { + if( sd && sd->bl.id == aid ) { char msg[512]; safestrncpy(msg, (char*)RFIFOP(fd,12), RFIFOW(fd,2) - 12); clif->message(u_fd,msg); @@ -2148,7 +2162,34 @@ void intif_parse_MessageToFD(int fd) { return; } +/*========================================== + * Item Bound System [Xantara][Mhalicot] + *------------------------------------------*/ +void intif_itembound_req(int char_id,int aid,int guild_id) { +#ifdef GP_BOUND_ITEMS + struct guild_storage *gstor = gstorage->id2storage2(guild_id); + WFIFOHEAD(inter_fd,12); + WFIFOW(inter_fd,0) = 0x3056; + WFIFOL(inter_fd,2) = char_id; + WFIFOL(inter_fd,6) = aid; + WFIFOW(inter_fd,10) = guild_id; + WFIFOSET(inter_fd,12); + if(gstor) + gstor->lock = 1; //Lock for retrieval process +#endif +} + +//3856 +void intif_parse_Itembound_ack(int fd) { +#ifdef GP_BOUND_ITEMS + struct guild_storage *gstor; + int guild_id = RFIFOW(fd,6); + gstor = gstorage->id2storage2(guild_id); + if(gstor) + gstor->lock = 0; //Unlock now that operation is completed +#endif +} //----------------------------------------------------------------- // Communication from the inter server // Return a 0 (false) if there were any errors. @@ -2158,12 +2199,12 @@ int intif_parse(int fd) int packet_len, cmd; cmd = RFIFOW(fd,0); // Verify ID of the packet - if(cmd<0x3800 || cmd>=0x3800+(sizeof(packet_len_table)/sizeof(packet_len_table[0])) || - packet_len_table[cmd-0x3800]==0){ + if(cmd<0x3800 || cmd>=0x3800+(sizeof(intif->packet_len_table)/sizeof(intif->packet_len_table[0])) || + intif->packet_len_table[cmd-0x3800]==0){ return 0; } // Check the length of the packet - packet_len = packet_len_table[cmd-0x3800]; + packet_len = intif->packet_len_table[cmd-0x3800]; if(packet_len==-1){ if(RFIFOREST(fd)<4) return 2; @@ -2174,81 +2215,88 @@ int intif_parse(int fd) } // Processing branch switch(cmd){ - case 0x3800: - if (RFIFOL(fd,4) == 0xFF000000) //Normal announce. - clif->broadcast(NULL, (char *) RFIFOP(fd,16), packet_len-16, 0, ALL_CLIENT); - else //Color announce. - clif->broadcast2(NULL, (char *) RFIFOP(fd,16), packet_len-16, RFIFOL(fd,4), RFIFOW(fd,8), RFIFOW(fd,10), RFIFOW(fd,12), RFIFOW(fd,14), ALL_CLIENT); - break; - case 0x3801: intif_parse_WisMessage(fd); break; - case 0x3802: intif_parse_WisEnd(fd); break; - case 0x3803: mapif_parse_WisToGM(fd); break; - case 0x3804: intif_parse_Registers(fd); break; - case 0x3806: intif_parse_ChangeNameOk(fd); break; - case 0x3807: intif_parse_MessageToFD(fd); break; - case 0x3818: intif_parse_LoadGuildStorage(fd); break; - case 0x3819: intif_parse_SaveGuildStorage(fd); break; - case 0x3820: intif_parse_PartyCreated(fd); break; - case 0x3821: intif_parse_PartyInfo(fd); break; - case 0x3822: intif_parse_PartyMemberAdded(fd); break; - case 0x3823: intif_parse_PartyOptionChanged(fd); break; - case 0x3824: intif_parse_PartyMemberWithdraw(fd); break; - case 0x3825: intif_parse_PartyMove(fd); break; - case 0x3826: intif_parse_PartyBroken(fd); break; - case 0x3827: intif_parse_PartyMessage(fd); break; - case 0x3830: intif_parse_GuildCreated(fd); break; - case 0x3831: intif_parse_GuildInfo(fd); break; - case 0x3832: intif_parse_GuildMemberAdded(fd); break; - case 0x3834: intif_parse_GuildMemberWithdraw(fd); break; - case 0x3835: intif_parse_GuildMemberInfoShort(fd); break; - case 0x3836: intif_parse_GuildBroken(fd); break; - case 0x3837: intif_parse_GuildMessage(fd); break; - case 0x3839: intif_parse_GuildBasicInfoChanged(fd); break; - case 0x383a: intif_parse_GuildMemberInfoChanged(fd); break; - case 0x383b: intif_parse_GuildPosition(fd); break; - case 0x383c: intif_parse_GuildSkillUp(fd); break; - case 0x383d: intif_parse_GuildAlliance(fd); break; - case 0x383e: intif_parse_GuildNotice(fd); break; - case 0x383f: intif_parse_GuildEmblem(fd); break; - case 0x3840: intif_parse_GuildCastleDataLoad(fd); break; - case 0x3843: intif_parse_GuildMasterChanged(fd); break; - - //Quest system - case 0x3860: intif_parse_questlog(fd); break; - case 0x3861: intif_parse_questsave(fd); break; - -// Mail System - case 0x3848: intif_parse_Mail_inboxreceived(fd); break; - case 0x3849: intif_parse_Mail_new(fd); break; - case 0x384a: intif_parse_Mail_getattach(fd); break; - case 0x384b: intif_parse_Mail_delete(fd); break; - case 0x384c: intif_parse_Mail_return(fd); break; - case 0x384d: intif_parse_Mail_send(fd); break; -// Auction System - case 0x3850: intif_parse_Auction_results(fd); break; - case 0x3851: intif_parse_Auction_register(fd); break; - case 0x3852: intif_parse_Auction_cancel(fd); break; - case 0x3853: intif_parse_Auction_close(fd); break; - case 0x3854: intif_parse_Auction_message(fd); break; - case 0x3855: intif_parse_Auction_bid(fd); break; - -// Mercenary System - case 0x3870: intif_parse_mercenary_received(fd); break; - case 0x3871: intif_parse_mercenary_deleted(fd); break; - case 0x3872: intif_parse_mercenary_saved(fd); break; -// Elemental System - case 0x387c: intif_parse_elemental_received(fd); break; - case 0x387d: intif_parse_elemental_deleted(fd); break; - case 0x387e: intif_parse_elemental_saved(fd); break; - - case 0x3880: intif_parse_CreatePet(fd); break; - case 0x3881: intif_parse_RecvPetData(fd); break; - case 0x3882: intif_parse_SavePetOk(fd); break; - case 0x3883: intif_parse_DeletePetOk(fd); break; - case 0x3890: intif_parse_CreateHomunculus(fd); break; - case 0x3891: intif_parse_RecvHomunculusData(fd); break; - case 0x3892: intif_parse_SaveHomunculusOk(fd); break; - case 0x3893: intif_parse_DeleteHomunculusOk(fd); break; + case 0x3800: + if (RFIFOL(fd,4) == 0xFF000000) //Normal announce. + clif->broadcast(NULL, (char *) RFIFOP(fd,16), packet_len-16, BC_DEFAULT, ALL_CLIENT); + else //Color announce. + clif->broadcast2(NULL, (char *) RFIFOP(fd,16), packet_len-16, RFIFOL(fd,4), RFIFOW(fd,8), RFIFOW(fd,10), RFIFOW(fd,12), RFIFOW(fd,14), ALL_CLIENT); + break; + case 0x3801: intif->pWisMessage(fd); break; + case 0x3802: intif->pWisEnd(fd); break; + case 0x3803: intif->pWisToGM(fd); break; + case 0x3804: intif->pRegisters(fd); break; + case 0x3806: intif->pChangeNameOk(fd); break; + case 0x3807: intif->pMessageToFD(fd); break; + case 0x3818: intif->pLoadGuildStorage(fd); break; + case 0x3819: intif->pSaveGuildStorage(fd); break; + case 0x3820: intif->pPartyCreated(fd); break; + case 0x3821: intif->pPartyInfo(fd); break; + case 0x3822: intif->pPartyMemberAdded(fd); break; + case 0x3823: intif->pPartyOptionChanged(fd); break; + case 0x3824: intif->pPartyMemberWithdraw(fd); break; + case 0x3825: intif->pPartyMove(fd); break; + case 0x3826: intif->pPartyBroken(fd); break; + case 0x3827: intif->pPartyMessage(fd); break; + case 0x3830: intif->pGuildCreated(fd); break; + case 0x3831: intif->pGuildInfo(fd); break; + case 0x3832: intif->pGuildMemberAdded(fd); break; + case 0x3834: intif->pGuildMemberWithdraw(fd); break; + case 0x3835: intif->pGuildMemberInfoShort(fd); break; + case 0x3836: intif->pGuildBroken(fd); break; + case 0x3837: intif->pGuildMessage(fd); break; + case 0x3839: intif->pGuildBasicInfoChanged(fd); break; + case 0x383a: intif->pGuildMemberInfoChanged(fd); break; + case 0x383b: intif->pGuildPosition(fd); break; + case 0x383c: intif->pGuildSkillUp(fd); break; + case 0x383d: intif->pGuildAlliance(fd); break; + case 0x383e: intif->pGuildNotice(fd); break; + case 0x383f: intif->pGuildEmblem(fd); break; + case 0x3840: intif->pGuildCastleDataLoad(fd); break; + case 0x3843: intif->pGuildMasterChanged(fd); break; + + //Quest system + case 0x3860: intif->pQuestLog(fd); break; + case 0x3861: intif->pQuestSave(fd); break; + + // Mail System + case 0x3848: intif->pMailInboxReceived(fd); break; + case 0x3849: intif->pMailNew(fd); break; + case 0x384a: intif->pMailGetAttach(fd); break; + case 0x384b: intif->pMailDelete(fd); break; + case 0x384c: intif->pMailReturn(fd); break; + case 0x384d: intif->pMailSend(fd); break; + // Auction System + case 0x3850: intif->pAuctionResults(fd); break; + case 0x3851: intif->pAuctionRegister(fd); break; + case 0x3852: intif->pAuctionCancel(fd); break; + case 0x3853: intif->pAuctionClose(fd); break; + case 0x3854: intif->pAuctionMessage(fd); break; + case 0x3855: intif->pAuctionBid(fd); break; + //Bound items + case 0x3856: +#ifdef GP_BOUND_ITEMS + intif->pItembound_ack(fd); +#else + ShowWarning("intif_parse: Received 0x3856 with GP_BOUND_ITEMS disabled !!!\n"); +#endif + break; + // Mercenary System + case 0x3870: intif->pMercenaryReceived(fd); break; + case 0x3871: intif->pMercenaryDeleted(fd); break; + case 0x3872: intif->pMercenarySaved(fd); break; + // Elemental System + case 0x387c: intif->pElementalReceived(fd); break; + case 0x387d: intif->pElementalDeleted(fd); break; + case 0x387e: intif->pElementalSaved(fd); break; + + case 0x3880: intif->pCreatePet(fd); break; + case 0x3881: intif->pRecvPetData(fd); break; + case 0x3882: intif->pSavePetOk(fd); break; + case 0x3883: intif->pDeletePetOk(fd); break; + case 0x3890: intif->pCreateHomunculus(fd); break; + case 0x3891: intif->pRecvHomunculusData(fd); break; + case 0x3892: intif->pSaveHomunculusOk(fd); break; + case 0x3893: intif->pDeleteHomunculusOk(fd); break; default: ShowError("intif_parse : unknown packet %d %x\n",fd,RFIFOW(fd,0)); return 0; @@ -2257,3 +2305,170 @@ int intif_parse(int fd) RFIFOSKIP(fd,packet_len); return 1; } + +/*===================================== +* Default Functions : intif.h +* Generated by HerculesInterfaceMaker +* created by Susu +*-------------------------------------*/ +void intif_defaults(void) { + const int packet_len_table [INTIF_PACKET_LEN_TABLE_SIZE] = { + -1,-1,27,-1, -1, 0,37,-1, 0, 0, 0, 0, 0, 0, 0, 0, //0x3800-0x380f + 0, 0, 0, 0, 0, 0, 0, 0, -1,11, 0, 0, 0, 0, 0, 0, //0x3810 + 39,-1,15,15, 14,19, 7,-1, 0, 0, 0, 0, 0, 0, 0, 0, //0x3820 + 10,-1,15, 0, 79,19, 7,-1, 0,-1,-1,-1, 14,67,186,-1, //0x3830 + -1, 0, 0,14, 0, 0, 0, 0, -1,74,-1,11, 11,-1, 0, 0, //0x3840 + -1,-1, 7, 7, 7,11, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3850 Auctions [Zephyrus] itembound[Akinari] + -1, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3860 Quests [Kevin] [Inkfish] + -1, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 3, 3, 0, //0x3870 Mercenaries [Zephyrus] / Elemental [pakpil] + 12,-1, 7, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3880 + -1,-1, 7, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3890 Homunculus [albator] + }; + + intif = &intif_s; + + /* */ + memcpy(intif->packet_len_table,&packet_len_table,sizeof(intif->packet_len_table)); + + /* funcs */ + intif->parse = intif_parse; + intif->create_pet = intif_create_pet; + intif->broadcast = intif_broadcast; + intif->broadcast2 = intif_broadcast2; + intif->main_message = intif_main_message; + intif->wis_message = intif_wis_message; + intif->wis_message_to_gm = intif_wis_message_to_gm; + intif->saveregistry = intif_saveregistry; + intif->request_registry = intif_request_registry; + intif->request_guild_storage = intif_request_guild_storage; + intif->send_guild_storage = intif_send_guild_storage; + intif->create_party = intif_create_party; + intif->request_partyinfo = intif_request_partyinfo; + intif->party_addmember = intif_party_addmember; + intif->party_changeoption = intif_party_changeoption; + intif->party_leave = intif_party_leave; + intif->party_changemap = intif_party_changemap; + intif->break_party = intif_break_party; + intif->party_message = intif_party_message; + intif->party_leaderchange = intif_party_leaderchange; + intif->guild_create = intif_guild_create; + intif->guild_request_info = intif_guild_request_info; + intif->guild_addmember = intif_guild_addmember; + intif->guild_leave = intif_guild_leave; + intif->guild_memberinfoshort = intif_guild_memberinfoshort; + intif->guild_break = intif_guild_break; + intif->guild_message = intif_guild_message; + intif->guild_change_gm = intif_guild_change_gm; + intif->guild_change_basicinfo = intif_guild_change_basicinfo; + intif->guild_change_memberinfo = intif_guild_change_memberinfo; + intif->guild_position = intif_guild_position; + intif->guild_skillup = intif_guild_skillup; + intif->guild_alliance = intif_guild_alliance; + intif->guild_notice = intif_guild_notice; + intif->guild_emblem = intif_guild_emblem; + intif->guild_castle_dataload = intif_guild_castle_dataload; + intif->guild_castle_datasave = intif_guild_castle_datasave; + intif->request_petdata = intif_request_petdata; + intif->save_petdata = intif_save_petdata; + intif->delete_petdata = intif_delete_petdata; + intif->rename = intif_rename; + intif->homunculus_create = intif_homunculus_create; + intif->homunculus_requestload = intif_homunculus_requestload; + intif->homunculus_requestsave = intif_homunculus_requestsave; + intif->homunculus_requestdelete = intif_homunculus_requestdelete; + /******QUEST SYTEM*******/ + intif->request_questlog = intif_request_questlog; + intif->quest_save = intif_quest_save; + // MERCENARY SYSTEM + intif->mercenary_create = intif_mercenary_create; + intif->mercenary_request = intif_mercenary_request; + intif->mercenary_delete = intif_mercenary_delete; + intif->mercenary_save = intif_mercenary_save; + // MAIL SYSTEM + intif->Mail_requestinbox = intif_Mail_requestinbox; + intif->Mail_read = intif_Mail_read; + intif->Mail_getattach = intif_Mail_getattach; + intif->Mail_delete = intif_Mail_delete; + intif->Mail_return = intif_Mail_return; + intif->Mail_send = intif_Mail_send; + // AUCTION SYSTEM + intif->Auction_requestlist = intif_Auction_requestlist; + intif->Auction_register = intif_Auction_register; + intif->Auction_cancel = intif_Auction_cancel; + intif->Auction_close = intif_Auction_close; + intif->Auction_bid = intif_Auction_bid; + // ELEMENTAL SYSTEM + intif->elemental_create = intif_elemental_create; + intif->elemental_request = intif_elemental_request; + intif->elemental_delete = intif_elemental_delete; + intif->elemental_save = intif_elemental_save; + /* @accinfo */ + intif->request_accinfo = intif_request_accinfo; + /* */ + intif->CheckForCharServer = CheckForCharServer; + /* */ + intif->itembound_req = intif_itembound_req; + /* 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->pRegisters = intif_parse_Registers; + intif->pChangeNameOk = intif_parse_ChangeNameOk; + intif->pMessageToFD = intif_parse_MessageToFD; + intif->pLoadGuildStorage = intif_parse_LoadGuildStorage; + intif->pSaveGuildStorage = intif_parse_SaveGuildStorage; + intif->pPartyCreated = intif_parse_PartyCreated; + intif->pPartyInfo = intif_parse_PartyInfo; + intif->pPartyMemberAdded = intif_parse_PartyMemberAdded; + intif->pPartyOptionChanged = intif_parse_PartyOptionChanged; + intif->pPartyMemberWithdraw = intif_parse_PartyMemberWithdraw; + intif->pPartyMove = intif_parse_PartyMove; + intif->pPartyBroken = intif_parse_PartyBroken; + intif->pPartyMessage = intif_parse_PartyMessage; + intif->pGuildCreated = intif_parse_GuildCreated; + intif->pGuildInfo = intif_parse_GuildInfo; + intif->pGuildMemberAdded = intif_parse_GuildMemberAdded; + intif->pGuildMemberWithdraw = intif_parse_GuildMemberWithdraw; + intif->pGuildMemberInfoShort = intif_parse_GuildMemberInfoShort; + intif->pGuildBroken = intif_parse_GuildBroken; + intif->pGuildMessage = intif_parse_GuildMessage; + intif->pGuildBasicInfoChanged = intif_parse_GuildBasicInfoChanged; + intif->pGuildMemberInfoChanged = intif_parse_GuildMemberInfoChanged; + intif->pGuildPosition = intif_parse_GuildPosition; + intif->pGuildSkillUp = intif_parse_GuildSkillUp; + intif->pGuildAlliance = intif_parse_GuildAlliance; + intif->pGuildNotice = intif_parse_GuildNotice; + intif->pGuildEmblem = intif_parse_GuildEmblem; + intif->pGuildCastleDataLoad = intif_parse_GuildCastleDataLoad; + intif->pGuildMasterChanged = intif_parse_GuildMasterChanged; + intif->pQuestLog = intif_parse_QuestLog; + intif->pQuestSave = intif_parse_QuestSave; + intif->pMailInboxReceived = intif_parse_MailInboxReceived; + intif->pMailNew = intif_parse_MailNew; + intif->pMailGetAttach = intif_parse_MailGetAttach; + intif->pMailDelete = intif_parse_MailDelete; + intif->pMailReturn = intif_parse_MailReturn; + intif->pMailSend = intif_parse_MailSend; + intif->pAuctionResults = intif_parse_AuctionResults; + intif->pAuctionRegister = intif_parse_AuctionRegister; + intif->pAuctionCancel = intif_parse_AuctionCancel; + intif->pAuctionClose = intif_parse_AuctionClose; + intif->pAuctionMessage = intif_parse_AuctionMessage; + intif->pAuctionBid = intif_parse_AuctionBid; + intif->pItembound_ack = intif_parse_Itembound_ack; + intif->pMercenaryReceived = intif_parse_MercenaryReceived; + intif->pMercenaryDeleted = intif_parse_MercenaryDeleted; + intif->pMercenarySaved = intif_parse_MercenarySaved; + intif->pElementalReceived = intif_parse_ElementalReceived; + intif->pElementalDeleted = intif_parse_ElementalDeleted; + intif->pElementalSaved = intif_parse_ElementalSaved; + intif->pCreatePet = intif_parse_CreatePet; + intif->pRecvPetData = intif_parse_RecvPetData; + intif->pSavePetOk = intif_parse_SavePetOk; + intif->pDeletePetOk = intif_parse_DeletePetOk; + intif->pCreateHomunculus = intif_parse_CreateHomunculus; + intif->pRecvHomunculusData = intif_parse_RecvHomunculusData; + intif->pSaveHomunculusOk = intif_parse_SaveHomunculusOk; + intif->pDeleteHomunculusOk = intif_parse_DeleteHomunculusOk; +} diff --git a/src/map/intif.h b/src/map/intif.h index 43bbc0859..fe47d6537 100644 --- a/src/map/intif.h +++ b/src/map/intif.h @@ -1,112 +1,189 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder +// Copyright (c) Hercules Dev Team, licensed under GNU GPL. +// See the LICENSE file +// Portions Copyright (c) Athena Dev Teams -#ifndef _INTIF_H_ -#define _INFIF_H_ +#ifndef MAP_INTIF_H +#define MAP_INTIF_H -//#include "../common/mmo.h" -struct party_member; +#include "../common/cbasetypes.h" + +/** + * Declarations + **/ +struct auction_data; struct guild_member; struct guild_position; -struct s_pet; +struct guild_storage; +struct mail_message; +struct map_session_data; +struct party_member; +struct s_elemental; struct s_homunculus; struct s_mercenary; -struct s_elemental; -struct mail_message; -struct auction_data; - -int intif_parse(int fd); - -int intif_broadcast(const char* mes, int len, int type); -int intif_broadcast2(const char* mes, int len, unsigned long fontColor, short fontType, short fontSize, short fontAlign, short fontY); -int intif_main_message(struct map_session_data* sd, const char* message); - -int intif_wis_message(struct map_session_data *sd,char *nick,char *mes,int mes_len); -int intif_wis_message_to_gm(char *Wisp_name, int permission, char *mes); - -int intif_saveregistry(struct map_session_data *sd, int type); -int intif_request_registry(struct map_session_data *sd, int flag); - -int intif_request_guild_storage(int account_id, int guild_id); -int intif_send_guild_storage(int account_id, struct guild_storage *gstor); - - -int intif_create_party(struct party_member *member,char *name,int item,int item2); -int intif_request_partyinfo(int party_id, int char_id); - -int intif_party_addmember(int party_id,struct party_member *member); -int intif_party_changeoption(int party_id, int account_id, int exp, int item); -int intif_party_leave(int party_id,int account_id, int char_id); -int intif_party_changemap(struct map_session_data *sd, int online); -int intif_break_party(int party_id); -int intif_party_message(int party_id, int account_id, const char *mes,int len); -int intif_party_leaderchange(int party_id,int account_id,int char_id); - - -int intif_guild_create(const char *name, const struct guild_member *master); -int intif_guild_request_info(int guild_id); -int intif_guild_addmember(int guild_id, struct guild_member *m); -int intif_guild_leave(int guild_id, int account_id, int char_id, int flag, const char *mes); -int intif_guild_memberinfoshort(int guild_id, int account_id, int char_id, int online, int lv, int class_); -int intif_guild_break(int guild_id); -int intif_guild_message(int guild_id, int account_id, const char *mes, int len); -int intif_guild_change_gm(int guild_id, const char* name, int len); -int intif_guild_change_basicinfo(int guild_id, int type, const void *data, int len); -int intif_guild_change_memberinfo(int guild_id, int account_id, int char_id, int type, const void *data, int len); -int intif_guild_position(int guild_id, int idx, struct guild_position *p); -int intif_guild_skillup(int guild_id, uint16 skill_id, int account_id, int max); -int intif_guild_alliance(int guild_id1, int guild_id2, int account_id1, int account_id2, int flag); -int intif_guild_notice(int guild_id, const char *mes1, const char *mes2); -int intif_guild_emblem(int guild_id, int len, const char *data); -int intif_guild_castle_dataload(int num, int *castle_ids); -int intif_guild_castle_datasave(int castle_id, int index, int value); - -int intif_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 incuvate, char *pet_name); -int intif_request_petdata(int account_id, int char_id, int pet_id); -int intif_save_petdata(int account_id, struct s_pet *p); -int intif_delete_petdata(int pet_id); -int intif_rename(struct map_session_data *sd, int type, char *name); -#define intif_rename_pc(sd, name) intif_rename(sd, 0, name) -#define intif_rename_pet(sd, name) intif_rename(sd, 1, name) -#define intif_rename_hom(sd, name) intif_rename(sd, 2, name) -int intif_homunculus_create(int account_id, struct s_homunculus *sh); -bool intif_homunculus_requestload(int account_id, int homun_id); -int intif_homunculus_requestsave(int account_id, struct s_homunculus* sh); -int intif_homunculus_requestdelete(int homun_id); - -/******QUEST SYTEM*******/ -int intif_request_questlog(struct map_session_data * sd); -int intif_quest_save(struct map_session_data * sd); - -// MERCENARY SYSTEM -int intif_mercenary_create(struct s_mercenary *merc); -int intif_mercenary_request(int merc_id, int char_id); -int intif_mercenary_delete(int merc_id); -int intif_mercenary_save(struct s_mercenary *merc); - -// MAIL SYSTEM -int intif_Mail_requestinbox(int char_id, unsigned char flag); -int intif_Mail_read(int mail_id); -int intif_Mail_getattach(int char_id, int mail_id); -int intif_Mail_delete(int char_id, int mail_id); -int intif_Mail_return(int char_id, int mail_id); -int intif_Mail_send(int account_id, struct mail_message *msg); -// AUCTION SYSTEM -int intif_Auction_requestlist(int char_id, short type, int price, const char* searchtext, short page); -int intif_Auction_register(struct auction_data *auction); -int intif_Auction_cancel(int char_id, unsigned int auction_id); -int intif_Auction_close(int char_id, unsigned int auction_id); -int intif_Auction_bid(int char_id, const char* name, unsigned int auction_id, int bid); -// ELEMENTAL SYSTEM -int intif_elemental_create(struct s_elemental *ele); -int intif_elemental_request(int ele_id, int char_id); -int intif_elemental_delete(int ele_id); -int intif_elemental_save(struct s_elemental *ele); - -/* @accinfo */ -void intif_request_accinfo( int u_fd, int aid, int group_lv, char* query ); - -int CheckForCharServer(void); +struct s_pet; -#endif /* _INTIF_H_ */ +/** + * Defines + **/ +#define intif_rename_pc(sd, name) (intif->rename((sd), 0, (name))) +#define intif_rename_pet(sd, name) (intif->rename((sd), 1, (name))) +#define intif_rename_hom(sd, name) (intif->rename((sd), 2, (name))) +#define INTIF_PACKET_LEN_TABLE_SIZE 161 + + +/*===================================== +* Interface : intif.h +* Generated by HerculesInterfaceMaker +* created by Susu +*-------------------------------------*/ +struct intif_interface { + /* */ + int packet_len_table[INTIF_PACKET_LEN_TABLE_SIZE]; + /* funcs */ + 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 (*main_message) (struct map_session_data* sd, const char* message); + int (*wis_message) (struct map_session_data *sd,char *nick,char *mes,size_t 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); + int (*request_guild_storage) (int account_id, int guild_id); + int (*send_guild_storage) (int account_id, struct guild_storage *gstor); + int (*create_party) (struct party_member *member,char *name,int item,int item2); + int (*request_partyinfo) (int party_id, int char_id); + int (*party_addmember) (int party_id,struct party_member *member); + int (*party_changeoption) (int party_id, int account_id, int exp, int item); + int (*party_leave) (int party_id,int account_id, int char_id); + int (*party_changemap) (struct map_session_data *sd, int online); + int (*break_party) (int party_id); + int (*party_message) (int party_id, int account_id, const char *mes,int len); + int (*party_leaderchange) (int party_id,int account_id,int char_id); + int (*guild_create) (const char *name, const struct guild_member *master); + int (*guild_request_info) (int guild_id); + int (*guild_addmember) (int guild_id, struct guild_member *m); + int (*guild_leave) (int guild_id, int account_id, int char_id, int flag, const char *mes); + 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_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); + int (*guild_skillup) (int guild_id, uint16 skill_id, int account_id, int max); + int (*guild_alliance) (int guild_id1, int guild_id2, int account_id1, int account_id2, int flag); + int (*guild_notice) (int guild_id, const char *mes1, const char *mes2); + int (*guild_emblem) (int guild_id, int len, const char *data); + int (*guild_castle_dataload) (int num, int *castle_ids); + int (*guild_castle_datasave) (int castle_id, int index, int value); + void (*itembound_req) (int char_id, int aid, int guild_id); + int (*request_petdata) (int account_id, int char_id, int pet_id); + int (*save_petdata) (int account_id, struct s_pet *p); + int (*delete_petdata) (int pet_id); + int (*rename) (struct map_session_data *sd, int type, char *name); + int (*homunculus_create) (int account_id, struct s_homunculus *sh); + bool (*homunculus_requestload) (int account_id, int homun_id); + int (*homunculus_requestsave) (int account_id, struct s_homunculus* sh); + int (*homunculus_requestdelete) (int homun_id); + /******QUEST SYTEM*******/ + void (*request_questlog) (struct map_session_data * sd); + int (*quest_save) (struct map_session_data * sd); + // MERCENARY SYSTEM + int (*mercenary_create) (struct s_mercenary *merc); + int (*mercenary_request) (int merc_id, int char_id); + int (*mercenary_delete) (int merc_id); + int (*mercenary_save) (struct s_mercenary *merc); + // MAIL SYSTEM + int (*Mail_requestinbox) (int char_id, unsigned char flag); + int (*Mail_read) (int mail_id); + int (*Mail_getattach) (int char_id, int mail_id); + int (*Mail_delete) (int char_id, int mail_id); + int (*Mail_return) (int char_id, int mail_id); + int (*Mail_send) (int account_id, struct mail_message *msg); + // AUCTION SYSTEM + int (*Auction_requestlist) (int char_id, short type, int price, const char* searchtext, short page); + int (*Auction_register) (struct auction_data *auction); + int (*Auction_cancel) (int char_id, unsigned int auction_id); + int (*Auction_close) (int char_id, unsigned int auction_id); + int (*Auction_bid) (int char_id, const char* name, unsigned int auction_id, int bid); + // ELEMENTAL SYSTEM + int (*elemental_create) (struct s_elemental *ele); + int (*elemental_request) (int ele_id, int char_id); + int (*elemental_delete) (int ele_id); + int (*elemental_save) (struct s_elemental *ele); + /* @accinfo */ + void (*request_accinfo) (int u_fd, int aid, int group_lv, char* query); + /* */ + int (*CheckForCharServer) (void); + /* */ + void (*pWisMessage) (int fd); + void (*pWisEnd) (int fd); + int (*pWisToGM_sub) (struct map_session_data* sd,va_list va); + void (*pWisToGM) (int fd); + void (*pRegisters) (int fd); + void (*pChangeNameOk) (int fd); + void (*pMessageToFD) (int fd); + void (*pLoadGuildStorage) (int fd); + void (*pSaveGuildStorage) (int fd); + void (*pPartyCreated) (int fd); + void (*pPartyInfo) (int fd); + void (*pPartyMemberAdded) (int fd); + void (*pPartyOptionChanged) (int fd); + void (*pPartyMemberWithdraw) (int fd); + void (*pPartyMove) (int fd); + void (*pPartyBroken) (int fd); + void (*pPartyMessage) (int fd); + void (*pGuildCreated) (int fd); + void (*pGuildInfo) (int fd); + void (*pGuildMemberAdded) (int fd); + void (*pGuildMemberWithdraw) (int fd); + void (*pGuildMemberInfoShort) (int fd); + void (*pGuildBroken) (int fd); + void (*pGuildMessage) (int fd); + void (*pGuildBasicInfoChanged) (int fd); + void (*pGuildMemberInfoChanged) (int fd); + void (*pGuildPosition) (int fd); + void (*pGuildSkillUp) (int fd); + void (*pGuildAlliance) (int fd); + void (*pGuildNotice) (int fd); + void (*pGuildEmblem) (int fd); + void (*pGuildCastleDataLoad) (int fd); + void (*pGuildMasterChanged) (int fd); + void (*pQuestLog) (int fd); + void (*pQuestSave) (int fd); + void (*pMailInboxReceived) (int fd); + void (*pMailNew) (int fd); + void (*pMailGetAttach) (int fd); + void (*pMailDelete) (int fd); + void (*pMailReturn) (int fd); + void (*pMailSend) (int fd); + void (*pAuctionResults) (int fd); + void (*pAuctionRegister) (int fd); + void (*pAuctionCancel) (int fd); + void (*pAuctionClose) (int fd); + void (*pAuctionMessage) (int fd); + void (*pAuctionBid) (int fd); + void (*pItembound_ack) (int fd); + void (*pMercenaryReceived) (int fd); + void (*pMercenaryDeleted) (int fd); + void (*pMercenarySaved) (int fd); + void (*pElementalReceived) (int fd); + void (*pElementalDeleted) (int fd); + void (*pElementalSaved) (int fd); + void (*pCreatePet) (int fd); + void (*pRecvPetData) (int fd); + void (*pSavePetOk) (int fd); + void (*pDeletePetOk) (int fd); + void (*pCreateHomunculus) (int fd); + void (*pRecvHomunculusData) (int fd); + void (*pSaveHomunculusOk) (int fd); + void (*pDeleteHomunculusOk) (int fd); +}; + +struct intif_interface *intif; + +void intif_defaults(void); + +#endif /* MAP_INTIF_H */ diff --git a/src/map/irc-bot.c b/src/map/irc-bot.c index 7f03ed8d4..6f016697f 100644 --- a/src/map/irc-bot.c +++ b/src/map/irc-bot.c @@ -2,26 +2,36 @@ // See the LICENSE file // Base Author: shennetsind @ http://hercules.ws +#define HERCULES_CORE + +#include "irc-bot.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "clif.h" +#include "map.h" +#include "pc.h" #include "../common/cbasetypes.h" #include "../common/malloc.h" -#include "../common/strlib.h" +#include "../common/random.h" #include "../common/showmsg.h" #include "../common/socket.h" +#include "../common/strlib.h" #include "../common/timer.h" -#include "../common/random.h" -#include "map.h" -#include "pc.h" -#include "clif.h" -#include "irc-bot.h" +//#define IRCBOT_DEBUG -#include <stdio.h> -#include <stdlib.h> -#include <string.h> +struct irc_bot_interface irc_bot_s; -char send_string[200]; +char send_string[IRC_MESSAGE_LENGTH]; -int irc_connect_timer(int tid, unsigned int tick, int id, intptr_t data) { +/** + * Timer callback to (re-)connect to an IRC server + * @see timer->do_timer + */ +int irc_connect_timer(int tid, int64 tick, int id, intptr_t data) { struct hSockOpt opt; if( ircbot->isOn || ++ircbot->fails >= 3 ) return 0; @@ -29,18 +39,22 @@ int irc_connect_timer(int tid, unsigned int tick, int id, intptr_t data) { opt.silent = 1; opt.setTimeo = 0; - ircbot->last_try = iTimer->gettick(); + ircbot->last_try = timer->gettick(); if( ( ircbot->fd = make_connection(ircbot->ip,hChSys.irc_server_port,&opt) ) > 0 ){ session[ircbot->fd]->func_parse = ircbot->parse; session[ircbot->fd]->flag.server = 1; - iTimer->add_timer(iTimer->gettick() + 3000, ircbot->identify_timer, 0, 0); + timer->add(timer->gettick() + 3000, ircbot->identify_timer, 0, 0); ircbot->isOn = true; } return 0; } -int irc_identify_timer(int tid, unsigned int tick, int id, intptr_t data) { +/** + * Timer callback to send identification commands to an IRC server + * @see timer->do_timer + */ +int irc_identify_timer(int tid, int64 tick, int id, intptr_t data) { if( !ircbot->isOn ) return 0; @@ -49,18 +63,25 @@ int irc_identify_timer(int tid, unsigned int tick, int id, intptr_t data) { sprintf(send_string, "NICK %s", hChSys.irc_nick); ircbot->send(send_string); - iTimer->add_timer(iTimer->gettick() + 3000, ircbot->join_timer, 0, 0); + timer->add(timer->gettick() + 3000, ircbot->join_timer, 0, 0); return 0; } -int irc_join_timer(int tid, unsigned int tick, int id, intptr_t data) { +/** + * Timer callback to join channels (and optionally send NickServ commands) + * @see timer->do_timer + */ +int irc_join_timer(int tid, int64 tick, int id, intptr_t data) { if( !ircbot->isOn ) return 0; if( hChSys.irc_nick_pw[0] != '\0' ) { sprintf(send_string, "PRIVMSG NICKSERV : IDENTIFY %s", hChSys.irc_nick_pw); ircbot->send(send_string); + if( hChSys.irc_use_ghost ) { + sprintf(send_string, "PRIVMSG NICKSERV : GHOST %s %s", hChSys.irc_nick, hChSys.irc_nick_pw); + } } sprintf(send_string, "JOIN %s", hChSys.irc_channel); @@ -70,6 +91,12 @@ int irc_join_timer(int tid, unsigned int tick, int id, intptr_t data) { 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 + */ struct irc_func* irc_func_search(char* function_name) { int i; for(i = 0; i < ircbot->funcs.size; i++) { @@ -80,6 +107,10 @@ struct irc_func* irc_func_search(char* function_name) { return NULL; } +/** + * Parser for the IRC server connection + * @see do_sockets + */ int irc_parse(int fd) { char *parse_string = NULL, *str_safe = NULL; @@ -90,7 +121,7 @@ int irc_parse(int fd) { ircbot->isIn = false; ircbot->fails = 0; ircbot->ip = host2ip(hChSys.irc_server); - iTimer->add_timer(iTimer->gettick() + 120000, ircbot->connect_timer, 0, 0); + timer->add(timer->gettick() + 120000, ircbot->connect_timer, 0, 0); return 0; } @@ -112,83 +143,156 @@ 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) + */ void irc_parse_source(char *source, char *nick, char *ident, char *host) { - int i, len = strlen(source), pos = 0; + int i, pos = 0; + size_t len = strlen(source); unsigned char stage = 0; for(i = 0; i < len; i++) { if( stage == 0 && source[i] == '!' ) { - memcpy(nick, &source[0], min(i,IRC_NICK_LENGTH)); - nick[i] = '\0'; + safestrncpy(nick, &source[0], min(i + 1, IRC_NICK_LENGTH)); pos = i+1; stage = 1; } else if( stage == 1 && source[i] == '@' ) { - memcpy(ident, &source[pos], min(i - pos,IRC_IDENT_LENGTH)); - ident[i-pos] = '\0'; - memcpy(host, &source[i+1], min(len - i,IRC_HOST_LENGTH)); - host[len] = '\0'; + safestrncpy(ident, &source[pos], min(i - pos + 1, IRC_IDENT_LENGTH)); + safestrncpy(host, &source[i+1], min(len - i, IRC_HOST_LENGTH)); break; } } } + +/** + * 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 irc_parse_sub(int fd, char *str) { - char source[180], command[60], target[60], message[200]; + char source[180], command[60], buf1[IRC_MESSAGE_LENGTH], buf2[IRC_MESSAGE_LENGTH]; + char *target = buf1, *message = buf2; struct irc_func *func; - source[0] = command[0] = target[0] = message[0] = '\0'; + source[0] = command[0] = buf1[0] = buf2[0] = '\0'; if( str[0] == ':' ) str++; - sscanf(str, "%179s %59s %59s :%199[^\r\n]", source, command, target, message); + if (sscanf(str, "%179s %59s %499s :%499[^\r\n]", source, command, buf1, buf2) == 3 && buf1[0] == ':') { + // source command :message (i.e. QUIT) + message = buf1+1; + target = buf2; + } if( command[0] == '\0' ) return; if( !(func = ircbot->func_search(command)) && !(func = ircbot->func_search(source)) ) { - //ShowWarning("Unknown command received %s from %s\n",command,source); +#ifdef IRCBOT_DEBUG + ShowWarning("Unknown command received %s from %s\n",command,source); +#endif // IRCBOT_DEBUG return; } 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) { - int len = strlen(str) + 2; + size_t len = strlen(str) + 2; + if (len > IRC_MESSAGE_LENGTH-3) + len = IRC_MESSAGE_LENGTH-3; WFIFOHEAD(ircbot->fd, len); - snprintf((char*)WFIFOP(ircbot->fd,0),200, "%s\r\n", str); + snprintf((char*)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 + */ void irc_pong(int fd, char *cmd, char *source, char *target, char *msg) { sprintf(send_string, "PONG %s", cmd); ircbot->send(send_string); } -void irc_join(int fd, char *cmd, char *source, char *target, char *msg) { - if( ircbot->isIn ) - return; - sprintf(send_string, "JOIN %s", hChSys.irc_channel); - ircbot->send(send_string); - ircbot->isIn = true; +/** + * Handler for CTCP commands received via PRIVMSG + * @see irc_privmsg + */ +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]; + + source_nick[0] = source_ident[0] = source_host[0] = '\0'; + + if( source[0] != '\0' ) + ircbot->parse_source(source,source_nick,source_ident,source_host); + + if( strcmpi(cmd,"ACTION") == 0 ) { + if( ircbot->channel ) { + snprintf(send_string, 150, "[ #%s ] * IRC.%s %s *",ircbot->channel->name,source_nick,msg); + clif->chsys_msg2(ircbot->channel,send_string); + } + } else if( strcmpi(cmd,"ERRMSG") == 0 ) { + // Ignore it + } else if( strcmpi(cmd,"FINGER") == 0 ) { + // Ignore it + } else if( strcmpi(cmd,"PING") == 0 ) { + sprintf(send_string, "NOTICE %s :\001PING %s\001",source_nick,msg); + ircbot->send(send_string); + } 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, ... + char temp[CHAT_SIZE_MAX]; + + memset(temp, '\0', sizeof(temp)); + + time(&time_server); // get time in seconds since 1/1/1970 + datetime = localtime(&time_server); // convert seconds in structure + // like sprintf, but only for date/time (Sunday, November 02 2003 15:12:52) + strftime(temp, sizeof(temp)-1, msg_txt(230), datetime); // Server time (normal time): %A, %B %d %Y %X. + + sprintf(send_string, "NOTICE %s :\001TIME %s\001",source_nick,temp); + ircbot->send(send_string); + } else if( strcmpi(cmd,"VERSION") == 0 ) { + sprintf(send_string, "NOTICE %s :\001VERSION Hercules.ws IRC Bridge\001",source_nick); + ircbot->send(send_string); +#ifdef IRCBOT_DEBUG + } else { + ShowWarning("Unknown CTCP command received %s (%s) from %s\n",cmd,msg,source); +#endif // IRCBOT_DEBUG + } } +/** + * Handler for the PRIVMSG IRC command (action depends on the message contents) + * @see irc_parse_sub + */ void irc_privmsg(int fd, char *cmd, char *source, char *target, char *msg) { - if( strcmpi(target,hChSys.irc_nick) == 0 ) { - if( msg[0] == ':' ) msg++; - if( strcmpi(msg,"VERSION") == 0 ) { - char source_nick[IRC_NICK_LENGTH], source_ident[IRC_IDENT_LENGTH], source_host[IRC_HOST_LENGTH]; - - source_nick[0] = source_ident[0] = source_host[0] = '\0'; - - if( source[0] != '\0' ) - ircbot->parse_source(source,source_nick,source_ident,source_host); - - sprintf(send_string, "NOTICE %s :Hercules.ws IRC Bridge",source_nick); - ircbot->send(send_string); - return; - } - } else if( strcmpi(target,hChSys.irc_channel) == 0 ) { + if( msg && *msg == '\001' && strlen(msg) > 2 && msg[strlen(msg)-1] == '\001' ) { + // CTCP + char command[IRC_MESSAGE_LENGTH], message[IRC_MESSAGE_LENGTH]; + 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); +#ifdef IRCBOT_DEBUG + } else if( strcmpi(target,hChSys.irc_nick) == 0 ) { + ShowDebug("irc_privmsg: Received message from %s: '%s'\n", source ? source : "(null)", msg); +#endif // IRCBOT_DEBUG + } else if( msg && strcmpi(target,hChSys.irc_channel) == 0 ) { char source_nick[IRC_NICK_LENGTH], source_ident[IRC_IDENT_LENGTH], source_host[IRC_HOST_LENGTH]; source_nick[0] = source_ident[0] = source_host[0] = '\0'; @@ -197,26 +301,110 @@ void irc_privmsg(int fd, char *cmd, char *source, char *target, char *msg) { ircbot->parse_source(source,source_nick,source_ident,source_host); if( ircbot->channel ) { - snprintf(send_string, 150, "[ #%s ] IRC.%s : %s",ircbot->channel->name,source_nick,msg); - clif->chsys_msg2(ircbot->channel,send_string); + size_t padding_len = strlen(ircbot->channel->name) + strlen(source_nick) + 13; + while (1) { + snprintf(send_string, 150, "[ #%s ] IRC.%s : %s",ircbot->channel->name,source_nick,msg); + clif->chsys_msg2(ircbot->channel,send_string); + //break; // Uncomment this line to truncate long messages instead of posting them as multiple lines + if (strlen(msg) <= 149 - padding_len) + break; + msg += 149 - padding_len; + } } } } -void irc_relay (char *name, char *msg) { +/** + * Handler for the JOIN IRC command (notify an in-game channel of users joining + * the IRC channel) + * @see irc_parse_sub + */ +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]; + + source_nick[0] = source_ident[0] = source_host[0] = '\0'; + + if( source[0] != '\0' ) + ircbot->parse_source(source,source_nick,source_ident,source_host); + + if( ircbot->channel ) { + snprintf(send_string, 150, "[ #%s ] User IRC.%s joined the channel.",ircbot->channel->name,source_nick); + clif->chsys_msg2(ircbot->channel,send_string); + } +} + +/** + * Handler for the PART and QUIT IRC commands (notify an in-game channel of + * users leaving the IRC channel) + * @see irc_parse_sub + */ +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]; + + source_nick[0] = source_ident[0] = source_host[0] = '\0'; + + if( source[0] != '\0' ) + ircbot->parse_source(source,source_nick,source_ident,source_host); + + if( ircbot->channel ) { + if (!strcmpi(cmd, "QUIT")) + snprintf(send_string, 150, "[ #%s ] User IRC.%s left the channel. [Quit: %s]",ircbot->channel->name,source_nick,msg); + else + snprintf(send_string, 150, "[ #%s ] User IRC.%s left the channel. [%s]",ircbot->channel->name,source_nick,msg); + clif->chsys_msg2(ircbot->channel,send_string); + } +} + +/** + * 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 + */ +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]; + + source_nick[0] = source_ident[0] = source_host[0] = '\0'; + + if( source[0] != '\0' ) + ircbot->parse_source(source,source_nick,source_ident,source_host); + + if( ircbot->channel ) { + snprintf(send_string, 150, "[ #%s ] User IRC.%s is now known as IRC.%s",ircbot->channel->name,source_nick,msg); + clif->chsys_msg2(ircbot->channel,send_string); + } +} + +/** + * Relay a chat message to the irc channel the bot is connected to + * @param name Sender's name + * @param msg Message text + */ +void irc_relay(char *name, const char *msg) { if( !ircbot->isIn ) return; sprintf(send_string,"PRIVMSG %s :[ %s ] : %s",hChSys.irc_channel,name,msg); ircbot->send(send_string); } -void irc_bot_init(void) { + +/** + * IRC bot initializer + */ +void irc_bot_init(bool minimal) { + /// Command handlers const struct irc_func irc_func_base[] = { { "PING" , ircbot->pong }, { "PRIVMSG", ircbot->privmsg }, + { "JOIN", ircbot->userjoin }, + { "QUIT", ircbot->userleave }, + { "PART", ircbot->userleave }, + { "NICK", ircbot->usernick }, }; struct irc_func* function; int i; + if (minimal) + return; + if( !hChSys.irc ) return; @@ -245,10 +433,13 @@ void irc_bot_init(void) { ircbot->isIn = false; ircbot->isOn = false; - iTimer->add_timer_func_list(ircbot->connect_timer, "irc_connect_timer"); - iTimer->add_timer(iTimer->gettick() + 7000, ircbot->connect_timer, 0, 0); + timer->add_func_list(ircbot->connect_timer, "irc_connect_timer"); + timer->add(timer->gettick() + 7000, ircbot->connect_timer, 0, 0); } +/** + * IRC bot finalizer + */ void irc_bot_final(void) { int i; @@ -265,6 +456,9 @@ void irc_bot_final(void) { aFree(ircbot->funcs.list); } +/** + * IRC bot interface defaults initializer + */ void ircbot_defaults(void) { ircbot = &irc_bot_s; @@ -287,6 +481,9 @@ void ircbot_defaults(void) { ircbot->relay = irc_relay; ircbot->pong = irc_pong; - ircbot->join = irc_join; ircbot->privmsg = irc_privmsg; + + ircbot->userjoin = irc_userjoin; + ircbot->userleave = irc_userleave; + ircbot->usernick = irc_usernick; } diff --git a/src/map/irc-bot.h b/src/map/irc-bot.h index 911a15b0e..0c26c3cd8 100644 --- a/src/map/irc-bot.h +++ b/src/map/irc-bot.h @@ -3,13 +3,16 @@ // Base Author: shennetsind @ http://hercules.ws -#ifndef _IRC_BOT_H_ -#define _IRC_BOT_H_ +#ifndef MAP_IRC_BOT_H +#define MAP_IRC_BOT_H + +#include "../common/cbasetypes.h" #define IRC_NICK_LENGTH 40 #define IRC_IDENT_LENGTH 40 #define IRC_HOST_LENGTH 63 #define IRC_FUNC_LENGTH 30 +#define IRC_MESSAGE_LENGTH 500 struct hChSysCh; @@ -21,9 +24,9 @@ struct irc_func { struct irc_bot_interface { int fd; bool isIn, isOn; - unsigned int last_try; + int64 last_try; unsigned char fails; - unsigned long ip; + uint32 ip; unsigned short port; /* */ struct hChSysCh *channel; @@ -33,7 +36,7 @@ struct irc_bot_interface { unsigned int size; } funcs; /* */ - void (*init) (void); + void (*init) (bool minimal); void (*final) (void); /* */ int (*parse) (int fd); @@ -42,20 +45,22 @@ struct irc_bot_interface { /* */ struct irc_func* (*func_search) (char* function_name); /* */ - int (*connect_timer) (int tid, unsigned int tick, int id, intptr_t data); - int (*identify_timer) (int tid, unsigned int tick, int id, intptr_t data); - int (*join_timer) (int tid, unsigned int tick, int id, intptr_t data); + int (*connect_timer) (int tid, int64 tick, int id, intptr_t data); + int (*identify_timer) (int tid, int64 tick, int id, intptr_t data); + int (*join_timer) (int tid, int64 tick, int id, intptr_t data); /* */ void (*send)(char *str); - void (*relay) (char *name, char *msg); + void (*relay) (char *name, const char *msg); /* */ void (*pong) (int fd, char *cmd, char *source, char *target, char *msg); - void (*join) (int fd, char *cmd, char *source, char *target, char *msg); void (*privmsg) (int fd, char *cmd, char *source, char *target, char *msg); -} irc_bot_s; + void (*userjoin) (int fd, char *cmd, char *source, char *target, char *msg); + void (*userleave) (int fd, char *cmd, char *source, char *target, char *msg); + void (*usernick) (int fd, char *cmd, char *source, char *target, char *msg); +}; struct irc_bot_interface *ircbot; void ircbot_defaults(void); -#endif /* _IRC_BOT_H_ */ +#endif /* MAP_IRC_BOT_H */ diff --git a/src/map/itemdb.c b/src/map/itemdb.c index 859b19aac..0d3146191 100644 --- a/src/map/itemdb.c +++ b/src/map/itemdb.c @@ -2,44 +2,49 @@ // See the LICENSE file // Portions Copyright (c) Athena Dev Teams -#include "../common/nullpo.h" -#include "../common/malloc.h" -#include "../common/random.h" -#include "../common/showmsg.h" -#include "../common/strlib.h" -#include "../common/utils.h" +#define HERCULES_CORE + +#include "../config/core.h" // DBPATH, RENEWAL #include "itemdb.h" -#include "map.h" -#include "battle.h" // struct battle_config -#include "script.h" // item script processing -#include "pc.h" // W_MUSICAL, W_WHIP #include <stdio.h> #include <stdlib.h> #include <string.h> -static struct item_data* itemdb_array[MAX_ITEMDB]; -static DBMap* itemdb_other;// int nameid -> struct item_data* +#include "battle.h" // struct battle_config +#include "map.h" +#include "mob.h" // MAX_MOB_DB +#include "pc.h" // W_MUSICAL, W_WHIP +#include "script.h" // item script processing +#include "../common/conf.h" +#include "../common/malloc.h" +#include "../common/nullpo.h" +#include "../common/random.h" +#include "../common/showmsg.h" +#include "../common/strlib.h" +#include "../common/utils.h" -struct item_data dummy_item; //This is the default dummy item used for non-existant items. [Skotlex] +struct itemdb_interface itemdb_s; /** - * Search for item name + * Search for item name * name = item alias, so we should find items aliases first. if not found then look for "jname" (full name) * @see DBApply */ -static int itemdb_searchname_sub(DBKey key, DBData *data, va_list ap) +int itemdb_searchname_sub(DBKey key, DBData *data, va_list ap) { struct item_data *item = DB->data2ptr(data), **dst, **dst2; char *str; str=va_arg(ap,char *); dst=va_arg(ap,struct item_data **); dst2=va_arg(ap,struct item_data **); - if(item == &dummy_item) return 0; + if (item == &itemdb->dummy) return 0; //Absolute priority to Aegis code name. if (*dst != NULL) return 0; - if( strcmpi(item->name,str)==0 ) + if ( battle_config.case_sensitive_aegisnames && strcmp(item->name,str) == 0 ) + *dst=item; + else if ( !battle_config.case_sensitive_aegisnames && strcasecmp(item->name,str) == 0 ) *dst=item; //Second priority to Client displayed name. @@ -50,22 +55,22 @@ static int itemdb_searchname_sub(DBKey key, DBData *data, va_list ap) } /*========================================== - * Return item data from item name. (lookup) + * Return item data from item name. (lookup) *------------------------------------------*/ -struct item_data* itemdb_searchname(const char *str) -{ +struct item_data* itemdb_searchname(const char *str) { struct item_data* item; struct item_data* item2=NULL; int i; - for( i = 0; i < ARRAYLENGTH(itemdb_array); ++i ) - { - item = itemdb_array[i]; + for( i = 0; i < ARRAYLENGTH(itemdb->array); ++i ) { + item = itemdb->array[i]; if( item == NULL ) continue; // Absolute priority to Aegis code name. - if( strcasecmp(item->name,str) == 0 ) + if ( battle_config.case_sensitive_aegisnames && strcmp(item->name,str) == 0 ) + return item; + else if ( !battle_config.case_sensitive_aegisnames && strcasecmp(item->name,str) == 0 ) return item; //Second priority to Client displayed name. @@ -74,45 +79,63 @@ struct item_data* itemdb_searchname(const char *str) } item = NULL; - itemdb_other->foreach(itemdb_other,itemdb_searchname_sub,str,&item,&item2); + itemdb->other->foreach(itemdb->other,itemdb->searchname_sub,str,&item,&item2); return item?item:item2; } +/* name to item data */ +struct item_data* itemdb_name2id(const char *str) { + return strdb_get(itemdb->names,str); +} /** * @see DBMatcher */ -static int itemdb_searchname_array_sub(DBKey key, DBData data, va_list ap) +int itemdb_searchname_array_sub(DBKey key, DBData data, va_list ap) { struct item_data *item = DB->data2ptr(&data); char *str; str=va_arg(ap,char *); - if (item == &dummy_item) + if (item == &itemdb->dummy) return 1; //Invalid item. if(stristr(item->jname,str)) return 0; - if(stristr(item->name,str)) + if(battle_config.case_sensitive_aegisnames && strstr(item->name,str)) + return 0; + if(!battle_config.case_sensitive_aegisnames && stristr(item->name,str)) return 0; return strcmpi(item->jname,str); } /*========================================== * Founds up to N matches. Returns number of matches [Skotlex] + * search flag : + * 0 - approximate match + * 1 - exact match *------------------------------------------*/ -int itemdb_searchname_array(struct item_data** data, int size, const char *str) -{ +int itemdb_searchname_array(struct item_data** data, int size, const char *str, int flag) { struct item_data* item; int i; int count=0; // Search in the array - for( i = 0; i < ARRAYLENGTH(itemdb_array); ++i ) + for( i = 0; i < ARRAYLENGTH(itemdb->array); ++i ) { - item = itemdb_array[i]; + item = itemdb->array[i]; if( item == NULL ) continue; - if( stristr(item->jname,str) || stristr(item->name,str) ) - { + if( + (!flag + && (stristr(item->jname,str) + || (battle_config.case_sensitive_aegisnames && strstr(item->name,str)) + || (!battle_config.case_sensitive_aegisnames && stristr(item->name,str)) + )) + || (flag + && (strcmp(item->jname,str) == 0 + || (battle_config.case_sensitive_aegisnames && strcmp(item->name,str) == 0) + || (!battle_config.case_sensitive_aegisnames && strcasecmp(item->name,str) == 0) + )) + ) { if( count < size ) data[count] = item; ++count; @@ -125,45 +148,132 @@ int itemdb_searchname_array(struct item_data** data, int size, const char *str) DBData *db_data[MAX_SEARCH]; int db_count = 0; size -= count; - db_count = itemdb_other->getall(itemdb_other, (DBData**)&db_data, size, itemdb_searchname_array_sub, str); + db_count = itemdb->other->getall(itemdb->other, (DBData**)&db_data, size, itemdb->searchname_array_sub, str); for (i = 0; i < db_count; i++) data[count++] = DB->data2ptr(db_data[i]); count += db_count; } return count; } - - -/*========================================== - * Return a random item id from group. (takes into account % chance giving/tot group) - *------------------------------------------*/ -int itemdb_searchrandomid(int group) -{ - if(group<1 || group>=MAX_ITEMGROUP) { - ShowError("itemdb_searchrandomid: Invalid group id %d\n", group); +/* [Ind/Hercules] */ +int itemdb_chain_item(unsigned short chain_id, int *rate) { + struct item_chain_entry *entry; + + if( chain_id >= itemdb->chain_count ) { + ShowError("itemdb_chain_item: unknown chain id %d\n", chain_id); return UNKNOWN_ITEM_ID; } - if (itemgroup_db[group].qty) - return itemgroup_db[group].nameid[rnd()%itemgroup_db[group].qty]; - ShowError("itemdb_searchrandomid: No item entries for group id %d\n", group); - return UNKNOWN_ITEM_ID; + entry = &itemdb->chains[chain_id].items[ rnd()%itemdb->chains[chain_id].qty ]; + + if( rnd()%10000 >= entry->rate ) + return 0; + + if( rate ) + rate[0] = entry->rate; + return entry->id; } +/* [Ind/Hercules] */ +void itemdb_package_item(struct map_session_data *sd, struct item_package *package) { + int i = 0, get_count, j, flag; + + for( i = 0; i < package->must_qty; i++ ) { + struct item it; + memset(&it, 0, sizeof(it)); + it.nameid = package->must_items[i].id; + it.identify = 1; + + if( package->must_items[i].hours ) { + it.expire_time = (unsigned int)(time(NULL) + ((package->must_items[i].hours*60)*60)); + } + + if( package->must_items[i].named ) { + it.card[0] = CARD0_FORGE; + it.card[1] = 0; + it.card[2] = GetWord(sd->status.char_id, 0); + it.card[3] = GetWord(sd->status.char_id, 1); + } + + if( package->must_items[i].announce ) + clif->package_announce(sd,package->must_items[i].id,package->id); + + get_count = itemdb->isstackable(package->must_items[i].id) ? package->must_items[i].qty : 1; + + it.amount = get_count == 1 ? 1 : get_count; + + for( j = 0; j < package->must_items[i].qty; j += get_count ) { + if ( ( flag = pc->additem(sd, &it, get_count, LOG_TYPE_SCRIPT) ) ) + clif->additem(sd, 0, 0, flag); + } + } + + if( package->random_qty ) { + for( i = 0; i < package->random_qty; i++ ) { + struct item_package_rand_entry *entry; + + entry = &package->random_groups[i].random_list[rnd()%package->random_groups[i].random_qty]; + + while( 1 ) { + if( rnd()%10000 >= entry->rate ) { + entry = entry->next; + continue; + } else { + struct item it; + memset(&it, 0, sizeof(it)); + + it.nameid = entry->id; + it.identify = 1; + + if( entry->hours ) { + it.expire_time = (unsigned int)(time(NULL) + ((entry->hours*60)*60)); + } + + if( entry->named ) { + it.card[0] = CARD0_FORGE; + it.card[1] = 0; + it.card[2] = GetWord(sd->status.char_id, 0); + it.card[3] = GetWord(sd->status.char_id, 1); + } + + if( entry->announce ) + clif->package_announce(sd,entry->id,package->id); + + get_count = itemdb->isstackable(entry->id) ? entry->qty : 1; + + it.amount = get_count == 1 ? 1 : get_count; + + for( j = 0; j < entry->qty; j += get_count ) { + if ( ( flag = pc->additem(sd, &it, get_count, LOG_TYPE_SCRIPT) ) ) + clif->additem(sd, 0, 0, flag); + } + break; + } + } + } + } + + return; +} /*========================================== - * Calculates total item-group related bonuses for the given item + * Return a random item id from group. (takes into account % chance giving/tot group) *------------------------------------------*/ -int itemdb_group_bonus(struct map_session_data* sd, int itemid) -{ - int bonus = 0, i, j; - for (i=0; i < MAX_ITEMGROUP; i++) { - if (!sd->itemgrouphealrate[i]) - continue; - ARR_FIND( 0, itemgroup_db[i].qty, j, itemgroup_db[i].nameid[j] == itemid ); - if( j < itemgroup_db[i].qty ) - bonus += sd->itemgrouphealrate[i]; - } - return bonus; +int itemdb_searchrandomid(struct item_group *group) { + + if (group->qty) + return group->nameid[rnd()%group->qty]; + + ShowError("itemdb_searchrandomid: No item entries for group id %d\n", group->id); + return UNKNOWN_ITEM_ID; +} +bool itemdb_in_group(struct item_group *group, int nameid) { + int i; + + for( i = 0; i < group->qty; i++ ) + if( group->nameid[i] == nameid ) + return true; + + return false; } /// Searches for the item_data. @@ -172,10 +282,10 @@ struct item_data* itemdb_exists(int nameid) { struct item_data* item; - if( nameid >= 0 && nameid < ARRAYLENGTH(itemdb_array) ) - return itemdb_array[nameid]; - item = (struct item_data*)idb_get(itemdb_other,nameid); - if( item == &dummy_item ) + if( nameid >= 0 && nameid < ARRAYLENGTH(itemdb->array) ) + return itemdb->array[nameid]; + item = (struct item_data*)idb_get(itemdb->other,nameid); + if( item == &itemdb->dummy ) return NULL;// dummy data, doesn't exist return item; } @@ -202,10 +312,10 @@ const char* itemdb_typename(int type) } /*========================================== - * Converts the jobid from the format in itemdb + * Converts the jobid from the format in itemdb * to the format used by the map server. [Skotlex] *------------------------------------------*/ -static void itemdb_jobid2mapid(unsigned int *bclass, unsigned int jobmask) +void itemdb_jobid2mapid(unsigned int *bclass, unsigned int jobmask) { int i; bclass[0]= bclass[1]= bclass[2]= 0; @@ -257,7 +367,10 @@ static void itemdb_jobid2mapid(unsigned int *bclass, unsigned int jobmask) if (jobmask & 1<<23) //Soul Linker bclass[2] |= 1<<MAPID_TAEKWON; if (jobmask & 1<<JOB_GUNSLINGER) + {//Rebellion job can equip Gunslinger equips. [Rytech] bclass[0] |= 1<<MAPID_GUNSLINGER; + bclass[1] |= 1<<MAPID_GUNSLINGER; + } if (jobmask & 1<<JOB_NINJA) {bclass[0] |= 1<<MAPID_NINJA; bclass[1] |= 1<<MAPID_NINJA;}//Kagerou/Oboro jobs can equip Ninja equips. [Rytech] @@ -269,21 +382,23 @@ static void itemdb_jobid2mapid(unsigned int *bclass, unsigned int jobmask) bclass[2] |= 1<<MAPID_GANGSI; if (jobmask & 1<<29) //Kagerou / Oboro bclass[1] |= 1<<MAPID_NINJA; + if (jobmask & 1<<30) //Rebellion + bclass[1] |= 1<<MAPID_GUNSLINGER; } -static void create_dummy_data(void) +void create_dummy_data(void) { - memset(&dummy_item, 0, sizeof(struct item_data)); - dummy_item.nameid=500; - dummy_item.weight=1; - dummy_item.value_sell=1; - dummy_item.type=IT_ETC; //Etc item - safestrncpy(dummy_item.name,"UNKNOWN_ITEM",sizeof(dummy_item.name)); - safestrncpy(dummy_item.jname,"UNKNOWN_ITEM",sizeof(dummy_item.jname)); - dummy_item.view_id=UNKNOWN_ITEM_ID; + memset(&itemdb->dummy, 0, sizeof(struct item_data)); + itemdb->dummy.nameid=500; + itemdb->dummy.weight=1; + itemdb->dummy.value_sell=1; + itemdb->dummy.type=IT_ETC; //Etc item + safestrncpy(itemdb->dummy.name,"UNKNOWN_ITEM",sizeof(itemdb->dummy.name)); + safestrncpy(itemdb->dummy.jname,"UNKNOWN_ITEM",sizeof(itemdb->dummy.jname)); + itemdb->dummy.view_id=UNKNOWN_ITEM_ID; } -static struct item_data* create_item_data(int nameid) +struct item_data* create_item_data(int nameid) { struct item_data *id; CREATE(id, struct item_data, 1); @@ -299,19 +414,19 @@ static struct item_data* create_item_data(int nameid) struct item_data* itemdb_load(int nameid) { struct item_data *id; - if( nameid >= 0 && nameid < ARRAYLENGTH(itemdb_array) ) + if( nameid >= 0 && nameid < ARRAYLENGTH(itemdb->array) ) { - id = itemdb_array[nameid]; - if( id == NULL || id == &dummy_item ) - id = itemdb_array[nameid] = create_item_data(nameid); + id = itemdb->array[nameid]; + if( id == NULL || id == &itemdb->dummy ) + id = itemdb->array[nameid] = itemdb->create_item_data(nameid); return id; } - id = (struct item_data*)idb_get(itemdb_other, nameid); - if( id == NULL || id == &dummy_item ) + id = (struct item_data*)idb_get(itemdb->other, nameid); + if( id == NULL || id == &itemdb->dummy ) { - id = create_item_data(nameid); - idb_put(itemdb_other, nameid, id); + id = itemdb->create_item_data(nameid); + idb_put(itemdb->other, nameid, id); } return id; } @@ -322,16 +437,16 @@ struct item_data* itemdb_load(int nameid) { struct item_data* itemdb_search(int nameid) { struct item_data* id; - if( nameid >= 0 && nameid < ARRAYLENGTH(itemdb_array) ) - id = itemdb_array[nameid]; + if( nameid >= 0 && nameid < ARRAYLENGTH(itemdb->array) ) + id = itemdb->array[nameid]; else - id = (struct item_data*)idb_get(itemdb_other, nameid); + id = (struct item_data*)idb_get(itemdb->other, nameid); if( id == NULL ) { ShowWarning("itemdb_search: Item ID %d does not exists in the item_db. Using dummy data.\n", nameid); - id = &dummy_item; - dummy_item.nameid = nameid; + id = &itemdb->dummy; + itemdb->dummy.nameid = nameid; } return id; } @@ -355,8 +470,7 @@ int itemdb_isequip(int nameid) /*========================================== * Alternate version of itemdb_isequip *------------------------------------------*/ -int itemdb_isequip2(struct item_data *data) -{ +int itemdb_isequip2(struct item_data *data) { nullpo_ret(data); switch(data->type) { case IT_WEAPON: @@ -407,44 +521,44 @@ int itemdb_isstackable2(struct item_data *data) * Trade Restriction functions [Skotlex] *------------------------------------------*/ int itemdb_isdropable_sub(struct item_data *item, int gmlv, int unused) { - return (item && (!(item->flag.trade_restriction&1) || gmlv >= item->gm_lv_trade_override)); + return (item && (!(item->flag.trade_restriction&ITR_NODROP) || gmlv >= item->gm_lv_trade_override)); } int itemdb_cantrade_sub(struct item_data* item, int gmlv, int gmlv2) { - return (item && (!(item->flag.trade_restriction&2) || gmlv >= item->gm_lv_trade_override || gmlv2 >= item->gm_lv_trade_override)); + return (item && (!(item->flag.trade_restriction&ITR_NOTRADE) || gmlv >= item->gm_lv_trade_override || gmlv2 >= item->gm_lv_trade_override)); } int itemdb_canpartnertrade_sub(struct item_data* item, int gmlv, int gmlv2) { - return (item && (item->flag.trade_restriction&4 || gmlv >= item->gm_lv_trade_override || gmlv2 >= item->gm_lv_trade_override)); + return (item && (item->flag.trade_restriction&ITR_PARTNEROVERRIDE || gmlv >= item->gm_lv_trade_override || gmlv2 >= item->gm_lv_trade_override)); } int itemdb_cansell_sub(struct item_data* item, int gmlv, int unused) { - return (item && (!(item->flag.trade_restriction&8) || gmlv >= item->gm_lv_trade_override)); + return (item && (!(item->flag.trade_restriction&ITR_NOSELLTONPC) || gmlv >= item->gm_lv_trade_override)); } int itemdb_cancartstore_sub(struct item_data* item, int gmlv, int unused) { - return (item && (!(item->flag.trade_restriction&16) || gmlv >= item->gm_lv_trade_override)); + return (item && (!(item->flag.trade_restriction&ITR_NOCART) || gmlv >= item->gm_lv_trade_override)); } int itemdb_canstore_sub(struct item_data* item, int gmlv, int unused) { - return (item && (!(item->flag.trade_restriction&32) || gmlv >= item->gm_lv_trade_override)); + return (item && (!(item->flag.trade_restriction&ITR_NOSTORAGE) || gmlv >= item->gm_lv_trade_override)); } int itemdb_canguildstore_sub(struct item_data* item, int gmlv, int unused) { - return (item && (!(item->flag.trade_restriction&64) || gmlv >= item->gm_lv_trade_override)); + return (item && (!(item->flag.trade_restriction&ITR_NOGSTORAGE) || gmlv >= item->gm_lv_trade_override)); } int itemdb_canmail_sub(struct item_data* item, int gmlv, int unused) { - return (item && (!(item->flag.trade_restriction&128) || gmlv >= item->gm_lv_trade_override)); + return (item && (!(item->flag.trade_restriction&ITR_NOMAIL) || gmlv >= item->gm_lv_trade_override)); } int itemdb_canauction_sub(struct item_data* item, int gmlv, int unused) { - return (item && (!(item->flag.trade_restriction&256) || gmlv >= item->gm_lv_trade_override)); + return (item && (!(item->flag.trade_restriction&ITR_NOAUCTION) || gmlv >= item->gm_lv_trade_override)); } int itemdb_isrestricted(struct item* item, int gmlv, int gmlv2, int (*func)(struct item_data*, int, int)) { - struct item_data* item_data = itemdb_search(item->nameid); + struct item_data* item_data = itemdb->search(item->nameid); int i; if (!func(item_data, gmlv, gmlv2)) @@ -455,7 +569,7 @@ int itemdb_isrestricted(struct item* item, int gmlv, int gmlv2, int (*func)(stru for(i = 0; i < item_data->slot; i++) { if (!item->card[i]) continue; - if (!func(itemdb_search(item->card[i]), gmlv, gmlv2)) + if (!func(itemdb->search(item->card[i]), gmlv, gmlv2)) return 0; } return 1; @@ -487,269 +601,589 @@ int itemdb_isidentified2(struct item_data *data) { } } +void itemdb_read_groups(void) { + config_t item_group_conf; + config_setting_t *itg = NULL, *it = NULL; +#ifdef RENEWAL + const char *config_filename = "db/re/item_group.conf"; // FIXME hardcoded name +#else + const char *config_filename = "db/pre-re/item_group.conf"; // FIXME hardcoded name +#endif + const char *itname; + int i = 0, count = 0, c; + unsigned int *gsize = NULL; -/*========================================== - * Search by name for the override flags available items - * (Give item another sprite) - *------------------------------------------*/ -static bool itemdb_read_itemavail(char* str[], int columns, int current) -{// <nameid>,<sprite> - int nameid, sprite; - struct item_data *id; - - nameid = atoi(str[0]); - - if( ( id = itemdb_exists(nameid) ) == NULL ) - { - ShowWarning("itemdb_read_itemavail: Invalid item id %d.\n", nameid); - return false; - } - - sprite = atoi(str[1]); - - if( sprite > 0 ) - { - id->flag.available = 1; - id->view_id = sprite; - } - else - { - id->flag.available = 0; - } - - return true; -} - -/*========================================== - * read item group data - *------------------------------------------*/ -static unsigned int itemdb_read_itemgroup_sub(const char* filename) { - FILE *fp; - char line[1024]; - int ln=0; - unsigned int count = 0; - int groupid,j,k,nameid; - char *str[3],*p; - char w1[1024], w2[1024]; - - if( (fp=fopen(filename,"r"))==NULL ){ - ShowError("can't read %s\n", filename); - return 0; + if (libconfig->read_file(&item_group_conf, config_filename)) { + ShowError("can't read %s\n", config_filename); + return; } - - while(fgets(line, sizeof(line), fp)) - { - ln++; - if(line[0]=='/' && line[1]=='/') - continue; - if(strstr(line,"import")) { - if (sscanf(line, "%[^:]: %[^\r\n]", w1, w2) == 2 && - strcmpi(w1, "import") == 0) { - count += itemdb_read_itemgroup_sub(w2); - continue; - } - } - memset(str,0,sizeof(str)); - for(j=0,p=line;j<3 && p;j++){ - str[j]=p; - p=strchr(p,','); - if(p) *p++=0; - } - if(str[0]==NULL) - continue; - if (j<3) { - if (j>1) //Or else it barks on blank lines... - ShowWarning("itemdb_read_itemgroup: Insufficient fields for entry at %s:%d\n", filename, ln); - continue; - } - groupid = atoi(str[0]); - if (groupid < 0 || groupid >= MAX_ITEMGROUP) { - ShowWarning("itemdb_read_itemgroup: Invalid group %d in %s:%d\n", groupid, filename, ln); + + gsize = aMalloc( libconfig->setting_length(item_group_conf.root) * sizeof(unsigned int) ); + + for(i = 0; i < libconfig->setting_length(item_group_conf.root); i++) + gsize[i] = 0; + + i = 0; + while( (itg = libconfig->setting_get_elem(item_group_conf.root,i++)) ) { + const char *name = config_setting_name(itg); + + if( !itemdb->name2id(name) ) { + ShowWarning("itemdb_read_groups: unknown group item '%s', skipping..\n",name); + config_setting_remove(item_group_conf.root, name); + --i; continue; } - nameid = atoi(str[1]); - if (!itemdb_exists(nameid)) { - ShowWarning("itemdb_read_itemgroup: Non-existant item %d in %s:%d\n", nameid, filename, ln); - continue; + + c = 0; + while( (it = libconfig->setting_get_elem(itg,c++)) ) { + if( config_setting_is_list(it) ) + gsize[ i - 1 ] += libconfig->setting_get_int_elem(it,1); + else + gsize[ i - 1 ] += 1; } - k = atoi(str[2]); - if (itemgroup_db[groupid].qty+k >= MAX_RANDITEM) { - ShowWarning("itemdb_read_itemgroup: Group %d is full (%d entries) in %s:%d\n", groupid, MAX_RANDITEM, filename, ln); - continue; + + } + + i = 0; + CREATE(itemdb->groups, struct item_group, libconfig->setting_length(item_group_conf.root)); + itemdb->group_count = (unsigned short)libconfig->setting_length(item_group_conf.root); + + while( (itg = libconfig->setting_get_elem(item_group_conf.root,i++)) ) { + struct item_data *data = itemdb->name2id(config_setting_name(itg)); + int ecount = 0; + + data->group = &itemdb->groups[count]; + + itemdb->groups[count].id = data->nameid; + itemdb->groups[count].qty = gsize[ count ]; + + CREATE(itemdb->groups[count].nameid, unsigned short, gsize[ count ] + 1); + c = 0; + while( (it = libconfig->setting_get_elem(itg,c++)) ) { + int repeat = 1; + if( config_setting_is_list(it) ) { + itname = libconfig->setting_get_string_elem(it,0); + repeat = libconfig->setting_get_int_elem(it,1); + } else + itname = libconfig->setting_get_string_elem(itg,c - 1); + + if( itname[0] == 'I' && itname[1] == 'D' && strlen(itname) < 8 ) { + if( !( data = itemdb->exists(atoi(itname+2)) ) ) + ShowWarning("itemdb_read_groups: unknown item ID '%d' in group '%s'!\n",atoi(itname+2),config_setting_name(itg)); + } else if( !( data = itemdb->name2id(itname) ) ) + ShowWarning("itemdb_read_groups: unknown item '%s' in group '%s'!\n",itname,config_setting_name(itg)); + + itemdb->groups[count].nameid[ecount] = data ? data->nameid : 0; + if( repeat > 1 ) { + //memset would be better? I failed to get the following to work though hu + //memset(&itemdb->groups[count].nameid[ecount+1],itemdb->groups[count].nameid[ecount],sizeof(itemdb->groups[count].nameid[0])*repeat); + int z; + for( z = ecount+1; z < ecount+repeat; z++ ) + itemdb->groups[count].nameid[z] = itemdb->groups[count].nameid[ecount]; + } + ecount += repeat; } - for(j=0;j<k;j++) - itemgroup_db[groupid].nameid[itemgroup_db[groupid].qty++] = nameid; + count++; } - fclose(fp); - return count; -} - -static void itemdb_read_itemgroup(void) -{ - char path[256]; - unsigned int count; - snprintf(path, 255, "%s/"DBPATH"item_group_db.txt", iMap->db_path); - memset(&itemgroup_db, 0, sizeof(itemgroup_db)); - count = itemdb_read_itemgroup_sub(path); - ShowStatus("Done reading '"CL_WHITE"%lu"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", count, "item_group_db.txt"); - return; + + libconfig->destroy(&item_group_conf); + aFree(gsize); + + ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", count, config_filename); } - -/*========================================== - * Reads item trade restrictions [Skotlex] - *------------------------------------------*/ -static bool itemdb_read_itemtrade(char* str[], int columns, int current) -{// <nameid>,<mask>,<gm level> - int nameid, flag, gmlv; - struct item_data *id; - - nameid = atoi(str[0]); - - if( ( id = itemdb_exists(nameid) ) == NULL ) - { - //ShowWarning("itemdb_read_itemtrade: Invalid item id %d.\n", nameid); - //return false; - // FIXME: item_trade.txt contains items, which are commented in item database. - return true; - } - - flag = atoi(str[1]); - gmlv = atoi(str[2]); - - if( flag < 0 || flag > 511 ) {//Check range - ShowWarning("itemdb_read_itemtrade: Invalid trading mask %d for item id %d.\n", flag, nameid); - return false; +/* [Ind/Hercules] - HCache for Packages */ +void itemdb_write_cached_packages(const char *config_filename) { + FILE *file; + unsigned short pcount = itemdb->package_count; + unsigned short i; + + if( !(file = HCache->open(config_filename,"wb")) ) { + return; } - if( gmlv < 1 ) - { - ShowWarning("itemdb_read_itemtrade: Invalid override GM level %d for item id %d.\n", gmlv, nameid); - return false; + + // first 2 bytes = package count + hwrite(&pcount,sizeof(pcount),1,file); + + for(i = 0; i < pcount; i++) { + unsigned short id = itemdb->packages[i].id, random_qty = itemdb->packages[i].random_qty, must_qty = itemdb->packages[i].must_qty; + unsigned short c; + //into a package, first 2 bytes = id. + hwrite(&id,sizeof(id),1,file); + //next 2 bytes = must count + hwrite(&must_qty,sizeof(must_qty),1,file); + //next 2 bytes = random count + hwrite(&random_qty,sizeof(random_qty),1,file); + //now we loop into must + for(c = 0; c < must_qty; c++) { + struct item_package_must_entry *entry = &itemdb->packages[i].must_items[c]; + unsigned char announce = entry->announce == 1 ? 1 : 0, named = entry->named == 1 ? 1 : 0; + //first 2 byte = item id + hwrite(&entry->id,sizeof(entry->id),1,file); + //next 2 byte = qty + hwrite(&entry->qty,sizeof(entry->qty),1,file); + //next 2 byte = hours + hwrite(&entry->hours,sizeof(entry->hours),1,file); + //next 1 byte = announce (1:0) + hwrite(&announce,sizeof(announce),1,file); + //next 1 byte = named (1:0) + hwrite(&named,sizeof(announce),1,file); + } + //now we loop into random groups + for(c = 0; c < random_qty; c++) { + struct item_package_rand_group *group = &itemdb->packages[i].random_groups[c]; + unsigned short group_qty = group->random_qty, h; + + //next 2 bytes = how many entries in this group + hwrite(&group_qty,sizeof(group_qty),1,file); + //now we loop into the group's list + for(h = 0; h < group_qty; h++) { + struct item_package_rand_entry *entry = &itemdb->packages[i].random_groups[c].random_list[h]; + unsigned char announce = entry->announce == 1 ? 1 : 0, named = entry->named == 1 ? 1 : 0; + //first 2 byte = item id + hwrite(&entry->id,sizeof(entry->id),1,file); + //next 2 byte = qty + hwrite(&entry->qty,sizeof(entry->qty),1,file); + //next 2 byte = rate + hwrite(&entry->rate,sizeof(entry->rate),1,file); + //next 2 byte = hours + hwrite(&entry->hours,sizeof(entry->hours),1,file); + //next 1 byte = announce (1:0) + hwrite(&announce,sizeof(announce),1,file); + //next 1 byte = named (1:0) + hwrite(&named,sizeof(announce),1,file); + } + } } - - id->flag.trade_restriction = flag; - id->gm_lv_trade_override = gmlv; - - return true; + + fclose(file); + + return; } +bool itemdb_read_cached_packages(const char *config_filename) { + FILE *file; + unsigned short pcount; + unsigned short i; -/*========================================== - * Reads item delay amounts [Paradox924X] - *------------------------------------------*/ -static bool itemdb_read_itemdelay(char* str[], int columns, int current) -{// <nameid>,<delay> - int nameid, delay; - struct item_data *id; - - nameid = atoi(str[0]); - - if( ( id = itemdb_exists(nameid) ) == NULL ) - { - ShowWarning("itemdb_read_itemdelay: Invalid item id %d.\n", nameid); + if( !(file = HCache->open(config_filename,"rb")) ) { return false; } + + // first 2 bytes = package count + hread(&pcount,sizeof(pcount),1,file); - delay = atoi(str[1]); + CREATE(itemdb->packages, struct item_package, pcount); + itemdb->package_count = pcount; - if( delay < 0 ) - { - ShowWarning("itemdb_read_itemdelay: Invalid delay %d for item id %d.\n", id->delay, nameid); - return false; + for( i = 0; i < pcount; i++ ) { + unsigned short id = 0, random_qty = 0, must_qty = 0; + struct item_data *pdata; + struct item_package *package = &itemdb->packages[i]; + unsigned short c; + + //into a package, first 2 bytes = id. + hread(&id,sizeof(id),1,file); + //next 2 bytes = must count + hread(&must_qty,sizeof(must_qty),1,file); + //next 2 bytes = random count + hread(&random_qty,sizeof(random_qty),1,file); + + if( !(pdata = itemdb->exists(id)) ) + ShowWarning("itemdb_read_cached_packages: unknown package item '%d', skipping..\n",id); + else + pdata->package = &itemdb->packages[i]; + + package->id = id; + package->random_qty = random_qty; + package->must_qty = must_qty; + package->must_items = NULL; + package->random_groups = NULL; + + if( package->must_qty ) { + CREATE(package->must_items, struct item_package_must_entry, package->must_qty); + //now we loop into must + for(c = 0; c < package->must_qty; c++) { + struct item_package_must_entry *entry = &itemdb->packages[i].must_items[c]; + unsigned short mid = 0, qty = 0, hours = 0; + unsigned char announce = 0, named = 0; + struct item_data *data; + //first 2 byte = item id + hread(&mid,sizeof(mid),1,file); + //next 2 byte = qty + hread(&qty,sizeof(qty),1,file); + //next 2 byte = hours + hread(&hours,sizeof(hours),1,file); + //next 1 byte = announce (1:0) + hread(&announce,sizeof(announce),1,file); + //next 1 byte = named (1:0) + hread(&named,sizeof(announce),1,file); + + if( !(data = itemdb->exists(mid)) ) + ShowWarning("itemdb_read_cached_packages: unknown item '%d' in package '%s'!\n",mid,itemdb_name(package->id)); + + entry->id = data ? data->nameid : 0; + entry->hours = hours; + entry->qty = qty; + entry->announce = announce ? 1 : 0; + entry->named = named ? 1 : 0; + } + } + if( package->random_qty ) { + //now we loop into random groups + CREATE(package->random_groups, struct item_package_rand_group, package->random_qty); + for(c = 0; c < package->random_qty; c++) { + unsigned short group_qty = 0, h; + struct item_package_rand_entry *prev = NULL; + + //next 2 bytes = how many entries in this group + hread(&group_qty,sizeof(group_qty),1,file); + + package->random_groups[c].random_qty = group_qty; + CREATE(package->random_groups[c].random_list, struct item_package_rand_entry, package->random_groups[c].random_qty); + + //now we loop into the group's list + for(h = 0; h < group_qty; h++) { + struct item_package_rand_entry *entry = &itemdb->packages[i].random_groups[c].random_list[h]; + unsigned short mid = 0, qty = 0, hours = 0, rate = 0; + unsigned char announce = 0, named = 0; + struct item_data *data; + + if( prev ) prev->next = entry; + + //first 2 byte = item id + hread(&mid,sizeof(mid),1,file); + //next 2 byte = qty + hread(&qty,sizeof(qty),1,file); + //next 2 byte = rate + hread(&rate,sizeof(rate),1,file); + //next 2 byte = hours + hread(&hours,sizeof(hours),1,file); + //next 1 byte = announce (1:0) + hread(&announce,sizeof(announce),1,file); + //next 1 byte = named (1:0) + hread(&named,sizeof(announce),1,file); + + if( !(data = itemdb->exists(mid)) ) + ShowWarning("itemdb_read_cached_packages: unknown item '%d' in package '%s'!\n",mid,itemdb_name(package->id)); + + entry->id = data ? data->nameid : 0; + entry->rate = rate; + entry->hours = hours; + entry->qty = qty; + entry->announce = announce ? 1 : 0; + entry->named = named ? 1 : 0; + + prev = entry; + } + if( prev ) + prev->next = &itemdb->packages[i].random_groups[c].random_list[0]; + } + } } - - id->delay = delay; + + fclose(file); + + ShowStatus("Done reading '"CL_WHITE"%hu"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"' ("CL_GREEN"C"CL_RESET").\n", pcount, config_filename); return true; } - -/*================================================================== - * Reads item stacking restrictions - *----------------------------------------------------------------*/ -static bool itemdb_read_stack(char* fields[], int columns, int current) -{// <item id>,<stack limit amount>,<type> - unsigned short nameid, amount; - unsigned int type; - struct item_data* id; - - nameid = (unsigned short)strtoul(fields[0], NULL, 10); - - if( ( id = itemdb_exists(nameid) ) == NULL ) - { - ShowWarning("itemdb_read_stack: Unknown item id '%hu'.\n", nameid); - return false; +void itemdb_read_packages(void) { + config_t item_packages_conf; + config_setting_t *itg = NULL, *it = NULL, *t = NULL; +#ifdef RENEWAL + const char *config_filename = "db/re/item_packages.conf"; // FIXME hardcoded name +#else + const char *config_filename = "db/pre-re/item_packages.conf"; // FIXME hardcoded name +#endif + const char *itname; + int i = 0, count = 0, c = 0, highest_gcount = 0; + unsigned int *must = NULL, *random = NULL, *rgroup = NULL, **rgroups = NULL; + struct item_package_rand_entry **prev = NULL; + + if( HCache->check(config_filename) ) { + if( itemdb->read_cached_packages(config_filename) ) + return; } - - if( !itemdb_isstackable2(id) ) - { - ShowWarning("itemdb_read_stack: Item id '%hu' is not stackable.\n", nameid); - return false; + + if (libconfig->read_file(&item_packages_conf, config_filename)) { + ShowError("can't read %s\n", config_filename); + return; } + + must = aMalloc( libconfig->setting_length(item_packages_conf.root) * sizeof(unsigned int) ); + random = aMalloc( libconfig->setting_length(item_packages_conf.root) * sizeof(unsigned int) ); + rgroup = aMalloc( libconfig->setting_length(item_packages_conf.root) * sizeof(unsigned int) ); + rgroups = aMalloc( libconfig->setting_length(item_packages_conf.root) * sizeof(unsigned int *) ); - amount = (unsigned short)strtoul(fields[1], NULL, 10); - type = strtoul(fields[2], NULL, 10); - - if( !amount ) - {// ignore - return true; + + for(i = 0; i < libconfig->setting_length(item_packages_conf.root); i++) { + must[i] = 0; + random[i] = 0; + rgroup[i] = 0; + rgroups[i] = NULL; + } + + /* validate tree, drop poisonous fruits! */ + i = 0; + while( (itg = libconfig->setting_get_elem(item_packages_conf.root,i++)) ) { + const char *name = config_setting_name(itg); + + if( !itemdb->name2id(name) ) { + ShowWarning("itemdb_read_packages: unknown package item '%s', skipping..\n",name); + libconfig->setting_remove(item_packages_conf.root, name); + --i; + continue; + } + + c = 0; + while( (it = libconfig->setting_get_elem(itg,c++)) ) { + int rval = 0; + if( !( t = libconfig->setting_get_member(it, "Random") ) || (rval = libconfig->setting_get_int(t)) < 0 ) { + ShowWarning("itemdb_read_packages: invalid 'Random' value (%d) for item '%s' in package '%s', defaulting to must!\n",rval,config_setting_name(it),name); + libconfig->setting_remove(it, config_setting_name(it)); + --c; + continue; + } + + if( rval == 0 ) + must[ i - 1 ] += 1; + else { + random[ i - 1 ] += 1; + if( rval > rgroup[i - 1] ) + rgroup[i - 1] = rval; + if( rval > highest_gcount ) + highest_gcount = rval; + } + } } - id->stack.amount = amount; - id->stack.inventory = (type&1)!=0; - id->stack.cart = (type&2)!=0; - id->stack.storage = (type&4)!=0; - id->stack.guildstorage = (type&8)!=0; - - return true; -} - + CREATE(prev, struct item_package_rand_entry *, highest_gcount); + for(i = 0; i < highest_gcount; i++) { + prev[i] = NULL; + } + + for(i = 0; i < libconfig->setting_length(item_packages_conf.root); i++ ) { + rgroups[i] = aMalloc( rgroup[i] * sizeof(unsigned int) ); + for( c = 0; c < rgroup[i]; c++ ) { + rgroups[i][c] = 0; + } + } -/// Reads items allowed to be sold in buying stores -static bool itemdb_read_buyingstore(char* fields[], int columns, int current) -{// <nameid> - int nameid; - struct item_data* id; + /* grab the known sizes */ + i = 0; + while( (itg = libconfig->setting_get_elem(item_packages_conf.root,i++)) ) { + c = 0; + while( (it = libconfig->setting_get_elem(itg,c++)) ) { + int rval = 0; + if( ( t = libconfig->setting_get_member(it, "Random")) && ( rval = libconfig->setting_get_int(t) ) > 0 ) { + rgroups[i - 1][rval - 1] += 1; + } + } + } + + CREATE(itemdb->packages, struct item_package, libconfig->setting_length(item_packages_conf.root)); + itemdb->package_count = (unsigned short)libconfig->setting_length(item_packages_conf.root); + + /* write */ + i = 0; + while( (itg = libconfig->setting_get_elem(item_packages_conf.root,i++)) ) { + struct item_data *data = itemdb->name2id(config_setting_name(itg)); + int r = 0, m = 0; + + for(r = 0; r < highest_gcount; r++) { + prev[r] = NULL; + } + + data->package = &itemdb->packages[count]; + + itemdb->packages[count].id = data->nameid; + itemdb->packages[count].random_groups = NULL; + itemdb->packages[count].must_items = NULL; + itemdb->packages[count].random_qty = rgroup[ i - 1 ]; + itemdb->packages[count].must_qty = must[ i - 1 ]; + + if( itemdb->packages[count].random_qty ) { + CREATE(itemdb->packages[count].random_groups, struct item_package_rand_group, itemdb->packages[count].random_qty); + for( c = 0; c < itemdb->packages[count].random_qty; c++ ) { + if( !rgroups[ i - 1 ][c] ) + ShowError("itemdb_read_packages: package '%s' missing 'Random' field %d! there must not be gaps!\n",config_setting_name(itg),c+1); + else + CREATE(itemdb->packages[count].random_groups[c].random_list, struct item_package_rand_entry, rgroups[ i - 1 ][c]); + itemdb->packages[count].random_groups[c].random_qty = 0; + } + } + if( itemdb->packages[count].must_qty ) + CREATE(itemdb->packages[count].must_items, struct item_package_must_entry, itemdb->packages[count].must_qty); + + c = 0; + while( (it = libconfig->setting_get_elem(itg,c++)) ) { + int icount = 1, expire = 0, rate = 10000, gid = 0; + bool announce = false, named = false; + + itname = config_setting_name(it); + + if( itname[0] == 'I' && itname[1] == 'D' && strlen(itname) < 8 ) { + if( !( data = itemdb->exists(atoi(itname+2)) ) ) + ShowWarning("itemdb_read_packages: unknown item ID '%d' in package '%s'!\n",atoi(itname+2),config_setting_name(itg)); + } else if( !( data = itemdb->name2id(itname) ) ) + ShowWarning("itemdb_read_packages: unknown item '%s' in package '%s'!\n",itname,config_setting_name(itg)); + + if( ( t = libconfig->setting_get_member(it, "Count")) ) + icount = libconfig->setting_get_int(t); + + if( ( t = libconfig->setting_get_member(it, "Expire")) ) + expire = libconfig->setting_get_int(t); + + if( ( t = libconfig->setting_get_member(it, "Rate")) ) { + if( (rate = (unsigned short)libconfig->setting_get_int(t)) > 10000 ) { + ShowWarning("itemdb_read_packages: invalid rate (%d) for item '%s' in package '%s'!\n",rate,itname,config_setting_name(itg)); + rate = 10000; + } + } - nameid = atoi(fields[0]); + if( ( t = libconfig->setting_get_member(it, "Announce")) && libconfig->setting_get_bool(t) ) + announce = true; - if( ( id = itemdb_exists(nameid) ) == NULL ) - { - ShowWarning("itemdb_read_buyingstore: Invalid item id %d.\n", nameid); - return false; + if( ( t = libconfig->setting_get_member(it, "Named")) && libconfig->setting_get_bool(t) ) + named = true; + + if( !( t = libconfig->setting_get_member(it, "Random") ) ) { + ShowWarning("itemdb_read_packages: missing 'Random' field for item '%s' in package '%s', defaulting to must!\n",itname,config_setting_name(itg)); + gid = 0; + } else + gid = libconfig->setting_get_int(t); + + if( gid == 0 ) { + itemdb->packages[count].must_items[m].id = data ? data->nameid : 0; + itemdb->packages[count].must_items[m].qty = icount; + itemdb->packages[count].must_items[m].hours = expire; + itemdb->packages[count].must_items[m].announce = announce == true ? 1 : 0; + itemdb->packages[count].must_items[m].named = named == true ? 1 : 0; + m++; + } else { + int gidx = gid - 1; + + r = itemdb->packages[count].random_groups[gidx].random_qty; + + if( prev[gidx] ) + prev[gidx]->next = &itemdb->packages[count].random_groups[gidx].random_list[r]; + + itemdb->packages[count].random_groups[gidx].random_list[r].id = data ? data->nameid : 0; + itemdb->packages[count].random_groups[gidx].random_list[r].qty = icount; + if( (itemdb->packages[count].random_groups[gidx].random_list[r].rate = rate) == 10000 ) { + ShowWarning("itemdb_read_packages: item '%s' in '%s' has 100%% drop rate!! set this item as 'Random: 0' or other items won't drop!!!\n",itname,config_setting_name(itg)); + } + itemdb->packages[count].random_groups[gidx].random_list[r].hours = expire; + itemdb->packages[count].random_groups[gidx].random_list[r].announce = announce == true ? 1 : 0; + itemdb->packages[count].random_groups[gidx].random_list[r].named = named == true ? 1 : 0; + itemdb->packages[count].random_groups[gidx].random_qty += 1; + + prev[gidx] = &itemdb->packages[count].random_groups[gidx].random_list[r]; + } + + } + + for(r = 0; r < highest_gcount; r++) { + if( prev[r] ) + prev[r]->next = &itemdb->packages[count].random_groups[r].random_list[0]; + } + + for( r = 0; r < itemdb->packages[count].random_qty; r++ ) { + if( itemdb->packages[count].random_groups[r].random_qty == 1 ) { + //item packages don't stop looping until something comes out of them, so if you have only one item in it the drop is guaranteed. + ShowWarning("itemdb_read_packages: in '%s' 'Random: %d' group has only 1 random option, drop rate will be 100%%!\n", + itemdb_name(itemdb->packages[count].id),r+1); + itemdb->packages[count].random_groups[r].random_list[0].rate = 10000; + } + } + + count++; } - - if( !itemdb_isstackable2(id) ) - { - ShowWarning("itemdb_read_buyingstore: Non-stackable item id %d cannot be enabled for buying store.\n", nameid); - return false; + + + aFree(must); + aFree(random); + for(i = 0; i < libconfig->setting_length(item_packages_conf.root); i++ ) { + aFree(rgroups[i]); } + aFree(rgroups); + aFree(rgroup); + aFree(prev); + + libconfig->destroy(&item_packages_conf); - id->flag.buyingstore = true; - - return true; + if( HCache->enabled ) + itemdb->write_cached_packages(config_filename); + + ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", count, config_filename); } -/******************************************* -** Item usage restriction (item_nouse.txt) -********************************************/ -static bool itemdb_read_nouse(char* fields[], int columns, int current) -{// <nameid>,<flag>,<override> - int nameid, flag, override; - struct item_data* id; +void itemdb_read_chains(void) { + config_t item_chain_conf; + config_setting_t *itc = NULL, *entry = NULL; +#ifdef RENEWAL + const char *config_filename = "db/re/item_chain.conf"; // FIXME hardcoded name +#else + const char *config_filename = "db/pre-re/item_chain.conf"; // FIXME hardcoded name +#endif + int i = 0, count = 0; + + if (libconfig->read_file(&item_chain_conf, config_filename)) { + ShowError("can't read %s\n", config_filename); + return; + } - nameid = atoi(fields[0]); + CREATE(itemdb->chains, struct item_chain, libconfig->setting_length(item_chain_conf.root)); + itemdb->chain_count = (unsigned short)libconfig->setting_length(item_chain_conf.root); - if( ( id = itemdb_exists(nameid) ) == NULL ) { - ShowWarning("itemdb_read_nouse: Invalid item id %d.\n", nameid); - return false; +#ifdef ENABLE_CASE_CHECK + script->parser_current_file = config_filename; +#endif // ENABLE_CASE_CHECK + while( (itc = libconfig->setting_get_elem(item_chain_conf.root,i++)) ) { + struct item_data *data = NULL; + struct item_chain_entry *prev = NULL; + const char *name = config_setting_name(itc); + int c = 0; + + script->set_constant2(name,i-1,0); + itemdb->chains[count].qty = (unsigned short)libconfig->setting_length(itc); + + CREATE(itemdb->chains[count].items, struct item_chain_entry, libconfig->setting_length(itc)); + + while( (entry = libconfig->setting_get_elem(itc,c++)) ) { + const char *itname = config_setting_name(entry); + if( itname[0] == 'I' && itname[1] == 'D' && strlen(itname) < 8 ) { + if( !( data = itemdb->exists(atoi(itname+2)) ) ) + ShowWarning("itemdb_read_chains: unknown item ID '%d' in chain '%s'!\n",atoi(itname+2),name); + } else if( !( data = itemdb->name2id(itname) ) ) + ShowWarning("itemdb_read_chains: unknown item '%s' in chain '%s'!\n",itname,name); + + if( prev ) + prev->next = &itemdb->chains[count].items[c - 1]; + + itemdb->chains[count].items[c - 1].id = data ? data->nameid : 0; + itemdb->chains[count].items[c - 1].rate = data ? libconfig->setting_get_int(entry) : 0; + + prev = &itemdb->chains[count].items[c - 1]; + } + + if( prev ) + prev->next = &itemdb->chains[count].items[0]; + + count++; } +#ifdef ENABLE_CASE_CHECK + script->parser_current_file = NULL; +#endif // ENABLE_CASE_CHECK - flag = atoi(fields[1]); - override = atoi(fields[2]); - - id->item_usage.flag = flag; - id->item_usage.override = override; - - return true; + libconfig->destroy(&item_chain_conf); + + if( !script->get_constant("ITMCHAIN_ORE",&i) ) + ShowWarning("itemdb_read_chains: failed to find 'ITMCHAIN_ORE' chain to link to cache!\n"); + else + itemdb->chain_cache[ECC_ORE] = i; + + ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", count, config_filename); } /** @@ -781,13 +1215,13 @@ void itemdb_read_combos() { uint32 lines = 0, count = 0; char line[1024]; - char path[256]; + char filepath[256]; FILE* fp; - sprintf(path, "%s/%s", iMap->db_path, DBPATH"item_combo_db.txt"); + sprintf(filepath, "%s/%s", map->db_path, DBPATH"item_combo_db.txt"); - if ((fp = fopen(path, "r")) == NULL) { - ShowError("itemdb_read_combos: File not found \"%s\".\n", path); + if ((fp = fopen(filepath, "r")) == NULL) { + ShowError("itemdb_read_combos: File not found \"%s\".\n", filepath); return; } @@ -809,10 +1243,9 @@ void itemdb_read_combos() { if (*p == '\0') continue;// empty line - if (!strchr(p,',')) - { + if (!strchr(p,',')) { /* is there even a single column? */ - ShowError("itemdb_read_combos: Insufficient columns in line %d of \"%s\", skipping.\n", lines, path); + ShowError("itemdb_read_combos: Insufficient columns in line %d of \"%s\", skipping.\n", lines, filepath); continue; } @@ -822,86 +1255,65 @@ void itemdb_read_combos() { p++; str[1] = p; - p = strchr(p,','); + p = strchr(p,','); p++; if (str[1][0] != '{') { - ShowError("itemdb_read_combos(#1): Invalid format (Script column) in line %d of \"%s\", skipping.\n", lines, path); + ShowError("itemdb_read_combos(#1): Invalid format (Script column) in line %d of \"%s\", skipping.\n", lines, filepath); continue; } /* no ending key anywhere (missing \}\) */ if ( str[1][strlen(str[1])-1] != '}' ) { - ShowError("itemdb_read_combos(#2): Invalid format (Script column) in line %d of \"%s\", skipping.\n", lines, path); + ShowError("itemdb_read_combos(#2): Invalid format (Script column) in line %d of \"%s\", skipping.\n", lines, filepath); continue; } else { int items[MAX_ITEMS_PER_COMBO]; int v = 0, retcount = 0; - struct item_data * id = NULL; - int idx = 0; + struct item_combo *combo = NULL; - if((retcount = itemdb_combo_split_atoi(str[0], items)) < 2) { - ShowError("itemdb_read_combos: line %d of \"%s\" doesn't have enough items to make for a combo (min:2), skipping.\n", lines, path); + if((retcount = itemdb->combo_split_atoi(str[0], items)) < 2) { + ShowError("itemdb_read_combos: line %d of \"%s\" doesn't have enough items to make for a combo (min:2), skipping.\n", lines, filepath); continue; } /* validate */ for(v = 0; v < retcount; v++) { - if( !itemdb_exists(items[v]) ) { - ShowError("itemdb_read_combos: line %d of \"%s\" contains unknown item ID %d, skipping.\n", lines, path,items[v]); + if( !itemdb->exists(items[v]) ) { + ShowError("itemdb_read_combos: line %d of \"%s\" contains unknown item ID %d, skipping.\n", lines, filepath,items[v]); break; } } /* failed at some item */ if( v < retcount ) continue; - - id = itemdb_exists(items[0]); - idx = id->combos_count; - - /* first entry, create */ - if( id->combos == NULL ) { - CREATE(id->combos, struct item_combo*, 1); - id->combos_count = 1; - } else { - RECREATE(id->combos, struct item_combo*, ++id->combos_count); - } + RECREATE(itemdb->combos, struct item_combo*, ++itemdb->combo_count); - CREATE(id->combos[idx],struct item_combo,1); + CREATE(combo, struct item_combo, 1); - id->combos[idx]->nameid = aMalloc( retcount * sizeof(unsigned short) ); - id->combos[idx]->count = retcount; - id->combos[idx]->script = parse_script(str[1], path, lines, 0); - id->combos[idx]->id = count; - id->combos[idx]->isRef = false; + combo->count = retcount; + combo->script = script->parse(str[1], filepath, lines, 0, NULL); + combo->id = itemdb->combo_count - 1; /* populate ->nameid field */ for( v = 0; v < retcount; v++ ) { - id->combos[idx]->nameid[v] = items[v]; + combo->nameid[v] = items[v]; } - /* populate the children to refer to this combo */ - for( v = 1; v < retcount; v++ ) { + itemdb->combos[itemdb->combo_count - 1] = combo; + + /* populate the items to refer to this combo */ + for( v = 0; v < retcount; v++ ) { struct item_data * it; int index; - it = itemdb_exists(items[v]); + it = itemdb->exists(items[v]); index = it->combos_count; - if( it->combos == NULL ) { - CREATE(it->combos, struct item_combo*, 1); - it->combos_count = 1; - } else { - RECREATE(it->combos, struct item_combo*, ++it->combos_count); - } + RECREATE(it->combos, struct item_combo*, ++it->combos_count); - CREATE(it->combos[index],struct item_combo,1); - - /* we copy previously alloc'd pointers and just set it to reference */ - memcpy(it->combos[index],id->combos[idx],sizeof(struct item_combo)); - /* we flag this way to ensure we don't double-dealloc same data */ - it->combos[index]->isRef = true; + it->combos[index] = combo; } } @@ -911,7 +1323,7 @@ void itemdb_read_combos() { fclose(fp); - ShowStatus("Done reading '"CL_WHITE"%lu"CL_RESET"' entries in '"CL_WHITE"item_combo_db"CL_RESET"'.\n", count); + ShowStatus("Done reading '"CL_WHITE"%"PRIu32""CL_RESET"' entries in '"CL_WHITE"item_combo_db"CL_RESET"'.\n", count); return; } @@ -921,7 +1333,7 @@ void itemdb_read_combos() { /*====================================== * Applies gender restrictions according to settings. [Skotlex] *======================================*/ -static int itemdb_gendercheck(struct item_data *id) +int itemdb_gendercheck(struct item_data *id) { if (id->nameid == WEDDING_RING_M) //Grom Ring return 1; @@ -934,409 +1346,708 @@ static int itemdb_gendercheck(struct item_data *id) return (battle_config.ignore_items_gender) ? 2 : id->sex; } -/** - * [RRInd] - * For backwards compatibility, in Renewal mode, MATK from weapons comes from the atk slot - * We use a ':' delimiter which, if not found, assumes the weapon does not provide any matk. - **/ -void itemdb_re_split_atoi(char *str, int *atk, int *matk) { - int i, val[2]; - for (i=0; i<2; i++) { - if (!str) break; - val[i] = atoi(str); - str = strchr(str,':'); - if (str) - *str++=0; +/** + * Validates an item DB entry and inserts it into the database. + * This function is called after preparing the item entry data, and it takes + * care of inserting it and cleaning up any remainders of the previous one. + * + * @param *entry Pointer to the new item_data entry. Ownership is NOT taken, + * but the content is modified to reflect the validation. + * @param n Ordinal number of the entry, to be displayed in case of + * validation errors. + * @param *source Source of the entry (table or file name), to be displayed in + * case of validation errors. + * @return Nameid of the validated entry, or 0 in case of failure. + * + * Note: This is safe to call if the new entry is a copy of the old one (i.e. + * item_db2 inheritance), as it will make sure not to free any scripts still in + * use in the new entry. + */ +int itemdb_validate_entry(struct item_data *entry, int n, const char *source) { + struct item_data *item; + + if( entry->nameid <= 0 || entry->nameid >= MAX_ITEMDB ) { + ShowWarning("itemdb_validate_entry: Invalid item ID %d in entry %d of '%s', allowed values 0 < ID < %d (MAX_ITEMDB), skipping.\n", + entry->nameid, n, source, MAX_ITEMDB); + if (entry->script) { + script->free_code(entry->script); + entry->script = NULL; + } + if (entry->equip_script) { + script->free_code(entry->equip_script); + entry->equip_script = NULL; + } + if (entry->unequip_script) { + script->free_code(entry->unequip_script); + entry->unequip_script = NULL; + } + return 0; } - if( i == 0 ) { - *atk = *matk = 0; - return;//no data found + + if( entry->type < 0 || entry->type == IT_UNKNOWN || entry->type == IT_UNKNOWN2 + || (entry->type > IT_DELAYCONSUME && entry->type < IT_CASH ) || entry->type >= IT_MAX + ) { + // catch invalid item types + ShowWarning("itemdb_validate_entry: Invalid item type %d for item %d in '%s'. IT_ETC will be used.\n", + entry->type, entry->nameid, source); + entry->type = IT_ETC; + } else if( entry->type == IT_DELAYCONSUME ) { + //Items that are consumed only after target confirmation + entry->type = IT_USABLE; + entry->flag.delay_consume = 1; } - if( i == 1 ) {//Single Value, we assume it's the ATK - *atk = val[0]; - *matk = 0; - return; + + //When a particular price is not given, we should base it off the other one + //(it is important to make a distinction between 'no price' and 0z) + if( entry->value_buy < 0 && entry->value_sell < 0 ) { + entry->value_buy = entry->value_sell = 0; + } else if( entry->value_buy < 0 ) { + entry->value_buy = entry->value_sell * 2; + } else if( entry->value_sell < 0 ) { + entry->value_sell = entry->value_buy / 2; } - //We assume we have 2 values. - *atk = val[0]; - *matk = val[1]; - return; -} -/*========================================== - * processes one itemdb entry - *------------------------------------------*/ -int itemdb_parse_dbrow(char** str, const char* source, int line, int scriptopt) { - /* - +----+--------------+---------------+------+-----------+------------+--------+--------+---------+-------+-------+------------+-------------+---------------+-----------------+--------------+-------------+------------+------+--------+--------------+----------------+ - | 00 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | - +----+--------------+---------------+------+-----------+------------+--------+--------+---------+-------+-------+------------+-------------+---------------+-----------------+--------------+-------------+------------+------+--------+--------------+----------------+ - | id | name_english | name_japanese | type | price_buy | price_sell | weight | attack | defence | range | slots | equip_jobs | equip_upper | equip_genders | equip_locations | weapon_level | equip_level | refineable | view | script | equip_script | unequip_script | - +----+--------------+---------------+------+-----------+------------+--------+--------+---------+-------+-------+------------+-------------+---------------+-----------------+--------------+-------------+------------+------+--------+--------------+----------------+ - */ - int nameid; - struct item_data* id; - unsigned char offset = 0; - - nameid = atoi(str[0]); - if( nameid <= 0 ) { - ShowWarning("itemdb_parse_dbrow: Invalid id %d in line %d of \"%s\", skipping.\n", nameid, line, source); - return 0; + if( entry->value_buy/124. < entry->value_sell/75. ) { + ShowWarning("itemdb_validate_entry: Buying/Selling [%d/%d] price of item %d (%s) in '%s' " + "allows Zeny making exploit through buying/selling at discounted/overcharged prices!\n", + entry->value_buy, entry->value_sell, entry->nameid, entry->jname, source); } - //ID,Name,Jname,Type,Price,Sell,Weight,ATK,DEF,Range,Slot,Job,Job Upper,Gender,Loc,wLV,eLV,refineable,View - id = itemdb_load(nameid); - safestrncpy(id->name, str[1], sizeof(id->name)); - safestrncpy(id->jname, str[2], sizeof(id->jname)); + if( entry->slot > MAX_SLOTS ) { + ShowWarning("itemdb_validate_entry: Item %d (%s) in '%s' specifies %d slots, but the server only supports up to %d. Using %d slots.\n", + entry->nameid, entry->jname, source, entry->slot, MAX_SLOTS, MAX_SLOTS); + entry->slot = MAX_SLOTS; + } - id->type = atoi(str[3]); + if (!entry->equip && itemdb->isequip2(entry)) { + ShowWarning("itemdb_validate_entry: Item %d (%s) in '%s' is an equipment with no equip-field! Making it an etc item.\n", + entry->nameid, entry->jname, source); + entry->type = IT_ETC; + } - if( id->type < 0 || id->type == IT_UNKNOWN || id->type == IT_UNKNOWN2 || ( id->type > IT_DELAYCONSUME && id->type < IT_CASH ) || id->type >= IT_MAX ) - {// catch invalid item types - ShowWarning("itemdb_parse_dbrow: Invalid item type %d for item %d. IT_ETC will be used.\n", id->type, nameid); - id->type = IT_ETC; + if (entry->flag.trade_restriction < 0 || entry->flag.trade_restriction > ITR_ALL) { + ShowWarning("itemdb_validate_entry: Invalid trade restriction flag 0x%x for item %d (%s) in '%s', defaulting to none.\n", + entry->flag.trade_restriction, entry->nameid, entry->jname, source); + entry->flag.trade_restriction = ITR_NONE; } - if (id->type == IT_DELAYCONSUME) - { //Items that are consumed only after target confirmation - id->type = IT_USABLE; - id->flag.delay_consume = 1; - } else //In case of an itemdb reload and the item type changed. - id->flag.delay_consume = 0; + if (entry->gm_lv_trade_override < 0 || entry->gm_lv_trade_override > 100) { + ShowWarning("itemdb_validate_entry: Invalid trade-override GM level %d for item %d (%s) in '%s', defaulting to none.\n", + entry->gm_lv_trade_override, entry->nameid, entry->jname, source); + entry->gm_lv_trade_override = 0; + } + if (entry->gm_lv_trade_override == 0) { + // Default value if none or an ivalid one was specified + entry->gm_lv_trade_override = 100; + } - //When a particular price is not given, we should base it off the other one - //(it is important to make a distinction between 'no price' and 0z) - if ( str[4][0] ) - id->value_buy = atoi(str[4]); - else - id->value_buy = atoi(str[5]) * 2; + if (entry->item_usage.flag > INR_ALL) { + ShowWarning("itemdb_validate_entry: Invalid nouse flag 0x%x for item %d (%s) in '%s', defaulting to none.\n", + entry->item_usage.flag, entry->nameid, entry->jname, source); + entry->item_usage.flag = INR_NONE; + } - if ( str[5][0] ) - id->value_sell = atoi(str[5]); - else - id->value_sell = id->value_buy / 2; - /* - if ( !str[4][0] && !str[5][0]) - { - ShowWarning("itemdb_parse_dbrow: No buying/selling price defined for item %d (%s), using 20/10z\n", nameid, id->jname); - id->value_buy = 20; - id->value_sell = 10; - } else - */ - if (id->value_buy/124. < id->value_sell/75.) - ShowWarning("itemdb_parse_dbrow: Buying/Selling [%d/%d] price of item %d (%s) allows Zeny making exploit through buying/selling at discounted/overcharged prices!\n", - id->value_buy, id->value_sell, nameid, id->jname); - - id->weight = atoi(str[6]); -#ifdef RENEWAL - if( iMap->db_use_sqldbs ) { - id->atk = atoi(str[7]); - id->matk = atoi(str[8]); - offset += 1; - } else - itemdb_re_split_atoi(str[7],&id->atk,&id->matk); -#else - id->atk = atoi(str[7]); -#endif - id->def = atoi(str[8+offset]); - id->range = atoi(str[9+offset]); - id->slot = atoi(str[10+offset]); + if (entry->item_usage.override > 100) { + ShowWarning("itemdb_validate_entry: Invalid nouse-override GM level %d for item %d (%s) in '%s', defaulting to none.\n", + entry->item_usage.override, entry->nameid, entry->jname, source); + entry->item_usage.override = 0; + } + if (entry->item_usage.override == 0) { + // Default value if none or an ivalid one was specified + entry->item_usage.override = 100; + } - if (id->slot > MAX_SLOTS) { - ShowWarning("itemdb_parse_dbrow: Item %d (%s) specifies %d slots, but the server only supports up to %d. Using %d slots.\n", nameid, id->jname, id->slot, MAX_SLOTS, MAX_SLOTS); - id->slot = MAX_SLOTS; + if (entry->stack.amount > 0 && !itemdb->isstackable2(entry)) { + ShowWarning("itemdb_validate_entry: Item %d (%s) of type %d is not stackable, ignoring stack settings in '%s'.\n", + entry->nameid, entry->jname, entry->type, source); + memset(&entry->stack, '\0', sizeof(entry->stack)); } - itemdb_jobid2mapid(id->class_base, (unsigned int)strtoul(str[11+offset],NULL,0)); - id->class_upper = atoi(str[12+offset]); - id->sex = atoi(str[13+offset]); - id->equip = atoi(str[14+offset]); + entry->wlv = cap_value(entry->wlv, REFINE_TYPE_ARMOR, REFINE_TYPE_MAX); - if (!id->equip && itemdb_isequip2(id)) { - ShowWarning("Item %d (%s) is an equipment with no equip-field! Making it an etc item.\n", nameid, id->jname); - id->type = IT_ETC; - } + if( !entry->elvmax ) + entry->elvmax = MAX_LEVEL; + else if( entry->elvmax < entry->elv ) + entry->elvmax = entry->elv; - id->wlv = cap_value(atoi(str[15+offset]), REFINE_TYPE_ARMOR, REFINE_TYPE_MAX); -#ifdef RENEWAL - if( iMap->db_use_sqldbs ) { - id->elv = atoi(str[16+offset]); - id->elvmax = atoi(str[17+offset]); - offset += 1; - } else - itemdb_re_split_atoi(str[16],&id->elv,&id->elvmax); -#else - id->elv = atoi(str[16]); -#endif - id->flag.no_refine = atoi(str[17+offset]) ? 0 : 1; //FIXME: verify this - id->look = atoi(str[18+offset]); + if( entry->type != IT_ARMOR && entry->type != IT_WEAPON && !entry->flag.no_refine ) + entry->flag.no_refine = 1; - id->flag.available = 1; - id->view_id = 0; - id->sex = itemdb_gendercheck(id); //Apply gender filtering. + if (entry->flag.available != 1) { + entry->flag.available = 1; + entry->view_id = 0; + } + + entry->sex = itemdb->gendercheck(entry); //Apply gender filtering. - if (id->script) { - script_free_code(id->script); - id->script = NULL; + // Validated. Finally insert it + item = itemdb->load(entry->nameid); + + if (item->script && item->script != entry->script) { // Don't free if it's inheriting the same script + script->free_code(item->script); + item->script = NULL; } - if (id->equip_script) { - script_free_code(id->equip_script); - id->equip_script = NULL; + if (item->equip_script && item->equip_script != entry->equip_script) { // Don't free if it's inheriting the same script + script->free_code(item->equip_script); + item->equip_script = NULL; } - if (id->unequip_script) { - script_free_code(id->unequip_script); - id->unequip_script = NULL; + if (item->unequip_script && item->unequip_script != entry->unequip_script) { // Don't free if it's inheriting the same script + script->free_code(item->unequip_script); + item->unequip_script = NULL; } - if (*str[19+offset]) - id->script = parse_script(str[19+offset], source, line, scriptopt); - if (*str[20+offset]) - id->equip_script = parse_script(str[20+offset], source, line, scriptopt); - if (*str[21+offset]) - id->unequip_script = parse_script(str[21+offset], source, line, scriptopt); + *item = *entry; + return item->nameid; +} + +/** + * Processes one itemdb entry from the sql backend, loading and inserting it + * into the item database. + * + * @param *handle MySQL connection handle. It is expected to have data + * available (i.e. already queried) and it won't be freed (it + * is care of the caller to do so) + * @param n Ordinal number of the entry, to be displayed in case of + * validation errors. + * @param *source Source of the entry (table name), to be displayed in case of + * validation errors. + * @return Nameid of the validated entry, or 0 in case of failure. + */ +int itemdb_readdb_sql_sub(Sql *handle, int n, const char *source) { + struct item_data id = { 0 }; + char *data = NULL; + + /* + * `id` smallint(5) unsigned NOT NULL DEFAULT '0' + * `name_english` varchar(50) NOT NULL DEFAULT '' + * `name_japanese` varchar(50) NOT NULL DEFAULT '' + * `type` tinyint(2) unsigned NOT NULL DEFAULT '0' + * `price_buy` mediumint(10) DEFAULT NULL + * `price_sell` mediumint(10) DEFAULT NULL + * `weight` smallint(5) unsigned DEFAULT NULL + * `atk` smallint(5) unsigned DEFAULT NULL + * `matk` smallint(5) unsigned DEFAULT NULL + * `defence` smallint(5) unsigned DEFAULT NULL + * `range` tinyint(2) unsigned DEFAULT NULL + * `slots` tinyint(2) unsigned DEFAULT NULL + * `equip_jobs` int(12) unsigned DEFAULT NULL + * `equip_upper` tinyint(8) unsigned DEFAULT NULL + * `equip_genders` tinyint(2) unsigned DEFAULT NULL + * `equip_locations` smallint(4) unsigned DEFAULT NULL + * `weapon_level` tinyint(2) unsigned DEFAULT NULL + * `equip_level_min` smallint(5) unsigned DEFAULT NULL + * `equip_level_max` smallint(5) unsigned DEFAULT NULL + * `refineable` tinyint(1) unsigned DEFAULT NULL + * `view` smallint(3) unsigned DEFAULT NULL + * `bindonequip` tinyint(1) unsigned DEFAULT NULL + * `buyingstore` tinyint(1) NOT NULL DEFAULT NULL + * `delay` mediumint(9) NOT NULL DEFAULT NULL + * `trade_flag` smallint(4) NOT NULL DEFAULT NULL + * `trade_group` smallint(4) NOT NULL DEFAULT NULL + * `nouse_flag` smallint(4) NOT NULL DEFAULT NULL + * `nouse_group` smallint(4) NOT NULL DEFAULT NULL + * `stack_amount` mediumint(6) NOT NULL DEFAULT NULL + * `stack_flag` smallint(2) NOT NULL DEFAULT NULL + * `sprite` mediumint(6) NOT NULL DEFAULT NULL + * `script` text + * `equip_script` text + * `unequip_script` text + */ + SQL->GetData(handle, 0, &data, NULL); id.nameid = (uint16)atoi(data); + SQL->GetData(handle, 1, &data, NULL); safestrncpy(id.name, data, sizeof(id.name)); + SQL->GetData(handle, 2, &data, NULL); safestrncpy(id.jname, data, sizeof(id.jname)); + SQL->GetData(handle, 3, &data, NULL); id.type = atoi(data); + SQL->GetData(handle, 4, &data, NULL); id.value_buy = data ? atoi(data) : -1; // Using invalid price -1 when missing, it'll be validated later + SQL->GetData(handle, 5, &data, NULL); id.value_sell = data ? atoi(data) : -1; + SQL->GetData(handle, 6, &data, NULL); id.weight = data ? atoi(data) : 0; + SQL->GetData(handle, 7, &data, NULL); id.atk = data ? atoi(data) : 0; + SQL->GetData(handle, 8, &data, NULL); id.matk = data ? atoi(data) : 0; + SQL->GetData(handle, 9, &data, NULL); id.def = data ? atoi(data) : 0; + SQL->GetData(handle, 10, &data, NULL); id.range = data ? atoi(data) : 0; + SQL->GetData(handle, 11, &data, NULL); id.slot = data ? atoi(data) : 0; + SQL->GetData(handle, 12, &data, NULL); itemdb->jobid2mapid(id.class_base, data ? (unsigned int)strtoul(data,NULL,0) : UINT_MAX); + SQL->GetData(handle, 13, &data, NULL); id.class_upper = data ? (unsigned int)atoi(data) : ITEMUPPER_ALL; + SQL->GetData(handle, 14, &data, NULL); id.sex = data ? atoi(data) : 2; + SQL->GetData(handle, 15, &data, NULL); id.equip = data ? atoi(data) : 0; + SQL->GetData(handle, 16, &data, NULL); id.wlv = data ? atoi(data) : 0; + SQL->GetData(handle, 17, &data, NULL); id.elv = data ? atoi(data) : 0; + SQL->GetData(handle, 18, &data, NULL); id.elvmax = data ? atoi(data) : 0; + SQL->GetData(handle, 19, &data, NULL); id.flag.no_refine = data && atoi(data) ? 0 : 1; + SQL->GetData(handle, 20, &data, NULL); id.look = data ? atoi(data) : 0; + SQL->GetData(handle, 21, &data, NULL); id.flag.bindonequip = data && atoi(data) ? 1 : 0; + SQL->GetData(handle, 22, &data, NULL); id.flag.buyingstore = data && atoi(data) ? 1 : 0; + SQL->GetData(handle, 23, &data, NULL); id.delay = data ? atoi(data) : 0; + SQL->GetData(handle, 24, &data, NULL); id.flag.trade_restriction = data ? atoi(data) : ITR_NONE; + SQL->GetData(handle, 25, &data, NULL); id.gm_lv_trade_override = data ? atoi(data) : 0; + SQL->GetData(handle, 26, &data, NULL); id.item_usage.flag = data ? atoi(data) : INR_NONE; + SQL->GetData(handle, 27, &data, NULL); id.item_usage.override = data ? atoi(data) : 0; + SQL->GetData(handle, 28, &data, NULL); id.stack.amount = data ? atoi(data) : 0; + SQL->GetData(handle, 29, &data, NULL); + if (data) { + int stack_flag = atoi(data); + id.stack.inventory = (stack_flag&1)!=0; + id.stack.cart = (stack_flag&2)!=0; + id.stack.storage = (stack_flag&4)!=0; + id.stack.guildstorage = (stack_flag&8)!=0; + } + SQL->GetData(handle, 30, &data, NULL); + if (data) { + id.view_id = atoi(data); + if (id.view_id) + id.flag.available = 1; + } + SQL->GetData(handle, 31, &data, NULL); id.script = data && *data ? script->parse(data, source, -id.nameid, SCRIPT_IGNORE_EXTERNAL_BRACKETS, NULL) : NULL; + SQL->GetData(handle, 32, &data, NULL); id.equip_script = data && *data ? script->parse(data, source, -id.nameid, SCRIPT_IGNORE_EXTERNAL_BRACKETS, NULL) : NULL; + SQL->GetData(handle, 33, &data, NULL); id.unequip_script = data && *data ? script->parse(data, source, -id.nameid, SCRIPT_IGNORE_EXTERNAL_BRACKETS, NULL) : NULL; - return id->nameid; + return itemdb->validate_entry(&id, n, source); } -/*========================================== - * Reading item from item db - * item_db2 overwriting item_db - *------------------------------------------*/ -static int itemdb_readdb(void) -{ - const char* filename[] = { - DBPATH"item_db.txt", - "item_db2.txt" }; +/** + * Processes one itemdb entry from the sql backend, loading and inserting it + * into the item database. + * + * @param *it Libconfig setting entry. It is expected to be valid and it + * won't be freed (it is care of the caller to do so if + * necessary) + * @param n Ordinal number of the entry, to be displayed in case of + * validation errors. + * @param *source Source of the entry (file name), to be displayed in case of + * validation errors. + * @return Nameid of the validated entry, or 0 in case of failure. + */ +int itemdb_readdb_libconfig_sub(config_setting_t *it, int n, const char *source) { + struct item_data id = { 0 }; + config_setting_t *t = NULL; + const char *str = NULL; + int i32 = 0; + bool inherit = false; - int fi; + /* + * // Mandatory fields + * Id: ID + * AegisName: "Aegis_Name" + * Name: "Item Name" + * // Optional fields + * Type: Item Type + * Buy: Buy Price + * Sell: Sell Price + * Weight: Item Weight + * Atk: Attack + * Matk: Attack + * Def: Defense + * Range: Attack Range + * Slots: Slots + * Job: Job mask + * Upper: Upper mask + * Gender: Gender + * Loc: Equip location + * WeaponLv: Weapon Level + * EquipLv: Equip required level or [min, max] + * Refine: Refineable + * View: View ID + * BindOnEquip: (true or false) + * BuyingStore: (true or false) + * Delay: Delay to use item + * Trade: { + * override: Group to override + * nodrop: (true or false) + * notrade: (true or false) + * partneroverride: (true or false) + * noselltonpc: (true or false) + * nocart: (true or false) + * nostorage: (true or false) + * nogstorage: (true or false) + * nomail: (true or false) + * noauction: (true or false) + * } + * Nouse: { + * override: Group to override + * sitting: (true or false) + * } + * Stack: [Stackable Amount, Stack Type] + * Sprite: SpriteID + * Script: <" + * Script + * (it can be multi-line) + * "> + * OnEquipScript: <" OnEquip Script "> + * OnUnequipScript: <" OnUnequip Script "> + * Inherit: inherit or override + */ + if( !libconfig->setting_lookup_int(it, "Id", &i32) ) { + ShowWarning("itemdb_readdb_libconfig_sub: Invalid or missing id in \"%s\", entry #%d, skipping.\n", source, n); + return 0; + } + id.nameid = (uint16)i32; - for( fi = 0; fi < ARRAYLENGTH(filename); ++fi ) { - uint32 lines = 0, count = 0; - char line[1024]; + if( (t = libconfig->setting_get_member(it, "Inherit")) && (inherit = libconfig->setting_get_bool(t)) ) { + if( !itemdb->exists(id.nameid) ) { + ShowWarning("itemdb_readdb_libconfig_sub: Trying to inherit nonexistent item %d, default values will be used instead.\n", id.nameid); + inherit = false; + } else { + // Use old entry as default + struct item_data *old_entry = itemdb->load(id.nameid); + memcpy(&id, old_entry, sizeof(struct item_data)); + } + } - char path[256]; - FILE* fp; + if( !libconfig->setting_lookup_string(it, "AegisName", &str) || !*str ) { + if( !inherit ) { + ShowWarning("itemdb_readdb_libconfig_sub: Missing AegisName in item %d of \"%s\", skipping.\n", id.nameid, source); + return 0; + } + } else { + safestrncpy(id.name, str, sizeof(id.name)); + } - sprintf(path, "%s/%s", iMap->db_path, filename[fi]); - fp = fopen(path, "r"); - if( fp == NULL ) { - ShowWarning("itemdb_readdb: File not found \"%s\", skipping.\n", path); - continue; + if( !libconfig->setting_lookup_string(it, "Name", &str) || !*str ) { + if( !inherit ) { + ShowWarning("itemdb_readdb_libconfig_sub: Missing Name in item %d of \"%s\", skipping.\n", id.nameid, source); + return 0; } + } else { + safestrncpy(id.jname, str, sizeof(id.jname)); + } - // process rows one by one - while(fgets(line, sizeof(line), fp)) - { - char *str[32], *p; - int i; - lines++; - if(line[0] == '/' && line[1] == '/') - continue; - memset(str, 0, sizeof(str)); - - p = line; - while( ISSPACE(*p) ) - ++p; - if( *p == '\0' ) - continue;// empty line - for( i = 0; i < 19; ++i ) - { - str[i] = p; - p = strchr(p,','); - if( p == NULL ) - break;// comma not found - *p = '\0'; - ++p; + if( libconfig->setting_lookup_int(it, "Type", &i32) ) + id.type = i32; + else if( !inherit ) + id.type = IT_UNKNOWN; + + if( libconfig->setting_lookup_int(it, "Buy", &i32) ) + id.value_buy = i32; + else if( !inherit ) + id.value_buy = -1; + if( libconfig->setting_lookup_int(it, "Sell", &i32) ) + id.value_sell = i32; + else if( !inherit ) + id.value_sell = -1; + + if( libconfig->setting_lookup_int(it, "Weight", &i32) && i32 >= 0 ) + id.weight = i32; + + if( libconfig->setting_lookup_int(it, "Atk", &i32) && i32 >= 0 ) + id.atk = i32; + + if( libconfig->setting_lookup_int(it, "Matk", &i32) && i32 >= 0 ) + id.matk = i32; + + if( libconfig->setting_lookup_int(it, "Def", &i32) && i32 >= 0 ) + id.def = i32; + + if( libconfig->setting_lookup_int(it, "Range", &i32) && i32 >= 0 ) + id.range = i32; + + if( libconfig->setting_lookup_int(it, "Slots", &i32) && i32 >= 0 ) + id.slot = i32; + + if( libconfig->setting_lookup_int(it, "Job", &i32) ) // This is an unsigned value, do not check for >= 0 + itemdb->jobid2mapid(id.class_base, (unsigned int)i32); + else if( !inherit ) + itemdb->jobid2mapid(id.class_base, UINT_MAX); + + if( libconfig->setting_lookup_int(it, "Upper", &i32) && i32 >= 0 ) + id.class_upper = (unsigned int)i32; + else if( !inherit ) + id.class_upper = ITEMUPPER_ALL; + + if( libconfig->setting_lookup_int(it, "Gender", &i32) && i32 >= 0 ) + id.sex = i32; + else if( !inherit ) + id.sex = 2; + + if( libconfig->setting_lookup_int(it, "Loc", &i32) && i32 >= 0 ) + id.equip = i32; + + if( libconfig->setting_lookup_int(it, "WeaponLv", &i32) && i32 >= 0 ) + id.wlv = i32; + + if( (t = libconfig->setting_get_member(it, "EquipLv")) ) { + if( config_setting_is_aggregate(t) ) { + if( libconfig->setting_length(t) >= 2 ) + id.elvmax = libconfig->setting_get_int_elem(t, 1); + if( libconfig->setting_length(t) >= 1 ) + id.elv = libconfig->setting_get_int_elem(t, 0); + } else { + id.elv = libconfig->setting_get_int(t); + } + } + + if( (t = libconfig->setting_get_member(it, "Refine")) ) + id.flag.no_refine = libconfig->setting_get_bool(t) ? 0 : 1; + + if( libconfig->setting_lookup_int(it, "View", &i32) && i32 >= 0 ) + id.look = i32; + + if( (t = libconfig->setting_get_member(it, "BindOnEquip")) ) + id.flag.bindonequip = libconfig->setting_get_bool(t) ? 1 : 0; + + if ( (t = libconfig->setting_get_member(it, "BuyingStore")) ) + id.flag.buyingstore = libconfig->setting_get_bool(t) ? 1 : 0; + + if (libconfig->setting_lookup_int(it, "Delay", &i32) && i32 >= 0) + id.delay = i32; + + if ( (t = libconfig->setting_get_member(it, "Trade")) ) { + if (config_setting_is_group(t)) { + config_setting_t *tt = NULL; + + if ((tt = libconfig->setting_get_member(t, "override"))) { + id.gm_lv_trade_override = libconfig->setting_get_int(tt); } - if( p == NULL ) - { - ShowError("itemdb_readdb: Insufficient columns in line %d of \"%s\" (item with id %d), skipping.\n", lines, path, atoi(str[0])); - continue; + if ((tt = libconfig->setting_get_member(t, "nodrop"))) { + id.flag.trade_restriction &= ~ITR_NODROP; + if (libconfig->setting_get_bool(tt)) + id.flag.trade_restriction |= ITR_NODROP; } - // Script - if( *p != '{' ) - { - ShowError("itemdb_readdb: Invalid format (Script column) in line %d of \"%s\" (item with id %d), skipping.\n", lines, path, atoi(str[0])); - continue; + if ((tt = libconfig->setting_get_member(t, "notrade"))) { + id.flag.trade_restriction &= ~ITR_NOTRADE; + if (libconfig->setting_get_bool(tt)) + id.flag.trade_restriction |= ITR_NOTRADE; } - str[19] = p; - p = strstr(p+1,"},"); - if( p == NULL ) - { - ShowError("itemdb_readdb: Invalid format (Script column) in line %d of \"%s\" (item with id %d), skipping.\n", lines, path, atoi(str[0])); - continue; + + if ((tt = libconfig->setting_get_member(t, "partneroverride"))) { + id.flag.trade_restriction &= ~ITR_PARTNEROVERRIDE; + if (libconfig->setting_get_bool(tt)) + id.flag.trade_restriction |= ITR_PARTNEROVERRIDE; } - p[1] = '\0'; - p += 2; - // OnEquip_Script - if( *p != '{' ) - { - ShowError("itemdb_readdb: Invalid format (OnEquip_Script column) in line %d of \"%s\" (item with id %d), skipping.\n", lines, path, atoi(str[0])); - continue; + if ((tt = libconfig->setting_get_member(t, "noselltonpc"))) { + id.flag.trade_restriction &= ~ITR_NOSELLTONPC; + if (libconfig->setting_get_bool(tt)) + id.flag.trade_restriction |= ITR_NOSELLTONPC; } - str[20] = p; - p = strstr(p+1,"},"); - if( p == NULL ) - { - ShowError("itemdb_readdb: Invalid format (OnEquip_Script column) in line %d of \"%s\" (item with id %d), skipping.\n", lines, path, atoi(str[0])); - continue; + + if ((tt = libconfig->setting_get_member(t, "nocart"))) { + id.flag.trade_restriction &= ~ITR_NOCART; + if (libconfig->setting_get_bool(tt)) + id.flag.trade_restriction |= ITR_NOCART; } - p[1] = '\0'; - p += 2; - // OnUnequip_Script (last column) - if( *p != '{' ) - { - ShowError("itemdb_readdb: Invalid format (OnUnequip_Script column) in line %d of \"%s\" (item with id %d), skipping.\n", lines, path, atoi(str[0])); - continue; + if ((tt = libconfig->setting_get_member(t, "nostorage"))) { + id.flag.trade_restriction &= ~ITR_NOSTORAGE; + if (libconfig->setting_get_bool(tt)) + id.flag.trade_restriction |= ITR_NOSTORAGE; } - str[21] = p; - - if ( str[21][strlen(str[21])-2] != '}' ) { - /* lets count to ensure it's not something silly e.g. a extra space at line ending */ - int v, lcurly = 0, rcurly = 0; - - for( v = 0; v < strlen(str[21]); v++ ) { - if( str[21][v] == '{' ) - lcurly++; - else if ( str[21][v] == '}' ) - rcurly++; - } - - if( lcurly != rcurly ) { - ShowError("itemdb_readdb: Mismatching curly braces in line %d of \"%s\" (item with id %d), skipping.\n", lines, path, atoi(str[0])); - continue; - } + + if ((tt = libconfig->setting_get_member(t, "nogstorage"))) { + id.flag.trade_restriction &= ~ITR_NOGSTORAGE; + if (libconfig->setting_get_bool(tt)) + id.flag.trade_restriction |= ITR_NOGSTORAGE; } - if (!itemdb->parse_dbrow(str, path, lines, 0)) - continue; - - count++; + if ((tt = libconfig->setting_get_member(t, "nomail"))) { + id.flag.trade_restriction &= ~ITR_NOMAIL; + if (libconfig->setting_get_bool(tt)) + id.flag.trade_restriction |= ITR_NOMAIL; + } + + if ((tt = libconfig->setting_get_member(t, "noauction"))) { + id.flag.trade_restriction &= ~ITR_NOAUCTION; + if (libconfig->setting_get_bool(tt)) + id.flag.trade_restriction |= ITR_NOAUCTION; + } + } else { // Fallback to int if it's not a group + id.flag.trade_restriction = libconfig->setting_get_int(t); } + } - fclose(fp); + if ((t = libconfig->setting_get_member(it, "Nouse"))) { + if (config_setting_is_group(t)) { + config_setting_t *nt = NULL; + + if ((nt = libconfig->setting_get_member(t, "override"))) { + id.item_usage.override = libconfig->setting_get_int(nt); + } + + if ((nt = libconfig->setting_get_member(t, "sitting"))) { + id.item_usage.flag &= ~INR_SITTING; + if (libconfig->setting_get_bool(nt)) + id.item_usage.flag |= INR_SITTING; + } - ShowStatus("Done reading '"CL_WHITE"%lu"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", count, filename[fi]); + } else { // Fallback to int if it's not a group + id.item_usage.flag = libconfig->setting_get_int(t); + } } - return 0; + if ((t = libconfig->setting_get_member(it, "Stack"))) { + if (config_setting_is_aggregate(t) && libconfig->setting_length(t) >= 1) { + int stack_flag = libconfig->setting_get_int_elem(t, 1); + int stack_amount = libconfig->setting_get_int_elem(t, 0); + if (stack_amount >= 0) { + id.stack.amount = cap_value(stack_amount, 0, USHRT_MAX); + id.stack.inventory = (stack_flag&1)!=0; + id.stack.cart = (stack_flag&2)!=0; + id.stack.storage = (stack_flag&4)!=0; + id.stack.guildstorage = (stack_flag&8)!=0; + } + } + } + + if (libconfig->setting_lookup_int(it, "Sprite", &i32) && i32 >= 0) { + id.flag.available = 1; + id.view_id = i32; + } + + if( libconfig->setting_lookup_string(it, "Script", &str) ) + id.script = *str ? script->parse(str, source, -id.nameid, SCRIPT_IGNORE_EXTERNAL_BRACKETS, NULL) : NULL; + + if( libconfig->setting_lookup_string(it, "OnEquipScript", &str) ) + id.equip_script = *str ? script->parse(str, source, -id.nameid, SCRIPT_IGNORE_EXTERNAL_BRACKETS, NULL) : NULL; + + if( libconfig->setting_lookup_string(it, "OnUnequipScript", &str) ) + id.unequip_script = *str ? script->parse(str, source, -id.nameid, SCRIPT_IGNORE_EXTERNAL_BRACKETS, NULL) : NULL; + + return itemdb->validate_entry(&id, n, source); } -/*====================================== - * item_db table reading - *======================================*/ -static int itemdb_read_sqldb(void) { - - const char* item_db_name[] = { - #ifdef RENEWAL - iMap->item_db_re_db, - #else - iMap->item_db_db, - #endif - iMap->item_db2_db }; - int fi; - - for( fi = 0; fi < ARRAYLENGTH(item_db_name); ++fi ) { - uint32 count = 0; - - // retrieve all rows from the item database - if( SQL_ERROR == SQL->Query(mmysql_handle, "SELECT * FROM `%s`", item_db_name[fi]) ) { - Sql_ShowDebug(mmysql_handle); + +/** + * Reads from a libconfig-formatted itemdb file and inserts the found entries into the + * item database, overwriting duplicate ones (i.e. item_db2 overriding item_db.) + * + * @param *filename File name, relative to the database path. + * @return The number of found entries. + */ +int itemdb_readdb_libconfig(const char *filename) { + bool duplicate[MAX_ITEMDB]; + config_t item_db_conf; + config_setting_t *itdb, *it; + char filepath[256]; + int i = 0, count = 0; + + sprintf(filepath, "%s/%s", map->db_path, filename); + memset(&duplicate,0,sizeof(duplicate)); + if( libconfig->read_file(&item_db_conf, filepath) || !(itdb = libconfig->setting_get_member(item_db_conf.root, "item_db")) ) { + ShowError("can't read %s\n", filepath); + return 0; + } + + while( (it = libconfig->setting_get_elem(itdb,i++)) ) { + int nameid = itemdb->readdb_libconfig_sub(it, i-1, filename); + + if( !nameid ) continue; - } - // process rows one by one - while( SQL_SUCCESS == SQL->NextRow(mmysql_handle) ) {// wrap the result into a TXT-compatible format - char* str[ITEMDB_SQL_COLUMNS]; - char* dummy = ""; - int i; - for( i = 0; i < ITEMDB_SQL_COLUMNS; ++i ) { - SQL->GetData(mmysql_handle, i, &str[i], NULL); - if( str[i] == NULL ) - str[i] = dummy; // get rid of NULL columns - } + count++; - if (!itemdb->parse_dbrow(str, item_db_name[fi], -(atoi(str[0])), SCRIPT_IGNORE_EXTERNAL_BRACKETS)) - continue; - ++count; - } + if( duplicate[nameid] ) { + ShowWarning("itemdb_readdb:%s: duplicate entry of ID #%d (%s/%s)\n", + filename, nameid, itemdb_name(nameid), itemdb_jname(nameid)); + } else + duplicate[nameid] = true; + } + libconfig->destroy(&item_db_conf); + ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", count, filename); + + return count; +} - // free the query result - SQL->FreeResult(mmysql_handle); +/** + * Reads from a sql itemdb table and inserts the found entries into the item + * database, overwriting duplicate ones (i.e. item_db2 overriding item_db.) + * + * @param *tablename Table name to query. + * @return The number of found entries. + */ +int itemdb_readdb_sql(const char *tablename) { + int i = 0, count = 0; + + // retrieve all rows from the item database + if( SQL_ERROR == SQL->Query(map->mysql_handle, "SELECT `id`, `name_english`, `name_japanese`, `type`," + " `price_buy`, `price_sell`, `weight`, `atk`," + " `matk`, `defence`, `range`, `slots`," + " `equip_jobs`, `equip_upper`, `equip_genders`, `equip_locations`," + " `weapon_level`, `equip_level_min`, `equip_level_max`, `refineable`," + " `view`, `bindonequip`, `buyingstore`, `delay`," + " `trade_flag`, `trade_group`, `nouse_flag`, `nouse_group`," + " `stack_amount`, `stack_flag`, `sprite`, `script`," + " `equip_script`, `unequip_script`" + "FROM `%s`", tablename) ) { + Sql_ShowDebug(map->mysql_handle); + return 0; + } - ShowStatus("Done reading '"CL_WHITE"%lu"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", count, item_db_name[fi]); + // process rows one by one + while( SQL_SUCCESS == SQL->NextRow(map->mysql_handle) ) { + if( itemdb->readdb_sql_sub(map->mysql_handle, i++, tablename) ) + count++; } - return 0; + // free the query result + SQL->FreeResult(map->mysql_handle); + + ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", count, tablename); + + return count; } /*========================================== * Unique item ID function * Only one operation by once -* Flag: -* 0 return new id -* 1 set new value, checked with current value -* 2 set new value bypassing anything -* 3/other return last value *------------------------------------------*/ -uint64 itemdb_unique_id(int8 flag, int64 value) { - static uint64 item_uid = 0; - - if(flag) - { - if(flag == 1) - { if(item_uid < value) - return (item_uid = value); - }else if(flag == 2) - return (item_uid = value); - - return item_uid; - } +uint64 itemdb_unique_id(struct map_session_data *sd) { - return ++item_uid; + return ((uint64)sd->status.char_id << 32) | sd->status.uniqueitem_counter++; } -int itemdb_uid_load() { - - char * uid; - if (SQL_ERROR == SQL->Query(mmysql_handle, "SELECT `value` FROM `%s` WHERE `varname`='unique_id'",iMap->interreg_db)) - Sql_ShowDebug(mmysql_handle); - if( SQL_SUCCESS != SQL->NextRow(mmysql_handle) ) { - ShowError("itemdb_uid_load: Unable to fetch unique_id data\n"); - SQL->FreeResult(mmysql_handle); - return -1; +/** + * Reads all item-related databases. + */ +void itemdb_read(bool minimal) { + int i; + DBData prev; + + if (map->db_use_sql_item_db) { + const char* item_db_name[] = { +#ifdef RENEWAL + map->item_db_re_db, +#else // not RENEWAL + map->item_db_db, +#endif // RENEWAL + map->item_db2_db + }; + for(i = 0; i < ARRAYLENGTH(item_db_name); i++) + itemdb->readdb_sql(item_db_name[i]); + } else { + const char* filename[] = { + DBPATH"item_db.conf", + "item_db2.conf", + }; + + for(i = 0; i < ARRAYLENGTH(filename); i++) + itemdb->readdb_libconfig(filename[i]); } + + for( i = 0; i < ARRAYLENGTH(itemdb->array); ++i ) { + if( itemdb->array[i] ) { + if( itemdb->names->put(itemdb->names,DB->str2key(itemdb->array[i]->name),DB->ptr2data(itemdb->array[i]),&prev) ) { + struct item_data *data = DB->data2ptr(&prev); + ShowError("itemdb_read: duplicate AegisName '%s' in item ID %d and %d\n",itemdb->array[i]->name,itemdb->array[i]->nameid,data->nameid); + } + } + } + + if (minimal) + return; - SQL->GetData(mmysql_handle, 0, &uid, NULL); - itemdb_unique_id(1, (uint64)strtoull(uid, NULL, 10)); - SQL->FreeResult(mmysql_handle); + itemdb->read_combos(); + itemdb->read_groups(); + itemdb->read_chains(); + itemdb->read_packages(); - return 0; } -/*==================================== - * read all item-related databases - *------------------------------------*/ -static void itemdb_read(void) { - - if (iMap->db_use_sqldbs) - itemdb_read_sqldb(); - else - itemdb_readdb(); - - itemdb_read_combos(); - itemdb_read_itemgroup(); - sv->readdb(iMap->db_path, "item_avail.txt", ',', 2, 2, -1, &itemdb_read_itemavail); - sv->readdb(iMap->db_path, DBPATH"item_trade.txt", ',', 3, 3, -1, &itemdb_read_itemtrade); - sv->readdb(iMap->db_path, "item_delay.txt", ',', 2, 2, -1, &itemdb_read_itemdelay); - sv->readdb(iMap->db_path, "item_stack.txt", ',', 3, 3, -1, &itemdb_read_stack); - sv->readdb(iMap->db_path, DBPATH"item_buyingstore.txt", ',', 1, 1, -1, &itemdb_read_buyingstore); - sv->readdb(iMap->db_path, "item_nouse.txt", ',', 3, 3, -1, &itemdb_read_nouse); - - itemdb_uid_load(); +/** + * retrieves item_combo data by combo id + **/ +struct item_combo * itemdb_id2combo( unsigned short id ) { + if( id > itemdb->combo_count ) + return NULL; + return itemdb->combos[id]; } /*========================================== @@ -1344,28 +2055,19 @@ static void itemdb_read(void) { *------------------------------------------*/ /// Destroys the item_data. -static void destroy_item_data(struct item_data* self, int free_self) +void destroy_item_data(struct item_data* self, int free_self) { if( self == NULL ) return; // free scripts if( self->script ) - script_free_code(self->script); + script->free_code(self->script); if( self->equip_script ) - script_free_code(self->equip_script); + script->free_code(self->equip_script); if( self->unequip_script ) - script_free_code(self->unequip_script); - if( self->combos_count ) { - int i; - for( i = 0; i < self->combos_count; i++ ) { - if( !self->combos[i]->isRef ) { - aFree(self->combos[i]->nameid); - script_free_code(self->combos[i]->script); - } - aFree(self->combos[i]); - } + script->free_code(self->unequip_script); + if( self->combos ) aFree(self->combos); - } #if defined(DEBUG) // trash item memset(self, 0xDD, sizeof(struct item_data)); @@ -1378,34 +2080,92 @@ static void destroy_item_data(struct item_data* self, int free_self) /** * @see DBApply */ -static int itemdb_final_sub(DBKey key, DBData *data, va_list ap) +int itemdb_final_sub(DBKey key, DBData *data, va_list ap) { struct item_data *id = DB->data2ptr(data); - if( id != &dummy_item ) - destroy_item_data(id, 1); + if( id != &itemdb->dummy ) + itemdb->destroy_item_data(id, 1); return 0; } +void itemdb_clear(bool total) { + int i; + // clear the previous itemdb data + for( i = 0; i < ARRAYLENGTH(itemdb->array); ++i ) { + if( itemdb->array[i] ) + itemdb->destroy_item_data(itemdb->array[i], 1); + } + + for( i = 0; i < itemdb->group_count; i++ ) { + if( itemdb->groups[i].nameid ) + aFree(itemdb->groups[i].nameid); + } + + if( itemdb->groups ) + aFree(itemdb->groups); + + itemdb->groups = NULL; + itemdb->group_count = 0; + + for( i = 0; i < itemdb->chain_count; i++ ) { + if( itemdb->chains[i].items ) + aFree(itemdb->chains[i].items); + } + + if( itemdb->chains ) + aFree(itemdb->chains); + + itemdb->chains = NULL; + itemdb->chain_count = 0; + + for( i = 0; i < itemdb->package_count; i++ ) { + int c; + for( c = 0; c < itemdb->packages[i].random_qty; c++ ) + aFree(itemdb->packages[i].random_groups[c].random_list); + if( itemdb->packages[i].random_groups ) + aFree(itemdb->packages[i].random_groups); + if( itemdb->packages[i].must_items ) + aFree(itemdb->packages[i].must_items); + } + + if( itemdb->packages ) + aFree(itemdb->packages); + + itemdb->packages = NULL; + itemdb->package_count = 0; + + for(i = 0; i < itemdb->combo_count; i++) { + if( itemdb->combos[i]->script ) // Check if script was loaded + script->free_code(itemdb->combos[i]->script); + aFree(itemdb->combos[i]); + } + if( itemdb->combos ) + aFree(itemdb->combos); + + itemdb->combos = NULL; + itemdb->combo_count = 0; + + if( total ) + return; + + itemdb->other->clear(itemdb->other, itemdb->final_sub); + + memset(itemdb->array, 0, sizeof(itemdb->array)); + + db_clear(itemdb->names); -void itemdb_reload(void) -{ +} +void itemdb_reload(void) { struct s_mapiterator* iter; struct map_session_data* sd; int i,d,k; - // clear the previous itemdb data - for( i = 0; i < ARRAYLENGTH(itemdb_array); ++i ) - if( itemdb_array[i] ) - destroy_item_data(itemdb_array[i], 1); + itemdb->clear(false); - itemdb_other->clear(itemdb_other, itemdb_final_sub); - - memset(itemdb_array, 0, sizeof(itemdb_array)); - // read new data - itemdb_read(); + itemdb->read(false); //Epoque's awesome @reloaditemdb fix - thanks! [Ind] //- Fixes the need of a @reloadmobdb after a @reloaditemdb to re-link monster drop data @@ -1413,12 +2173,12 @@ void itemdb_reload(void) struct mob_db *entry; if( !((i < 1324 || i > 1363) && (i < 1938 || i > 1946)) ) continue; - entry = mob_db(i); + entry = mob->db(i); for(d = 0; d < MAX_MOB_DROP; d++) { struct item_data *id; if( !entry->dropitem[d].nameid ) continue; - id = itemdb_search(entry->dropitem[d].nameid); + id = itemdb->search(entry->dropitem[d].nameid); for (k = 0; k < MAX_SEARCH; k++) { if (id->mob[k].chance <= entry->dropitem[d].p) @@ -1440,48 +2200,133 @@ void itemdb_reload(void) for( sd = (struct map_session_data*)mapit->first(iter); mapit->exists(iter); sd = (struct map_session_data*)mapit->next(iter) ) { memset(sd->item_delay, 0, sizeof(sd->item_delay)); // reset item delays pc->setinventorydata(sd); + if( battle_config.item_check ) + sd->state.itemcheck = 1; /* clear combo bonuses */ - if( sd->combos.count ) { - aFree(sd->combos.bonus); - aFree(sd->combos.id); - sd->combos.bonus = NULL; - sd->combos.id = NULL; - sd->combos.count = 0; + if( sd->combo_count ) { + aFree(sd->combos); + sd->combos = NULL; + sd->combo_count = 0; if( pc->load_combo(sd) > 0 ) - status_calc_pc(sd,0); + status_calc_pc(sd,SCO_FORCE); } - + pc->checkitem(sd); } mapit->free(iter); } +void itemdb_name_constants(void) { + DBIterator *iter = db_iterator(itemdb->names); + struct item_data *data; + +#ifdef ENABLE_CASE_CHECK + script->parser_current_file = "Item Database (Likely an invalid or conflicting AegisName)"; +#endif // ENABLE_CASE_CHECK + for( data = dbi_first(iter); dbi_exists(iter); data = dbi_next(iter) ) + script->set_constant2(data->name,data->nameid,0); +#ifdef ENABLE_CASE_CHECK + script->parser_current_file = NULL; +#endif // ENABLE_CASE_CHECK + + dbi_destroy(iter); +} +void do_final_itemdb(void) { + itemdb->clear(true); + + itemdb->other->destroy(itemdb->other, itemdb->final_sub); + itemdb->destroy_item_data(&itemdb->dummy, 0); + db_destroy(itemdb->names); +} -void do_final_itemdb(void) -{ - int i; - - for( i = 0; i < ARRAYLENGTH(itemdb_array); ++i ) - if( itemdb_array[i] ) - destroy_item_data(itemdb_array[i], 1); +void do_init_itemdb(bool minimal) { + memset(itemdb->array, 0, sizeof(itemdb->array)); + itemdb->other = idb_alloc(DB_OPT_BASE); + itemdb->names = strdb_alloc(DB_OPT_BASE,ITEM_NAME_LENGTH); + itemdb->create_dummy_data(); //Dummy data item. + itemdb->read(minimal); - itemdb_other->destroy(itemdb_other, itemdb_final_sub); - destroy_item_data(&dummy_item, 0); -} + if (minimal) + return; -int do_init_itemdb(void) { - memset(itemdb_array, 0, sizeof(itemdb_array)); - itemdb_other = idb_alloc(DB_OPT_BASE); - create_dummy_data(); //Dummy data item. - itemdb_read(); clif->cashshop_load(); - - return 0; } -/* incomplete */ void itemdb_defaults(void) { itemdb = &itemdb_s; - itemdb->reload = itemdb_reload;//incomplet=e + itemdb->init = do_init_itemdb; + itemdb->final = do_final_itemdb; + itemdb->reload = itemdb_reload; + itemdb->name_constants = itemdb_name_constants; + /* */ + itemdb->groups = NULL; + itemdb->group_count = 0; + /* */ + itemdb->chains = NULL; + itemdb->chain_count = 0; + /* */ + itemdb->packages = NULL; + itemdb->package_count = 0; + /* */ + itemdb->combos = NULL; + itemdb->combo_count = 0; + /* */ + itemdb->names = NULL; + /* */ + /* itemdb->array is cleared on itemdb->init() */ + itemdb->other = NULL; + memset(&itemdb->dummy, 0, sizeof(struct item_data)); + /* */ + itemdb->read_groups = itemdb_read_groups; + itemdb->read_chains = itemdb_read_chains; + itemdb->read_packages = itemdb_read_packages; + /* */ + itemdb->write_cached_packages = itemdb_write_cached_packages; + itemdb->read_cached_packages = itemdb_read_cached_packages; /* */ - itemdb->parse_dbrow = itemdb_parse_dbrow; - itemdb->exists = itemdb_exists;//incomplete + itemdb->name2id = itemdb_name2id; + itemdb->search_name = itemdb_searchname; + itemdb->search_name_array = itemdb_searchname_array; + itemdb->load = itemdb_load; + itemdb->search = itemdb_search; + itemdb->exists = itemdb_exists; + itemdb->in_group = itemdb_in_group; + itemdb->group_item = itemdb_searchrandomid; + itemdb->chain_item = itemdb_chain_item; + itemdb->package_item = itemdb_package_item; + itemdb->searchname_sub = itemdb_searchname_sub; + itemdb->searchname_array_sub = itemdb_searchname_array_sub; + itemdb->searchrandomid = itemdb_searchrandomid; + itemdb->typename = itemdb_typename; + itemdb->jobid2mapid = itemdb_jobid2mapid; + itemdb->create_dummy_data = create_dummy_data; + itemdb->create_item_data = create_item_data; + itemdb->isequip = itemdb_isequip; + itemdb->isequip2 = itemdb_isequip2; + itemdb->isstackable = itemdb_isstackable; + itemdb->isstackable2 = itemdb_isstackable2; + itemdb->isdropable_sub = itemdb_isdropable_sub; + itemdb->cantrade_sub = itemdb_cantrade_sub; + itemdb->canpartnertrade_sub = itemdb_canpartnertrade_sub; + itemdb->cansell_sub = itemdb_cansell_sub; + itemdb->cancartstore_sub = itemdb_cancartstore_sub; + itemdb->canstore_sub = itemdb_canstore_sub; + itemdb->canguildstore_sub = itemdb_canguildstore_sub; + itemdb->canmail_sub = itemdb_canmail_sub; + itemdb->canauction_sub = itemdb_canauction_sub; + itemdb->isrestricted = itemdb_isrestricted; + itemdb->isidentified = itemdb_isidentified; + itemdb->isidentified2 = itemdb_isidentified2; + itemdb->combo_split_atoi = itemdb_combo_split_atoi; + itemdb->read_combos = itemdb_read_combos; + itemdb->gendercheck = itemdb_gendercheck; + itemdb->validate_entry = itemdb_validate_entry; + itemdb->readdb_sql_sub = itemdb_readdb_sql_sub; + itemdb->readdb_libconfig_sub = itemdb_readdb_libconfig_sub; + itemdb->readdb_libconfig = itemdb_readdb_libconfig; + itemdb->readdb_sql = itemdb_readdb_sql; + itemdb->unique_id = itemdb_unique_id; + itemdb->read = itemdb_read; + itemdb->destroy_item_data = destroy_item_data; + itemdb->final_sub = itemdb_final_sub; + itemdb->clear = itemdb_clear; + itemdb->id2combo = itemdb_id2combo; } diff --git a/src/map/itemdb.h b/src/map/itemdb.h index 44b455d80..198d7a542 100644 --- a/src/map/itemdb.h +++ b/src/map/itemdb.h @@ -2,95 +2,372 @@ // See the LICENSE file // Portions Copyright (c) Athena Dev Teams -#ifndef _ITEMDB_H_ -#define _ITEMDB_H_ +#ifndef MAP_ITEMDB_H +#define MAP_ITEMDB_H +#include "map.h" +#include "../common/cbasetypes.h" +#include "../common/conf.h" #include "../common/db.h" #include "../common/mmo.h" // ITEM_NAME_LENGTH -#include "map.h" +#include "../common/sql.h" -// 32k array entries in array (the rest goes to the db) -#define MAX_ITEMDB 0x8000 +/** + * Declarations + **/ +struct item_group; +struct item_package; -#define MAX_RANDITEM 11000 +/** + * Defines + **/ +#define MAX_ITEMDB 0x8000 // 32k array entries in array (the rest goes to the db) +#define MAX_ITEMDELAYS 10 // The maximum number of item delays +#define MAX_SEARCH 5 //Designed for search functions, species max number of matches to display. +#define MAX_ITEMS_PER_COMBO 6 /* maximum amount of items a combo may require */ -// The maximum number of item delays -#define MAX_ITEMDELAYS 10 +#define CARD0_FORGE 0x00FF +#define CARD0_CREATE 0x00FE +#define CARD0_PET ((short)0xFF00) -#define MAX_SEARCH 5 //Designed for search functions, species max number of matches to display. +//Marks if the card0 given is "special" (non-item id used to mark pets/created items. [Skotlex] +#define itemdb_isspecial(i) ((i) == CARD0_FORGE || (i) == CARD0_CREATE || (i) == CARD0_PET) -/* maximum amount of items a combo may require */ -#define MAX_ITEMS_PER_COMBO 6 +//Use apple for unknown items. +#define UNKNOWN_ITEM_ID 512 enum item_itemid { - ITEMID_HOLY_WATER = 523, - ITEMID_EMPERIUM = 714, - ITEMID_YELLOW_GEMSTONE = 715, - ITEMID_RED_GEMSTONE = 716, - ITEMID_BLUE_GEMSTONE = 717, - ITEMID_TRAP = 1065, - ITEMID_FACE_PAINT = 6120, - ITEMID_STONE = 7049, - ITEMID_SKULL_ = 7420, - ITEMID_TOKEN_OF_SIEGFRIED = 7621, - ITEMID_TRAP_ALLOY = 7940, - ITEMID_ANCILLA = 12333, - ITEMID_REINS_OF_MOUNT = 12622, + ITEMID_RED_POTION = 501, + ITEMID_YELLOW_POTION = 503, + ITEMID_WHITE_POTION = 504, + ITEMID_BLUE_POTION = 505, + ITEMID_HOLY_WATER = 523, + ITEMID_RED_SLIM_POTION = 545, + ITEMID_YELLOW_SLIM_POTION = 546, + ITEMID_WHITE_SLIM_POTION = 547, + ITEMID_WING_OF_FLY = 601, + ITEMID_WING_OF_BUTTERFLY = 602, + ITEMID_BRANCH_OF_DEAD_TREE = 604, + ITEMID_ANODYNE = 605, + ITEMID_ALOEBERA = 606, + ITEMID_EMPTY_BOTTLE = 713, + ITEMID_EMPERIUM = 714, + ITEMID_YELLOW_GEMSTONE = 715, + ITEMID_RED_GEMSTONE = 716, + ITEMID_BLUE_GEMSTONE = 717, + ITEMID_ORIDECON_STONE = 756, + ITEMID_ALCHOL = 970, + ITEMID_ORIDECON = 984, + ITEMID_ANVIL = 986, + ITEMID_ORIDECON_ANVIL = 987, + ITEMID_GOLDEN_ANVIL = 988, + ITEMID_EMPERIUM_ANVIL = 989, + ITEMID_BOODY_RED = 990, + ITEMID_CRYSTAL_BLUE = 991, + ITEMID_WIND_OF_VERDURE = 992, + ITEMID_YELLOW_LIVE = 993, + ITEMID_FLAME_HEART = 994, + ITEMID_MISTIC_FROZEN = 995, + ITEMID_ROUGH_WIND = 996, + ITEMID_GREAT_NATURE = 997, + ITEMID_IRON = 998, + ITEMID_STEEL = 999, + ITEMID_STAR_CRUMB = 1000, + ITEMID_IRON_ORE = 1002, + ITEMID_PHRACON = 1010, + ITEMID_EMVERETARCON = 1011, + ITEMID_TRAP = 1065, + ITEMID_PILEBUNCKER = 1549, + ITEMID_ANGRA_MANYU = 1599, + ITEMID_STRANGE_EMBRYO = 6415, + ITEMID_FACE_PAINT = 6120, + ITEMID_STONE = 7049, + ITEMID_FIRE_BOTTLE = 7135, + ITEMID_ACID_BOTTLE = 7136, + ITEMID_MENEATER_PLANT_BOTTLE = 7137, + ITEMID_MINI_BOTTLE = 7138, + ITEMID_COATING_BOTTLE = 7139, + ITEMID_FRAGMENT_OF_CRYSTAL = 7321, + ITEMID_SKULL_ = 7420, + ITEMID_TOKEN_OF_SIEGFRIED = 7621, + ITEMID_TRAP_ALLOY = 7940, + ITEMID_RED_POUCH_OF_SURPRISE = 12024, + ITEMID_BLOODY_DEAD_BRANCH = 12103, + ITEMID_PORING_BOX = 12109, + ITEMID_MERCENARY_RED_POTION = 12184, + ITEMID_MERCENARY_BLUE_POTION = 12185, + ITEMID_BATTLE_MANUAL = 12208, + ITEMID_BUBBLE_GUM = 12210, + ITEMID_GIANT_FLY_WING = 12212, + ITEMID_NEURALIZER = 12213, + ITEMID_M_CENTER_POTION = 12241, + ITEMID_M_AWAKENING_POTION = 12242, + ITEMID_M_BERSERK_POTION = 12243, + ITEMID_COMP_BATTLE_MANUAL = 12263, + ITEMID_COMP_BUBBLE_GUM = 12264, + ITEMID_LOVE_ANGEL = 12287, + ITEMID_SQUIRREL = 12288, + ITEMID_GOGO = 12289, + ITEMID_PICTURE_DIARY = 12304, + ITEMID_MINI_HEART = 12305, + ITEMID_NEWCOMER = 12306, + ITEMID_KID = 12307, + ITEMID_MAGIC_CASTLE = 12308, + ITEMID_BULGING_HEAD = 12309, + ITEMID_THICK_MANUAL50 = 12312, + ITEMID_ANCILLA = 12333, + ITEMID_REPAIR_A = 12392, + ITEMID_REPAIR_B = 12393, + ITEMID_REPAIR_C = 12394, + ITEMID_BLACK_THING = 12435, + ITEMID_REINS_OF_MOUNT = 12622, + ITEMID_NOBLE_NAMEPLATE = 12705, + ITEMID_DUN_TELE_SCROLL1 = 14527, + ITEMID_BATTLE_MANUAL25 = 14532, + ITEMIDBATTLE_MANUAL100 = 14533, + ITEMID_BATTLE_MANUAL_X3 = 14545, + ITEMID_DUN_TELE_SCROLL2 = 14581, + ITEMID_WOB_RUNE = 14582, + ITEMID_WOB_SCHWALTZ = 14583, + ITEMID_WOB_RACHEL = 14584, + ITEMID_WOB_LOCAL = 14585, + ITEMID_SIEGE_TELEPORT_SCROLL = 14591, + ITEMID_JOB_MANUAL50 = 14592, +}; + +enum cards_item_list { + ITEMID_GHOSTRING_CARD = 4047, + ITEMID_PHREEONI_CARD = 4121, + ITEMID_MISTRESS_CARD = 4132, + ITEMID_ORC_LOAD_CARD = 4135, + ITEMID_ORC_HERO_CARD = 4143, + ITEMID_TAO_GUNKA_CARD = 4302, }; /** - * Rune Knight + * Mechanic **/ +enum mechanic_item_list { + ITEMID_ACCELERATOR = 2800, + ITEMID_HOVERING_BOOSTER, // 2801 + ITEMID_SUICIDAL_DEVICE, // 2802 + ITEMID_SHAPE_SHIFTER, // 2803 + ITEMID_COOLING_DEVICE, // 2804 + ITEMID_MAGNETIC_FIELD_GENERATOR, // 2805 + ITEMID_BARRIER_BUILDER, // 2806 + ITEMID_REPAIR_KIT, // 2807 + ITEMID_CAMOUFLAGE_GENERATOR, // 2808 + ITEMID_HIGH_QUALITY_COOLER, // 2809 + ITEMID_SPECIAL_COOLER, // 2810 + ITEMID_MONKEY_SPANNER = 6186, +}; -enum { - ITEMID_NAUTHIZ = 12725, - ITEMID_RAIDO, - ITEMID_BERKANA, - ITEMID_ISA, - ITEMID_OTHILA, - ITEMID_URUZ, - ITEMID_THURISAZ, - ITEMID_WYRD, - ITEMID_HAGALAZ, -} rune_list; +/** + * Spell Books + */ +enum spell_book_item_list { + ITEMID_MAGIC_BOOK_FB = 6189, + ITEMID_MAGIC_BOOK_CB, // 6190 + ITEMID_MAGIC_BOOK_LB, // 6191 + ITEMID_MAGIC_BOOK_SG, // 6192 + ITEMID_MAGIC_BOOK_LOV, // 6193 + ITEMID_MAGIC_BOOK_MS, // 6194 + ITEMID_MAGIC_BOOK_CM, // 6195 + ITEMID_MAGIC_BOOK_TV, // 6196 + ITEMID_MAGIC_BOOK_TS, // 6197 + ITEMID_MAGIC_BOOK_JT, // 6198 + ITEMID_MAGIC_BOOK_WB, // 6199 + ITEMID_MAGIC_BOOK_HD, // 6200 + ITEMID_MAGIC_BOOK_ES, // 6201 + ITEMID_MAGIC_BOOK_ES_, // 6202 + ITEMID_MAGIC_BOOK_CL, // 6203 + ITEMID_MAGIC_BOOK_CR, // 6204 + ITEMID_MAGIC_BOOK_DL, // 6205 +}; /** - * Mechanic + * Mercenary Scrolls + */ +enum mercenary_scroll_item_list { + ITEMID_BOW_MERCENARY_SCROLL1 = 12153, + ITEMID_BOW_MERCENARY_SCROLL2, // 12154 + ITEMID_BOW_MERCENARY_SCROLL3, // 12155 + ITEMID_BOW_MERCENARY_SCROLL4, // 12156 + ITEMID_BOW_MERCENARY_SCROLL5, // 12157 + ITEMID_BOW_MERCENARY_SCROLL6, // 12158 + ITEMID_BOW_MERCENARY_SCROLL7, // 12159 + ITEMID_BOW_MERCENARY_SCROLL8, // 12160 + ITEMID_BOW_MERCENARY_SCROLL9, // 12161 + ITEMID_BOW_MERCENARY_SCROLL10, // 12162 + ITEMID_SWORDMERCENARY_SCROLL1, // 12163 + ITEMID_SWORDMERCENARY_SCROLL2, // 12164 + ITEMID_SWORDMERCENARY_SCROLL3, // 12165 + ITEMID_SWORDMERCENARY_SCROLL4, // 12166 + ITEMID_SWORDMERCENARY_SCROLL5, // 12167 + ITEMID_SWORDMERCENARY_SCROLL6, // 12168 + ITEMID_SWORDMERCENARY_SCROLL7, // 12169 + ITEMID_SWORDMERCENARY_SCROLL8, // 12170 + ITEMID_SWORDMERCENARY_SCROLL9, // 12171 + ITEMID_SWORDMERCENARY_SCROLL10, // 12172 + ITEMID_SPEARMERCENARY_SCROLL1, // 12173 + ITEMID_SPEARMERCENARY_SCROLL2, // 12174 + ITEMID_SPEARMERCENARY_SCROLL3, // 12175 + ITEMID_SPEARMERCENARY_SCROLL4, // 12176 + ITEMID_SPEARMERCENARY_SCROLL5, // 12177 + ITEMID_SPEARMERCENARY_SCROLL6, // 12178 + ITEMID_SPEARMERCENARY_SCROLL7, // 12179 + ITEMID_SPEARMERCENARY_SCROLL8, // 12180 + ITEMID_SPEARMERCENARY_SCROLL9, // 12181 + ITEMID_SPEARMERCENARY_SCROLL10, // 12182 +}; + +/** + * Cash Food + */ +enum cash_food_item_list { + ITEMID_STR_DISH10_ = 12202, + ITEMID_AGI_DISH10_, // 12203 + ITEMID_INT_DISH10_, // 12204 + ITEMID_DEX_DISH10_, // 12205 + ITEMID_LUK_DISH10_, // 12206 + ITEMID_VIT_DISH10_, // 12207 +}; + +/** + * GC Poison + */ +enum poison_item_list { + ITEMID_POISON_PARALYSIS = 12717, + ITEMID_POISON_LEECH, // 12718 + ITEMID_POISON_OBLIVION, // 12719 + ITEMID_POISON_CONTAMINATION, // 12720 + ITEMID_POISON_NUMB, // 12721 + ITEMID_POISON_FEVER, // 12722 + ITEMID_POISON_LAUGHING, // 12723 + ITEMID_POISON_FATIGUE, // 12724 +}; + + +/** + * Rune Knight **/ -enum { - ITEMID_ACCELERATOR = 2800, - ITEMID_HOVERING_BOOSTER, - ITEMID_SUICIDAL_DEVICE, - ITEMID_SHAPE_SHIFTER, - ITEMID_COOLING_DEVICE, - ITEMID_MAGNETIC_FIELD_GENERATOR, - ITEMID_BARRIER_BUILDER, - ITEMID_REPAIR_KIT, - ITEMID_CAMOUFLAGE_GENERATOR, - ITEMID_HIGH_QUALITY_COOLER, - ITEMID_SPECIAL_COOLER, - ITEMID_MONKEY_SPANNER = 6186, -} mecha_item_list; - -enum { - NOUSE_SITTING = 0x01, -} item_nouse_list; - -//The only item group required by the code to be known. See const.txt for the full list. -#define IG_FINDINGORE 6 -#define IG_POTION 37 -//The max. item group count (increase this when needed). -#define MAX_ITEMGROUP 63 +enum rune_item_list { + ITEMID_NAUTHIZ = 12725, + ITEMID_RAIDO, // 12726 + ITEMID_BERKANA, // 12727 + ITEMID_ISA, // 12728 + ITEMID_OTHILA, // 12729 + ITEMID_URUZ, // 12730 + ITEMID_THURISAZ, // 12731 + ITEMID_WYRD, // 12732 + ITEMID_HAGALAZ, // 12733 + ITEMID_LUX_ANIMA = 22540, +}; -#define CARD0_FORGE 0x00FF -#define CARD0_CREATE 0x00FE -#define CARD0_PET ((short)0xFF00) +/** + * Geneticist + */ +enum geneticist_item_list { + /// Pharmacy / Cooking + ITEMID_SEED_OF_HORNY_PLANT = 6210, + ITEMID_BLOODSUCK_PLANT_SEED, // 6211 + ITEMID_BOMB_MUSHROOM_SPORE, // 6212 + ITEMID_HP_INCREASE_POTIONS = 12422, + ITEMID_HP_INCREASE_POTIONM, // 12423 + ITEMID_HP_INCREASE_POTIONL, // 12424 + ITEMID_SP_INCREASE_POTIONS, // 12425 + ITEMID_SP_INCREASE_POTIONM, // 12426 + ITEMID_SP_INCREASE_POTIONL, // 12427 + ITEMID_ENRICH_WHITE_POTIONZ, // 12428 + ITEMID_SAVAGE_BBQ, // 12429 + ITEMID_WUG_BLOOD_COCKTAIL, // 12430 + ITEMID_MINOR_BRISKET, // 12431 + ITEMID_SIROMA_ICETEA, // 12432 + ITEMID_DROCERA_HERB_STEW, // 12433 + ITEMID_PETTI_TAIL_NOODLE, // 12434 + ITEMID_VITATA500, // 12436 + ITEMID_ENRICH_CELERMINE_JUICE, // 12437 + ITEMID_CURE_FREE, // 12475 + /// Bombs + ITEMID_APPLE_BOMB = 13260, + ITEMID_COCONUT_BOMB, // 13261 + ITEMID_MELON_BOMB, // 13262 + ITEMID_PINEAPPLE_BOMB, // 13263 + ITEMID_BANANA_BOMB, // 13264 + ITEMID_BLACK_LUMP, // 13265 + ITEMID_BLACK_HARD_LUMP, // 13266 + ITEMID_VERY_HARD_LUMP, // 13267 + /// Throwables + ITEMID_MYSTERIOUS_POWDER, // 13268 + ITEMID_BOOST500_TO_THROW, // 13269 + ITEMID_FULL_SWINGK_TO_THROW, // 13270 + ITEMID_MANA_PLUS_TO_THROW, // 13271 + ITEMID_CURE_FREE_TO_THROW, // 13272 + ITEMID_STAMINA_UP_M_TO_THROW, // 13273 + ITEMID_DIGESTIVE_F_TO_THROW, // 13274 + ITEMID_HP_INC_POTS_TO_THROW, // 13275 + ITEMID_HP_INC_POTM_TO_THROW, // 13276 + ITEMID_HP_INC_POTL_TO_THROW, // 13277 + ITEMID_SP_INC_POTS_TO_THROW, // 13278 + ITEMID_SP_INC_POTM_TO_THROW, // 13279 + ITEMID_SP_INC_POTL_TO_THROW, // 13280 + ITEMID_EN_WHITE_POTZ_TO_THROW, // 13281 + ITEMID_VITATA500_TO_THROW, // 13282 + ITEMID_EN_CEL_JUICE_TO_THROW, // 13283 + ITEMID_SAVAGE_BBQ_TO_THROW, // 13284 + ITEMID_WUG_COCKTAIL_TO_THROW, // 13285 + ITEMID_M_BRISKET_TO_THROW, // 13286 + ITEMID_SIROMA_ICETEA_TO_THROW, // 13287 + ITEMID_DROCERA_STEW_TO_THROW, // 13288 + ITEMID_PETTI_NOODLE_TO_THROW, // 13289 + ITEMID_BLACK_THING_TO_THROW, // 13290 +}; -//Marks if the card0 given is "special" (non-item id used to mark pets/created items. [Skotlex] -#define itemdb_isspecial(i) (i == CARD0_FORGE || i == CARD0_CREATE || i == CARD0_PET) +// +enum e_chain_cache { + ECC_ORE, + /* */ + ECC_MAX, +}; -//Use apple for unknown items. -#define UNKNOWN_ITEM_ID 512 +enum item_class_upper { + ITEMUPPER_NONE = 0x00, + ITEMUPPER_NORMAL = 0x01, + ITEMUPPER_UPPER = 0x02, + ITEMUPPER_BABY = 0x04, + ITEMUPPER_THIRD = 0x08, + ITEMUPPER_THURDUPPER = 0x10, + ITEMUPPER_THIRDBABY = 0x20, + ITEMUPPER_ALL = 0x3f, // Sum of all the above +}; + +/** + * Item Trade restrictions + */ +enum ItemTradeRestrictions { + ITR_NONE = 0x000, ///< No restrictions + ITR_NODROP = 0x001, ///< Item can't be dropped + ITR_NOTRADE = 0x002, ///< Item can't be traded (nor vended) + ITR_PARTNEROVERRIDE = 0x004, ///< Wedded partner can override ITR_NOTRADE restriction + ITR_NOSELLTONPC = 0x008, ///< Item can't be sold to NPCs + ITR_NOCART = 0x010, ///< Item can't be placed in the cart + ITR_NOSTORAGE = 0x020, ///< Item can't be placed in the storage + ITR_NOGSTORAGE = 0x040, ///< Item can't be placed in the guild storage + ITR_NOMAIL = 0x080, ///< Item can't be attached to mail messages + ITR_NOAUCTION = 0x100, ///< Item can't be auctioned + + ITR_ALL = 0x1ff ///< Sum of all the above values +}; + +/** + * Iten No-use restrictions + */ +enum ItemNouseRestrictions { + INR_NONE = 0x0, ///< No restrictions + INR_SITTING = 0x1, ///< Item can't be used while sitting + + INR_ALL = 0x1 ///< Sum of all the above values +}; struct item_data { uint16 nameid; @@ -112,16 +389,14 @@ struct item_data { int elv; int wlv; int view_id; -#ifdef RENEWAL int matk; int elvmax;/* maximum level for this item */ -#endif int delay; //Lupus: I rearranged order of these fields due to compatibility with ITEMINFO script command // some script commands should be revised as well... unsigned int class_base[3]; //Specifies if the base can wear this item (split in 3 indexes per type: 1-1, 2-1, 2-2) - unsigned class_upper : 4; //Specifies if the upper-type can equip it (bitfield, 1: normal, 2: upper, 3: baby,4:third) + unsigned class_upper : 6; //Specifies if the upper-type can equip it (bitfield, 0x01: normal, 0x02: upper, 0x04: baby normal, 0x08: third normal, 0x10: third upper, 0x20: third baby) struct { unsigned short chance; int id; @@ -133,9 +408,10 @@ struct item_data { unsigned available : 1; unsigned no_refine : 1; // [celest] unsigned delay_consume : 1; // Signifies items that are not consumed immediately upon double-click [Skotlex] - unsigned trade_restriction : 9; //Item restrictions mask [Skotlex] + unsigned trade_restriction : 9; ///< Item trade restrictions mask (@see enum ItemTradeRestrictions) unsigned autoequip: 1; unsigned buyingstore : 1; + unsigned bindonequip : 1; } flag; struct {// item stacking limitation unsigned short amount; @@ -144,112 +420,197 @@ struct item_data { unsigned int storage:1; unsigned int guildstorage:1; } stack; - struct {// used by item_nouse.txt - unsigned int flag; + struct { + unsigned int flag; ///< Item nouse restriction mask (@see enum ItemNouseRestrictions) unsigned short override; } item_usage; short gm_lv_trade_override; //GM-level to override trade_restriction /* bugreport:309 */ struct item_combo **combos; unsigned char combos_count; -}; - -struct item_group { - int nameid[MAX_RANDITEM]; - int qty; //Counts amount of items in the group. + /* TODO add a pointer to some sort of (struct extra) and gather all the not-common vals into it to save memory */ + struct item_group *group; + struct item_package *package; }; struct item_combo { struct script_code *script; - unsigned short *nameid;/* nameid array */ + unsigned short nameid[MAX_ITEMS_PER_COMBO];/* nameid array */ unsigned char count; unsigned short id;/* id of this combo */ - bool isRef;/* whether this struct is a reference or the master */ -}; - -struct item_group itemgroup_db[MAX_ITEMGROUP]; - -struct item_data* itemdb_searchname(const char *name); -int itemdb_searchname_array(struct item_data** data, int size, const char *str); -struct item_data* itemdb_load(int nameid); -struct item_data* itemdb_search(int nameid); -struct item_data* itemdb_exists(int nameid); -#define itemdb_name(n) itemdb_search(n)->name -#define itemdb_jname(n) itemdb_search(n)->jname -#define itemdb_type(n) itemdb_search(n)->type -#define itemdb_atk(n) itemdb_search(n)->atk -#define itemdb_def(n) itemdb_search(n)->def -#define itemdb_look(n) itemdb_search(n)->look -#define itemdb_weight(n) itemdb_search(n)->weight -#define itemdb_equip(n) itemdb_search(n)->equip -#define itemdb_usescript(n) itemdb_search(n)->script -#define itemdb_equipscript(n) itemdb_search(n)->script -#define itemdb_wlv(n) itemdb_search(n)->wlv -#define itemdb_range(n) itemdb_search(n)->range -#define itemdb_slot(n) itemdb_search(n)->slot -#define itemdb_available(n) (itemdb_search(n)->flag.available) -#define itemdb_viewid(n) (itemdb_search(n)->view_id) -#define itemdb_autoequip(n) (itemdb_search(n)->flag.autoequip) -#define itemdb_is_rune(n) (n >= ITEMID_NAUTHIZ && n <= ITEMID_HAGALAZ) -#define itemdb_is_element(n) (n >= 990 && n <= 993) -#define itemdb_is_spellbook(n) (n >= 6188 && n <= 6205) -#define itemdb_is_poison(n) (n >= 12717 && n <= 12724) -#define itemid_isgemstone(id) ( (id) >= ITEMID_YELLOW_GEMSTONE && (id) <= ITEMID_BLUE_GEMSTONE ) -#define itemdb_iscashfood(id) ( (id) >= 12202 && (id) <= 12207 ) -#define itemdb_is_GNbomb(n) (n >= 13260 && n <= 13267) -#define itemdb_is_GNthrowable(n) (n >= 13268 && n <= 13290) -const char* itemdb_typename(int type); - -int itemdb_group_bonus(struct map_session_data* sd, int itemid); -int itemdb_searchrandomid(int flags); - -#define itemdb_value_buy(n) itemdb_search(n)->value_buy -#define itemdb_value_sell(n) itemdb_search(n)->value_sell -#define itemdb_canrefine(n) (!itemdb_search(n)->flag.no_refine) +}; + +struct item_group { + unsigned short id; + unsigned short *nameid; + unsigned short qty; +}; + +struct item_chain_entry { + unsigned short id; + unsigned short rate; + struct item_chain_entry *next; +}; + +struct item_chain { + struct item_chain_entry *items; + unsigned short qty; +}; + +struct item_package_rand_entry { + unsigned short id; + unsigned short qty; + unsigned short rate; + unsigned short hours; + unsigned int announce : 1; + unsigned int named : 1; + struct item_package_rand_entry *next; +}; + +struct item_package_must_entry { + unsigned short id; + unsigned short qty; + unsigned short hours; + unsigned int announce : 1; + unsigned int named : 1; +}; + +struct item_package_rand_group { + struct item_package_rand_entry *random_list; + unsigned short random_qty; +}; + +struct item_package { + unsigned short id; + struct item_package_rand_group *random_groups; + struct item_package_must_entry *must_items; + unsigned short random_qty; + unsigned short must_qty; +}; + +#define itemdb_name(n) (itemdb->search(n)->name) +#define itemdb_jname(n) (itemdb->search(n)->jname) +#define itemdb_type(n) (itemdb->search(n)->type) +#define itemdb_atk(n) (itemdb->search(n)->atk) +#define itemdb_def(n) (itemdb->search(n)->def) +#define itemdb_look(n) (itemdb->search(n)->look) +#define itemdb_weight(n) (itemdb->search(n)->weight) +#define itemdb_equip(n) (itemdb->search(n)->equip) +#define itemdb_usescript(n) (itemdb->search(n)->script) +#define itemdb_equipscript(n) (itemdb->search(n)->script) +#define itemdb_wlv(n) (itemdb->search(n)->wlv) +#define itemdb_range(n) (itemdb->search(n)->range) +#define itemdb_slot(n) (itemdb->search(n)->slot) +#define itemdb_available(n) (itemdb->search(n)->flag.available) +#define itemdb_viewid(n) (itemdb->search(n)->view_id) +#define itemdb_autoequip(n) (itemdb->search(n)->flag.autoequip) +#define itemdb_value_buy(n) (itemdb->search(n)->value_buy) +#define itemdb_value_sell(n) (itemdb->search(n)->value_sell) +#define itemdb_canrefine(n) (!itemdb->search(n)->flag.no_refine) + +#define itemdb_is_rune(n) (((n) >= ITEMID_NAUTHIZ && (n) <= ITEMID_HAGALAZ) || (n) == ITEMID_LUX_ANIMA) +#define itemdb_is_element(n) ((n) >= ITEMID_BOODY_RED && (n) <= ITEMID_YELLOW_LIVE) +#define itemdb_is_spellbook(n) ((n) >= ITEMID_MAGIC_BOOK_FB && (n) <= ITEMID_MAGIC_BOOK_DL) +#define itemdb_is_poison(n) ((n) >= ITEMID_POISON_PARALYSIS && (n) <= ITEMID_POISON_FATIGUE) +#define itemid_isgemstone(n) ((n) >= ITEMID_YELLOW_GEMSTONE && (n) <= ITEMID_BLUE_GEMSTONE) +#define itemdb_iscashfood(n) ((n) >= ITEMID_STR_DISH10_ && (n) <= ITEMID_VIT_DISH10_) +#define itemdb_is_GNbomb(n) ((n) >= ITEMID_APPLE_BOMB && (n) <= ITEMID_VERY_HARD_LUMP) +#define itemdb_is_GNthrowable(n) ((n) >= ITEMID_MYSTERIOUS_POWDER && (n) <= ITEMID_BLACK_THING_TO_THROW) + //Item trade restrictions [Skotlex] -int itemdb_isdropable_sub(struct item_data *, int, int); -int itemdb_cantrade_sub(struct item_data*, int, int); -int itemdb_canpartnertrade_sub(struct item_data*, int, int); -int itemdb_cansell_sub(struct item_data*,int, int); -int itemdb_cancartstore_sub(struct item_data*, int, int); -int itemdb_canstore_sub(struct item_data*, int, int); -int itemdb_canguildstore_sub(struct item_data*, int, int); -int itemdb_canmail_sub(struct item_data*, int, int); -int itemdb_canauction_sub(struct item_data*, int, int); -int itemdb_isrestricted(struct item* item, int gmlv, int gmlv2, int (*func)(struct item_data*, int, int)); -#define itemdb_isdropable(item, gmlv) itemdb_isrestricted(item, gmlv, 0, itemdb_isdropable_sub) -#define itemdb_cantrade(item, gmlv, gmlv2) itemdb_isrestricted(item, gmlv, gmlv2, itemdb_cantrade_sub) -#define itemdb_canpartnertrade(item, gmlv, gmlv2) itemdb_isrestricted(item, gmlv, gmlv2, itemdb_canpartnertrade_sub) -#define itemdb_cansell(item, gmlv) itemdb_isrestricted(item, gmlv, 0, itemdb_cansell_sub) -#define itemdb_cancartstore(item, gmlv) itemdb_isrestricted(item, gmlv, 0, itemdb_cancartstore_sub) -#define itemdb_canstore(item, gmlv) itemdb_isrestricted(item, gmlv, 0, itemdb_canstore_sub) -#define itemdb_canguildstore(item, gmlv) itemdb_isrestricted(item , gmlv, 0, itemdb_canguildstore_sub) -#define itemdb_canmail(item, gmlv) itemdb_isrestricted(item , gmlv, 0, itemdb_canmail_sub) -#define itemdb_canauction(item, gmlv) itemdb_isrestricted(item , gmlv, 0, itemdb_canauction_sub) - -int itemdb_isequip(int); -int itemdb_isequip2(struct item_data *); -int itemdb_isidentified(int); -int itemdb_isidentified2(struct item_data *data); -int itemdb_isstackable(int); -int itemdb_isstackable2(struct item_data *); -uint64 itemdb_unique_id(int8 flag, int64 value); // Unique Item ID - -void itemdb_reload(void); - -void do_final_itemdb(void); -int do_init_itemdb(void); - -/* incomplete */ +#define itemdb_isdropable(item, gmlv) (itemdb->isrestricted((item), (gmlv), 0, itemdb->isdropable_sub)) +#define itemdb_cantrade(item, gmlv, gmlv2) (itemdb->isrestricted((item), (gmlv), (gmlv2), itemdb->cantrade_sub)) +#define itemdb_canpartnertrade(item, gmlv, gmlv2) (itemdb->isrestricted((item), (gmlv), (gmlv2), itemdb->canpartnertrade_sub)) +#define itemdb_cansell(item, gmlv) (itemdb->isrestricted((item), (gmlv), 0, itemdb->cansell_sub)) +#define itemdb_cancartstore(item, gmlv) (itemdb->isrestricted((item), (gmlv), 0, itemdb->cancartstore_sub)) +#define itemdb_canstore(item, gmlv) (itemdb->isrestricted((item), (gmlv), 0, itemdb->canstore_sub)) +#define itemdb_canguildstore(item, gmlv) (itemdb->isrestricted((item), (gmlv), 0, itemdb->canguildstore_sub)) +#define itemdb_canmail(item, gmlv) (itemdb->isrestricted((item), (gmlv), 0, itemdb->canmail_sub)) +#define itemdb_canauction(item, gmlv) (itemdb->isrestricted((item), (gmlv), 0, itemdb->canauction_sub)) + struct itemdb_interface { + void (*init) (bool minimal); + void (*final) (void); void (*reload) (void); + void (*name_constants) (void); + /* */ + struct item_group *groups; + unsigned short group_count; + /* */ + struct item_chain *chains; + unsigned short chain_count; + unsigned short chain_cache[ECC_MAX]; + /* */ + struct item_package *packages; + unsigned short package_count; + /* list of item combos loaded */ + struct item_combo **combos; + unsigned short combo_count; /* */ - int (*parse_dbrow) (char** str, const char* source, int line, int scriptopt); + DBMap *names; + /* */ + struct item_data *array[MAX_ITEMDB]; + DBMap *other;// int nameid -> struct item_data* + struct item_data dummy; //This is the default dummy item used for non-existant items. [Skotlex] + /* */ + void (*read_groups) (void); + void (*read_chains) (void); + void (*read_packages) (void); + /* */ + void (*write_cached_packages) (const char *config_filename); + bool (*read_cached_packages) (const char *config_filename); + /* */ + struct item_data* (*name2id) (const char *str); + struct item_data* (*search_name) (const char *name); + int (*search_name_array) (struct item_data** data, int size, const char *str, int flag); + struct item_data* (*load)(int nameid); + struct item_data* (*search)(int nameid); struct item_data* (*exists) (int nameid); -} itemdb_s; + bool (*in_group) (struct item_group *group, int nameid); + int (*group_item) (struct item_group *group); + int (*chain_item) (unsigned short chain_id, int *rate); + void (*package_item) (struct map_session_data *sd, struct item_package *package); + int (*searchname_sub) (DBKey key, DBData *data, va_list ap); + int (*searchname_array_sub) (DBKey key, DBData data, va_list ap); + int (*searchrandomid) (struct item_group *group); + const char* (*typename) (int type); + void (*jobid2mapid) (unsigned int *bclass, unsigned int jobmask); + void (*create_dummy_data) (void); + struct item_data* (*create_item_data) (int nameid); + int (*isequip) (int nameid); + int (*isequip2) (struct item_data *data); + int (*isstackable) (int nameid); + int (*isstackable2) (struct item_data *data); + int (*isdropable_sub) (struct item_data *item, int gmlv, int unused); + int (*cantrade_sub) (struct item_data *item, int gmlv, int gmlv2); + int (*canpartnertrade_sub) (struct item_data *item, int gmlv, int gmlv2); + int (*cansell_sub) (struct item_data *item, int gmlv, int unused); + int (*cancartstore_sub) (struct item_data *item, int gmlv, int unused); + int (*canstore_sub) (struct item_data *item, int gmlv, int unused); + int (*canguildstore_sub) (struct item_data *item, int gmlv, int unused); + int (*canmail_sub) (struct item_data *item, int gmlv, int unused); + int (*canauction_sub) (struct item_data *item, int gmlv, int unused); + int (*isrestricted) (struct item *item, int gmlv, int gmlv2, int(*func)(struct item_data *, int, int)); + int (*isidentified) (int nameid); + int (*isidentified2) (struct item_data *data); + int (*combo_split_atoi) (char *str, int *val); + void (*read_combos) (); + int (*gendercheck) (struct item_data *id); + int (*validate_entry) (struct item_data *entry, int n, const char *source); + int (*readdb_sql_sub) (Sql *handle, int n, const char *source); + int (*readdb_libconfig_sub) (config_setting_t *it, int n, const char *source); + int (*readdb_libconfig) (const char *filename); + int (*readdb_sql) (const char *tablename); + uint64 (*unique_id) (struct map_session_data *sd); + void (*read) (bool minimal); + void (*destroy_item_data) (struct item_data *self, int free_self); + int (*final_sub) (DBKey key, DBData *data, va_list ap); + void (*clear) (bool total); + struct item_combo * (*id2combo) (unsigned short id); +}; struct itemdb_interface *itemdb; void itemdb_defaults(void); -#endif /* _ITEMDB_H_ */ +#endif /* MAP_ITEMDB_H */ diff --git a/src/map/log.c b/src/map/log.c index dfb4c4a61..b5179e16b 100644 --- a/src/map/log.c +++ b/src/map/log.c @@ -2,53 +2,29 @@ // See the LICENSE file // Portions Copyright (c) Athena Dev Teams -#include "../common/cbasetypes.h" -#include "../common/sql.h" // SQL_INNODB -#include "../common/strlib.h" -#include "../common/nullpo.h" -#include "../common/showmsg.h" -#include "battle.h" -#include "itemdb.h" +#define HERCULES_CORE + #include "log.h" -#include "map.h" -#include "mob.h" -#include "pc.h" #include <stdio.h> #include <stdlib.h> #include <string.h> +#include "battle.h" +#include "itemdb.h" +#include "map.h" +#include "mob.h" +#include "pc.h" +#include "../common/cbasetypes.h" +#include "../common/nullpo.h" +#include "../common/showmsg.h" +#include "../common/sql.h" // SQL_INNODB +#include "../common/strlib.h" -/// filters for item logging -typedef enum e_log_filter { - LOG_FILTER_NONE = 0x000, - LOG_FILTER_ALL = 0x001, - // bits - LOG_FILTER_HEALING = 0x002, // Healing items (0) - LOG_FILTER_ETC_AMMO = 0x004, // Etc Items(3) + Arrows (10) - LOG_FILTER_USABLE = 0x008, // Usable Items(2) + Scrolls, Lures(11) + Usable Cash Items(18) - LOG_FILTER_WEAPON = 0x010, // Weapons(4) - LOG_FILTER_ARMOR = 0x020, // Shields, Armors, Headgears, Accessories, Garments and Shoes(5) - LOG_FILTER_CARD = 0x040, // Cards(6) - LOG_FILTER_PETITEM = 0x080, // Pet Accessories(8) + Eggs(7) (well, monsters don't drop 'em but we'll use the same system for ALL logs) - LOG_FILTER_PRICE = 0x100, // Log expensive items ( >= price_log ) - LOG_FILTER_AMOUNT = 0x200, // Log large amount of items ( >= amount_log ) - LOG_FILTER_REFINE = 0x400, // Log refined items ( refine >= refine_log ) [not implemented] - LOG_FILTER_CHANCE = 0x800, // Log rare items and Emperium ( drop chance <= rare_log ) -} -e_log_filter; - -#ifdef SQL_INNODB -// database is using an InnoDB engine so do not use DELAYED -#define LOG_QUERY "INSERT" -#else -// database is using a MyISAM engine so use DELAYED -#define LOG_QUERY "INSERT DELAYED" -#endif - +struct log_interface log_s; /// obtain log type character for item/zeny logs -static char log_picktype2char(e_log_pick_type type) { +char log_picktype2char(e_log_pick_type type) { switch( type ) { case LOG_TYPE_TRADE: return 'T'; // (T)rade case LOG_TYPE_VENDING: return 'V'; // (V)ending @@ -67,6 +43,7 @@ static char log_picktype2char(e_log_pick_type type) { case LOG_TYPE_AUCTION: return 'I'; // Auct(I)on case LOG_TYPE_BUYING_STORE: return 'B'; // (B)uying Store case LOG_TYPE_LOOT: return 'L'; // (L)oot (consumed monster pick/drop) + case LOG_TYPE_BANK: return 'K'; // Ban(K) Transactions case LOG_TYPE_OTHER: return 'X'; // Other } @@ -77,7 +54,7 @@ static char log_picktype2char(e_log_pick_type type) { /// obtain log type character for chat logs -static char log_chattype2char(e_log_chat_type type) { +char log_chattype2char(e_log_chat_type type) { switch( type ) { case LOG_CHAT_GLOBAL: return 'O'; // Gl(O)bal case LOG_CHAT_WHISPER: return 'W'; // (W)hisper @@ -93,7 +70,7 @@ static char log_chattype2char(e_log_chat_type type) { /// check if this item should be logged according the settings -static bool should_log_item(int nameid, int amount, int refine, struct item_data *id) { +bool should_log_item(int nameid, int amount, int refine, struct item_data *id) { int filter = logs->config.filter; if( id == NULL ) @@ -118,7 +95,7 @@ static bool should_log_item(int nameid, int amount, int refine, struct item_data } void log_branch_sub_sql(struct map_session_data* sd) { SqlStmt* stmt; - stmt = SQL->StmtMalloc(logmysql_handle); + stmt = SQL->StmtMalloc(logs->mysql_handle); if( SQL_SUCCESS != SQL->StmtPrepare(stmt, LOG_QUERY " INTO `%s` (`branch_date`, `account_id`, `char_id`, `char_name`, `map`) VALUES (NOW(), '%d', '%d', ?, '%s')", logs->config.log_branch, sd->status.account_id, sd->status.char_id, mapindex_id2name(sd->mapindex) ) || SQL_SUCCESS != SQL->StmtBindParam(stmt, 0, SQLDT_STRING, sd->status.name, strnlen(sd->status.name, NAME_LENGTH)) || SQL_SUCCESS != SQL->StmtExecute(stmt) ) @@ -152,10 +129,13 @@ void log_branch(struct map_session_data* sd) { logs->branch_sub(sd); } void log_pick_sub_sql(int id, int16 m, e_log_pick_type type, int amount, struct item* itm, struct item_data *data) { - if( SQL_ERROR == SQL->Query(logmysql_handle, LOG_QUERY " INTO `%s` (`time`, `char_id`, `type`, `nameid`, `amount`, `refine`, `card0`, `card1`, `card2`, `card3`, `map`, `unique_id`) VALUES (NOW(), '%d', '%c', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%s', '%"PRIu64"')", - logs->config.log_pick, id, log_picktype2char(type), itm->nameid, amount, itm->refine, itm->card[0], itm->card[1], itm->card[2], itm->card[3], map[m].name?map[m].name:"", itm->unique_id) ) - { - Sql_ShowDebug(logmysql_handle); + if( SQL_ERROR == SQL->Query(logs->mysql_handle, + LOG_QUERY " INTO `%s` (`time`, `char_id`, `type`, `nameid`, `amount`, `refine`, `card0`, `card1`, `card2`, `card3`, `map`, `unique_id`) " + "VALUES (NOW(), '%d', '%c', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%s', '%"PRIu64"')", + logs->config.log_pick, id, logs->picktype2char(type), itm->nameid, amount, itm->refine, itm->card[0], itm->card[1], itm->card[2], itm->card[3], + map->list[m].name?map->list[m].name:"", itm->unique_id) + ) { + Sql_ShowDebug(logs->mysql_handle); return; } } @@ -168,7 +148,9 @@ void log_pick_sub_txt(int id, int16 m, e_log_pick_type type, int amount, struct return; time(&curtime); strftime(timestring, sizeof(timestring), "%m/%d/%Y %H:%M:%S", localtime(&curtime)); - fprintf(logfp,"%s - %d\t%c\t%d,%d,%d,%d,%d,%d,%d,%s,'%"PRIu64"'\n", timestring, id, log_picktype2char(type), itm->nameid, amount, itm->refine, itm->card[0], itm->card[1], itm->card[2], itm->card[3], map[m].name?map[m].name:"", itm->unique_id); + fprintf(logfp,"%s - %d\t%c\t%d,%d,%d,%d,%d,%d,%d,%s,'%"PRIu64"'\n", + timestring, id, logs->picktype2char(type), itm->nameid, amount, itm->refine, itm->card[0], itm->card[1], itm->card[2], itm->card[3], + map->list[m].name?map->list[m].name:"", itm->unique_id); fclose(logfp); } /// logs item transactions (generic) @@ -178,7 +160,7 @@ void log_pick(int id, int16 m, e_log_pick_type type, int amount, struct item* it return; } - if( !should_log_item(itm->nameid, amount, itm->refine, data) ) + if( !logs->should_log_item(itm->nameid, amount, itm->refine, data) ) return; //we skip logging this item set - it doesn't meet our logging conditions [Lupus] logs->pick_sub(id,m,type,amount,itm,data); @@ -187,20 +169,20 @@ void log_pick(int id, int16 m, e_log_pick_type type, int amount, struct item* it /// logs item transactions (players) void log_pick_pc(struct map_session_data* sd, e_log_pick_type type, int amount, struct item* itm, struct item_data *data) { nullpo_retv(sd); - log_pick(sd->status.char_id, sd->bl.m, type, amount, itm, data ? data : itemdb_exists(itm->nameid)); + log_pick(sd->status.char_id, sd->bl.m, type, amount, itm, data ? data : itemdb->exists(itm->nameid)); } /// logs item transactions (monsters) void log_pick_mob(struct mob_data* md, e_log_pick_type type, int amount, struct item* itm, struct item_data *data) { nullpo_retv(md); - log_pick(md->class_, md->bl.m, type, amount, itm, data ? data : itemdb_exists(itm->nameid)); + log_pick(md->class_, md->bl.m, type, amount, itm, data ? data : itemdb->exists(itm->nameid)); } void log_zeny_sub_sql(struct map_session_data* sd, e_log_pick_type type, struct map_session_data* src_sd, int amount) { - if( SQL_ERROR == SQL->Query(logmysql_handle, LOG_QUERY " INTO `%s` (`time`, `char_id`, `src_id`, `type`, `amount`, `map`) VALUES (NOW(), '%d', '%d', '%c', '%d', '%s')", - logs->config.log_zeny, sd->status.char_id, src_sd->status.char_id, log_picktype2char(type), amount, mapindex_id2name(sd->mapindex)) ) + if( SQL_ERROR == SQL->Query(logs->mysql_handle, LOG_QUERY " INTO `%s` (`time`, `char_id`, `src_id`, `type`, `amount`, `map`) VALUES (NOW(), '%d', '%d', '%c', '%d', '%s')", + logs->config.log_zeny, sd->status.char_id, src_sd->status.char_id, logs->picktype2char(type), amount, mapindex_id2name(sd->mapindex)) ) { - Sql_ShowDebug(logmysql_handle); + Sql_ShowDebug(logs->mysql_handle); return; } } @@ -227,10 +209,10 @@ void log_zeny(struct map_session_data* sd, e_log_pick_type type, struct map_sess logs->zeny_sub(sd,type,src_sd,amount); } void log_mvpdrop_sub_sql(struct map_session_data* sd, int monster_id, int* log_mvp) { - if( SQL_ERROR == SQL->Query(logmysql_handle, LOG_QUERY " INTO `%s` (`mvp_date`, `kill_char_id`, `monster_id`, `prize`, `mvpexp`, `map`) VALUES (NOW(), '%d', '%d', '%d', '%d', '%s') ", + if( SQL_ERROR == SQL->Query(logs->mysql_handle, LOG_QUERY " INTO `%s` (`mvp_date`, `kill_char_id`, `monster_id`, `prize`, `mvpexp`, `map`) VALUES (NOW(), '%d', '%d', '%d', '%d', '%s') ", logs->config.log_mvpdrop, sd->status.char_id, monster_id, log_mvp[0], log_mvp[1], mapindex_id2name(sd->mapindex)) ) { - Sql_ShowDebug(logmysql_handle); + Sql_ShowDebug(logs->mysql_handle); return; } } @@ -260,7 +242,7 @@ void log_mvpdrop(struct map_session_data* sd, int monster_id, int* log_mvp) void log_atcommand_sub_sql(struct map_session_data* sd, const char* message) { SqlStmt* stmt; - stmt = SQL->StmtMalloc(logmysql_handle); + stmt = SQL->StmtMalloc(logs->mysql_handle); if( SQL_SUCCESS != SQL->StmtPrepare(stmt, LOG_QUERY " INTO `%s` (`atcommand_date`, `account_id`, `char_id`, `char_name`, `map`, `command`) VALUES (NOW(), '%d', '%d', ?, '%s', ?)", logs->config.log_gm, sd->status.account_id, sd->status.char_id, mapindex_id2name(sd->mapindex) ) || SQL_SUCCESS != SQL->StmtBindParam(stmt, 0, SQLDT_STRING, sd->status.name, strnlen(sd->status.name, NAME_LENGTH)) || SQL_SUCCESS != SQL->StmtBindParam(stmt, 1, SQLDT_STRING, (char*)message, safestrnlen(message, 255)) @@ -290,7 +272,7 @@ void log_atcommand(struct map_session_data* sd, const char* message) nullpo_retv(sd); if( !logs->config.commands || - !pc_should_log_commands(sd) ) + !pc->should_log_commands(sd) ) return; logs->atcommand_sub(sd,message); @@ -298,7 +280,7 @@ void log_atcommand(struct map_session_data* sd, const char* message) void log_npc_sub_sql(struct map_session_data *sd, const char *message) { SqlStmt* stmt; - stmt = SQL->StmtMalloc(logmysql_handle); + stmt = SQL->StmtMalloc(logs->mysql_handle); if( SQL_SUCCESS != SQL->StmtPrepare(stmt, LOG_QUERY " INTO `%s` (`npc_date`, `account_id`, `char_id`, `char_name`, `map`, `mes`) VALUES (NOW(), '%d', '%d', ?, '%s', ?)", logs->config.log_npc, sd->status.account_id, sd->status.char_id, mapindex_id2name(sd->mapindex) ) || SQL_SUCCESS != SQL->StmtBindParam(stmt, 0, SQLDT_STRING, sd->status.name, strnlen(sd->status.name, NAME_LENGTH)) || SQL_SUCCESS != SQL->StmtBindParam(stmt, 1, SQLDT_STRING, (char*)message, safestrnlen(message, 255)) @@ -333,22 +315,22 @@ void log_npc(struct map_session_data* sd, const char* message) logs->npc_sub(sd,message); } -void log_chat_sub_sql(e_log_chat_type type, int type_id, int src_charid, int src_accid, const char* map, int x, int y, const char* dst_charname, const char* message) { +void log_chat_sub_sql(e_log_chat_type type, int type_id, int src_charid, int src_accid, const char *mapname, int x, int y, const char* dst_charname, const char* message) { SqlStmt* stmt; - stmt = SQL->StmtMalloc(logmysql_handle); - if( SQL_SUCCESS != SQL->StmtPrepare(stmt, LOG_QUERY " INTO `%s` (`time`, `type`, `type_id`, `src_charid`, `src_accountid`, `src_map`, `src_map_x`, `src_map_y`, `dst_charname`, `message`) VALUES (NOW(), '%c', '%d', '%d', '%d', '%s', '%d', '%d', ?, ?)", logs->config.log_chat, log_chattype2char(type), type_id, src_charid, src_accid, map, x, y) - || SQL_SUCCESS != SQL->StmtBindParam(stmt, 0, SQLDT_STRING, (char*)dst_charname, safestrnlen(dst_charname, NAME_LENGTH)) - || SQL_SUCCESS != SQL->StmtBindParam(stmt, 1, SQLDT_STRING, (char*)message, safestrnlen(message, CHAT_SIZE_MAX)) - || SQL_SUCCESS != SQL->StmtExecute(stmt) ) - { + stmt = SQL->StmtMalloc(logs->mysql_handle); + if( SQL_SUCCESS != SQL->StmtPrepare(stmt, LOG_QUERY " INTO `%s` (`time`, `type`, `type_id`, `src_charid`, `src_accountid`, `src_map`, `src_map_x`, `src_map_y`, `dst_charname`, `message`) VALUES (NOW(), '%c', '%d', '%d', '%d', '%s', '%d', '%d', ?, ?)", logs->config.log_chat, logs->chattype2char(type), type_id, src_charid, src_accid, mapname, x, y) + || SQL_SUCCESS != SQL->StmtBindParam(stmt, 0, SQLDT_STRING, (char*)dst_charname, safestrnlen(dst_charname, NAME_LENGTH)) + || SQL_SUCCESS != SQL->StmtBindParam(stmt, 1, SQLDT_STRING, (char*)message, safestrnlen(message, CHAT_SIZE_MAX)) + || SQL_SUCCESS != SQL->StmtExecute(stmt) + ) { SqlStmt_ShowDebug(stmt); SQL->StmtFree(stmt); return; } SQL->StmtFree(stmt); } -void log_chat_sub_txt(e_log_chat_type type, int type_id, int src_charid, int src_accid, const char* map, int x, int y, const char* dst_charname, const char* message) { +void log_chat_sub_txt(e_log_chat_type type, int type_id, int src_charid, int src_accid, const char *mapname, int x, int y, const char* dst_charname, const char* message) { char timestring[255]; time_t curtime; FILE* logfp; @@ -357,26 +339,43 @@ void log_chat_sub_txt(e_log_chat_type type, int type_id, int src_charid, int src return; time(&curtime); strftime(timestring, sizeof(timestring), "%m/%d/%Y %H:%M:%S", localtime(&curtime)); - fprintf(logfp, "%s - %c,%d,%d,%d,%s,%d,%d,%s,%s\n", timestring, log_chattype2char(type), type_id, src_charid, src_accid, map, x, y, dst_charname, message); + fprintf(logfp, "%s - %c,%d,%d,%d,%s,%d,%d,%s,%s\n", timestring, logs->chattype2char(type), type_id, src_charid, src_accid, mapname, x, y, dst_charname, message); fclose(logfp); } /// logs chat -void log_chat(e_log_chat_type type, int type_id, int src_charid, int src_accid, const char* map, int x, int y, const char* dst_charname, const char* message) -{ - if( ( logs->config.chat&type ) == 0 ) - {// disabled +void log_chat(e_log_chat_type type, int type_id, int src_charid, int src_accid, const char *mapname, int x, int y, const char* dst_charname, const char* message) { + if( ( logs->config.chat&type ) == 0 ) { + // disabled return; } - if( logs->config.log_chat_woe_disable && ( iMap->agit_flag || iMap->agit2_flag ) ) - {// no chat logging during woe + if( logs->config.log_chat_woe_disable && ( map->agit_flag || map->agit2_flag ) ) { + // no chat logging during woe return; } - logs->chat_sub(type,type_id,src_charid,src_accid,map,x,y,dst_charname,message); + logs->chat_sub(type,type_id,src_charid,src_accid,mapname,x,y,dst_charname,message); } +void log_sql_init(void) { + // log db connection + logs->mysql_handle = SQL->Malloc(); + + ShowInfo(""CL_WHITE"[SQL]"CL_RESET": Connecting to the Log Database "CL_WHITE"%s"CL_RESET" At "CL_WHITE"%s"CL_RESET"...\n",logs->db_name,logs->db_ip); + if ( SQL_ERROR == SQL->Connect(logs->mysql_handle, logs->db_id, logs->db_pw, logs->db_ip, logs->db_port, logs->db_name) ) + exit(EXIT_FAILURE); + ShowStatus(""CL_WHITE"[SQL]"CL_RESET": Successfully '"CL_GREEN"connected"CL_RESET"' to Database '"CL_WHITE"%s"CL_RESET"'.\n", logs->db_name); + + if( strlen(map->default_codepage) > 0 ) + if ( SQL_ERROR == SQL->SetEncoding(logs->mysql_handle, map->default_codepage) ) + Sql_ShowDebug(logs->mysql_handle); +} +void log_sql_final(void) { + ShowStatus("Close Log DB Connection....\n"); + SQL->Free(logs->mysql_handle); + logs->mysql_handle = NULL; +} void log_set_defaults(void) { memset(&logs->config, 0, sizeof(logs->config)); @@ -402,11 +401,11 @@ int log_config_read(const char* cfgName) { return 1; } - while( fgets(line, sizeof(line), fp) ) { - if( line[0] == '/' && line[1] == '/' ) + while (fgets(line, sizeof(line), fp)) { + if (line[0] == '/' && line[1] == '/') continue; - if( sscanf(line, "%[^:]: %[^\r\n]", w1, w2) == 2 ) { + if (sscanf(line, "%1023[^:]: %1023[^\r\n]", w1, w2) == 2) { if( strcmpi(w1, "enable_logs") == 0 ) logs->config.enable_logs = (e_log_pick_type)config_switch(w2); else if( strcmpi(w1, "sql_logs") == 0 ) @@ -504,6 +503,15 @@ void log_config_complete(void) { void log_defaults(void) { logs = &log_s; + sprintf(logs->db_ip,"127.0.0.1"); + sprintf(logs->db_id,"ragnarok"); + sprintf(logs->db_pw,"ragnarok"); + sprintf(logs->db_name,"log"); + + logs->db_port = 3306; + logs->mysql_handle = NULL; + /* */ + logs->pick_pc = log_pick_pc; logs->pick_mob = log_pick_mob; logs->zeny = log_zeny; @@ -512,8 +520,6 @@ void log_defaults(void) { logs->atcommand = log_atcommand; logs->branch = log_branch; logs->mvpdrop = log_mvpdrop; - logs->config_read = log_config_read; - logs->config_done = log_config_complete; /* will be modified in a few seconds once loading is complete. */ logs->pick_sub = log_pick_sub_txt; @@ -524,4 +530,12 @@ void log_defaults(void) { logs->branch_sub = log_branch_sub_txt; logs->mvpdrop_sub = log_mvpdrop_sub_txt; + logs->config_read = log_config_read; + logs->config_done = log_config_complete; + logs->sql_init = log_sql_init; + logs->sql_final = log_sql_final; + + logs->picktype2char = log_picktype2char; + logs->chattype2char = log_chattype2char; + logs->should_log_item = should_log_item; } diff --git a/src/map/log.h b/src/map/log.h index 462a12ff5..6ab142f87 100644 --- a/src/map/log.h +++ b/src/map/log.h @@ -2,16 +2,34 @@ // See the LICENSE file // Portions Copyright (c) Athena Dev Teams -#ifndef _LOG_H_ -#define _LOG_H_ +#ifndef MAP_LOG_H +#define MAP_LOG_H -struct block_list; -struct map_session_data; -struct mob_data; +#include "../common/cbasetypes.h" +#include "../common/sql.h" + +/** + * Declarations + **/ struct item; struct item_data; +struct map_session_data; +struct mob_data; +/** + * Defines + **/ +#ifdef SQL_INNODB +// database is using an InnoDB engine so do not use DELAYED + #define LOG_QUERY "INSERT" +#else +// database is using a MyISAM engine so use DELAYED + #define LOG_QUERY "INSERT DELAYED" +#endif +/** + * Enumerations + **/ typedef enum e_log_chat_type { LOG_CHAT_GLOBAL = 0x01, LOG_CHAT_WHISPER = 0x02, @@ -22,7 +40,6 @@ typedef enum e_log_chat_type { LOG_CHAT_ALL = 0xFF, } e_log_chat_type; - typedef enum e_log_pick_type { LOG_TYPE_NONE = 0, LOG_TYPE_TRADE = 0x00001, @@ -42,12 +59,31 @@ typedef enum e_log_pick_type { LOG_TYPE_AUCTION = 0x04000, LOG_TYPE_BUYING_STORE = 0x08000, LOG_TYPE_OTHER = 0x10000, + LOG_TYPE_BANK = 0x20000, // combinations LOG_TYPE_LOOT = LOG_TYPE_PICKDROP_MONSTER|LOG_TYPE_CONSUME, // all LOG_TYPE_ALL = 0xFFFFF, } e_log_pick_type; +/// filters for item logging +typedef enum e_log_filter { + LOG_FILTER_NONE = 0x000, + LOG_FILTER_ALL = 0x001, + // bits + LOG_FILTER_HEALING = 0x002, // Healing items (0) + LOG_FILTER_ETC_AMMO = 0x004, // Etc Items(3) + Arrows (10) + LOG_FILTER_USABLE = 0x008, // Usable Items(2) + Scrolls, Lures(11) + Usable Cash Items(18) + LOG_FILTER_WEAPON = 0x010, // Weapons(4) + LOG_FILTER_ARMOR = 0x020, // Shields, Armors, Headgears, Accessories, Garments and Shoes(5) + LOG_FILTER_CARD = 0x040, // Cards(6) + LOG_FILTER_PETITEM = 0x080, // Pet Accessories(8) + Eggs(7) (well, monsters don't drop 'em but we'll use the same system for ALL logs) + LOG_FILTER_PRICE = 0x100, // Log expensive items ( >= price_log ) + LOG_FILTER_AMOUNT = 0x200, // Log large amount of items ( >= amount_log ) + LOG_FILTER_REFINE = 0x400, // Log refined items ( refine >= refine_log ) [not implemented] + LOG_FILTER_CHANCE = 0x800, // Log rare items and Emperium ( drop chance <= rare_log ) +} e_log_filter; + struct log_interface { struct { e_log_pick_type enable_logs; @@ -59,11 +95,18 @@ struct log_interface { char log_branch[64], log_pick[64], log_zeny[64], log_mvpdrop[64], log_gm[64], log_npc[64], log_chat[64]; } config; /* */ + char db_ip[32]; + int db_port; + char db_id[32]; + char db_pw[32]; + char db_name[32]; + Sql* mysql_handle; + /* */ void (*pick_pc) (struct map_session_data* sd, e_log_pick_type type, int amount, struct item* itm, struct item_data *data); void (*pick_mob) (struct mob_data* md, e_log_pick_type type, int amount, struct item* itm, struct item_data *data); void (*zeny) (struct map_session_data* sd, e_log_pick_type type, struct map_session_data* src_sd, int amount); void (*npc) (struct map_session_data* sd, const char *message); - void (*chat) (e_log_chat_type type, int type_id, int src_charid, int src_accid, const char* map, int x, int y, const char* dst_charname, const char* message); + void (*chat) (e_log_chat_type type, int type_id, int src_charid, int src_accid, const char *mapname, int x, int y, const char* dst_charname, const char* message); void (*atcommand) (struct map_session_data* sd, const char* message); void (*branch) (struct map_session_data* sd); void (*mvpdrop) (struct map_session_data* sd, int monster_id, int* log_mvp); @@ -71,17 +114,23 @@ struct log_interface { void (*pick_sub) (int id, int16 m, e_log_pick_type type, int amount, struct item* itm, struct item_data *data); void (*zeny_sub) (struct map_session_data* sd, e_log_pick_type type, struct map_session_data* src_sd, int amount); void (*npc_sub) (struct map_session_data* sd, const char *message); - void (*chat_sub) (e_log_chat_type type, int type_id, int src_charid, int src_accid, const char* map, int x, int y, const char* dst_charname, const char* message); + void (*chat_sub) (e_log_chat_type type, int type_id, int src_charid, int src_accid, const char *mapname, int x, int y, const char* dst_charname, const char* message); void (*atcommand_sub) (struct map_session_data* sd, const char* message); void (*branch_sub) (struct map_session_data* sd); void (*mvpdrop_sub) (struct map_session_data* sd, int monster_id, int* log_mvp); int (*config_read) (const char* cfgName); void (*config_done) (void); -} log_s; + void (*sql_init) (void); + void (*sql_final) (void); + + char (*picktype2char) (e_log_pick_type type); + char (*chattype2char) (e_log_chat_type type); + bool (*should_log_item) (int nameid, int amount, int refine, struct item_data *id); +}; struct log_interface *logs; void log_defaults(void); -#endif /* _LOG_H_ */ +#endif /* MAP_LOG_H */ diff --git a/src/map/mail.c b/src/map/mail.c index 9a8d4e521..7ba7d7470 100644 --- a/src/map/mail.c +++ b/src/map/mail.c @@ -2,18 +2,22 @@ // See the LICENSE file // Portions Copyright (c) Athena Dev Teams -#include "../common/nullpo.h" -#include "../common/showmsg.h" +#define HERCULES_CORE #include "mail.h" + +#include <time.h> +#include <string.h> + #include "atcommand.h" -#include "itemdb.h" #include "clif.h" -#include "pc.h" +#include "itemdb.h" #include "log.h" +#include "pc.h" +#include "../common/nullpo.h" +#include "../common/showmsg.h" -#include <time.h> -#include <string.h> +struct mail_interface mail_s; void mail_clear(struct map_session_data *sd) { @@ -62,7 +66,7 @@ unsigned char mail_setitem(struct map_session_data *sd, int idx, int amount) { return 1; if( idx == 0 ) { // Zeny Transfer - if( amount < 0 || !pc->can_give_items(sd) ) + if( amount < 0 || !pc_can_give_items(sd) ) return 1; if( amount > sd->status.zeny ) @@ -79,8 +83,9 @@ unsigned char mail_setitem(struct map_session_data *sd, int idx, int amount) { return 1; if( amount < 0 || amount > sd->status.inventory[idx].amount ) return 1; - if( !pc->can_give_items(sd) || sd->status.inventory[idx].expire_time || - !itemdb_canmail(&sd->status.inventory[idx],pc->get_group_level(sd)) ) + if( !pc_can_give_items(sd) || sd->status.inventory[idx].expire_time || + !itemdb_canmail(&sd->status.inventory[idx],pc_get_group_level(sd)) || + (sd->status.inventory[idx].bound && !pc_can_give_bound_items(sd)) ) return 1; sd->mail.index = idx; @@ -174,10 +179,8 @@ void mail_deliveryfail(struct map_session_data *sd, struct mail_message *msg) } // This function only check if the mail operations are valid -bool mail_invalid_operation(struct map_session_data *sd) -{ - if( !map[sd->bl.m].flag.town && !pc->can_use_command(sd, "@mail") ) - { +bool mail_invalid_operation(struct map_session_data *sd) { + if( !map->list[sd->bl.m].flag.town && !pc->can_use_command(sd, "@mail") ) { ShowWarning("clif->parse_Mail: char '%s' trying to do invalid mail operations.\n", sd->status.name); return true; } @@ -198,4 +201,4 @@ void mail_defaults(void) mail->openmail = mail_openmail; mail->deliveryfail = mail_deliveryfail; mail->invalid_operation = mail_invalid_operation; -}
\ No newline at end of file +} diff --git a/src/map/mail.h b/src/map/mail.h index 99742c7bd..64b0f9779 100644 --- a/src/map/mail.h +++ b/src/map/mail.h @@ -2,10 +2,14 @@ // See the LICENSE file // Portions Copyright (c) Athena Dev Teams -#ifndef _MAIL_H_ -#define _MAIL_H_ +#ifndef MAP_MAIL_H +#define MAP_MAIL_H -#include "../common/mmo.h" +#include "../common/cbasetypes.h" + +struct item; +struct mail_message; +struct map_session_data; struct mail_interface { void (*clear) (struct map_session_data *sd); @@ -17,10 +21,10 @@ struct mail_interface { int (*openmail) (struct map_session_data *sd); void (*deliveryfail) (struct map_session_data *sd, struct mail_message *msg); bool (*invalid_operation) (struct map_session_data *sd); -} mail_s; +}; struct mail_interface *mail; void mail_defaults(void); -#endif /* _MAIL_H_ */ +#endif /* MAP_MAIL_H */ diff --git a/src/map/map.c b/src/map/map.c index 5f86286e9..0c8c2d949 100644 --- a/src/map/map.c +++ b/src/map/map.c @@ -2,251 +2,203 @@ // See the LICENSE file // Portions Copyright (c) Athena Dev Teams -#include "../common/cbasetypes.h" -#include "../common/core.h" -#include "../common/timer.h" -#include "../common/ers.h" -#include "../common/grfio.h" -#include "../common/malloc.h" -#include "../common/socket.h" // WFIFO*() -#include "../common/showmsg.h" -#include "../common/nullpo.h" -#include "../common/random.h" -#include "../common/strlib.h" -#include "../common/utils.h" -#include "../common/conf.h" -#include "../common/console.h" -#include "../common/HPM.h" +#define HERCULES_CORE +#include "../config/core.h" // CELL_NOSTACK, CIRCULAR_AREA, CONSOLE_INPUT, DBPATH, RENEWAL #include "map.h" -#include "path.h" + +#include <math.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "HPMmap.h" +#include "atcommand.h" +#include "battle.h" +#include "battleground.h" +#include "chat.h" #include "chrif.h" #include "clif.h" #include "duel.h" +#include "elemental.h" +#include "guild.h" +#include "homunculus.h" +#include "instance.h" #include "intif.h" +#include "irc-bot.h" +#include "itemdb.h" +#include "log.h" +#include "mail.h" +#include "mapreg.h" +#include "mercenary.h" +#include "mob.h" #include "npc.h" +#include "npc.h" // npc_setcells(), npc_unsetcells() +#include "party.h" +#include "path.h" #include "pc.h" +#include "pet.h" +#include "quest.h" +#include "script.h" +#include "skill.h" #include "status.h" -#include "mob.h" -#include "npc.h" // npc_setcells(), npc_unsetcells() -#include "chat.h" -#include "itemdb.h" #include "storage.h" -#include "skill.h" #include "trade.h" -#include "party.h" #include "unit.h" -#include "battle.h" -#include "battleground.h" -#include "quest.h" -#include "script.h" -#include "mapreg.h" -#include "guild.h" -#include "pet.h" -#include "homunculus.h" -#include "instance.h" -#include "mercenary.h" -#include "elemental.h" -#include "atcommand.h" -#include "log.h" -#include "mail.h" -#include "irc-bot.h" +#include "../common/HPM.h" +#include "../common/cbasetypes.h" +#include "../common/conf.h" +#include "../common/console.h" +#include "../common/core.h" +#include "../common/ers.h" +#include "../common/grfio.h" +#include "../common/malloc.h" +#include "../common/nullpo.h" +#include "../common/random.h" +#include "../common/showmsg.h" +#include "../common/socket.h" // WFIFO*() +#include "../common/strlib.h" +#include "../common/timer.h" +#include "../common/utils.h" -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <stdarg.h> -#include <math.h> #ifndef _WIN32 #include <unistd.h> #endif -char default_codepage[32] = ""; - -int map_server_port = 3306; -char map_server_ip[32] = "127.0.0.1"; -char map_server_id[32] = "ragnarok"; -char map_server_pw[32] = "ragnarok"; -char map_server_db[32] = "ragnarok"; -Sql* mmysql_handle; - -int map_port=0; - -// log database -char log_db_ip[32] = "127.0.0.1"; -int log_db_port = 3306; -char log_db_id[32] = "ragnarok"; -char log_db_pw[32] = "ragnarok"; -char log_db_db[32] = "log"; -Sql* logmysql_handle; - -// DBMap declaartion -static DBMap* id_db=NULL; // int id -> struct block_list* -static DBMap* pc_db=NULL; // int id -> struct map_session_data* -static DBMap* mobid_db=NULL; // int id -> struct mob_data* -static DBMap* bossid_db=NULL; // int id -> struct mob_data* (MVP db) -static DBMap* map_db=NULL; // unsigned int mapindex -> struct map_data_other_server* -static DBMap* nick_db=NULL; // int char_id -> struct charid2nick* (requested names of offline characters) -static DBMap* charid_db=NULL; // int char_id -> struct map_session_data* -static DBMap* regen_db=NULL; // int id -> struct block_list* (status_natural_heal processing) - -static int map_users=0; - -#define BLOCK_SIZE 8 -#define block_free_max 1048576 -struct block_list *block_free[block_free_max]; -static int block_free_count = 0, block_free_lock = 0; - -#define BL_LIST_MAX 1048576 -static struct block_list *bl_list[BL_LIST_MAX]; -static int bl_list_count = 0; - -struct charid_request { - struct charid_request* next; - int charid;// who want to be notified of the nick -}; -struct charid2nick { - char nick[NAME_LENGTH]; - struct charid_request* requests;// requests of notification on this nick -}; - -// This is the main header found at the very beginning of the map cache -struct map_cache_main_header { - uint32 file_size; - uint16 map_count; -}; - -// This is the header appended before every compressed map cells info in the map cache -struct map_cache_map_info { - char name[MAP_NAME_LENGTH]; - int16 xs; - int16 ys; - int32 len; -}; - -int16 index2mapid[MAX_MAPINDEX]; +struct map_interface map_s; +struct mapit_interface mapit_s; -int enable_grf = 0; //To enable/disable reading maps from GRF files, bypassing mapcache [blackhole89] +/*========================================== + * server player count (of all mapservers) + *------------------------------------------*/ +void map_setusers(int users) { + map->users = users; +} -/* [Ind/Hercules] */ -struct eri *map_iterator_ers; -char *map_cache_buffer = NULL; // Has the uncompressed gat data of all maps, so just one allocation has to be made +int map_getusers(void) { + return map->users; +} -/*========================================== -* server player count (of all mapservers) -*------------------------------------------*/ -void map_setusers(int users) -{ - map_users = users; +/** + * Expands map->bl_list on demand + **/ +static inline void map_bl_list_expand(void) { + map->bl_list_size += 250; + RECREATE(map->bl_list, struct block_list *, map->bl_list_size); } -int map_getusers(void) -{ - return map_users; +/** + * Expands map->block_free on demand + **/ +static inline void map_block_free_expand(void) { + map->block_free_list_size += 100; + RECREATE(map->block_free, struct block_list *, map->block_free_list_size); } /*========================================== -* server player count (this mapserver only) -*------------------------------------------*/ -int map_usercount(void) -{ - return pc_db->size(pc_db); + * server player count (this mapserver only) + *------------------------------------------*/ +int map_usercount(void) { + return db_size(map->pc_db); } - /*========================================== -* Attempt to free a map blocklist -*------------------------------------------*/ -int map_freeblock (struct block_list *bl) -{ - nullpo_retr(block_free_lock, bl); - if (block_free_lock == 0 || block_free_count >= block_free_max) - { - aFree(bl); + * Attempt to free a map blocklist + *------------------------------------------*/ +int map_freeblock (struct block_list *bl) { + nullpo_retr(map->block_free_lock, bl); + + if (map->block_free_lock == 0) { + if( bl->type == BL_ITEM ) + ers_free(map->flooritem_ers, bl); + else + aFree(bl); bl = NULL; - if (block_free_count >= block_free_max) - ShowWarning("map_freeblock: too many free block! %d %d\n", block_free_count, block_free_lock); - } else - block_free[block_free_count++] = bl; + } else { + + if( map->block_free_count >= map->block_free_list_size ) + map_block_free_expand(); + + map->block_free[map->block_free_count++] = bl; + } - return block_free_lock; + return map->block_free_lock; } /*========================================== -* Lock blocklist, (prevent iMap->freeblock usage) -*------------------------------------------*/ -int map_freeblock_lock (void) -{ - return ++block_free_lock; + * Lock blocklist, (prevent map->freeblock usage) + *------------------------------------------*/ +int map_freeblock_lock (void) { + return ++map->block_free_lock; } /*========================================== -* Remove the lock on map_bl -*------------------------------------------*/ -int map_freeblock_unlock (void) -{ - if ((--block_free_lock) == 0) { + * Remove the lock on map_bl + *------------------------------------------*/ +int map_freeblock_unlock (void) { + + if ((--map->block_free_lock) == 0) { int i; - for (i = 0; i < block_free_count; i++) - { - aFree(block_free[i]); - block_free[i] = NULL; + for (i = 0; i < map->block_free_count; i++) { + if( map->block_free[i]->type == BL_ITEM ) + ers_free(map->flooritem_ers, map->block_free[i]); + else + aFree(map->block_free[i]); + map->block_free[i] = NULL; } - block_free_count = 0; - } else if (block_free_lock < 0) { + map->block_free_count = 0; + } else if (map->block_free_lock < 0) { ShowError("map_freeblock_unlock: lock count < 0 !\n"); - block_free_lock = 0; + map->block_free_lock = 0; } - return block_free_lock; + return map->block_free_lock; } // Timer function to check if there some remaining lock and remove them if so. // Called each 1s -int map_freeblock_timer(int tid, unsigned int tick, int id, intptr_t data) -{ - if (block_free_lock > 0) { - ShowError("map_freeblock_timer: block_free_lock(%d) is invalid.\n", block_free_lock); - block_free_lock = 1; - iMap->freeblock_unlock(); +int map_freeblock_timer(int tid, int64 tick, int id, intptr_t data) { + if (map->block_free_lock > 0) { + ShowError("map_freeblock_timer: block_free_lock(%d) is invalid.\n", map->block_free_lock); + map->block_free_lock = 1; + map->freeblock_unlock(); } return 0; } -// -// blocklist -// -/*========================================== -* Handling of map_bl[] -* The adresse of bl_heal is set in bl->prev -*------------------------------------------*/ -static struct block_list bl_head; - +/** + * Updates the counter (cell.cell_bl) of how many objects are on a tile. + * @param add Whether the counter should be increased or decreased + **/ +void map_update_cell_bl( struct block_list *bl, bool increase ) { #ifdef CELL_NOSTACK -/*========================================== -* These pair of functions update the counter of how many objects -* lie on a tile. -*------------------------------------------*/ -static void map_addblcell(struct block_list *bl) -{ - if( bl->m<0 || bl->x<0 || bl->x>=map[bl->m].xs || bl->y<0 || bl->y>=map[bl->m].ys || !(bl->type&BL_CHAR) ) - return; - map[bl->m].cell[bl->x+bl->y*map[bl->m].xs].cell_bl++; - return; -} + int pos; -static void map_delblcell(struct block_list *bl) -{ - if( bl->m <0 || bl->x<0 || bl->x>=map[bl->m].xs || bl->y<0 || bl->y>=map[bl->m].ys || !(bl->type&BL_CHAR) ) + if( bl->m < 0 || bl->x < 0 || bl->x >= map->list[bl->m].xs + || bl->y < 0 || bl->y >= map->list[bl->m].ys + || !(bl->type&BL_CHAR) ) return; - map[bl->m].cell[bl->x+bl->y*map[bl->m].xs].cell_bl--; -} + + // When reading from mapcache the cell isn't initialized + // TODO: Maybe start initializing cells when they're loaded instead of + // having to get them here? [Panikon] + if( map->list[bl->m].cell == (struct mapcell *)0xdeadbeaf ) + map->cellfromcache(&map->list[bl->m]); + + pos = bl->x + bl->y*map->list[bl->m].xs; + if( increase ) + map->list[bl->m].cell[pos].cell_bl++; + else + map->list[bl->m].cell[pos].cell_bl--; #endif + return; +} /*========================================== -* Adds a block to the map. -* Returns 0 on success, 1 on failure (illegal coordinates). -*------------------------------------------*/ + * Adds a block to the map. + * Returns 0 on success, 1 on failure (illegal coordinates). + *------------------------------------------*/ int map_addblock(struct block_list* bl) { int16 m, x, y; @@ -262,41 +214,39 @@ int map_addblock(struct block_list* bl) m = bl->m; x = bl->x; y = bl->y; - if( m < 0 || m >= iMap->map_num ) - { - ShowError("map_addblock: invalid map id (%d), only %d are loaded.\n", m, iMap->map_num); + if( m < 0 || m >= map->count ) { + ShowError("map_addblock: invalid map id (%d), only %d are loaded.\n", m, map->count); return 1; } - if( x < 0 || x >= map[m].xs || y < 0 || y >= map[m].ys ) - { - ShowError("map_addblock: out-of-bounds coordinates (\"%s\",%d,%d), map is %dx%d\n", map[m].name, x, y, map[m].xs, map[m].ys); + if( x < 0 || x >= map->list[m].xs || y < 0 || y >= map->list[m].ys ) { + ShowError("map_addblock: out-of-bounds coordinates (\"%s\",%d,%d), map is %dx%d\n", map->list[m].name, x, y, map->list[m].xs, map->list[m].ys); return 1; } - pos = x/BLOCK_SIZE+(y/BLOCK_SIZE)*map[m].bxs; + pos = x/BLOCK_SIZE+(y/BLOCK_SIZE)*map->list[m].bxs; if (bl->type == BL_MOB) { - bl->next = map[m].block_mob[pos]; - bl->prev = &bl_head; + bl->next = map->list[m].block_mob[pos]; + bl->prev = &map->bl_head; if (bl->next) bl->next->prev = bl; - map[m].block_mob[pos] = bl; + map->list[m].block_mob[pos] = bl; } else { - bl->next = map[m].block[pos]; - bl->prev = &bl_head; + bl->next = map->list[m].block[pos]; + bl->prev = &map->bl_head; if (bl->next) bl->next->prev = bl; - map[m].block[pos] = bl; + map->list[m].block[pos] = bl; } #ifdef CELL_NOSTACK - map_addblcell(bl); + map->update_cell_bl(bl, true); #endif return 0; } /*========================================== -* Removes a block from the map. -*------------------------------------------*/ + * Removes a block from the map. + *------------------------------------------*/ int map_delblock(struct block_list* bl) { int pos; @@ -305,26 +255,26 @@ int map_delblock(struct block_list* bl) // blocklist (2ways chainlist) if (bl->prev == NULL) { if (bl->next != NULL) { - // can't delete block (already at the begining of the chain) + // can't delete block (already at the beginning of the chain) ShowError("map_delblock error : bl->next!=NULL\n"); } return 0; } #ifdef CELL_NOSTACK - map_delblcell(bl); + map->update_cell_bl(bl, false); #endif - pos = bl->x/BLOCK_SIZE+(bl->y/BLOCK_SIZE)*map[bl->m].bxs; + pos = bl->x/BLOCK_SIZE+(bl->y/BLOCK_SIZE)*map->list[bl->m].bxs; if (bl->next) bl->next->prev = bl->prev; - if (bl->prev == &bl_head) { + if (bl->prev == &map->bl_head) { //Since the head of the list, update the block_list map of [] if (bl->type == BL_MOB) { - map[bl->m].block_mob[pos] = bl->next; + map->list[bl->m].block_mob[pos] = bl->next; } else { - map[bl->m].block[pos] = bl->next; + map->list[bl->m].block[pos] = bl->next; } } else { bl->prev->next = bl->next; @@ -336,12 +286,11 @@ int map_delblock(struct block_list* bl) } /*========================================== -* Moves a block a x/y target position. [Skotlex] -* Pass flag as 1 to prevent doing skill->unit_move checks -* (which are executed by default on BL_CHAR types) -*------------------------------------------*/ -int map_moveblock(struct block_list *bl, int x1, int y1, unsigned int tick) -{ + * Moves a block a x/y target position. [Skotlex] + * Pass flag as 1 to prevent doing skill->unit_move checks + * (which are executed by default on BL_CHAR types) + *------------------------------------------*/ +int map_moveblock(struct block_list *bl, int x1, int y1, int64 tick) { int x0 = bl->x, y0 = bl->y; struct status_change *sc = NULL; int moveblock = ( x0/BLOCK_SIZE != x1/BLOCK_SIZE || y0/BLOCK_SIZE != y1/BLOCK_SIZE); @@ -355,7 +304,7 @@ int map_moveblock(struct block_list *bl, int x1, int y1, unsigned int tick) //TODO: Perhaps some outs of bounds checking should be placed here? if (bl->type&BL_CHAR) { - sc = status_get_sc(bl); + sc = status->get_sc(bl); skill->unit_move(bl,tick,2); status_change_end(bl, SC_RG_CCONFINE_M, INVALID_TIMER); @@ -363,21 +312,21 @@ int map_moveblock(struct block_list *bl, int x1, int y1, unsigned int tick) // status_change_end(bl, SC_BLADESTOP, INVALID_TIMER); //Won't stop when you are knocked away, go figure... status_change_end(bl, SC_NJ_TATAMIGAESHI, INVALID_TIMER); status_change_end(bl, SC_MAGICROD, INVALID_TIMER); - if (sc->data[SC_PROPERTYWALK] && + if (sc && sc->data[SC_PROPERTYWALK] && sc->data[SC_PROPERTYWALK]->val3 >= skill->get_maxcount(sc->data[SC_PROPERTYWALK]->val1,sc->data[SC_PROPERTYWALK]->val2) ) status_change_end(bl,SC_PROPERTYWALK,INVALID_TIMER); } else if (bl->type == BL_NPC) - npc_unsetcells((TBL_NPC*)bl); + npc->unsetcells((TBL_NPC*)bl); - if (moveblock) iMap->delblock(bl); + if (moveblock) map->delblock(bl); #ifdef CELL_NOSTACK - else map_delblcell(bl); + else map->update_cell_bl(bl, false); #endif bl->x = x1; bl->y = y1; - if (moveblock) iMap->addblock(bl); + if (moveblock) map->addblock(bl); #ifdef CELL_NOSTACK - else map_addblcell(bl); + else map->update_cell_bl(bl, true); #endif if (bl->type&BL_CHAR) { @@ -386,7 +335,7 @@ int map_moveblock(struct block_list *bl, int x1, int y1, unsigned int tick) if( bl->type == BL_PC && ((TBL_PC*)bl)->shadowform_id ) {//Shadow Form Target Moving struct block_list *d_bl; - if( (d_bl = iMap->id2bl(((TBL_PC*)bl)->shadowform_id)) == NULL || !check_distance_bl(bl,d_bl,10) ) { + if( (d_bl = map->id2bl(((TBL_PC*)bl)->shadowform_id)) == NULL || !check_distance_bl(bl,d_bl,10) ) { if( d_bl ) status_change_end(d_bl,SC__SHADOWFORM,INVALID_TIMER); ((TBL_PC*)bl)->shadowform_id = 0; @@ -411,16 +360,17 @@ int map_moveblock(struct block_list *bl, int x1, int y1, unsigned int tick) if( sc->data[SC__SHADOWFORM] ) {//Shadow Form Caster Moving struct block_list *d_bl; - if( (d_bl = iMap->id2bl(sc->data[SC__SHADOWFORM]->val2)) == NULL || !check_distance_bl(bl,d_bl,10) ) + if( (d_bl = map->id2bl(sc->data[SC__SHADOWFORM]->val2)) == NULL || !check_distance_bl(bl,d_bl,10) ) status_change_end(bl,SC__SHADOWFORM,INVALID_TIMER); } if (sc->data[SC_PROPERTYWALK] - && sc->data[SC_PROPERTYWALK]->val3 < skill->get_maxcount(sc->data[SC_PROPERTYWALK]->val1,sc->data[SC_PROPERTYWALK]->val2) - && iMap->find_skill_unit_oncell(bl,bl->x,bl->y,SO_ELECTRICWALK,NULL,0) == NULL - && iMap->find_skill_unit_oncell(bl,bl->x,bl->y,SO_FIREWALK,NULL,0) == NULL - && skill->unitsetting(bl,sc->data[SC_PROPERTYWALK]->val1,sc->data[SC_PROPERTYWALK]->val2,x0, y0,0)) { - sc->data[SC_PROPERTYWALK]->val3++; + && sc->data[SC_PROPERTYWALK]->val3 < skill->get_maxcount(sc->data[SC_PROPERTYWALK]->val1,sc->data[SC_PROPERTYWALK]->val2) + && map->find_skill_unit_oncell(bl,bl->x,bl->y,SO_ELECTRICWALK,NULL,0) == NULL + && map->find_skill_unit_oncell(bl,bl->x,bl->y,SO_FIREWALK,NULL,0) == NULL + && skill->unitsetting(bl,sc->data[SC_PROPERTYWALK]->val1,sc->data[SC_PROPERTYWALK]->val2,x0, y0,0) + ) { + sc->data[SC_PROPERTYWALK]->val3++; } @@ -438,608 +388,848 @@ int map_moveblock(struct block_list *bl, int x1, int y1, unsigned int tick) } } } else if (bl->type == BL_NPC) - npc_setcells((TBL_NPC*)bl); + npc->setcells((TBL_NPC*)bl); return 0; } /*========================================== -* Counts specified number of objects on given cell. -*------------------------------------------*/ -int map_count_oncell(int16 m, int16 x, int16 y, int type) -{ + * Counts specified number of objects on given cell. + * TODO: merge with bl_getall_area + *------------------------------------------*/ +int map_count_oncell(int16 m, int16 x, int16 y, int type) { int bx,by; struct block_list *bl; int count = 0; - if (x < 0 || y < 0 || (x >= map[m].xs) || (y >= map[m].ys)) + if (x < 0 || y < 0 || (x >= map->list[m].xs) || (y >= map->list[m].ys)) return 0; bx = x/BLOCK_SIZE; by = y/BLOCK_SIZE; if (type&~BL_MOB) - for( bl = map[m].block[bx+by*map[m].bxs] ; bl != NULL ; bl = bl->next ) + for( bl = map->list[m].block[bx+by*map->list[m].bxs] ; bl != NULL ; bl = bl->next ) if(bl->x == x && bl->y == y && bl->type&type) count++; if (type&BL_MOB) - for( bl = map[m].block_mob[bx+by*map[m].bxs] ; bl != NULL ; bl = bl->next ) + for( bl = map->list[m].block_mob[bx+by*map->list[m].bxs] ; bl != NULL ; bl = bl->next ) if(bl->x == x && bl->y == y) count++; return count; } /* -* Looks for a skill unit on a given cell -* flag&1: runs battle_check_target check based on unit->group->target_flag -*/ + * Looks for a skill unit on a given cell + * flag&1: runs battle_check_target check based on unit->group->target_flag + */ struct skill_unit* map_find_skill_unit_oncell(struct block_list* target,int16 x,int16 y,uint16 skill_id,struct skill_unit* out_unit, int flag) { int16 m,bx,by; struct block_list *bl; - struct skill_unit *unit; + struct skill_unit *su; m = target->m; - if (x < 0 || y < 0 || (x >= map[m].xs) || (y >= map[m].ys)) + if (x < 0 || y < 0 || (x >= map->list[m].xs) || (y >= map->list[m].ys)) return NULL; bx = x/BLOCK_SIZE; by = y/BLOCK_SIZE; - for( bl = map[m].block[bx+by*map[m].bxs] ; bl != NULL ; bl = bl->next ) - { + for( bl = map->list[m].block[bx+by*map->list[m].bxs] ; bl != NULL ; bl = bl->next ) { if (bl->x != x || bl->y != y || bl->type != BL_SKILL) continue; - unit = (struct skill_unit *) bl; - if( unit == out_unit || !unit->alive || !unit->group || unit->group->skill_id != skill_id ) + su = (struct skill_unit *) bl; + if( su == out_unit || !su->alive || !su->group || su->group->skill_id != skill_id ) continue; - if( !(flag&1) || battle->check_target(&unit->bl,target,unit->group->target_flag) > 0 ) - return unit; + if( !(flag&1) || battle->check_target(&su->bl,target,su->group->target_flag) > 0 ) + return su; } return NULL; } -/*========================================== -* Adapted from foreachinarea for an easier invocation. [Skotlex] -*------------------------------------------*/ -int map_foreachinrange(int (*func)(struct block_list*,va_list), struct block_list* center, int16 range, int type, ...) -{ - int bx, by, m; - int returnCount = 0; //total sum of returned values of func() [Skotlex] - struct block_list *bl; - int blockcount = bl_list_count, i; - int x0, x1, y0, y1; - va_list ap; - - m = center->m; - x0 = max(center->x - range, 0); - y0 = max(center->y - range, 0); - x1 = min(center->x + range, map[ m ].xs - 1); - y1 = min(center->y + range, map[ m ].ys - 1); - - if ( type&~BL_MOB ) - for ( by = y0 / BLOCK_SIZE; by <= y1 / BLOCK_SIZE; by++ ) { - for( bx = x0 / BLOCK_SIZE; bx <= x1 / BLOCK_SIZE; bx++ ) { - for( bl = map[m].block[ bx + by * map[ m ].bxs ]; bl != NULL; bl = bl->next ) { - if( bl->type&type - && bl->x >= x0 && bl->x <= x1 && bl->y >= y0 && bl->y <= y1 -#ifdef CIRCULAR_AREA - && check_distance_bl(center, bl, range) -#endif - && bl_list_count < BL_LIST_MAX ) - bl_list[ bl_list_count++ ] = bl; - } - } - } - - if( type&BL_MOB ) - for( by = y0 / BLOCK_SIZE; by <= y1 / BLOCK_SIZE; by++ ) { - for(bx=x0/BLOCK_SIZE;bx<=x1/BLOCK_SIZE;bx++) { - for( bl = map[ m ].block_mob[ bx + by * map[ m ].bxs ]; bl != NULL; bl = bl->next ) { - if( bl->x >= x0 && bl->x <= x1 && bl->y >= y0 && bl->y <= y1 -#ifdef CIRCULAR_AREA - && check_distance_bl(center, bl, range) -#endif - && bl_list_count < BL_LIST_MAX ) - bl_list[ bl_list_count++ ] = bl; - } - } - } - - if( bl_list_count >= BL_LIST_MAX ) - ShowWarning("iMap->foreachinrange: block count too many!\n"); +/** @name Functions for block_list search and manipulation + */ - iMap->freeblock_lock(); +/* @{ */ +/** + * Applies func to every block_list in bl_list starting with bl_list[blockcount]. + * Sets bl_list_count back to blockcount. + * Returns the sum of values returned by func. + * @param func Function to be applied + * @param blockcount Index of first relevant entry in bl_list + * @param max Maximum sum of values returned by func (usually max number of func calls) + * @param args Extra arguments for func + * @return Sum of the values returned by func + */ +static int bl_vforeach(int (*func)(struct block_list*, va_list), int blockcount, int max, va_list args) { + int i; + int returnCount = 0; - for( i = blockcount; i < bl_list_count; i++ ) - if( bl_list[ i ]->prev ) { //func() may delete this bl_list[] slot, checking for prev ensures it wasnt queued for deletion. - va_start(ap, type); - returnCount += func(bl_list[ i ], ap); - va_end(ap); - } + map->freeblock_lock(); + for (i = blockcount; i < map->bl_list_count && returnCount < max; i++) { + if (map->bl_list[i]->prev) { //func() may delete this bl_list[] slot, checking for prev ensures it wasn't queued for deletion. + va_list argscopy; + va_copy(argscopy, args); + returnCount += func(map->bl_list[i], argscopy); + va_end(argscopy); + } + } + map->freeblock_unlock(); - iMap->freeblock_unlock(); + map->bl_list_count = blockcount; - bl_list_count = blockcount; - return returnCount; //[Skotlex] + return returnCount; } -/*========================================== -* Same as foreachinrange, but there must be a shoot-able range between center and target to be counted in. [Skotlex] -*------------------------------------------*/ -int map_foreachinshootrange(int (*func)(struct block_list*,va_list),struct block_list* center, int16 range, int type,...) -{ - int bx, by, m; - int returnCount = 0; //total sum of returned values of func() [Skotlex] +/** + * Applies func to every block_list object of bl_type type on map m. + * Returns the sum of values returned by func. + * @param func Function to be applied + * @param m Map id + * @param type enum bl_type + * @param args Extra arguments for func + * @return Sum of the values returned by func + */ +static int map_vforeachinmap(int (*func)(struct block_list*, va_list), int16 m, int type, va_list args) { + int i; + int returnCount = 0; + int bsize; + va_list argscopy; struct block_list *bl; - int blockcount = bl_list_count, i; - int x0, x1, y0, y1; - va_list ap; + int blockcount = map->bl_list_count; - m = center->m; - if ( m < 0 ) + if (m < 0) return 0; - x0 = max(center->x-range, 0); - y0 = max(center->y-range, 0); - x1 = min(center->x+range, map[m].xs-1); - y1 = min(center->y+range, map[m].ys-1); - - if ( type&~BL_MOB ) - for( by = y0 / BLOCK_SIZE; by <= y1 / BLOCK_SIZE; by++ ) { - for( bx = x0 / BLOCK_SIZE; bx <= x1 / BLOCK_SIZE; bx++ ) { - for( bl = map[ m ].block[ bx + by * map[ m ].bxs ]; bl != NULL; bl = bl->next ) { - if( bl->type&type - && bl->x >= x0 && bl->x <= x1 && bl->y >= y0 && bl->y <= y1 -#ifdef CIRCULAR_AREA - && check_distance_bl(center, bl, range) -#endif - && path_search_long(NULL, center->m, center->x, center->y, bl->x, bl->y, CELL_CHKWALL) - && bl_list_count < BL_LIST_MAX ) - bl_list[ bl_list_count++ ] = bl; + bsize = map->list[m].bxs * map->list[m].bys; + for (i = 0; i < bsize; i++) { + if (type&~BL_MOB) { + for (bl = map->list[m].block[i]; bl != NULL; bl = bl->next) { + if (bl->type&type) { + if( map->bl_list_count >= map->bl_list_size ) + map_bl_list_expand(); + map->bl_list[map->bl_list_count++] = bl; } } } - if( type&BL_MOB ) - for( by = y0 / BLOCK_SIZE; by <= y1 / BLOCK_SIZE; by++ ) { - for( bx=x0 / BLOCK_SIZE; bx <= x1 / BLOCK_SIZE; bx++ ) { - for( bl = map[ m ].block_mob[ bx + by * map[ m ].bxs ]; bl != NULL; bl = bl->next ) { - if( bl->x >= x0 && bl->x <= x1 && bl->y >= y0 && bl->y <= y1 -#ifdef CIRCULAR_AREA - && check_distance_bl(center, bl, range) -#endif - && path_search_long(NULL, center->m, center->x, center->y, bl->x, bl->y, CELL_CHKWALL) - && bl_list_count < BL_LIST_MAX ) - bl_list[ bl_list_count++ ] = bl; - } - } + if (type&BL_MOB) { + for (bl = map->list[m].block_mob[i]; bl != NULL; bl = bl->next) { + if( map->bl_list_count >= map->bl_list_size ) + map_bl_list_expand(); + map->bl_list[map->bl_list_count++] = bl; } + } + } - if( bl_list_count >= BL_LIST_MAX ) - ShowWarning("iMap->foreachinrange: block count too many!\n"); + va_copy(argscopy, args); + returnCount = bl_vforeach(func, blockcount, INT_MAX, argscopy); + va_end(argscopy); - iMap->freeblock_lock(); + return returnCount; +} - for( i = blockcount; i < bl_list_count; i++ ) - if( bl_list[ i ]->prev ) { //func() may delete this bl_list[] slot, checking for prev ensures it wasnt queued for deletion. - va_start(ap, type); - returnCount += func(bl_list[ i ], ap); - va_end(ap); - } +/** + * Applies func to every block_list object of bl_type type on map m. + * Returns the sum of values returned by func. + * @see map_vforeachinmap + * @param func Function to be applied + * @param m Map id + * @param type enum bl_type + * @param ... Extra arguments for func + * @return Sum of the values returned by func + */ +int map_foreachinmap(int (*func)(struct block_list*, va_list), int16 m, int type, ...) { + int returnCount; + va_list ap; - iMap->freeblock_unlock(); + va_start(ap, type); + returnCount = map->vforeachinmap(func, m, type, ap); + va_end(ap); - bl_list_count = blockcount; - return returnCount; //[Skotlex] + return returnCount; } -/*========================================== -* range = map m (x0,y0)-(x1,y1) -* Apply *func with ... arguments for the range. -* @type = BL_PC/BL_MOB etc.. -*------------------------------------------*/ -int map_foreachinarea(int (*func)(struct block_list*,va_list), int16 m, int16 x0, int16 y0, int16 x1, int16 y1, int type, ...) -{ +/** + * Applies func to every block_list object of bl_type type on all maps + * of instance instance_id. + * Returns the sum of values returned by func. + * @see map_vforeachinmap. + * @param func Function to be applied + * @param m Map id + * @param type enum bl_type + * @param ap Extra arguments for func + * @return Sum of the values returned by func + */ +int map_vforeachininstance(int (*func)(struct block_list*, va_list), int16 instance_id, int type, va_list ap) { + int i; + int returnCount = 0; + + for (i = 0; i < instance->list[instance_id].num_map; i++) { + int m = instance->list[instance_id].map[i]; + va_list apcopy; + va_copy(apcopy, ap); + returnCount += map->vforeachinmap(func, m, type, apcopy); + va_end(apcopy); + } + + return returnCount; +} + +/** + * Applies func to every block_list object of bl_type type on all maps + * of instance instance_id. + * Returns the sum of values returned by func. + * @see map_vforeachininstance. + * @param func Function to be applied + * @param m Map id + * @param type enum bl_type + * @param ... Extra arguments for func + * @return Sum of the values returned by func + */ +int map_foreachininstance(int (*func)(struct block_list*, va_list), int16 instance_id, int type, ...) { + int returnCount; + va_list ap; + + va_start(ap, type); + returnCount = map->vforeachininstance(func, instance_id, type, ap); + va_end(ap); + + return returnCount; +} + +/** + * Retrieves all map objects in area that are matched by the type + * and func. Appends them at the end of global bl_list array. + * @param type Matching enum bl_type + * @param m Map + * @param func Matching function + * @param ... Extra arguments for func + * @return Number of found objects + */ +static int bl_getall_area(int type, int m, int x0, int y0, int x1, int y1, int (*func)(struct block_list*, va_list), ...) { + va_list args; int bx, by; - int returnCount = 0; //total sum of returned values of func() [Skotlex] struct block_list *bl; - int blockcount = bl_list_count, i; - va_list ap; + int found = 0; - if ( m < 0 ) + if (m < 0) return 0; - if ( x1 < x0 ) - swap(x0, x1); - if ( y1 < y0 ) - swap(y0, y1); + if (x1 < x0) swap(x0, x1); + if (y1 < y0) swap(y0, y1); + // Limit search area to map size x0 = max(x0, 0); y0 = max(y0, 0); - x1 = min(x1, map[ m ].xs - 1); - y1 = min(y1, map[ m ].ys - 1); - if ( type&~BL_MOB ) - for( by = y0 / BLOCK_SIZE; by <= y1 / BLOCK_SIZE; by++ ) - for( bx = x0 / BLOCK_SIZE; bx <= x1 / BLOCK_SIZE; bx++ ) - for( bl = map[ m ].block[ bx + by * map[ m ].bxs ]; bl != NULL; bl = bl->next ) - if( bl->type&type && bl->x >= x0 && bl->x <= x1 && bl->y >= y0 && bl->y <= y1 && bl_list_count < BL_LIST_MAX ) - bl_list[ bl_list_count++ ] = bl; + x1 = min(x1, map->list[m].xs - 1); + y1 = min(y1, map->list[m].ys - 1); + + for (by = y0 / BLOCK_SIZE; by <= y1 / BLOCK_SIZE; by++) { + for (bx = x0 / BLOCK_SIZE; bx <= x1 / BLOCK_SIZE; bx++) { + if (type&~BL_MOB) { + for (bl = map->list[m].block[bx + by * map->list[m].bxs]; bl != NULL; bl = bl->next) { + if (bl->type&type && bl->x >= x0 && bl->x <= x1 && bl->y >= y0 && bl->y <= y1) { + if( map->bl_list_count >= map->bl_list_size ) + map_bl_list_expand(); + if (func) { + va_start(args, func); + if (func(bl, args)) { + map->bl_list[map->bl_list_count++] = bl; + found++; + } + va_end(args); + } else { + map->bl_list[map->bl_list_count++] = bl; + found++; + } + } + } + } + if (type&BL_MOB) { // TODO: fix this code duplication + for (bl = map->list[m].block_mob[bx + by * map->list[m].bxs]; bl != NULL; bl = bl->next) { + if (bl->x >= x0 && bl->x <= x1 && bl->y >= y0 && bl->y <= y1) { + if( map->bl_list_count >= map->bl_list_size ) + map_bl_list_expand(); + if (func) { + va_start(args, func); + if (func(bl, args)) { + map->bl_list[map->bl_list_count++] = bl; + found++; + } + va_end(args); + } else { + map->bl_list[map->bl_list_count++] = bl; + found++; + } + } + } + } + } + } + + return found; +} - if( type&BL_MOB ) - for( by = y0 / BLOCK_SIZE; by <= y1 / BLOCK_SIZE; by++ ) - for( bx = x0 / BLOCK_SIZE; bx <= x1 / BLOCK_SIZE; bx++ ) - for( bl = map[ m ].block_mob[ bx + by * map[ m ].bxs ]; bl != NULL; bl = bl->next ) - if( bl->x >= x0 && bl->x <= x1 && bl->y >= y0 && bl->y <= y1 && bl_list_count < BL_LIST_MAX ) - bl_list[ bl_list_count++ ] = bl; +/** + * Checks if bl is within range cells from center. + * If CIRCULAR AREA is not used always returns 1, since + * preliminary range selection is already done in bl_getall_area. + * @return 1 if matches, 0 otherwise + */ +static int bl_vgetall_inrange(struct block_list *bl, va_list args) +{ +#ifdef CIRCULAR_AREA + struct block_list *center = va_arg(args, struct block_list*); + int range = va_arg(args, int); + if (!check_distance_bl(center, bl, range)) + return 0; +#endif + return 1; +} - if( bl_list_count >= BL_LIST_MAX ) - ShowWarning("map_foreachinarea: block count too many!\n"); +/** + * Applies func to every block_list object of bl_type type within range cells from center. + * Area is rectangular, unless CIRCULAR_AREA is defined. + * Returns the sum of values returned by func. + * @param func Function to be applied + * @param center Center of the selection area + * @param range Range in cells from center + * @param type enum bl_type + * @param ap Extra arguments for func + * @return Sum of the values returned by func + */ +int map_vforeachinrange(int (*func)(struct block_list*, va_list), struct block_list* center, int16 range, int type, va_list ap) { + int returnCount = 0; + int blockcount = map->bl_list_count; + va_list apcopy; + + if (range < 0) range *= -1; + + bl_getall_area(type, center->m, center->x - range, center->y - range, center->x + range, center->y + range, bl_vgetall_inrange, center, range); + + va_copy(apcopy, ap); + returnCount = bl_vforeach(func, blockcount, INT_MAX, apcopy); + va_end(apcopy); - iMap->freeblock_lock(); + return returnCount; +} - for( i = blockcount; i < bl_list_count; i++ ) - if( bl_list[ i ]->prev ) { //func() may delete this bl_list[] slot, checking for prev ensures it wasnt queued for deletion. - va_start(ap, type); - returnCount += func(bl_list[ i ], ap); - va_end(ap); - } +/** + * Applies func to every block_list object of bl_type type within range cells from center. + * Area is rectangular, unless CIRCULAR_AREA is defined. + * Returns the sum of values returned by func. + * @see map_vforeachinrange + * @param func Function to be applied + * @param center Center of the selection area + * @param range Range in cells from center + * @param type enum bl_type + * @param ... Extra arguments for func + * @return Sum of the values returned by func + */ +int map_foreachinrange(int (*func)(struct block_list*, va_list), struct block_list* center, int16 range, int type, ...) { + int returnCount; + va_list ap; - iMap->freeblock_unlock(); + va_start(ap, type); + returnCount = map->vforeachinrange(func, center, range, type, ap); + va_end(ap); - bl_list_count = blockcount; - return returnCount; //[Skotlex] + return returnCount; } -/*========================================== -* Adapted from forcountinarea for an easier invocation. [pakpil] -*------------------------------------------*/ -int map_forcountinrange(int (*func)(struct block_list*,va_list), struct block_list* center, int16 range, int count, int type, ...) -{ - int bx, by, m; - int returnCount = 0; //total sum of returned values of func() [Skotlex] - struct block_list *bl; - int blockcount = bl_list_count, i; - int x0, x1, y0, y1; + +/** + * Applies func to some block_list objects of bl_type type within range cells from center. + * Limit is set by count parameter. + * Area is rectangular, unless CIRCULAR_AREA is defined. + * Returns the sum of values returned by func. + * @param func Function to be applied + * @param center Center of the selection area + * @param range Range in cells from center + * @param count Maximum sum of values returned by func (usually max number of func calls) + * @param type enum bl_type + * @param ap Extra arguments for func + * @return Sum of the values returned by func + */ +int map_vforcountinrange(int (*func)(struct block_list*, va_list), struct block_list* center, int16 range, int count, int type, va_list ap) { + int returnCount = 0; + int blockcount = map->bl_list_count; + va_list apcopy; + + if (range < 0) range *= -1; + + bl_getall_area(type, center->m, center->x - range, center->y - range, center->x + range, center->y + range, bl_vgetall_inrange, center, range); + + va_copy(apcopy, ap); + returnCount = bl_vforeach(func, blockcount, count, apcopy); + va_end(apcopy); + + return returnCount; +} + +/** + * Applies func to some block_list objects of bl_type type within range cells from center. + * Limit is set by count parameter. + * Area is rectangular, unless CIRCULAR_AREA is defined. + * Returns the sum of values returned by func. + * @see map_vforcountinrange + * @param func Function to be applied + * @param center Center of the selection area + * @param range Range in cells from center + * @param count Maximum sum of values returned by func (usually max number of func calls) + * @param type enum bl_type + * @param ... Extra arguments for func + * @return Sum of the values returned by func + */ +int map_forcountinrange(int (*func)(struct block_list*, va_list), struct block_list* center, int16 range, int count, int type, ...) { + int returnCount; va_list ap; - m = center->m; - x0 = max(center->x - range, 0); - y0 = max(center->y - range, 0); - x1 = min(center->x + range, map[ m ].xs - 1); - y1 = min(center->y + range, map[ m ].ys - 1); - - if ( type&~BL_MOB ) - for ( by = y0 / BLOCK_SIZE; by <= y1 / BLOCK_SIZE; by++ ) { - for( bx = x0 / BLOCK_SIZE; bx <= x1 / BLOCK_SIZE; bx++ ) { - for( bl = map[ m ].block[ bx + by * map[ m ].bxs ]; bl != NULL; bl = bl->next ) { - if( bl->type&type - && bl->x >= x0 && bl->x <= x1 && bl->y >= y0 && bl->y <= y1 -#ifdef CIRCULAR_AREA - && check_distance_bl(center, bl, range) -#endif - && bl_list_count < BL_LIST_MAX ) - bl_list[ bl_list_count++ ] = bl; - } - } - } - if( type&BL_MOB ) - for( by = y0 / BLOCK_SIZE; by <= y1 / BLOCK_SIZE; by++ ) { - for( bx = x0 / BLOCK_SIZE; bx <= x1 / BLOCK_SIZE; bx++ ){ - for( bl = map[ m ].block_mob[ bx + by * map[ m ].bxs ]; bl != NULL; bl = bl->next ) { - if( bl->x >= x0 && bl->x <= x1 && bl->y >= y0 && bl->y <= y1 + va_start(ap, type); + returnCount = map->vforcountinrange(func, center, range, count, type, ap); + va_end(ap); + + return returnCount; +} + +/** + * Checks if bl is within shooting range from center. + * There must be a shootable path between bl and center. + * Does not check for range if CIRCULAR AREA is not defined, since + * preliminary range selection is already done in bl_getall_area. + * @return 1 if matches, 0 otherwise + */ +static int bl_vgetall_inshootrange(struct block_list *bl, va_list args) +{ + struct block_list *center = va_arg(args, struct block_list*); #ifdef CIRCULAR_AREA - && check_distance_bl(center, bl, range) + int range = va_arg(args, int); + if (!check_distance_bl(center, bl, range)) + return 0; #endif - && bl_list_count < BL_LIST_MAX ) - bl_list[ bl_list_count++ ] = bl; - } - } - } + if (!path->search_long(NULL, center->m, center->x, center->y, bl->x, bl->y, CELL_CHKWALL)) + return 0; + return 1; +} - if( bl_list_count >= BL_LIST_MAX ) - ShowWarning("map_forcountinrange: block count too many!\n"); +/** + * Applies func to every block_list object of bl_type type within shootable range from center. + * There must be a shootable path between bl and center. + * Area is rectangular, unless CIRCULAR_AREA is defined. + * Returns the sum of values returned by func. + * @param func Function to be applied + * @param center Center of the selection area + * @param range Range in cells from center + * @param type enum bl_type + * @param ap Extra arguments for func + * @return Sum of the values returned by func + */ +int map_vforeachinshootrange(int (*func)(struct block_list*, va_list), struct block_list* center, int16 range, int type, va_list ap) { + int returnCount = 0; + int blockcount = map->bl_list_count; + va_list apcopy; + + if (range < 0) range *= -1; + + bl_getall_area(type, center->m, center->x - range, center->y - range, center->x + range, center->y + range, bl_vgetall_inshootrange, center, range); + + va_copy(apcopy, ap); + returnCount = bl_vforeach(func, blockcount, INT_MAX, ap); + va_end(apcopy); - iMap->freeblock_lock(); + return returnCount; +} - for( i = blockcount; i < bl_list_count; i++ ) - if( bl_list[ i ]->prev ) { //func() may delete this bl_list[] slot, checking for prev ensures it wasnt queued for deletion. - va_start(ap, type); - returnCount += func(bl_list[ i ], ap); - va_end(ap); - if( count && returnCount >= count ) - break; - } +/** + * Applies func to every block_list object of bl_type type within shootable range from center. + * There must be a shootable path between bl and center. + * Area is rectangular, unless CIRCULAR_AREA is defined. + * Returns the sum of values returned by func. + * @param func Function to be applied + * @param center Center of the selection area + * @param range Range in cells from center + * @param type enum bl_type + * @param ... Extra arguments for func + * @return Sum of the values returned by func + */ +int map_foreachinshootrange(int (*func)(struct block_list*, va_list), struct block_list* center, int16 range, int type, ...) { + int returnCount; + va_list ap; - iMap->freeblock_unlock(); + va_start(ap, type); + returnCount = map->vforeachinshootrange(func, center, range, type, ap); + va_end(ap); - bl_list_count = blockcount; - return returnCount; //[Skotlex] + return returnCount; } -int map_forcountinarea(int (*func)(struct block_list*,va_list), int16 m, int16 x0, int16 y0, int16 x1, int16 y1, int count, int type, ...) -{ - int bx, by; - int returnCount = 0; //total sum of returned values of func() [Skotlex] - struct block_list *bl; - int blockcount = bl_list_count, i; + +/** + * Applies func to every block_list object of bl_type type in + * rectangular area (x0,y0)~(x1,y1) on map m. + * Returns the sum of values returned by func. + * @param func Function to be applied + * @param m Map id + * @param x0 Starting X-coordinate + * @param y0 Starting Y-coordinate + * @param x1 Ending X-coordinate + * @param y1 Ending Y-coordinate + * @param type enum bl_type + * @param ap Extra arguments for func + * @return Sum of the values returned by func + */ +int map_vforeachinarea(int (*func)(struct block_list*, va_list), int16 m, int16 x0, int16 y0, int16 x1, int16 y1, int type, va_list ap) { + int returnCount = 0; + int blockcount = map->bl_list_count; + va_list apcopy; + + bl_getall_area(type, m, x0, y0, x1, y1, NULL); + + va_copy(apcopy, ap); + returnCount = bl_vforeach(func, blockcount, INT_MAX, apcopy); + va_end(apcopy); + + return returnCount; +} + +/** + * Applies func to every block_list object of bl_type type in + * rectangular area (x0,y0)~(x1,y1) on map m. + * Returns the sum of values returned by func. + * @see map_vforeachinarea + * @param func Function to be applied + * @param m Map id + * @param x0 Starting X-coordinate + * @param y0 Starting Y-coordinate + * @param x1 Ending X-coordinate + * @param y1 Ending Y-coordinate + * @param type enum bl_type + * @param ... Extra arguments for func + * @return Sum of the values returned by func + */ +int map_foreachinarea(int (*func)(struct block_list*, va_list), int16 m, int16 x0, int16 y0, int16 x1, int16 y1, int type, ...) { + int returnCount; va_list ap; - if ( m < 0 ) - return 0; + va_start(ap, type); + returnCount = map->vforeachinarea(func, m, x0, y0, x1, y1, type, ap); + va_end(ap); - if ( x1 < x0 ) - swap(x0, x1); - if ( y1 < y0 ) - swap(y0, y1); + return returnCount; +} - x0 = max(x0, 0); - y0 = max(y0, 0); - x1 = min(x1, map[ m ].xs - 1); - y1 = min(y1, map[ m ].ys - 1); - - if ( type&~BL_MOB ) - for( by = y0 / BLOCK_SIZE; by <= y1 / BLOCK_SIZE; by++ ) - for( bx = x0 / BLOCK_SIZE; bx <= x1 / BLOCK_SIZE; bx++ ) - for( bl = map[ m ].block[ bx + by * map[ m ].bxs ]; bl != NULL; bl = bl->next ) - if( bl->type&type && bl->x >= x0 && bl->x <= x1 && bl->y >= y0 && bl->y <= y1 && bl_list_count < BL_LIST_MAX ) - bl_list[ bl_list_count++ ] = bl; - - if( type&BL_MOB ) - for( by = y0 / BLOCK_SIZE; by <= y1 / BLOCK_SIZE; by++ ) - for( bx = x0 / BLOCK_SIZE; bx <= x1 / BLOCK_SIZE; bx++ ) - for( bl = map[ m ].block_mob[ bx + by * map[ m ].bxs ]; bl != NULL; bl = bl->next ) - if( bl->x >= x0 && bl->x <= x1 && bl->y >= y0 && bl->y <= y1 && bl_list_count < BL_LIST_MAX ) - bl_list[ bl_list_count++ ] = bl; - - if( bl_list_count >= BL_LIST_MAX ) - ShowWarning("map_foreachinarea: block count too many!\n"); - - iMap->freeblock_lock(); - - for( i = blockcount; i < bl_list_count; i++ ) - if(bl_list[ i ]->prev) { //func() may delete this bl_list[] slot, checking for prev ensures it wasnt queued for deletion. - va_start(ap, type); - returnCount += func(bl_list[ i ], ap); - va_end(ap); - if( count && returnCount >= count ) - break; - } +/** + * Applies func to some block_list objects of bl_type type in + * rectangular area (x0,y0)~(x1,y1) on map m. + * Limit is set by @count parameter. + * Returns the sum of values returned by func. + * @param func Function to be applied + * @param m Map id + * @param x0 Starting X-coordinate + * @param y0 Starting Y-coordinate + * @param x1 Ending X-coordinate + * @param y1 Ending Y-coordinate + * @param count Maximum sum of values returned by func (usually max number of func calls) + * @param type enum bl_type + * @param ap Extra arguments for func + * @return Sum of the values returned by func + */ +int map_vforcountinarea(int (*func)(struct block_list*,va_list), int16 m, int16 x0, int16 y0, int16 x1, int16 y1, int count, int type, va_list ap) { + int returnCount = 0; + int blockcount = map->bl_list_count; + va_list apcopy; + + bl_getall_area(type, m, x0, y0, x1, y1, NULL); + + va_copy(apcopy, ap); + returnCount = bl_vforeach(func, blockcount, count, apcopy); + va_end(apcopy); + + return returnCount; +} + +/** + * Applies func to some block_list objects of bl_type type in + * rectangular area (x0,y0)~(x1,y1) on map m. + * Limit is set by @count parameter. + * Returns the sum of values returned by func. + * @see map_vforcountinarea + * @param func Function to be applied + * @param m Map id + * @param x0 Starting X-coordinate + * @param y0 Starting Y-coordinate + * @param x1 Ending X-coordinate + * @param y1 Ending Y-coordinate + * @param count Maximum sum of values returned by func (usually max number of func calls) + * @param type enum bl_type + * @param ... Extra arguments for func + * @return Sum of the values returned by func + */ +int map_forcountinarea(int (*func)(struct block_list*,va_list), int16 m, int16 x0, int16 y0, int16 x1, int16 y1, int count, int type, ...) { + int returnCount; + va_list ap; - iMap->freeblock_unlock(); + va_start(ap, type); + returnCount = map->vforcountinarea(func, m, x0, y0, x1, y1, count, type, ap); + va_end(ap); - bl_list_count = blockcount; - return returnCount; //[Skotlex] + return returnCount; } -/*========================================== -* For what I get -* Move bl and do func* with va_list while moving. -* Mouvement is set by dx dy wich are distance in x and y -*------------------------------------------*/ -int map_foreachinmovearea(int (*func)(struct block_list*,va_list), struct block_list* center, int16 range, int16 dx, int16 dy, int type, ...) +/** + * Checks if bl is inside area that was in range cells from the center + * before it was moved by (dx,dy) cells, but it is not in range cells + * from center after movement is completed. + * In other words, checks if bl is inside area that is no longer covered + * by center's range. + * Preliminary range selection is already done in bl_getall_area. + * @return 1 if matches, 0 otherwise + */ +static int bl_vgetall_inmovearea(struct block_list *bl, va_list args) { - int bx, by, m; - int returnCount = 0; //total sum of returned values of func() [Skotlex] - struct block_list *bl; - int blockcount = bl_list_count, i; - int x0, x1, y0, y1; - va_list ap; + int dx = va_arg(args, int); + int dy = va_arg(args, int); + struct block_list *center = va_arg(args, struct block_list*); + int range = va_arg(args, int); + + if ((dx > 0 && bl->x < center->x - range + dx) || + (dx < 0 && bl->x > center->x + range + dx) || + (dy > 0 && bl->y < center->y - range + dy) || + (dy < 0 && bl->y > center->y + range + dy)) + return 1; + return 0; +} - if ( !range ) return 0; - if ( !dx && !dy ) return 0; //No movement. +/** + * Applies func to every block_list object of bl_type type in + * area that was covered by range cells from center, but is no + * longer after center is moved by (dx,dy) cells (i.e. area that + * center has lost sight of). + * If used after center has reached its destination and with + * opposed movement vector (-dx,-dy), selection corresponds + * to new area in center's view). + * Uses rectangular area. + * Returns the sum of values returned by func. + * @param func Function to be applied + * @param center Center of the selection area + * @param range Range in cells from center + * @param dx Center's movement on X-axis + * @param dy Center's movement on Y-axis + * @param type enum bl_type + * @param ap Extra arguments for func + * @return Sum of the values returned by func + */ +int map_vforeachinmovearea(int (*func)(struct block_list*, va_list), struct block_list* center, int16 range, int16 dx, int16 dy, int type, va_list ap) { + int returnCount = 0; + int blockcount = map->bl_list_count; + int m, x0, x1, y0, y1; + va_list apcopy; + + if (!range) return 0; + if (!dx && !dy) return 0; // No movement. + + if (range < 0) range *= -1; m = center->m; - x0 = center->x - range; x1 = center->x + range; y0 = center->y - range; y1 = center->y + range; - if ( x1 < x0 ) - swap(x0, x1); - if ( y1 < y0 ) - swap(y0, y1); - - if( dx == 0 || dy == 0 ) { - //Movement along one axis only. - if( dx == 0 ){ - if( dy < 0 ) //Moving south - y0 = y1 + dy + 1; - else //North - y1 = y0 + dy - 1; + if (dx == 0 || dy == 0) { // Movement along one axis only. + if (dx == 0) { + if (dy < 0) { y0 = y1 + dy + 1; } // Moving south + else { y1 = y0 + dy - 1; } // North } else { //dy == 0 - if( dx < 0 ) //West - x0 = x1 + dx + 1; - else //East - x1 = x0 + dx - 1; - } - - x0 = max(x0, 0); - y0 = max(y0, 0); - x1 = min(x1, map[ m ].xs - 1); - y1 = min(y1, map[ m ].ys - 1); - - for( by = y0 / BLOCK_SIZE; by <= y1 / BLOCK_SIZE; by++ ) { - for( bx = x0 / BLOCK_SIZE; bx <= x1 / BLOCK_SIZE; bx++ ) { - if ( type&~BL_MOB ) { - for( bl = map[m].block[ bx + by * map[ m ].bxs ]; bl != NULL; bl = bl->next ) { - if( bl->type&type && - bl->x >= x0 && bl->x <= x1 && - bl->y >= y0 && bl->y <= y1 && - bl_list_count < BL_LIST_MAX ) - bl_list[ bl_list_count++ ] = bl; - } - } - if ( type&BL_MOB ) { - for( bl = map[ m ].block_mob[ bx + by * map[ m ].bxs ]; bl != NULL; bl = bl->next ) { - if( bl->x >= x0 && bl->x <= x1 && - bl->y >= y0 && bl->y <= y1 && - bl_list_count < BL_LIST_MAX ) - bl_list[ bl_list_count++ ] = bl; - } - } - } - } - } else { // Diagonal movement - - x0 = max(x0, 0); - y0 = max(y0, 0); - x1 = min(x1, map[ m ].xs - 1); - y1 = min(y1, map[ m ].ys - 1); - - for( by = y0 / BLOCK_SIZE; by <= y1 / BLOCK_SIZE; by++ ) { - for( bx = x0 / BLOCK_SIZE; bx <= x1 / BLOCK_SIZE; bx++ ) { - if ( type & ~BL_MOB ) { - for( bl = map[ m ].block[ bx + by * map[ m ].bxs ]; bl != NULL; bl = bl->next ) { - if( bl->type&type && - bl->x >= x0 && bl->x <= x1 && - bl->y >= y0 && bl->y <= y1 && - bl_list_count < BL_LIST_MAX ) - if( ( dx > 0 && bl->x < x0 + dx) || - ( dx < 0 && bl->x > x1 + dx) || - ( dy > 0 && bl->y < y0 + dy) || - ( dy < 0 && bl->y > y1 + dy) ) - bl_list[ bl_list_count++ ] = bl; - } - } - if ( type&BL_MOB ) { - for( bl = map[ m ].block_mob[ bx + by * map[ m ].bxs ]; bl != NULL; bl = bl->next ) { - if( bl->x >= x0 && bl->x <= x1 && - bl->y >= y0 && bl->y <= y1 && - bl_list_count < BL_LIST_MAX) - if( ( dx > 0 && bl->x < x0 + dx) || - ( dx < 0 && bl->x > x1 + dx) || - ( dy > 0 && bl->y < y0 + dy) || - ( dy < 0 && bl->y > y1 + dy) ) - bl_list[ bl_list_count++ ] = bl; - } - } - } + if (dx < 0) { x0 = x1 + dx + 1; } // West + else { x1 = x0 + dx - 1; } // East } - + bl_getall_area(type, m, x0, y0, x1, y1, NULL); + } + else { // Diagonal movement + bl_getall_area(type, m, x0, y0, x1, y1, bl_vgetall_inmovearea, dx, dy, center, range); } - if( bl_list_count >= BL_LIST_MAX ) - ShowWarning("map_foreachinmovearea: block count too many!\n"); + va_copy(apcopy, ap); + returnCount = bl_vforeach(func, blockcount, INT_MAX, apcopy); + va_end(apcopy); - iMap->freeblock_lock(); // Prohibit the release from memory + return returnCount; +} - for( i = blockcount; i < bl_list_count; i++ ) - if( bl_list[ i ]->prev ) { //func() may delete this bl_list[] slot, checking for prev ensures it wasnt queued for deletion. - va_start(ap, type); - returnCount += func(bl_list[ i ], ap); - va_end(ap); - } +/** + * Applies func to every block_list object of bl_type type in + * area that was covered by range cells from center, but is no + * longer after center is moved by (dx,dy) cells (i.e. area that + * center has lost sight of). + * If used after center has reached its destination and with + * opposed movement vector (-dx,-dy), selection corresponds + * to new area in center's view). + * Uses rectangular area. + * Returns the sum of values returned by func. + * @see map_vforeachinmovearea + * @param func Function to be applied + * @param center Center of the selection area + * @param range Range in cells from center + * @param dx Center's movement on X-axis + * @param dy Center's movement on Y-axis + * @param type enum bl_type + * @param ... Extra arguments for func + * @return Sum of the values returned by func + */ +int map_foreachinmovearea(int (*func)(struct block_list*, va_list), struct block_list* center, int16 range, int16 dx, int16 dy, int type, ...) { + int returnCount; + va_list ap; - iMap->freeblock_unlock(); // Allow Free + va_start(ap, type); + returnCount = map->vforeachinmovearea(func, center, range, dx, dy, type, ap); + va_end(ap); - bl_list_count = blockcount; - return returnCount; + return returnCount; } -// -- moonsoul (added map_foreachincell which is a rework of map_foreachinarea but -// which only checks the exact single x/y passed to it rather than an -// area radius - may be more useful in some instances) -// -int map_foreachincell(int (*func)(struct block_list*,va_list), int16 m, int16 x, int16 y, int type, ...) -{ - int bx, by; - int returnCount = 0; //total sum of returned values of func() [Skotlex] - struct block_list *bl; - int blockcount = bl_list_count, i; +/** + * Applies func to every block_list object of bl_type type in + * cell (x,y) on map m. + * Returns the sum of values returned by func. + * @param func Function to be applied + * @param m Map id + * @param x Target cell X-coordinate + * @param y Target cell Y-coordinate + * @param type enum bl_type + * @param ap Extra arguments for func + * @return Sum of the values returned by func + */ +int map_vforeachincell(int (*func)(struct block_list*, va_list), int16 m, int16 x, int16 y, int type, va_list ap) { + int returnCount = 0; + int blockcount = map->bl_list_count; + va_list apcopy; + + bl_getall_area(type, m, x, y, x, y, NULL); + + va_copy(apcopy, ap); + returnCount = bl_vforeach(func, blockcount, INT_MAX, apcopy); + va_end(apcopy); + + return returnCount; +} + +/** + * Applies func to every block_list object of bl_type type in + * cell (x,y) on map m. + * Returns the sum of values returned by func. + * @param func Function to be applied + * @param m Map id + * @param x Target cell X-coordinate + * @param y Target cell Y-coordinate + * @param type enum bl_type + * @param ... Extra arguments for func + * @return Sum of the values returned by func + */ +int map_foreachincell(int (*func)(struct block_list*, va_list), int16 m, int16 x, int16 y, int type, ...) { + int returnCount; va_list ap; - if ( x < 0 || y < 0 || x >= map[ m ].xs || y >= map[ m ].ys ) return 0; + va_start(ap, type); + returnCount = map->vforeachincell(func, m, x, y, type, ap); + va_end(ap); - by = y / BLOCK_SIZE; - bx = x / BLOCK_SIZE; + return returnCount; +} - if( type&~BL_MOB ) - for( bl = map[ m ].block[ bx + by * map[ m ].bxs ]; bl != NULL; bl = bl->next ) - if( bl->type&type && bl->x == x && bl->y == y && bl_list_count < BL_LIST_MAX ) - bl_list[ bl_list_count++ ] = bl; - if( type&BL_MOB ) - for( bl = map[ m ].block_mob[ bx + by * map[ m ].bxs]; bl != NULL; bl = bl->next ) - if( bl->x == x && bl->y == y && bl_list_count < BL_LIST_MAX) - bl_list[ bl_list_count++ ] = bl; +/** + * Helper function for map_foreachinpath() + * Checks if shortest distance from bl to path + * between (x0,y0) and (x1,y1) is shorter than range. + * @see map_foreachinpath + */ +static int bl_vgetall_inpath(struct block_list *bl, va_list args) +{ + int m = va_arg(args, int); + int x0 = va_arg(args, int); + int y0 = va_arg(args, int); + int x1 = va_arg(args, int); + int y1 = va_arg(args, int); + int range = va_arg(args, int); + int len_limit = va_arg(args, int); + int magnitude2 = va_arg(args, int); + + int xi = bl->x; + int yi = bl->y; + int xu, yu; + + int k = ( xi - x0 ) * ( x1 - x0 ) + ( yi - y0 ) * ( y1 - y0 ); + + if ( k < 0 || k > len_limit ) //Since more skills use this, check for ending point as well. + return 0; - if( bl_list_count >= BL_LIST_MAX ) - ShowWarning("map_foreachincell: block count too many!\n"); + if ( k > magnitude2 && !path->search_long(NULL, m, x0, y0, xi, yi, CELL_CHKWALL) ) + return 0; //Targets beyond the initial ending point need the wall check. - iMap->freeblock_lock(); + //All these shifts are to increase the precision of the intersection point and distance considering how it's + //int math. + k = ( k << 4 ) / magnitude2; //k will be between 1~16 instead of 0~1 + xi <<= 4; + yi <<= 4; + xu = ( x0 << 4 ) + k * ( x1 - x0 ); + yu = ( y0 << 4 ) + k * ( y1 - y0 ); - for( i = blockcount; i < bl_list_count; i++ ) - if( bl_list[ i ]->prev ) { //func() may delete this bl_list[] slot, checking for prev ensures it wasnt queued for deletion. - va_start(ap, type); - returnCount += func(bl_list[ i ], ap); - va_end(ap); - } +//Avoid needless calculations by not getting the sqrt right away. +#define MAGNITUDE2(x0, y0, x1, y1) ( ( ( x1 ) - ( x0 ) ) * ( ( x1 ) - ( x0 ) ) + ( ( y1 ) - ( y0 ) ) * ( ( y1 ) - ( y0 ) ) ) - iMap->freeblock_unlock(); + k = MAGNITUDE2(xi, yi, xu, yu); - bl_list_count = blockcount; - return returnCount; + //If all dot coordinates were <<4 the square of the magnitude is <<8 + if ( k > range ) + return 0; + + return 1; } -/*============================================================ -* For checking a path between two points (x0, y0) and (x1, y1) -*------------------------------------------------------------*/ -int map_foreachinpath(int (*func)(struct block_list*,va_list),int16 m,int16 x0,int16 y0,int16 x1,int16 y1,int16 range,int length, int type,...) -{ - int returnCount = 0; //total sum of returned values of func() [Skotlex] - ////////////////////////////////////////////////////////////// - // - // sharp shooting 3 [Skotlex] - // - ////////////////////////////////////////////////////////////// - // problem: - // Same as Sharp Shooting 1. Hits all targets within range of - // the line. - // (t1,t2 t3 and t4 get hit) - // - // target 1 - // x t4 - // t2 - // t3 x - // x - // S - ////////////////////////////////////////////////////////////// - // Methodology: - // My trigonometrics and math are a little rusty... so the approach I am writing - // here is basicly do a double for to check for all targets in the square that +/** + * Applies func to every block_list object of bl_type type in + * path on a line between (x0,y0) and (x1,y1) on map m. + * Path starts at (x0,y0) and is \a length cells long and \a range cells wide. + * Objects beyond the initial (x1,y1) ending point are checked + * for walls in the path. + * Returns the sum of values returned by func. + * @param func Function to be applied + * @param m Map id + * @param x Target cell X-coordinate + * @param y Target cell Y-coordinate + * @param type enum bl_type + * @param ap Extra arguments for func + * @return Sum of the values returned by func + */ +int map_vforeachinpath(int (*func)(struct block_list*, va_list), int16 m, int16 x0, int16 y0, int16 x1, int16 y1, int16 range, int length, int type, va_list ap) { + // [Skotlex] + // check for all targets in the square that // contains the initial and final positions (area range increased to match the // radius given), then for each object to test, calculate the distance to the // path and include it if the range fits and the target is in the line (0<k<1, // as they call it). // The implementation I took as reference is found at - // http://astronomy.swin.edu.au/~pbourke/geometry/pointline/ - // (they have a link to a C implementation, too) - // This approach is a lot like #2 commented on this function, which I have no - // idea why it was commented. I won't use doubles/floats, but pure int math for + // http://web.archive.org/web/20050720125314/http://astronomy.swin.edu.au/~pbourke/geometry/pointline/ + // http://paulbourke.net/geometry/pointlineplane/ + // I won't use doubles/floats, but pure int math for // speed purposes. The range considered is always the same no matter how // close/far the target is because that's how SharpShooting works currently in - // kRO. + // kRO + + int returnCount = 0; + int blockcount = map->bl_list_count; + va_list apcopy; - //Generic map_foreach* variables. - int i, blockcount = bl_list_count; - struct block_list *bl; - int bx, by; //method specific variables int magnitude2, len_limit; //The square of the magnitude - int k, xi, yi, xu, yu; + int k; int mx0 = x0, mx1 = x1, my0 = y0, my1 = y1; - va_list ap; - - //Avoid needless calculations by not getting the sqrt right away. -#define MAGNITUDE2(x0, y0, x1, y1) ( ( ( x1 ) - ( x0 ) ) * ( ( x1 ) - ( x0 ) ) + ( ( y1 ) - ( y0 ) ) * ( ( y1 ) - ( y0 ) ) ) - - if ( m < 0 ) - return 0; len_limit = magnitude2 = MAGNITUDE2(x0, y0, x1, y1); - if ( magnitude2 < 1 ) //Same begin and ending point, can't trace path. + if (magnitude2 < 1) //Same begin and ending point, can't trace path. return 0; - if ( length ) { //Adjust final position to fit in the given area. + if (length) { //Adjust final position to fit in the given area. //TODO: Find an alternate method which does not requires a square root calculation. k = (int)sqrt((float)magnitude2); mx1 = x0 + (x1 - x0) * length / k; @@ -1047,7 +1237,7 @@ int map_foreachinpath(int (*func)(struct block_list*,va_list),int16 m,int16 x0,i len_limit = MAGNITUDE2(x0, y0, mx1, my1); } //Expand target area to cover range. - if ( mx0 > mx1 ) { + if (mx0 > mx1) { mx0 += range; mx1 -= range; } else { @@ -1061,191 +1251,46 @@ int map_foreachinpath(int (*func)(struct block_list*,va_list),int16 m,int16 x0,i my0 -= range; my1 += range; } - - //The two fors assume mx0 < mx1 && my0 < my1 - if ( mx0 > mx1 ) - swap(mx0, mx1); - if ( my0 > my1 ) - swap(my0, my1); - - mx0 = max(mx0, 0); - my0 = max(my0, 0); - mx1 = min(mx1, map[ m ].xs - 1); - my1 = min(my1, map[ m ].ys - 1); - range *= range << 8; //Values are shifted later on for higher precision using int math. - if ( type&~BL_MOB ) - for ( by = my0 / BLOCK_SIZE; by <= my1 / BLOCK_SIZE; by++ ) { - for( bx = mx0 / BLOCK_SIZE; bx <= mx1 / BLOCK_SIZE; bx++ ) { - for( bl = map[ m ].block[ bx + by * map[ m ].bxs ]; bl != NULL; bl = bl->next ) { - if( bl->prev && bl->type&type && bl_list_count < BL_LIST_MAX ) { - xi = bl->x; - yi = bl->y; - - k = ( xi - x0 ) * ( x1 - x0 ) + ( yi - y0 ) * ( y1 - y0 ); - - if ( k < 0 || k > len_limit ) //Since more skills use this, check for ending point as well. - continue; + bl_getall_area(type, m, mx0, my0, mx1, my1, bl_vgetall_inpath, m, x0, y0, x1, y1, range, len_limit, magnitude2); - if ( k > magnitude2 && !path_search_long(NULL, m, x0, y0, xi, yi, CELL_CHKWALL) ) - continue; //Targets beyond the initial ending point need the wall check. - - //All these shifts are to increase the precision of the intersection point and distance considering how it's - //int math. - k = ( k << 4 ) / magnitude2; //k will be between 1~16 instead of 0~1 - xi <<= 4; - yi <<= 4; - xu = ( x0 << 4 ) + k * ( x1 - x0 ); - yu = ( y0 << 4 ) + k * ( y1 - y0 ); - k = MAGNITUDE2(xi, yi, xu, yu); - - //If all dot coordinates were <<4 the square of the magnitude is <<8 - if ( k > range ) - continue; - - bl_list[ bl_list_count++ ] = bl; - } - } - } - } - if( type&BL_MOB ) - for( by = my0 / BLOCK_SIZE; by <= my1 / BLOCK_SIZE; by++ ) { - for( bx = mx0 / BLOCK_SIZE; bx <= mx1 / BLOCK_SIZE; bx++ ) { - for( bl = map[ m ].block_mob[ bx + by * map[ m ].bxs ]; bl != NULL; bl = bl->next ) { - if( bl->prev && bl_list_count < BL_LIST_MAX ) { - xi = bl->x; - yi = bl->y; - k = ( xi - x0 ) * ( x1 - x0 ) + ( yi - y0 ) * ( y1 - y0 ); - - if ( k < 0 || k > len_limit ) - continue; - - if ( k > magnitude2 && !path_search_long(NULL, m, x0, y0, xi, yi, CELL_CHKWALL) ) - continue; //Targets beyond the initial ending point need the wall check. - - k = ( k << 4 ) / magnitude2; //k will be between 1~16 instead of 0~1 - xi <<= 4; - yi <<= 4; - xu = ( x0 << 4 ) + k * ( x1 - x0 ); - yu = ( y0 << 4 ) + k * ( y1 - y0 ); - k = MAGNITUDE2(xi, yi, xu, yu); - - //If all dot coordinates were <<4 the square of the magnitude is <<8 - if ( k > range ) - continue; - - bl_list[ bl_list_count++ ] = bl; - } - } - } - } - - if( bl_list_count >= BL_LIST_MAX ) - ShowWarning("map_foreachinpath: block count too many!\n"); - - iMap->freeblock_lock(); - - for( i = blockcount; i < bl_list_count; i++ ) - if( bl_list[ i ]->prev ) { //func() may delete this bl_list[] slot, checking for prev ensures it wasnt queued for deletion. - va_start(ap, type); - returnCount += func(bl_list[ i ], ap); - va_end(ap); - } - - iMap->freeblock_unlock(); - - bl_list_count = blockcount; - return returnCount; //[Skotlex] + va_copy(apcopy, ap); + returnCount = bl_vforeach(func, blockcount, INT_MAX, apcopy); + va_end(apcopy); + return returnCount; } +#undef MAGNITUDE2 -// Copy of map_foreachincell, but applied to the whole map. [Skotlex] -int map_foreachinmap(int (*func)(struct block_list*,va_list), int16 m, int type,...) { - int b, bsize; - int returnCount = 0; //total sum of returned values of func() [Skotlex] - struct block_list *bl; - int blockcount = bl_list_count, i; - va_list ap; - - bsize = map[ m ].bxs * map[ m ].bys; - - if( type&~BL_MOB ) - for( b = 0; b < bsize; b++ ) - for( bl = map[ m ].block[ b ]; bl != NULL; bl = bl->next ) - if( bl->type&type && bl_list_count < BL_LIST_MAX ) - bl_list[ bl_list_count++ ] = bl; - - if( type&BL_MOB ) - for( b = 0; b < bsize; b++ ) - for( bl = map[ m ].block_mob[ b ]; bl != NULL; bl = bl->next ) - if( bl_list_count < BL_LIST_MAX ) - bl_list[ bl_list_count++ ] = bl; - - if( bl_list_count >= BL_LIST_MAX ) - ShowWarning("map_foreachinmap: block count too many!\n"); - - iMap->freeblock_lock(); - - for( i = blockcount; i < bl_list_count ; i++ ) - if( bl_list[ i ]->prev ) { //func() may delete this bl_list[] slot, checking for prev ensures it wasnt queued for deletion. - va_start(ap, type); - returnCount += func(bl_list[ i ], ap); - va_end(ap); - } - - iMap->freeblock_unlock(); - - bl_list_count = blockcount; - return returnCount; -} -// Copy of map_foreachinmap, but applied to all maps in a instance id. [Ind/Hercules] -int map_foreachininstance(int (*func)(struct block_list*,va_list), int16 instance_id, int type,...) { - int b, bsize; - int returnCount = 0; //total sum of returned values of func() [Skotlex] - struct block_list *bl; - int blockcount = bl_list_count, i, j; - int16 m; +/** + * Applies func to every block_list object of bl_type type in + * path on a line between (x0,y0) and (x1,y1) on map m. + * Path starts at (x0,y0) and is \a length cells long and \a range cells wide. + * Objects beyond the initial (x1,y1) ending point are checked + * for walls in the path. + * Returns the sum of values returned by func. + * @see map_vforeachinpath + * @param func Function to be applied + * @param m Map id + * @param x Target cell X-coordinate + * @param y Target cell Y-coordinate + * @param type enum bl_type + * @param ... Extra arguments for func + * @return Sum of the values returned by func + */ +int map_foreachinpath(int (*func)(struct block_list*, va_list), int16 m, int16 x0, int16 y0, int16 x1, int16 y1, int16 range, int length, int type, ...) { + int returnCount; va_list ap; - for( j = 0; j < instances[instance_id].num_map; j++ ) { - - m = instances[instance_id].map[j]; - - bsize = map[ m ].bxs * map[ m ].bys; - - if( type&~BL_MOB ) - for( b = 0; b < bsize; b++ ) - for( bl = map[ m ].block[ b ]; bl != NULL; bl = bl->next ) - if( bl->type&type && bl_list_count < BL_LIST_MAX ) - bl_list[ bl_list_count++ ] = bl; - - if( type&BL_MOB ) - for( b = 0; b < bsize; b++ ) - for( bl = map[ m ].block_mob[ b ]; bl != NULL; bl = bl->next ) - if( bl_list_count < BL_LIST_MAX ) - bl_list[ bl_list_count++ ] = bl; - - if( bl_list_count >= BL_LIST_MAX ) - ShowWarning("map_foreachininstance: block count too many!\n"); - - iMap->freeblock_lock(); + va_start(ap, type); + returnCount = map->vforeachinpath(func, m, x0, y0, x1, y1, range, length, type, ap); + va_end(ap); - for( i = blockcount; i < bl_list_count ; i++ ) - if( bl_list[ i ]->prev ) { //func() may delete this bl_list[] slot, checking for prev ensures it wasnt queued for deletion. - va_start(ap, type); - returnCount += func(bl_list[ i ], ap); - va_end(ap); - } - - iMap->freeblock_unlock(); - - } - - bl_list_count = blockcount; return returnCount; } +/** @} */ /// Generates a new flooritem object id from the interval [MIN_FLOORITEM, MAX_FLOORITEM). /// Used for floor items, skill units and chatroom objects. @@ -1261,7 +1306,7 @@ int map_get_new_object_id(void) if( i == MAX_FLOORITEM ) i = MIN_FLOORITEM; - if( !idb_exists(id_db, i) ) + if( !idb_exists(map->id_db, i) ) break; ++i; @@ -1279,12 +1324,11 @@ int map_get_new_object_id(void) } /*========================================== -* Timered function to clear the floor (remove remaining item) -* Called each flooritem_lifetime ms -*------------------------------------------*/ -int map_clearflooritem_timer(int tid, unsigned int tick, int id, intptr_t data) -{ - struct flooritem_data* fitem = (struct flooritem_data*)idb_get(id_db, id); + * Timered function to clear the floor (remove remaining item) + * Called each flooritem_lifetime ms + *------------------------------------------*/ +int map_clearflooritem_timer(int tid, int64 tick, int id, intptr_t data) { + struct flooritem_data* fitem = (struct flooritem_data*)idb_get(map->id_db, id); if (fitem == NULL || fitem->bl.type != BL_ITEM || (fitem->cleartimer != tid)) { ShowError("map_clearflooritem_timer : error\n"); @@ -1292,50 +1336,50 @@ int map_clearflooritem_timer(int tid, unsigned int tick, int id, intptr_t data) } - if (search_petDB_index(fitem->item_data.nameid, PET_EGG) >= 0) - intif_delete_petdata(MakeDWord(fitem->item_data.card[1], fitem->item_data.card[2])); + if (pet->search_petDB_index(fitem->item_data.nameid, PET_EGG) >= 0) + intif->delete_petdata(MakeDWord(fitem->item_data.card[1], fitem->item_data.card[2])); clif->clearflooritem(fitem, 0); - iMap->deliddb(&fitem->bl); - iMap->delblock(&fitem->bl); - iMap->freeblock(&fitem->bl); + map->deliddb(&fitem->bl); + map->delblock(&fitem->bl); + map->freeblock(&fitem->bl); return 0; } /* -* clears a single bl item out of the bazooonga. -*/ + * clears a single bl item out of the bazooonga. + */ void map_clearflooritem(struct block_list *bl) { struct flooritem_data* fitem = (struct flooritem_data*)bl; - if( fitem->cleartimer ) - iTimer->delete_timer(fitem->cleartimer,iMap->clearflooritem_timer); + if( fitem->cleartimer != INVALID_TIMER ) + timer->delete(fitem->cleartimer,map->clearflooritem_timer); clif->clearflooritem(fitem, 0); - iMap->deliddb(&fitem->bl); - iMap->delblock(&fitem->bl); - iMap->freeblock(&fitem->bl); + map->deliddb(&fitem->bl); + map->delblock(&fitem->bl); + map->freeblock(&fitem->bl); } /*========================================== -* (m,x,y) locates a random available free cell around the given coordinates -* to place an BL_ITEM object. Scan area is 9x9, returns 1 on success. -* x and y are modified with the target cell when successful. -*------------------------------------------*/ + * (m,x,y) locates a random available free cell around the given coordinates + * to place an BL_ITEM object. Scan area is 9x9, returns 1 on success. + * x and y are modified with the target cell when successful. + *------------------------------------------*/ int map_searchrandfreecell(int16 m,int16 *x,int16 *y,int stack) { int free_cell,i,j; int free_cells[9][2]; for(free_cell=0,i=-1;i<=1;i++){ - if(i+*y<0 || i+*y>=map[m].ys) + if(i+*y<0 || i+*y>=map->list[m].ys) continue; for(j=-1;j<=1;j++){ - if(j+*x<0 || j+*x>=map[m].xs) + if(j+*x<0 || j+*x>=map->list[m].xs) continue; - if(iMap->getcell(m,j+*x,i+*y,CELL_CHKNOPASS) && !iMap->getcell(m,j+*x,i+*y,CELL_CHKICEWALL)) + if(map->getcell(m,j+*x,i+*y,CELL_CHKNOPASS) && !map->getcell(m,j+*x,i+*y,CELL_CHKICEWALL)) continue; //Avoid item stacking to prevent against exploits. [Skotlex] - if(stack && iMap->count_oncell(m,j+*x,i+*y, BL_ITEM) > stack) + if(stack && map->count_oncell(m,j+*x,i+*y, BL_ITEM) > stack) continue; free_cells[free_cell][0] = j+*x; free_cells[free_cell++][1] = i+*y; @@ -1350,23 +1394,22 @@ int map_searchrandfreecell(int16 m,int16 *x,int16 *y,int stack) { } -static int map_count_sub(struct block_list *bl,va_list ap) -{ +int map_count_sub(struct block_list *bl,va_list ap) { return 1; } /*========================================== -* Locates a random spare cell around the object given, using range as max -* distance from that spot. Used for warping functions. Use range < 0 for -* whole map range. -* Returns 1 on success. when it fails and src is available, x/y are set to src's -* src can be null as long as flag&1 -* when ~flag&1, m is not needed. -* Flag values: -* &1 = random cell must be around given m,x,y, not around src -* &2 = the target should be able to walk to the target tile. -* &4 = there shouldn't be any players around the target tile (use the no_spawn_on_player setting) -*------------------------------------------*/ + * Locates a random spare cell around the object given, using range as max + * distance from that spot. Used for warping functions. Use range < 0 for + * whole map range. + * Returns 1 on success. when it fails and src is available, x/y are set to src's + * src can be null as long as flag&1 + * when ~flag&1, m is not needed. + * Flag values: + * &1 = random cell must be around given m,x,y, not around src + * &2 = the target should be able to walk to the target tile. + * &4 = there shouldn't be any players around the target tile (use the no_spawn_on_player setting) + *------------------------------------------*/ int map_search_freecell(struct block_list *src, int16 m, int16 *x,int16 *y, int16 rx, int16 ry, int flag) { int tries, spawn=0; @@ -1392,35 +1435,33 @@ int map_search_freecell(struct block_list *src, int16 m, int16 *x,int16 *y, int1 //No range? Return the target cell then.... *x = bx; *y = by; - return iMap->getcell(m,*x,*y,CELL_CHKREACH); + return map->getcell(m,*x,*y,CELL_CHKREACH); } if (rx >= 0 && ry >= 0) { tries = rx2*ry2; if (tries > 100) tries = 100; } else { - tries = map[m].xs*map[m].ys; + tries = map->list[m].xs*map->list[m].ys; if (tries > 500) tries = 500; } while(tries--) { - *x = (rx >= 0)?(rnd()%rx2-rx+bx):(rnd()%(map[m].xs-2)+1); - *y = (ry >= 0)?(rnd()%ry2-ry+by):(rnd()%(map[m].ys-2)+1); + *x = (rx >= 0)?(rnd()%rx2-rx+bx):(rnd()%(map->list[m].xs-2)+1); + *y = (ry >= 0)?(rnd()%ry2-ry+by):(rnd()%(map->list[m].ys-2)+1); if (*x == bx && *y == by) continue; //Avoid picking the same target tile. - if (iMap->getcell(m,*x,*y,CELL_CHKREACH)) - { - if(flag&2 && !unit_can_reach_pos(src, *x, *y, 1)) + if (map->getcell(m,*x,*y,CELL_CHKREACH)) { + if(flag&2 && !unit->can_reach_pos(src, *x, *y, 1)) continue; if(flag&4) { if (spawn >= 100) return 0; //Limit of retries reached. - if (spawn++ < battle_config.no_spawn_on_player && - map_foreachinarea(map_count_sub, m, - *x-AREA_SIZE, *y-AREA_SIZE, - *x+AREA_SIZE, *y+AREA_SIZE, BL_PC) - ) + if (spawn++ < battle_config.no_spawn_on_player + && map->foreachinarea(map->count_sub, m, *x-AREA_SIZE, *y-AREA_SIZE, + *x+AREA_SIZE, *y+AREA_SIZE, BL_PC) + ) continue; } return 1; @@ -1432,14 +1473,14 @@ int map_search_freecell(struct block_list *src, int16 m, int16 *x,int16 *y, int1 } /*========================================== -* Add an item to location (m,x,y) -* Parameters -* @item_data item attributes -* @amount quantity -* @m, @x, @y mapid,x,y -* @first_charid, @second_charid, @third_charid, looting priority -* @flag: &1 MVP item. &2 do stacking check. -*------------------------------------------*/ + * Add an item to location (m,x,y) + * Parameters + * @item_data item attributes + * @amount quantity + * @m, @x, @y mapid,x,y + * @first_charid, @second_charid, @third_charid, looting priority + * @flag: &1 MVP item. &2 do stacking check. + *------------------------------------------*/ int map_addflooritem(struct item *item_data,int amount,int16 m,int16 x,int16 y,int first_charid,int second_charid,int third_charid,int flags) { int r; @@ -1447,24 +1488,25 @@ int map_addflooritem(struct item *item_data,int amount,int16 m,int16 x,int16 y,i nullpo_ret(item_data); - if(!map_searchrandfreecell(m,&x,&y,flags&2?1:0)) + if(!map->searchrandfreecell(m,&x,&y,flags&2?1:0)) return 0; r=rnd(); - CREATE(fitem, struct flooritem_data, 1); - fitem->bl.type=BL_ITEM; + fitem = ers_alloc(map->flooritem_ers, struct flooritem_data); + + fitem->bl.type = BL_ITEM; fitem->bl.prev = fitem->bl.next = NULL; - fitem->bl.m=m; - fitem->bl.x=x; - fitem->bl.y=y; - fitem->bl.id = iMap->get_new_object_id(); + fitem->bl.m = m; + fitem->bl.x = x; + fitem->bl.y = y; + fitem->bl.id = map->get_new_object_id(); if(fitem->bl.id==0){ - aFree(fitem); + ers_free(map->flooritem_ers, fitem); return 0; } fitem->first_get_charid = first_charid; - fitem->first_get_tick = iTimer->gettick() + (flags&1 ? battle_config.mvp_item_first_get_time : battle_config.item_first_get_time); + fitem->first_get_tick = timer->gettick() + (flags&1 ? battle_config.mvp_item_first_get_time : battle_config.item_first_get_time); fitem->second_get_charid = second_charid; fitem->second_get_tick = fitem->first_get_tick + (flags&1 ? battle_config.mvp_item_second_get_time : battle_config.item_second_get_time); fitem->third_get_charid = third_charid; @@ -1474,19 +1516,19 @@ int map_addflooritem(struct item *item_data,int amount,int16 m,int16 x,int16 y,i fitem->item_data.amount=amount; fitem->subx=(r&3)*3+3; fitem->suby=((r>>2)&3)*3+3; - fitem->cleartimer=iTimer->add_timer(iTimer->gettick()+battle_config.flooritem_lifetime,iMap->clearflooritem_timer,fitem->bl.id,0); + fitem->cleartimer=timer->add(timer->gettick()+battle_config.flooritem_lifetime,map->clearflooritem_timer,fitem->bl.id,0); - iMap->addiddb(&fitem->bl); - iMap->addblock(&fitem->bl); + map->addiddb(&fitem->bl); + map->addblock(&fitem->bl); clif->dropflooritem(fitem); return fitem->bl.id; } /** -* @see DBCreateData -*/ -static DBData create_charid2nick(DBKey key, va_list args) + * @see DBCreateData + */ +DBData create_charid2nick(DBKey key, va_list args) { struct charid2nick *p; CREATE(p, struct charid2nick, 1); @@ -1501,16 +1543,16 @@ void map_addnickdb(int charid, const char* nick) struct charid_request* req; struct map_session_data* sd; - if( iMap->charid2sd(charid) ) + if( map->charid2sd(charid) ) return;// already online - p = idb_ensure(nick_db, charid, create_charid2nick); + p = idb_ensure(map->nick_db, charid, map->create_charid2nick); safestrncpy(p->nick, nick, sizeof(p->nick)); while( p->requests ) { req = p->requests; p->requests = req->next; - sd = iMap->charid2sd(req->charid); + sd = map->charid2sd(req->charid); if( sd ) clif->solved_charname(sd->fd, charid, p->nick); aFree(req); @@ -1526,13 +1568,13 @@ void map_delnickdb(int charid, const char* name) struct map_session_data* sd; DBData data; - if (!nick_db->remove(nick_db, DB->i2key(charid), &data) || (p = DB->data2ptr(&data)) == NULL) + if (!map->nick_db->remove(map->nick_db, DB->i2key(charid), &data) || (p = DB->data2ptr(&data)) == NULL) return; while( p->requests ) { req = p->requests; p->requests = req->next; - sd = iMap->charid2sd(req->charid); + sd = map->charid2sd(req->charid); if( sd ) clif->solved_charname(sd->fd, charid, name); aFree(req); @@ -1551,13 +1593,13 @@ void map_reqnickdb(struct map_session_data * sd, int charid) nullpo_retv(sd); - tsd = iMap->charid2sd(charid); + tsd = map->charid2sd(charid); if( tsd ) { clif->solved_charname(sd->fd, charid, tsd->status.name); return; } - p = idb_ensure(nick_db, charid, create_charid2nick); + p = idb_ensure(map->nick_db, charid, map->create_charid2nick); if( *p->nick ) { clif->solved_charname(sd->fd, charid, p->nick); return; @@ -1566,12 +1608,12 @@ void map_reqnickdb(struct map_session_data * sd, int charid) CREATE(req, struct charid_request, 1); req->next = p->requests; p->requests = req; - chrif_searchcharid(charid); + chrif->searchcharid(charid); } /*========================================== -* add bl to id_db -*------------------------------------------*/ + * add bl to id_db + *------------------------------------------*/ void map_addiddb(struct block_list *bl) { nullpo_retv(bl); @@ -1579,27 +1621,27 @@ void map_addiddb(struct block_list *bl) if( bl->type == BL_PC ) { TBL_PC* sd = (TBL_PC*)bl; - idb_put(pc_db,sd->bl.id,sd); - idb_put(charid_db,sd->status.char_id,sd); + idb_put(map->pc_db,sd->bl.id,sd); + idb_put(map->charid_db,sd->status.char_id,sd); } else if( bl->type == BL_MOB ) { TBL_MOB* md = (TBL_MOB*)bl; - idb_put(mobid_db,bl->id,bl); + idb_put(map->mobid_db,bl->id,bl); if( md->state.boss ) - idb_put(bossid_db, bl->id, bl); + idb_put(map->bossid_db, bl->id, bl); } if( bl->type & BL_REGEN ) - idb_put(regen_db, bl->id, bl); + idb_put(map->regen_db, bl->id, bl); - idb_put(id_db,bl->id,bl); + idb_put(map->id_db,bl->id,bl); } /*========================================== -* remove bl from id_db -*------------------------------------------*/ + * remove bl from id_db + *------------------------------------------*/ void map_deliddb(struct block_list *bl) { nullpo_retv(bl); @@ -1607,68 +1649,76 @@ void map_deliddb(struct block_list *bl) if( bl->type == BL_PC ) { TBL_PC* sd = (TBL_PC*)bl; - idb_remove(pc_db,sd->bl.id); - idb_remove(charid_db,sd->status.char_id); + idb_remove(map->pc_db,sd->bl.id); + idb_remove(map->charid_db,sd->status.char_id); } else if( bl->type == BL_MOB ) { - idb_remove(mobid_db,bl->id); - idb_remove(bossid_db,bl->id); + idb_remove(map->mobid_db,bl->id); + idb_remove(map->bossid_db,bl->id); } if( bl->type & BL_REGEN ) - idb_remove(regen_db,bl->id); + idb_remove(map->regen_db,bl->id); - idb_remove(id_db,bl->id); + idb_remove(map->id_db,bl->id); } /*========================================== -* Standard call when a player connection is closed. -*------------------------------------------*/ + * Standard call when a player connection is closed. + *------------------------------------------*/ int map_quit(struct map_session_data *sd) { int i; if(!sd->state.active) { //Removing a player that is not active. - struct auth_node *node = chrif_search(sd->status.account_id); + struct auth_node *node = chrif->search(sd->status.account_id); if (node && node->char_id == sd->status.char_id && node->state != ST_LOGOUT) //Except when logging out, clear the auth-connect data immediately. - chrif_auth_delete(node->account_id, node->char_id, node->state); + chrif->auth_delete(node->account_id, node->char_id, node->state); //Non-active players should not have loaded any data yet (or it was cleared already) so no additional cleanups are needed. return 0; } + + if( sd->expiration_tid != INVALID_TIMER ) + timer->delete(sd->expiration_tid,pc->expiration_timer); if (sd->npc_timer_id != INVALID_TIMER) //Cancel the event timer. - npc_timerevent_quit(sd); + npc->timerevent_quit(sd); if (sd->npc_id) - npc_event_dequeue(sd); + npc->event_dequeue(sd); + + if( sd->bg_id && !sd->bg_queue.arena ) /* TODO: dump this chunk after bg_queue is fully enabled */ + bg->team_leave(sd,BGTL_QUIT); - if( sd->bg_id ) - bg_team_leave(sd,1); + if( sd->state.autotrade && runflag != MAPSERVER_ST_SHUTDOWN && !hChSys.closing ) + pc->autotrade_update(sd,PAUC_REMOVE); + skill->cooldown_save(sd); pc->itemcd_do(sd,false); for( i = 0; i < sd->queues_count; i++ ) { struct hQueue *queue; if( (queue = script->queue(sd->queues[i])) && queue->onLogOut[0] != '\0' ) { - npc_event(sd, queue->onLogOut, 0); + npc->event(sd, queue->onLogOut, 0); } } /* two times, the npc event above may assign a new one or delete others */ for( i = 0; i < sd->queues_count; i++ ) { - script->queue_remove(sd->queues[i],sd->status.account_id); + if( sd->queues[i] != -1 ) + script->queue_remove(sd->queues[i],sd->status.account_id); } - npc_script_event(sd, NPCE_LOGOUT); + npc->script_event(sd, NPCE_LOGOUT); //Unit_free handles clearing the player related data, - //iMap->quit handles extra specific data which is related to quitting normally - //(changing map-servers invokes unit_free but bypasses iMap->quit) + //map->quit handles extra specific data which is related to quitting normally + //(changing map-servers invokes unit_free but bypasses map->quit) if( sd->sc.count ) { //Status that are not saved... for(i=0; i < SC_MAX; i++){ - if ( status_get_sc_type(i)&SC_NO_SAVE ){ + if ( status->get_sc_type(i)&SC_NO_SAVE ) { if ( !sd->sc.data[i] ) continue; switch( i ){ @@ -1690,34 +1740,32 @@ int map_quit(struct map_session_data *sd) { } // Return loot to owner - if( sd->pd ) pet_lootitem_drop(sd->pd, sd); + if( sd->pd ) pet->lootitem_drop(sd->pd, sd); if( sd->state.storage_flag == 1 ) sd->state.storage_flag = 0; // No need to Double Save Storage on Quit. - if (sd->state.permanent_speed == 1) sd->state.permanent_speed = 0; // Remove lock so speed is set back to normal at login. - if( sd->ed ) { - elemental_clean_effect(sd->ed); - unit_remove_map(&sd->ed->bl,CLR_TELEPORT); + elemental->clean_effect(sd->ed); + unit->remove_map(&sd->ed->bl,CLR_TELEPORT,ALC_MARK); } - if( hChSys.local && map[sd->bl.m].channel && idb_exists(map[sd->bl.m].channel->users, sd->status.char_id) ) { - clif->chsys_left(map[sd->bl.m].channel,sd); + if( hChSys.local && map->list[sd->bl.m].channel && idb_exists(map->list[sd->bl.m].channel->users, sd->status.char_id) ) { + clif->chsys_left(map->list[sd->bl.m].channel,sd); } clif->chsys_quit(sd); - unit_remove_map_pc(sd,CLR_TELEPORT); + unit->remove_map_pc(sd,CLR_RESPAWN); - if( map[sd->bl.m].instance_id >= 0 ) { // Avoid map conflicts and warnings on next login + if( map->list[sd->bl.m].instance_id >= 0 ) { // Avoid map conflicts and warnings on next login int16 m; struct point *pt; - if( map[sd->bl.m].save.map ) - pt = &map[sd->bl.m].save; + if( map->list[sd->bl.m].save.map ) + pt = &map->list[sd->bl.m].save; else pt = &sd->status.save_point; - if( (m=iMap->mapindex2mapid(pt->map)) >= 0 ) { + if( (m=map->mapindex2mapid(pt->map)) >= 0 ) { sd->bl.m = m; sd->bl.x = pt->x; sd->bl.y = pt->y; @@ -1725,86 +1773,84 @@ int map_quit(struct map_session_data *sd) { } } + if( sd->state.vending ) { + idb_remove(vending->db, sd->status.char_id); + } + party->booking_delete(sd); // Party Booking [Spiria] pc->makesavestatus(sd); pc->clean_skilltree(sd); - chrif_save(sd,1); - unit_free_pc(sd); + chrif->save(sd,1); + unit->free_pc(sd); return 0; } /*========================================== -* Lookup, id to session (player,mob,npc,homon,merc..) -*------------------------------------------*/ -struct map_session_data * map_id2sd(int id) -{ + * Lookup, id to session (player,mob,npc,homon,merc..) + *------------------------------------------*/ +struct map_session_data *map_id2sd(int id) { if (id <= 0) return NULL; - return (struct map_session_data*)idb_get(pc_db,id); + return (struct map_session_data*)idb_get(map->pc_db,id); } -struct mob_data * map_id2md(int id) -{ +struct mob_data *map_id2md(int id) { if (id <= 0) return NULL; - return (struct mob_data*)idb_get(mobid_db,id); + return (struct mob_data*)idb_get(map->mobid_db,id); } -struct npc_data * map_id2nd(int id) -{// just a id2bl lookup because there's no npc_db - struct block_list* bl = iMap->id2bl(id); +struct npc_data *map_id2nd(int id) { + // just a id2bl lookup because there's no npc_db + struct block_list* bl = map->id2bl(id); return BL_CAST(BL_NPC, bl); } -struct homun_data* map_id2hd(int id) -{ - struct block_list* bl = iMap->id2bl(id); +struct homun_data *map_id2hd(int id) { + struct block_list* bl = map->id2bl(id); return BL_CAST(BL_HOM, bl); } -struct mercenary_data* map_id2mc(int id) -{ - struct block_list* bl = iMap->id2bl(id); +struct mercenary_data *map_id2mc(int id) { + struct block_list* bl = map->id2bl(id); return BL_CAST(BL_MER, bl); } -struct chat_data* map_id2cd(int id) -{ - struct block_list* bl = iMap->id2bl(id); +struct chat_data *map_id2cd(int id) { + struct block_list* bl = map->id2bl(id); return BL_CAST(BL_CHAT, bl); } /// Returns the nick of the target charid or NULL if unknown (requests the nick to the char server). -const char* map_charid2nick(int charid) -{ +const char *map_charid2nick(int charid) { struct charid2nick *p; struct map_session_data* sd; - sd = iMap->charid2sd(charid); + sd = map->charid2sd(charid); if( sd ) return sd->status.name;// character is online, return it's name - p = idb_ensure(nick_db, charid, create_charid2nick); + p = idb_ensure(map->nick_db, charid, map->create_charid2nick); if( *p->nick ) return p->nick;// name in nick_db - chrif_searchcharid(charid);// request the name + chrif->searchcharid(charid);// request the name return NULL; } /// Returns the struct map_session_data of the charid or NULL if the char is not online. struct map_session_data* map_charid2sd(int charid) { - return (struct map_session_data*)idb_get(charid_db, charid); + return (struct map_session_data*)idb_get(map->charid_db, charid); } /*========================================== -* Search session data from a nick name -* (without sensitive case if necessary) -* return map_session_data pointer or NULL -*------------------------------------------*/ + * Search session data from a nick name + * (without sensitive case if necessary) + * return map_session_data pointer or NULL + *------------------------------------------*/ struct map_session_data * map_nick2sd(const char *nick) { struct map_session_data* sd; @@ -1852,29 +1898,29 @@ struct map_session_data * map_nick2sd(const char *nick) } /*========================================== -* Looksup id_db DBMap and returns BL pointer of 'id' or NULL if not found -*------------------------------------------*/ + * Looksup id_db DBMap and returns BL pointer of 'id' or NULL if not found + *------------------------------------------*/ struct block_list * map_id2bl(int id) { - return (struct block_list*)idb_get(id_db,id); + return (struct block_list*)idb_get(map->id_db,id); } /** -* Same as iMap->id2bl except it only checks for its existence -**/ + * Same as map->id2bl except it only checks for its existence + **/ bool map_blid_exists( int id ) { - return (idb_exists(id_db,id)); + return (idb_exists(map->id_db,id)); } /*========================================== -* Convext Mirror -*------------------------------------------*/ + * Convext Mirror + *------------------------------------------*/ struct mob_data * map_getmob_boss(int16 m) { DBIterator* iter; struct mob_data *md = NULL; bool found = false; - iter = db_iterator(bossid_db); + iter = db_iterator(map->bossid_db); for( md = (struct mob_data*)dbi_first(iter); dbi_exists(iter); md = (struct mob_data*)dbi_next(iter) ) { if( md->bl.m == m ) @@ -1891,71 +1937,88 @@ struct mob_data * map_getmob_boss(int16 m) struct mob_data * map_id2boss(int id) { if (id <= 0) return NULL; - return (struct mob_data*)idb_get(bossid_db,id); + return (struct mob_data*)idb_get(map->bossid_db,id); } /// Applies func to all the players in the db. /// Stops iterating if func returns -1. -void map_map_foreachpc(int (*func)(struct map_session_data* sd, va_list args), ...) { +void map_vforeachpc(int (*func)(struct map_session_data* sd, va_list args), va_list args) { DBIterator* iter; struct map_session_data* sd; - iter = db_iterator(pc_db); + iter = db_iterator(map->pc_db); for( sd = dbi_first(iter); dbi_exists(iter); sd = dbi_next(iter) ) { - va_list args; + va_list argscopy; int ret; - va_start(args, func); - ret = func(sd, args); - va_end(args); + va_copy(argscopy, args); + ret = func(sd, argscopy); + va_end(argscopy); if( ret == -1 ) break;// stop iterating } dbi_destroy(iter); } +/// Applies func to all the players in the db. +/// Stops iterating if func returns -1. +/// @see map_vforeachpc +void map_foreachpc(int (*func)(struct map_session_data* sd, va_list args), ...) { + va_list args; + + va_start(args, func); + map->vforeachpc(func, args); + va_end(args); +} + /// Applies func to all the mobs in the db. /// Stops iterating if func returns -1. -void map_map_foreachmob(int (*func)(struct mob_data* md, va_list args), ...) -{ +void map_vforeachmob(int (*func)(struct mob_data* md, va_list args), va_list args) { DBIterator* iter; struct mob_data* md; - iter = db_iterator(mobid_db); - for( md = (struct mob_data*)dbi_first(iter); dbi_exists(iter); md = (struct mob_data*)dbi_next(iter) ) - { - va_list args; + iter = db_iterator(map->mobid_db); + for( md = (struct mob_data*)dbi_first(iter); dbi_exists(iter); md = (struct mob_data*)dbi_next(iter) ) { + va_list argscopy; int ret; - va_start(args, func); - ret = func(md, args); - va_end(args); + va_copy(argscopy, args); + ret = func(md, argscopy); + va_end(argscopy); if( ret == -1 ) break;// stop iterating } dbi_destroy(iter); } +/// Applies func to all the mobs in the db. +/// Stops iterating if func returns -1. +/// @see map_vforeachmob +void map_foreachmob(int (*func)(struct mob_data* md, va_list args), ...) { + va_list args; + + va_start(args, func); + map->vforeachmob(func, args); + va_end(args); +} + /// Applies func to all the npcs in the db. /// Stops iterating if func returns -1. -void map_map_foreachnpc(int (*func)(struct npc_data* nd, va_list args), ...) -{ +void map_vforeachnpc(int (*func)(struct npc_data* nd, va_list args), va_list args) { DBIterator* iter; struct block_list* bl; - iter = db_iterator(id_db); - for( bl = (struct block_list*)dbi_first(iter); dbi_exists(iter); bl = (struct block_list*)dbi_next(iter) ) - { - if( bl->type == BL_NPC ) - { + iter = db_iterator(map->id_db); + for( bl = (struct block_list*)dbi_first(iter); dbi_exists(iter); bl = (struct block_list*)dbi_next(iter) ) { + if( bl->type == BL_NPC ) { struct npc_data* nd = (struct npc_data*)bl; - va_list args; + va_list argscopy; int ret; - va_start(args, func); - ret = func(nd, args); - va_end(args); + va_copy(argscopy, args); + ret = func(nd, argscopy); + va_end(argscopy); if( ret == -1 ) break;// stop iterating } @@ -1963,22 +2026,31 @@ void map_map_foreachnpc(int (*func)(struct npc_data* nd, va_list args), ...) dbi_destroy(iter); } +/// Applies func to all the npcs in the db. +/// Stops iterating if func returns -1. +/// @see map_vforeachnpc +void map_foreachnpc(int (*func)(struct npc_data* nd, va_list args), ...) { + va_list args; + + va_start(args, func); + map->vforeachnpc(func, args); + va_end(args); +} + /// Applies func to everything in the db. -/// Stops iteratin gif func returns -1. -void map_map_foreachregen(int (*func)(struct block_list* bl, va_list args), ...) -{ +/// Stops iterating gif func returns -1. +void map_vforeachregen(int (*func)(struct block_list* bl, va_list args), va_list args) { DBIterator* iter; struct block_list* bl; - iter = db_iterator(regen_db); - for( bl = (struct block_list*)dbi_first(iter); dbi_exists(iter); bl = (struct block_list*)dbi_next(iter) ) - { - va_list args; + iter = db_iterator(map->regen_db); + for( bl = (struct block_list*)dbi_first(iter); dbi_exists(iter); bl = (struct block_list*)dbi_next(iter) ) { + va_list argscopy; int ret; - va_start(args, func); - ret = func(bl, args); - va_end(args); + va_copy(argscopy, args); + ret = func(bl, argscopy); + va_end(argscopy); if( ret == -1 ) break;// stop iterating } @@ -1986,27 +2058,47 @@ void map_map_foreachregen(int (*func)(struct block_list* bl, va_list args), ...) } /// Applies func to everything in the db. +/// Stops iterating gif func returns -1. +/// @see map_vforeachregen +void map_foreachregen(int (*func)(struct block_list* bl, va_list args), ...) { + va_list args; + + va_start(args, func); + map->vforeachregen(func, args); + va_end(args); +} + +/// Applies func to everything in the db. /// Stops iterating if func returns -1. -void map_map_foreachiddb(int (*func)(struct block_list* bl, va_list args), ...) -{ +void map_vforeachiddb(int (*func)(struct block_list* bl, va_list args), va_list args) { DBIterator* iter; struct block_list* bl; - iter = db_iterator(id_db); - for( bl = (struct block_list*)dbi_first(iter); dbi_exists(iter); bl = (struct block_list*)dbi_next(iter) ) - { - va_list args; + iter = db_iterator(map->id_db); + for( bl = (struct block_list*)dbi_first(iter); dbi_exists(iter); bl = (struct block_list*)dbi_next(iter) ) { + va_list argscopy; int ret; - va_start(args, func); - ret = func(bl, args); - va_end(args); + va_copy(argscopy, args); + ret = func(bl, argscopy); + va_end(argscopy); if( ret == -1 ) break;// stop iterating } dbi_destroy(iter); } +/// Applies func to everything in the db. +/// Stops iterating if func returns -1. +/// @see map_vforeachiddb +void map_foreachiddb(int (*func)(struct block_list* bl, va_list args), ...) { + va_list args; + + va_start(args, func); + map->vforeachiddb(func, args); + va_end(args); +} + /// Iterator. /// Can filter by bl type. struct s_mapiterator @@ -2022,9 +2114,7 @@ struct s_mapiterator /// @param _bl_ block_list /// @return true if it matches #define MAPIT_MATCHES(_mapit_,_bl_) \ - ( \ - ( (_bl_)->type & (_mapit_)->types /* type matches */ ) \ - ) + ( (_bl_)->type & (_mapit_)->types /* type matches */ ) /// Allocates a new iterator. /// Returns the new iterator. @@ -2034,44 +2124,40 @@ struct s_mapiterator /// @param flags Flags of the iterator /// @param type Target types /// @return Iterator -struct s_mapiterator* mapit_alloc(enum e_mapitflags flags, enum bl_type types) -{ - struct s_mapiterator* mapit; +struct s_mapiterator* mapit_alloc(enum e_mapitflags flags, enum bl_type types) { + struct s_mapiterator* iter; - mapit = ers_alloc(map_iterator_ers, struct s_mapiterator); - mapit->flags = flags; - mapit->types = types; - if( types == BL_PC ) mapit->dbi = db_iterator(pc_db); - else if( types == BL_MOB ) mapit->dbi = db_iterator(mobid_db); - else mapit->dbi = db_iterator(id_db); - return mapit; + iter = ers_alloc(map->iterator_ers, struct s_mapiterator); + iter->flags = flags; + iter->types = types; + if( types == BL_PC ) iter->dbi = db_iterator(map->pc_db); + else if( types == BL_MOB ) iter->dbi = db_iterator(map->mobid_db); + else iter->dbi = db_iterator(map->id_db); + return iter; } /// Frees the iterator. /// -/// @param mapit Iterator -void mapit_free(struct s_mapiterator* mapit) -{ - nullpo_retv(mapit); +/// @param iter Iterator +void mapit_free(struct s_mapiterator* iter) { + nullpo_retv(iter); - dbi_destroy(mapit->dbi); - ers_free(map_iterator_ers, mapit); + dbi_destroy(iter->dbi); + ers_free(map->iterator_ers, iter); } /// Returns the first block_list that matches the description. /// Returns NULL if not found. /// -/// @param mapit Iterator +/// @param iter Iterator /// @return first block_list or NULL -struct block_list* mapit_first(struct s_mapiterator* mapit) -{ +struct block_list* mapit_first(struct s_mapiterator* iter) { struct block_list* bl; - nullpo_retr(NULL,mapit); + nullpo_retr(NULL,iter); - for( bl = (struct block_list*)dbi_first(mapit->dbi); bl != NULL; bl = (struct block_list*)dbi_next(mapit->dbi) ) - { - if( MAPIT_MATCHES(mapit,bl) ) + for( bl = (struct block_list*)dbi_first(iter->dbi); bl != NULL; bl = (struct block_list*)dbi_next(iter->dbi) ) { + if( MAPIT_MATCHES(iter,bl) ) break;// found match } return bl; @@ -2080,17 +2166,15 @@ struct block_list* mapit_first(struct s_mapiterator* mapit) /// Returns the last block_list that matches the description. /// Returns NULL if not found. /// -/// @param mapit Iterator +/// @param iter Iterator /// @return last block_list or NULL -struct block_list* mapit_last(struct s_mapiterator* mapit) -{ +struct block_list* mapit_last(struct s_mapiterator* iter) { struct block_list* bl; - nullpo_retr(NULL,mapit); + nullpo_retr(NULL,iter); - for( bl = (struct block_list*)dbi_last(mapit->dbi); bl != NULL; bl = (struct block_list*)dbi_prev(mapit->dbi) ) - { - if( MAPIT_MATCHES(mapit,bl) ) + for( bl = (struct block_list*)dbi_last(iter->dbi); bl != NULL; bl = (struct block_list*)dbi_prev(iter->dbi) ) { + if( MAPIT_MATCHES(iter,bl) ) break;// found match } return bl; @@ -2099,20 +2183,18 @@ struct block_list* mapit_last(struct s_mapiterator* mapit) /// Returns the next block_list that matches the description. /// Returns NULL if not found. /// -/// @param mapit Iterator +/// @param iter Iterator /// @return next block_list or NULL -struct block_list* mapit_next(struct s_mapiterator* mapit) -{ +struct block_list* mapit_next(struct s_mapiterator* iter) { struct block_list* bl; - nullpo_retr(NULL,mapit); + nullpo_retr(NULL,iter); - for( ; ; ) - { - bl = (struct block_list*)dbi_next(mapit->dbi); + for( ; ; ) { + bl = (struct block_list*)dbi_next(iter->dbi); if( bl == NULL ) break;// end - if( MAPIT_MATCHES(mapit,bl) ) + if( MAPIT_MATCHES(iter,bl) ) break;// found a match // try next } @@ -2122,20 +2204,18 @@ struct block_list* mapit_next(struct s_mapiterator* mapit) /// Returns the previous block_list that matches the description. /// Returns NULL if not found. /// -/// @param mapit Iterator +/// @param iter Iterator /// @return previous block_list or NULL -struct block_list* mapit_prev(struct s_mapiterator* mapit) -{ +struct block_list* mapit_prev(struct s_mapiterator* iter) { struct block_list* bl; - nullpo_retr(NULL,mapit); + nullpo_retr(NULL,iter); - for( ; ; ) - { - bl = (struct block_list*)dbi_prev(mapit->dbi); + for( ; ; ) { + bl = (struct block_list*)dbi_prev(iter->dbi); if( bl == NULL ) break;// end - if( MAPIT_MATCHES(mapit,bl) ) + if( MAPIT_MATCHES(iter,bl) ) break;// found a match // try prev } @@ -2144,72 +2224,66 @@ struct block_list* mapit_prev(struct s_mapiterator* mapit) /// Returns true if the current block_list exists in the database. /// -/// @param mapit Iterator +/// @param iter Iterator /// @return true if it exists -bool mapit_exists(struct s_mapiterator* mapit) -{ - nullpo_retr(false,mapit); +bool mapit_exists(struct s_mapiterator* iter) { + nullpo_retr(false,iter); - return dbi_exists(mapit->dbi); + return dbi_exists(iter->dbi); } /*========================================== -* Add npc-bl to id_db, basically register npc to map -*------------------------------------------*/ + * Add npc-bl to id_db, basically register npc to map + *------------------------------------------*/ bool map_addnpc(int16 m,struct npc_data *nd) { nullpo_ret(nd); - if( m < 0 || m >= iMap->map_num ) + if( m < 0 || m >= map->count ) return false; - if( map[m].npc_num == MAX_NPC_PER_MAP ) - { - ShowWarning("too many NPCs in one map %s\n",map[m].name); + if( map->list[m].npc_num == MAX_NPC_PER_MAP ) { + ShowWarning("too many NPCs in one map %s\n",map->list[m].name); return false; } - map[m].npc[map[m].npc_num]=nd; - map[m].npc_num++; - idb_put(id_db,nd->bl.id,nd); + map->list[m].npc[map->list[m].npc_num]=nd; + map->list[m].npc_num++; + idb_put(map->id_db,nd->bl.id,nd); return true; } /*========================================= -* Dynamic Mobs [Wizputer] -*-----------------------------------------*/ + * Dynamic Mobs [Wizputer] + *-----------------------------------------*/ // Stores the spawn data entry in the mob list. // Returns the index of successful, or -1 if the list was full. -int map_addmobtolist(unsigned short m, struct spawn_data *spawn) -{ - size_t i; - ARR_FIND( 0, MAX_MOB_LIST_PER_MAP, i, map[m].moblist[i] == NULL ); +int map_addmobtolist(unsigned short m, struct spawn_data *spawn) { + int i; + ARR_FIND( 0, MAX_MOB_LIST_PER_MAP, i, map->list[m].moblist[i] == NULL ); if( i < MAX_MOB_LIST_PER_MAP ) { - map[m].moblist[i] = spawn; + map->list[m].moblist[i] = spawn; return i; } return -1; } -void map_spawnmobs(int16 m) -{ +void map_spawnmobs(int16 m) { int i, k=0; - if (map[m].mob_delete_timer != INVALID_TIMER) - { //Mobs have not been removed yet [Skotlex] - iTimer->delete_timer(map[m].mob_delete_timer, iMap->removemobs_timer); - map[m].mob_delete_timer = INVALID_TIMER; + if (map->list[m].mob_delete_timer != INVALID_TIMER) { + //Mobs have not been removed yet [Skotlex] + timer->delete(map->list[m].mob_delete_timer, map->removemobs_timer); + map->list[m].mob_delete_timer = INVALID_TIMER; return; } for(i=0; i<MAX_MOB_LIST_PER_MAP; i++) - if(map[m].moblist[i]!=NULL) - { - k+=map[m].moblist[i]->num; - npc_parse_mob2(map[m].moblist[i]); + if(map->list[m].moblist[i]!=NULL) { + k+=map->list[m].moblist[i]->num; + npc->parse_mob2(map->list[m].moblist[i]); } - if (battle_config.etc_log && k > 0) - { - ShowStatus("Map %s: Spawned '"CL_WHITE"%d"CL_RESET"' mobs.\n",map[m].name, k); - } + if (battle_config.etc_log && k > 0) { + ShowStatus("Map %s: Spawned '"CL_WHITE"%d"CL_RESET"' mobs.\n",map->list[m].name, k); + } } int map_removemobs_sub(struct block_list *bl, va_list ap) @@ -2234,73 +2308,71 @@ int map_removemobs_sub(struct block_list *bl, va_list ap) if( md->db->mexp > 0 ) return 0; - unit_free(&md->bl,CLR_OUTSIGHT); + unit->free(&md->bl,CLR_OUTSIGHT); return 1; } -int map_removemobs_timer(int tid, unsigned int tick, int id, intptr_t data) -{ +int map_removemobs_timer(int tid, int64 tick, int id, intptr_t data) { int count; const int16 m = id; - if (m < 0 || m >= iMap->map_num) { //Incorrect map id! + if (m < 0 || m >= map->count) { //Incorrect map id! ShowError("map_removemobs_timer error: timer %d points to invalid map %d\n",tid, m); return 0; } - if (map[m].mob_delete_timer != tid) { //Incorrect timer call! - ShowError("map_removemobs_timer mismatch: %d != %d (map %s)\n",map[m].mob_delete_timer, tid, map[m].name); + if (map->list[m].mob_delete_timer != tid) { //Incorrect timer call! + ShowError("map_removemobs_timer mismatch: %d != %d (map %s)\n",map->list[m].mob_delete_timer, tid, map->list[m].name); return 0; } - map[m].mob_delete_timer = INVALID_TIMER; - if (map[m].users > 0) //Map not empty! + map->list[m].mob_delete_timer = INVALID_TIMER; + if (map->list[m].users > 0) //Map not empty! return 1; - count = map_foreachinmap(map_removemobs_sub, m, BL_MOB); + count = map->foreachinmap(map->removemobs_sub, m, BL_MOB); if (battle_config.etc_log && count > 0) - ShowStatus("Map %s: Removed '"CL_WHITE"%d"CL_RESET"' mobs.\n",map[m].name, count); + ShowStatus("Map %s: Removed '"CL_WHITE"%d"CL_RESET"' mobs.\n",map->list[m].name, count); return 1; } -void map_removemobs(int16 m) -{ - if (map[m].mob_delete_timer != INVALID_TIMER) // should never happen +void map_removemobs(int16 m) { + if (map->list[m].mob_delete_timer != INVALID_TIMER) // should never happen return; //Mobs are already scheduled for removal - map[m].mob_delete_timer = iTimer->add_timer(iTimer->gettick()+battle_config.mob_remove_delay, iMap->removemobs_timer, m, 0); + map->list[m].mob_delete_timer = timer->add(timer->gettick()+battle_config.mob_remove_delay, map->removemobs_timer, m, 0); } /*========================================== -* Hookup, get map_id from map_name -*------------------------------------------*/ + * Hookup, get map_id from map_name + *------------------------------------------*/ int16 map_mapname2mapid(const char* name) { unsigned short map_index; - map_index = mapindex_name2id(name); + map_index = mapindex->name2id(name); if (!map_index) return -1; - return iMap->mapindex2mapid(map_index); + return map->mapindex2mapid(map_index); } /*========================================== -* Returns the map of the given mapindex. [Skotlex] -*------------------------------------------*/ -int16 map_mapindex2mapid(unsigned short mapindex) { + * Returns the map of the given mapindex. [Skotlex] + *------------------------------------------*/ +int16 map_mapindex2mapid(unsigned short map_index) { - if (!mapindex || mapindex > MAX_MAPINDEX) + if (!map_index || map_index > MAX_MAPINDEX) return -1; - return index2mapid[mapindex]; + return map->index2mapid[map_index]; } /*========================================== -* Switching Ip, port ? (like changing map_server) get ip/port from map_name -*------------------------------------------*/ + * Switching Ip, port ? (like changing map_server) get ip/port from map_name + *------------------------------------------*/ int map_mapname2ipport(unsigned short name, uint32* ip, uint16* port) { struct map_data_other_server *mdos; - mdos = (struct map_data_other_server*)uidb_get(map_db,(unsigned int)name); + mdos = (struct map_data_other_server*)uidb_get(map->map_db,(unsigned int)name); if(mdos==NULL || mdos->cell) //If gat isn't null, this is a local map. return -1; *ip=mdos->ip; @@ -2316,21 +2388,21 @@ int map_check_dir(int s_dir,int t_dir) if(s_dir == t_dir) return 0; switch(s_dir) { - case 0: if(t_dir == 7 || t_dir == 1 || t_dir == 0) return 0; break; - case 1: if(t_dir == 0 || t_dir == 2 || t_dir == 1) return 0; break; - case 2: if(t_dir == 1 || t_dir == 3 || t_dir == 2) return 0; break; - case 3: if(t_dir == 2 || t_dir == 4 || t_dir == 3) return 0; break; - case 4: if(t_dir == 3 || t_dir == 5 || t_dir == 4) return 0; break; - case 5: if(t_dir == 4 || t_dir == 6 || t_dir == 5) return 0; break; - case 6: if(t_dir == 5 || t_dir == 7 || t_dir == 6) return 0; break; - case 7: if(t_dir == 6 || t_dir == 0 || t_dir == 7) return 0; break; + case 0: if(t_dir == 7 || t_dir == 1 || t_dir == 0) return 0; break; + case 1: if(t_dir == 0 || t_dir == 2 || t_dir == 1) return 0; break; + case 2: if(t_dir == 1 || t_dir == 3 || t_dir == 2) return 0; break; + case 3: if(t_dir == 2 || t_dir == 4 || t_dir == 3) return 0; break; + case 4: if(t_dir == 3 || t_dir == 5 || t_dir == 4) return 0; break; + case 5: if(t_dir == 4 || t_dir == 6 || t_dir == 5) return 0; break; + case 6: if(t_dir == 5 || t_dir == 7 || t_dir == 6) return 0; break; + case 7: if(t_dir == 6 || t_dir == 0 || t_dir == 7) return 0; break; } return 1; } /*========================================== -* Returns the direction of the given cell, relative to 'src' -*------------------------------------------*/ + * Returns the direction of the given cell, relative to 'src' + *------------------------------------------*/ uint8 map_calc_dir(struct block_list* src, int16 x, int16 y) { uint8 dir = 0; @@ -2341,9 +2413,10 @@ uint8 map_calc_dir(struct block_list* src, int16 x, int16 y) dx = x-src->x; dy = y-src->y; if( dx == 0 && dy == 0 ) - { // both are standing on the same spot - //dir = 6; // aegis-style, makes knockback default to the left - dir = unit_getdir(src); // athena-style, makes knockback default to behind 'src' + { // both are standing on the same spot. + // aegis-style, makes knockback default to the left. + // athena-style, makes knockback default to behind 'src'. + dir = (battle_config.knockback_left ? 6 : unit->getdir(src)); } else if( dx >= 0 && dy >=0 ) { // upper-right @@ -2374,9 +2447,9 @@ uint8 map_calc_dir(struct block_list* src, int16 x, int16 y) } /*========================================== -* Randomizes target cell x,y to a random walkable cell that -* has the same distance from object as given coordinates do. [Skotlex] -*------------------------------------------*/ + * Randomizes target cell x,y to a random walkable cell that + * has the same distance from object as given coordinates do. [Skotlex] + *------------------------------------------*/ int map_random_dir(struct block_list *bl, int16 *x, int16 *y) { short xi = *x-bl->x; @@ -2394,9 +2467,8 @@ int map_random_dir(struct block_list *bl, int16 *x, int16 *y) xi = bl->x + segment*dirx[j]; segment = (short)sqrt((float)(dist2 - segment*segment)); //The complement of the previously picked segment yi = bl->y + segment*diry[j]; - } while ( - (iMap->getcell(bl->m,xi,yi,CELL_CHKNOPASS) || !path_search(NULL,bl->m,bl->x,bl->y,xi,yi,1,CELL_CHKNOREACH)) - && (++i)<100 ); + } while ( (map->getcell(bl->m,xi,yi,CELL_CHKNOPASS) || !path->search(NULL,bl->m,bl->x,bl->y,xi,yi,1,CELL_CHKNOREACH)) + && (++i)<100 ); if (i < 100) { *x = xi; @@ -2413,13 +2485,13 @@ inline static struct mapcell map_gat2cell(int gat) { memset(&cell,0,sizeof(struct mapcell)); switch( gat ) { - case 0: cell.walkable = 1; cell.shootable = 1; cell.water = 0; break; // walkable ground - case 1: cell.walkable = 0; cell.shootable = 0; cell.water = 0; break; // non-walkable ground - case 2: cell.walkable = 1; cell.shootable = 1; cell.water = 0; break; // ??? - case 3: cell.walkable = 1; cell.shootable = 1; cell.water = 1; break; // walkable water - case 4: cell.walkable = 1; cell.shootable = 1; cell.water = 0; break; // ??? - case 5: cell.walkable = 0; cell.shootable = 1; cell.water = 0; break; // gap (snipable) - case 6: cell.walkable = 1; cell.shootable = 1; cell.water = 0; break; // ??? + case 0: cell.walkable = 1; cell.shootable = 1; cell.water = 0; break; // walkable ground + case 1: cell.walkable = 0; cell.shootable = 0; cell.water = 0; break; // non-walkable ground + case 2: cell.walkable = 1; cell.shootable = 1; cell.water = 0; break; // ??? + case 3: cell.walkable = 1; cell.shootable = 1; cell.water = 1; break; // walkable water + case 4: cell.walkable = 1; cell.shootable = 1; cell.water = 0; break; // ??? + case 5: cell.walkable = 0; cell.shootable = 1; cell.water = 0; break; // gap (snipable) + case 6: cell.walkable = 1; cell.shootable = 1; cell.water = 0; break; // ??? default: ShowWarning("map_gat2cell: unrecognized gat type '%d'\n", gat); break; @@ -2428,7 +2500,7 @@ inline static struct mapcell map_gat2cell(int gat) { return cell; } -static int map_cell2gat(struct mapcell cell) { +int map_cell2gat(struct mapcell cell) { if( cell.walkable == 1 && cell.shootable == 1 && cell.water == 0 ) return 0; if( cell.walkable == 0 && cell.shootable == 0 && cell.water == 0 ) return 1; if( cell.walkable == 1 && cell.shootable == 1 && cell.water == 1 ) return 3; @@ -2437,8 +2509,6 @@ static int map_cell2gat(struct mapcell cell) { ShowWarning("map_cell2gat: cell has no matching gat type\n"); return 1; // default to 'wall' } -int map_getcellp(struct map_data* m,int16 x,int16 y,cell_chk cellchk); -void map_setcell(int16 m, int16 x, int16 y, cell_t cell, bool flag); void map_cellfromcache(struct map_data *m) { char decode_buffer[MAX_MAP_SIZE]; struct map_cache_map_info *info = NULL; @@ -2453,23 +2523,28 @@ void map_cellfromcache(struct map_data *m) { decode_zip(decode_buffer, &size, m->cellPos+sizeof(struct map_cache_map_info), info->len); CREATE(m->cell, struct mapcell, size); - for( xy = 0; xy < size; ++xy ) - m->cell[xy] = map_gat2cell(decode_buffer[xy]); + // Set cell properties + for( xy = 0; xy < size; ++xy ) { + m->cell[xy] = map->gat2cell(decode_buffer[xy]); +#ifdef CELL_NOSTACK + m->cell[xy].cell_bl = 0; +#endif + } - m->getcellp = map_getcellp; - m->setcell = map_setcell; + m->getcellp = map->getcellp; + m->setcell = map->setcell; for(i = 0; i < m->npc_num; i++) { - npc_setcells(m->npc[i]); + npc->setcells(m->npc[i]); } } } /*========================================== -* Confirm if celltype in (m,x,y) match the one given in cellchk -*------------------------------------------*/ + * Confirm if celltype in (m,x,y) match the one given in cellchk + *------------------------------------------*/ int map_getcell(int16 m,int16 x,int16 y,cell_chk cellchk) { - return (m < 0 || m >= iMap->map_num) ? 0 : map[m].getcellp(&map[m],x,y,cellchk); + return (m < 0 || m >= map->count) ? 0 : map->list[m].getcellp(&map->list[m],x,y,cellchk); } int map_getcellp(struct map_data* m,int16 x,int16 y,cell_chk cellchk) { @@ -2486,7 +2561,7 @@ int map_getcellp(struct map_data* m,int16 x,int16 y,cell_chk cellchk) { switch(cellchk) { // gat type retrieval case CELL_GETTYPE: - return map_cell2gat(cell); + return map->cell2gat(cell); // base gat type checks case CELL_CHKWALL: @@ -2510,8 +2585,6 @@ int map_getcellp(struct map_data* m,int16 x,int16 y,cell_chk cellchk) { return (cell.novending); case CELL_CHKNOCHAT: return (cell.nochat); - case CELL_CHKMAELSTROM: - return (cell.maelstrom); case CELL_CHKICEWALL: return (cell.icewall); @@ -2544,72 +2617,67 @@ int map_getcellp(struct map_data* m,int16 x,int16 y,cell_chk cellchk) { /* [Ind/Hercules] */ int map_sub_getcellp(struct map_data* m,int16 x,int16 y,cell_chk cellchk) { - iMap->cellfromcache(m); - m->getcellp = map_getcellp; - m->setcell = map_setcell; + map->cellfromcache(m); + m->getcellp = map->getcellp; + m->setcell = map->setcell; return m->getcellp(m,x,y,cellchk); } /*========================================== -* Change the type/flags of a map cell -* 'cell' - which flag to modify -* 'flag' - true = on, false = off -*------------------------------------------*/ + * Change the type/flags of a map cell + * 'cell' - which flag to modify + * 'flag' - true = on, false = off + *------------------------------------------*/ void map_setcell(int16 m, int16 x, int16 y, cell_t cell, bool flag) { int j; - if( m < 0 || m >= iMap->map_num || x < 0 || x >= map[m].xs || y < 0 || y >= map[m].ys ) + if( m < 0 || m >= map->count || x < 0 || x >= map->list[m].xs || y < 0 || y >= map->list[m].ys ) return; - j = x + y*map[m].xs; + j = x + y*map->list[m].xs; switch( cell ) { - case CELL_WALKABLE: map[m].cell[j].walkable = flag; break; - case CELL_SHOOTABLE: map[m].cell[j].shootable = flag; break; - case CELL_WATER: map[m].cell[j].water = flag; break; - - case CELL_NPC: map[m].cell[j].npc = flag; break; - case CELL_BASILICA: map[m].cell[j].basilica = flag; break; - case CELL_LANDPROTECTOR: map[m].cell[j].landprotector = flag; break; - case CELL_NOVENDING: map[m].cell[j].novending = flag; break; - case CELL_NOCHAT: map[m].cell[j].nochat = flag; break; - case CELL_MAELSTROM: map[m].cell[j].maelstrom = flag; break; - case CELL_ICEWALL: map[m].cell[j].icewall = flag; break; + case CELL_WALKABLE: map->list[m].cell[j].walkable = flag; break; + case CELL_SHOOTABLE: map->list[m].cell[j].shootable = flag; break; + case CELL_WATER: map->list[m].cell[j].water = flag; break; + + case CELL_NPC: map->list[m].cell[j].npc = flag; break; + case CELL_BASILICA: map->list[m].cell[j].basilica = flag; break; + case CELL_LANDPROTECTOR: map->list[m].cell[j].landprotector = flag; break; + case CELL_NOVENDING: map->list[m].cell[j].novending = flag; break; + case CELL_NOCHAT: map->list[m].cell[j].nochat = flag; break; + case CELL_ICEWALL: map->list[m].cell[j].icewall = flag; break; default: ShowWarning("map_setcell: invalid cell type '%d'\n", (int)cell); break; } } void map_sub_setcell(int16 m, int16 x, int16 y, cell_t cell, bool flag) { - - if( m < 0 || m >= iMap->map_num || x < 0 || x >= map[m].xs || y < 0 || y >= map[m].ys ) + if( m < 0 || m >= map->count || x < 0 || x >= map->list[m].xs || y < 0 || y >= map->list[m].ys ) return; - iMap->cellfromcache(&map[m]); - map[m].setcell = map_setcell; - map[m].getcellp = map_getcellp; - map[m].setcell(m,x,y,cell,flag); + map->cellfromcache(&map->list[m]); + map->list[m].setcell = map->setcell; + map->list[m].getcellp = map->getcellp; + map->list[m].setcell(m,x,y,cell,flag); } -void map_setgatcell(int16 m, int16 x, int16 y, int gat) -{ +void map_setgatcell(int16 m, int16 x, int16 y, int gat) { int j; struct mapcell cell; - if( m < 0 || m >= iMap->map_num || x < 0 || x >= map[m].xs || y < 0 || y >= map[m].ys ) + if( m < 0 || m >= map->count || x < 0 || x >= map->list[m].xs || y < 0 || y >= map->list[m].ys ) return; - j = x + y*map[m].xs; + j = x + y*map->list[m].xs; - cell = map_gat2cell(gat); - map[m].cell[j].walkable = cell.walkable; - map[m].cell[j].shootable = cell.shootable; - map[m].cell[j].water = cell.water; + cell = map->gat2cell(gat); + map->list[m].cell[j].walkable = cell.walkable; + map->list[m].cell[j].shootable = cell.shootable; + map->list[m].cell[j].water = cell.water; } /*========================================== * Invisible Walls *------------------------------------------*/ -static DBMap* iwall_db; - void map_iwall_nextxy(int16 x, int16 y, int8 dir, int pos, int16 *x1, int16 *y1) { if( dir == 0 || dir == 4 ) @@ -2636,10 +2704,10 @@ bool map_iwall_set(int16 m, int16 x, int16 y, int size, int8 dir, bool shootable if( size < 1 || !wall_name ) return false; - if( (iwall = (struct iwall_data *)strdb_get(iwall_db, wall_name)) != NULL ) + if( (iwall = (struct iwall_data *)strdb_get(map->iwall_db, wall_name)) != NULL ) return false; // Already Exists - if( iMap->getcell(m, x, y, CELL_CHKNOREACH) ) + if( map->getcell(m, x, y, CELL_CHKNOREACH) ) return false; // Starting cell problem CREATE(iwall, struct iwall_data, 1); @@ -2651,23 +2719,22 @@ bool map_iwall_set(int16 m, int16 x, int16 y, int size, int8 dir, bool shootable iwall->shootable = shootable; safestrncpy(iwall->wall_name, wall_name, sizeof(iwall->wall_name)); - for( i = 0; i < size; i++ ) - { - map_iwall_nextxy(x, y, dir, i, &x1, &y1); + for( i = 0; i < size; i++ ) { + map->iwall_nextxy(x, y, dir, i, &x1, &y1); - if( iMap->getcell(m, x1, y1, CELL_CHKNOREACH) ) + if( map->getcell(m, x1, y1, CELL_CHKNOREACH) ) break; // Collision - map[m].setcell(m, x1, y1, CELL_WALKABLE, false); - map[m].setcell(m, x1, y1, CELL_SHOOTABLE, shootable); + map->list[m].setcell(m, x1, y1, CELL_WALKABLE, false); + map->list[m].setcell(m, x1, y1, CELL_SHOOTABLE, shootable); - clif->changemapcell(0, m, x1, y1, iMap->getcell(m, x1, y1, CELL_GETTYPE), ALL_SAMEMAP); + clif->changemapcell(0, m, x1, y1, map->getcell(m, x1, y1, CELL_GETTYPE), ALL_SAMEMAP); } iwall->size = i; - strdb_put(iwall_db, iwall->wall_name, iwall); - map[m].iwall_num++; + strdb_put(map->iwall_db, iwall->wall_name, iwall); + map->list[m].iwall_num++; return true; } @@ -2678,17 +2745,17 @@ void map_iwall_get(struct map_session_data *sd) { int16 x1, y1; int i; - if( map[sd->bl.m].iwall_num < 1 ) + if( map->list[sd->bl.m].iwall_num < 1 ) return; - iter = db_iterator(iwall_db); + iter = db_iterator(map->iwall_db); for( iwall = dbi_first(iter); dbi_exists(iter); iwall = dbi_next(iter) ) { if( iwall->m != sd->bl.m ) continue; for( i = 0; i < iwall->size; i++ ) { - map_iwall_nextxy(iwall->x, iwall->y, iwall->dir, i, &x1, &y1); - clif->changemapcell(sd->fd, iwall->m, x1, y1, iMap->getcell(iwall->m, x1, y1, CELL_GETTYPE), SELF); + map->iwall_nextxy(iwall->x, iwall->y, iwall->dir, i, &x1, &y1); + clif->changemapcell(sd->fd, iwall->m, x1, y1, map->getcell(iwall->m, x1, y1, CELL_GETTYPE), SELF); } } dbi_destroy(iter); @@ -2699,49 +2766,49 @@ void map_iwall_remove(const char *wall_name) struct iwall_data *iwall; int16 i, x1, y1; - if( (iwall = (struct iwall_data *)strdb_get(iwall_db, wall_name)) == NULL ) + if( (iwall = (struct iwall_data *)strdb_get(map->iwall_db, wall_name)) == NULL ) return; // Nothing to do for( i = 0; i < iwall->size; i++ ) { - map_iwall_nextxy(iwall->x, iwall->y, iwall->dir, i, &x1, &y1); + map->iwall_nextxy(iwall->x, iwall->y, iwall->dir, i, &x1, &y1); - map[iwall->m].setcell(iwall->m, x1, y1, CELL_SHOOTABLE, true); - map[iwall->m].setcell(iwall->m, x1, y1, CELL_WALKABLE, true); + map->list[iwall->m].setcell(iwall->m, x1, y1, CELL_SHOOTABLE, true); + map->list[iwall->m].setcell(iwall->m, x1, y1, CELL_WALKABLE, true); - clif->changemapcell(0, iwall->m, x1, y1, iMap->getcell(iwall->m, x1, y1, CELL_GETTYPE), ALL_SAMEMAP); + clif->changemapcell(0, iwall->m, x1, y1, map->getcell(iwall->m, x1, y1, CELL_GETTYPE), ALL_SAMEMAP); } - map[iwall->m].iwall_num--; - strdb_remove(iwall_db, iwall->wall_name); + map->list[iwall->m].iwall_num--; + strdb_remove(map->iwall_db, iwall->wall_name); } /** -* @see DBCreateData -*/ -static DBData create_map_data_other_server(DBKey key, va_list args) + * @see DBCreateData + */ +DBData create_map_data_other_server(DBKey key, va_list args) { struct map_data_other_server *mdos; - unsigned short mapindex = (unsigned short)key.ui; + unsigned short map_index = (unsigned short)key.ui; mdos=(struct map_data_other_server *)aCalloc(1,sizeof(struct map_data_other_server)); - mdos->index = mapindex; - memcpy(mdos->name, mapindex_id2name(mapindex), MAP_NAME_LENGTH); + mdos->index = map_index; + memcpy(mdos->name, mapindex_id2name(map_index), MAP_NAME_LENGTH); return DB->ptr2data(mdos); } /*========================================== -* Add mapindex to db of another map server -*------------------------------------------*/ -int map_setipport(unsigned short mapindex, uint32 ip, uint16 port) + * Add mapindex to db of another map server + *------------------------------------------*/ +int map_setipport(unsigned short map_index, uint32 ip, uint16 port) { struct map_data_other_server *mdos; - mdos= uidb_ensure(map_db,(unsigned int)mapindex, create_map_data_other_server); + mdos= uidb_ensure(map->map_db,(unsigned int)map_index, map->create_map_data_other_server); if(mdos->cell) //Local map,Do nothing. Give priority to our own local maps over ones from another server. [Skotlex] return 0; if(ip == clif->map_ip && port == clif->map_port) { //That's odd, we received info that we are the ones with this map, but... we don't have it. - ShowFatalError("map_setipport : received info that this map-server SHOULD have map '%s', but it is not loaded.\n",mapindex_id2name(mapindex)); + ShowFatalError("map_setipport : received info that this map-server SHOULD have map '%s', but it is not loaded.\n",mapindex_id2name(map_index)); exit(EXIT_FAILURE); } mdos->ip = ip; @@ -2750,36 +2817,36 @@ int map_setipport(unsigned short mapindex, uint32 ip, uint16 port) } /** -* Delete all the other maps server management -* @see DBApply -*/ + * Delete all the other maps server management + * @see DBApply + */ int map_eraseallipport_sub(DBKey key, DBData *data, va_list va) { struct map_data_other_server *mdos = DB->data2ptr(data); if(mdos->cell == NULL) { - db_remove(map_db,key); + db_remove(map->map_db,key); aFree(mdos); } return 0; } int map_eraseallipport(void) { - map_db->foreach(map_db,map_eraseallipport_sub); + map->map_db->foreach(map->map_db,map->eraseallipport_sub); return 1; } /*========================================== -* Delete mapindex from db of another map server -*------------------------------------------*/ -int map_eraseipport(unsigned short mapindex, uint32 ip, uint16 port) { + * Delete mapindex from db of another map server + *------------------------------------------*/ +int map_eraseipport(unsigned short map_index, uint32 ip, uint16 port) { struct map_data_other_server *mdos; - mdos = (struct map_data_other_server*)uidb_get(map_db,(unsigned int)mapindex); + mdos = (struct map_data_other_server*)uidb_get(map->map_db,(unsigned int)map_index); if(!mdos || mdos->cell) //Map either does not exists or is a local map. return 0; if(mdos->ip==ip && mdos->port == port) { - uidb_remove(map_db,(unsigned int)mapindex); + uidb_remove(map->map_db,(unsigned int)map_index); aFree(mdos); return 1; } @@ -2787,10 +2854,10 @@ int map_eraseipport(unsigned short mapindex, uint32 ip, uint16 port) { } /*========================================== -* [Shinryo]: Init the mapcache -*------------------------------------------*/ -static char *map_init_mapcache(FILE *fp) -{ + * [Shinryo]: Init the mapcache + *------------------------------------------*/ +char *map_init_mapcache(FILE *fp) { + struct map_cache_main_header header; size_t size = 0; char *buffer; @@ -2811,6 +2878,21 @@ static char *map_init_mapcache(FILE *fp) // Read file into buffer.. if(fread(buffer, sizeof(char), size, fp) != size) { ShowError("map_init_mapcache: Could not read entire mapcache file\n"); + aFree(buffer); + return NULL; + } + + rewind(fp); + + // Get main header to verify if data is corrupted + if( fread(&header, sizeof(header), 1, fp) != 1 ) { + ShowError("map_init_mapcache: Error obtaining main header!\n"); + aFree(buffer); + return NULL; + } + if( GetULong((unsigned char *)&(header.file_size)) != size ) { + ShowError("map_init_mapcache: Map cache is corrupted!\n"); + aFree(buffer); return NULL; } @@ -2818,9 +2900,9 @@ static char *map_init_mapcache(FILE *fp) } /*========================================== -* Map cache reading -* [Shinryo]: Optimized some behaviour to speed this up -*==========================================*/ + * Map cache reading + * [Shinryo]: Optimized some behaviour to speed this up + *==========================================*/ int map_readfromcache(struct map_data *m, char *buffer) { int i; struct map_cache_main_header *header = (struct map_cache_main_header *)buffer; @@ -2862,16 +2944,16 @@ int map_readfromcache(struct map_data *m, char *buffer) { } -int map_addmap(char* mapname) { - map[iMap->map_num].instance_id = -1; - mapindex_getmapname(mapname, map[iMap->map_num++].name); +int map_addmap(const char* mapname) { + map->list[map->count].instance_id = -1; + mapindex->getmapname(mapname, map->list[map->count++].name); return 0; } -static void map_delmapid(int id) { - ShowNotice("Removing map [ %s ] from maplist"CL_CLL"\n",map[id].name); - memmove(map+id, map+id+1, sizeof(map[0])*(iMap->map_num-id-1)); - iMap->map_num--; +void map_delmapid(int id) { + ShowNotice("Removing map [ %s ] from maplist"CL_CLL"\n",map->list[id].name); + memmove(map->list+id, map->list+id+1, sizeof(map->list[0])*(map->count-id-1)); + map->count--; } int map_delmap(char* mapname) { @@ -2879,14 +2961,14 @@ int map_delmap(char* mapname) { char map_name[MAP_NAME_LENGTH]; if (strcmpi(mapname, "all") == 0) { - iMap->map_num = 0; + map->count = 0; return 0; } - mapindex_getmapname(mapname, map_name); - for(i = 0; i < iMap->map_num; i++) { - if (strcmp(map[i].name, map_name) == 0) { - map_delmapid(i); + mapindex->getmapname(mapname, map_name); + for(i = 0; i < map->count; i++) { + if (strcmp(map->list[i].name, map_name) == 0) { + map->delmapid(i); return 1; } } @@ -2896,7 +2978,7 @@ void map_zone_db_clear(void) { struct map_zone_data *zone; int i; - DBIterator *iter = db_iterator(zone_db); + DBIterator *iter = db_iterator(map->zone_db); for(zone = dbi_first(iter); dbi_exists(iter); zone = dbi_next(iter)) { for(i = 0; i < zone->disabled_skills_count; i++) { aFree(zone->disabled_skills[i]); @@ -2918,229 +3000,247 @@ void map_zone_db_clear(void) { } dbi_destroy(iter); - db_destroy(zone_db);/* will aFree(zone) */ + db_destroy(map->zone_db);/* will aFree(zone) */ /* clear the pk zone stuff */ - for(i = 0; i < map_zone_pk.disabled_skills_count; i++) { - aFree(map_zone_pk.disabled_skills[i]); + for(i = 0; i < map->zone_pk.disabled_skills_count; i++) { + aFree(map->zone_pk.disabled_skills[i]); } - aFree(map_zone_pk.disabled_skills); - aFree(map_zone_pk.disabled_items); - for(i = 0; i < map_zone_pk.mapflags_count; i++) { - aFree(map_zone_pk.mapflags[i]); + aFree(map->zone_pk.disabled_skills); + aFree(map->zone_pk.disabled_items); + for(i = 0; i < map->zone_pk.mapflags_count; i++) { + aFree(map->zone_pk.mapflags[i]); } - aFree(map_zone_pk.mapflags); - for(i = 0; i < map_zone_pk.disabled_commands_count; i++) { - aFree(map_zone_pk.disabled_commands[i]); + aFree(map->zone_pk.mapflags); + for(i = 0; i < map->zone_pk.disabled_commands_count; i++) { + aFree(map->zone_pk.disabled_commands[i]); } - aFree(map_zone_pk.disabled_commands); - for(i = 0; i < map_zone_pk.capped_skills_count; i++) { - aFree(map_zone_pk.capped_skills[i]); + aFree(map->zone_pk.disabled_commands); + for(i = 0; i < map->zone_pk.capped_skills_count; i++) { + aFree(map->zone_pk.capped_skills[i]); } - aFree(map_zone_pk.capped_skills); + aFree(map->zone_pk.capped_skills); /* clear the main zone stuff */ - for(i = 0; i < map_zone_all.disabled_skills_count; i++) { - aFree(map_zone_all.disabled_skills[i]); + for(i = 0; i < map->zone_all.disabled_skills_count; i++) { + aFree(map->zone_all.disabled_skills[i]); } - aFree(map_zone_all.disabled_skills); - aFree(map_zone_all.disabled_items); - for(i = 0; i < map_zone_all.mapflags_count; i++) { - aFree(map_zone_all.mapflags[i]); + aFree(map->zone_all.disabled_skills); + aFree(map->zone_all.disabled_items); + for(i = 0; i < map->zone_all.mapflags_count; i++) { + aFree(map->zone_all.mapflags[i]); } - aFree(map_zone_all.mapflags); - for(i = 0; i < map_zone_all.disabled_commands_count; i++) { - aFree(map_zone_all.disabled_commands[i]); + aFree(map->zone_all.mapflags); + for(i = 0; i < map->zone_all.disabled_commands_count; i++) { + aFree(map->zone_all.disabled_commands[i]); } - aFree(map_zone_all.disabled_commands); - for(i = 0; i < map_zone_all.capped_skills_count; i++) { - aFree(map_zone_all.capped_skills[i]); + aFree(map->zone_all.disabled_commands); + for(i = 0; i < map->zone_all.capped_skills_count; i++) { + aFree(map->zone_all.capped_skills[i]); } - aFree(map_zone_all.capped_skills); + aFree(map->zone_all.capped_skills); } void map_clean(int i) { int v; - if(map[i].cell && map[i].cell != (struct mapcell *)0xdeadbeaf) aFree(map[i].cell); - if(map[i].block) aFree(map[i].block); - if(map[i].block_mob) aFree(map[i].block_mob); + if(map->list[i].cell && map->list[i].cell != (struct mapcell *)0xdeadbeaf) aFree(map->list[i].cell); + if(map->list[i].block) aFree(map->list[i].block); + if(map->list[i].block_mob) aFree(map->list[i].block_mob); if(battle_config.dynamic_mobs) { //Dynamic mobs flag by [random] int j; - if(map[i].mob_delete_timer != INVALID_TIMER) - iTimer->delete_timer(map[i].mob_delete_timer, iMap->removemobs_timer); + if(map->list[i].mob_delete_timer != INVALID_TIMER) + timer->delete(map->list[i].mob_delete_timer, map->removemobs_timer); for (j=0; j<MAX_MOB_LIST_PER_MAP; j++) - if (map[i].moblist[j]) aFree(map[i].moblist[j]); + if (map->list[i].moblist[j]) aFree(map->list[i].moblist[j]); } - if( map[i].unit_count ) { - for(v = 0; v < map[i].unit_count; v++) { - aFree(map[i].units[v]); + if( map->list[i].unit_count ) { + for(v = 0; v < map->list[i].unit_count; v++) { + aFree(map->list[i].units[v]); } - if( map[i].units ) { - aFree(map[i].units); - map[i].units = NULL; + if( map->list[i].units ) { + aFree(map->list[i].units); + map->list[i].units = NULL; } - map[i].unit_count = 0; + map->list[i].unit_count = 0; } - if( map[i].skill_count ) { - for(v = 0; v < map[i].skill_count; v++) { - aFree(map[i].skills[v]); + if( map->list[i].skill_count ) { + for(v = 0; v < map->list[i].skill_count; v++) { + aFree(map->list[i].skills[v]); } - if( map[i].skills ) { - aFree(map[i].skills); - map[i].skills = NULL; + if( map->list[i].skills ) { + aFree(map->list[i].skills); + map->list[i].skills = NULL; } - map[i].skill_count = 0; + map->list[i].skill_count = 0; } - if( map[i].zone_mf_count ) { - for(v = 0; v < map[i].zone_mf_count; v++) { - aFree(map[i].zone_mf[v]); + if( map->list[i].zone_mf_count ) { + for(v = 0; v < map->list[i].zone_mf_count; v++) { + aFree(map->list[i].zone_mf[v]); } - if( map[i].zone_mf ) { - aFree(map[i].zone_mf); - map[i].zone_mf = NULL; + if( map->list[i].zone_mf ) { + aFree(map->list[i].zone_mf); + map->list[i].zone_mf = NULL; } - map[i].zone_mf_count = 0; + map->list[i].zone_mf_count = 0; } - if( map[i].channel ) - clif->chsys_delete(map[i].channel); + if( map->list[i].channel ) + clif->chsys_delete(map->list[i].channel); } void do_final_maps(void) { int i, v = 0; - for( i = 0; i < iMap->map_num; i++ ) { + for( i = 0; i < map->count; i++ ) { - if(map[i].cell && map[i].cell != (struct mapcell *)0xdeadbeaf ) aFree(map[i].cell); - if(map[i].block) aFree(map[i].block); - if(map[i].block_mob) aFree(map[i].block_mob); + if(map->list[i].cell && map->list[i].cell != (struct mapcell *)0xdeadbeaf ) aFree(map->list[i].cell); + if(map->list[i].block) aFree(map->list[i].block); + if(map->list[i].block_mob) aFree(map->list[i].block_mob); if(battle_config.dynamic_mobs) { //Dynamic mobs flag by [random] int j; - if(map[i].mob_delete_timer != INVALID_TIMER) - iTimer->delete_timer(map[i].mob_delete_timer, iMap->removemobs_timer); + if(map->list[i].mob_delete_timer != INVALID_TIMER) + timer->delete(map->list[i].mob_delete_timer, map->removemobs_timer); for (j=0; j<MAX_MOB_LIST_PER_MAP; j++) - if (map[i].moblist[j]) aFree(map[i].moblist[j]); + if (map->list[i].moblist[j]) aFree(map->list[i].moblist[j]); } - if( map[i].unit_count ) { - for(v = 0; v < map[i].unit_count; v++) { - aFree(map[i].units[v]); + if( map->list[i].unit_count ) { + for(v = 0; v < map->list[i].unit_count; v++) { + aFree(map->list[i].units[v]); } - if( map[i].units ) { - aFree(map[i].units); - map[i].units = NULL; + if( map->list[i].units ) { + aFree(map->list[i].units); + map->list[i].units = NULL; } - map[i].unit_count = 0; + map->list[i].unit_count = 0; } - if( map[i].skill_count ) { - for(v = 0; v < map[i].skill_count; v++) { - aFree(map[i].skills[v]); + if( map->list[i].skill_count ) { + for(v = 0; v < map->list[i].skill_count; v++) { + aFree(map->list[i].skills[v]); } - if( map[i].skills ) { - aFree(map[i].skills); - map[i].skills = NULL; + if( map->list[i].skills ) { + aFree(map->list[i].skills); + map->list[i].skills = NULL; } - map[i].skill_count = 0; + map->list[i].skill_count = 0; } - if( map[i].zone_mf_count ) { - for(v = 0; v < map[i].zone_mf_count; v++) { - aFree(map[i].zone_mf[v]); + if( map->list[i].zone_mf_count ) { + for(v = 0; v < map->list[i].zone_mf_count; v++) { + aFree(map->list[i].zone_mf[v]); } - if( map[i].zone_mf ) { - aFree(map[i].zone_mf); - map[i].zone_mf = NULL; + if( map->list[i].zone_mf ) { + aFree(map->list[i].zone_mf); + map->list[i].zone_mf = NULL; } - map[i].zone_mf_count = 0; + map->list[i].zone_mf_count = 0; } - if( map[i].drop_list_count ) { - map[i].drop_list_count = 0; + if( map->list[i].drop_list_count ) { + map->list[i].drop_list_count = 0; } - if( map[i].drop_list != NULL ) - aFree(map[i].drop_list); + if( map->list[i].drop_list != NULL ) + aFree(map->list[i].drop_list); - if( map[i].channel ) - clif->chsys_delete(map[i].channel); + if( map->list[i].channel ) + clif->chsys_delete(map->list[i].channel); + + if( map->list[i].qi_data ) + aFree(map->list[i].qi_data); + + for( v = 0; v < map->list[i].hdatac; v++ ) { + if( map->list[i].hdata[v]->flag.free ) { + aFree(map->list[i].hdata[v]->data); + } + aFree(map->list[i].hdata[v]); + } + if( map->list[i].hdata ) + aFree(map->list[i].hdata); } - map_zone_db_clear(); + map->zone_db_clear(); } /// Initializes map flags and adjusts them depending on configuration. void map_flags_init(void) { int i, v = 0; - for( i = 0; i < iMap->map_num; i++ ) { + for( i = 0; i < map->count; i++ ) { // mapflags - memset(&map[i].flag, 0, sizeof(map[i].flag)); + memset(&map->list[i].flag, 0, sizeof(map->list[i].flag)); // additional mapflag data - map[i].nocommand = 0; // nocommand mapflag level - map[i].bexp = 100; // per map base exp multiplicator - map[i].jexp = 100; // per map job exp multiplicator - if( map[i].drop_list != NULL ) - aFree(map[i].drop_list); - map[i].drop_list = NULL; - map[i].drop_list_count = 0; - - if( map[i].unit_count ) { - for(v = 0; v < map[i].unit_count; v++) { - aFree(map[i].units[v]); + map->list[i].nocommand = 0; // nocommand mapflag level + map->list[i].bexp = 100; // per map base exp multiplicator + map->list[i].jexp = 100; // per map job exp multiplicator + if( map->list[i].drop_list != NULL ) + aFree(map->list[i].drop_list); + map->list[i].drop_list = NULL; + map->list[i].drop_list_count = 0; + + if( map->list[i].unit_count ) { + for(v = 0; v < map->list[i].unit_count; v++) { + aFree(map->list[i].units[v]); } - aFree(map[i].units); + aFree(map->list[i].units); } - map[i].units = NULL; - map[i].unit_count = 0; + map->list[i].units = NULL; + map->list[i].unit_count = 0; - if( map[i].skill_count ) { - for(v = 0; v < map[i].skill_count; v++) { - aFree(map[i].skills[v]); + if( map->list[i].skill_count ) { + for(v = 0; v < map->list[i].skill_count; v++) { + aFree(map->list[i].skills[v]); } - aFree(map[i].skills); + aFree(map->list[i].skills); } - map[i].skills = NULL; - map[i].skill_count = 0; + map->list[i].skills = NULL; + map->list[i].skill_count = 0; // adjustments if( battle_config.pk_mode ) { - map[i].flag.pvp = 1; // make all maps pvp for pk_mode [Valaris] - map[i].zone = &map_zone_pk; + map->list[i].flag.pvp = 1; // make all maps pvp for pk_mode [Valaris] + map->list[i].zone = &map->zone_pk; } else /* align with 'All' zone */ - map[i].zone = &map_zone_all; + map->list[i].zone = &map->zone_all; - if( map[i].zone_mf_count ) { - for(v = 0; v < map[i].zone_mf_count; v++) { - aFree(map[i].zone_mf[v]); + if( map->list[i].zone_mf_count ) { + for(v = 0; v < map->list[i].zone_mf_count; v++) { + aFree(map->list[i].zone_mf[v]); } - aFree(map[i].zone_mf); + aFree(map->list[i].zone_mf); } - map[i].zone_mf = NULL; - map[i].zone_mf_count = 0; - map[i].prev_zone = map[i].zone; + map->list[i].zone_mf = NULL; + map->list[i].zone_mf_count = 0; + map->list[i].prev_zone = map->list[i].zone; - map[i].invincible_time_inc = 0; + map->list[i].invincible_time_inc = 0; - map[i].weapon_damage_rate = 100; - map[i].magic_damage_rate = 100; - map[i].misc_damage_rate = 100; - map[i].short_damage_rate = 100; - map[i].long_damage_rate = 100; + map->list[i].weapon_damage_rate = 100; + map->list[i].magic_damage_rate = 100; + map->list[i].misc_damage_rate = 100; + map->list[i].short_damage_rate = 100; + map->list[i].long_damage_rate = 100; + + if( map->list[i].qi_data ) + aFree(map->list[i].qi_data); + + map->list[i].qi_data = NULL; + map->list[i].qi_count = 0; } } #define NO_WATER 1000000 /* -* Reads from the .rsw for each map -* Returns water height (or NO_WATER if file doesn't exist) or other error is encountered. -* Assumed path for file is data/mapname.rsw -* Credits to LittleWolf -*/ + * Reads from the .rsw for each map + * Returns water height (or NO_WATER if file doesn't exist) or other error is encountered. + * Assumed path for file is data/mapname.rsw + * Credits to LittleWolf + */ int map_waterheight(char* mapname) { char fn[256]; @@ -3154,19 +3254,19 @@ int map_waterheight(char* mapname) // read & convert fn rsw = (char *) grfio_read (fn); - if (rsw) - { //Load water height from file + if (rsw) { + //Load water height from file int wh = (int) *(float*)(rsw+166); aFree(rsw); return wh; } - ShowWarning("Failed to find water level for (%s)\n", mapname, fn); + ShowWarning("Failed to find water level for %s (%s)\n", mapname, fn); return NO_WATER; } /*================================== -* .GAT format -*----------------------------------*/ + * .GAT format + *----------------------------------*/ int map_readgat (struct map_data* m) { char filename[256]; @@ -3185,7 +3285,7 @@ int map_readgat (struct map_data* m) num_cells = m->xs * m->ys; CREATE(m->cell, struct mapcell, num_cells); - water_height = map_waterheight(m->name); + water_height = map->waterheight(m->name); // Set cell properties off = 14; @@ -3199,7 +3299,10 @@ int map_readgat (struct map_data* m) if( type == 0 && water_height != NO_WATER && height > water_height ) type = 3; // Cell is 0 (walkable) but under water level, set to 3 (walkable water) - m->cell[xy] = map_gat2cell(type); + m->cell[xy] = map->gat2cell(type); +#ifdef CELL_NOSTACK + m->cell[xy].cell_bl = 0; +#endif } aFree(gat); @@ -3208,29 +3311,29 @@ int map_readgat (struct map_data* m) } /*====================================== -* Add/Remove map to the map_db -*--------------------------------------*/ + * Add/Remove map to the map_db + *--------------------------------------*/ void map_addmap2db(struct map_data *m) { - index2mapid[m->index] = m->m; + map->index2mapid[m->index] = m->m; } void map_removemapdb(struct map_data *m) { - index2mapid[m->index] = -1; + map->index2mapid[m->index] = -1; } /*====================================== -* Initiate maps loading stage -*--------------------------------------*/ + * Initiate maps loading stage + *--------------------------------------*/ int map_readallmaps (void) { int i; FILE* fp=NULL; int maps_removed = 0; - if( enable_grf ) + if( map->enable_grf ) ShowStatus("Loading maps (using GRF files)...\n"); else { char mapcachefilepath[254]; - sprintf(mapcachefilepath,"%s/%s%s",iMap->db_path,DBPATH,"map_cache.dat"); + sprintf(mapcachefilepath,"%s/%s%s",map->db_path,DBPATH,"map_cache.dat"); ShowStatus("Loading maps (using %s as map cache)...\n", mapcachefilepath); if( (fp = fopen(mapcachefilepath, "rb")) == NULL ) { ShowFatalError("Unable to open map cache file "CL_WHITE"%s"CL_RESET"\n", mapcachefilepath); @@ -3238,73 +3341,73 @@ int map_readallmaps (void) { } // Init mapcache data.. [Shinryo] - map_cache_buffer = map_init_mapcache(fp); - if(!map_cache_buffer) { + map->cache_buffer = map->init_mapcache(fp); + if(!map->cache_buffer) { ShowFatalError("Failed to initialize mapcache data (%s)..\n", mapcachefilepath); exit(EXIT_FAILURE); } } - for(i = 0; i < iMap->map_num; i++) { + for(i = 0; i < map->count; i++) { size_t size; // show progress - if(enable_grf) - ShowStatus("Loading maps [%i/%i]: %s"CL_CLL"\r", i, iMap->map_num, map[i].name); + if(map->enable_grf) + ShowStatus("Loading maps [%i/%i]: %s"CL_CLL"\r", i, map->count, map->list[i].name); // try to load the map if( ! - (enable_grf? - map_readgat(&map[i]) - :map_readfromcache(&map[i], map_cache_buffer)) + (map->enable_grf? + map->readgat(&map->list[i]) + :map->readfromcache(&map->list[i], map->cache_buffer)) ) { - map_delmapid(i); + map->delmapid(i); maps_removed++; i--; continue; } - map[i].index = mapindex_name2id(map[i].name); + map->list[i].index = mapindex->name2id(map->list[i].name); - if ( index2mapid[map[i].index] != -1 ) { - ShowWarning("Map %s already loaded!"CL_CLL"\n", map[i].name); - if (map[i].cell && map[i].cell != (struct mapcell *)0xdeadbeaf) { - aFree(map[i].cell); - map[i].cell = NULL; + if ( map->index2mapid[map_id2index(i)] != -1 ) { + ShowWarning("Map %s already loaded!"CL_CLL"\n", map->list[i].name); + if (map->list[i].cell && map->list[i].cell != (struct mapcell *)0xdeadbeaf) { + aFree(map->list[i].cell); + map->list[i].cell = NULL; } - map_delmapid(i); + map->delmapid(i); maps_removed++; i--; continue; } - map[i].m = i; - iMap->addmap2db(&map[i]); + map->list[i].m = i; + map->addmap2db(&map->list[i]); - memset(map[i].moblist, 0, sizeof(map[i].moblist)); //Initialize moblist [Skotlex] - map[i].mob_delete_timer = INVALID_TIMER; //Initialize timer [Skotlex] + memset(map->list[i].moblist, 0, sizeof(map->list[i].moblist)); //Initialize moblist [Skotlex] + map->list[i].mob_delete_timer = INVALID_TIMER; //Initialize timer [Skotlex] - map[i].bxs = (map[i].xs + BLOCK_SIZE - 1) / BLOCK_SIZE; - map[i].bys = (map[i].ys + BLOCK_SIZE - 1) / BLOCK_SIZE; + map->list[i].bxs = (map->list[i].xs + BLOCK_SIZE - 1) / BLOCK_SIZE; + map->list[i].bys = (map->list[i].ys + BLOCK_SIZE - 1) / BLOCK_SIZE; - size = map[i].bxs * map[i].bys * sizeof(struct block_list*); - map[i].block = (struct block_list**)aCalloc(size, 1); - map[i].block_mob = (struct block_list**)aCalloc(size, 1); + size = map->list[i].bxs * map->list[i].bys * sizeof(struct block_list*); + map->list[i].block = (struct block_list**)aCalloc(size, 1); + map->list[i].block_mob = (struct block_list**)aCalloc(size, 1); - map[i].getcellp = map_sub_getcellp; - map[i].setcell = map_sub_setcell; + map->list[i].getcellp = map->sub_getcellp; + map->list[i].setcell = map->sub_setcell; } // intialization and configuration-dependent adjustments of mapflags - iMap->flags_init(); + map->flags_init(); - if( !enable_grf ) { + if( !map->enable_grf ) { fclose(fp); } // finished map loading - ShowInfo("Successfully loaded '"CL_WHITE"%d"CL_RESET"' maps."CL_CLL"\n",iMap->map_num); - instance->start_id = iMap->map_num; // Next Map Index will be instances + ShowInfo("Successfully loaded '"CL_WHITE"%d"CL_RESET"' maps."CL_CLL"\n",map->count); + instance->start_id = map->count; // Next Map Index will be instances if (maps_removed) ShowNotice("Maps removed: '"CL_WHITE"%d"CL_RESET"'\n",maps_removed); @@ -3312,13 +3415,9 @@ int map_readallmaps (void) { return 0; } -//////////////////////////////////////////////////////////////////////// -static int map_ip_set = 0; -static int char_ip_set = 0; - /*========================================== -* Read map server configuration files (conf/map_server.conf...) -*------------------------------------------*/ + * Read map server configuration files (conf/map_server.conf...) + *------------------------------------------*/ int map_config_read(char *cfgName) { char line[1024], w1[1024], w2[1024]; FILE *fp; @@ -3329,14 +3428,14 @@ int map_config_read(char *cfgName) { return 1; } - while( fgets(line, sizeof(line), fp) ) { + while (fgets(line, sizeof(line), fp)) { char* ptr; - if( line[0] == '/' && line[1] == '/' ) + if (line[0] == '/' && line[1] == '/') continue; - if( (ptr = strstr(line, "//")) != NULL ) + if ((ptr = strstr(line, "//")) != NULL) *ptr = '\n'; //Strip comments - if( sscanf(line, "%[^:]: %[^\t\r\n]", w1, w2) < 2 ) + if (sscanf(line, "%1023[^:]: %1023[^\t\r\n]", w1, w2) < 2) continue; //Strip trailing spaces @@ -3354,56 +3453,56 @@ int map_config_read(char *cfgName) { if( msg_silent ) // only bother if its actually enabled ShowInfo("Console Silent Setting: %d\n", atoi(w2)); } else if (strcmpi(w1, "userid")==0) - chrif_setuserid(w2); + chrif->setuserid(w2); else if (strcmpi(w1, "passwd") == 0) - chrif_setpasswd(w2); + chrif->setpasswd(w2); else if (strcmpi(w1, "char_ip") == 0) - char_ip_set = chrif_setip(w2); + map->char_ip_set = chrif->setip(w2); else if (strcmpi(w1, "char_port") == 0) - chrif_setport(atoi(w2)); + chrif->setport(atoi(w2)); else if (strcmpi(w1, "map_ip") == 0) - map_ip_set = clif->setip(w2); + map->ip_set = clif->setip(w2); else if (strcmpi(w1, "bind_ip") == 0) clif->setbindip(w2); else if (strcmpi(w1, "map_port") == 0) { clif->setport(atoi(w2)); - map_port = (atoi(w2)); + map->port = (atoi(w2)); } else if (strcmpi(w1, "map") == 0) - iMap->map_num++; + map->count++; else if (strcmpi(w1, "delmap") == 0) - iMap->map_num--; + map->count--; else if (strcmpi(w1, "npc") == 0) - npc_addsrcfile(w2); + npc->addsrcfile(w2); else if (strcmpi(w1, "delnpc") == 0) - npc_delsrcfile(w2); + npc->delsrcfile(w2); else if (strcmpi(w1, "autosave_time") == 0) { - iMap->autosave_interval = atoi(w2); - if (iMap->autosave_interval < 1) //Revert to default saving. - iMap->autosave_interval = DEFAULT_AUTOSAVE_INTERVAL; + map->autosave_interval = atoi(w2); + if (map->autosave_interval < 1) //Revert to default saving. + map->autosave_interval = DEFAULT_AUTOSAVE_INTERVAL; else - iMap->autosave_interval *= 1000; //Pass from sec to ms + map->autosave_interval *= 1000; //Pass from sec to ms } else if (strcmpi(w1, "minsave_time") == 0) { - iMap->minsave_interval= atoi(w2); - if (iMap->minsave_interval < 1) - iMap->minsave_interval = 1; + map->minsave_interval= atoi(w2); + if (map->minsave_interval < 1) + map->minsave_interval = 1; } else if (strcmpi(w1, "save_settings") == 0) - iMap->save_settings = atoi(w2); + map->save_settings = atoi(w2); else if (strcmpi(w1, "help_txt") == 0) - strcpy(iMap->help_txt, w2); + strcpy(map->help_txt, w2); else if (strcmpi(w1, "help2_txt") == 0) - strcpy(iMap->help2_txt, w2); + strcpy(map->help2_txt, w2); else if (strcmpi(w1, "charhelp_txt") == 0) - strcpy(iMap->charhelp_txt, w2); + strcpy(map->charhelp_txt, w2); else if(strcmpi(w1,"db_path") == 0) - safestrncpy(iMap->db_path,w2,255); + safestrncpy(map->db_path,w2,255); else if (strcmpi(w1, "enable_spy") == 0) - iMap->enable_spy = config_switch(w2); + map->enable_spy = config_switch(w2); else if (strcmpi(w1, "use_grf") == 0) - enable_grf = config_switch(w2); + map->enable_grf = config_switch(w2); else if (strcmpi(w1, "console_msg_log") == 0) console_msg_log = atoi(w2);//[Ind] else if (strcmpi(w1, "import") == 0) - map_config_read(w2); + map->config_read(w2); else ShowWarning("Unknown setting '%s' in file %s\n", w1, cfgName); } @@ -3416,19 +3515,19 @@ int map_config_read_sub(char *cfgName) { FILE *fp; fp = fopen(cfgName,"r"); - if( fp == NULL ) { + if (fp == NULL) { ShowError("Map configuration file not found at: %s\n", cfgName); return 1; } - while( fgets(line, sizeof(line), fp) ) { + while (fgets(line, sizeof(line), fp)) { char* ptr; - if( line[0] == '/' && line[1] == '/' ) + if (line[0] == '/' && line[1] == '/') continue; - if( (ptr = strstr(line, "//")) != NULL ) + if ((ptr = strstr(line, "//")) != NULL) *ptr = '\n'; //Strip comments - if( sscanf(line, "%[^:]: %[^\t\r\n]", w1, w2) < 2 ) + if (sscanf(line, "%1023[^:]: %1023[^\t\r\n]", w1, w2) < 2) continue; //Strip trailing spaces @@ -3438,37 +3537,34 @@ int map_config_read_sub(char *cfgName) { *ptr = '\0'; if (strcmpi(w1, "map") == 0) - map_addmap(w2); + map->addmap(w2); else if (strcmpi(w1, "delmap") == 0) - iMap->delmap(w2); + map->delmap(w2); else if (strcmpi(w1, "import") == 0) - map_config_read_sub(w2); + map->config_read_sub(w2); } fclose(fp); return 0; } -void map_reloadnpc_sub(char *cfgName) -{ +void map_reloadnpc_sub(char *cfgName) { char line[1024], w1[1024], w2[1024]; FILE *fp; fp = fopen(cfgName,"r"); - if( fp == NULL ) - { + if (fp == NULL) { ShowError("Map configuration file not found at: %s\n", cfgName); return; } - while( fgets(line, sizeof(line), fp) ) - { + while (fgets(line, sizeof(line), fp)) { char* ptr; - if( line[0] == '/' && line[1] == '/' ) + if (line[0] == '/' && line[1] == '/') continue; - if( (ptr = strstr(line, "//")) != NULL ) + if ((ptr = strstr(line, "//")) != NULL) *ptr = '\n'; //Strip comments - if( sscanf(line, "%[^:]: %[^\t\r\n]", w1, w2) < 2 ) + if (sscanf(line, "%1023[^:]: %1023[^\t\r\n]", w1, w2) < 2) continue; //Strip trailing spaces @@ -3478,9 +3574,11 @@ void map_reloadnpc_sub(char *cfgName) *ptr = '\0'; if (strcmpi(w1, "npc") == 0) - npc_addsrcfile(w2); + npc->addsrcfile(w2); else if (strcmpi(w1, "import") == 0) - map_reloadnpc_sub(w2); + map->reloadnpc_sub(w2); + else if (strcmpi(w1, "delnpc") == 0) + npc->delsrcfile(w2); else ShowWarning("Unknown setting '%s' in file %s\n", w1, cfgName); } @@ -3488,83 +3586,102 @@ void map_reloadnpc_sub(char *cfgName) fclose(fp); } -void map_reloadnpc(bool clear) -{ +void map_reloadnpc(bool clear, const char * const *extra_scripts, int extra_scripts_count) { + int i; if (clear) - npc_addsrcfile("clear"); // this will clear the current script list + npc->addsrcfile("clear"); // this will clear the current script list #ifdef RENEWAL - map_reloadnpc_sub("npc/re/scripts_main.conf"); + map->reloadnpc_sub("npc/re/scripts_main.conf"); #else - map_reloadnpc_sub("npc/pre-re/scripts_main.conf"); + map->reloadnpc_sub("npc/pre-re/scripts_main.conf"); #endif + + // Append extra scripts + for( i = 0; i < extra_scripts_count; i++ ) { + npc->addsrcfile(extra_scripts[i]); + } } int inter_config_read(char *cfgName) { char line[1024],w1[1024],w2[1024]; FILE *fp; - if( !( fp = fopen(cfgName,"r") ) ){ + if (!(fp = fopen(cfgName,"r"))) { ShowError("File not found: %s\n",cfgName); return 1; } - while(fgets(line, sizeof(line), fp)) { - if(line[0] == '/' && line[1] == '/') + while (fgets(line, sizeof(line), fp)) { + if (line[0] == '/' && line[1] == '/') continue; - if( sscanf(line,"%[^:]: %[^\r\n]",w1,w2) < 2 ) + if (sscanf(line,"%1023[^:]: %1023[^\r\n]", w1, w2) < 2) continue; /* table names */ if(strcmpi(w1,"item_db_db")==0) - strcpy(iMap->item_db_db,w2); + strcpy(map->item_db_db,w2); else if(strcmpi(w1,"mob_db_db")==0) - strcpy(iMap->mob_db_db,w2); + strcpy(map->mob_db_db,w2); else if(strcmpi(w1,"item_db2_db")==0) - strcpy(iMap->item_db2_db,w2); + strcpy(map->item_db2_db,w2); else if(strcmpi(w1,"item_db_re_db")==0) - strcpy(iMap->item_db_re_db,w2); + strcpy(map->item_db_re_db,w2); else if(strcmpi(w1,"mob_db2_db")==0) - strcpy(iMap->mob_db2_db,w2); + strcpy(map->mob_db2_db,w2); else if(strcmpi(w1,"mob_skill_db_db")==0) - strcpy(iMap->mob_skill_db_db,w2); + strcpy(map->mob_skill_db_db,w2); else if(strcmpi(w1,"mob_skill_db2_db")==0) - strcpy(iMap->mob_skill_db2_db,w2); + strcpy(map->mob_skill_db2_db,w2); else if(strcmpi(w1,"interreg_db")==0) - strcpy(iMap->interreg_db,w2); + strcpy(map->interreg_db,w2); /* map sql stuff */ else if(strcmpi(w1,"map_server_ip")==0) - strcpy(map_server_ip, w2); + strcpy(map->server_ip, w2); else if(strcmpi(w1,"map_server_port")==0) - map_server_port=atoi(w2); + map->server_port=atoi(w2); else if(strcmpi(w1,"map_server_id")==0) - strcpy(map_server_id, w2); + strcpy(map->server_id, w2); else if(strcmpi(w1,"map_server_pw")==0) - strcpy(map_server_pw, w2); + strcpy(map->server_pw, w2); else if(strcmpi(w1,"map_server_db")==0) - strcpy(map_server_db, w2); + strcpy(map->server_db, w2); else if(strcmpi(w1,"default_codepage")==0) - strcpy(default_codepage, w2); - else if(strcmpi(w1,"use_sql_db")==0) { - iMap->db_use_sqldbs = config_switch(w2); - ShowStatus ("Using SQL dbs: %s\n",w2); - } + strcpy(map->default_codepage, w2); + else if(strcmpi(w1,"use_sql_item_db")==0) { + map->db_use_sql_item_db = config_switch(w2); + ShowStatus ("Using item database as SQL: '%s'\n", w2); + } + else if(strcmpi(w1,"use_sql_mob_db")==0) { + map->db_use_sql_mob_db = config_switch(w2); + ShowStatus ("Using monster database as SQL: '%s'\n", w2); + } + else if(strcmpi(w1,"use_sql_mob_skill_db")==0) { + map->db_use_sql_mob_skill_db = config_switch(w2); + ShowStatus ("Using monster skill database as SQL: '%s'\n", w2); + } + else if(strcmpi(w1,"autotrade_merchants_db")==0) + strcpy(map->autotrade_merchants_db, w2); + else if(strcmpi(w1,"autotrade_data_db")==0) + strcpy(map->autotrade_data_db, w2); + else if(strcmpi(w1,"npc_market_data_db")==0) + strcpy(map->npc_market_data_db, w2); /* sql log db */ else if(strcmpi(w1,"log_db_ip")==0) - strcpy(log_db_ip, w2); + strcpy(logs->db_ip, w2); else if(strcmpi(w1,"log_db_id")==0) - strcpy(log_db_id, w2); + strcpy(logs->db_id, w2); else if(strcmpi(w1,"log_db_pw")==0) - strcpy(log_db_pw, w2); + strcpy(logs->db_pw, w2); else if(strcmpi(w1,"log_db_port")==0) - log_db_port = atoi(w2); + logs->db_port = atoi(w2); else if(strcmpi(w1,"log_db_db")==0) - strcpy(log_db_db, w2); + strcpy(logs->db_name, w2); /* mapreg */ - else if( mapreg_config_read(w1,w2) ) + else if( mapreg->config_read(w1,w2) ) continue; /* import */ else if(strcmpi(w1,"import")==0) - inter_config_read(w2); + map->inter_config_read(w2); } fclose(fp); @@ -3572,21 +3689,21 @@ int inter_config_read(char *cfgName) { } /*======================================= -* MySQL Init -*---------------------------------------*/ + * MySQL Init + *---------------------------------------*/ int map_sql_init(void) { // main db connection - mmysql_handle = SQL->Malloc(); + map->mysql_handle = SQL->Malloc(); ShowInfo("Connecting to the Map DB Server....\n"); - if( SQL_ERROR == SQL->Connect(mmysql_handle, map_server_id, map_server_pw, map_server_ip, map_server_port, map_server_db) ) + if( SQL_ERROR == SQL->Connect(map->mysql_handle, map->server_id, map->server_pw, map->server_ip, map->server_port, map->server_db) ) exit(EXIT_FAILURE); ShowStatus("connect success! (Map Server Connection)\n"); - if( strlen(default_codepage) > 0 ) - if ( SQL_ERROR == SQL->SetEncoding(mmysql_handle, default_codepage) ) - Sql_ShowDebug(mmysql_handle); + if( strlen(map->default_codepage) > 0 ) + if ( SQL_ERROR == SQL->SetEncoding(map->mysql_handle, map->default_codepage) ) + Sql_ShowDebug(map->mysql_handle); return 0; } @@ -3594,58 +3711,141 @@ int map_sql_init(void) int map_sql_close(void) { ShowStatus("Close Map DB Connection....\n"); - SQL->Free(mmysql_handle); - mmysql_handle = NULL; + SQL->Free(map->mysql_handle); + map->mysql_handle = NULL; if (logs->config.sql_logs) { - ShowStatus("Close Log DB Connection....\n"); - SQL->Free(logmysql_handle); - logmysql_handle = NULL; + logs->sql_final(); } return 0; } -int log_sql_init(void) -{ - // log db connection - logmysql_handle = SQL->Malloc(); - - ShowInfo(""CL_WHITE"[SQL]"CL_RESET": Connecting to the Log Database "CL_WHITE"%s"CL_RESET" At "CL_WHITE"%s"CL_RESET"...\n",log_db_db,log_db_ip); - if ( SQL_ERROR == SQL->Connect(logmysql_handle, log_db_id, log_db_pw, log_db_ip, log_db_port, log_db_db) ) - exit(EXIT_FAILURE); - ShowStatus(""CL_WHITE"[SQL]"CL_RESET": Successfully '"CL_GREEN"connected"CL_RESET"' to Database '"CL_WHITE"%s"CL_RESET"'.\n", log_db_db); - - if( strlen(default_codepage) > 0 ) - if ( SQL_ERROR == SQL->SetEncoding(logmysql_handle, default_codepage) ) - Sql_ShowDebug(logmysql_handle); - return 0; +/** + * Merges two zones into a new one + * @param main the zone whose data must override the others upon conflict, + * e.g. enabling pvp on a town means that main is the pvp zone, while "other" is the towns previous zone + * + * @return the newly created zone from merging main and other + **/ +struct map_zone_data *map_merge_zone(struct map_zone_data *main, struct map_zone_data *other) { + char newzone[MAP_ZONE_NAME_LENGTH]; + struct map_zone_data *zone = NULL; + int cursor, i; + + sprintf(newzone, "%s+%s",main->name,other->name); + + if( (zone = strdb_get(map->zone_db, newzone)) ) + return zone;/* this zone has already been merged */ + + CREATE(zone, struct map_zone_data, 1); + + safestrncpy(zone->name, newzone, MAP_ZONE_NAME_LENGTH); + + zone->disabled_skills_count = main->disabled_skills_count + other->disabled_skills_count; + zone->disabled_items_count = main->disabled_items_count + other->disabled_items_count; + zone->mapflags_count = main->mapflags_count + other->mapflags_count; + zone->disabled_commands_count = main->disabled_commands_count + other->disabled_commands_count; + zone->capped_skills_count = main->capped_skills_count + other->capped_skills_count; + + CREATE(zone->disabled_skills, struct map_zone_disabled_skill_entry *, zone->disabled_skills_count ); + + for(i = 0, cursor = 0; i < main->disabled_skills_count; i++, cursor++ ) { + CREATE(zone->disabled_skills[cursor], struct map_zone_disabled_skill_entry, 1 ); + memcpy(zone->disabled_skills[cursor], main->disabled_skills[i], sizeof(struct map_zone_disabled_skill_entry)); + } + + for(i = 0; i < other->disabled_skills_count; i++, cursor++ ) { + CREATE(zone->disabled_skills[cursor], struct map_zone_disabled_skill_entry, 1 ); + memcpy(zone->disabled_skills[cursor], other->disabled_skills[i], sizeof(struct map_zone_disabled_skill_entry)); + } + + CREATE(zone->disabled_items, int, zone->disabled_items_count ); + + for(i = 0, cursor = 0; i < main->disabled_items_count; i++, cursor++ ) { + zone->disabled_items[cursor] = main->disabled_items[i]; + } + + for(i = 0; i < other->disabled_items_count; i++, cursor++ ) { + zone->disabled_items[cursor] = other->disabled_items[i]; + } + + CREATE(zone->mapflags, char *, zone->mapflags_count ); + + for(i = 0, cursor = 0; i < main->mapflags_count; i++, cursor++ ) { + CREATE(zone->mapflags[cursor], char, MAP_ZONE_MAPFLAG_LENGTH ); + safestrncpy(zone->mapflags[cursor], main->mapflags[i], MAP_ZONE_MAPFLAG_LENGTH); + } + + for(i = 0; i < other->mapflags_count; i++, cursor++ ) { + CREATE(zone->mapflags[cursor], char, MAP_ZONE_MAPFLAG_LENGTH ); + safestrncpy(zone->mapflags[cursor], other->mapflags[i], MAP_ZONE_MAPFLAG_LENGTH); + } + + CREATE(zone->disabled_commands, struct map_zone_disabled_command_entry *, zone->disabled_commands_count); + + for(i = 0, cursor = 0; i < main->disabled_commands_count; i++, cursor++ ) { + CREATE(zone->disabled_commands[cursor], struct map_zone_disabled_command_entry, 1); + memcpy(zone->disabled_commands[cursor], main->disabled_commands[i], sizeof(struct map_zone_disabled_command_entry)); + } + + for(i = 0; i < other->disabled_commands_count; i++, cursor++ ) { + CREATE(zone->disabled_commands[cursor], struct map_zone_disabled_command_entry, 1); + memcpy(zone->disabled_commands[cursor], other->disabled_commands[i], sizeof(struct map_zone_disabled_command_entry)); + } + + CREATE(zone->capped_skills, struct map_zone_skill_damage_cap_entry *, zone->capped_skills_count); + + for(i = 0, cursor = 0; i < main->capped_skills_count; i++, cursor++ ) { + CREATE(zone->capped_skills[cursor], struct map_zone_skill_damage_cap_entry, 1); + memcpy(zone->capped_skills[cursor], main->capped_skills[i], sizeof(struct map_zone_skill_damage_cap_entry)); + } + + for(i = 0; i < other->capped_skills_count; i++, cursor++ ) { + CREATE(zone->capped_skills[cursor], struct map_zone_skill_damage_cap_entry, 1); + memcpy(zone->capped_skills[cursor], other->capped_skills[i], sizeof(struct map_zone_skill_damage_cap_entry)); + } + + zone->info.special = 2; + + strdb_put(map->zone_db, newzone, zone); + + return zone; } + void map_zone_change2(int m, struct map_zone_data *zone) { char empty[1] = "\0"; - map[m].prev_zone = map[m].zone; - - if( map[m].zone_mf_count ) - iMap->zone_remove(m); + if( map->list[m].zone == zone ) + return; + + if( map->list[m].zone->info.special != 2 ) /* we don't update it for merged zones! */ + map->list[m].prev_zone = map->list[m].zone; + + if( map->list[m].zone_mf_count ) + map->zone_remove(m); - iMap->zone_apply(m,zone,empty,empty,empty); + if( zone->info.special ) { + zone = map->merge_zone(zone,map->list[m].prev_zone); + } + + map->zone_apply(m,zone,empty,empty,empty); } /* when changing from a mapflag to another during runtime */ void map_zone_change(int m, struct map_zone_data *zone, const char* start, const char* buffer, const char* filepath) { - map[m].prev_zone = map[m].zone; + map->list[m].prev_zone = map->list[m].zone; - if( map[m].zone_mf_count ) - iMap->zone_remove(m); - iMap->zone_apply(m,zone,start,buffer,filepath); + if( map->list[m].zone_mf_count ) + map->zone_remove(m); + map->zone_apply(m,zone,start,buffer,filepath); } /* removes previous mapflags from this map */ void map_zone_remove(int m) { char flag[MAP_ZONE_MAPFLAG_LENGTH], params[MAP_ZONE_MAPFLAG_LENGTH]; unsigned short k; char empty[1] = "\0"; - for(k = 0; k < map[m].zone_mf_count; k++) { - int len = strlen(map[m].zone_mf[k]),j; + for(k = 0; k < map->list[m].zone_mf_count; k++) { + size_t len = strlen(map->list[m].zone_mf[k]),j; params[0] = '\0'; - memcpy(flag, map[m].zone_mf[k], MAP_ZONE_MAPFLAG_LENGTH); + memcpy(flag, map->list[m].zone_mf[k], MAP_ZONE_MAPFLAG_LENGTH); for(j = 0; j < len; j++) { if( flag[j] == '\t' ) { memcpy(params, &flag[j+1], len - j); @@ -3654,19 +3854,19 @@ void map_zone_remove(int m) { } } - npc_parse_mapflag(map[m].name,empty,flag,params,empty,empty,empty); - aFree(map[m].zone_mf[k]); - map[m].zone_mf[k] = NULL; + npc->parse_mapflag(map->list[m].name,empty,flag,params,empty,empty,empty, NULL); + aFree(map->list[m].zone_mf[k]); + map->list[m].zone_mf[k] = NULL; } - aFree(map[m].zone_mf); - map[m].zone_mf = NULL; - map[m].zone_mf_count = 0; + aFree(map->list[m].zone_mf); + map->list[m].zone_mf = NULL; + map->list[m].zone_mf_count = 0; } static inline void map_zone_mf_cache_add(int m, char *rflag) { - RECREATE(map[m].zone_mf, char *, ++map[m].zone_mf_count); - CREATE(map[m].zone_mf[map[m].zone_mf_count - 1], char, MAP_ZONE_MAPFLAG_LENGTH); - safestrncpy(map[m].zone_mf[map[m].zone_mf_count - 1], rflag, MAP_ZONE_MAPFLAG_LENGTH); + RECREATE(map->list[m].zone_mf, char *, ++map->list[m].zone_mf_count); + CREATE(map->list[m].zone_mf[map->list[m].zone_mf_count - 1], char, MAP_ZONE_MAPFLAG_LENGTH); + safestrncpy(map->list[m].zone_mf[map->list[m].zone_mf_count - 1], rflag, MAP_ZONE_MAPFLAG_LENGTH); } /* TODO: introduce enumerations to each mapflag so instead of reading the string a number of times we read it only once and use its value wherever we need */ /* cache previous values to revert */ @@ -3678,524 +3878,524 @@ bool map_zone_mf_cache(int m, char *flag, char *params) { state = 0; if (!strcmpi(flag, "nosave")) { - ;/* not yet supported to be reversed */ - /* +#if 0 /* not yet supported to be reversed */ char savemap[32]; int savex, savey; if (state == 0) { - if( map[m].flag.nosave ) { - sprintf(rflag, "nosave SavePoint"); - map_zone_mf_cache_add(m,nosave); - } + if( map->list[m].flag.nosave ) { + sprintf(rflag, "nosave\tSavePoint"); + map_zone_mf_cache_add(m,nosave); + } } else if (!strcmpi(params, "SavePoint")) { - if( map[m].save.map ) { - sprintf(rflag, "nosave %s,%d,%d",mapindex_id2name(map[m].save.map),map[m].save.x,map[m].save.y); - } else - sprintf(rflag, "nosave %s,%d,%d",mapindex_id2name(map[m].save.map),map[m].save.x,map[m].save.y); - map_zone_mf_cache_add(m,nosave); + if( map->list[m].save.map ) { + sprintf(rflag, "nosave\t%s,%d,%d",mapindex_id2name(map->list[m].save.map),map->list[m].save.x,map->list[m].save.y); + } else + sprintf(rflag, "nosave\t%s,%d,%d",mapindex_id2name(map->list[m].save.map),map->list[m].save.x,map->list[m].save.y); + map_zone_mf_cache_add(m,nosave); } else if (sscanf(params, "%31[^,],%d,%d", savemap, &savex, &savey) == 3) { - if( map[m].save.map ) { - sprintf(rflag, "nosave %s,%d,%d",mapindex_id2name(map[m].save.map),map[m].save.x,map[m].save.y); - map_zone_mf_cache_add(m,nosave); + if( map->list[m].save.map ) { + sprintf(rflag, "nosave\t%s,%d,%d",mapindex_id2name(map->list[m].save.map),map->list[m].save.x,map->list[m].save.y); + map_zone_mf_cache_add(m,nosave); + } } - }*/ +#endif // 0 } else if (!strcmpi(flag,"autotrade")) { - if( state && map[m].flag.autotrade ) + if( state && map->list[m].flag.autotrade ) ;/* nothing to do */ else { if( state ) - map_zone_mf_cache_add(m,"autotrade off"); - else if( !map[m].flag.autotrade ) + map_zone_mf_cache_add(m,"autotrade\toff"); + else if( !map->list[m].flag.autotrade ) map_zone_mf_cache_add(m,"autotrade"); } } else if (!strcmpi(flag,"allowks")) { - if( state && map[m].flag.allowks ) + if( state && map->list[m].flag.allowks ) ;/* nothing to do */ else { if( state ) - map_zone_mf_cache_add(m,"allowks off"); - else if( !map[m].flag.allowks ) + map_zone_mf_cache_add(m,"allowks\toff"); + else if( !map->list[m].flag.allowks ) map_zone_mf_cache_add(m,"allowks"); } } else if (!strcmpi(flag,"town")) { - if( state && map[m].flag.town ) + if( state && map->list[m].flag.town ) ;/* nothing to do */ else { if( state ) - map_zone_mf_cache_add(m,"town off"); - else if( !map[m].flag.town ) + map_zone_mf_cache_add(m,"town\toff"); + else if( !map->list[m].flag.town ) map_zone_mf_cache_add(m,"town"); } } else if (!strcmpi(flag,"nomemo")) { - if( state && map[m].flag.nomemo ) + if( state && map->list[m].flag.nomemo ) ;/* nothing to do */ else { if( state ) - map_zone_mf_cache_add(m,"nomemo off"); - else if( !map[m].flag.nomemo ) + map_zone_mf_cache_add(m,"nomemo\toff"); + else if( !map->list[m].flag.nomemo ) map_zone_mf_cache_add(m,"nomemo"); } } else if (!strcmpi(flag,"noteleport")) { - if( state && map[m].flag.noteleport ) + if( state && map->list[m].flag.noteleport ) ;/* nothing to do */ else { if( state ) - map_zone_mf_cache_add(m,"noteleport off"); - else if( !map[m].flag.noteleport ) + map_zone_mf_cache_add(m,"noteleport\toff"); + else if( !map->list[m].flag.noteleport ) map_zone_mf_cache_add(m,"noteleport"); } } else if (!strcmpi(flag,"nowarp")) { - if( state && map[m].flag.nowarp ) + if( state && map->list[m].flag.nowarp ) ;/* nothing to do */ else { if( state ) - map_zone_mf_cache_add(m,"nowarp off"); - else if( !map[m].flag.nowarp ) + map_zone_mf_cache_add(m,"nowarp\toff"); + else if( !map->list[m].flag.nowarp ) map_zone_mf_cache_add(m,"nowarp"); } } else if (!strcmpi(flag,"nowarpto")) { - if( state && map[m].flag.nowarpto ) + if( state && map->list[m].flag.nowarpto ) ;/* nothing to do */ else { if( state ) - map_zone_mf_cache_add(m,"nowarpto off"); - else if( !map[m].flag.nowarpto ) + map_zone_mf_cache_add(m,"nowarpto\toff"); + else if( !map->list[m].flag.nowarpto ) map_zone_mf_cache_add(m,"nowarpto"); } } else if (!strcmpi(flag,"noreturn")) { - if( state && map[m].flag.noreturn ) + if( state && map->list[m].flag.noreturn ) ;/* nothing to do */ else { if( state ) - map_zone_mf_cache_add(m,"noreturn off"); - else if( map[m].flag.noreturn ) + map_zone_mf_cache_add(m,"noreturn\toff"); + else if( map->list[m].flag.noreturn ) map_zone_mf_cache_add(m,"noreturn"); } } else if (!strcmpi(flag,"monster_noteleport")) { - if( state && map[m].flag.monster_noteleport ) + if( state && map->list[m].flag.monster_noteleport ) ;/* nothing to do */ else { if( state ) - map_zone_mf_cache_add(m,"monster_noteleport off"); - else if( map[m].flag.monster_noteleport ) + map_zone_mf_cache_add(m,"monster_noteleport\toff"); + else if( map->list[m].flag.monster_noteleport ) map_zone_mf_cache_add(m,"monster_noteleport"); } } else if (!strcmpi(flag,"nobranch")) { - if( state && map[m].flag.nobranch ) + if( state && map->list[m].flag.nobranch ) ;/* nothing to do */ else { if( state ) - map_zone_mf_cache_add(m,"nobranch off"); - else if( map[m].flag.nobranch ) + map_zone_mf_cache_add(m,"nobranch\toff"); + else if( map->list[m].flag.nobranch ) map_zone_mf_cache_add(m,"nobranch"); } } else if (!strcmpi(flag,"nopenalty")) { - if( state && map[m].flag.noexppenalty ) /* they are applied together, no need to check both */ + if( state && map->list[m].flag.noexppenalty ) /* they are applied together, no need to check both */ ;/* nothing to do */ else { if( state ) - map_zone_mf_cache_add(m,"nopenalty off"); - else if( map[m].flag.noexppenalty ) + map_zone_mf_cache_add(m,"nopenalty\toff"); + else if( map->list[m].flag.noexppenalty ) map_zone_mf_cache_add(m,"nopenalty"); } } else if (!strcmpi(flag,"pvp")) { - if( state && map[m].flag.pvp ) + if( state && map->list[m].flag.pvp ) ;/* nothing to do */ else { if( state ) - map_zone_mf_cache_add(m,"pvp off"); - else if( map[m].flag.pvp ) + map_zone_mf_cache_add(m,"pvp\toff"); + else if( map->list[m].flag.pvp ) map_zone_mf_cache_add(m,"pvp"); } } else if (!strcmpi(flag,"pvp_noparty")) { - if( state && map[m].flag.pvp_noparty ) + if( state && map->list[m].flag.pvp_noparty ) ;/* nothing to do */ else { if( state ) - map_zone_mf_cache_add(m,"pvp_noparty off"); - else if( map[m].flag.pvp_noparty ) + map_zone_mf_cache_add(m,"pvp_noparty\toff"); + else if( map->list[m].flag.pvp_noparty ) map_zone_mf_cache_add(m,"pvp_noparty"); } } else if (!strcmpi(flag,"pvp_noguild")) { - if( state && map[m].flag.pvp_noguild ) + if( state && map->list[m].flag.pvp_noguild ) ;/* nothing to do */ else { if( state ) - map_zone_mf_cache_add(m,"pvp_noguild off"); - else if( map[m].flag.pvp_noguild ) + map_zone_mf_cache_add(m,"pvp_noguild\toff"); + else if( map->list[m].flag.pvp_noguild ) map_zone_mf_cache_add(m,"pvp_noguild"); } } else if (!strcmpi(flag, "pvp_nightmaredrop")) { - if( state && map[m].flag.pvp_nightmaredrop ) + if( state && map->list[m].flag.pvp_nightmaredrop ) ;/* nothing to do */ else { if( state ) - map_zone_mf_cache_add(m,"pvp_nightmaredrop off"); - else if( map[m].flag.pvp_nightmaredrop ) + map_zone_mf_cache_add(m,"pvp_nightmaredrop\toff"); + else if( map->list[m].flag.pvp_nightmaredrop ) map_zone_mf_cache_add(m,"pvp_nightmaredrop"); } - /* not yet fully supported */ - /*char drop_arg1[16], drop_arg2[16]; +#if 0 /* not yet fully supported */ + char drop_arg1[16], drop_arg2[16]; int drop_per = 0; - if (sscanf(w4, "%[^,],%[^,],%d", drop_arg1, drop_arg2, &drop_per) == 3) { - int drop_id = 0, drop_type = 0; - if (!strcmpi(drop_arg1, "random")) - drop_id = -1; - else if (itemdb_exists((drop_id = atoi(drop_arg1))) == NULL) - drop_id = 0; - if (!strcmpi(drop_arg2, "inventory")) - drop_type = 1; - else if (!strcmpi(drop_arg2,"equip")) - drop_type = 2; - else if (!strcmpi(drop_arg2,"all")) - drop_type = 3; - - if (drop_id != 0){ - int i; - for (i = 0; i < MAX_DROP_PER_MAP; i++) { - if (map[m].drop_list[i].drop_id == 0){ - map[m].drop_list[i].drop_id = drop_id; - map[m].drop_list[i].drop_type = drop_type; - map[m].drop_list[i].drop_per = drop_per; - break; - } - } - map[m].flag.pvp_nightmaredrop = 1; - } + if (sscanf(w4, "%15[^,],%15[^,],%d", drop_arg1, drop_arg2, &drop_per) == 3) { + int drop_id = 0, drop_type = 0; + if (!strcmpi(drop_arg1, "random")) + drop_id = -1; + else if (itemdb->exists((drop_id = atoi(drop_arg1))) == NULL) + drop_id = 0; + if (!strcmpi(drop_arg2, "inventory")) + drop_type = 1; + else if (!strcmpi(drop_arg2,"equip")) + drop_type = 2; + else if (!strcmpi(drop_arg2,"all")) + drop_type = 3; + + if (drop_id != 0) { + int i; + for (i = 0; i < MAX_DROP_PER_MAP; i++) { + if (map->list[m].drop_list[i].drop_id == 0){ + map->list[m].drop_list[i].drop_id = drop_id; + map->list[m].drop_list[i].drop_type = drop_type; + map->list[m].drop_list[i].drop_per = drop_per; + break; + } + } + map->list[m].flag.pvp_nightmaredrop = 1; + } } else if (!state) //Disable - map[m].flag.pvp_nightmaredrop = 0; - */ + map->list[m].flag.pvp_nightmaredrop = 0; +#endif // 0 } else if (!strcmpi(flag,"pvp_nocalcrank")) { - if( state && map[m].flag.pvp_nocalcrank ) + if( state && map->list[m].flag.pvp_nocalcrank ) ;/* nothing to do */ else { if( state ) - map_zone_mf_cache_add(m,"pvp_nocalcrank off"); - else if( map[m].flag.pvp_nocalcrank ) + map_zone_mf_cache_add(m,"pvp_nocalcrank\toff"); + else if( map->list[m].flag.pvp_nocalcrank ) map_zone_mf_cache_add(m,"pvp_nocalcrank"); } } else if (!strcmpi(flag,"gvg")) { - if( state && map[m].flag.gvg ) + if( state && map->list[m].flag.gvg ) ;/* nothing to do */ else { if( state ) - map_zone_mf_cache_add(m,"gvg off"); - else if( map[m].flag.gvg ) + map_zone_mf_cache_add(m,"gvg\toff"); + else if( map->list[m].flag.gvg ) map_zone_mf_cache_add(m,"gvg"); } } else if (!strcmpi(flag,"gvg_noparty")) { - if( state && map[m].flag.gvg_noparty ) + if( state && map->list[m].flag.gvg_noparty ) ;/* nothing to do */ else { if( state ) - map_zone_mf_cache_add(m,"gvg_noparty off"); - else if( map[m].flag.gvg_noparty ) + map_zone_mf_cache_add(m,"gvg_noparty\toff"); + else if( map->list[m].flag.gvg_noparty ) map_zone_mf_cache_add(m,"gvg_noparty"); } } else if (!strcmpi(flag,"gvg_dungeon")) { - if( state && map[m].flag.gvg_dungeon ) + if( state && map->list[m].flag.gvg_dungeon ) ;/* nothing to do */ else { if( state ) - map_zone_mf_cache_add(m,"gvg_dungeon off"); - else if( map[m].flag.gvg_dungeon ) + map_zone_mf_cache_add(m,"gvg_dungeon\toff"); + else if( map->list[m].flag.gvg_dungeon ) map_zone_mf_cache_add(m,"gvg_dungeon"); } } else if (!strcmpi(flag,"gvg_castle")) { - if( state && map[m].flag.gvg_castle ) + if( state && map->list[m].flag.gvg_castle ) ;/* nothing to do */ else { if( state ) - map_zone_mf_cache_add(m,"gvg_castle off"); - else if( map[m].flag.gvg_castle ) + map_zone_mf_cache_add(m,"gvg_castle\toff"); + else if( map->list[m].flag.gvg_castle ) map_zone_mf_cache_add(m,"gvg_castle"); } } else if (!strcmpi(flag,"battleground")) { - if( state && map[m].flag.battleground ) + if( state && map->list[m].flag.battleground ) ;/* nothing to do */ else { if( state ) - map_zone_mf_cache_add(m,"battleground off"); - else if( map[m].flag.battleground ) + map_zone_mf_cache_add(m,"battleground\toff"); + else if( map->list[m].flag.battleground ) map_zone_mf_cache_add(m,"battleground"); } } else if (!strcmpi(flag,"noexppenalty")) { - if( state && map[m].flag.noexppenalty ) + if( state && map->list[m].flag.noexppenalty ) ;/* nothing to do */ else { if( state ) - map_zone_mf_cache_add(m,"noexppenalty off"); - else if( map[m].flag.noexppenalty ) + map_zone_mf_cache_add(m,"noexppenalty\toff"); + else if( map->list[m].flag.noexppenalty ) map_zone_mf_cache_add(m,"noexppenalty"); } } else if (!strcmpi(flag,"nozenypenalty")) { - if( state && map[m].flag.nozenypenalty ) + if( state && map->list[m].flag.nozenypenalty ) ;/* nothing to do */ else { if( state ) - map_zone_mf_cache_add(m,"nozenypenalty off"); - else if( map[m].flag.nozenypenalty ) + map_zone_mf_cache_add(m,"nozenypenalty\toff"); + else if( map->list[m].flag.nozenypenalty ) map_zone_mf_cache_add(m,"nozenypenalty"); } } else if (!strcmpi(flag,"notrade")) { - if( state && map[m].flag.notrade ) + if( state && map->list[m].flag.notrade ) ;/* nothing to do */ else { if( state ) - map_zone_mf_cache_add(m,"notrade off"); - else if( map[m].flag.notrade ) + map_zone_mf_cache_add(m,"notrade\toff"); + else if( map->list[m].flag.notrade ) map_zone_mf_cache_add(m,"notrade"); } } else if (!strcmpi(flag,"novending")) { - if( state && map[m].flag.novending ) + if( state && map->list[m].flag.novending ) ;/* nothing to do */ else { if( state ) - map_zone_mf_cache_add(m,"novending off"); - else if( map[m].flag.novending ) + map_zone_mf_cache_add(m,"novending\toff"); + else if( map->list[m].flag.novending ) map_zone_mf_cache_add(m,"novending"); } } else if (!strcmpi(flag,"nodrop")) { - if( state && map[m].flag.nodrop ) + if( state && map->list[m].flag.nodrop ) ;/* nothing to do */ else { if( state ) - map_zone_mf_cache_add(m,"nodrop off"); - else if( map[m].flag.nodrop ) + map_zone_mf_cache_add(m,"nodrop\toff"); + else if( map->list[m].flag.nodrop ) map_zone_mf_cache_add(m,"nodrop"); } } else if (!strcmpi(flag,"noskill")) { - if( state && map[m].flag.noskill ) + if( state && map->list[m].flag.noskill ) ;/* nothing to do */ else { if( state ) - map_zone_mf_cache_add(m,"noskill off"); - else if( map[m].flag.noskill ) + map_zone_mf_cache_add(m,"noskill\toff"); + else if( map->list[m].flag.noskill ) map_zone_mf_cache_add(m,"noskill"); } } else if (!strcmpi(flag,"noicewall")) { - if( state && map[m].flag.noicewall ) + if( state && map->list[m].flag.noicewall ) ;/* nothing to do */ else { if( state ) - map_zone_mf_cache_add(m,"noicewall off"); - else if( map[m].flag.noicewall ) + map_zone_mf_cache_add(m,"noicewall\toff"); + else if( map->list[m].flag.noicewall ) map_zone_mf_cache_add(m,"noicewall"); } } else if (!strcmpi(flag,"snow")) { - if( state && map[m].flag.snow ) + if( state && map->list[m].flag.snow ) ;/* nothing to do */ else { if( state ) - map_zone_mf_cache_add(m,"snow off"); - else if( map[m].flag.snow ) + map_zone_mf_cache_add(m,"snow\toff"); + else if( map->list[m].flag.snow ) map_zone_mf_cache_add(m,"snow"); } } else if (!strcmpi(flag,"clouds")) { - if( state && map[m].flag.clouds ) + if( state && map->list[m].flag.clouds ) ;/* nothing to do */ else { if( state ) - map_zone_mf_cache_add(m,"clouds off"); - else if( map[m].flag.clouds ) + map_zone_mf_cache_add(m,"clouds\toff"); + else if( map->list[m].flag.clouds ) map_zone_mf_cache_add(m,"clouds"); } } else if (!strcmpi(flag,"clouds2")) { - if( state && map[m].flag.clouds2 ) + if( state && map->list[m].flag.clouds2 ) ;/* nothing to do */ else { if( state ) - map_zone_mf_cache_add(m,"clouds2 off"); - else if( map[m].flag.clouds2 ) + map_zone_mf_cache_add(m,"clouds2\toff"); + else if( map->list[m].flag.clouds2 ) map_zone_mf_cache_add(m,"clouds2"); } } else if (!strcmpi(flag,"fog")) { - if( state && map[m].flag.fog ) + if( state && map->list[m].flag.fog ) ;/* nothing to do */ else { if( state ) - map_zone_mf_cache_add(m,"fog off"); - else if( map[m].flag.fog ) + map_zone_mf_cache_add(m,"fog\toff"); + else if( map->list[m].flag.fog ) map_zone_mf_cache_add(m,"fog"); } } else if (!strcmpi(flag,"fireworks")) { - if( state && map[m].flag.fireworks ) + if( state && map->list[m].flag.fireworks ) ;/* nothing to do */ else { if( state ) - map_zone_mf_cache_add(m,"fireworks off"); - else if( map[m].flag.fireworks ) + map_zone_mf_cache_add(m,"fireworks\toff"); + else if( map->list[m].flag.fireworks ) map_zone_mf_cache_add(m,"fireworks"); } } else if (!strcmpi(flag,"sakura")) { - if( state && map[m].flag.sakura ) + if( state && map->list[m].flag.sakura ) ;/* nothing to do */ else { if( state ) - map_zone_mf_cache_add(m,"sakura off"); - else if( map[m].flag.sakura ) + map_zone_mf_cache_add(m,"sakura\toff"); + else if( map->list[m].flag.sakura ) map_zone_mf_cache_add(m,"sakura"); } } else if (!strcmpi(flag,"leaves")) { - if( state && map[m].flag.leaves ) + if( state && map->list[m].flag.leaves ) ;/* nothing to do */ else { if( state ) - map_zone_mf_cache_add(m,"leaves off"); - else if( map[m].flag.leaves ) + map_zone_mf_cache_add(m,"leaves\toff"); + else if( map->list[m].flag.leaves ) map_zone_mf_cache_add(m,"leaves"); } } else if (!strcmpi(flag,"nightenabled")) { - if( state && map[m].flag.nightenabled ) + if( state && map->list[m].flag.nightenabled ) ;/* nothing to do */ else { if( state ) - map_zone_mf_cache_add(m,"nightenabled off"); - else if( map[m].flag.nightenabled ) + map_zone_mf_cache_add(m,"nightenabled\toff"); + else if( map->list[m].flag.nightenabled ) map_zone_mf_cache_add(m,"nightenabled"); } } else if (!strcmpi(flag,"noexp")) { - if( state && map[m].flag.nobaseexp ) + if( state && map->list[m].flag.nobaseexp ) ;/* nothing to do */ else { if( state ) - map_zone_mf_cache_add(m,"noexp off"); - else if( map[m].flag.nobaseexp ) + map_zone_mf_cache_add(m,"noexp\toff"); + else if( map->list[m].flag.nobaseexp ) map_zone_mf_cache_add(m,"noexp"); } } else if (!strcmpi(flag,"nobaseexp")) { - if( state && map[m].flag.nobaseexp ) + if( state && map->list[m].flag.nobaseexp ) ;/* nothing to do */ else { if( state ) - map_zone_mf_cache_add(m,"nobaseexp off"); - else if( map[m].flag.nobaseexp ) + map_zone_mf_cache_add(m,"nobaseexp\toff"); + else if( map->list[m].flag.nobaseexp ) map_zone_mf_cache_add(m,"nobaseexp"); } } else if (!strcmpi(flag,"nojobexp")) { - if( state && map[m].flag.nojobexp ) + if( state && map->list[m].flag.nojobexp ) ;/* nothing to do */ else { if( state ) - map_zone_mf_cache_add(m,"nojobexp off"); - else if( map[m].flag.nojobexp ) + map_zone_mf_cache_add(m,"nojobexp\toff"); + else if( map->list[m].flag.nojobexp ) map_zone_mf_cache_add(m,"nojobexp"); } } else if (!strcmpi(flag,"noloot")) { - if( state && map[m].flag.nomobloot ) + if( state && map->list[m].flag.nomobloot ) ;/* nothing to do */ else { if( state ) - map_zone_mf_cache_add(m,"noloot off"); - else if( map[m].flag.nomobloot ) + map_zone_mf_cache_add(m,"noloot\toff"); + else if( map->list[m].flag.nomobloot ) map_zone_mf_cache_add(m,"noloot"); } } else if (!strcmpi(flag,"nomobloot")) { - if( state && map[m].flag.nomobloot ) + if( state && map->list[m].flag.nomobloot ) ;/* nothing to do */ else { if( state ) - map_zone_mf_cache_add(m,"nomobloot off"); - else if( map[m].flag.nomobloot ) + map_zone_mf_cache_add(m,"nomobloot\toff"); + else if( map->list[m].flag.nomobloot ) map_zone_mf_cache_add(m,"nomobloot"); } } else if (!strcmpi(flag,"nomvploot")) { - if( state && map[m].flag.nomvploot ) + if( state && map->list[m].flag.nomvploot ) ;/* nothing to do */ else { if( state ) - map_zone_mf_cache_add(m,"nomvploot off"); - else if( map[m].flag.nomvploot ) + map_zone_mf_cache_add(m,"nomvploot\toff"); + else if( map->list[m].flag.nomvploot ) map_zone_mf_cache_add(m,"nomvploot"); } } else if (!strcmpi(flag,"nocommand")) { /* implementation may be incomplete */ if( state && sscanf(params, "%d", &state) == 1 ) { - sprintf(rflag, "nocommand %s",params); + sprintf(rflag, "nocommand\t%s",params); map_zone_mf_cache_add(m,rflag); - } else if( !state && map[m].nocommand ) { - sprintf(rflag, "nocommand %d",map[m].nocommand); + } else if( !state && map->list[m].nocommand ) { + sprintf(rflag, "nocommand\t%d",map->list[m].nocommand); map_zone_mf_cache_add(m,rflag); - } else if( map[m].nocommand ) { - map_zone_mf_cache_add(m,"nocommand off"); + } else if( map->list[m].nocommand ) { + map_zone_mf_cache_add(m,"nocommand\toff"); } } else if (!strcmpi(flag,"jexp")) { if( !state ) { - if( map[m].jexp != 100 ) { - sprintf(rflag,"jexp %d",map[m].jexp); + if( map->list[m].jexp != 100 ) { + sprintf(rflag,"jexp\t%d",map->list[m].jexp); map_zone_mf_cache_add(m,rflag); } } if( sscanf(params, "%d", &state) == 1 ) { - if( state != map[m].jexp ) { - sprintf(rflag,"jexp %s",params); + if( state != map->list[m].jexp ) { + sprintf(rflag,"jexp\t%s",params); map_zone_mf_cache_add(m,rflag); } } } else if (!strcmpi(flag,"bexp")) { if( !state ) { - if( map[m].bexp != 100 ) { - sprintf(rflag,"bexp %d",map[m].jexp); + if( map->list[m].bexp != 100 ) { + sprintf(rflag,"bexp\t%d",map->list[m].jexp); map_zone_mf_cache_add(m,rflag); } } if( sscanf(params, "%d", &state) == 1 ) { - if( state != map[m].bexp ) { - sprintf(rflag,"bexp %s",params); + if( state != map->list[m].bexp ) { + sprintf(rflag,"bexp\t%s",params); map_zone_mf_cache_add(m,rflag); } } } else if (!strcmpi(flag,"loadevent")) { - if( state && map[m].flag.loadevent ) + if( state && map->list[m].flag.loadevent ) ;/* nothing to do */ else { if( state ) - map_zone_mf_cache_add(m,"loadevent off"); - else if( map[m].flag.loadevent ) + map_zone_mf_cache_add(m,"loadevent\toff"); + else if( map->list[m].flag.loadevent ) map_zone_mf_cache_add(m,"loadevent"); } } else if (!strcmpi(flag,"nochat")) { - if( state && map[m].flag.nochat ) + if( state && map->list[m].flag.nochat ) ;/* nothing to do */ else { if( state ) - map_zone_mf_cache_add(m,"nochat off"); - else if( map[m].flag.nochat ) + map_zone_mf_cache_add(m,"nochat\toff"); + else if( map->list[m].flag.nochat ) map_zone_mf_cache_add(m,"nochat"); } } else if (!strcmpi(flag,"partylock")) { - if( state && map[m].flag.partylock ) + if( state && map->list[m].flag.partylock ) ;/* nothing to do */ else { if( state ) - map_zone_mf_cache_add(m,"partylock off"); - else if( map[m].flag.partylock ) + map_zone_mf_cache_add(m,"partylock\toff"); + else if( map->list[m].flag.partylock ) map_zone_mf_cache_add(m,"partylock"); } } else if (!strcmpi(flag,"guildlock")) { - if( state && map[m].flag.guildlock ) + if( state && map->list[m].flag.guildlock ) ;/* nothing to do */ else { if( state ) - map_zone_mf_cache_add(m,"guildlock off"); - else if( map[m].flag.guildlock ) + map_zone_mf_cache_add(m,"guildlock\toff"); + else if( map->list[m].flag.guildlock ) map_zone_mf_cache_add(m,"guildlock"); } } else if (!strcmpi(flag,"reset")) { - if( state && map[m].flag.reset ) + if( state && map->list[m].flag.reset ) ;/* nothing to do */ else { if( state ) - map_zone_mf_cache_add(m,"reset off"); - else if( map[m].flag.reset ) + map_zone_mf_cache_add(m,"reset\toff"); + else if( map->list[m].flag.reset ) map_zone_mf_cache_add(m,"reset"); } } else if (!strcmpi(flag,"adjust_unit_duration")) { int skill_id, k; char skill_name[MAP_ZONE_MAPFLAG_LENGTH], modifier[MAP_ZONE_MAPFLAG_LENGTH]; - int len = strlen(params); + size_t len = strlen(params); modifier[0] = '\0'; memcpy(skill_name, params, MAP_ZONE_MAPFLAG_LENGTH); @@ -4209,27 +4409,26 @@ bool map_zone_mf_cache(int m, char *flag, char *params) { } if( modifier[0] == '\0' || !( skill_id = skill->name2id(skill_name) ) || !skill->get_unit_id( skill->name2id(skill_name), 0) || atoi(modifier) < 1 || atoi(modifier) > USHRT_MAX ) { - ;/* we dont mind it, the server will take care of it next. */ + ;/* we don't mind it, the server will take care of it next. */ } else { - int idx = map[m].unit_count; + int idx = map->list[m].unit_count; - k = 0; - ARR_FIND(0, idx, k, map[m].units[k]->skill_id == skill_id); + ARR_FIND(0, idx, k, map->list[m].units[k]->skill_id == skill_id); if( k < idx ) { - if( atoi(modifier) != map[m].units[k]->modifier ) { - sprintf(rflag,"adjust_unit_duration %s %d",skill_name,map[m].units[k]->modifier); + if( atoi(modifier) != map->list[m].units[k]->modifier ) { + sprintf(rflag,"adjust_unit_duration\t%s\t%d",skill_name,map->list[m].units[k]->modifier); map_zone_mf_cache_add(m,rflag); } } else { - sprintf(rflag,"adjust_unit_duration %s 100",skill_name); + sprintf(rflag,"adjust_unit_duration\t%s\t100",skill_name); map_zone_mf_cache_add(m,rflag); - } + } } } else if (!strcmpi(flag,"adjust_skill_damage")) { int skill_id, k; char skill_name[MAP_ZONE_MAPFLAG_LENGTH], modifier[MAP_ZONE_MAPFLAG_LENGTH]; - int len = strlen(params); + size_t len = strlen(params); modifier[0] = '\0'; memcpy(skill_name, params, MAP_ZONE_MAPFLAG_LENGTH); @@ -4243,127 +4442,136 @@ bool map_zone_mf_cache(int m, char *flag, char *params) { } if( modifier[0] == '\0' || !( skill_id = skill->name2id(skill_name) ) || atoi(modifier) < 1 || atoi(modifier) > USHRT_MAX ) { - ;/* we dont mind it, the server will take care of it next. */ + ;/* we don't mind it, the server will take care of it next. */ } else { - int idx = map[m].skill_count; + int idx = map->list[m].skill_count; - k = 0; - ARR_FIND(0, idx, k, map[m].skills[k]->skill_id == skill_id); + ARR_FIND(0, idx, k, map->list[m].skills[k]->skill_id == skill_id); if( k < idx ) { - if( atoi(modifier) != map[m].skills[k]->modifier ) { - sprintf(rflag,"adjust_skill_damage %s %d",skill_name,map[m].skills[k]->modifier); + if( atoi(modifier) != map->list[m].skills[k]->modifier ) { + sprintf(rflag,"adjust_skill_damage\t%s\t%d",skill_name,map->list[m].skills[k]->modifier); map_zone_mf_cache_add(m,rflag); } } else { - sprintf(rflag,"adjust_skill_damage %s 100",skill_name); + sprintf(rflag,"adjust_skill_damage\t%s\t100",skill_name); map_zone_mf_cache_add(m,rflag); } } } else if (!strcmpi(flag,"zone")) { - ShowWarning("You can't add a zone through a zone! ERROR, skipping for '%s'...\n",map[m].name); + ShowWarning("You can't add a zone through a zone! ERROR, skipping for '%s'...\n",map->list[m].name); return true; } else if ( !strcmpi(flag,"nomapchannelautojoin") ) { - if( state && map[m].flag.chsysnolocalaj ) + if( state && map->list[m].flag.chsysnolocalaj ) ;/* nothing to do */ else { if( state ) - map_zone_mf_cache_add(m,"nomapchannelautojoin off"); - else if( map[m].flag.chsysnolocalaj ) + map_zone_mf_cache_add(m,"nomapchannelautojoin\toff"); + else if( map->list[m].flag.chsysnolocalaj ) map_zone_mf_cache_add(m,"nomapchannelautojoin"); } } else if ( !strcmpi(flag,"invincible_time_inc") ) { if( !state ) { - if( map[m].invincible_time_inc != 0 ) { - sprintf(rflag,"invincible_time_inc %d",map[m].invincible_time_inc); + if( map->list[m].invincible_time_inc != 0 ) { + sprintf(rflag,"invincible_time_inc\t%d",map->list[m].invincible_time_inc); map_zone_mf_cache_add(m,rflag); } } if( sscanf(params, "%d", &state) == 1 ) { - if( state != map[m].invincible_time_inc ) { - sprintf(rflag,"invincible_time_inc %s",params); + if( state != map->list[m].invincible_time_inc ) { + sprintf(rflag,"invincible_time_inc\t%s",params); map_zone_mf_cache_add(m,rflag); } } } else if ( !strcmpi(flag,"noknockback") ) { - if( state && map[m].flag.noknockback ) + if( state && map->list[m].flag.noknockback ) ;/* nothing to do */ else { if( state ) - map_zone_mf_cache_add(m,"noknockback off"); - else if( map[m].flag.noknockback ) + map_zone_mf_cache_add(m,"noknockback\toff"); + else if( map->list[m].flag.noknockback ) map_zone_mf_cache_add(m,"noknockback"); } } else if ( !strcmpi(flag,"weapon_damage_rate") ) { if( !state ) { - if( map[m].weapon_damage_rate != 100 ) { - sprintf(rflag,"weapon_damage_rate %d",map[m].weapon_damage_rate); + if( map->list[m].weapon_damage_rate != 100 ) { + sprintf(rflag,"weapon_damage_rate\t%d",map->list[m].weapon_damage_rate); map_zone_mf_cache_add(m,rflag); } } if( sscanf(params, "%d", &state) == 1 ) { - if( state != map[m].weapon_damage_rate ) { - sprintf(rflag,"weapon_damage_rate %s",params); + if( state != map->list[m].weapon_damage_rate ) { + sprintf(rflag,"weapon_damage_rate\t%s",params); map_zone_mf_cache_add(m,rflag); } } } else if ( !strcmpi(flag,"magic_damage_rate") ) { if( !state ) { - if( map[m].magic_damage_rate != 100 ) { - sprintf(rflag,"magic_damage_rate %d",map[m].magic_damage_rate); + if( map->list[m].magic_damage_rate != 100 ) { + sprintf(rflag,"magic_damage_rate\t%d",map->list[m].magic_damage_rate); map_zone_mf_cache_add(m,rflag); } } if( sscanf(params, "%d", &state) == 1 ) { - if( state != map[m].magic_damage_rate ) { - sprintf(rflag,"magic_damage_rate %s",params); + if( state != map->list[m].magic_damage_rate ) { + sprintf(rflag,"magic_damage_rate\t%s",params); map_zone_mf_cache_add(m,rflag); } } } else if ( !strcmpi(flag,"misc_damage_rate") ) { if( !state ) { - if( map[m].misc_damage_rate != 100 ) { - sprintf(rflag,"misc_damage_rate %d",map[m].misc_damage_rate); + if( map->list[m].misc_damage_rate != 100 ) { + sprintf(rflag,"misc_damage_rate\t%d",map->list[m].misc_damage_rate); map_zone_mf_cache_add(m,rflag); } } if( sscanf(params, "%d", &state) == 1 ) { - if( state != map[m].misc_damage_rate ) { - sprintf(rflag,"misc_damage_rate %s",params); + if( state != map->list[m].misc_damage_rate ) { + sprintf(rflag,"misc_damage_rate\t%s",params); map_zone_mf_cache_add(m,rflag); } } } else if ( !strcmpi(flag,"short_damage_rate") ) { if( !state ) { - if( map[m].short_damage_rate != 100 ) { - sprintf(rflag,"short_damage_rate %d",map[m].short_damage_rate); + if( map->list[m].short_damage_rate != 100 ) { + sprintf(rflag,"short_damage_rate\t%d",map->list[m].short_damage_rate); map_zone_mf_cache_add(m,rflag); } } if( sscanf(params, "%d", &state) == 1 ) { - if( state != map[m].short_damage_rate ) { - sprintf(rflag,"short_damage_rate %s",params); + if( state != map->list[m].short_damage_rate ) { + sprintf(rflag,"short_damage_rate\t%s",params); map_zone_mf_cache_add(m,rflag); } } } else if ( !strcmpi(flag,"long_damage_rate") ) { if( !state ) { - if( map[m].long_damage_rate != 100 ) { - sprintf(rflag,"long_damage_rate %d",map[m].long_damage_rate); + if( map->list[m].long_damage_rate != 100 ) { + sprintf(rflag,"long_damage_rate\t%d",map->list[m].long_damage_rate); map_zone_mf_cache_add(m,rflag); } } if( sscanf(params, "%d", &state) == 1 ) { - if( state != map[m].long_damage_rate ) { - sprintf(rflag,"long_damage_rate %s",params); + if( state != map->list[m].long_damage_rate ) { + sprintf(rflag,"long_damage_rate\t%s",params); map_zone_mf_cache_add(m,rflag); } } + } else if (!strcmpi(flag,"nocashshop")) { + if( state && map->list[m].flag.nocashshop ) + ;/* nothing to do */ + else { + if( state ) + map_zone_mf_cache_add(m,"nocashshop\toff"); + else if( map->list[m].flag.nocashshop ) + map_zone_mf_cache_add(m,"nocashshop"); + } } + return false; } void map_zone_apply(int m, struct map_zone_data *zone, const char* start, const char* buffer, const char* filepath) { int i; char empty[1] = "\0"; char flag[MAP_ZONE_MAPFLAG_LENGTH], params[MAP_ZONE_MAPFLAG_LENGTH]; - map[m].zone = zone; + map->list[m].zone = zone; for(i = 0; i < zone->mapflags_count; i++) { - int len = strlen(zone->mapflags[i]); + size_t len = strlen(zone->mapflags[i]); int k; params[0] = '\0'; memcpy(flag, zone->mapflags[i], MAP_ZONE_MAPFLAG_LENGTH); @@ -4375,10 +4583,10 @@ void map_zone_apply(int m, struct map_zone_data *zone, const char* start, const } } - if( map_zone_mf_cache(m,flag,params) ) + if( map->zone_mf_cache(m,flag,params) ) continue; - npc_parse_mapflag(map[m].name,empty,flag,params,start,buffer,filepath); + npc->parse_mapflag(map->list[m].name, empty, flag, params, start, buffer, filepath, NULL); } } /* used on npc load and reload to apply all "Normal" and "PK Mode" zones */ @@ -4388,10 +4596,10 @@ void map_zone_init(void) { char empty[1] = "\0"; int i,k,j; - zone = &map_zone_all; + zone = &map->zone_all; for(i = 0; i < zone->mapflags_count; i++) { - int len = strlen(zone->mapflags[i]); + size_t len = strlen(zone->mapflags[i]); params[0] = '\0'; memcpy(flag, zone->mapflags[i], MAP_ZONE_MAPFLAG_LENGTH); for(k = 0; k < len; k++) { @@ -4402,19 +4610,19 @@ void map_zone_init(void) { } } - for(j = 0; j < iMap->map_num; j++) { - if( map[j].zone == zone ) { - if( map_zone_mf_cache(j,flag,params) ) + for(j = 0; j < map->count; j++) { + if( map->list[j].zone == zone ) { + if( map->zone_mf_cache(j,flag,params) ) break; - npc_parse_mapflag(map[j].name,empty,flag,params,empty,empty,empty); + npc->parse_mapflag(map->list[j].name, empty, flag, params, empty, empty, empty, NULL); } } } if( battle_config.pk_mode ) { - zone = &map_zone_pk; + zone = &map->zone_pk; for(i = 0; i < zone->mapflags_count; i++) { - int len = strlen(zone->mapflags[i]); + size_t len = strlen(zone->mapflags[i]); params[0] = '\0'; memcpy(flag, zone->mapflags[i], MAP_ZONE_MAPFLAG_LENGTH); for(k = 0; k < len; k++) { @@ -4424,11 +4632,11 @@ void map_zone_init(void) { break; } } - for(j = 0; j < iMap->map_num; j++) { - if( map[j].zone == zone ) { - if( map_zone_mf_cache(j,flag,params) ) + for(j = 0; j < map->count; j++) { + if( map->list[j].zone == zone ) { + if( map->zone_mf_cache(j,flag,params) ) break; - npc_parse_mapflag(map[j].name,empty,flag,params,empty,empty,empty); + npc->parse_mapflag(map->list[j].name, empty, flag, params, empty, empty, empty, NULL); } } } @@ -4440,12 +4648,12 @@ unsigned short map_zone_str2itemid(const char *name) { if( !name ) return 0; - if( name[0] == 'I' && name[1] == 'D' && strlen(name) <= 7 ) { - if( !( data = itemdb_exists(atoi(name+2))) ) { + if( name[0] == 'I' && name[1] == 'D' && strlen(name) < 8 ) { + if( !( data = itemdb->exists(atoi(name+2))) ) { return 0; } } else { - if( !( data = itemdb_searchname(name) ) ) { + if( !( data = itemdb->search_name(name) ) ) { return 0; } } @@ -4457,11 +4665,11 @@ unsigned short map_zone_str2skillid(const char *name) { if( !name ) return 0; - if( name[0] == 'I' && name[1] == 'D' && strlen(name) <= 7 ) { + if( name[0] == 'I' && name[1] == 'D' && strlen(name) < 8 ) { if( !skill->get_index((nameid = atoi(name+2))) ) return 0; } else { - if( !( nameid = strdb_iget(skilldb_name2id, name) ) ) { + if( !( nameid = strdb_iget(skill->name2id_db, name) ) ) { return 0; } } @@ -4521,10 +4729,10 @@ void read_map_zone_db(void) { #else const char *config_filename = "db/pre-re/map_zone_db.conf"; // FIXME hardcoded name #endif - if (conf_read_file(&map_zone_db, config_filename)) + if (libconfig->read_file(&map_zone_db, config_filename)) return; - zones = config_lookup(&map_zone_db, "zones"); + zones = libconfig->lookup(&map_zone_db, "zones"); if (zones != NULL) { struct map_zone_data *zone; @@ -4541,24 +4749,24 @@ void read_map_zone_db(void) { disabled_commands_count = 0, capped_skills_count = 0; enum map_zone_skill_subtype subtype; - zone_count = config_setting_length(zones); + zone_count = libconfig->setting_length(zones); for (i = 0; i < zone_count; ++i) { bool is_all = false; - zone_e = config_setting_get_elem(zones, i); + zone_e = libconfig->setting_get_elem(zones, i); - if (!config_setting_lookup_string(zone_e, "name", &zonename)) { + if (!libconfig->setting_lookup_string(zone_e, "name", &zonename)) { ShowError("map_zone_db: missing zone name, skipping... (%s:%d)\n", config_setting_source_file(zone_e), config_setting_source_line(zone_e)); - config_setting_remove_elem(zones,i);/* remove from the tree */ + libconfig->setting_remove_elem(zones,i);/* remove from the tree */ --zone_count; --i; continue; } - if( strdb_exists(zone_db, zonename) ) { + if( strdb_exists(map->zone_db, zonename) ) { ShowError("map_zone_db: duplicate zone name '%s', skipping...\n",zonename); - config_setting_remove_elem(zones,i);/* remove from the tree */ + libconfig->setting_remove_elem(zones,i);/* remove from the tree */ --zone_count; --i; continue; @@ -4566,46 +4774,46 @@ void read_map_zone_db(void) { /* is this the global template? */ if( strncmpi(zonename,MAP_ZONE_NORMAL_NAME,MAP_ZONE_NAME_LENGTH) == 0 ) { - zone = &map_zone_all; + zone = &map->zone_all; is_all = true; } else if( strncmpi(zonename,MAP_ZONE_PK_NAME,MAP_ZONE_NAME_LENGTH) == 0 ) { - zone = &map_zone_pk; + zone = &map->zone_pk; is_all = true; } else { CREATE( zone, struct map_zone_data, 1 ); zone->disabled_skills_count = 0; zone->disabled_items_count = 0; } - safestrncpy(zone->name, zonename, MAP_ZONE_NAME_LENGTH); + safestrncpy(zone->name, zonename, MAP_ZONE_NAME_LENGTH/2); - if( (skills = config_setting_get_member(zone_e, "disabled_skills")) != NULL ) { - disabled_skills_count = config_setting_length(skills); + if( (skills = libconfig->setting_get_member(zone_e, "disabled_skills")) != NULL ) { + disabled_skills_count = libconfig->setting_length(skills); /* validate */ - for(h = 0; h < config_setting_length(skills); h++) { - config_setting_t *skill = config_setting_get_elem(skills, h); - name = config_setting_name(skill); - if( !map_zone_str2skillid(name) ) { + for(h = 0; h < libconfig->setting_length(skills); h++) { + config_setting_t *skillinfo = libconfig->setting_get_elem(skills, h); + name = config_setting_name(skillinfo); + if( !map->zone_str2skillid(name) ) { ShowError("map_zone_db: unknown skill (%s) in disabled_skills for zone '%s', skipping skill...\n",name,zone->name); - config_setting_remove_elem(skills,h); + libconfig->setting_remove_elem(skills,h); --disabled_skills_count; --h; continue; } - if( !map_zone_bl_type(config_setting_get_string_elem(skills,h),&subtype) )/* we dont remove it from the three due to inheritance */ + if( !map->zone_bl_type(libconfig->setting_get_string_elem(skills,h),&subtype) )/* we don't remove it from the three due to inheritance */ --disabled_skills_count; } /* all ok, process */ CREATE( zone->disabled_skills, struct map_zone_disabled_skill_entry *, disabled_skills_count ); - for(h = 0, v = 0; h < config_setting_length(skills); h++) { - config_setting_t *skill = config_setting_get_elem(skills, h); + for(h = 0, v = 0; h < libconfig->setting_length(skills); h++) { + config_setting_t *skillinfo = libconfig->setting_get_elem(skills, h); struct map_zone_disabled_skill_entry * entry; enum bl_type type; - name = config_setting_name(skill); + name = config_setting_name(skillinfo); - if( (type = map_zone_bl_type(config_setting_get_string_elem(skills,h),&subtype)) ) { /* only add if enabled */ + if( (type = map->zone_bl_type(libconfig->setting_get_string_elem(skills,h),&subtype)) ) { /* only add if enabled */ CREATE( entry, struct map_zone_disabled_skill_entry, 1 ); - entry->nameid = map_zone_str2skillid(name); + entry->nameid = map->zone_str2skillid(name); entry->type = type; entry->subtype = subtype; @@ -4616,44 +4824,44 @@ void read_map_zone_db(void) { zone->disabled_skills_count = disabled_skills_count; } - if( (items = config_setting_get_member(zone_e, "disabled_items")) != NULL ) { - disabled_items_count = config_setting_length(items); + if( (items = libconfig->setting_get_member(zone_e, "disabled_items")) != NULL ) { + disabled_items_count = libconfig->setting_length(items); /* validate */ - for(h = 0; h < config_setting_length(items); h++) { - config_setting_t *item = config_setting_get_elem(items, h); + for(h = 0; h < libconfig->setting_length(items); h++) { + config_setting_t *item = libconfig->setting_get_elem(items, h); name = config_setting_name(item); - if( !map_zone_str2itemid(name) ) { + if( !map->zone_str2itemid(name) ) { ShowError("map_zone_db: unknown item (%s) in disabled_items for zone '%s', skipping item...\n",name,zone->name); - config_setting_remove_elem(items,h); + libconfig->setting_remove_elem(items,h); --disabled_items_count; --h; continue; } - if( !config_setting_get_bool(item) )/* we dont remove it from the three due to inheritance */ + if( !libconfig->setting_get_bool(item) )/* we don't remove it from the three due to inheritance */ --disabled_items_count; } /* all ok, process */ CREATE( zone->disabled_items, int, disabled_items_count ); - for(h = 0, v = 0; h < config_setting_length(items); h++) { - config_setting_t *item = config_setting_get_elem(items, h); + for(h = 0, v = 0; h < libconfig->setting_length(items); h++) { + config_setting_t *item = libconfig->setting_get_elem(items, h); - if( config_setting_get_bool(item) ) { /* only add if enabled */ + if( libconfig->setting_get_bool(item) ) { /* only add if enabled */ name = config_setting_name(item); - zone->disabled_items[v++] = map_zone_str2itemid(name); + zone->disabled_items[v++] = map->zone_str2itemid(name); } } zone->disabled_items_count = disabled_items_count; } - if( (mapflags = config_setting_get_member(zone_e, "mapflags")) != NULL ) { - mapflags_count = config_setting_length(mapflags); + if( (mapflags = libconfig->setting_get_member(zone_e, "mapflags")) != NULL ) { + mapflags_count = libconfig->setting_length(mapflags); /* mapflags are not validated here, so we save all anyway */ CREATE( zone->mapflags, char *, mapflags_count ); for(h = 0; h < mapflags_count; h++) { CREATE( zone->mapflags[h], char, MAP_ZONE_MAPFLAG_LENGTH ); - name = config_setting_get_string_elem(mapflags, h); + name = libconfig->setting_get_string_elem(mapflags, h); safestrncpy(zone->mapflags[h], name, MAP_ZONE_MAPFLAG_LENGTH); @@ -4661,81 +4869,81 @@ void read_map_zone_db(void) { zone->mapflags_count = mapflags_count; } - if( (commands = config_setting_get_member(zone_e, "disabled_commands")) != NULL ) { - disabled_commands_count = config_setting_length(commands); + if( (commands = libconfig->setting_get_member(zone_e, "disabled_commands")) != NULL ) { + disabled_commands_count = libconfig->setting_length(commands); /* validate */ - for(h = 0; h < config_setting_length(commands); h++) { - config_setting_t *command = config_setting_get_elem(commands, h); + for(h = 0; h < libconfig->setting_length(commands); h++) { + config_setting_t *command = libconfig->setting_get_elem(commands, h); name = config_setting_name(command); if( !atcommand->exists(name) ) { ShowError("map_zone_db: unknown command '%s' in disabled_commands for zone '%s', skipping entry...\n",name,zone->name); - config_setting_remove_elem(commands,h); + libconfig->setting_remove_elem(commands,h); --disabled_commands_count; --h; continue; } - if( !config_setting_get_int(command) )/* we dont remove it from the three due to inheritance */ + if( !libconfig->setting_get_int(command) )/* we don't remove it from the three due to inheritance */ --disabled_commands_count; } /* all ok, process */ CREATE( zone->disabled_commands, struct map_zone_disabled_command_entry *, disabled_commands_count ); - for(h = 0, v = 0; h < config_setting_length(commands); h++) { - config_setting_t *command = config_setting_get_elem(commands, h); + for(h = 0, v = 0; h < libconfig->setting_length(commands); h++) { + config_setting_t *command = libconfig->setting_get_elem(commands, h); struct map_zone_disabled_command_entry * entry; int group_lv; name = config_setting_name(command); - if( (group_lv = config_setting_get_int(command)) ) { /* only add if enabled */ + if( (group_lv = libconfig->setting_get_int(command)) ) { /* only add if enabled */ CREATE( entry, struct map_zone_disabled_command_entry, 1 ); entry->cmd = atcommand->exists(name)->func; entry->group_lv = group_lv; zone->disabled_commands[v++] = entry; - } + } } zone->disabled_commands_count = disabled_commands_count; } - if( (caps = config_setting_get_member(zone_e, "skill_damage_cap")) != NULL ) { - capped_skills_count = config_setting_length(caps); + if( (caps = libconfig->setting_get_member(zone_e, "skill_damage_cap")) != NULL ) { + capped_skills_count = libconfig->setting_length(caps); /* validate */ - for(h = 0; h < config_setting_length(caps); h++) { - config_setting_t *cap = config_setting_get_elem(caps, h); + for(h = 0; h < libconfig->setting_length(caps); h++) { + config_setting_t *cap = libconfig->setting_get_elem(caps, h); name = config_setting_name(cap); - if( !map_zone_str2skillid(name) ) { + if( !map->zone_str2skillid(name) ) { ShowError("map_zone_db: unknown skill (%s) in skill_damage_cap for zone '%s', skipping skill...\n",name,zone->name); - config_setting_remove_elem(caps,h); + libconfig->setting_remove_elem(caps,h); --capped_skills_count; --h; continue; } - if( !map_zone_bl_type(config_setting_get_string_elem(cap,1),&subtype) )/* we dont remove it from the three due to inheritance */ + if( !map->zone_bl_type(libconfig->setting_get_string_elem(cap,1),&subtype) )/* we don't remove it from the three due to inheritance */ --capped_skills_count; } /* all ok, process */ CREATE( zone->capped_skills, struct map_zone_skill_damage_cap_entry *, capped_skills_count ); - for(h = 0, v = 0; h < config_setting_length(caps); h++) { - config_setting_t *cap = config_setting_get_elem(caps, h); + for(h = 0, v = 0; h < libconfig->setting_length(caps); h++) { + config_setting_t *cap = libconfig->setting_get_elem(caps, h); struct map_zone_skill_damage_cap_entry * entry; enum bl_type type; name = config_setting_name(cap); - if( (type = map_zone_bl_type(config_setting_get_string_elem(cap,1),&subtype)) ) { /* only add if enabled */ + if( (type = map->zone_bl_type(libconfig->setting_get_string_elem(cap,1),&subtype)) ) { /* only add if enabled */ CREATE( entry, struct map_zone_skill_damage_cap_entry, 1 ); - entry->nameid = map_zone_str2skillid(name); - entry->cap = config_setting_get_int_elem(cap,0); + entry->nameid = map->zone_str2skillid(name); + entry->cap = libconfig->setting_get_int_elem(cap,0); entry->type = type; entry->subtype = subtype; zone->capped_skills[v++] = entry; } } zone->capped_skills_count = capped_skills_count; - } + } if( !is_all ) /* global template doesn't go into db -- since it isn't a alloc'd piece of data */ - strdb_put(zone_db, zonename, zone); + strdb_put(map->zone_db, zonename, zone); } @@ -4745,24 +4953,24 @@ void read_map_zone_db(void) { config_setting_t *new_entry = NULL; int inherit_count; - zone_e = config_setting_get_elem(zones, i); - config_setting_lookup_string(zone_e, "name", &zonename); + zone_e = libconfig->setting_get_elem(zones, i); + libconfig->setting_lookup_string(zone_e, "name", &zonename); if( strncmpi(zonename,MAP_ZONE_ALL_NAME,MAP_ZONE_NAME_LENGTH) == 0 ) { continue;/* all zone doesn't inherit anything (if it did, everything would link to each other and boom endless loop) */ } - if( (inherit_tree = config_setting_get_member(zone_e, "inherit")) != NULL ) { + if( (inherit_tree = libconfig->setting_get_member(zone_e, "inherit")) != NULL ) { /* append global zone to this */ - new_entry = config_setting_add(inherit_tree,MAP_ZONE_ALL_NAME,CONFIG_TYPE_STRING); - config_setting_set_string(new_entry,MAP_ZONE_ALL_NAME); + new_entry = libconfig->setting_add(inherit_tree,MAP_ZONE_ALL_NAME,CONFIG_TYPE_STRING); + libconfig->setting_set_string(new_entry,MAP_ZONE_ALL_NAME); } else { /* create inherit member and add global zone to it */ - inherit_tree = config_setting_add(zone_e, "inherit",CONFIG_TYPE_ARRAY); - new_entry = config_setting_add(inherit_tree,MAP_ZONE_ALL_NAME,CONFIG_TYPE_STRING); - config_setting_set_string(new_entry,MAP_ZONE_ALL_NAME); + inherit_tree = libconfig->setting_add(zone_e, "inherit",CONFIG_TYPE_ARRAY); + new_entry = libconfig->setting_add(inherit_tree,MAP_ZONE_ALL_NAME,CONFIG_TYPE_STRING); + libconfig->setting_set_string(new_entry,MAP_ZONE_ALL_NAME); } - inherit_count = config_setting_length(inherit_tree); + inherit_count = libconfig->setting_length(inherit_tree); for(h = 0; h < inherit_count; h++) { struct map_zone_data *izone; /* inherit zone */ int disabled_skills_count_i = 0; /* disabled skill count from inherit zone */ @@ -4772,20 +4980,20 @@ void read_map_zone_db(void) { int capped_skills_count_i = 0; /* skill capped count from inherit zone */ int j; - name = config_setting_get_string_elem(inherit_tree, h); - config_setting_lookup_string(zone_e, "name", &zonename);/* will succeed for we validated it earlier */ + name = libconfig->setting_get_string_elem(inherit_tree, h); + libconfig->setting_lookup_string(zone_e, "name", &zonename);/* will succeed for we validated it earlier */ - if( !(izone = strdb_get(zone_db, name)) ) { + if( !(izone = strdb_get(map->zone_db, name)) ) { ShowError("map_zone_db: Unknown zone '%s' being inherit by zone '%s', skipping...\n",name,zonename); continue; } if( strncmpi(zonename,MAP_ZONE_NORMAL_NAME,MAP_ZONE_NAME_LENGTH) == 0 ) { - zone = &map_zone_all; + zone = &map->zone_all; } else if( strncmpi(zonename,MAP_ZONE_PK_NAME,MAP_ZONE_NAME_LENGTH) == 0 ) { - zone = &map_zone_pk; + zone = &map->zone_pk; } else - zone = strdb_get(zone_db, zonename);/* will succeed for we just put it in here */ + zone = strdb_get(map->zone_db, zonename);/* will succeed for we just put it in here */ disabled_skills_count_i = izone->disabled_skills_count; disabled_items_count_i = izone->disabled_items_count; @@ -4795,14 +5003,14 @@ void read_map_zone_db(void) { /* process everything to override, paying attention to config_setting_get_bool */ if( disabled_skills_count_i ) { - if( (skills = config_setting_get_member(zone_e, "disabled_skills")) == NULL ) - skills = config_setting_add(zone_e, "disabled_skills",CONFIG_TYPE_GROUP); - disabled_skills_count = config_setting_length(skills); + if( (skills = libconfig->setting_get_member(zone_e, "disabled_skills")) == NULL ) + skills = libconfig->setting_add(zone_e, "disabled_skills",CONFIG_TYPE_GROUP); + disabled_skills_count = libconfig->setting_length(skills); for(j = 0; j < disabled_skills_count_i; j++) { int k; for(k = 0; k < disabled_skills_count; k++) { - config_setting_t *skill = config_setting_get_elem(skills, k); - if( map_zone_str2skillid(config_setting_name(skill)) == izone->disabled_skills[j]->nameid ) { + config_setting_t *skillinfo = libconfig->setting_get_elem(skills, k); + if( map->zone_str2skillid(config_setting_name(skillinfo)) == izone->disabled_skills[j]->nameid ) { break; } } @@ -4818,18 +5026,18 @@ void read_map_zone_db(void) { } if( disabled_items_count_i ) { - if( (items = config_setting_get_member(zone_e, "disabled_items")) == NULL ) - items = config_setting_add(zone_e, "disabled_items",CONFIG_TYPE_GROUP); - disabled_items_count = config_setting_length(items); + if( (items = libconfig->setting_get_member(zone_e, "disabled_items")) == NULL ) + items = libconfig->setting_add(zone_e, "disabled_items",CONFIG_TYPE_GROUP); + disabled_items_count = libconfig->setting_length(items); for(j = 0; j < disabled_items_count_i; j++) { int k; for(k = 0; k < disabled_items_count; k++) { - config_setting_t *item = config_setting_get_elem(items, k); + config_setting_t *item = libconfig->setting_get_elem(items, k); name = config_setting_name(item); - if( map_zone_str2itemid(name) == izone->disabled_items[j] ) { - if( config_setting_get_bool(item) ) + if( map->zone_str2itemid(name) == izone->disabled_items[j] ) { + if( libconfig->setting_get_bool(item) ) continue; break; } @@ -4842,13 +5050,13 @@ void read_map_zone_db(void) { } if( mapflags_count_i ) { - if( (mapflags = config_setting_get_member(zone_e, "mapflags")) == NULL ) - mapflags = config_setting_add(zone_e, "mapflags",CONFIG_TYPE_ARRAY); - mapflags_count = config_setting_length(mapflags); + if( (mapflags = libconfig->setting_get_member(zone_e, "mapflags")) == NULL ) + mapflags = libconfig->setting_add(zone_e, "mapflags",CONFIG_TYPE_ARRAY); + mapflags_count = libconfig->setting_length(mapflags); for(j = 0; j < mapflags_count_i; j++) { int k; for(k = 0; k < mapflags_count; k++) { - name = config_setting_get_string_elem(mapflags, k); + name = libconfig->setting_get_string_elem(mapflags, k); if( strcmpi(name,izone->mapflags[j]) == 0 ) { break; @@ -4863,14 +5071,14 @@ void read_map_zone_db(void) { } if( disabled_commands_count_i ) { - if( (commands = config_setting_get_member(zone_e, "disabled_commands")) == NULL ) - commands = config_setting_add(zone_e, "disabled_commands",CONFIG_TYPE_GROUP); + if( (commands = libconfig->setting_get_member(zone_e, "disabled_commands")) == NULL ) + commands = libconfig->setting_add(zone_e, "disabled_commands",CONFIG_TYPE_GROUP); - disabled_commands_count = config_setting_length(commands); + disabled_commands_count = libconfig->setting_length(commands); for(j = 0; j < disabled_commands_count_i; j++) { int k; for(k = 0; k < disabled_commands_count; k++) { - config_setting_t *command = config_setting_get_elem(commands, k); + config_setting_t *command = libconfig->setting_get_elem(commands, k); if( atcommand->exists(config_setting_name(command))->func == izone->disabled_commands[j]->cmd ) { break; } @@ -4887,15 +5095,15 @@ void read_map_zone_db(void) { } if( capped_skills_count_i ) { - if( (caps = config_setting_get_member(zone_e, "skill_damage_cap")) == NULL ) - caps = config_setting_add(zone_e, "skill_damage_cap",CONFIG_TYPE_GROUP); + if( (caps = libconfig->setting_get_member(zone_e, "skill_damage_cap")) == NULL ) + caps = libconfig->setting_add(zone_e, "skill_damage_cap",CONFIG_TYPE_GROUP); - capped_skills_count = config_setting_length(caps); + capped_skills_count = libconfig->setting_length(caps); for(j = 0; j < capped_skills_count_i; j++) { int k; for(k = 0; k < capped_skills_count; k++) { - config_setting_t *cap = config_setting_get_elem(caps, k); - if( map_zone_str2skillid(config_setting_name(cap)) == izone->capped_skills[j]->nameid ) { + config_setting_t *cap = libconfig->setting_get_elem(caps, k); + if( map->zone_str2skillid(config_setting_name(cap)) == izone->capped_skills[j]->nameid ) { break; } } @@ -4916,13 +5124,57 @@ void read_map_zone_db(void) { ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' zones in '"CL_WHITE"%s"CL_RESET"'.\n", zone_count, config_filename); /* not supposed to go in here but in skill_final whatever */ - config_destroy(&map_zone_db); + libconfig->destroy(&map_zone_db); + + /* post-load processing */ + if( (zone = strdb_get(map->zone_db, MAP_ZONE_PVP_NAME)) ) + zone->info.special = 1; + if( (zone = strdb_get(map->zone_db, MAP_ZONE_GVG_NAME)) ) + zone->info.special = 1; + if( (zone = strdb_get(map->zone_db, MAP_ZONE_BG_NAME)) ) + zone->info.special = 1; + } +} + +int map_get_new_bonus_id (void) { + return map->bonus_id++; +} + +void map_add_questinfo(int m, struct questinfo *qi) { + unsigned short i; + + /* duplicate, override */ + for(i = 0; i < map->list[m].qi_count; i++) { + if( map->list[m].qi_data[i].nd == qi->nd ) + break; + } + + if( i == map->list[m].qi_count ) + RECREATE(map->list[m].qi_data, struct questinfo, ++map->list[m].qi_count); + + memcpy(&map->list[m].qi_data[i], qi, sizeof(struct questinfo)); +} + +bool map_remove_questinfo(int m, struct npc_data *nd) { + unsigned short i; + + for(i = 0; i < map->list[m].qi_count; i++) { + struct questinfo *qi = &map->list[m].qi_data[i]; + if( qi->nd == nd ) { + memset(&map->list[m].qi_data[i], 0, sizeof(struct questinfo)); + if( i != --map->list[m].qi_count ) { + memmove(&map->list[m].qi_data[i],&map->list[m].qi_data[i+1],sizeof(struct questinfo)*(map->list[m].qi_count-i)); + } + return true; + } } + + return false; } /** -* @see DBApply -*/ + * @see DBApply + */ int map_db_final(DBKey key, DBData *data, va_list ap) { struct map_data_other_server *mdos = DB->data2ptr(data); @@ -4933,8 +5185,8 @@ int map_db_final(DBKey key, DBData *data, va_list ap) { } /** -* @see DBApply -*/ + * @see DBApply + */ int nick_db_final(DBKey key, DBData *data, va_list args) { struct charid2nick* p = DB->data2ptr(data); @@ -4956,127 +5208,139 @@ int cleanup_sub(struct block_list *bl, va_list ap) { nullpo_ret(bl); switch(bl->type) { - case BL_PC: - iMap->quit((struct map_session_data *) bl); - break; - case BL_NPC: - npc_unload((struct npc_data *)bl,false); - break; - case BL_MOB: - unit_free(bl,CLR_OUTSIGHT); - break; - case BL_PET: - //There is no need for this, the pet is removed together with the player. [Skotlex] - break; - case BL_ITEM: - iMap->clearflooritem(bl); - break; - case BL_SKILL: - skill->delunit((struct skill_unit *) bl); - break; + case BL_PC: + map->quit((struct map_session_data *) bl); + break; + case BL_NPC: + npc->unload((struct npc_data *)bl,false); + break; + case BL_MOB: + unit->free(bl,CLR_OUTSIGHT); + break; + case BL_PET: + //There is no need for this, the pet is removed together with the player. [Skotlex] + break; + case BL_ITEM: + map->clearflooritem(bl); + break; + case BL_SKILL: + skill->delunit((struct skill_unit *) bl); + break; } return 1; } /** -* @see DBApply -*/ -static int cleanup_db_sub(DBKey key, DBData *data, va_list va) -{ - return iMap->cleanup_sub(DB->data2ptr(data), va); + * @see DBApply + */ +int cleanup_db_sub(DBKey key, DBData *data, va_list va) { + return map->cleanup_sub(DB->data2ptr(data), va); } /*========================================== -* map destructor -*------------------------------------------*/ -void do_final(void) -{ + * map destructor + *------------------------------------------*/ +int do_final(void) { int i; struct map_session_data* sd; struct s_mapiterator* iter; ShowStatus("Terminating...\n"); + hChSys.closing = true; HPM->event(HPET_FINAL); + + if (map->cpsd) aFree(map->cpsd); //Ladies and babies first. iter = mapit_getallusers(); for( sd = (TBL_PC*)mapit->first(iter); mapit->exists(iter); sd = (TBL_PC*)mapit->next(iter) ) - iMap->quit(sd); + map->quit(sd); mapit->free(iter); - instance->final(); - /* prepares npcs for a faster shutdown process */ - do_clear_npc(); + npc->do_clear_npc(); // remove all objects on maps - for (i = 0; i < iMap->map_num; i++) { - ShowStatus("Cleaning up maps [%d/%d]: %s..."CL_CLL"\r", i+1, iMap->map_num, map[i].name); - if (map[i].m >= 0) - map_foreachinmap(iMap->cleanup_sub, i, BL_ALL); + for (i = 0; i < map->count; i++) { + ShowStatus("Cleaning up maps [%d/%d]: %s..."CL_CLL"\r", i+1, map->count, map->list[i].name); + if (map->list[i].m >= 0) + map->foreachinmap(map->cleanup_sub, i, BL_ALL); } - ShowStatus("Cleaned up %d maps."CL_CLL"\n", iMap->map_num); + ShowStatus("Cleaned up %d maps."CL_CLL"\n", map->count); - id_db->foreach(id_db,cleanup_db_sub); - chrif_char_reset_offline(); - chrif_flush_fifo(); + map->id_db->foreach(map->id_db,map->cleanup_db_sub); + chrif->char_reset_offline(); + chrif->flush(); atcommand->final(); battle->final(); - do_final_chrif(); + chrif->final(); ircbot->final();/* before clif. */ clif->final(); - do_final_npc(); + npc->final(); + quest->final(); script->final(); - do_final_itemdb(); - do_final_storage(); + itemdb->final(); + instance->final(); + gstorage->final(); guild->final(); - party->do_final_party(); - pc->do_final_pc(); - do_final_pet(); - do_final_mob(); + party->final(); + pc->final(); + pet->final(); + mob->final(); homun->final(); atcommand->final_msg(); skill->final(); - do_final_status(); - do_final_unit(); - do_final_battleground(); - do_final_duel(); - do_final_elemental(); - do_final_maps(); + status->final(); + unit->final(); + bg->final(); + duel->final(); + elemental->final(); + map->list_final(); vending->final(); - map_db->destroy(map_db, map_db_final); + HPM_map_do_final(); + + map->map_db->destroy(map->map_db, map->db_final); - mapindex_final(); - if(enable_grf) + mapindex->final(); + if(map->enable_grf) grfio_final(); - id_db->destroy(id_db, NULL); - pc_db->destroy(pc_db, NULL); - mobid_db->destroy(mobid_db, NULL); - bossid_db->destroy(bossid_db, NULL); - nick_db->destroy(nick_db, nick_db_final); - charid_db->destroy(charid_db, NULL); - iwall_db->destroy(iwall_db, NULL); - regen_db->destroy(regen_db, NULL); - - map_sql_close(); - ers_destroy(map_iterator_ers); - - aFree(map); - - if( !enable_grf ) - aFree(map_cache_buffer); - + db_destroy(map->id_db); + db_destroy(map->pc_db); + db_destroy(map->mobid_db); + db_destroy(map->bossid_db); + map->nick_db->destroy(map->nick_db, map->nick_db_final); + db_destroy(map->charid_db); + db_destroy(map->iwall_db); + db_destroy(map->regen_db); + + map->sql_close(); + ers_destroy(map->iterator_ers); + ers_destroy(map->flooritem_ers); + + aFree(map->list); + + if( map->block_free ) + aFree(map->block_free); + if( map->bl_list ) + aFree(map->bl_list); + + + if( !map->enable_grf ) + aFree(map->cache_buffer); + + HPM->event(HPET_POST_FINAL); + ShowStatus("Finished.\n"); + return map->retval; } -static int map_abort_sub(struct map_session_data* sd, va_list ap) -{ - chrif_save(sd,1); +int map_abort_sub(struct map_session_data* sd, va_list ap) { + chrif->save(sd,1); return 1; } @@ -5094,47 +5358,49 @@ void do_abort(void) return; } run = 1; - if (!chrif_isconnected()) + if (!chrif->isconnected()) { - if (pc_db->size(pc_db)) - ShowFatalError("Server has crashed without a connection to the char-server, %u characters can't be saved!\n", pc_db->size(pc_db)); + if (db_size(map->pc_db)) + ShowFatalError("Server has crashed without a connection to the char-server, %u characters can't be saved!\n", db_size(map->pc_db)); return; } ShowError("Server received crash signal! Attempting to save all online characters!\n"); - iMap->map_foreachpc(map_abort_sub); - chrif_flush_fifo(); + map->foreachpc(map->abort_sub); + chrif->flush(); } /*====================================================== * Map-Server Version Screen [MC Cameri] *------------------------------------------------------*/ -static void map_helpscreen(bool do_exit) +void map_helpscreen(bool do_exit) { ShowInfo("Usage: %s [options]\n", SERVER_NAME); ShowInfo("\n"); ShowInfo("Options:\n"); - ShowInfo(" -?, -h [--help]\t\tDisplays this help screen.\n"); - ShowInfo(" -v [--version]\t\tDisplays the server's version.\n"); - ShowInfo(" --run-once\t\t\tCloses server after loading (testing).\n"); - ShowInfo(" --map-config <file>\t\tAlternative map-server configuration.\n"); - ShowInfo(" --battle-config <file>\tAlternative battle configuration.\n"); - ShowInfo(" --atcommand-config <file>\tAlternative atcommand configuration.\n"); - ShowInfo(" --script-config <file>\tAlternative script configuration.\n"); - ShowInfo(" --msg-config <file>\t\tAlternative message configuration.\n"); - ShowInfo(" --grf-path <file>\t\tAlternative GRF path configuration.\n"); - ShowInfo(" --inter-config <file>\t\tAlternative inter-server configuration.\n"); - ShowInfo(" --log-config <file>\t\tAlternative logging configuration.\n"); + ShowInfo(" -?, -h [--help] Displays this help screen.\n"); + ShowInfo(" -v [--version] Displays the server's version.\n"); + ShowInfo(" --run-once Closes server after loading (testing).\n"); + ShowInfo(" --map-config <file> Alternative map-server configuration.\n"); + ShowInfo(" --battle-config <file> Alternative battle configuration.\n"); + ShowInfo(" --atcommand-config <file> Alternative atcommand configuration.\n"); + ShowInfo(" --script-config <file> Alternative script configuration.\n"); + ShowInfo(" --msg-config <file> Alternative message configuration.\n"); + ShowInfo(" --grf-path <file> Alternative GRF path configuration.\n"); + ShowInfo(" --inter-config <file> Alternative inter-server configuration.\n"); + ShowInfo(" --log-config <file> Alternative logging configuration.\n"); + ShowInfo(" --script-check Doesn't run the server, only tests the\n"); + ShowInfo(" scripts passed through --load-script.\n"); + ShowInfo(" --load-script <file> Loads an additional script (can be repeated).\n"); + ShowInfo(" --load-plugin <name> Loads an additional plugin (can be repeated).\n"); + HPM->arg_help();/* display help for commands implemented thru HPM */ if( do_exit ) exit(EXIT_SUCCESS); } /*====================================================== -* Map-Server Version Screen [MC Cameri] -*------------------------------------------------------*/ -static void map_versionscreen(bool do_exit) { - const char *svn = get_svn_revision(); - const char *git = get_git_hash(); - ShowInfo(CL_WHITE"Hercules version: %s" CL_RESET"\n", git[0] != HERC_UNKNOWN_VER ? git : svn[0] != HERC_UNKNOWN_VER ? svn : "Unknown"); + * Map-Server Version Screen [MC Cameri] + *------------------------------------------------------*/ +void map_versionscreen(bool do_exit) { ShowInfo(CL_GREEN"Website/Forum:"CL_RESET"\thttp://hercules.ws/\n"); ShowInfo(CL_GREEN"IRC Channel:"CL_RESET"\tirc://irc.rizon.net/#Hercules\n"); ShowInfo("Open "CL_WHITE"readme.txt"CL_RESET" for more information.\n"); @@ -5162,20 +5428,21 @@ void do_shutdown(void) mapit->free(iter); flush_fifos(); } - chrif_check_shutdown(); + chrif->check_shutdown(); } } -static bool map_arg_next_value(const char* option, int i, int argc) +bool map_arg_next_value(const char* option, int i, int argc, bool must) { if( i >= argc-1 ) { - ShowWarning("Missing value for option '%s'.\n", option); + if( must ) + ShowWarning("Missing value for option '%s'.\n", option); return false; } return true; } -struct map_session_data cpsd; + CPCMD(gm_position) { int x = 0, y = 0, m = 0; char map_name[25]; @@ -5185,20 +5452,20 @@ CPCMD(gm_position) { return; } - if ( (m = iMap->mapname2mapid(map_name) <= 0 ) ) { + if ( (m = map->mapname2mapid(map_name) <= 0 ) ) { ShowError("gm:info '"CL_WHITE"%s"CL_RESET"' is not a known map\n",map_name); return; } - if( x < 0 || x >= map[m].xs || y < 0 || y >= map[m].ys ) { + if( x < 0 || x >= map->list[m].xs || y < 0 || y >= map->list[m].ys ) { ShowError("gm:info '"CL_WHITE"%d %d"CL_RESET"' is out of '"CL_WHITE"%s"CL_RESET"' map bounds!\n",x,y,map_name); return; } ShowInfo("HCP: updated console's game position to '"CL_WHITE"%d %d %s"CL_RESET"'\n",x,y,map_name); - cpsd.bl.x = x; - cpsd.bl.y = y; - cpsd.bl.m = m; + map->cpsd->bl.x = x; + map->cpsd->bl.y = y; + map->cpsd->bl.m = m; } CPCMD(gm_use) { @@ -5206,25 +5473,29 @@ CPCMD(gm_use) { ShowError("gm:use invalid syntax. use '"CL_WHITE"gm:use @command <optional params>"CL_RESET"'\n"); return; } - cpsd.fd = -2; - if( !atcommand->parse(cpsd.fd, &cpsd, line, 0) ) + + map->cpsd_active = true; + + if( !atcommand->exec(map->cpsd->fd, map->cpsd, line, false) ) ShowInfo("HCP: '"CL_WHITE"%s"CL_RESET"' failed\n",line); else ShowInfo("HCP: '"CL_WHITE"%s"CL_RESET"' was used\n",line); - cpsd.fd = 0; - + + map->cpsd_active = false; } /* Hercules Console Parser */ void map_cp_defaults(void) { +#ifdef CONSOLE_INPUT /* default HCP data */ - memset(&cpsd, 0, sizeof(struct map_session_data)); - strcpy(cpsd.status.name, "Hercules Console"); - cpsd.bl.x = 150; - cpsd.bl.y = 150; - cpsd.bl.m = iMap->mapname2mapid("prontera"); - - console->addCommand("gm:info",CPCMD_A(gm_position)); - console->addCommand("gm:use",CPCMD_A(gm_use)); + map->cpsd = pc->get_dummy_sd(); + strcpy(map->cpsd->status.name, "Hercules Console"); + map->cpsd->bl.x = MAP_DEFAULT_X; + map->cpsd->bl.y = MAP_DEFAULT_Y; + map->cpsd->bl.m = map->mapname2mapid(MAP_DEFAULT); + + console->input->addCommand("gm:info",CPCMD_A(gm_position)); + console->input->addCommand("gm:use",CPCMD_A(gm_use)); +#endif } /* Hercules Plugin Mananger */ void map_hp_symbols(void) { @@ -5234,38 +5505,64 @@ void map_hp_symbols(void) { HPM->share(bg,"battlegrounds"); HPM->share(buyingstore,"buyingstore"); HPM->share(clif,"clif"); + HPM->share(chrif,"chrif"); HPM->share(guild,"guild"); + HPM->share(gstorage,"gstorage"); HPM->share(homun,"homun"); + HPM->share(map,"map"); HPM->share(ircbot,"ircbot"); HPM->share(itemdb,"itemdb"); HPM->share(logs,"logs"); HPM->share(mail,"mail"); + HPM->share(instance,"instance"); HPM->share(script,"script"); HPM->share(searchstore,"searchstore"); HPM->share(skill,"skill"); HPM->share(vending,"vending"); HPM->share(pc,"pc"); + HPM->share(pcg,"pc_groups"); HPM->share(party,"party"); + HPM->share(storage,"storage"); HPM->share(trade,"trade"); - HPM->share(iMap,"iMap"); - /* partial */ + HPM->share(status,"status"); + HPM->share(chat, "chat"); + HPM->share(duel,"duel"); + HPM->share(elemental,"elemental"); + HPM->share(intif,"intif"); + HPM->share(mercenary,"mercenary"); + HPM->share(mob,"mob"); + HPM->share(unit,"unit"); + HPM->share(npc,"npc"); + HPM->share(mapreg,"mapreg"); + HPM->share(pet,"pet"); + HPM->share(path,"path"); + HPM->share(quest,"quest"); +#ifdef PCRE_SUPPORT + HPM->share(npc_chat,"npc_chat"); + HPM->share(libpcre,"libpcre"); +#endif HPM->share(mapit,"mapit"); + HPM->share(mapindex,"mapindex"); /* sql link */ - HPM->share(mmysql_handle,"sql_handle"); + HPM->share(map->mysql_handle,"sql_handle"); /* specific */ HPM->share(atcommand->create,"addCommand"); HPM->share(script->addScript,"addScript"); - /* vars */ - HPM->share(map,"map"); + HPM->share(HPM_map_add_group_permission,"addGroupPermission"); } -void load_defaults(void) { +void map_load_defaults(void) { + mapindex_defaults(); + map_defaults(); + /* */ atcommand_defaults(); battle_defaults(); battleground_defaults(); buyingstore_defaults(); clif_defaults(); + chrif_defaults(); guild_defaults(); + gstorage_defaults(); homunculus_defaults(); instance_defaults(); ircbot_defaults(); @@ -5278,221 +5575,288 @@ void load_defaults(void) { skill_defaults(); vending_defaults(); pc_defaults(); + pc_groups_defaults(); party_defaults(); + storage_defaults(); trade_defaults(); + status_defaults(); + chat_defaults(); + duel_defaults(); + elemental_defaults(); + intif_defaults(); + mercenary_defaults(); + mob_defaults(); + unit_defaults(); + mapreg_defaults(); + pet_defaults(); + path_defaults(); + quest_defaults(); +#ifdef PCRE_SUPPORT + npc_chat_defaults(); +#endif } int do_init(int argc, char *argv[]) { - int i; + bool minimal = false; + bool scriptcheck = false; + int i, load_extras_count = 0; + char **load_extras = NULL; #ifdef GCOLLECT GC_enable_incremental(); #endif + + map_load_defaults(); - map_defaults(); - - iMap->map_num = 0; - - sprintf(iMap->db_path ,"db"); - sprintf(iMap->help_txt ,"conf/help.txt"); - sprintf(iMap->help2_txt ,"conf/help2.txt"); - sprintf(iMap->charhelp_txt ,"conf/charhelp.txt"); - - sprintf(iMap->wisp_server_name ,"Server"); // can be modified in char-server configuration file - - iMap->autosave_interval = DEFAULT_AUTOSAVE_INTERVAL; - iMap->minsave_interval = 100; - iMap->save_settings = 0xFFFF; - iMap->agit_flag = 0; - iMap->agit2_flag = 0; - iMap->night_flag = 0; // 0=day, 1=night [Yor] - iMap->enable_spy = 0; //To enable/disable @spy commands, which consume too much cpu time when sending packets. [Skotlex] - - iMap->db_use_sqldbs = 0; - - sprintf(iMap->item_db_db, "item_db"); - sprintf(iMap->item_db2_db, "item_db2"); - sprintf(iMap->item_db_re_db, "item_db_re"); - sprintf(iMap->mob_db_db, "mob_db"); - sprintf(iMap->mob_db2_db, "mob_db2"); - sprintf(iMap->mob_skill_db_db, "mob_skill_db"); - sprintf(iMap->mob_skill_db2_db, "mob_skill_db2"); - sprintf(iMap->interreg_db, "interreg"); - - iMap->INTER_CONF_NAME="conf/inter-server.conf"; - iMap->LOG_CONF_NAME="conf/logs.conf"; - iMap->MAP_CONF_NAME = "conf/map-server.conf"; - iMap->BATTLE_CONF_FILENAME = "conf/battle.conf"; - iMap->ATCOMMAND_CONF_FILENAME = "conf/atcommand.conf"; - iMap->SCRIPT_CONF_NAME = "conf/script.conf"; - iMap->MSG_CONF_NAME = "conf/messages.conf"; - iMap->GRF_PATH_FILENAME = "conf/grf-files.txt"; - rnd_init(); - + HPM_map_do_init(); + HPM->DataCheck = HPM_map_DataCheck; + HPM->load_sub = HPM_map_plugin_load_sub; + HPM->symbol_defaults_sub = map_hp_symbols; + HPM->grabHPDataSub = HPM_map_grabHPData; + for( i = 1; i < argc; i++ ) { + const char* arg = argv[i]; + if( strcmp(arg, "--load-plugin") == 0 ) { + if( map->arg_next_value(arg, i, argc, true) ) { + RECREATE(load_extras, char *, ++load_extras_count); + load_extras[load_extras_count-1] = argv[++i]; + } + } + } + HPM->config_read((const char * const *)load_extras, load_extras_count); + if (load_extras) { + aFree(load_extras); + load_extras = NULL; + load_extras_count = 0; + } + + HPM->event(HPET_PRE_INIT); + for( i = 1; i < argc ; i++ ) { const char* arg = argv[i]; if( arg[0] != '-' && ( arg[0] != '/' || arg[1] == '-' ) ) {// -, -- and / ShowError("Unknown option '%s'.\n", argv[i]); exit(EXIT_FAILURE); + } else if ( HPM->parse_arg(arg,&i,argv,map->arg_next_value(arg, i, argc, false)) ) { + continue; /* HPM Triggered */ } else if( (++arg)[0] == '-' ) {// long option arg++; if( strcmp(arg, "help") == 0 ) { - map_helpscreen(true); + map->helpscreen(true); } else if( strcmp(arg, "version") == 0 ) { - map_versionscreen(true); + map->versionscreen(true); } else if( strcmp(arg, "map-config") == 0 ) { - if( map_arg_next_value(arg, i, argc) ) - iMap->MAP_CONF_NAME = argv[++i]; + if( map->arg_next_value(arg, i, argc, true) ) + map->MAP_CONF_NAME = argv[++i]; } else if( strcmp(arg, "battle-config") == 0 ) { - if( map_arg_next_value(arg, i, argc) ) - iMap->BATTLE_CONF_FILENAME = argv[++i]; + if( map->arg_next_value(arg, i, argc, true) ) + map->BATTLE_CONF_FILENAME = argv[++i]; } else if( strcmp(arg, "atcommand-config") == 0 ) { - if( map_arg_next_value(arg, i, argc) ) - iMap->ATCOMMAND_CONF_FILENAME = argv[++i]; + if( map->arg_next_value(arg, i, argc, true) ) + map->ATCOMMAND_CONF_FILENAME = argv[++i]; } else if( strcmp(arg, "script-config") == 0 ) { - if( map_arg_next_value(arg, i, argc) ) - iMap->SCRIPT_CONF_NAME = argv[++i]; + if( map->arg_next_value(arg, i, argc, true) ) + map->SCRIPT_CONF_NAME = argv[++i]; } else if( strcmp(arg, "msg-config") == 0 ) { - if( map_arg_next_value(arg, i, argc) ) - iMap->MSG_CONF_NAME = argv[++i]; + if( map->arg_next_value(arg, i, argc, true) ) + map->MSG_CONF_NAME = argv[++i]; } else if( strcmp(arg, "grf-path-file") == 0 ) { - if( map_arg_next_value(arg, i, argc) ) - iMap->GRF_PATH_FILENAME = argv[++i]; + if( map->arg_next_value(arg, i, argc, true) ) + map->GRF_PATH_FILENAME = argv[++i]; } else if( strcmp(arg, "inter-config") == 0 ) { - if( map_arg_next_value(arg, i, argc) ) - iMap->INTER_CONF_NAME = argv[++i]; + if( map->arg_next_value(arg, i, argc, true) ) + map->INTER_CONF_NAME = argv[++i]; } else if( strcmp(arg, "log-config") == 0 ) { - if( map_arg_next_value(arg, i, argc) ) - iMap->LOG_CONF_NAME = argv[++i]; + if( map->arg_next_value(arg, i, argc, true) ) + map->LOG_CONF_NAME = argv[++i]; } else if( strcmp(arg, "run-once") == 0 ) { // close the map-server as soon as its done.. for testing [Celest] runflag = CORE_ST_STOP; + } else if( strcmp(arg, "script-check") == 0 ) { + map->minimal = true; + runflag = CORE_ST_STOP; + scriptcheck = true; + } else if( strcmp(arg, "load-plugin") == 0 ) { + if( map->arg_next_value(arg, i, argc, true) ) + i++; + } else if( strcmp(arg, "load-script") == 0 ) { + if( map->arg_next_value(arg, i, argc, true) ) { + RECREATE(load_extras, char *, ++load_extras_count); + load_extras[load_extras_count-1] = argv[++i]; + } } else { ShowError("Unknown option '%s'.\n", argv[i]); exit(EXIT_FAILURE); } - } else switch( arg[0] ) {// short option - case '?': - case 'h': - map_helpscreen(true); - break; - case 'v': - map_versionscreen(true); - break; - default: - ShowError("Unknown option '%s'.\n", argv[i]); - exit(EXIT_FAILURE); + } else { + switch( arg[0] ) {// short option + case '?': + case 'h': + map->helpscreen(true); + break; + case 'v': + map->versionscreen(true); + break; + default: + ShowError("Unknown option '%s'.\n", argv[i]); + exit(EXIT_FAILURE); + } } } - memset(&index2mapid, -1, sizeof(index2mapid)); + minimal = map->minimal;/* temp (perhaps make minimal a mask with options of what to load? e.g. plugin 1 does minimal |= mob_db; */ + if (!minimal) { + map->config_read(map->MAP_CONF_NAME); + CREATE(map->list,struct map_data,map->count); + map->count = 0; + map->config_read_sub(map->MAP_CONF_NAME); - load_defaults(); - map_config_read(iMap->MAP_CONF_NAME); - CREATE(map,struct map_data,iMap->map_num); - iMap->map_num = 0; - map_config_read_sub(iMap->MAP_CONF_NAME); - // loads npcs - iMap->reloadnpc(false); + // loads npcs + map->reloadnpc(false, (const char * const *)load_extras, load_extras_count); - chrif_checkdefaultlogin(); + chrif->checkdefaultlogin(); - if (!map_ip_set || !char_ip_set) { - char ip_str[16]; - ip2str(addr_[0], ip_str); + if (!map->ip_set || !map->char_ip_set) { + char ip_str[16]; + ip2str(sockt->addr_[0], ip_str); - ShowWarning("Not all IP addresses in /conf/map-server.conf configured, autodetecting...\n"); + ShowWarning("Not all IP addresses in /conf/map-server.conf configured, auto-detecting...\n"); - if (naddr_ == 0) - ShowError("Unable to determine your IP address...\n"); - else if (naddr_ > 1) - ShowNotice("Multiple interfaces detected...\n"); + if (sockt->naddr_ == 0) + ShowError("Unable to determine your IP address...\n"); + else if (sockt->naddr_ > 1) + ShowNotice("Multiple interfaces detected...\n"); - ShowInfo("Defaulting to %s as our IP address\n", ip_str); + ShowInfo("Defaulting to %s as our IP address\n", ip_str); - if (!map_ip_set) - clif->setip(ip_str); - if (!char_ip_set) - chrif_setip(ip_str); - } + if (!map->ip_set) + clif->setip(ip_str); + if (!map->char_ip_set) + chrif->setip(ip_str); + } - battle->config_read(iMap->BATTLE_CONF_FILENAME); - atcommand->msg_read(iMap->MSG_CONF_NAME); - script_config_read(iMap->SCRIPT_CONF_NAME); - inter_config_read(iMap->INTER_CONF_NAME); - logs->config_read(iMap->LOG_CONF_NAME); + battle->config_read(map->BATTLE_CONF_FILENAME); + atcommand->msg_read(map->MSG_CONF_NAME, false); + map->inter_config_read(map->INTER_CONF_NAME); + logs->config_read(map->LOG_CONF_NAME); + } + script->config_read(map->SCRIPT_CONF_NAME); - id_db = idb_alloc(DB_OPT_BASE); - pc_db = idb_alloc(DB_OPT_BASE); //Added for reliable iMap->id2sd() use. [Skotlex] - mobid_db = idb_alloc(DB_OPT_BASE); //Added to lower the load of the lazy mob ai. [Skotlex] - bossid_db = idb_alloc(DB_OPT_BASE); // Used for Convex Mirror quick MVP search - map_db = uidb_alloc(DB_OPT_BASE); - nick_db = idb_alloc(DB_OPT_BASE); - charid_db = idb_alloc(DB_OPT_BASE); - regen_db = idb_alloc(DB_OPT_BASE); // efficient status_natural_heal processing + map->id_db = idb_alloc(DB_OPT_BASE); + map->pc_db = idb_alloc(DB_OPT_BASE); //Added for reliable map->id2sd() use. [Skotlex] + map->mobid_db = idb_alloc(DB_OPT_BASE); //Added to lower the load of the lazy mob AI. [Skotlex] + map->bossid_db = idb_alloc(DB_OPT_BASE); // Used for Convex Mirror quick MVP search + map->map_db = uidb_alloc(DB_OPT_BASE); + map->nick_db = idb_alloc(DB_OPT_BASE); + map->charid_db = idb_alloc(DB_OPT_BASE); + map->regen_db = idb_alloc(DB_OPT_BASE); // efficient status_natural_heal processing + map->iwall_db = strdb_alloc(DB_OPT_RELEASE_DATA,2*NAME_LENGTH+2+1); // [Zephyrus] Invisible Walls + map->zone_db = strdb_alloc(DB_OPT_DUP_KEY|DB_OPT_RELEASE_DATA, MAP_ZONE_NAME_LENGTH); - iwall_db = strdb_alloc(DB_OPT_RELEASE_DATA,2*NAME_LENGTH+2+1); // [Zephyrus] Invisible Walls - zone_db = strdb_alloc(DB_OPT_DUP_KEY|DB_OPT_RELEASE_DATA, MAP_ZONE_NAME_LENGTH); + map->iterator_ers = ers_new(sizeof(struct s_mapiterator),"map.c::map_iterator_ers",ERS_OPT_CLEAN|ERS_OPT_FLEX_CHUNK); + ers_chunk_size(map->iterator_ers, 25); - map_iterator_ers = ers_new(sizeof(struct s_mapiterator),"map.c::map_iterator_ers",ERS_OPT_NONE); + map->flooritem_ers = ers_new(sizeof(struct flooritem_data),"map.c::map_flooritem_ers",ERS_OPT_CLEAN|ERS_OPT_FLEX_CHUNK); + ers_chunk_size(map->flooritem_ers, 100); - map_sql_init(); - if (logs->config.sql_logs) - log_sql_init(); + if (!minimal) { + map->sql_init(); + if (logs->config.sql_logs) + logs->sql_init(); + } - mapindex_init(); - if(enable_grf) - grfio_init(iMap->GRF_PATH_FILENAME); + i = mapindex->init(); - map_readallmaps(); + if (minimal) { + // Pretend all maps from the mapindex are on this mapserver + CREATE(map->list,struct map_data,i); - iTimer->add_timer_func_list(map_freeblock_timer, "map_freeblock_timer"); - iTimer->add_timer_func_list(map_clearflooritem_timer, "map_clearflooritem_timer"); - iTimer->add_timer_func_list(map_removemobs_timer, "map_removemobs_timer"); - iTimer->add_timer_interval(iTimer->gettick()+1000, map_freeblock_timer, 0, 0, 60*1000); + for( i = 0; i < MAX_MAPINDEX; i++ ) { + if (mapindex_exists(i)) { + map->addmap(mapindex_id2name(i)); + } + } + } - HPM->symbol_defaults_sub = map_hp_symbols; - HPM->config_read(); - HPM->event(HPET_INIT); - - atcommand->init(); - battle->init(); - instance->init(); - do_init_chrif(); - clif->init(); - ircbot->init(); - script->init(); - do_init_itemdb(); - skill->init(); - read_map_zone_db();/* read after item and skill initalization */ - do_init_mob(); - pc->do_init_pc(); - do_init_status(); - party->do_init_party(); - guild->init(); - do_init_storage(); - do_init_pet(); - homun->init(); - do_init_mercenary(); - do_init_elemental(); - do_init_quest(); - do_init_npc(); - do_init_unit(); - do_init_battleground(); - do_init_duel(); - vending->init(); - - npc_event_do_oninit(); // Init npcs (OnInit) + if(map->enable_grf) + grfio_init(map->GRF_PATH_FILENAME); + + map->readallmaps(); + + + if (!minimal) { + timer->add_func_list(map->freeblock_timer, "map_freeblock_timer"); + timer->add_func_list(map->clearflooritem_timer, "map_clearflooritem_timer"); + timer->add_func_list(map->removemobs_timer, "map_removemobs_timer"); + timer->add_interval(timer->gettick()+1000, map->freeblock_timer, 0, 0, 60*1000); + + HPM->event(HPET_INIT); + } + + atcommand->init(minimal); + battle->init(minimal); + instance->init(minimal); + chrif->init(minimal); + clif->init(minimal); + ircbot->init(minimal); + script->init(minimal); + itemdb->init(minimal); + skill->init(minimal); + if (!minimal) + map->read_zone_db();/* read after item and skill initialization */ + mob->init(minimal); + pc->init(minimal); + status->init(minimal); + party->init(minimal); + guild->init(minimal); + gstorage->init(minimal); + pet->init(minimal); + homun->init(minimal); + mercenary->init(minimal); + elemental->init(minimal); + quest->init(minimal); + npc->init(minimal); + unit->init(minimal); + bg->init(minimal); + duel->init(minimal); + vending->init(minimal); + + if (scriptcheck) { + bool failed = load_extras_count > 0 ? false : true; + for (i = 0; i < load_extras_count; i++) { + if (npc->parsesrcfile(load_extras[i], false) != EXIT_SUCCESS) + failed = true; + } + if (failed) + exit(EXIT_FAILURE); + exit(EXIT_SUCCESS); + } + if (load_extras) { + aFree(load_extras); + load_extras = NULL; + //load_extras_count = 0; // Dead store. Uncomment if needed again. + } + if( minimal ) { + HPM->event(HPET_READY); + exit(EXIT_SUCCESS); + } + + npc->event_do_oninit( false ); // Init npcs (OnInit) + npc->market_fromsql(); /* after OnInit */ + if (battle_config.pk_mode) ShowNotice("Server is running on '"CL_WHITE"PK Mode"CL_RESET"'.\n"); - Sql_HerculesUpdateCheck(mmysql_handle); - - ShowStatus("Server is '"CL_GREEN"ready"CL_RESET"' and listening on port '"CL_WHITE"%d"CL_RESET"'.\n\n", map_port); + Sql_HerculesUpdateCheck(map->mysql_handle); + +#ifdef CONSOLE_INPUT + console->input->setSQL(map->mysql_handle); +#endif + + ShowStatus("Server is '"CL_GREEN"ready"CL_RESET"' and listening on port '"CL_WHITE"%d"CL_RESET"'.\n\n", map->port); if( runflag != CORE_ST_STOP ) { - shutdown_callback = iMap->do_shutdown; + shutdown_callback = map->do_shutdown; runflag = MAPSERVER_ST_RUNNING; } @@ -5504,121 +5868,284 @@ int do_init(int argc, char *argv[]) } /*===================================== -* Default Functions : map.h +* Default Functions : map.h * Generated by HerculesInterfaceMaker * created by Susu *-------------------------------------*/ void map_defaults(void) { - iMap = &iMap_s; + map = &map_s; + /* */ + map->minimal = false; + map->count = 0; + map->retval = EXIT_SUCCESS; + + sprintf(map->db_path ,"db"); + sprintf(map->help_txt ,"conf/help.txt"); + sprintf(map->help2_txt ,"conf/help2.txt"); + sprintf(map->charhelp_txt ,"conf/charhelp.txt"); + + sprintf(map->wisp_server_name ,"Server"); // can be modified in char-server configuration file + + map->autosave_interval = DEFAULT_AUTOSAVE_INTERVAL; + map->minsave_interval = 100; + map->save_settings = 0xFFFF; + map->agit_flag = 0; + map->agit2_flag = 0; + map->night_flag = 0; // 0=day, 1=night [Yor] + map->enable_spy = 0; //To enable/disable @spy commands, which consume too much cpu time when sending packets. [Skotlex] + + map->db_use_sql_item_db = 0; + map->db_use_sql_mob_db = 0; + map->db_use_sql_mob_skill_db = 0; + + sprintf(map->item_db_db, "item_db"); + sprintf(map->item_db2_db, "item_db2"); + sprintf(map->item_db_re_db, "item_db_re"); + sprintf(map->mob_db_db, "mob_db"); + sprintf(map->mob_db2_db, "mob_db2"); + sprintf(map->mob_skill_db_db, "mob_skill_db"); + sprintf(map->mob_skill_db2_db, "mob_skill_db2"); + sprintf(map->interreg_db, "interreg"); + + map->INTER_CONF_NAME="conf/inter-server.conf"; + map->LOG_CONF_NAME="conf/logs.conf"; + map->MAP_CONF_NAME = "conf/map-server.conf"; + map->BATTLE_CONF_FILENAME = "conf/battle.conf"; + map->ATCOMMAND_CONF_FILENAME = "conf/atcommand.conf"; + map->SCRIPT_CONF_NAME = "conf/script.conf"; + map->MSG_CONF_NAME = "conf/messages.conf"; + map->GRF_PATH_FILENAME = "conf/grf-files.txt"; + + map->default_codepage[0] = '\0'; + map->server_port = 3306; + sprintf(map->server_ip,"127.0.0.1"); + sprintf(map->server_id,"ragnarok"); + sprintf(map->server_pw,"ragnarok"); + sprintf(map->server_db,"ragnarok"); + map->mysql_handle = NULL; + + map->cpsd_active = false; + + map->port = 0; + map->users = 0; + map->ip_set = 0; + map->char_ip_set = 0; + map->enable_grf = 0; + + memset(&map->index2mapid, -1, sizeof(map->index2mapid)); + + map->id_db = NULL; + map->pc_db = NULL; + map->mobid_db = NULL; + map->bossid_db = NULL; + map->map_db = NULL; + map->nick_db = NULL; + map->charid_db = NULL; + map->regen_db = NULL; + map->zone_db = NULL; + map->iwall_db = NULL; + + map->block_free = NULL; + map->block_free_count = 0; + map->block_free_lock = 0; + map->block_free_list_size = 0; + map->bl_list = NULL; + map->bl_list_count = 0; + map->bl_list_size = 0; + + //all in a big chunk, respects order + memset(&map->bl_head,0,sizeof(map->bl_head) + + sizeof(map->zone_all) + + sizeof(map->zone_pk) + ); + + map->cpsd = NULL; + map->list = NULL; + + map->iterator_ers = NULL; + map->cache_buffer = NULL; + + map->flooritem_ers = NULL; + /* */ + map->bonus_id = SP_LAST_KNOWN; /* funcs */ - iMap->zone_init = map_zone_init; - iMap->zone_remove = map_zone_remove; - iMap->zone_apply = map_zone_apply; - iMap->zone_change = map_zone_change; - iMap->zone_change2 = map_zone_change2; + map->zone_init = map_zone_init; + map->zone_remove = map_zone_remove; + map->zone_apply = map_zone_apply; + map->zone_change = map_zone_change; + map->zone_change2 = map_zone_change2; - iMap->getcell = map_getcell; - iMap->setgatcell = map_setgatcell; + map->getcell = map_getcell; + map->setgatcell = map_setgatcell; - iMap->cellfromcache = map_cellfromcache; + map->cellfromcache = map_cellfromcache; // users - iMap->setusers = map_setusers; - iMap->getusers = map_getusers; - iMap->usercount = map_usercount; + map->setusers = map_setusers; + map->getusers = map_getusers; + map->usercount = map_usercount; // blocklist lock - iMap->freeblock = map_freeblock; - iMap->freeblock_lock = map_freeblock_lock; - iMap->freeblock_unlock = map_freeblock_unlock; + map->freeblock = map_freeblock; + map->freeblock_lock = map_freeblock_lock; + map->freeblock_unlock = map_freeblock_unlock; // blocklist manipulation - iMap->addblock = map_addblock; - iMap->delblock = map_delblock; - iMap->moveblock = map_moveblock; + map->addblock = map_addblock; + map->delblock = map_delblock; + map->moveblock = map_moveblock; //blocklist nb in one cell - iMap->count_oncell = map_count_oncell; - iMap->find_skill_unit_oncell = map_find_skill_unit_oncell; + map->count_oncell = map_count_oncell; + map->find_skill_unit_oncell = map_find_skill_unit_oncell; // search and creation - iMap->get_new_object_id = map_get_new_object_id; - iMap->search_freecell = map_search_freecell; + map->get_new_object_id = map_get_new_object_id; + map->search_freecell = map_search_freecell; // - iMap->quit = map_quit; + map->quit = map_quit; // npc - iMap->addnpc = map_addnpc; + map->addnpc = map_addnpc; // map item - iMap->clearflooritem_timer = map_clearflooritem_timer; - iMap->removemobs_timer = map_removemobs_timer; - iMap->clearflooritem = map_clearflooritem; - iMap->addflooritem = map_addflooritem; + map->clearflooritem_timer = map_clearflooritem_timer; + map->removemobs_timer = map_removemobs_timer; + map->clearflooritem = map_clearflooritem; + map->addflooritem = map_addflooritem; // player to map session - iMap->addnickdb = map_addnickdb; - iMap->delnickdb = map_delnickdb; - iMap->reqnickdb = map_reqnickdb; - iMap->charid2nick = map_charid2nick; - iMap->charid2sd = map_charid2sd; - - iMap->id2sd = map_id2sd; - iMap->id2md = map_id2md; - iMap->id2nd = map_id2nd; - iMap->id2hd = map_id2hd; - iMap->id2mc = map_id2mc; - iMap->id2cd = map_id2cd; - iMap->id2bl = map_id2bl; - iMap->blid_exists = map_blid_exists; - iMap->mapindex2mapid = map_mapindex2mapid; - iMap->mapname2mapid = map_mapname2mapid; - iMap->mapname2ipport = map_mapname2ipport; - iMap->setipport = map_setipport; - iMap->eraseipport = map_eraseipport; - iMap->eraseallipport = map_eraseallipport; - iMap->addiddb = map_addiddb; - iMap->deliddb = map_deliddb; + map->addnickdb = map_addnickdb; + map->delnickdb = map_delnickdb; + map->reqnickdb = map_reqnickdb; + map->charid2nick = map_charid2nick; + map->charid2sd = map_charid2sd; + + map->vforeachpc = map_vforeachpc; + map->foreachpc = map_foreachpc; + map->vforeachmob = map_vforeachmob; + map->foreachmob = map_foreachmob; + map->vforeachnpc = map_vforeachnpc; + map->foreachnpc = map_foreachnpc; + map->vforeachregen = map_vforeachregen; + map->foreachregen = map_foreachregen; + map->vforeachiddb = map_vforeachiddb; + map->foreachiddb = map_foreachiddb; + + map->vforeachinrange = map_vforeachinrange; + map->foreachinrange = map_foreachinrange; + map->vforeachinshootrange = map_vforeachinshootrange; + map->foreachinshootrange = map_foreachinshootrange; + map->vforeachinarea = map_vforeachinarea; + map->foreachinarea = map_foreachinarea; + map->vforcountinrange = map_vforcountinrange; + map->forcountinrange = map_forcountinrange; + map->vforcountinarea = map_vforcountinarea; + map->forcountinarea = map_forcountinarea; + map->vforeachinmovearea = map_vforeachinmovearea; + map->foreachinmovearea = map_foreachinmovearea; + map->vforeachincell = map_vforeachincell; + map->foreachincell = map_foreachincell; + map->vforeachinpath = map_vforeachinpath; + map->foreachinpath = map_foreachinpath; + map->vforeachinmap = map_vforeachinmap; + map->foreachinmap = map_foreachinmap; + map->vforeachininstance = map_vforeachininstance; + map->foreachininstance = map_foreachininstance; + + map->id2sd = map_id2sd; + map->id2md = map_id2md; + map->id2nd = map_id2nd; + map->id2hd = map_id2hd; + map->id2mc = map_id2mc; + map->id2cd = map_id2cd; + map->id2bl = map_id2bl; + map->blid_exists = map_blid_exists; + map->mapindex2mapid = map_mapindex2mapid; + map->mapname2mapid = map_mapname2mapid; + map->mapname2ipport = map_mapname2ipport; + map->setipport = map_setipport; + map->eraseipport = map_eraseipport; + map->eraseallipport = map_eraseallipport; + map->addiddb = map_addiddb; + map->deliddb = map_deliddb; /* */ - iMap->nick2sd = map_nick2sd; - iMap->getmob_boss = map_getmob_boss; - iMap->id2boss = map_id2boss; + map->nick2sd = map_nick2sd; + map->getmob_boss = map_getmob_boss; + map->id2boss = map_id2boss; // reload config file looking only for npcs - iMap->reloadnpc = map_reloadnpc; - - iMap->check_dir = map_check_dir; - iMap->calc_dir = map_calc_dir; - iMap->random_dir = map_random_dir; // [Skotlex] - - iMap->cleanup_sub = cleanup_sub; - - iMap->delmap = map_delmap; - iMap->flags_init = map_flags_init; - - iMap->iwall_set = map_iwall_set; - iMap->iwall_get = map_iwall_get; - iMap->iwall_remove = map_iwall_remove; - - iMap->addmobtolist = map_addmobtolist; // [Wizputer] - iMap->spawnmobs = map_spawnmobs; // [Wizputer] - iMap->removemobs = map_removemobs; // [Wizputer] - iMap->addmap2db = map_addmap2db; - iMap->removemapdb = map_removemapdb; - iMap->clean = map_clean; - - iMap->do_shutdown = do_shutdown; - - iMap->map_foreachpc = map_map_foreachpc; - iMap->map_foreachmob = map_map_foreachmob; - iMap->map_foreachnpc = map_map_foreachnpc; - iMap->map_foreachregen = map_map_foreachregen; - iMap->map_foreachiddb = map_map_foreachiddb; - - iMap->foreachinrange = map_foreachinrange; - iMap->foreachinshootrange = map_foreachinshootrange; - iMap->foreachinarea=map_foreachinarea; - iMap->forcountinrange=map_forcountinrange; - iMap->forcountinarea=map_forcountinarea; - iMap->foreachinmovearea = map_foreachinmovearea; - iMap->foreachincell=map_foreachincell; - iMap->foreachinpath=map_foreachinpath; - iMap->foreachinmap=map_foreachinmap; - iMap->foreachininstance=map_foreachininstance; - - /* temporary until the map.c "Hercules Renewal Phase One" design is complete. [Ind] */ + map->reloadnpc = map_reloadnpc; + + map->check_dir = map_check_dir; + map->calc_dir = map_calc_dir; + map->random_dir = map_random_dir; // [Skotlex] + + map->cleanup_sub = cleanup_sub; + + map->delmap = map_delmap; + map->flags_init = map_flags_init; + + map->iwall_set = map_iwall_set; + map->iwall_get = map_iwall_get; + map->iwall_remove = map_iwall_remove; + + map->addmobtolist = map_addmobtolist; // [Wizputer] + map->spawnmobs = map_spawnmobs; // [Wizputer] + map->removemobs = map_removemobs; // [Wizputer] + map->addmap2db = map_addmap2db; + map->removemapdb = map_removemapdb; + map->clean = map_clean; + + map->do_shutdown = do_shutdown; + + map->freeblock_timer = map_freeblock_timer; + map->searchrandfreecell = map_searchrandfreecell; + map->count_sub = map_count_sub; + map->create_charid2nick = create_charid2nick; + map->removemobs_sub = map_removemobs_sub; + map->gat2cell = map_gat2cell; + map->cell2gat = map_cell2gat; + map->getcellp = map_getcellp; + map->setcell = map_setcell; + map->sub_getcellp = map_sub_getcellp; + map->sub_setcell = map_sub_setcell; + map->iwall_nextxy = map_iwall_nextxy; + map->create_map_data_other_server = create_map_data_other_server; + map->eraseallipport_sub = map_eraseallipport_sub; + map->init_mapcache = map_init_mapcache; + map->readfromcache = map_readfromcache; + map->addmap = map_addmap; + map->delmapid = map_delmapid; + map->zone_db_clear = map_zone_db_clear; + map->list_final = do_final_maps; + map->waterheight = map_waterheight; + map->readgat = map_readgat; + map->readallmaps = map_readallmaps; + map->config_read = map_config_read; + map->config_read_sub = map_config_read_sub; + map->reloadnpc_sub = map_reloadnpc_sub; + map->inter_config_read = inter_config_read; + map->sql_init = map_sql_init; + map->sql_close = map_sql_close; + map->zone_mf_cache = map_zone_mf_cache; + map->zone_str2itemid = map_zone_str2itemid; + map->zone_str2skillid = map_zone_str2skillid; + map->zone_bl_type = map_zone_bl_type; + map->read_zone_db = read_map_zone_db; + map->db_final = map_db_final; + map->nick_db_final = nick_db_final; + map->cleanup_db_sub = cleanup_db_sub; + map->abort_sub = map_abort_sub; + map->helpscreen = map_helpscreen; + map->versionscreen = map_versionscreen; + map->arg_next_value = map_arg_next_value; + + map->update_cell_bl = map_update_cell_bl; + + map->get_new_bonus_id = map_get_new_bonus_id; + + map->add_questinfo = map_add_questinfo; + map->remove_questinfo = map_remove_questinfo; + + map->merge_zone = map_merge_zone; + + /** + * mapit interface + **/ + mapit = &mapit_s; mapit->alloc = mapit_alloc; @@ -5628,4 +6155,5 @@ void map_defaults(void) { mapit->next = mapit_next; mapit->prev = mapit_prev; mapit->exists = mapit_exists; + } diff --git a/src/map/map.h b/src/map/map.h index 3e7c45bc3..dba565cc0 100644 --- a/src/map/map.h +++ b/src/map/map.h @@ -1,26 +1,32 @@ // Copyright (c) Hercules Dev Team, licensed under GNU GPL. // See the LICENSE file // Portions Copyright (c) Athena Dev Teams -#ifndef _MAP_H_ -#define _MAP_H_ + +#ifndef MAP_MAP_H +#define MAP_MAP_H + +#include <stdarg.h> + +#include "atcommand.h" #include "../common/cbasetypes.h" #include "../common/core.h" // CORE_ST_LAST -#include "../common/mmo.h" -#include "../common/mapindex.h" #include "../common/db.h" -#include "../config/core.h" -#include "atcommand.h" -#include <stdarg.h> +#include "../common/mapindex.h" +#include "../common/mmo.h" +#include "../common/sql.h" + +struct mob_data; struct npc_data; -struct item_data; struct hChSysCh; + enum E_MAPSERVER_ST { MAPSERVER_ST_RUNNING = CORE_ST_LAST, MAPSERVER_ST_SHUTDOWN, MAPSERVER_ST_LAST }; + #define MAX_NPC_PER_MAP 512 -#define AREA_SIZE battle_config.area_size +#define AREA_SIZE (battle->bc->area_size) #define DAMAGELOG_SIZE 30 #define LOOTITEM_SIZE 10 #define MAX_MOBSKILL 50 @@ -30,10 +36,15 @@ enum E_MAPSERVER_ST { #define NATURAL_HEAL_INTERVAL 500 #define MIN_FLOORITEM 2 #define MAX_FLOORITEM START_ACCOUNT_NUM -#define MAX_LEVEL 150 #define MAX_IGNORE_LIST 20 // official is 14 #define MAX_VENDING 12 -#define MAX_MAP_SIZE 512*512 // Wasn't there something like this already? Can't find it.. [Shinryo] +#define MAX_MAP_SIZE (512*512) // Wasn't there something like this already? Can't find it.. [Shinryo] + +#define BLOCK_SIZE 8 +#define block_free_max 1048576 +#define BL_LIST_MAX 1048576 + + // Added definitions for WoESE objects. [L0ne_W0lf] enum MOBID { MOBID_EMPERIUM = 1288, @@ -51,6 +62,7 @@ enum MOBID { MOBID_SILVERSNIPER = 2042, MOBID_MAGICDECOY_WIND = 2046, }; + // The following system marks a different job ID system used by the map server, // which makes a lot more sense than the normal one. [Skotlex] // These marks the "level" of the job. @@ -60,10 +72,12 @@ enum MOBID { #define JOBL_UPPER 0x1000 //4096 #define JOBL_BABY 0x2000 //8192 #define JOBL_THIRD 0x4000 //16384 + // For filtering and quick checking. #define MAPID_BASEMASK 0x00ff #define MAPID_UPPERMASK 0x0fff #define MAPID_THIRDMASK (JOBL_THIRD|MAPID_UPPERMASK) + //First Jobs //Note the oddity of the novice: //Super Novices are considered the 2-1 version of the novice! Novices are considered a first class type. @@ -92,6 +106,7 @@ enum { MAPID_BLACKSMITH, MAPID_ASSASSIN, MAPID_STAR_GLADIATOR, + MAPID_REBELLION = JOBL_2_1|0x09, MAPID_KAGEROUOBORO = JOBL_2_1|0x0A, MAPID_DEATH_KNIGHT = JOBL_2_1|0x0E, //2-2 Jobs @@ -102,7 +117,7 @@ enum { MAPID_ALCHEMIST, MAPID_ROGUE, MAPID_SOUL_LINKER, - MAPID_DARK_COLLECTOR = JOBL_2_2|0x0D, + MAPID_DARK_COLLECTOR = JOBL_2_2|0x0E, //Trans Novice And Trans 1-1 Jobs MAPID_NOVICE_HIGH = JOBL_UPPER|0x0, MAPID_SWORDMAN_HIGH, @@ -193,6 +208,7 @@ enum { MAPID_BABY_GENETIC, MAPID_BABY_CHASER, }; + // Max size for inputs to Graffiti, Talkie Box and Vending text prompts #define MESSAGE_SIZE (79 + 1) // String length you can write in the 'talking box' @@ -204,15 +220,15 @@ enum { #define CHAT_SIZE_MAX (255 + 1) // 24 for npc name + 24 for label + 2 for a "::" and 1 for EOS #define EVENT_NAME_LENGTH ( NAME_LENGTH * 2 + 3 ) -#define DEFAULT_AUTOSAVE_INTERVAL 5*60*1000 +#define DEFAULT_AUTOSAVE_INTERVAL (5*60*1000) // Specifies maps where players may hit each other -#define map_flag_vs(m) (map[m].flag.pvp || map[m].flag.gvg_dungeon || map[m].flag.gvg || ((iMap->agit_flag || iMap->agit2_flag) && map[m].flag.gvg_castle) || map[m].flag.battleground) +#define map_flag_vs(m) (map->list[m].flag.pvp || map->list[m].flag.gvg_dungeon || map->list[m].flag.gvg || ((map->agit_flag || map->agit2_flag) && map->list[m].flag.gvg_castle) || map->list[m].flag.battleground) // Specifies maps that have special GvG/WoE restrictions -#define map_flag_gvg(m) (map[m].flag.gvg || ((iMap->agit_flag || iMap->agit2_flag) && map[m].flag.gvg_castle)) -// Specifies if the map is tagged as GvG/WoE (regardless of iMap->agit_flag status) -#define map_flag_gvg2(m) (map[m].flag.gvg || map[m].flag.gvg_castle) +#define map_flag_gvg(m) (map->list[m].flag.gvg || ((map->agit_flag || map->agit2_flag) && map->list[m].flag.gvg_castle)) +// Specifies if the map is tagged as GvG/WoE (regardless of map->agit_flag status) +#define map_flag_gvg2(m) (map->list[m].flag.gvg || map->list[m].flag.gvg_castle) // No Kill Steal Protection -#define map_flag_ks(m) (map[m].flag.town || map[m].flag.pvp || map[m].flag.gvg || map[m].flag.battleground) +#define map_flag_ks(m) (map->list[m].flag.town || map->list[m].flag.pvp || map->list[m].flag.gvg || map->list[m].flag.battleground) //This stackable implementation does not means a BL can be more than one type at a time, but it's // meant to make it easier to check for multiple types at a time on invocations such as map_foreach* calls [Skotlex] @@ -296,7 +312,6 @@ struct block_list { enum bl_type type; }; - // Mob List Held in memory for Dynamic Mobs [Wizputer] // Expanded to specify all mob-related spawn data by [Skotlex] struct spawn_data { @@ -309,7 +324,7 @@ struct spawn_data { unsigned int level; struct { unsigned int size : 2; //Holds if mob has to be tiny/large - unsigned int ai : 4; //Special ai for summoned monsters. + unsigned int ai : 4; //Special AI for summoned monsters. //0: Normal mob | 1: Standard summon, attacks mobs //2: Alchemist Marine Sphere | 3: Alchemist Summon Flora | 4: Summon Zanzou unsigned int dynamic : 1; //Whether this data is indexed by a map's dynamic mob list @@ -323,11 +338,11 @@ struct flooritem_data { unsigned char subx,suby; int cleartimer; int first_get_charid,second_get_charid,third_get_charid; - unsigned int first_get_tick,second_get_tick,third_get_tick; + int64 first_get_tick,second_get_tick,third_get_tick; struct item item_data; }; -enum _sp { +enum status_point_types { SP_SPEED,SP_BASEEXP,SP_JOBEXP,SP_KARMA,SP_MANNER,SP_HP,SP_MAXHP,SP_SP, // 0-7 SP_MAXSP,SP_STATUSPOINT,SP_0a,SP_BASELEVEL,SP_SKILLPOINT,SP_STR,SP_AGI,SP_VIT, // 8-15 SP_INT,SP_DEX,SP_LUK,SP_CLASS,SP_ZENY,SP_SEX,SP_NEXTBASEEXP,SP_NEXTJOBEXP, // 16-23 @@ -344,6 +359,9 @@ enum _sp { SP_KILLEDRID=122, SP_SLOTCHANGE=123, SP_CHARRENAME=124, + SP_MOD_EXP=125, + SP_MOD_DROP=126, + SP_MOD_DEATH=127, // Mercenaries SP_MERCFLEE=165, SP_MERCKILLS=189, SP_MERCFAITH=190, @@ -386,14 +404,19 @@ enum _sp { SP_SUBSIZE, SP_HP_DRAIN_VALUE_RACE, SP_ADD_ITEM_HEAL_RATE, SP_SP_DRAIN_VALUE_RACE, SP_EXP_ADDRACE, // 2026-2030 SP_SP_GAIN_RACE, SP_SUBRACE2, SP_UNBREAKABLE_SHOES, // 2031-2033 SP_UNSTRIPABLE_WEAPON,SP_UNSTRIPABLE_ARMOR,SP_UNSTRIPABLE_HELM,SP_UNSTRIPABLE_SHIELD, // 2034-2037 - SP_INTRAVISION, SP_ADD_MONSTER_DROP_ITEMGROUP, SP_SP_LOSS_RATE, // 2038-2040 + SP_INTRAVISION, SP_ADD_MONSTER_DROP_CHAINITEM, SP_SP_LOSS_RATE, // 2038-2040 SP_ADD_SKILL_BLOW, SP_SP_VANISH_RATE, SP_MAGIC_SP_GAIN_VALUE, SP_MAGIC_HP_GAIN_VALUE, SP_ADD_CLASS_DROP_ITEM, //2041-2045 SP_EMATK, SP_SP_GAIN_RACE_ATTACK, SP_HP_GAIN_RACE_ATTACK, SP_SKILL_USE_SP_RATE, //2046-2049 SP_SKILL_COOLDOWN,SP_SKILL_FIXEDCAST, SP_SKILL_VARIABLECAST, SP_FIXCASTRATE, SP_VARCASTRATE, //2050-2054 - SP_SKILL_USE_SP,SP_MAGIC_ATK_ELE, SP_ADD_FIXEDCAST, SP_ADD_VARIABLECAST //2055-2058 + SP_SKILL_USE_SP,SP_MAGIC_ATK_ELE, SP_ADD_FIXEDCAST, SP_ADD_VARIABLECAST, //2055-2058 + SP_SET_DEF_RACE,SP_SET_MDEF_RACE, //2059-2060 + + + /* must be the last, plugins add bonuses from this value onwards */ + SP_LAST_KNOWN, }; -enum _look { +enum look { LOOK_BASE, LOOK_HAIR, LOOK_WEAPON, @@ -420,12 +443,11 @@ typedef enum { CELL_LANDPROTECTOR, CELL_NOVENDING, CELL_NOCHAT, - CELL_MAELSTROM, CELL_ICEWALL, } cell_t; -// used by iMap->getcell() +// used by map->getcell() typedef enum { CELL_GETTYPE, // retrieves a cell's 'gat' type @@ -444,31 +466,28 @@ typedef enum { CELL_CHKLANDPROTECTOR, CELL_CHKNOVENDING, CELL_CHKNOCHAT, - CELL_CHKMAELSTROM, CELL_CHKICEWALL, } cell_chk; -struct mapcell -{ +struct mapcell { // terrain flags unsigned char -walkable : 1, -shootable : 1, -water : 1; + walkable : 1, + shootable : 1, + water : 1; // dynamic flags unsigned char -npc : 1, -basilica : 1, -landprotector : 1, -novending : 1, -nochat : 1, -maelstrom : 1, -icewall : 1; + npc : 1, + basilica : 1, + landprotector : 1, + novending : 1, + nochat : 1, + icewall : 1; #ifdef CELL_NOSTACK - unsigned char cell_bl; //Holds amount of bls in this cell. + int cell_bl; //Holds amount of bls in this cell. #endif }; @@ -509,7 +528,7 @@ struct map_zone_skill_damage_cap_entry { enum map_zone_skill_subtype subtype; }; -#define MAP_ZONE_NAME_LENGTH 30 +#define MAP_ZONE_NAME_LENGTH 60 #define MAP_ZONE_ALL_NAME "All" #define MAP_ZONE_NORMAL_NAME "Normal" #define MAP_ZONE_PVP_NAME "PvP" @@ -517,7 +536,7 @@ struct map_zone_skill_damage_cap_entry { #define MAP_ZONE_BG_NAME "Battlegrounds" #define MAP_ZONE_PK_NAME "PK Mode" #define MAP_ZONE_MAPFLAG_LENGTH 50 -DBMap *zone_db;/* string => struct map_zone_data */ + struct map_zone_data { char name[MAP_ZONE_NAME_LENGTH];/* 20'd */ struct map_zone_disabled_skill_entry **disabled_skills; @@ -530,11 +549,11 @@ struct map_zone_data { int disabled_commands_count; struct map_zone_skill_damage_cap_entry **capped_skills; int capped_skills_count; + struct { + unsigned int special : 2;/* 1: whether this is a mergeable zone; 2: whether it is a merged zone */ + } info; }; -struct map_zone_data map_zone_all;/* used as a base on all maps */ -struct map_zone_data map_zone_pk;/* used for (pk_mode) */ - struct map_drop_list { int drop_id; int drop_type; @@ -542,12 +561,33 @@ struct map_drop_list { }; +struct questinfo { + struct npc_data *nd; + unsigned short icon; + unsigned char color; + int quest_id; + bool hasJob; + unsigned short job;/* perhaps a mapid mask would be most flexible? */ +}; + + struct map_data { char name[MAP_NAME_LENGTH]; uint16 index; // The map index used by the mapindex* functions. struct mapcell* cell; // Holds the information of each map cell (NULL if the map is not on this map-server). - struct block_list **block; - struct block_list **block_mob; + + /* 2D Orthogonal Range Search: Grid Implementation + "Algorithms in Java, Parts 1-4" 3.18, Robert Sedgewick + Map is divided into squares, called blocks (side length = BLOCK_SIZE). + For each block there is a linked list of objects in that block (block_list). + Array provides capability to access immediately the set of objects close + to a given object. + The linked lists provide the flexibility to store the objects without + knowing ahead how many objects fall into each block. + */ + struct block_list **block; // Grid array of block_lists containing only non-BL_MOB objects + struct block_list **block_mob; // Grid array of block_lists containing only BL_MOB objects + int16 m; int16 xs,ys; // map dimensions (in cells) int16 bxs,bys; // map dimensions (in blocks) @@ -605,6 +645,8 @@ struct map_data { unsigned reset :1; // [Daegaladh] unsigned chsysnolocalaj : 1; unsigned noknockback : 1; + unsigned notomb : 1; + unsigned nocashshop : 1; } flag; struct point save; struct npc_data *npc[MAX_NPC_PER_MAP]; @@ -618,8 +660,8 @@ struct map_data { int nocommand; //Blocks @/# commands for non-gms. [Skotlex] /** * Ice wall reference counter for bugreport:3574 - * - since there are a thounsand mobs out there in a lot of maps checking on, - * - every targetting for icewall on attack path would just be a waste, so, + * - since there are a thousand mobs out there in a lot of maps checking on, + * - every targeting for icewall on attack path would just be a waste, so, * - this counter allows icewall checking be only run when there is a actual ice wall on the map **/ int icewall_num; @@ -657,13 +699,23 @@ struct map_data { /* long_damage_rate mapflag */ unsigned short long_damage_rate; - /* instance unique name */ - char *cName; + bool custom_name; ///< Whether the instanced map is using a custom name /* */ int (*getcellp)(struct map_data* m,int16 x,int16 y,cell_chk cellchk); void (*setcell) (int16 m, int16 x, int16 y, cell_t cell, bool flag); char *cellPos; + + /* ShowEvent Data Cache */ + struct questinfo *qi_data; + unsigned short qi_count; + + /* speeds up clif_updatestatus processing by causing hpmeter to run only when someone with the permission can view it */ + unsigned short hpmeter_visible; + + /* HPM Custom Struct */ + struct HPluginData **hdata; + unsigned int hdatac; }; /// Stores information about a remote map (for multi-mapserver setups). @@ -676,59 +728,34 @@ struct map_data_other_server { uint16 port; }; - -struct map_data *map; - - - - - - -//int map_foreachinrange(int (*func)(struct block_list*,va_list), struct block_list* center, int16 range, int type, ...); -//int map_foreachinshootrange(int (*func)(struct block_list*,va_list), struct block_list* center, int16 range, int type, ...); -//int map_foreachinarea(int (*func)(struct block_list*,va_list), int16 m, int16 x0, int16 y0, int16 x1, int16 y1, int type, ...); -//int map_forcountinrange(int (*func)(struct block_list*,va_list), struct block_list* center, int16 range, int count, int type, ...); -//int map_forcountinarea(int (*func)(struct block_list*,va_list), int16 m, int16 x0, int16 y0, int16 x1, int16 y1, int count, int type, ...); -//int map_foreachinmovearea(int (*func)(struct block_list*,va_list), struct block_list* center, int16 range, int16 dx, int16 dy, int type, ...); -//int map_foreachincell(int (*func)(struct block_list*,va_list), int16 m, int16 x, int16 y, int type, ...); -//int map_foreachinpath(int (*func)(struct block_list*,va_list), int16 m, int16 x0, int16 y0, int16 x1, int16 y1, int16 range, int length, int type, ...); -//int map_foreachinmap(int (*func)(struct block_list*,va_list), int16 m, int type, ...); -//int map_foreachininstance(int (*func)(struct block_list*,va_list), int16 instance_id, int type,...); -// - - - - -#define map_id2index(id) map[(id)].index +#define map_id2index(id) (map->list[(id)].index) /// Bitfield of flags for the iterator. enum e_mapitflags { MAPIT_NORMAL = 0, - // MAPIT_PCISPLAYING = 1,// Unneeded as pc_db/id_db will only hold auth'ed, active players. + // MAPIT_PCISPLAYING = 1,// Unneeded as pc_db/id_db will only hold authed, active players. }; + struct s_mapiterator; + /* temporary until the map.c "Hercules Renewal Phase One" design is complete. */ struct mapit_interface { struct s_mapiterator* (*alloc) (enum e_mapitflags flags, enum bl_type types); - void (*free) (struct s_mapiterator* mapit); - struct block_list* (*first) (struct s_mapiterator* mapit); - struct block_list* (*last) (struct s_mapiterator* mapit); - struct block_list* (*next) (struct s_mapiterator* mapit); - struct block_list* (*prev) (struct s_mapiterator* mapit); - bool (*exists) (struct s_mapiterator* mapit); -} mapit_s; -struct mapit_interface *mapit; -#define mapit_getallusers() mapit->alloc(MAPIT_NORMAL,BL_PC) -#define mapit_geteachpc() mapit->alloc(MAPIT_NORMAL,BL_PC) -#define mapit_geteachmob() mapit->alloc(MAPIT_NORMAL,BL_MOB) -#define mapit_geteachnpc() mapit->alloc(MAPIT_NORMAL,BL_NPC) -#define mapit_geteachiddb() mapit->alloc(MAPIT_NORMAL,BL_ALL) - - - - + void (*free) (struct s_mapiterator* iter); + struct block_list* (*first) (struct s_mapiterator* iter); + struct block_list* (*last) (struct s_mapiterator* iter); + struct block_list* (*next) (struct s_mapiterator* iter); + struct block_list* (*prev) (struct s_mapiterator* iter); + bool (*exists) (struct s_mapiterator* iter); +}; +struct mapit_interface *mapit; +#define mapit_getallusers() (mapit->alloc(MAPIT_NORMAL,BL_PC)) +#define mapit_geteachpc() (mapit->alloc(MAPIT_NORMAL,BL_PC)) +#define mapit_geteachmob() (mapit->alloc(MAPIT_NORMAL,BL_MOB)) +#define mapit_geteachnpc() (mapit->alloc(MAPIT_NORMAL,BL_NPC)) +#define mapit_geteachiddb() (mapit->alloc(MAPIT_NORMAL,BL_ALL)) //Useful typedefs from jA [Skotlex] typedef struct map_session_data TBL_PC; @@ -745,23 +772,41 @@ typedef struct elemental_data TBL_ELEM; #define BL_CAST(type_, bl) \ ( ((bl) == (struct block_list*)NULL || (bl)->type != (type_)) ? (T ## type_ *)NULL : (T ## type_ *)(bl) ) -#include "../common/sql.h" - +struct charid_request { + struct charid_request* next; + int charid;// who want to be notified of the nick +}; +struct charid2nick { + char nick[NAME_LENGTH]; + struct charid_request* requests;// requests of notification on this nick +}; -extern Sql* mmysql_handle; -extern Sql* logmysql_handle; +// This is the main header found at the very beginning of the map cache +struct map_cache_main_header { + uint32 file_size; + uint16 map_count; +}; +// This is the header appended before every compressed map cells info in the map cache +struct map_cache_map_info { + char name[MAP_NAME_LENGTH]; + int16 xs; + int16 ys; + int32 len; +}; /*===================================== -* Interface : map.h +* Interface : map.h * Generated by HerculesInterfaceMaker * created by Susu *-------------------------------------*/ struct map_interface { /* vars */ - int map_num; + bool minimal; + int retval; + int count; int autosave_interval; int minsave_interval; @@ -787,7 +832,9 @@ struct map_interface { char *MSG_CONF_NAME; char *GRF_PATH_FILENAME; - int db_use_sqldbs; + int db_use_sql_item_db; + int db_use_sql_mob_db; + int db_use_sql_mob_skill_db; char item_db_db[32]; char item_db2_db[32]; @@ -797,7 +844,58 @@ struct map_interface { char mob_skill_db_db[32]; char mob_skill_db2_db[32]; char interreg_db[32]; + char autotrade_merchants_db[32]; + char autotrade_data_db[32]; + char npc_market_data_db[32]; + + char default_codepage[32]; + + int server_port; + char server_ip[32]; + char server_id[32]; + char server_pw[32]; + char server_db[32]; + Sql* mysql_handle; + + int port; + int users; + int enable_grf; //To enable/disable reading maps from GRF files, bypassing mapcache [blackhole89] + bool ip_set; + bool char_ip_set; + int16 index2mapid[MAX_MAPINDEX]; + /* */ + DBMap* id_db; // int id -> struct block_list* + DBMap* pc_db; // int id -> struct map_session_data* + DBMap* mobid_db; // int id -> struct mob_data* + DBMap* bossid_db; // int id -> struct mob_data* (MVP db) + DBMap* map_db; // unsigned int mapindex -> struct map_data_other_server* + DBMap* nick_db; // int char_id -> struct charid2nick* (requested names of offline characters) + DBMap* charid_db; // int char_id -> struct map_session_data* + DBMap* regen_db; // int id -> struct block_list* (status_natural_heal processing) + DBMap* zone_db; // string => struct map_zone_data + DBMap* iwall_db; + /* order respected by map_defaults() in order to zero */ + /* from block_free until zone_pk */ + struct block_list **block_free; + int block_free_count, block_free_lock, block_free_list_size; + struct block_list **bl_list; + int bl_list_count, bl_list_size; + struct block_list bl_head; + struct map_zone_data zone_all;/* used as a base on all maps */ + struct map_zone_data zone_pk;/* used for (pk_mode) */ + /* */ + struct map_session_data *cpsd; + struct map_data *list; + /* [Ind/Hercules] */ + struct eri *iterator_ers; + char *cache_buffer; // Has the uncompressed gat data of all maps, so just one allocation has to be made + /* */ + struct eri *flooritem_ers; + /* */ + int bonus_id; + /* */ + bool cpsd_active; /* funcs */ void (*zone_init) (void); void (*zone_remove) (int m); @@ -820,20 +918,20 @@ struct map_interface { // blocklist manipulation int (*addblock) (struct block_list* bl); int (*delblock) (struct block_list* bl); - int (*moveblock) (struct block_list *, int, int, unsigned int); + int (*moveblock) (struct block_list *bl, int x1, int y1, int64 tick); //blocklist nb in one cell int (*count_oncell) (int16 m,int16 x,int16 y,int type); - struct skill_unit * (*find_skill_unit_oncell) (struct block_list *,int16 x,int16 y,uint16 skill_id,struct skill_unit *, int flag); + struct skill_unit * (*find_skill_unit_oncell) (struct block_list* target,int16 x,int16 y,uint16 skill_id,struct skill_unit* out_unit, int flag); // search and creation int (*get_new_object_id) (void); int (*search_freecell) (struct block_list *src, int16 m, int16 *x, int16 *y, int16 rx, int16 ry, int flag); // - int (*quit) (struct map_session_data *); + int (*quit) (struct map_session_data *sd); // npc - bool (*addnpc) (int16 m,struct npc_data *); + bool (*addnpc) (int16 m,struct npc_data *nd); // map item - int (*clearflooritem_timer) (int tid, unsigned int tick, int id, intptr_t data); - int (*removemobs_timer) (int tid, unsigned int tick, int id, intptr_t data); + int (*clearflooritem_timer) (int tid, int64 tick, int id, intptr_t data); + int (*removemobs_timer) (int tid, int64 tick, int id, intptr_t data); void (*clearflooritem) (struct block_list* bl); int (*addflooritem) (struct item *item_data,int amount,int16 m,int16 x,int16 y,int first_charid,int second_charid,int third_charid,int flags); // player to map session @@ -843,21 +941,36 @@ struct map_interface { const char* (*charid2nick) (int charid); struct map_session_data* (*charid2sd) (int charid); - void (*map_foreachpc) (int (*func)(struct map_session_data* sd, va_list args), ...); - void (*map_foreachmob) (int (*func)(struct mob_data* md, va_list args), ...); - void (*map_foreachnpc) (int (*func)(struct npc_data* nd, va_list args), ...); - void (*map_foreachregen) (int (*func)(struct block_list* bl, va_list args), ...); - void (*map_foreachiddb) (int (*func)(struct block_list* bl, va_list args), ...); - + void (*vforeachpc) (int (*func)(struct map_session_data* sd, va_list args), va_list args); + void (*foreachpc) (int (*func)(struct map_session_data* sd, va_list args), ...); + void (*vforeachmob) (int (*func)(struct mob_data* md, va_list args), va_list args); + void (*foreachmob) (int (*func)(struct mob_data* md, va_list args), ...); + void (*vforeachnpc) (int (*func)(struct npc_data* nd, va_list args), va_list args); + void (*foreachnpc) (int (*func)(struct npc_data* nd, va_list args), ...); + void (*vforeachregen) (int (*func)(struct block_list* bl, va_list args), va_list args); + void (*foreachregen) (int (*func)(struct block_list* bl, va_list args), ...); + void (*vforeachiddb) (int (*func)(struct block_list* bl, va_list args), va_list args); + void (*foreachiddb) (int (*func)(struct block_list* bl, va_list args), ...); + + int (*vforeachinrange) (int (*func)(struct block_list*,va_list), struct block_list* center, int16 range, int type, va_list ap); int (*foreachinrange) (int (*func)(struct block_list*,va_list), struct block_list* center, int16 range, int type, ...); + int (*vforeachinshootrange) (int (*func)(struct block_list*,va_list), struct block_list* center, int16 range, int type, va_list ap); int (*foreachinshootrange) (int (*func)(struct block_list*,va_list), struct block_list* center, int16 range, int type, ...); + int (*vforeachinarea) (int (*func)(struct block_list*,va_list), int16 m, int16 x0, int16 y0, int16 x1, int16 y1, int type, va_list ap); int (*foreachinarea) (int (*func)(struct block_list*,va_list), int16 m, int16 x0, int16 y0, int16 x1, int16 y1, int type, ...); + int (*vforcountinrange) (int (*func)(struct block_list*,va_list), struct block_list* center, int16 range, int count, int type, va_list ap); int (*forcountinrange) (int (*func)(struct block_list*,va_list), struct block_list* center, int16 range, int count, int type, ...); + int (*vforcountinarea) (int (*func)(struct block_list*,va_list), int16 m, int16 x0, int16 y0, int16 x1, int16 y1, int count, int type, va_list ap); int (*forcountinarea) (int (*func)(struct block_list*,va_list), int16 m, int16 x0, int16 y0, int16 x1, int16 y1, int count, int type, ...); + int (*vforeachinmovearea) (int (*func)(struct block_list*,va_list), struct block_list* center, int16 range, int16 dx, int16 dy, int type, va_list ap); int (*foreachinmovearea) (int (*func)(struct block_list*,va_list), struct block_list* center, int16 range, int16 dx, int16 dy, int type, ...); + int (*vforeachincell) (int (*func)(struct block_list*,va_list), int16 m, int16 x, int16 y, int type, va_list ap); int (*foreachincell) (int (*func)(struct block_list*,va_list), int16 m, int16 x, int16 y, int type, ...); + int (*vforeachinpath) (int (*func)(struct block_list*,va_list), int16 m, int16 x0, int16 y0, int16 x1, int16 y1, int16 range, int length, int type, va_list ap); int (*foreachinpath) (int (*func)(struct block_list*,va_list), int16 m, int16 x0, int16 y0, int16 x1, int16 y1, int16 range, int length, int type, ...); + int (*vforeachinmap) (int (*func)(struct block_list*,va_list), int16 m, int type, va_list args); int (*foreachinmap) (int (*func)(struct block_list*,va_list), int16 m, int type, ...); + int (*vforeachininstance)(int (*func)(struct block_list*,va_list), int16 instance_id, int type, va_list ap); int (*foreachininstance)(int (*func)(struct block_list*,va_list), int16 instance_id, int type,...); struct map_session_data * (*id2sd) (int id); @@ -868,20 +981,20 @@ struct map_interface { struct chat_data* (*id2cd) (int id); struct block_list * (*id2bl) (int id); bool (*blid_exists) (int id); - int16 (*mapindex2mapid) (unsigned short mapindex); + int16 (*mapindex2mapid) (unsigned short map_index); int16 (*mapname2mapid) (const char* name); int (*mapname2ipport) (unsigned short name, uint32* ip, uint16* port); - int (*setipport) (unsigned short map, uint32 ip, uint16 port); - int (*eraseipport) (unsigned short map, uint32 ip, uint16 port); + int (*setipport) (unsigned short map_index, uint32 ip, uint16 port); + int (*eraseipport) (unsigned short map_index, uint32 ip, uint16 port); int (*eraseallipport) (void); - void (*addiddb) (struct block_list *); + void (*addiddb) (struct block_list *bl); void (*deliddb) (struct block_list *bl); /* */ - struct map_session_data * (*nick2sd) (const char*); + struct map_session_data * (*nick2sd) (const char *nick); struct mob_data * (*getmob_boss) (int16 m); struct mob_data * (*id2boss) (int id); // reload config file looking only for npcs - void (*reloadnpc) (bool clear); + void (*reloadnpc) (bool clear, const char * const *extra_scripts, int extra_scripts_count); int (*check_dir) (int s_dir,int t_dir); uint8 (*calc_dir) (struct block_list *src,int16 x,int16 y); @@ -899,16 +1012,63 @@ struct map_interface { int (*addmobtolist) (unsigned short m, struct spawn_data *spawn); // [Wizputer] void (*spawnmobs) (int16 m); // [Wizputer] void (*removemobs) (int16 m); // [Wizputer] - void (*do_reconnect_map) (void); //Invoked on map-char reconnection [Skotlex] Note used but still keeping it, just in case + //void (*do_reconnect_map) (void); //Invoked on map-char reconnection [Skotlex] Note used but still keeping it, just in case void (*addmap2db) (struct map_data *m); void (*removemapdb) (struct map_data *m); void (*clean) (int i); void (*do_shutdown) (void); -} iMap_s; + + int (*freeblock_timer) (int tid, int64 tick, int id, intptr_t data); + int (*searchrandfreecell) (int16 m, int16 *x, int16 *y, int stack); + int (*count_sub) (struct block_list *bl, va_list ap); + DBData (*create_charid2nick) (DBKey key, va_list args); + int (*removemobs_sub) (struct block_list *bl, va_list ap); + struct mapcell (*gat2cell) (int gat); + int (*cell2gat) (struct mapcell cell); + int (*getcellp) (struct map_data *m, int16 x, int16 y, cell_chk cellchk); + void (*setcell) (int16 m, int16 x, int16 y, cell_t cell, bool flag); + int (*sub_getcellp) (struct map_data *m, int16 x, int16 y, cell_chk cellchk); + void (*sub_setcell) (int16 m, int16 x, int16 y, cell_t cell, bool flag); + void (*iwall_nextxy) (int16 x, int16 y, int8 dir, int pos, int16 *x1, int16 *y1); + DBData (*create_map_data_other_server) (DBKey key, va_list args); + int (*eraseallipport_sub) (DBKey key, DBData *data, va_list va); + char* (*init_mapcache) (FILE *fp); + int (*readfromcache) (struct map_data *m, char *buffer); + int (*addmap) (const char *mapname); + void (*delmapid) (int id); + void (*zone_db_clear) (void); + void (*list_final) (void); + int (*waterheight) (char *mapname); + int (*readgat) (struct map_data *m); + int (*readallmaps) (void); + int (*config_read) (char *cfgName); + int (*config_read_sub) (char *cfgName); + void (*reloadnpc_sub) (char *cfgName); + int (*inter_config_read) (char *cfgName); + int (*sql_init) (void); + int (*sql_close) (void); + bool (*zone_mf_cache) (int m, char *flag, char *params); + unsigned short (*zone_str2itemid) (const char *name); + unsigned short (*zone_str2skillid) (const char *name); + enum bl_type (*zone_bl_type) (const char *entry, enum map_zone_skill_subtype *subtype); + void (*read_zone_db) (void); + int (*db_final) (DBKey key, DBData *data, va_list ap); + int (*nick_db_final) (DBKey key, DBData *data, va_list args); + int (*cleanup_db_sub) (DBKey key, DBData *data, va_list va); + int (*abort_sub) (struct map_session_data *sd, va_list ap); + void (*helpscreen) (bool do_exit); + void (*versionscreen) (bool do_exit); + bool (*arg_next_value) (const char *option, int i, int argc, bool must); + void (*update_cell_bl) (struct block_list *bl, bool increase); + int (*get_new_bonus_id) (void); + void (*add_questinfo) (int m, struct questinfo *qi); + bool (*remove_questinfo) (int m, struct npc_data *nd); + struct map_zone_data *(*merge_zone) (struct map_zone_data *main, struct map_zone_data *other); +}; -struct map_interface *iMap; +struct map_interface *map; void map_defaults(void); -#endif /* _MAP_H_ */ +#endif /* MAP_MAP_H */ diff --git a/src/map/mapreg.h b/src/map/mapreg.h index e83f9e053..59d226cda 100644 --- a/src/map/mapreg.h +++ b/src/map/mapreg.h @@ -2,26 +2,52 @@ // See the LICENSE file // Portions Copyright (c) Athena Dev Teams -#ifndef _MAPREG_H_ -#define _MAPREG_H_ +#ifndef MAP_MAPREG_H +#define MAP_MAPREG_H +#include "script.h" // struct reg_db +#include "../common/cbasetypes.h" +#include "../common/db.h" + +/** Container for a mapreg value */ struct mapreg_save { - int uid; + int64 uid; ///< Unique ID union { - int i; - char *str; + int i; ///< Numeric value + char *str; ///< String value } u; - bool save; + bool is_string; ///< true if it's a string, false if it's a number + bool save; ///< Whether a save operation is pending +}; + +struct mapreg_interface { + struct reg_db regs; + /* */ + bool skip_insert; + /* */ + struct eri *ers; //[Ind/Hercules] + /* */ + char table[32]; + /* */ + bool dirty; ///< Whether there are modified regs to be saved + /* */ + void (*init) (void); + void (*final) (void); + /* */ + int (*readreg) (int64 uid); + char* (*readregstr) (int64 uid); + bool (*setreg) (int64 uid, int val); + bool (*setregstr) (int64 uid, const char *str); + void (*load) (void); + void (*save) (void); + int (*save_timer) (int tid, int64 tick, int id, intptr_t data); + int (*destroyreg) (DBKey key, DBData *data, va_list ap); + void (*reload) (void); + bool (*config_read) (const char *w1, const char *w2); }; -void mapreg_reload(void); -void mapreg_final(void); -void mapreg_init(void); -bool mapreg_config_read(const char* w1, const char* w2); +struct mapreg_interface *mapreg; -int mapreg_readreg(int uid); -char* mapreg_readregstr(int uid); -bool mapreg_setreg(int uid, int val); -bool mapreg_setregstr(int uid, const char* str); +void mapreg_defaults(void); -#endif /* _MAPREG_H_ */ +#endif /* MAP_MAPREG_H */ diff --git a/src/map/mapreg_sql.c b/src/map/mapreg_sql.c index b6865c8fd..f026fde00 100644 --- a/src/map/mapreg_sql.c +++ b/src/map/mapreg_sql.c @@ -2,6 +2,15 @@ // See the LICENSE file // Portions Copyright (c) Athena Dev Teams +#define HERCULES_CORE + +#include "mapreg.h" + +#include <stdlib.h> +#include <string.h> + +#include "map.h" // map->mysql_handle +#include "script.h" #include "../common/cbasetypes.h" #include "../common/db.h" #include "../common/ers.h" @@ -10,143 +19,167 @@ #include "../common/sql.h" #include "../common/strlib.h" #include "../common/timer.h" -#include "map.h" // mmysql_handle -#include "script.h" -#include "mapreg.h" -#include <stdlib.h> -#include <string.h> - -static DBMap* mapreg_db = NULL; // int var_id -> int value -static DBMap* mapregstr_db = NULL; // int var_id -> char* value -static struct eri *mapreg_ers; //[Ind/Hercules] -static char mapreg_table[32] = "mapreg"; -static bool mapreg_i_dirty = false; -static bool mapreg_str_dirty = false; +struct mapreg_interface mapreg_s; #define MAPREG_AUTOSAVE_INTERVAL (300*1000) - -/// Looks up the value of an integer variable using its uid. -int mapreg_readreg(int uid) { - struct mapreg_save *m = idb_get(mapreg_db, uid); +/** + * Looks up the value of an integer variable using its uid. + * + * @param uid variable's unique identifier. + * @return variable's integer value + */ +int mapreg_readreg(int64 uid) { + struct mapreg_save *m = i64db_get(mapreg->regs.vars, uid); return m?m->u.i:0; } -/// Looks up the value of a string variable using its uid. -char* mapreg_readregstr(int uid) { - struct mapreg_save *m = idb_get(mapregstr_db, uid); +/** + * Looks up the value of a string variable using its uid. + * + * @param uid variable's unique identifier + * @return variable's string value + */ +char* mapreg_readregstr(int64 uid) { + struct mapreg_save *m = i64db_get(mapreg->regs.vars, uid); return m?m->u.str:NULL; } -/// Modifies the value of an integer variable. -bool mapreg_setreg(int uid, int val) { +/** + * Modifies the value of an integer variable. + * + * @param uid variable's unique identifier + * @param val new value + * @retval true value was successfully set + */ +bool mapreg_setreg(int64 uid, int val) { struct mapreg_save *m; - int num = (uid & 0x00ffffff); - int i = (uid & 0xff000000) >> 24; - const char* name = get_str(num); + int num = script_getvarid(uid); + unsigned int i = script_getvaridx(uid); + const char* name = script->get_str(num); if( val != 0 ) { - if( (m = idb_get(mapreg_db,uid)) ) { + if( (m = i64db_get(mapreg->regs.vars, uid)) ) { m->u.i = val; if(name[1] != '@') { m->save = true; - mapreg_i_dirty = true; + mapreg->dirty = true; } } else { - m = ers_alloc(mapreg_ers, struct mapreg_save); + if( i ) + script->array_update(&mapreg->regs, uid, false); + + m = ers_alloc(mapreg->ers, struct mapreg_save); m->u.i = val; m->uid = uid; m->save = false; + m->is_string = false; - if(name[1] != '@') {// write new variable to database + if(name[1] != '@' && !mapreg->skip_insert) {// write new variable to database char tmp_str[32*2+1]; - SQL->EscapeStringLen(mmysql_handle, tmp_str, name, strnlen(name, 32)); - if( SQL_ERROR == SQL->Query(mmysql_handle, "INSERT INTO `%s`(`varname`,`index`,`value`) VALUES ('%s','%d','%d')", mapreg_table, tmp_str, i, val) ) - Sql_ShowDebug(mmysql_handle); + SQL->EscapeStringLen(map->mysql_handle, tmp_str, name, strnlen(name, 32)); + if( SQL_ERROR == SQL->Query(map->mysql_handle, "INSERT INTO `%s`(`varname`,`index`,`value`) VALUES ('%s','%d','%d')", mapreg->table, tmp_str, i, val) ) + Sql_ShowDebug(map->mysql_handle); } - idb_put(mapreg_db, uid, m); + i64db_put(mapreg->regs.vars, uid, m); } } else { // val == 0 - if( (m = idb_get(mapreg_db,uid)) ) { - ers_free(mapreg_ers, m); + if( i ) + script->array_update(&mapreg->regs, uid, true); + if( (m = i64db_get(mapreg->regs.vars, uid)) ) { + ers_free(mapreg->ers, m); } - idb_remove(mapreg_db,uid); + i64db_remove(mapreg->regs.vars, uid); if( name[1] != '@' ) {// Remove from database because it is unused. - if( SQL_ERROR == SQL->Query(mmysql_handle, "DELETE FROM `%s` WHERE `varname`='%s' AND `index`='%d'", mapreg_table, name, i) ) - Sql_ShowDebug(mmysql_handle); + if( SQL_ERROR == SQL->Query(map->mysql_handle, "DELETE FROM `%s` WHERE `varname`='%s' AND `index`='%d'", mapreg->table, name, i) ) + Sql_ShowDebug(map->mysql_handle); } } return true; } -/// Modifies the value of a string variable. -bool mapreg_setregstr(int uid, const char* str) { +/** + * Modifies the value of a string variable. + * + * @param uid variable's unique identifier + * @param str new value + * @retval true value was successfully set + */ +bool mapreg_setregstr(int64 uid, const char* str) { struct mapreg_save *m; - int num = (uid & 0x00ffffff); - int i = (uid & 0xff000000) >> 24; - const char* name = get_str(num); - + int num = script_getvarid(uid); + unsigned int i = script_getvaridx(uid); + const char* name = script->get_str(num); + if( str == NULL || *str == 0 ) { + if( i ) + script->array_update(&mapreg->regs, uid, true); if(name[1] != '@') { - if( SQL_ERROR == SQL->Query(mmysql_handle, "DELETE FROM `%s` WHERE `varname`='%s' AND `index`='%d'", mapreg_table, name, i) ) - Sql_ShowDebug(mmysql_handle); + if( SQL_ERROR == SQL->Query(map->mysql_handle, "DELETE FROM `%s` WHERE `varname`='%s' AND `index`='%d'", mapreg->table, name, i) ) + Sql_ShowDebug(map->mysql_handle); } - if( (m = idb_get(mapregstr_db,uid)) ) { + if( (m = i64db_get(mapreg->regs.vars, uid)) ) { if( m->u.str != NULL ) aFree(m->u.str); - ers_free(mapreg_ers, m); + ers_free(mapreg->ers, m); } - idb_remove(mapregstr_db,uid); + i64db_remove(mapreg->regs.vars, uid); } else { - if( (m = idb_get(mapregstr_db,uid)) ) { + if( (m = i64db_get(mapreg->regs.vars, uid)) ) { if( m->u.str != NULL ) aFree(m->u.str); m->u.str = aStrdup(str); if(name[1] != '@') { - mapreg_str_dirty = true; + mapreg->dirty = true; m->save = true; } } else { - m = ers_alloc(mapreg_ers, struct mapreg_save); + if( i ) + script->array_update(&mapreg->regs, uid, false); + + m = ers_alloc(mapreg->ers, struct mapreg_save); m->uid = uid; m->u.str = aStrdup(str); m->save = false; - - if(name[1] != '@') { //put returned null, so we must insert. + m->is_string = true; + + if(name[1] != '@' && !mapreg->skip_insert) { //put returned null, so we must insert. char tmp_str[32*2+1]; char tmp_str2[255*2+1]; - SQL->EscapeStringLen(mmysql_handle, tmp_str, name, strnlen(name, 32)); - SQL->EscapeStringLen(mmysql_handle, tmp_str2, str, strnlen(str, 255)); - if( SQL_ERROR == SQL->Query(mmysql_handle, "INSERT INTO `%s`(`varname`,`index`,`value`) VALUES ('%s','%d','%s')", mapreg_table, tmp_str, i, tmp_str2) ) - Sql_ShowDebug(mmysql_handle); + SQL->EscapeStringLen(map->mysql_handle, tmp_str, name, strnlen(name, 32)); + SQL->EscapeStringLen(map->mysql_handle, tmp_str2, str, strnlen(str, 255)); + if( SQL_ERROR == SQL->Query(map->mysql_handle, "INSERT INTO `%s`(`varname`,`index`,`value`) VALUES ('%s','%d','%s')", mapreg->table, tmp_str, i, tmp_str2) ) + Sql_ShowDebug(map->mysql_handle); } - idb_put(mapregstr_db, uid, m); + i64db_put(mapreg->regs.vars, uid, m); } } return true; } -/// Loads permanent variables from database -static void script_load_mapreg(void) { +/** + * Loads permanent variables from database. + */ +void script_load_mapreg(void) { /* 0 1 2 +-------------------------+ | varname | index | value | +-------------------------+ */ - SqlStmt* stmt = SQL->StmtMalloc(mmysql_handle); + SqlStmt* stmt = SQL->StmtMalloc(map->mysql_handle); char varname[32+1]; int index; char value[255+1]; uint32 length; - if ( SQL_ERROR == SQL->StmtPrepare(stmt, "SELECT `varname`, `index`, `value` FROM `%s`", mapreg_table) + if ( SQL_ERROR == SQL->StmtPrepare(stmt, "SELECT `varname`, `index`, `value` FROM `%s`", mapreg->table) || SQL_ERROR == SQL->StmtExecute(stmt) ) { SqlStmt_ShowDebug(stmt); @@ -154,163 +187,187 @@ static void script_load_mapreg(void) { return; } + mapreg->skip_insert = true; + SQL->StmtBindColumn(stmt, 0, SQLDT_STRING, &varname[0], sizeof(varname), &length, NULL); SQL->StmtBindColumn(stmt, 1, SQLDT_INT, &index, 0, NULL, NULL); SQL->StmtBindColumn(stmt, 2, SQLDT_STRING, &value[0], sizeof(value), NULL, NULL); - + while ( SQL_SUCCESS == SQL->StmtNextRow(stmt) ) { - struct mapreg_save *m = NULL; - int s = add_str(varname); + int s = script->add_str(varname); int i = index; - if( varname[length-1] == '$' ) { - if( idb_exists(mapregstr_db, (i<<24)|s) ) { - ShowWarning("load_mapreg: duplicate! '%s' => '%s' skipping...\n",varname,value); - continue; - } - } else { - if( idb_exists(mapreg_db, (i<<24)|s) ) { - ShowWarning("load_mapreg: duplicate! '%s' => '%s' skipping...\n",varname,value); - continue; - } + + if( i64db_exists(mapreg->regs.vars, reference_uid(s, i)) ) { + ShowWarning("load_mapreg: duplicate! '%s' => '%s' skipping...\n",varname,value); + continue; } - - m = ers_alloc(mapreg_ers, struct mapreg_save); - m->uid = (i<<24)|s; - m->save = false; if( varname[length-1] == '$' ) { - m->u.str = aStrdup(value); - idb_put(mapregstr_db, m->uid, m); + mapreg->setregstr(reference_uid(s, i),value); } else { - m->u.i = atoi(value); - idb_put(mapreg_db, m->uid, m); + mapreg->setreg(reference_uid(s, i),atoi(value)); } } - + SQL->StmtFree(stmt); - mapreg_i_dirty = false; - mapreg_str_dirty = false; + mapreg->skip_insert = false; + + mapreg->dirty = false; } -/// Saves permanent variables to database -static void script_save_mapreg(void) { +/** + * Saves permanent variables to database. + */ +void script_save_mapreg(void) { DBIterator* iter; struct mapreg_save *m = NULL; - if( mapreg_i_dirty ) { - iter = db_iterator(mapreg_db); - for( m = dbi_first(iter); dbi_exists(iter); m = dbi_next(iter) ) { - if( m->save ) { - int num = (m->uid & 0x00ffffff); - int i = (m->uid & 0xff000000) >> 24; - const char* name = get_str(num); - - if( SQL_ERROR == SQL->Query(mmysql_handle, "UPDATE `%s` SET `value`='%d' WHERE `varname`='%s' AND `index`='%d' LIMIT 1", mapreg_table, m->u.i, name, i) ) - Sql_ShowDebug(mmysql_handle); - m->save = false; - } - } - dbi_destroy(iter); - mapreg_i_dirty = false; - } - - if( mapreg_str_dirty ) { - iter = db_iterator(mapregstr_db); + if( mapreg->dirty ) { + iter = db_iterator(mapreg->regs.vars); for( m = dbi_first(iter); dbi_exists(iter); m = dbi_next(iter) ) { if( m->save ) { - int num = (m->uid & 0x00ffffff); - int i = (m->uid & 0xff000000) >> 24; - const char* name = get_str(num); - char tmp_str2[2*255+1]; - - SQL->EscapeStringLen(mmysql_handle, tmp_str2, m->u.str, safestrnlen(m->u.str, 255)); - if( SQL_ERROR == SQL->Query(mmysql_handle, "UPDATE `%s` SET `value`='%s' WHERE `varname`='%s' AND `index`='%d' LIMIT 1", mapreg_table, tmp_str2, name, i) ) - Sql_ShowDebug(mmysql_handle); + int num = script_getvarid(m->uid); + int i = script_getvaridx(m->uid); + const char* name = script->get_str(num); + if (!m->is_string) { + if( SQL_ERROR == SQL->Query(map->mysql_handle, "UPDATE `%s` SET `value`='%d' WHERE `varname`='%s' AND `index`='%d' LIMIT 1", mapreg->table, m->u.i, name, i) ) + Sql_ShowDebug(map->mysql_handle); + } else { + char tmp_str2[2*255+1]; + SQL->EscapeStringLen(map->mysql_handle, tmp_str2, m->u.str, safestrnlen(m->u.str, 255)); + if( SQL_ERROR == SQL->Query(map->mysql_handle, "UPDATE `%s` SET `value`='%s' WHERE `varname`='%s' AND `index`='%d' LIMIT 1", mapreg->table, tmp_str2, name, i) ) + Sql_ShowDebug(map->mysql_handle); + } m->save = false; } } dbi_destroy(iter); - mapreg_str_dirty = false; + mapreg->dirty = false; } } -static int script_autosave_mapreg(int tid, unsigned int tick, int id, intptr_t data) { - script_save_mapreg(); +/** + * Timer event to auto-save permanent variables. + * + * @see timer->do_timer + */ +int script_autosave_mapreg(int tid, int64 tick, int id, intptr_t data) { + mapreg->save(); return 0; } - -void mapreg_reload(void) { - DBIterator* iter; +/** + * Destroys a mapreg_save structure, freeing the contained string, if any. + * + * @see DBApply + */ +int mapreg_destroyreg(DBKey key, DBData *data, va_list ap) { struct mapreg_save *m = NULL; - script_save_mapreg(); + if (data->type != DB_DATA_PTR) // Sanity check + return 0; - iter = db_iterator(mapreg_db); - for( m = dbi_first(iter); dbi_exists(iter); m = dbi_next(iter) ) { - ers_free(mapreg_ers, m); - } - dbi_destroy(iter); - - iter = db_iterator(mapregstr_db); - for( m = dbi_first(iter); dbi_exists(iter); m = dbi_next(iter) ) { - if( m->u.str != NULL ) { + m = DB->data2ptr(data); + + if (m->is_string) { + if (m->u.str) aFree(m->u.str); - } - ers_free(mapreg_ers, m); } - dbi_destroy(iter); - - db_clear(mapreg_db); - db_clear(mapregstr_db); + ers_free(mapreg->ers, m); - script_load_mapreg(); + return 0; } -void mapreg_final(void) { - DBIterator* iter; - struct mapreg_save *m = NULL; - - script_save_mapreg(); +/** + * Reloads mapregs, saving to database beforehand. + * + * This has the effect of clearing the temporary variables, and + * reloading the permanent ones. + */ +void mapreg_reload(void) { + mapreg->save(); - iter = db_iterator(mapreg_db); - for( m = dbi_first(iter); dbi_exists(iter); m = dbi_next(iter) ) { - ers_free(mapreg_ers, m); - } - dbi_destroy(iter); - - iter = db_iterator(mapregstr_db); - for( m = dbi_first(iter); dbi_exists(iter); m = dbi_next(iter) ) { - if( m->u.str != NULL ) { - aFree(m->u.str); - } - ers_free(mapreg_ers, m); + mapreg->regs.vars->clear(mapreg->regs.vars, mapreg->destroyreg); + + if( mapreg->regs.arrays ) { + mapreg->regs.arrays->destroy(mapreg->regs.arrays, script->array_free_db); + mapreg->regs.arrays = NULL; } - dbi_destroy(iter); - - db_destroy(mapreg_db); - db_destroy(mapregstr_db); - - ers_destroy(mapreg_ers); + + mapreg->load(); } +/** + * Finalizer. + */ +void mapreg_final(void) { + mapreg->save(); + + mapreg->regs.vars->destroy(mapreg->regs.vars, mapreg->destroyreg); + + ers_destroy(mapreg->ers); + + if( mapreg->regs.arrays ) + mapreg->regs.arrays->destroy(mapreg->regs.arrays, script->array_free_db); +} + +/** + * Initializer. + */ void mapreg_init(void) { - mapreg_db = idb_alloc(DB_OPT_BASE); - mapregstr_db = idb_alloc(DB_OPT_BASE); - mapreg_ers = ers_new(sizeof(struct mapreg_save), "mapreg_sql.c::mapreg_ers", ERS_OPT_NONE); + mapreg->regs.vars = i64db_alloc(DB_OPT_BASE); + mapreg->ers = ers_new(sizeof(struct mapreg_save), "mapreg_sql.c::mapreg_ers", ERS_OPT_CLEAN); - script_load_mapreg(); + mapreg->load(); - iTimer->add_timer_func_list(script_autosave_mapreg, "script_autosave_mapreg"); - iTimer->add_timer_interval(iTimer->gettick() + MAPREG_AUTOSAVE_INTERVAL, script_autosave_mapreg, 0, 0, MAPREG_AUTOSAVE_INTERVAL); + timer->add_func_list(mapreg->save_timer, "mapreg_script_autosave_mapreg"); + timer->add_interval(timer->gettick() + MAPREG_AUTOSAVE_INTERVAL, mapreg->save_timer, 0, 0, MAPREG_AUTOSAVE_INTERVAL); } +/** + * Loads the mapreg configuration file. + */ bool mapreg_config_read(const char* w1, const char* w2) { if(!strcmpi(w1, "mapreg_db")) - safestrncpy(mapreg_table, w2, sizeof(mapreg_table)); + safestrncpy(mapreg->table, w2, sizeof(mapreg->table)); else return false; return true; } + +/** + * Interface defaults initializer. + */ +void mapreg_defaults(void) { + mapreg = &mapreg_s; + + /* */ + mapreg->regs.vars = NULL; + mapreg->ers = NULL; + mapreg->skip_insert = false; + + safestrncpy(mapreg->table, "mapreg", sizeof(mapreg->table)); + mapreg->dirty = false; + + /* */ + mapreg->regs.arrays = NULL; + + /* */ + mapreg->init = mapreg_init; + mapreg->final = mapreg_final; + + /* */ + mapreg->readreg = mapreg_readreg; + mapreg->readregstr = mapreg_readregstr; + mapreg->setreg = mapreg_setreg; + mapreg->setregstr = mapreg_setregstr; + mapreg->load = script_load_mapreg; + mapreg->save = script_save_mapreg; + mapreg->save_timer = script_autosave_mapreg; + mapreg->destroyreg = mapreg_destroyreg; + mapreg->reload = mapreg_reload; + mapreg->config_read = mapreg_config_read; + +} diff --git a/src/map/mercenary.c b/src/map/mercenary.c index 566f68409..80bcfdf05 100644 --- a/src/map/mercenary.c +++ b/src/map/mercenary.c @@ -2,64 +2,66 @@ // See the LICENSE file // Portions Copyright (c) Athena Dev Teams -#include "../common/cbasetypes.h" -#include "../common/malloc.h" -#include "../common/socket.h" -#include "../common/timer.h" -#include "../common/nullpo.h" -#include "../common/mmo.h" -#include "../common/random.h" -#include "../common/showmsg.h" -#include "../common/strlib.h" -#include "../common/utils.h" +#define HERCULES_CORE -#include "log.h" -#include "clif.h" +#include "mercenary.h" + +#include <math.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "atcommand.h" +#include "battle.h" #include "chrif.h" +#include "clif.h" +#include "guild.h" #include "intif.h" #include "itemdb.h" +#include "log.h" #include "map.h" -#include "pc.h" -#include "status.h" -#include "skill.h" #include "mob.h" -#include "pet.h" -#include "battle.h" +#include "npc.h" #include "party.h" -#include "guild.h" -#include "atcommand.h" +#include "pc.h" +#include "pet.h" #include "script.h" -#include "npc.h" +#include "skill.h" +#include "status.h" #include "trade.h" #include "unit.h" -#include "mercenary.h" - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <math.h> +#include "../common/cbasetypes.h" +#include "../common/malloc.h" +#include "../common/mmo.h" +#include "../common/nullpo.h" +#include "../common/random.h" +#include "../common/showmsg.h" +#include "../common/socket.h" +#include "../common/strlib.h" +#include "../common/timer.h" +#include "../common/utils.h" -struct s_mercenary_db mercenary_db[MAX_MERCENARY_CLASS]; // Mercenary Database +struct mercenary_interface mercenary_s; int merc_search_index(int class_) { int i; - ARR_FIND(0, MAX_MERCENARY_CLASS, i, mercenary_db[i].class_ == class_); + ARR_FIND(0, MAX_MERCENARY_CLASS, i, mercenary->db[i].class_ == class_); return (i == MAX_MERCENARY_CLASS)?-1:i; } bool merc_class(int class_) { - return (bool)(merc_search_index(class_) > -1); + return (bool)(mercenary->search_index(class_) > -1); } struct view_data * merc_get_viewdata(int class_) { - int i = merc_search_index(class_); + int i = mercenary->search_index(class_); if( i < 0 ) return 0; - return &mercenary_db[i].vd; + return &mercenary->db[i].vd; } int merc_create(struct map_session_data *sd, int class_, unsigned int lifetime) @@ -69,10 +71,10 @@ int merc_create(struct map_session_data *sd, int class_, unsigned int lifetime) int i; nullpo_retr(0,sd); - if( (i = merc_search_index(class_)) < 0 ) + if( (i = mercenary->search_index(class_)) < 0 ) return 0; - db = &mercenary_db[i]; + db = &mercenary->db[i]; memset(&merc,0,sizeof(struct s_mercenary)); merc.char_id = sd->status.char_id; @@ -82,7 +84,7 @@ int merc_create(struct map_session_data *sd, int class_, unsigned int lifetime) merc.life_time = lifetime; // Request Char Server to create this mercenary - intif_mercenary_create(&merc); + intif->mercenary_create(&merc); return 1; } @@ -93,8 +95,8 @@ int mercenary_get_lifetime(struct mercenary_data *md) if( md == NULL || md->contract_timer == INVALID_TIMER ) return 0; - td = iTimer->get_timer(md->contract_timer); - return (td != NULL) ? DIFF_TICK(td->tick, iTimer->gettick()) : 0; + td = timer->get(md->contract_timer); + return (td != NULL) ? DIFF_TICK32(td->tick, timer->gettick()) : 0; } int mercenary_get_guild(struct mercenary_data *md) @@ -211,30 +213,29 @@ int mercenary_save(struct mercenary_data *md) { md->mercenary.hp = md->battle_status.hp; md->mercenary.sp = md->battle_status.sp; - md->mercenary.life_time = mercenary_get_lifetime(md); + md->mercenary.life_time = mercenary->get_lifetime(md); - intif_mercenary_save(&md->mercenary); + intif->mercenary_save(&md->mercenary); return 1; } -static int merc_contract_end(int tid, unsigned int tick, int id, intptr_t data) -{ +int merc_contract_end_timer(int tid, int64 tick, int id, intptr_t data) { struct map_session_data *sd; struct mercenary_data *md; - if( (sd = iMap->id2sd(id)) == NULL ) + if( (sd = map->id2sd(id)) == NULL ) return 1; if( (md = sd->md) == NULL ) return 1; if( md->contract_timer != tid ) { - ShowError("merc_contract_end %d != %d.\n", md->contract_timer, tid); + ShowError("merc_contract_end_timer %d != %d.\n", md->contract_timer, tid); return 0; } md->contract_timer = INVALID_TIMER; - merc_delete(md, 0); // Mercenary soldier's duty hour is over. + mercenary->delete(md, 0); // Mercenary soldier's duty hour is over. return 0; } @@ -244,10 +245,10 @@ int merc_delete(struct mercenary_data *md, int reply) struct map_session_data *sd = md->master; md->mercenary.life_time = 0; - merc_contract_stop(md); + mercenary->contract_stop(md); if( !sd ) - return unit_free(&md->bl, CLR_OUTSIGHT); + return unit->free(&md->bl, CLR_OUTSIGHT); if( md->devotion_flag ) { @@ -257,38 +258,37 @@ int merc_delete(struct mercenary_data *md, int reply) switch( reply ) { - case 0: mercenary_set_faith(md, 1); break; // +1 Loyalty on Contract ends. - case 1: mercenary_set_faith(md, -1); break; // -1 Loyalty on Mercenary killed + case 0: mercenary->set_faith(md, 1); break; // +1 Loyalty on Contract ends. + case 1: mercenary->set_faith(md, -1); break; // -1 Loyalty on Mercenary killed } clif->mercenary_message(sd, reply); - return unit_remove_map(&md->bl, CLR_OUTSIGHT); + return unit->remove_map(&md->bl, CLR_OUTSIGHT, ALC_MARK); } void merc_contract_stop(struct mercenary_data *md) { nullpo_retv(md); if( md->contract_timer != INVALID_TIMER ) - iTimer->delete_timer(md->contract_timer, merc_contract_end); + timer->delete(md->contract_timer, mercenary->contract_end_timer); md->contract_timer = INVALID_TIMER; } void merc_contract_init(struct mercenary_data *md) { if( md->contract_timer == INVALID_TIMER ) - md->contract_timer = iTimer->add_timer(iTimer->gettick() + md->mercenary.life_time, merc_contract_end, md->master->bl.id, 0); + md->contract_timer = timer->add(timer->gettick() + md->mercenary.life_time, mercenary->contract_end_timer, md->master->bl.id, 0); md->regen.state.block = 0; } -int merc_data_received(struct s_mercenary *merc, bool flag) -{ +int merc_data_received(struct s_mercenary *merc, bool flag) { struct map_session_data *sd; struct mercenary_data *md; struct s_mercenary_db *db; - int i = merc_search_index(merc->class_); + int i = mercenary->search_index(merc->class_); - if( (sd = iMap->charid2sd(merc->char_id)) == NULL ) + if( (sd = map->charid2sd(merc->char_id)) == NULL ) return 0; if( !flag || i < 0 ) { // Not created - loaded - DB info @@ -296,31 +296,30 @@ int merc_data_received(struct s_mercenary *merc, bool flag) return 0; } - db = &mercenary_db[i]; - if( !sd->md ) - { + db = &mercenary->db[i]; + if( !sd->md ) { sd->md = md = (struct mercenary_data*)aCalloc(1,sizeof(struct mercenary_data)); md->bl.type = BL_MER; - md->bl.id = npc_get_new_npc_id(); + md->bl.id = npc->get_new_npc_id(); md->devotion_flag = 0; md->master = sd; md->db = db; memcpy(&md->mercenary, merc, sizeof(struct s_mercenary)); - status_set_viewdata(&md->bl, md->mercenary.class_); - status_change_init(&md->bl); - unit_dataset(&md->bl); + status->set_viewdata(&md->bl, md->mercenary.class_); + status->change_init(&md->bl); + unit->dataset(&md->bl); md->ud.dir = sd->ud.dir; md->bl.m = sd->bl.m; md->bl.x = sd->bl.x; md->bl.y = sd->bl.y; - unit_calc_pos(&md->bl, sd->bl.x, sd->bl.y, sd->ud.dir); + unit->calc_pos(&md->bl, sd->bl.x, sd->bl.y, sd->ud.dir); md->bl.x = md->ud.to_x; md->bl.y = md->ud.to_y; - iMap->addiddb(&md->bl); - status_calc_mercenary(md,1); + map->addiddb(&md->bl); + status_calc_mercenary(md,SCO_FIRST); md->contract_timer = INVALID_TIMER; merc_contract_init(md); } @@ -331,12 +330,11 @@ int merc_data_received(struct s_mercenary *merc, bool flag) } if( sd->status.mer_id == 0 ) - mercenary_set_calls(md, 1); + mercenary->set_calls(md, 1); sd->status.mer_id = merc->mercenary_id; - if( md && md->bl.prev == NULL && sd->bl.prev != NULL ) - { - iMap->addblock(&md->bl); + if( md && md->bl.prev == NULL && sd->bl.prev != NULL ) { + map->addblock(&md->bl); clif->spawn(&md->bl); clif->mercenary_info(sd); clif->mercenary_skillblock(sd); @@ -355,7 +353,7 @@ void mercenary_heal(struct mercenary_data *md, int hp, int sp) int mercenary_dead(struct mercenary_data *md) { - merc_delete(md, 1); + mercenary->delete(md, 1); return 0; } @@ -364,7 +362,7 @@ int mercenary_killbonus(struct mercenary_data *md) const enum sc_type scs[] = { SC_MER_FLEE, SC_MER_ATK, SC_MER_HP, SC_MER_SP, SC_MER_HIT }; int index = rnd() % ARRAYLENGTH(scs); - sc_start(&md->bl, scs[index], 100, rnd() % 5, 600000); + sc_start(NULL,&md->bl, scs[index], 100, rnd() % 5, 600000); return 0; } @@ -375,8 +373,8 @@ int mercenary_kills(struct mercenary_data *md) if( (md->mercenary.kill_count % 50) == 0 ) { - mercenary_set_faith(md, 1); - mercenary_killbonus(md); + mercenary->set_faith(md, 1); + mercenary->killbonus(md); } if( md->master ) @@ -397,78 +395,74 @@ int mercenary_checkskill(struct mercenary_data *md, uint16 skill_id) return 0; } -static bool read_mercenarydb_sub(char* str[], int columns, int current) -{ +bool read_mercenarydb_sub(char* str[], int columns, int current) { int ele; struct s_mercenary_db *db; - struct status_data *status; + struct status_data *mstatus; - db = &mercenary_db[current]; + db = &mercenary->db[current]; db->class_ = atoi(str[0]); safestrncpy(db->sprite, str[1], NAME_LENGTH); safestrncpy(db->name, str[2], NAME_LENGTH); db->lv = atoi(str[3]); - status = &db->status; + mstatus = &db->status; db->vd.class_ = db->class_; - status->max_hp = atoi(str[4]); - status->max_sp = atoi(str[5]); - status->rhw.range = atoi(str[6]); - status->rhw.atk = atoi(str[7]); - status->rhw.atk2 = status->rhw.atk + atoi(str[8]); - status->def = atoi(str[9]); - status->mdef = atoi(str[10]); - status->str = atoi(str[11]); - status->agi = atoi(str[12]); - status->vit = atoi(str[13]); - status->int_ = atoi(str[14]); - status->dex = atoi(str[15]); - status->luk = atoi(str[16]); + mstatus->max_hp = atoi(str[4]); + mstatus->max_sp = atoi(str[5]); + mstatus->rhw.range = atoi(str[6]); + mstatus->rhw.atk = atoi(str[7]); + mstatus->rhw.atk2 = mstatus->rhw.atk + atoi(str[8]); + mstatus->def = atoi(str[9]); + mstatus->mdef = atoi(str[10]); + mstatus->str = atoi(str[11]); + mstatus->agi = atoi(str[12]); + mstatus->vit = atoi(str[13]); + mstatus->int_ = atoi(str[14]); + mstatus->dex = atoi(str[15]); + mstatus->luk = atoi(str[16]); db->range2 = atoi(str[17]); db->range3 = atoi(str[18]); - status->size = atoi(str[19]); - status->race = atoi(str[20]); + mstatus->size = atoi(str[19]); + mstatus->race = atoi(str[20]); ele = atoi(str[21]); - status->def_ele = ele%10; - status->ele_lv = ele/20; - if( status->def_ele >= ELE_MAX ) - { - ShowWarning("Mercenary %d has invalid element type %d (max element is %d)\n", db->class_, status->def_ele, ELE_MAX - 1); - status->def_ele = ELE_NEUTRAL; + mstatus->def_ele = ele%10; + mstatus->ele_lv = ele/20; + if( mstatus->def_ele >= ELE_MAX ) { + ShowWarning("Mercenary %d has invalid element type %d (max element is %d)\n", db->class_, mstatus->def_ele, ELE_MAX - 1); + mstatus->def_ele = ELE_NEUTRAL; } - if( status->ele_lv < 1 || status->ele_lv > 4 ) - { - ShowWarning("Mercenary %d has invalid element level %d (max is 4)\n", db->class_, status->ele_lv); - status->ele_lv = 1; + if( mstatus->ele_lv < 1 || mstatus->ele_lv > 4 ) { + ShowWarning("Mercenary %d has invalid element level %d (max is 4)\n", db->class_, mstatus->ele_lv); + mstatus->ele_lv = 1; } - status->aspd_rate = 1000; - status->speed = atoi(str[22]); - status->adelay = atoi(str[23]); - status->amotion = atoi(str[24]); - status->dmotion = atoi(str[25]); + mstatus->aspd_rate = 1000; + mstatus->speed = atoi(str[22]); + mstatus->adelay = atoi(str[23]); + mstatus->amotion = atoi(str[24]); + mstatus->dmotion = atoi(str[25]); return true; } -int read_mercenarydb(void) -{ - memset(mercenary_db,0,sizeof(mercenary_db)); - sv->readdb(iMap->db_path, "mercenary_db.txt", ',', 26, 26, MAX_MERCENARY_CLASS, &read_mercenarydb_sub); +int read_mercenarydb(void) { + memset(mercenary->db,0,sizeof(mercenary->db)); + sv->readdb(map->db_path, "mercenary_db.txt", ',', 26, 26, MAX_MERCENARY_CLASS, mercenary->read_db_sub); return 0; } -static bool read_mercenary_skilldb_sub(char* str[], int columns, int current) +bool read_mercenary_skilldb_sub(char* str[], int columns, int current) {// <merc id>,<skill id>,<skill level> struct s_mercenary_db *db; int i, class_; uint16 skill_id, skill_lv; class_ = atoi(str[0]); - ARR_FIND(0, MAX_MERCENARY_CLASS, i, class_ == mercenary_db[i].class_); + ARR_FIND(0, MAX_MERCENARY_CLASS, i, class_ == mercenary->db[i].class_); if( i == MAX_MERCENARY_CLASS ) { ShowError("read_mercenary_skilldb : Class %d not found in mercenary_db for skill entry.\n", class_); @@ -482,7 +476,7 @@ static bool read_mercenary_skilldb_sub(char* str[], int columns, int current) return false; } - db = &mercenary_db[i]; + db = &mercenary->db[i]; skill_lv = atoi(str[2]); i = skill_id - MC_SKILLBASE; @@ -492,20 +486,66 @@ static bool read_mercenary_skilldb_sub(char* str[], int columns, int current) return true; } -int read_mercenary_skilldb(void) -{ - sv->readdb(iMap->db_path, "mercenary_skill_db.txt", ',', 3, 3, -1, &read_mercenary_skilldb_sub); +int read_mercenary_skilldb(void) { + sv->readdb(map->db_path, "mercenary_skill_db.txt", ',', 3, 3, -1, mercenary->read_skill_db_sub); return 0; } -int do_init_mercenary(void) -{ - read_mercenarydb(); - read_mercenary_skilldb(); +void do_init_mercenary(bool minimal) { + if (minimal) + return; + + mercenary->read_db(); + mercenary->read_skilldb(); - //add_timer_func_list(mercenary_contract, "mercenary_contract"); - return 0; + timer->add_func_list(mercenary->contract_end_timer, "merc_contract_end_timer"); } -int do_final_mercenary(void); +/*===================================== +* Default Functions : mercenary.h +* Generated by HerculesInterfaceMaker +* created by Susu +*-------------------------------------*/ +void mercenary_defaults(void) { + mercenary = &mercenary_s; + + /* vars */ + memset(mercenary->db,0,sizeof(mercenary->db)); + + /* funcs */ + + mercenary->init = do_init_mercenary; + + mercenary->class = merc_class; + mercenary->get_viewdata = merc_get_viewdata; + + mercenary->create = merc_create; + mercenary->data_received = merc_data_received; + mercenary->save = mercenary_save; + + mercenary->heal = mercenary_heal; + mercenary->dead = mercenary_dead; + + mercenary->delete = merc_delete; + mercenary->contract_stop = merc_contract_stop; + + mercenary->get_lifetime = mercenary_get_lifetime; + mercenary->get_guild = mercenary_get_guild; + mercenary->get_faith = mercenary_get_faith; + mercenary->set_faith = mercenary_set_faith; + mercenary->get_calls = mercenary_get_calls; + mercenary->set_calls = mercenary_set_calls; + mercenary->kills = mercenary_kills; + + mercenary->checkskill = mercenary_checkskill; + mercenary->read_db = read_mercenarydb; + mercenary->read_skilldb = read_mercenary_skilldb; + + mercenary->killbonus = mercenary_killbonus; + mercenary->search_index = merc_search_index; + + mercenary->contract_end_timer = merc_contract_end_timer; + mercenary->read_db_sub = read_mercenarydb_sub; + mercenary->read_skill_db_sub = read_mercenary_skilldb_sub; +} diff --git a/src/map/mercenary.h b/src/map/mercenary.h index 994c7aaa4..270245e96 100644 --- a/src/map/mercenary.h +++ b/src/map/mercenary.h @@ -1,11 +1,12 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder - -#ifndef _MERCENARY_H_ -#define _MERCENARY_H_ +// Copyright (c) Hercules Dev Team, licensed under GNU GPL. +// See the LICENSE file +// Portions Copyright (c) Athena Dev Teams +#ifndef MAP_MERCENARY_H +#define MAP_MERCENARY_H #include "status.h" // struct status_data, struct status_change #include "unit.h" // struct unit_data +#include "../common/cbasetypes.h" // number of cells that a mercenary can walk to from it's master before being warped #define MAX_MER_DISTANCE 15 @@ -28,8 +29,6 @@ struct s_mercenary_db { } skill[MAX_MERCSKILL]; }; -extern struct s_mercenary_db mercenary_db[MAX_MERCENARY_CLASS]; - struct mercenary_data { struct block_list bl; struct unit_data ud; @@ -37,7 +36,6 @@ struct mercenary_data { struct status_data base_status, battle_status; struct status_change sc; struct regen_data regen; - struct s_mercenary_db *db; struct s_mercenary mercenary; char blockskill[MAX_SKILL]; @@ -46,38 +44,59 @@ struct mercenary_data { int contract_timer; unsigned devotion_flag : 1; - unsigned int masterteleport_timer; + int64 masterteleport_timer; }; -bool merc_class(int class_); -struct view_data * merc_get_viewdata(int class_); - -int merc_create(struct map_session_data *sd, int class_, unsigned int lifetime); -int merc_data_received(struct s_mercenary *merc, bool flag); -int mercenary_save(struct mercenary_data *md); +/*===================================== +* Interface : mercenary.h +* Generated by HerculesInterfaceMaker +* created by Susu +*-------------------------------------*/ +struct mercenary_interface { -void mercenary_heal(struct mercenary_data *md, int hp, int sp); -int mercenary_dead(struct mercenary_data *md); - -int merc_delete(struct mercenary_data *md, int reply); -void merc_contract_stop(struct mercenary_data *md); + /* vars */ + + struct s_mercenary_db db[MAX_MERCENARY_CLASS]; -int mercenary_get_lifetime(struct mercenary_data *md); -int mercenary_get_guild(struct mercenary_data *md); -int mercenary_get_faith(struct mercenary_data *md); -int mercenary_set_faith(struct mercenary_data *md, int value); -int mercenary_get_calls(struct mercenary_data *md); -int mercenary_set_calls(struct mercenary_data *md, int value); -int mercenary_kills(struct mercenary_data *md); + /* funcs */ -int mercenary_checkskill(struct mercenary_data *md, uint16 skill_id); + void (*init) (bool minimal); + + bool (*class) (int class_); + struct view_data * (*get_viewdata) (int class_); + + int (*create) (struct map_session_data *sd, int class_, unsigned int lifetime); + int (*data_received) (struct s_mercenary *merc, bool flag); + int (*save) (struct mercenary_data *md); + + void (*heal) (struct mercenary_data *md, int hp, int sp); + int (*dead) (struct mercenary_data *md); + + int (*delete) (struct mercenary_data *md, int reply); + void (*contract_stop) (struct mercenary_data *md); + + int (*get_lifetime) (struct mercenary_data *md); + int (*get_guild) (struct mercenary_data *md); + int (*get_faith) (struct mercenary_data *md); + int (*set_faith) (struct mercenary_data *md, int value); + int (*get_calls) (struct mercenary_data *md); + int (*set_calls) (struct mercenary_data *md, int value); + int (*kills) (struct mercenary_data *md); + + int (*checkskill) (struct mercenary_data *md, uint16 skill_id); + int (*read_db) (void); + int (*read_skilldb) (void); + + int (*killbonus) (struct mercenary_data *md); + int (*search_index) (int class_); + + int (*contract_end_timer) (int tid, int64 tick, int id, intptr_t data); + bool (*read_db_sub) (char* str[], int columns, int current); + bool (*read_skill_db_sub) (char* str[], int columns, int current); +}; -/** - * atcommand.c required - **/ -int read_mercenarydb(void); -int read_mercenary_skilldb(void); +struct mercenary_interface *mercenary; -int do_init_mercenary(void); +void mercenary_defaults(void); -#endif /* _MERCENARY_H_ */ +#endif /* MAP_MERCENARY_H */ diff --git a/src/map/mob.c b/src/map/mob.c index 6bb40478f..3f1769d37 100644 --- a/src/map/mob.c +++ b/src/map/mob.c @@ -2,46 +2,51 @@ // See the LICENSE file // Portions Copyright (c) Athena Dev Teams -#include "../common/cbasetypes.h" -#include "../common/timer.h" -#include "../common/db.h" -#include "../common/nullpo.h" -#include "../common/malloc.h" -#include "../common/showmsg.h" -#include "../common/ers.h" -#include "../common/random.h" -#include "../common/strlib.h" -#include "../common/utils.h" -#include "../common/socket.h" +#define HERCULES_CORE -#include "map.h" -#include "path.h" -#include "clif.h" -#include "intif.h" -#include "pc.h" -#include "pet.h" -#include "status.h" +#include "../config/core.h" // AUTOLOOT_DISTANCE, DBPATH, DEFTYPE_MAX, DEFTYPE_MIN, RENEWAL_DROP, RENEWAL_EXP #include "mob.h" -#include "homunculus.h" -#include "mercenary.h" + +#include <math.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "atcommand.h" +#include "battle.h" +#include "clif.h" +#include "date.h" #include "elemental.h" #include "guild.h" +#include "homunculus.h" +#include "intif.h" #include "itemdb.h" -#include "skill.h" -#include "battle.h" -#include "party.h" -#include "npc.h" #include "log.h" -#include "script.h" -#include "atcommand.h" -#include "date.h" +#include "map.h" +#include "mercenary.h" +#include "npc.h" +#include "party.h" +#include "path.h" +#include "pc.h" +#include "pet.h" #include "quest.h" +#include "script.h" +#include "skill.h" +#include "status.h" +#include "../common/cbasetypes.h" +#include "../common/db.h" +#include "../common/ers.h" +#include "../common/malloc.h" +#include "../common/nullpo.h" +#include "../common/random.h" +#include "../common/showmsg.h" +#include "../common/socket.h" +#include "../common/strlib.h" +#include "../common/timer.h" +#include "../common/utils.h" -#include <stdio.h> -#include <stdlib.h> -#include <stdarg.h> -#include <string.h> -#include <math.h> +struct mob_interface mob_s; #define ACTIVE_AI_RANGE 2 //Distance added on top of 'AREA_SIZE' at which mobs enter active AI mode. @@ -50,21 +55,10 @@ #define MOB_LAZYSKILLPERC 0 // Probability for mobs far from players from doing their IDLE skill. (rate of 1000 minute) // Move probability for mobs away from players (rate of 1000 minute) // in Aegis, this is 100% for mobs that have been activated by players and none otherwise. -#define MOB_LAZYMOVEPERC(md) (md->state.spotted?1000:0) +#define MOB_LAZYMOVEPERC(md) ((md)->state.spotted?1000:0) #define MOB_MAX_DELAY (24*3600*1000) #define MAX_MINCHASE 30 //Max minimum chase value to use for mobs. #define RUDE_ATTACKED_COUNT 2 //After how many rude-attacks should the skill be used? -#define MAX_MOB_CHAT 250 //Max Skill's messages - -//Dynamic mob database, allows saving of memory when there's big gaps in the mob_db [Skotlex] -struct mob_db *mob_db_data[MAX_MOB_DB+1]; -struct mob_db *mob_dummy = NULL; //Dummy mob to be returned when a non-existant one is requested. - -struct mob_db *mob_db(int index) { if (index < 0 || index > MAX_MOB_DB || mob_db_data[index] == NULL) return mob_dummy; return mob_db_data[index]; } - -//Dynamic mob chat database -struct mob_chat *mob_chat_db[MAX_MOB_CHAT+1]; -struct mob_chat *mob_chat(short id) { if(id<=0 || id>MAX_MOB_CHAT || mob_chat_db[id]==NULL) return (struct mob_chat*)NULL; return mob_chat_db[id]; } //Dynamic item drop ratio database for per-item drop ratio modifiers overriding global drop ratios. #define MAX_ITEMRATIO_MOBS 10 @@ -82,16 +76,16 @@ static struct { int class_[350]; } summon[MAX_RANDOMMONSTER]; -//Defines the Manuk/Splendide mob groups for the status reductions [Epoque] -const int mob_manuk[8] = { 1986, 1987, 1988, 1989, 1990, 1997, 1998, 1999 }; -const int mob_splendide[5] = { 1991, 1992, 1993, 1994, 1995 }; - -/*========================================== - * Local prototype declaration (only required thing) - *------------------------------------------*/ -static int mob_makedummymobdb(int); -static int mob_spawn_guardian_sub(int tid, unsigned int tick, int id, intptr_t data); -int mob_skill_id2skill_idx(int class_,uint16 skill_id); +struct mob_db *mob_db(int index) { + if (index < 0 || index > MAX_MOB_DB || mob->db_data[index] == NULL) + return mob->dummy; + return mob->db_data[index]; +} +struct mob_chat *mob_chat(short id) { + if(id <= 0 || id > MAX_MOB_CHAT || mob->chat_db[id] == NULL) + return NULL; + return mob->chat_db[id]; +} /*========================================== * Mob is searched with a name. @@ -99,28 +93,40 @@ int mob_skill_id2skill_idx(int class_,uint16 skill_id); int mobdb_searchname(const char *str) { int i; - struct mob_db* mob; + struct mob_db* monster; for(i=0;i<=MAX_MOB_DB;i++){ - mob = mob_db(i); - if(mob == mob_dummy) //Skip dummy mobs. + monster = mob->db(i); + if(monster == mob->dummy) //Skip dummy mobs. continue; - if(strcmpi(mob->name,str)==0 || strcmpi(mob->jname,str)==0 || strcmpi(mob->sprite,str)==0) + if(strcmpi(monster->name,str)==0 || strcmpi(monster->jname,str)==0) + return i; + if(battle_config.case_sensitive_aegisnames && strcmp(monster->sprite,str)==0) + return i; + if(!battle_config.case_sensitive_aegisnames && strcasecmp(monster->sprite,str)==0) return i; } return 0; } -static int mobdb_searchname_array_sub(struct mob_db* mob, const char *str) -{ - if (mob == mob_dummy) +int mobdb_searchname_array_sub(struct mob_db* monster, const char *str, int flag) { + if (monster == mob->dummy) return 1; - if(!mob->base_exp && !mob->job_exp && mob->spawn[0].qty < 1) + if(!monster->base_exp && !monster->job_exp && monster->spawn[0].qty < 1) return 1; // Monsters with no base/job exp and no spawn point are, by this criteria, considered "slave mobs" and excluded from search results - if(stristr(mob->jname,str)) - return 0; - if(stristr(mob->name,str)) - return 0; - return strcmpi(mob->jname,str); + if( !flag ) { + if(stristr(monster->jname,str)) + return 0; + if(stristr(monster->name,str)) + return 0; + } else { + if(strcmpi(monster->jname,str) == 0) + return 0; + if(strcmpi(monster->name,str) == 0) + return 0; + } + if (battle_config.case_sensitive_aegisnames) + return strcmp(monster->sprite,str); + return strcasecmp(monster->sprite,str); } /*========================================== @@ -131,19 +137,19 @@ void mvptomb_create(struct mob_data *md, char *killer, time_t time) struct npc_data *nd; if ( md->tomb_nid ) - mvptomb_destroy(md); + mob->mvptomb_destroy(md); CREATE(nd, struct npc_data, 1); - nd->bl.id = md->tomb_nid = npc_get_new_npc_id(); + nd->bl.id = md->tomb_nid = npc->get_new_npc_id(); - nd->dir = md->ud.dir; + nd->dir = md->ud.dir; nd->bl.m = md->bl.m; nd->bl.x = md->bl.x; nd->bl.y = md->bl.y; nd->bl.type = BL_NPC; - safestrncpy(nd->name, msg_txt(656), sizeof(nd->name)); + safestrncpy(nd->name, msg_txt(856), sizeof(nd->name)); // "Tomb" nd->class_ = 565; nd->speed = 200; @@ -157,33 +163,33 @@ void mvptomb_create(struct mob_data *md, char *killer, time_t time) else nd->u.tomb.killer_name[0] = '\0'; - iMap->addnpc(nd->bl.m, nd); - iMap->addblock(&nd->bl); - status_set_viewdata(&nd->bl, nd->class_); - clif->spawn(&nd->bl); + map->addnpc(nd->bl.m, nd); + map->addblock(&nd->bl); + status->set_viewdata(&nd->bl, nd->class_); + clif->spawn(&nd->bl); } void mvptomb_destroy(struct mob_data *md) { struct npc_data *nd; - if ( (nd = iMap->id2nd(md->tomb_nid)) ) { + if ( (nd = map->id2nd(md->tomb_nid)) ) { int16 m, i; m = nd->bl.m; clif->clearunit_area(&nd->bl,CLR_OUTSIGHT); - iMap->delblock(&nd->bl); + map->delblock(&nd->bl); - ARR_FIND( 0, map[m].npc_num, i, map[m].npc[i] == nd ); - if( !(i == map[m].npc_num) ) { - map[m].npc_num--; - map[m].npc[i] = map[m].npc[map[m].npc_num]; - map[m].npc[map[m].npc_num] = NULL; + ARR_FIND( 0, map->list[m].npc_num, i, map->list[m].npc[i] == nd ); + if( !(i == map->list[m].npc_num) ) { + map->list[m].npc_num--; + map->list[m].npc[i] = map->list[m].npc[map->list[m].npc_num]; + map->list[m].npc[map->list[m].npc_num] = NULL; } - iMap->deliddb(&nd->bl); + map->deliddb(&nd->bl); aFree(nd); } @@ -194,17 +200,17 @@ void mvptomb_destroy(struct mob_data *md) { /*========================================== * Founds up to N matches. Returns number of matches [Skotlex] *------------------------------------------*/ -int mobdb_searchname_array(struct mob_db** data, int size, const char *str) +int mobdb_searchname_array(struct mob_db** data, int size, const char *str, int flag) { int count = 0, i; - struct mob_db* mob; + struct mob_db* monster; for(i=0;i<=MAX_MOB_DB;i++){ - mob = mob_db(i); - if (mob == mob_dummy || mob_is_clone(i) ) //keep clones out (or you leak player stats) + monster = mob->db(i); + if (monster == mob->dummy || mob->is_clone(i) ) //keep clones out (or you leak player stats) continue; - if (!mobdb_searchname_array_sub(mob, str)) { + if (!mob->db_searchname_array_sub(monster, str, flag)) { if (count < size) - data[count] = mob; + data[count] = monster; count++; } } @@ -216,9 +222,9 @@ int mobdb_searchname_array(struct mob_db** data, int size, const char *str) *------------------------------------------*/ int mobdb_checkid(const int id) { - if (mob_db(id) == mob_dummy) + if (mob->db(id) == mob->dummy) return 0; - if (mob_is_clone(id)) //checkid is used mostly for random ID based code, therefore clone mobs are out of the question. + if (mob->is_clone(id)) //checkid is used mostly for random ID based code, therefore clone mobs are out of the question. return 0; return id; } @@ -228,9 +234,9 @@ int mobdb_checkid(const int id) *------------------------------------------*/ struct view_data * mob_get_viewdata(int class_) { - if (mob_db(class_) == mob_dummy) + if (mob->db(class_) == mob->dummy) return 0; - return &mob_db(class_)->vd; + return &mob->db(class_)->vd; } /*========================================== * Cleans up mob-spawn data to make it "valid" @@ -239,7 +245,7 @@ int mob_parse_dataset(struct spawn_data *data) { size_t len; - if ((!mobdb_checkid(data->class_) && !mob_is_clone(data->class_)) || !data->num) + if ((!mob->db_checkid(data->class_) && !mob->is_clone(data->class_)) || !data->num) return 0; if( ( len = strlen(data->eventname) ) > 0 ) @@ -251,9 +257,9 @@ int mob_parse_dataset(struct spawn_data *data) } if(strcmp(data->name,"--en--")==0) - safestrncpy(data->name, mob_db(data->class_)->name, sizeof(data->name)); + safestrncpy(data->name, mob->db(data->class_)->name, sizeof(data->name)); else if(strcmp(data->name,"--ja--")==0) - safestrncpy(data->name, mob_db(data->class_)->jname, sizeof(data->name)); + safestrncpy(data->name, mob->db(data->class_)->jname, sizeof(data->name)); return 1; } @@ -262,14 +268,14 @@ int mob_parse_dataset(struct spawn_data *data) *------------------------------------------*/ struct mob_data* mob_spawn_dataset(struct spawn_data *data) { struct mob_data *md = (struct mob_data*)aCalloc(1, sizeof(struct mob_data)); - md->bl.id= npc_get_new_npc_id(); + md->bl.id= npc->get_new_npc_id(); md->bl.type = BL_MOB; md->bl.m = data->m; md->bl.x = data->x; md->bl.y = data->y; md->class_ = data->class_; md->state.boss = data->state.boss; - md->db = mob_db(md->class_); + md->db = mob->db(md->class_); if (data->level > 0 && data->level <= MAX_LEVEL) md->level = data->level; memcpy(md->name, data->name, NAME_LENGTH); @@ -284,11 +290,11 @@ struct mob_data* mob_spawn_dataset(struct spawn_data *data) { md->spawn_timer = INVALID_TIMER; md->deletetimer = INVALID_TIMER; md->skill_idx = -1; - status_set_viewdata(&md->bl, md->class_); - status_change_init(&md->bl); - unit_dataset(&md->bl); + status->set_viewdata(&md->bl, md->class_); + status->change_init(&md->bl); + unit->dataset(&md->bl); - iMap->addiddb(&md->bl); + map->addiddb(&md->bl); return md; } @@ -307,7 +313,7 @@ struct mob_data* mob_spawn_dataset(struct spawn_data *data) { *------------------------------------------*/ int mob_get_random_id(int type, int flag, int lv) { - struct mob_db *mob; + struct mob_db *monster; int i=0, class_; if(type < 0 || type >= MAX_RANDOMMONSTER) { ShowError("mob_get_random_id: Invalid type (%d) of random monster.\n", type); @@ -318,25 +324,24 @@ int mob_get_random_id(int type, int flag, int lv) class_ = summon[type].class_[rnd()%summon[type].qty]; else //Dead branch class_ = rnd() % MAX_MOB_DB; - mob = mob_db(class_); - } while ((mob == mob_dummy || - mob_is_clone(class_) || - (flag&1 && mob->summonper[type] <= rnd() % 1000000) || - (flag&2 && lv < mob->lv) || - (flag&4 && mob->status.mode&MD_BOSS) || - (flag&8 && mob->spawn[0].qty < 1) + monster = mob->db(class_); + } while ((monster == mob->dummy || + mob->is_clone(class_) || + (flag&1 && monster->summonper[type] <= rnd() % 1000000) || + (flag&2 && lv < monster->lv) || + (flag&4 && monster->status.mode&MD_BOSS) || + (flag&8 && monster->spawn[0].qty < 1) ) && (i++) < MAX_MOB_DB); if(i >= MAX_MOB_DB) // no suitable monster found, use fallback for given list - class_ = mob_db_data[0]->summonper[type]; + class_ = mob->db_data[0]->summonper[type]; return class_; } /*========================================== * Kill Steal Protection [Zephyrus] *------------------------------------------*/ -bool mob_ksprotected (struct block_list *src, struct block_list *target) -{ +bool mob_ksprotected(struct block_list *src, struct block_list *target) { struct block_list *s_bl, *t_bl; struct map_session_data *sd, // Source @@ -344,14 +349,14 @@ bool mob_ksprotected (struct block_list *src, struct block_list *target) *t_sd; // Mob Target struct status_change_entry *sce; struct mob_data *md; - unsigned int tick = iTimer->gettick(); + int64 tick = timer->gettick(); char output[128]; if( !battle_config.ksprotection ) return false; // KS Protection Disabled if( !(md = BL_CAST(BL_MOB,target)) ) - return false; // Tarjet is not MOB + return false; // Target is not MOB if( (s_bl = battle->get_master(src)) == NULL ) s_bl = src; @@ -359,14 +364,14 @@ bool mob_ksprotected (struct block_list *src, struct block_list *target) if( !(sd = BL_CAST(BL_PC,s_bl)) ) return false; // Master is not PC - t_bl = iMap->id2bl(md->target_id); + t_bl = map->id2bl(md->target_id); if( !t_bl || (s_bl = battle->get_master(t_bl)) == NULL ) s_bl = t_bl; t_sd = BL_CAST(BL_PC,s_bl); do { - if( map[md->bl.m].flag.allowks || map_flag_ks(md->bl.m) ) + if( map->list[md->bl.m].flag.allowks || map_flag_ks(md->bl.m) ) return false; // Ignores GVG, PVP and AllowKS map flags if( md->db->mexp || md->master_id ) @@ -386,7 +391,7 @@ bool mob_ksprotected (struct block_list *src, struct block_list *target) (sce->val2 == 3 && sce->val4 && sce->val4 != t_sd->status.guild_id)) ) break; - if( (pl_sd = iMap->id2sd(sce->val1)) == NULL || pl_sd->bl.m != md->bl.m ) + if( (pl_sd = map->id2sd(sce->val1)) == NULL || pl_sd->bl.m != md->bl.m ) break; if( !pl_sd->state.noks ) @@ -396,7 +401,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, strlen(output)); sd->ks_floodprotect_tick = tick + 2000; } @@ -405,7 +410,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, strlen(output)); pl_sd->ks_floodprotect_tick = tick + 2000; } @@ -413,7 +418,7 @@ bool mob_ksprotected (struct block_list *src, struct block_list *target) return true; } while(0); - status_change_start(target, SC_KSPROTECTED, 10000, sd->bl.id, sd->state.noks, sd->status.party_id, sd->status.guild_id, battle_config.ksprotection, 0); + status->change_start(NULL, target, SC_KSPROTECTED, 10000, sd->bl.id, sd->state.noks, sd->status.party_id, sd->status.guild_id, battle_config.ksprotection, 0); return false; } @@ -442,68 +447,67 @@ struct mob_data *mob_once_spawn_sub(struct block_list *bl, int16 m, int16 x, int // Locate spot next to player. if (bl && (x < 0 || y < 0)) - iMap->search_freecell(bl, m, &x, &y, 1, 1, 0); + map->search_freecell(bl, m, &x, &y, 1, 1, 0); // if none found, pick random position on map - if (x <= 0 || y <= 0 || iMap->getcell(m,x,y,CELL_CHKNOREACH)) - iMap->search_freecell(NULL, m, &x, &y, -1, -1, 1); + if (x <= 0 || x >= map->list[m].xs || y <= 0 || y >= map->list[m].ys) + map->search_freecell(NULL, m, &x, &y, -1, -1, 1); data.x = x; data.y = y; - if (!mob_parse_dataset(&data)) + if (!mob->parse_dataset(&data)) return NULL; - return mob_spawn_dataset(&data); + return mob->spawn_dataset(&data); } /*========================================== * Spawn a single mob on the specified coordinates. *------------------------------------------*/ -int mob_once_spawn(struct map_session_data* sd, int16 m, int16 x, int16 y, const char* mobname, int class_, int amount, const char* event, unsigned int size, unsigned int ai) -{ +int mob_once_spawn(struct map_session_data* sd, int16 m, int16 x, int16 y, const char* mobname, int class_, int amount, const char* event, unsigned int size, unsigned int ai) { struct mob_data* md = NULL; int count, lv; + bool no_guardian_data = false; + + if( ai && ai&0x200 ) { + no_guardian_data = true; + ai &=~ 0x200; + } if (m < 0 || amount <= 0) return 0; // invalid input lv = (sd) ? sd->status.base_level : 255; - for (count = 0; count < amount; count++) - { - int c = (class_ >= 0) ? class_ : mob_get_random_id(-class_ - 1, (battle_config.random_monster_checklv) ? 3 : 1, lv); - md = mob_once_spawn_sub((sd) ? &sd->bl : NULL, m, x, y, mobname, c, event, size, ai); + for (count = 0; count < amount; count++) { + int c = (class_ >= 0) ? class_ : mob->get_random_id(-class_ - 1, (battle_config.random_monster_checklv) ? 3 : 1, lv); + md = mob->once_spawn_sub((sd) ? &sd->bl : NULL, m, x, y, mobname, c, event, size, ai); if (!md) continue; - if (class_ == MOBID_EMPERIUM) - { - struct guild_castle* gc = guild->mapindex2gc(map[m].index); + if ( class_ == MOBID_EMPERIUM && !no_guardian_data ) { + struct guild_castle* gc = guild->mapindex2gc(map_id2index(m)); struct guild* g = (gc) ? guild->search(gc->guild_id) : NULL; - if (gc) - { + if( gc ) { md->guardian_data = (struct guardian_data*)aCalloc(1, sizeof(struct guardian_data)); md->guardian_data->castle = gc; md->guardian_data->number = MAX_GUARDIANS; - md->guardian_data->guild_id = gc->guild_id; - if (g) - { - md->guardian_data->emblem_id = g->emblem_id; - memcpy(md->guardian_data->guild_name, g->name, NAME_LENGTH); - } - else if (gc->guild_id) //Guild not yet available, retry in 5. - iTimer->add_timer(iTimer->gettick()+5000,mob_spawn_guardian_sub,md->bl.id,md->guardian_data->guild_id); + if( g ) + md->guardian_data->g = g; + else if( gc->guild_id ) //Guild not yet available, retry in 5. + timer->add(timer->gettick()+5000,mob->spawn_guardian_sub,md->bl.id,gc->guild_id); } } // end addition [Valaris] - mob_spawn(md); + mob->spawn(md); - if (class_ < 0 && battle_config.dead_branch_active) + if (class_ < 0 && battle_config.dead_branch_active) { //Behold Aegis's masterful decisions yet again... //"I understand the "Aggressive" part, but the "Can Move" and "Can Attack" is just stupid" - Poki#3 - sc_start4(&md->bl, SC_MODECHANGE, 100, 1, 0, MD_AGGRESSIVE|MD_CANATTACK|MD_CANMOVE|MD_ANGRY, 0, 60000); + sc_start4(NULL, &md->bl, SC_MODECHANGE, 100, 1, 0, MD_AGGRESSIVE|MD_CANATTACK|MD_CANMOVE|MD_ANGRY, 0, 60000); + } } return (md) ? md->bl.id : 0; // id of last spawned mob @@ -542,7 +546,7 @@ int mob_once_spawn_area(struct map_session_data* sd, int16 m, int16 x0, int16 y0 x = rnd()%(x1-x0+1)+x0; y = rnd()%(y1-y0+1)+y0; j++; - } while (iMap->getcell(m,x,y,CELL_CHKNOPASS) && j < max); + } while (map->getcell(m,x,y,CELL_CHKNOPASS) && j < max); if (j == max) {// attempt to find an available cell failed @@ -558,26 +562,28 @@ int mob_once_spawn_area(struct map_session_data* sd, int16 m, int16 x0, int16 y0 lx = x; ly = y; - id = mob_once_spawn(sd, m, x, y, mobname, class_, 1, event, size, ai); + id = mob->once_spawn(sd, m, x, y, mobname, class_, 1, event, size, ai); } return id; // id of last spawned mob } -/*========================================== - * Set a Guardian's guild data [Skotlex] - *------------------------------------------*/ -static int mob_spawn_guardian_sub(int tid, unsigned int tick, int id, intptr_t data) -{ //Needed because the guild_data may not be available at guardian spawn time. - struct block_list* bl = iMap->id2bl(id); + +/** + * Sets a guardian's guild data and liberates castle if couldn't retrieve guild data + * @param data (int)guild_id + * @retval Always 0 + * @author Skotlex + **/ +int mob_spawn_guardian_sub(int tid, int64 tick, int id, intptr_t data) { + //Needed because the guild data may not be available at guardian spawn time. + struct block_list* bl = map->id2bl(id); struct mob_data* md; struct guild* g; - int guardup_lv; - if (bl == NULL) //It is possible mob was already removed from map when the castle has no owner. [Skotlex] + if( bl == NULL ) //It is possible mob was already removed from map when the castle has no owner. [Skotlex] return 0; - if (bl->type != BL_MOB) - { + if( bl->type != BL_MOB ) { ShowError("mob_spawn_guardian_sub: Block error!\n"); return 0; } @@ -586,30 +592,28 @@ static int mob_spawn_guardian_sub(int tid, unsigned int tick, int id, intptr_t d nullpo_ret(md->guardian_data); g = guild->search((int)data); - if (g == NULL) - { //Liberate castle, if the guild is not found this is an error! [Skotlex] + if( g == NULL ) { //Liberate castle, if the guild is not found this is an error! [Skotlex] ShowError("mob_spawn_guardian_sub: Couldn't load guild %d!\n", (int)data); - if (md->class_ == MOBID_EMPERIUM) - { //Not sure this is the best way, but otherwise we'd be invoking this for ALL guardians spawned later on. - md->guardian_data->guild_id = 0; - if (md->guardian_data->castle->guild_id) //Free castle up. - { + //Not sure this is the best way, but otherwise we'd be invoking this for ALL guardians spawned later on. + if( md->class_ == MOBID_EMPERIUM && md->guardian_data ) { + md->guardian_data->g = NULL; + if( md->guardian_data->castle->guild_id ) {//Free castle up. ShowNotice("Clearing ownership of castle %d (%s)\n", md->guardian_data->castle->castle_id, md->guardian_data->castle->castle_name); guild->castledatasave(md->guardian_data->castle->castle_id, 1, 0); } } else { - if (md->guardian_data->number >= 0 && md->guardian_data->number < MAX_GUARDIANS && md->guardian_data->castle->guardian[md->guardian_data->number].visible) + if( md->guardian_data && md->guardian_data->number >= 0 && md->guardian_data->number < MAX_GUARDIANS + && md->guardian_data->castle->guardian[md->guardian_data->number].visible ) guild->castledatasave(md->guardian_data->castle->castle_id, 10+md->guardian_data->number,0); - unit_free(&md->bl,CLR_OUTSIGHT); //Remove guardian. + + unit->free(&md->bl,CLR_OUTSIGHT); // Remove guardian. } return 0; } - guardup_lv = guild->checkskill(g,GD_GUARDUP); - md->guardian_data->emblem_id = g->emblem_id; - memcpy(md->guardian_data->guild_name, g->name, NAME_LENGTH); - md->guardian_data->guardup_lv = guardup_lv; - if( guardup_lv ) - status_calc_mob(md, 0); //Give bonuses. + + if( guild->checkskill(g,GD_GUARDUP) ) + status_calc_mob(md, SCO_NONE); // Give bonuses. + return 0; } @@ -626,7 +630,7 @@ int mob_spawn_guardian(const char* mapname, short x, short y, const char* mobnam memset(&data, 0, sizeof(struct spawn_data)); data.num = 1; - m=iMap->mapname2mapid(mapname); + m=map->mapname2mapid(mapname); if(m<0) { @@ -636,60 +640,55 @@ int mob_spawn_guardian(const char* mapname, short x, short y, const char* mobnam data.m = m; data.num = 1; if(class_<=0) { - class_ = mob_get_random_id(-class_-1, 1, 99); + class_ = mob->get_random_id(-class_-1, 1, 99); if (!class_) return 0; } data.class_ = class_; - if( !has_index ) - { + if( !has_index ) { guardian = -1; - } - else if( guardian < 0 || guardian >= MAX_GUARDIANS ) - { - ShowError("mob_spawn_guardian: Invalid guardian index %d for guardian %d (castle map %s)\n", guardian, class_, map[m].name); + } else if( guardian < 0 || guardian >= MAX_GUARDIANS ) { + ShowError("mob_spawn_guardian: Invalid guardian index %d for guardian %d (castle map %s)\n", guardian, class_, map->list[m].name); return 0; } - if((x<=0 || y<=0) && !iMap->search_freecell(NULL, m, &x, &y, -1,-1, 1)) - { - ShowWarning("mob_spawn_guardian: Couldn't locate a spawn cell for guardian class %d (index %d) at castle map %s\n",class_, guardian, map[m].name); + if((x<=0 || y<=0) && !map->search_freecell(NULL, m, &x, &y, -1,-1, 1)) { + ShowWarning("mob_spawn_guardian: Couldn't locate a spawn cell for guardian class %d (index %d) at castle map %s\n",class_, guardian, map->list[m].name); return 0; } data.x = x; data.y = y; safestrncpy(data.name, mobname, sizeof(data.name)); safestrncpy(data.eventname, event, sizeof(data.eventname)); - if (!mob_parse_dataset(&data)) + if (!mob->parse_dataset(&data)) return 0; - gc=guild->mapname2gc(map[m].name); - if (gc == NULL) - { - ShowError("mob_spawn_guardian: No castle set at map %s\n", map[m].name); + gc=guild->mapname2gc(map->list[m].name); + if (gc == NULL) { + ShowError("mob_spawn_guardian: No castle set at map %s\n", map->list[m].name); return 0; } if (!gc->guild_id) - ShowWarning("mob_spawn_guardian: Spawning guardian %d on a castle with no guild (castle map %s)\n", class_, map[m].name); + ShowWarning("mob_spawn_guardian: Spawning guardian %d on a castle with no guild (castle map %s)\n", class_, map->list[m].name); else g = guild->search(gc->guild_id); if( has_index && gc->guardian[guardian].id ) { //Check if guardian already exists, refuse to spawn if so. - struct mob_data *md2 = (TBL_MOB*)iMap->id2bl(gc->guardian[guardian].id); - if (md2 && md2->bl.type == BL_MOB && - md2->guardian_data && md2->guardian_data->number == guardian) - { - ShowError("mob_spawn_guardian: Attempted to spawn guardian in position %d which already has a guardian (castle map %s)\n", guardian, map[m].name); + struct mob_data *md2 = (TBL_MOB*)map->id2bl(gc->guardian[guardian].id); + if (md2 && md2->bl.type == BL_MOB + && md2->guardian_data + && md2->guardian_data->number == guardian + ) { + ShowError("mob_spawn_guardian: Attempted to spawn guardian in position %d which already has a guardian (castle map %s)\n", guardian, map->list[m].name); return 0; } } - md = mob_spawn_dataset(&data); + md = mob->spawn_dataset(&data); md->guardian_data = (struct guardian_data*)aCalloc(1, sizeof(struct guardian_data)); md->guardian_data->number = guardian; - md->guardian_data->guild_id = gc->guild_id; md->guardian_data->castle = gc; if( has_index ) {// permanent guardian @@ -706,14 +705,11 @@ int mob_spawn_guardian(const char* mapname, short x, short y, const char* mobnam } gc->temp_guardians[i] = md->bl.id; } - if (g) - { - md->guardian_data->emblem_id = g->emblem_id; - memcpy (md->guardian_data->guild_name, g->name, NAME_LENGTH); - md->guardian_data->guardup_lv = guild->checkskill(g,GD_GUARDUP); - } else if (md->guardian_data->guild_id) - iTimer->add_timer(iTimer->gettick()+5000,mob_spawn_guardian_sub,md->bl.id,md->guardian_data->guild_id); - mob_spawn(md); + if( g ) + md->guardian_data->g = g; + else if( gc->guild_id ) + timer->add(timer->gettick()+5000,mob->spawn_guardian_sub,md->bl.id,gc->guild_id); + mob->spawn(md); return md->bl.id; } @@ -727,8 +723,7 @@ int mob_spawn_bg(const char* mapname, short x, short y, const char* mobname, int struct spawn_data data; int16 m; - if( (m = iMap->mapname2mapid(mapname)) < 0 ) - { + if( (m = map->mapname2mapid(mapname)) < 0 ) { ShowWarning("mob_spawn_bg: Map [%s] not found.\n", mapname); return 0; } @@ -738,14 +733,13 @@ int mob_spawn_bg(const char* mapname, short x, short y, const char* mobname, int data.num = 1; if( class_ <= 0 ) { - class_ = mob_get_random_id(-class_-1,1,99); + class_ = mob->get_random_id(-class_-1,1,99); if( !class_ ) return 0; } data.class_ = class_; - if( (x <= 0 || y <= 0) && !iMap->search_freecell(NULL, m, &x, &y, -1,-1, 1) ) - { - ShowWarning("mob_spawn_bg: Couldn't locate a spawn cell for guardian class %d (bg_id %d) at map %s\n",class_, bg_id, map[m].name); + if( (x <= 0 || y <= 0) && !map->search_freecell(NULL, m, &x, &y, -1,-1, 1) ) { + ShowWarning("mob_spawn_bg: Couldn't locate a spawn cell for guardian class %d (bg_id %d) at map %s\n",class_, bg_id, map->list[m].name); return 0; } @@ -753,11 +747,11 @@ int mob_spawn_bg(const char* mapname, short x, short y, const char* mobname, int data.y = y; safestrncpy(data.name, mobname, sizeof(data.name)); safestrncpy(data.eventname, event, sizeof(data.eventname)); - if( !mob_parse_dataset(&data) ) + if( !mob->parse_dataset(&data) ) return 0; - md = mob_spawn_dataset(&data); - mob_spawn(md); + md = mob->spawn_dataset(&data); + mob->spawn(md); md->bg_id = bg_id; // BG Team ID return md->bl.id; @@ -786,30 +780,29 @@ int mob_can_reach(struct mob_data *md,struct block_list *bl,int range, int state easy = 1; break; } - return unit_can_reach_bl(&md->bl, bl, range, easy, NULL, NULL); + return unit->can_reach_bl(&md->bl, bl, range, easy, NULL, NULL); } /*========================================== * Links nearby mobs (supportive mobs) *------------------------------------------*/ -int mob_linksearch(struct block_list *bl,va_list ap) -{ +int mob_linksearch(struct block_list *bl,va_list ap) { struct mob_data *md; int class_; struct block_list *target; - unsigned int tick; + int64 tick; nullpo_ret(bl); md=(struct mob_data *)bl; class_ = va_arg(ap, int); target = va_arg(ap, struct block_list *); - tick=va_arg(ap, unsigned int); + tick = va_arg(ap, int64); if (md->class_ == class_ && DIFF_TICK(md->last_linktime, tick) < MIN_MOBLINKTIME && !md->target_id) { md->last_linktime = tick; - if( mob_can_reach(md,target,md->db->range2, MSS_FOLLOW) ){ // Reachability judging + if( mob->can_reach(md,target,md->db->range2, MSS_FOLLOW) ){ // Reachability judging md->target_id = target->id; md->min_chase=md->db->range3; return 1; @@ -822,9 +815,8 @@ int mob_linksearch(struct block_list *bl,va_list ap) /*========================================== * mob spawn with delay (timer function) *------------------------------------------*/ -int mob_delayspawn(int tid, unsigned int tick, int id, intptr_t data) -{ - struct block_list* bl = iMap->id2bl(id); +int mob_delayspawn(int tid, int64 tick, int id, intptr_t data) { + struct block_list* bl = map->id2bl(id); struct mob_data* md = BL_CAST(BL_MOB, bl); if( md ) @@ -835,7 +827,7 @@ int mob_delayspawn(int tid, unsigned int tick, int id, intptr_t data) return 0; } md->spawn_timer = INVALID_TIMER; - mob_spawn(md); + mob->spawn(md); } return 0; } @@ -849,14 +841,14 @@ int mob_setdelayspawn(struct mob_data *md) struct mob_db *db; if (!md->spawn) //Doesn't has respawn data! - return unit_free(&md->bl,CLR_DEAD); + return unit->free(&md->bl,CLR_DEAD); spawntime = md->spawn->delay1; //Base respawn time if (md->spawn->delay2) //random variance spawntime+= rnd()%md->spawn->delay2; //Apply the spawn delay fix [Skotlex] - db = mob_db(md->spawn->class_); + db = mob->db(md->spawn->class_); mode = db->status.mode; if (mode & MD_BOSS) { //Bosses if (battle_config.boss_spawn_delay != 100) { @@ -876,20 +868,21 @@ int mob_setdelayspawn(struct mob_data *md) spawntime = 5000; if( md->spawn_timer != INVALID_TIMER ) - iTimer->delete_timer(md->spawn_timer, mob_delayspawn); - md->spawn_timer = iTimer->add_timer(iTimer->gettick()+spawntime, mob_delayspawn, md->bl.id, 0); + timer->delete(md->spawn_timer, mob->delayspawn); + md->spawn_timer = timer->add(timer->gettick()+spawntime, mob->delayspawn, md->bl.id, 0); return 0; } int mob_count_sub(struct block_list *bl, va_list ap) { - int mobid[10], i; - ARR_FIND(0, 10, i, (mobid[i] = va_arg(ap, int)) == 0); //fetch till 0 - if (mobid[0]) { //if there one let's check it otherwise go backward - TBL_MOB *md = BL_CAST(BL_MOB, bl); - ARR_FIND(0, 10, i, md->class_ == mobid[i]); - return (i < 10) ? 1 : 0; - } - return 1; //backward compatibility + int mobid[10] = { 0 }, i; + ARR_FIND(0, 10, i, (mobid[i] = va_arg(ap, int)) == 0); //fetch till 0 + if (mobid[0]) { //if there one let's check it otherwise go backward + TBL_MOB *md = BL_CAST(BL_MOB, bl); + nullpo_ret(md); + ARR_FIND(0, 10, i, md->class_ == mobid[i]); + return (i < 10) ? 1 : 0; + } + return 1; //backward compatibility } /*========================================== @@ -898,18 +891,16 @@ int mob_count_sub(struct block_list *bl, va_list ap) { int mob_spawn (struct mob_data *md) { int i=0; - unsigned int tick = iTimer->gettick(); - int c =0; + int64 tick = timer->gettick(); + int64 c = 0; md->last_thinktime = tick; if (md->bl.prev != NULL) - unit_remove_map(&md->bl,CLR_RESPAWN); - else - if (md->spawn && md->class_ != md->spawn->class_) - { + unit->remove_map(&md->bl,CLR_RESPAWN,ALC_MARK); + else if (md->spawn && md->class_ != md->spawn->class_) { md->class_ = md->spawn->class_; - status_set_viewdata(&md->bl, md->class_); - md->db = mob_db(md->class_); + status->set_viewdata(&md->bl, md->class_); + md->db = mob->db(md->class_); memcpy(md->name,md->spawn->name,NAME_LENGTH); } @@ -918,27 +909,26 @@ int mob_spawn (struct mob_data *md) md->bl.x = md->spawn->x; md->bl.y = md->spawn->y; - if( (md->bl.x == 0 && md->bl.y == 0) || md->spawn->xs || md->spawn->ys ) - { //Monster can be spawned on an area. - if( !iMap->search_freecell(&md->bl, -1, &md->bl.x, &md->bl.y, md->spawn->xs, md->spawn->ys, battle_config.no_spawn_on_player?4:0) ) - { // retry again later + if( (md->bl.x == 0 && md->bl.y == 0) || md->spawn->xs || md->spawn->ys ) { + //Monster can be spawned on an area. + if( !map->search_freecell(&md->bl, -1, &md->bl.x, &md->bl.y, md->spawn->xs, md->spawn->ys, battle_config.no_spawn_on_player?4:0) ) { + // retry again later if( md->spawn_timer != INVALID_TIMER ) - iTimer->delete_timer(md->spawn_timer, mob_delayspawn); - md->spawn_timer = iTimer->add_timer(tick+5000,mob_delayspawn,md->bl.id,0); + timer->delete(md->spawn_timer, mob->delayspawn); + md->spawn_timer = timer->add(tick+5000,mob->delayspawn,md->bl.id,0); return 1; } - } - else if( battle_config.no_spawn_on_player > 99 && iMap->foreachinrange(mob_count_sub, &md->bl, AREA_SIZE, BL_PC) ) - { // retry again later (players on sight) + } else if( battle_config.no_spawn_on_player > 99 && map->foreachinrange(mob->count_sub, &md->bl, AREA_SIZE, BL_PC) ) { + // retry again later (players on sight) if( md->spawn_timer != INVALID_TIMER ) - iTimer->delete_timer(md->spawn_timer, mob_delayspawn); - md->spawn_timer = iTimer->add_timer(tick+5000,mob_delayspawn,md->bl.id,0); + timer->delete(md->spawn_timer, mob->delayspawn); + md->spawn_timer = timer->add(tick+5000,mob->delayspawn,md->bl.id,0); return 1; } } memset(&md->state, 0, sizeof(md->state)); - status_calc_mob(md, 1); + status_calc_mob(md, SCO_FIRST); md->attacked_id = 0; md->target_id = 0; md->move_fail_count = 0; @@ -946,7 +936,7 @@ int mob_spawn (struct mob_data *md) md->ud.target_to = 0; if( md->spawn_timer != INVALID_TIMER ) { - iTimer->delete_timer(md->spawn_timer, mob_delayspawn); + timer->delete(md->spawn_timer, mob->delayspawn); md->spawn_timer = INVALID_TIMER; } @@ -977,20 +967,20 @@ int mob_spawn (struct mob_data *md) // MvP tomb [GreenBox] if ( md->tomb_nid ) - mvptomb_destroy(md); + mob->mvptomb_destroy(md); - iMap->addblock(&md->bl); - if( map[md->bl.m].users ) + map->addblock(&md->bl); + if( map->list[md->bl.m].users ) clif->spawn(&md->bl); skill->unit_move(&md->bl,tick,1); - mobskill_use(md, tick, MSC_SPAWN); + mob->skill_use(md, tick, MSC_SPAWN); return 0; } /*========================================== * Determines if the mob can change target. [Skotlex] *------------------------------------------*/ -static int mob_can_changetarget(struct mob_data* md, struct block_list* target, int mode) +int mob_can_changetarget(struct mob_data* md, struct block_list* target, int mode) { // if the monster was provoked ignore the above rule [celest] if(md->state.provoke_flag) @@ -1028,10 +1018,10 @@ int mob_target(struct mob_data *md,struct block_list *bl,int dist) nullpo_ret(bl); // Nothing will be carried out if there is no mind of changing TAGE by TAGE ending. - if(md->target_id && !mob_can_changetarget(md, bl, status_get_mode(&md->bl))) + if(md->target_id && !mob->can_changetarget(md, bl, status_get_mode(&md->bl))) return 0; - if(!status_check_skilluse(&md->bl, bl, 0, 0)) + if(!status->check_skilluse(&md->bl, bl, 0, 0)) return 0; md->target_id = bl->id; // Since there was no disturbance, it locks on to target. @@ -1046,7 +1036,7 @@ int mob_target(struct mob_data *md,struct block_list *bl,int dist) /*========================================== * The ?? routine of an active monster *------------------------------------------*/ -static int mob_ai_sub_hard_activesearch(struct block_list *bl,va_list ap) +int mob_ai_sub_hard_activesearch(struct block_list *bl,va_list ap) { struct mob_data *md; struct block_list **target; @@ -1059,48 +1049,47 @@ static int mob_ai_sub_hard_activesearch(struct block_list *bl,va_list ap) mode= va_arg(ap,int); //If can't seek yet, not an enemy, or you can't attack it, skip. - if ((*target) == bl || !status_check_skilluse(&md->bl, bl, 0, 0)) + if (md->bl.id == bl->id || (*target) == bl || !status->check_skilluse(&md->bl, bl, 0, 0)) return 0; - if ((mode&MD_TARGETWEAK) && status_get_lv(bl) >= md->level-5) + if ((mode&MD_TARGETWEAK) && status->get_lv(bl) >= md->level-5) return 0; if(battle->check_target(&md->bl,bl,BCT_ENEMY)<=0) return 0; - switch (bl->type) - { - case BL_PC: - if (((TBL_PC*)bl)->state.gangsterparadise && - !(status_get_mode(&md->bl)&MD_BOSS)) - return 0; //Gangster paradise protection. - default: - if (battle_config.hom_setting&0x4 && - (*target) && (*target)->type == BL_HOM && bl->type != BL_HOM) - return 0; //For some reason Homun targets are never overriden. + switch (bl->type) { + case BL_PC: + if (((TBL_PC*)bl)->state.gangsterparadise && + !(status_get_mode(&md->bl)&MD_BOSS)) + return 0; //Gangster paradise protection. + default: + if (battle_config.hom_setting&0x4 && + (*target) && (*target)->type == BL_HOM && bl->type != BL_HOM) + return 0; //For some reason Homun targets are never overridden. - dist = distance_bl(&md->bl, bl); - if( - ((*target) == NULL || !check_distance_bl(&md->bl, *target, dist)) && - battle->check_range(&md->bl,bl,md->db->range2) - ) { //Pick closest target? + dist = distance_bl(&md->bl, bl); + if( + ((*target) == NULL || !check_distance_bl(&md->bl, *target, dist)) && + battle->check_range(&md->bl,bl,md->db->range2) + ) { //Pick closest target? - if( map[bl->m].icewall_num && - !path_search_long(NULL,bl->m,md->bl.x,md->bl.y,bl->x,bl->y,CELL_CHKICEWALL) ) { + if( map->list[bl->m].icewall_num && + !path->search_long(NULL,bl->m,md->bl.x,md->bl.y,bl->x,bl->y,CELL_CHKICEWALL) ) { - if( !check_distance_bl(&md->bl, bl, status_get_range(&md->bl) ) ) - return 0; + if( !check_distance_bl(&md->bl, bl, status_get_range(&md->bl) ) ) + return 0; - } + } - (*target) = bl; - md->target_id=bl->id; - md->min_chase= dist + md->db->range3; - if(md->min_chase>MAX_MINCHASE) - md->min_chase=MAX_MINCHASE; - return 1; - } - break; + (*target) = bl; + md->target_id=bl->id; + md->min_chase= dist + md->db->range3; + if(md->min_chase>MAX_MINCHASE) + md->min_chase=MAX_MINCHASE; + return 1; + } + break; } return 0; } @@ -1108,8 +1097,7 @@ static int mob_ai_sub_hard_activesearch(struct block_list *bl,va_list ap) /*========================================== * chase target-change routine. *------------------------------------------*/ -static int mob_ai_sub_hard_changechase(struct block_list *bl,va_list ap) -{ +int mob_ai_sub_hard_changechase(struct block_list *bl,va_list ap) { struct mob_data *md; struct block_list **target; @@ -1118,9 +1106,10 @@ static int mob_ai_sub_hard_changechase(struct block_list *bl,va_list ap) target= va_arg(ap,struct block_list**); //If can't seek yet, not an enemy, or you can't attack it, skip. - if ((*target) == bl || - battle->check_target(&md->bl,bl,BCT_ENEMY)<=0 || - !status_check_skilluse(&md->bl, bl, 0, 0)) + if( md->bl.id == bl->id || *target == bl + || battle->check_target(&md->bl,bl,BCT_ENEMY) <= 0 + || !status->check_skilluse(&md->bl, bl, 0, 0) + ) return 0; if(battle->check_range (&md->bl, bl, md->status.rhw.range)) { @@ -1134,7 +1123,7 @@ static int mob_ai_sub_hard_changechase(struct block_list *bl,va_list ap) /*========================================== * finds nearby bg ally for guardians looking for users to follow. *------------------------------------------*/ -static int mob_ai_sub_hard_bg_ally(struct block_list *bl,va_list ap) { +int mob_ai_sub_hard_bg_ally(struct block_list *bl,va_list ap) { struct mob_data *md; struct block_list **target; @@ -1142,7 +1131,7 @@ static int mob_ai_sub_hard_bg_ally(struct block_list *bl,va_list ap) { md=va_arg(ap,struct mob_data *); target= va_arg(ap,struct block_list**); - if( status_check_skilluse(&md->bl, bl, 0, 0) && battle->check_target(&md->bl,bl,BCT_ENEMY)<=0 ) { + if( status->check_skilluse(&md->bl, bl, 0, 0) && battle->check_target(&md->bl,bl,BCT_ENEMY)<=0 ) { (*target) = bl; } return 1; @@ -1151,7 +1140,7 @@ static int mob_ai_sub_hard_bg_ally(struct block_list *bl,va_list ap) { /*========================================== * loot monster item search *------------------------------------------*/ -static int mob_ai_sub_hard_lootsearch(struct block_list *bl,va_list ap) +int mob_ai_sub_hard_lootsearch(struct block_list *bl,va_list ap) { struct mob_data* md; struct block_list **target; @@ -1161,7 +1150,7 @@ static int mob_ai_sub_hard_lootsearch(struct block_list *bl,va_list ap) target= va_arg(ap,struct block_list**); dist=distance_bl(&md->bl, bl); - if(mob_can_reach(md,bl,dist+1, MSS_LOOT) && + if(mob->can_reach(md,bl,dist+1, MSS_LOOT) && ((*target) == NULL || !check_distance_bl(&md->bl, *target, dist)) //New target closer than previous one. ) { (*target) = bl; @@ -1171,7 +1160,7 @@ static int mob_ai_sub_hard_lootsearch(struct block_list *bl,va_list ap) return 0; } -static int mob_warpchase_sub(struct block_list *bl,va_list ap) { +int mob_warpchase_sub(struct block_list *bl,va_list ap) { struct block_list *target; struct npc_data **target_nd; struct npc_data *nd; @@ -1187,12 +1176,12 @@ static int mob_warpchase_sub(struct block_list *bl,va_list ap) { if(nd->subtype != WARP) return 0; //Not a warp - if(nd->u.warp.mapindex != map[target->m].index) + if(nd->u.warp.mapindex != map_id2index(target->m)) return 0; //Does not lead to the same map. cur_distance = distance_blxy(target, nd->u.warp.x, nd->u.warp.y); - if (cur_distance < *min_distance) - { //Pick warp that leads closest to target. + if (cur_distance < *min_distance) { + //Pick warp that leads closest to target. *target_nd = nd; *min_distance = cur_distance; return 1; @@ -1202,13 +1191,12 @@ static int mob_warpchase_sub(struct block_list *bl,va_list ap) { /*========================================== * Processing of slave monsters *------------------------------------------*/ -static int mob_ai_sub_hard_slavemob(struct mob_data *md,unsigned int tick) -{ +int mob_ai_sub_hard_slavemob(struct mob_data *md, int64 tick) { struct block_list *bl; - bl=iMap->id2bl(md->master_id); + bl=map->id2bl(md->master_id); - if (!bl || status_isdead(bl)) { + if (!bl || status->isdead(bl)) { status_kill(&md->bl); return 1; } @@ -1229,7 +1217,7 @@ static int mob_ai_sub_hard_slavemob(struct mob_data *md,unsigned int tick) md->master_dist > MAX_MINCHASE ){ md->master_dist = 0; - unit_warp(&md->bl,bl->m,bl->x,bl->y,CLR_TELEPORT); + unit->warp(&md->bl,bl->m,bl->x,bl->y,CLR_TELEPORT); return 1; } @@ -1237,13 +1225,13 @@ static int mob_ai_sub_hard_slavemob(struct mob_data *md,unsigned int tick) return 0; // Approach master if within view range, chase back to Master's area also if standing on top of the master. - if((md->master_dist>MOB_SLAVEDISTANCE || md->master_dist == 0) && - unit_can_move(&md->bl)) - { + if( (md->master_dist>MOB_SLAVEDISTANCE || md->master_dist == 0) + && unit->can_move(&md->bl) + ) { short x = bl->x, y = bl->y; mob_stop_attack(md); - if(iMap->search_freecell(&md->bl, bl->m, &x, &y, MOB_SLAVEDISTANCE, MOB_SLAVEDISTANCE, 1) - && unit_walktoxy(&md->bl, x, y, 0)) + if(map->search_freecell(&md->bl, bl->m, &x, &y, MOB_SLAVEDISTANCE, MOB_SLAVEDISTANCE, 1) + && unit->walktoxy(&md->bl, x, y, 0)) return 1; } } else if (bl->m != md->bl.m && map_flag_gvg(md->bl.m)) { @@ -1255,20 +1243,20 @@ static int mob_ai_sub_hard_slavemob(struct mob_data *md,unsigned int tick) //Avoid attempting to lock the master's target too often to avoid unnecessary overload. [Skotlex] if (DIFF_TICK(md->last_linktime, tick) < MIN_MOBLINKTIME && !md->target_id) { - struct unit_data *ud = unit_bl2ud(bl); + struct unit_data *ud = unit->bl2ud(bl); md->last_linktime = tick; if (ud) { struct block_list *tbl=NULL; if (ud->target && ud->state.attack_continue) - tbl=iMap->id2bl(ud->target); + tbl=map->id2bl(ud->target); else if (ud->skilltarget) { - tbl = iMap->id2bl(ud->skilltarget); + tbl = map->id2bl(ud->skilltarget); //Required check as skilltarget is not always an enemy. [Skotlex] if (tbl && battle->check_target(&md->bl, tbl, BCT_ENEMY) <= 0) tbl = NULL; } - if (tbl && status_check_skilluse(&md->bl, tbl, 0, 0)) { + if (tbl && status->check_skilluse(&md->bl, tbl, 0, 0)) { md->target_id=tbl->id; md->min_chase=md->db->range3+distance_bl(&md->bl, tbl); if(md->min_chase>MAX_MINCHASE) @@ -1286,8 +1274,7 @@ static int mob_ai_sub_hard_slavemob(struct mob_data *md,unsigned int tick) * when trying to pick new targets when the current chosen target is * unreachable. *------------------------------------------*/ -int mob_unlocktarget(struct mob_data *md, unsigned int tick) -{ +int mob_unlocktarget(struct mob_data *md, int64 tick) { nullpo_ret(md); switch (md->state.skillstate) { @@ -1299,12 +1286,12 @@ int mob_unlocktarget(struct mob_data *md, unsigned int tick) case MSS_IDLE: // Idle skill. if ((md->target_id || !(++md->ud.walk_count%IDLE_SKILL_INTERVAL)) && - mobskill_use(md, tick, -1)) + mob->skill_use(md, tick, -1)) break; //Random walk. if (!md->master_id && DIFF_TICK(md->next_walktime, tick) <= 0 && - !mob_randomwalk(md,tick)) + !mob->randomwalk(md,tick)) //Delay next random walk when this one failed. md->next_walktime=tick+rnd()%3000; break; @@ -1319,15 +1306,14 @@ int mob_unlocktarget(struct mob_data *md, unsigned int tick) if (md->target_id) { md->target_id=0; md->ud.target_to = 0; - unit_set_target(&md->ud, 0); + unit->set_target(&md->ud, 0); } return 0; } /*========================================== * Random walk *------------------------------------------*/ -int mob_randomwalk(struct mob_data *md,unsigned int tick) -{ +int mob_randomwalk(struct mob_data *md, int64 tick) { const int retrycount=20; int i,x,y,c,d; int speed; @@ -1335,7 +1321,7 @@ int mob_randomwalk(struct mob_data *md,unsigned int tick) nullpo_ret(md); if(DIFF_TICK(md->next_walktime,tick)>0 || - !unit_can_move(&md->bl) || + !unit->can_move(&md->bl) || !(status_get_mode(&md->bl)&MD_CANMOVE)) return 0; @@ -1348,23 +1334,24 @@ int mob_randomwalk(struct mob_data *md,unsigned int tick) x+=md->bl.x; y+=md->bl.y; - if((iMap->getcell(md->bl.m,x,y,CELL_CHKPASS)) && unit_walktoxy(&md->bl,x,y,1)){ + if((map->getcell(md->bl.m,x,y,CELL_CHKPASS)) && unit->walktoxy(&md->bl,x,y,1)){ break; } } if(i==retrycount){ md->move_fail_count++; if(md->move_fail_count>1000){ - ShowWarning("MOB can't move. random spawn %d, class = %d, at %s (%d,%d)\n",md->bl.id,md->class_,map[md->bl.m].name, md->bl.x, md->bl.y); + ShowWarning("MOB can't move. random spawn %d, class = %d, at %s (%d,%d)\n",md->bl.id,md->class_,map->list[md->bl.m].name, md->bl.x, md->bl.y); md->move_fail_count=0; - mob_spawn(md); + mob->spawn(md); } return 0; } - speed=status_get_speed(&md->bl); - for(i=c=0;i<md->ud.walkpath.path_len;i++){ // The next walk start time is calculated. + speed=status->get_speed(&md->bl); + for(i=c=0;i<md->ud.walkpath.path_len;i++) { + // The next walk start time is calculated. if(md->ud.walkpath.path[i]&1) - c+=speed*14/10; + c+=speed*MOVE_DIAGONAL_COST/MOVE_COST; else c+=speed; } @@ -1385,14 +1372,14 @@ int mob_warpchase(struct mob_data *md, struct block_list *target) return 0; //No need to do a warp chase. if (md->ud.walktimer != INVALID_TIMER && - iMap->getcell(md->bl.m,md->ud.to_x,md->ud.to_y,CELL_CHKNPC)) + map->getcell(md->bl.m,md->ud.to_x,md->ud.to_y,CELL_CHKNPC)) return 1; //Already walking to a warp. //Search for warps within mob's viewing range. - iMap->foreachinrange (mob_warpchase_sub, &md->bl, - md->db->range2, BL_NPC, target, &warp, &distance); + map->foreachinrange(mob->warpchase_sub, &md->bl, + md->db->range2, BL_NPC, target, &warp, &distance); - if (warp && unit_walktobl(&md->bl, &warp->bl, 1, 1)) + if (warp && unit->walktobl(&md->bl, &warp->bl, 1, 1)) return 1; return 0; } @@ -1400,8 +1387,7 @@ int mob_warpchase(struct mob_data *md, struct block_list *target) /*========================================== * AI of MOB whose is near a Player *------------------------------------------*/ -static bool mob_ai_sub_hard(struct mob_data *md, unsigned int tick) -{ +bool mob_ai_sub_hard(struct mob_data *md, int64 tick) { struct block_list *tbl = NULL, *abl = NULL; int mode; int view_range, can_move; @@ -1422,7 +1408,8 @@ static bool mob_ai_sub_hard(struct mob_data *md, unsigned int tick) // Abnormalities if(( md->sc.opt1 > 0 && md->sc.opt1 != OPT1_STONEWAIT && md->sc.opt1 != OPT1_BURNING && md->sc.opt1 != OPT1_CRYSTALIZE ) - || md->sc.data[SC_BLADESTOP] || md->sc.data[SC__MANHOLE] || md->sc.data[SC_CURSEDCIRCLE_TARGET]) {//Should reset targets. + || md->sc.data[SC_DEEP_SLEEP] || md->sc.data[SC_BLADESTOP] || md->sc.data[SC__MANHOLE] || md->sc.data[SC_CURSEDCIRCLE_TARGET]) { + //Should reset targets. md->target_id = md->attacked_id = 0; return false; } @@ -1433,22 +1420,23 @@ static bool mob_ai_sub_hard(struct mob_data *md, unsigned int tick) view_range = md->db->range2; mode = status_get_mode(&md->bl); - can_move = (mode&MD_CANMOVE)&&unit_can_move(&md->bl); - - if (md->target_id) - { //Check validity of current target. [Skotlex] - tbl = iMap->id2bl(md->target_id); - if (!tbl || tbl->m != md->bl.m || - (md->ud.attacktimer == INVALID_TIMER && !status_check_skilluse(&md->bl, tbl, 0, 0)) || - (md->ud.walktimer != INVALID_TIMER && !(battle_config.mob_ai&0x1) && !check_distance_bl(&md->bl, tbl, md->min_chase)) || - ( - tbl->type == BL_PC && - ((((TBL_PC*)tbl)->state.gangsterparadise && !(mode&MD_BOSS)) || - ((TBL_PC*)tbl)->invincible_timer != INVALID_TIMER) - )) { //Unlock current target. - if (mob_warpchase(md, tbl)) + can_move = (mode&MD_CANMOVE)&&unit->can_move(&md->bl); + + if (md->target_id) { + //Check validity of current target. [Skotlex] + tbl = map->id2bl(md->target_id); + if (!tbl || tbl->m != md->bl.m + || (md->ud.attacktimer == INVALID_TIMER && !status->check_skilluse(&md->bl, tbl, 0, 0)) + || (md->ud.walktimer != INVALID_TIMER && !(battle_config.mob_ai&0x1) && !check_distance_bl(&md->bl, tbl, md->min_chase)) + || ( tbl->type == BL_PC + && ((((TBL_PC*)tbl)->state.gangsterparadise && !(mode&MD_BOSS)) + || ((TBL_PC*)tbl)->invincible_timer != INVALID_TIMER) + ) + ) { + //Unlock current target. + if (mob->warpchase(md, tbl)) return true; //Chasing this target. - mob_unlocktarget(md, tick-(battle_config.mob_ai&0x8?3000:0)); //Imediately do random walk. + mob->unlocktarget(md, tick-(battle_config.mob_ai&0x8?3000:0)); //Immediately do random walk. tbl = NULL; } } @@ -1463,36 +1451,36 @@ static bool mob_ai_sub_hard(struct mob_data *md, unsigned int tick) (!can_move && DIFF_TICK(tick, md->ud.canmove_tick) > 0 && (battle_config.mob_ai&0x2 || (md->sc.data[SC_SPIDERWEB] && md->sc.data[SC_SPIDERWEB]->val1) || md->sc.data[SC_WUGBITE] || md->sc.data[SC_VACUUM_EXTREME] || md->sc.data[SC_THORNS_TRAP] || md->sc.data[SC__MANHOLE])) // Not yet confirmed if boss will teleport once it can't reach target. - || !mob_can_reach(md, tbl, md->min_chase, MSS_RUSH) + || !mob->can_reach(md, tbl, md->min_chase, MSS_RUSH) ) && md->state.attacked_count++ >= RUDE_ATTACKED_COUNT - && !mobskill_use(md, tick, MSC_RUDEATTACKED) // If can't rude Attack - && can_move && unit_escape(&md->bl, tbl, rnd()%10 +1)) // Attempt escape + && !mob->skill_use(md, tick, MSC_RUDEATTACKED) // If can't rude Attack + && can_move && unit->escape(&md->bl, tbl, rnd()%10 +1)) // Attempt escape { //Escaped md->attacked_id = 0; return true; } } else - if( (abl = iMap->id2bl(md->attacked_id)) && (!tbl || mob_can_changetarget(md, abl, mode)) ) - { + if( (abl = map->id2bl(md->attacked_id)) && (!tbl || mob->can_changetarget(md, abl, mode) || (md->sc.count && md->sc.data[SC__CHAOS]))) { int dist; if( md->bl.m != abl->m || abl->prev == NULL - || (dist = distance_bl(&md->bl, abl)) >= MAX_MINCHASE // Attacker longer than visual area - || battle->check_target(&md->bl, abl, BCT_ENEMY) <= 0 // Attacker is not enemy of mob - || (battle_config.mob_ai&0x2 && !status_check_skilluse(&md->bl, abl, 0, 0)) // Cannot normal attack back to Attacker - || (!battle->check_range(&md->bl, abl, md->status.rhw.range) // Not on Melee Range and ... - && ( // Reach check - (!can_move && DIFF_TICK(tick, md->ud.canmove_tick) > 0 && (battle_config.mob_ai&0x2 || (md->sc.data[SC_SPIDERWEB] && md->sc.data[SC_SPIDERWEB]->val1) - || md->sc.data[SC_WUGBITE] || md->sc.data[SC_VACUUM_EXTREME] || md->sc.data[SC_THORNS_TRAP] - || md->sc.data[SC__MANHOLE])) // Not yet confirmed if boss will teleport once it can't reach target. - || !mob_can_reach(md, abl, dist+md->db->range3, MSS_RUSH) - ) - ) ) - { // Rude attacked + || (dist = distance_bl(&md->bl, abl)) >= MAX_MINCHASE // Attacker longer than visual area + || battle->check_target(&md->bl, abl, BCT_ENEMY) <= 0 // Attacker is not enemy of mob + || (battle_config.mob_ai&0x2 && !status->check_skilluse(&md->bl, abl, 0, 0)) // Cannot normal attack back to Attacker + || (!battle->check_range(&md->bl, abl, md->status.rhw.range) // Not on Melee Range and ... + && ( // Reach check + (!can_move && DIFF_TICK(tick, md->ud.canmove_tick) > 0 && (battle_config.mob_ai&0x2 || (md->sc.data[SC_SPIDERWEB] && md->sc.data[SC_SPIDERWEB]->val1) + || md->sc.data[SC_WUGBITE] || md->sc.data[SC_VACUUM_EXTREME] || md->sc.data[SC_THORNS_TRAP] + || md->sc.data[SC__MANHOLE])) // Not yet confirmed if boss will teleport once it can't reach target. + || !mob->can_reach(md, abl, dist+md->db->range3, MSS_RUSH) + ) + ) + ) { + // Rude attacked if (md->state.attacked_count++ >= RUDE_ATTACKED_COUNT - && !mobskill_use(md, tick, MSC_RUDEATTACKED) && can_move - && !tbl && unit_escape(&md->bl, abl, rnd()%10 +1)) + && !mob->skill_use(md, tick, MSC_RUDEATTACKED) && can_move + && !tbl && unit->escape(&md->bl, abl, rnd()%10 +1)) { //Escaped. //TODO: Maybe it shouldn't attempt to run if it has another, valid target? md->attacked_id = 0; @@ -1500,12 +1488,10 @@ static bool mob_ai_sub_hard(struct mob_data *md, unsigned int tick) } } else - if (!(battle_config.mob_ai&0x2) && !status_check_skilluse(&md->bl, abl, 0, 0)) - { + if (!(battle_config.mob_ai&0x2) && !status->check_skilluse(&md->bl, abl, 0, 0)) { //Can't attack back, but didn't invoke a rude attacked skill... - } - else - { //Attackable + } else { + //Attackable if (!tbl || dist < md->status.rhw.range || !check_distance_bl(&md->bl, tbl, dist) || battle->get_target(tbl) != md->bl.id) { //Change if the new target is closer than the actual one @@ -1526,26 +1512,23 @@ static bool mob_ai_sub_hard(struct mob_data *md, unsigned int tick) } // Processing of slave monster - if (md->master_id > 0 && mob_ai_sub_hard_slavemob(md, tick)) + if (md->master_id > 0 && mob->ai_sub_hard_slavemob(md, tick)) return true; // Scan area for targets - if (!tbl && mode&MD_LOOTER && md->lootitem && DIFF_TICK(tick, md->ud.canact_tick) > 0 && - (md->lootitem_count < LOOTITEM_SIZE || battle_config.monster_loot_type != 1)) - { // Scan area for items to loot, avoid trying to loot if the mob is full and can't consume the items. - iMap->foreachinrange (mob_ai_sub_hard_lootsearch, &md->bl, view_range, BL_ITEM, md, &tbl); + if (!tbl && mode&MD_LOOTER && md->lootitem && DIFF_TICK(tick, md->ud.canact_tick) > 0 + && (md->lootitem_count < LOOTITEM_SIZE || battle_config.monster_loot_type != 1) + ) { + // Scan area for items to loot, avoid trying to loot if the mob is full and can't consume the items. + map->foreachinrange (mob->ai_sub_hard_lootsearch, &md->bl, view_range, BL_ITEM, md, &tbl); } - if ((!tbl && mode&MD_AGGRESSIVE) || md->state.skillstate == MSS_FOLLOW) - { - iMap->foreachinrange (mob_ai_sub_hard_activesearch, &md->bl, view_range, DEFAULT_ENEMY_TYPE(md), md, &tbl, mode); - } - else - if (mode&MD_CHANGECHASE && (md->state.skillstate == MSS_RUSH || md->state.skillstate == MSS_FOLLOW)) - { + if ((!tbl && mode&MD_AGGRESSIVE) || md->state.skillstate == MSS_FOLLOW) { + map->foreachinrange (mob->ai_sub_hard_activesearch, &md->bl, view_range, DEFAULT_ENEMY_TYPE(md), md, &tbl, mode); + } else if ((mode&MD_CHANGECHASE && (md->state.skillstate == MSS_RUSH || md->state.skillstate == MSS_FOLLOW)) || (md->sc.count && md->sc.data[SC__CHAOS])) { int search_size; search_size = view_range<md->status.rhw.range ? view_range:md->status.rhw.range; - iMap->foreachinrange (mob_ai_sub_hard_changechase, &md->bl, search_size, DEFAULT_ENEMY_TYPE(md), md, &tbl); + map->foreachinrange (mob->ai_sub_hard_changechase, &md->bl, search_size, DEFAULT_ENEMY_TYPE(md), md, &tbl); } if (!tbl) { //No targets available. @@ -1556,15 +1539,15 @@ static bool mob_ai_sub_hard(struct mob_data *md, unsigned int tick) if( md->bg_id && mode&MD_CANATTACK ) { if( md->ud.walktimer != INVALID_TIMER ) return true;/* we are already moving */ - iMap->foreachinrange (mob_ai_sub_hard_bg_ally, &md->bl, view_range, BL_PC, md, &tbl, mode); + map->foreachinrange (mob->ai_sub_hard_bg_ally, &md->bl, view_range, BL_PC, md, &tbl, mode); if( tbl ) { - if( distance_blxy(&md->bl, tbl->x, tbl->y) <= 3 || unit_walktobl(&md->bl, tbl, 1, 1) ) + if( distance_blxy(&md->bl, tbl->x, tbl->y) <= 3 || unit->walktobl(&md->bl, tbl, 1, 1) ) return true;/* we're moving or close enough don't unlock the target. */ } } //This handles triggering idle walk/skill. - mob_unlocktarget(md, tick); + mob->unlocktarget(md, tick); return true; } @@ -1576,21 +1559,21 @@ static bool mob_ai_sub_hard(struct mob_data *md, unsigned int tick) return true; //Already locked. if (md->lootitem == NULL) { //Can't loot... - mob_unlocktarget (md, tick); + mob->unlocktarget (md, tick); return true; } if (!check_distance_bl(&md->bl, tbl, 1)) { //Still not within loot range. if (!(mode&MD_CANMOVE)) { //A looter that can't move? Real smart. - mob_unlocktarget(md,tick); + mob->unlocktarget(md,tick); return true; } if (!can_move) //Stuck. Wait before walking. return true; md->state.skillstate = MSS_LOOT; - if (!unit_walktobl(&md->bl, tbl, 1, 1)) - mob_unlocktarget(md, tick); //Can't loot... + if (!unit->walktobl(&md->bl, tbl, 1, 1)) + mob->unlocktarget(md, tick); //Can't loot... return true; } //Within looting range. @@ -1605,7 +1588,7 @@ static bool mob_ai_sub_hard(struct mob_data *md, unsigned int tick) memcpy (&md->lootitem[md->lootitem_count++], &fitem->item_data, sizeof(md->lootitem[0])); } else { //Destroy first looted item... if (md->lootitem[0].card[0] == CARD0_PET) - intif_delete_petdata( MakeDWord(md->lootitem[0].card[1],md->lootitem[0].card[2]) ); + intif->delete_petdata( MakeDWord(md->lootitem[0].card[1],md->lootitem[0].card[2]) ); memmove(&md->lootitem[0], &md->lootitem[1], (LOOTITEM_SIZE-1)*sizeof(md->lootitem[0])); memcpy (&md->lootitem[LOOTITEM_SIZE-1], &fitem->item_data, sizeof(md->lootitem[0])); } @@ -1613,11 +1596,11 @@ static bool mob_ai_sub_hard(struct mob_data *md, unsigned int tick) { //Give them walk act/delay to properly mimic players. [Skotlex] clif->takeitem(&md->bl,tbl); md->ud.canact_tick = tick + md->status.amotion; - unit_set_walkdelay(&md->bl, tick, md->status.amotion, 1); + unit->set_walkdelay(&md->bl, tick, md->status.amotion, 1); } //Clear item. - iMap->clearflooritem (tbl); - mob_unlocktarget (md,tick); + map->clearflooritem (tbl); + mob->unlocktarget (md,tick); return true; } //Attempt to attack. @@ -1629,8 +1612,20 @@ static bool mob_ai_sub_hard(struct mob_data *md, unsigned int tick) { //Target within range, engage if(tbl->type == BL_PC) - mob_log_damage(md, tbl, 0); //Log interaction (counts as 'attacker' for the exp bonus) - unit_attack(&md->bl,tbl->id,1); + mob->log_damage(md, tbl, 0); //Log interaction (counts as 'attacker' for the exp bonus) + + if(!(mode&MD_RANDOMTARGET)) + unit->attack(&md->bl,tbl->id,1); + else { // Attack once and find new random target + int search_size = (view_range < md->status.rhw.range) ? view_range : md->status.rhw.range; + unit->attack(&md->bl,tbl->id,0); + tbl = battle->get_enemy(&md->bl, DEFAULT_ENEMY_TYPE(md), search_size); + // If no target was found, keep atacking the old one + if( tbl ) { + md->target_id = tbl->id; + md->min_chase = md->db->range3; + } + } return true; } @@ -1638,8 +1633,8 @@ static bool mob_ai_sub_hard(struct mob_data *md, unsigned int tick) if (!(mode&MD_CANMOVE)) { //Can't chase. Attempt an idle skill before unlocking. md->state.skillstate = MSS_IDLE; - if (!mobskill_use(md, tick, -1)) - mob_unlocktarget(md,tick); + if (!mob->skill_use(md, tick, -1)) + mob->unlocktarget(md,tick); return true; } @@ -1647,7 +1642,7 @@ static bool mob_ai_sub_hard(struct mob_data *md, unsigned int tick) { //Stuck. Attempt an idle skill md->state.skillstate = MSS_IDLE; if (!(++md->ud.walk_count%IDLE_SKILL_INTERVAL)) - mobskill_use(md, tick, -1); + mob->skill_use(md, tick, -1); return true; } @@ -1659,18 +1654,17 @@ static bool mob_ai_sub_hard(struct mob_data *md, unsigned int tick) return true; //Follow up if possible. - if(!mob_can_reach(md, tbl, md->min_chase, MSS_RUSH) || - !unit_walktobl(&md->bl, tbl, md->status.rhw.range, 2)) - mob_unlocktarget(md,tick); + if(!mob->can_reach(md, tbl, md->min_chase, MSS_RUSH) || + !unit->walktobl(&md->bl, tbl, md->status.rhw.range, 2)) + mob->unlocktarget(md,tick); return true; } -static int mob_ai_sub_hard_timer(struct block_list *bl,va_list ap) -{ +int mob_ai_sub_hard_timer(struct block_list *bl, va_list ap) { struct mob_data *md = (struct mob_data*)bl; - unsigned int tick = va_arg(ap, unsigned int); - if (mob_ai_sub_hard(md, tick)) + int64 tick = va_arg(ap, int64); + if (mob->ai_sub_hard(md, tick)) { //Hard AI triggered. if(!md->state.spotted) md->state.spotted = 1; @@ -1682,11 +1676,10 @@ static int mob_ai_sub_hard_timer(struct block_list *bl,va_list ap) /*========================================== * Serious processing for mob in PC field of view (foreachclient) *------------------------------------------*/ -static int mob_ai_sub_foreachclient(struct map_session_data *sd,va_list ap) -{ - unsigned int tick; - tick=va_arg(ap,unsigned int); - iMap->foreachinrange(mob_ai_sub_hard_timer,&sd->bl, AREA_SIZE+ACTIVE_AI_RANGE, BL_MOB,tick); +int mob_ai_sub_foreachclient(struct map_session_data *sd, va_list ap) { + int64 tick; + tick=va_arg(ap, int64); + map->foreachinrange(mob->ai_sub_hard_timer,&sd->bl, AREA_SIZE+ACTIVE_AI_RANGE, BL_MOB,tick); return 0; } @@ -1694,19 +1687,18 @@ static int mob_ai_sub_foreachclient(struct map_session_data *sd,va_list ap) /*========================================== * Negligent mode MOB AI (PC is not in near) *------------------------------------------*/ -static int mob_ai_sub_lazy(struct mob_data *md, va_list args) -{ - unsigned int tick; +int mob_ai_sub_lazy(struct mob_data *md, va_list args) { + int64 tick; nullpo_ret(md); if(md->bl.prev == NULL) return 0; - tick = va_arg(args,unsigned int); + tick = va_arg(args, int64); - if (battle_config.mob_ai&0x20 && map[md->bl.m].users>0) - return (int)mob_ai_sub_hard(md, tick); + if (battle_config.mob_ai&0x20 && map->list[md->bl.m].users>0) + return (int)mob->ai_sub_hard(md, tick); if (md->bl.prev==NULL || md->status.hp == 0) return 1; @@ -1717,7 +1709,7 @@ static int mob_ai_sub_lazy(struct mob_data *md, va_list args) DIFF_TICK(tick,md->last_thinktime) > MIN_MOBTHINKTIME) { if (DIFF_TICK(tick,md->last_pcneartime) < battle_config.mob_active_time) - return (int)mob_ai_sub_hard(md, tick); + return (int)mob->ai_sub_hard(md, tick); md->last_pcneartime = 0; } @@ -1727,7 +1719,7 @@ static int mob_ai_sub_lazy(struct mob_data *md, va_list args) DIFF_TICK(tick,md->last_thinktime) > MIN_MOBTHINKTIME) { if (DIFF_TICK(tick,md->last_pcneartime) < battle_config.boss_active_time) - return (int)mob_ai_sub_hard(md, tick); + return (int)mob->ai_sub_hard(md, tick); md->last_pcneartime = 0; } @@ -1737,24 +1729,23 @@ static int mob_ai_sub_lazy(struct mob_data *md, va_list args) md->last_thinktime=tick; if (md->master_id) { - mob_ai_sub_hard_slavemob (md,tick); + mob->ai_sub_hard_slavemob(md,tick); return 0; } - if( DIFF_TICK(md->next_walktime,tick) < 0 && (status_get_mode(&md->bl)&MD_CANMOVE) && unit_can_move(&md->bl) ) - { - if( map[md->bl.m].users > 0 ) + if( DIFF_TICK(md->next_walktime,tick) < 0 && (status_get_mode(&md->bl)&MD_CANMOVE) && unit->can_move(&md->bl) ) { + if( map->list[md->bl.m].users > 0 ) { if( rnd()%1000 < MOB_LAZYMOVEPERC(md) ) - mob_randomwalk(md, tick); + mob->randomwalk(md, tick); else if( rnd()%1000 < MOB_LAZYSKILLPERC ) //Chance to do a mob's idle skill. - mobskill_use(md, tick, -1); + mob->skill_use(md, tick, -1); } else { if( rnd()%1000 < MOB_LAZYMOVEPERC(md) ) - mob_randomwalk(md, tick); + mob->randomwalk(md, tick); } } return 0; @@ -1763,22 +1754,20 @@ static int mob_ai_sub_lazy(struct mob_data *md, va_list args) /*========================================== * Negligent processing for mob outside PC field of view (interval timer function) *------------------------------------------*/ -static int mob_ai_lazy(int tid, unsigned int tick, int id, intptr_t data) -{ - iMap->map_foreachmob(mob_ai_sub_lazy,tick); +int mob_ai_lazy(int tid, int64 tick, int id, intptr_t data) { + map->foreachmob(mob->ai_sub_lazy,tick); return 0; } /*========================================== * Serious processing for mob in PC field of view (interval timer function) *------------------------------------------*/ -static int mob_ai_hard(int tid, unsigned int tick, int id, intptr_t data) -{ +int mob_ai_hard(int tid, int64 tick, int id, intptr_t data) { if (battle_config.mob_ai&0x20) - iMap->map_foreachmob(mob_ai_sub_lazy,tick); + map->foreachmob(mob->ai_sub_lazy,tick); else - iMap->map_foreachpc(mob_ai_sub_foreachclient,tick); + map->foreachpc(mob->ai_sub_foreachclient,tick); return 0; } @@ -1786,12 +1775,11 @@ static int mob_ai_hard(int tid, unsigned int tick, int id, intptr_t data) /*========================================== * Initializes the delay drop structure for mob-dropped items. *------------------------------------------*/ -static struct item_drop* mob_setdropitem(int nameid, int qty, struct item_data *data) { +struct item_drop* mob_setdropitem(int nameid, int qty, struct item_data *data) { struct item_drop *drop = ers_alloc(item_drop_ers, struct item_drop); - memset(&drop->item_data, 0, sizeof(struct item)); drop->item_data.nameid = nameid; drop->item_data.amount = qty; - drop->item_data.identify = data ? itemdb_isidentified2(data) : itemdb_isidentified(nameid); + drop->item_data.identify = data ? itemdb->isidentified2(data) : itemdb->isidentified(nameid); drop->next = NULL; return drop; } @@ -1799,7 +1787,7 @@ static struct item_drop* mob_setdropitem(int nameid, int qty, struct item_data * /*========================================== * Initializes the delay drop structure for mob-looted items. *------------------------------------------*/ -static struct item_drop* mob_setlootitem(struct item* item) +struct item_drop* mob_setlootitem(struct item* item) { struct item_drop *drop = ers_alloc(item_drop_ers, struct item_drop); memcpy(&drop->item_data, item, sizeof(struct item)); @@ -1810,16 +1798,15 @@ static struct item_drop* mob_setlootitem(struct item* item) /*========================================== * item drop with delay (timer function) *------------------------------------------*/ -static int mob_delay_item_drop(int tid, unsigned int tick, int id, intptr_t data) -{ +int mob_delay_item_drop(int tid, int64 tick, int id, intptr_t data) { struct item_drop_list *list; struct item_drop *ditem, *ditem_prev; list=(struct item_drop_list *)data; ditem = list->item; while (ditem) { - iMap->addflooritem(&ditem->item_data,ditem->item_data.amount, - list->m,list->x,list->y, - list->first_charid,list->second_charid,list->third_charid,0); + map->addflooritem(&ditem->item_data,ditem->item_data.amount, + list->m,list->x,list->y, + list->first_charid,list->second_charid,list->third_charid,0); ditem_prev = ditem; ditem = ditem->next; ers_free(item_drop_ers, ditem_prev); @@ -1834,20 +1821,20 @@ static int mob_delay_item_drop(int tid, unsigned int tick, int id, intptr_t data * rate is the drop-rate of the item, required for autoloot. * flag : Killed only by homunculus? *------------------------------------------*/ -static void mob_item_drop(struct mob_data *md, struct item_drop_list *dlist, struct item_drop *ditem, int loot, int drop_rate, unsigned short flag) +void mob_item_drop(struct mob_data *md, struct item_drop_list *dlist, struct item_drop *ditem, int loot, int drop_rate, unsigned short flag) { TBL_PC* sd; //Logs items, dropped by mobs [Lupus] logs->pick_mob(md, loot?LOG_TYPE_LOOT:LOG_TYPE_PICKDROP_MONSTER, -ditem->item_data.amount, &ditem->item_data, NULL); - sd = iMap->charid2sd(dlist->first_charid); - if( sd == NULL ) sd = iMap->charid2sd(dlist->second_charid); - if( sd == NULL ) sd = iMap->charid2sd(dlist->third_charid); + sd = map->charid2sd(dlist->first_charid); + if( sd == NULL ) sd = map->charid2sd(dlist->second_charid); + if( sd == NULL ) sd = map->charid2sd(dlist->third_charid); if( sd && (drop_rate <= sd->state.autoloot || pc->isautolooting(sd, ditem->item_data.nameid)) - && (battle_config.idle_no_autoloot == 0 || DIFF_TICK(last_tick, sd->idletime) < battle_config.idle_no_autoloot) + && (battle_config.idle_no_autoloot == 0 || DIFF_TICK(sockt->last_tick, sd->idletime) < battle_config.idle_no_autoloot) && (battle_config.homunculus_autoloot?1:!flag) #ifdef AUTOLOOT_DISTANCE && sd->bl.m == md->bl.m @@ -1865,9 +1852,8 @@ static void mob_item_drop(struct mob_data *md, struct item_drop_list *dlist, str dlist->item = ditem; } -int mob_timer_delete(int tid, unsigned int tick, int id, intptr_t data) -{ - struct block_list* bl = iMap->id2bl(id); +int mob_timer_delete(int tid, int64 tick, int id, intptr_t data) { + struct block_list* bl = map->id2bl(id); struct mob_data* md = BL_CAST(BL_MOB, bl); if( md ) @@ -1879,7 +1865,7 @@ int mob_timer_delete(int tid, unsigned int tick, int id, intptr_t data) } //for Alchemist CANNIBALIZE [Lupus] md->deletetimer = INVALID_TIMER; - unit_free(bl, CLR_TELEPORT); + unit->free(bl, CLR_TELEPORT); } return 0; } @@ -1904,20 +1890,18 @@ int mob_deleteslave_sub(struct block_list *bl,va_list ap) /*========================================== * *------------------------------------------*/ -int mob_deleteslave(struct mob_data *md) -{ +int mob_deleteslave(struct mob_data *md) { nullpo_ret(md); - iMap->foreachinmap(mob_deleteslave_sub, md->bl.m, BL_MOB,md->bl.id); + map->foreachinmap(mob->deleteslave_sub, md->bl.m, BL_MOB,md->bl.id); return 0; } // Mob respawning through KAIZEL or NPC_REBIRTH [Skotlex] -int mob_respawn(int tid, unsigned int tick, int id, intptr_t data) -{ - struct block_list *bl = iMap->id2bl(id); +int mob_respawn(int tid, int64 tick, int id, intptr_t data) { + struct block_list *bl = map->id2bl(id); if(!bl) return 0; - status_revive(bl, (uint8)data, 0); + status->revive(bl, (uint8)data, 0); return 1; } @@ -1976,9 +1960,8 @@ void mob_log_damage(struct mob_data *md, struct block_list *src, int damage) case BL_MOB: { struct mob_data* md2 = (TBL_MOB*)src; - if( md2->special_state.ai && md2->master_id ) - { - struct map_session_data* msd = iMap->id2sd(md2->master_id); + if( md2->special_state.ai && md2->master_id ) { + struct map_session_data* msd = map->id2sd(md2->master_id); if( msd ) char_id = msd->status.char_id; } @@ -2053,8 +2036,8 @@ void mob_damage(struct mob_data *md, struct block_list *src, int damage) { } //Log damage if (src) - mob_log_damage(md, src, damage); - md->dmgtick = iTimer->gettick(); + mob->log_damage(md, src, damage); + md->dmgtick = timer->gettick(); } if (battle_config.show_mob_info&3) @@ -2068,7 +2051,7 @@ void mob_damage(struct mob_data *md, struct block_list *src, int damage) { int i; for(i = 0; i < DAMAGELOG_SIZE; i++){ // must show hp bar to all char who already hit the mob. if( md->dmglog[i].id ) { - struct map_session_data *sd = iMap->charid2sd(md->dmglog[i].id); + struct map_session_data *sd = map->charid2sd(md->dmglog[i].id); if( sd && check_distance_bl(&md->bl, &sd->bl, AREA_SIZE) ) // check if in range clif->monster_hp_bar(md,sd); } @@ -2078,7 +2061,7 @@ void mob_damage(struct mob_data *md, struct block_list *src, int damage) { if( md->special_state.ai == 2 ) {//LOne WOlf explained that ANYONE can trigger the marine countdown skill. [Skotlex] md->state.alchemist = 1; - mobskill_use(md, iTimer->gettick(), MSC_ALCHEMIST); + mob->skill_use(md, timer->gettick(), MSC_ALCHEMIST); } } @@ -2086,9 +2069,8 @@ void mob_damage(struct mob_data *md, struct block_list *src, int damage) { * Signals death of mob. * type&1 -> no drops, type&2 -> no exp *------------------------------------------*/ -int mob_dead(struct mob_data *md, struct block_list *src, int type) -{ - struct status_data *status; +int mob_dead(struct mob_data *md, struct block_list *src, int type) { + struct status_data *mstatus; struct map_session_data *sd = NULL, *tmpsd[DAMAGELOG_SIZE]; struct map_session_data *mvp_sd = NULL, *second_sd = NULL, *third_sd = NULL; @@ -2098,11 +2080,12 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type) unsigned int base_exp,job_exp; } pt[DAMAGELOG_SIZE]; int i, temp, count, m = md->bl.m, pnum = 0; - int dmgbltypes = 0; // bitfield of all bl types, that caused damage to the mob and are elligible for exp distribution - unsigned int mvp_damage, tick = iTimer->gettick(); + int dmgbltypes = 0; // bitfield of all bl types, that caused damage to the mob and are eligible for exp distribution + unsigned int mvp_damage; + int64 tick = timer->gettick(); bool rebirth, homkillonly; - status = &md->status; + mstatus = &md->status; if( src && src->type == BL_PC ) { @@ -2116,21 +2099,20 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type) if( src ) { // Use Dead skill only if not killed by Script or Command md->state.skillstate = MSS_DEAD; - mobskill_use(md,tick,-1); + mob->skill_use(md,tick,-1); } - iMap->freeblock_lock(); + map->freeblock_lock(); memset(pt,0,sizeof(pt)); if(src && src->type == BL_MOB) - mob_unlocktarget((struct mob_data *)src,tick); + mob->unlocktarget((struct mob_data *)src,tick); // filter out entries not eligible for exp distribution memset(tmpsd,0,sizeof(tmpsd)); - for(i = 0, count = 0, mvp_damage = 0; i < DAMAGELOG_SIZE && md->dmglog[i].id; i++) - { - struct map_session_data* tsd = iMap->charid2sd(md->dmglog[i].id); + for(i = 0, count = 0, mvp_damage = 0; i < DAMAGELOG_SIZE && md->dmglog[i].id; i++) { + struct map_session_data* tsd = map->charid2sd(md->dmglog[i].id); if(tsd == NULL) continue; // skip empty entries @@ -2175,21 +2157,21 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type) } } - if(!(type&2) && //No exp - (!map[m].flag.pvp || battle_config.pvp_exp) && //Pvp no exp rule [MouseJstr] - (!md->master_id || !md->special_state.ai) && //Only player-summoned mobs do not give exp. [Skotlex] - (!map[m].flag.nobaseexp || !map[m].flag.nojobexp) //Gives Exp + if( !(type&2) //No exp + && (!map->list[m].flag.pvp || battle_config.pvp_exp) //Pvp no exp rule [MouseJstr] + && (!md->master_id || !md->special_state.ai) //Only player-summoned mobs do not give exp. [Skotlex] + && (!map->list[m].flag.nobaseexp || !map->list[m].flag.nojobexp) //Gives Exp ) { //Experience calculation. int bonus = 100; //Bonus on top of your share (common to all attackers). if (md->sc.data[SC_RICHMANKIM]) bonus += md->sc.data[SC_RICHMANKIM]->val2; if(sd) { - temp = status_get_class(&md->bl); + temp = status->get_class(&md->bl); if(sd->sc.data[SC_MIRACLE]) i = 2; //All mobs are Star Targets else ARR_FIND(0, MAX_PC_FEELHATE, i, temp == sd->hate_mob[i] && - (battle_config.allow_skill_without_day || sg_info[i].day_func())); - if(i<MAX_PC_FEELHATE && (temp=pc->checkskill(sd,sg_info[i].bless_id))) + (battle_config.allow_skill_without_day || pc->sg_info[i].day_func())); + if(i<MAX_PC_FEELHATE && (temp=pc->checkskill(sd,pc->sg_info[i].bless_id))) bonus += (i==2?20:10)*temp; } if(battle_config.mobs_level_up && md->level > md->db->lv) // [Valaris] @@ -2207,7 +2189,7 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type) per = (double)md->dmglog[i].dmg/(double)md->tdmg; else { //eAthena's exp formula based on max hp. - per = (double)md->dmglog[i].dmg/(double)status->max_hp; + per = (double)md->dmglog[i].dmg/(double)mstatus->max_hp; if (per > 2) per = 2; // prevents unlimited exp gain } @@ -2221,7 +2203,7 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type) // change experience for different sized monsters [Valaris] if (battle_config.mob_size_influence) { switch( md->special_state.size ) { - case SZ_MEDIUM: + case SZ_SMALL: per /= 2.; break; case SZ_BIG: @@ -2240,15 +2222,15 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type) zeny*=rnd()%250; } - if (map[m].flag.nobaseexp || !md->db->base_exp) + if (map->list[m].flag.nobaseexp || !md->db->base_exp) base_exp = 0; else - base_exp = (unsigned int)cap_value(md->db->base_exp * per * bonus/100. * map[m].bexp/100., 1, UINT_MAX); + base_exp = (unsigned int)cap_value(md->db->base_exp * per * bonus/100. * map->list[m].bexp/100., 1, UINT_MAX); - if (map[m].flag.nojobexp || !md->db->job_exp || md->dmglog[i].flag == MDLF_HOMUN) //Homun earned job-exp is always lost. + if (map->list[m].flag.nojobexp || !md->db->job_exp || md->dmglog[i].flag == MDLF_HOMUN) //Homun earned job-exp is always lost. job_exp = 0; else - job_exp = (unsigned int)cap_value(md->db->job_exp * per * bonus/100. * map[m].jexp/100., 1, UINT_MAX); + job_exp = (unsigned int)cap_value(md->db->job_exp * per * bonus/100. * map->list[m].jexp/100., 1, UINT_MAX); if ( (temp = tmpsd[i]->status.party_id) > 0 ) { int j; @@ -2285,7 +2267,7 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type) 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(tmpsd[i], md, 1); + 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 @@ -2302,7 +2284,7 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type) } //End EXP giving. - if( !(type&1) && !map[m].flag.nomobloot && !md->state.rebirth && ( + if( !(type&1) && !map->list[m].flag.nomobloot && !md->state.rebirth && ( !md->special_state.ai || //Non special mob battle_config.alchemist_summon_reward == 2 || //All summoned give drops (md->special_state.ai==2 && battle_config.alchemist_summon_reward == 1) //Marine Sphere Drops items. @@ -2313,10 +2295,10 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type) struct item_data* it = NULL; int drop_rate; #ifdef RENEWAL_DROP - int drop_modifier = mvp_sd ? pc->level_penalty_mod(mvp_sd, md, 2) : - second_sd ? pc->level_penalty_mod(second_sd, md, 2): - third_sd ? pc->level_penalty_mod(third_sd, md, 2) : - 100;/* no player was attached, we dont use any modifier (100 = rates are not touched) */ + int drop_modifier = mvp_sd ? pc->level_penalty_mod( md->level - mvp_sd->status.base_level, md->status.race, md->status.mode, 2) : + second_sd ? pc->level_penalty_mod( md->level - second_sd->status.base_level, md->status.race, md->status.mode, 2): + third_sd ? pc->level_penalty_mod( md->level - third_sd->status.base_level, md->status.race, md->status.mode, 2) : + 100;/* no player was attached, we don't use any modifier (100 = rates are not touched) */ #endif dlist->m = md->bl.m; dlist->x = md->bl.x; @@ -2330,7 +2312,7 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type) { if (md->db->dropitem[i].nameid <= 0) continue; - if ( !(it = itemdb_exists(md->db->dropitem[i].nameid)) ) + if ( !(it = itemdb->exists(md->db->dropitem[i].nameid)) ) continue; drop_rate = md->db->dropitem[i].p; if (drop_rate <= 0) { @@ -2342,7 +2324,7 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type) // change drops depending on monsters size [Valaris] if (battle_config.mob_size_influence) { - if (md->special_state.size == SZ_MEDIUM && drop_rate >= 2) + if (md->special_state.size == SZ_SMALL && drop_rate >= 2) drop_rate /= 2; else if( md->special_state.size == SZ_BIG) drop_rate *= 2; @@ -2370,33 +2352,49 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type) drop_rate = 1; } #endif + if( sd && sd->status.mod_drop != 100 ) { + drop_rate = drop_rate * sd->status.mod_drop / 100; + if( drop_rate < 1 ) + drop_rate = 1; + } + // attempt to drop the item if (rnd() % 10000 >= drop_rate) continue; if( mvp_sd && it->type == IT_PETEGG ) { - pet_create_egg(mvp_sd, md->db->dropitem[i].nameid); + pet->create_egg(mvp_sd, md->db->dropitem[i].nameid); continue; } - ditem = mob_setdropitem(md->db->dropitem[i].nameid, 1, it); + ditem = mob->setdropitem(md->db->dropitem[i].nameid, 1, it); //A Rare Drop Global Announce by Lupus if( mvp_sd && drop_rate <= battle_config.rare_drop_announce ) { 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,0); + intif->broadcast(message, strlen(message)+1, BC_DEFAULT); } + + /* heres the thing we got the feature set up however we're still discussing how to best define the ids, + * so while we discuss, for a small period of time, the list is hardcoded (yes officially only those 2 use it, + * thus why we're unsure on how to best place the setting) */ + /* temp, will not be hardcoded for long thudu. */ + if( it->nameid == 7782 || it->nameid == 7783 ) /* for when not hardcoded: add a check on mvp bonus drop as well */ + clif->item_drop_announce(mvp_sd, it->nameid, md->name); + // Announce first, or else ditem will be freed. [Lance] // By popular demand, use base drop rate for autoloot code. [Skotlex] - mob_item_drop(md, dlist, ditem, 0, md->db->dropitem[i].p, homkillonly); + mob->item_drop(md, dlist, ditem, 0, md->db->dropitem[i].p, homkillonly); } // Ore Discovery [Celest] - if (sd == mvp_sd && pc->checkskill(sd,BS_FINDINGORE)>0 && battle_config.finding_ore_rate/10 >= rnd()%10000) { - ditem = mob_setdropitem(itemdb_searchrandomid(IG_FINDINGORE), 1, NULL); - mob_item_drop(md, dlist, ditem, 0, battle_config.finding_ore_rate/10, homkillonly); + if (sd == mvp_sd && pc->checkskill(sd,BS_FINDINGORE) > 0) { + if( (temp = itemdb->chain_item(itemdb->chain_cache[ECC_ORE],&i)) ) { + ditem = mob->setdropitem(temp, 1, NULL); + mob->item_drop(md, dlist, ditem, 0, i, homkillonly); + } } if(sd) { @@ -2406,8 +2404,8 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type) { if ( sd->add_drop[i].race == -md->class_ || ( sd->add_drop[i].race > 0 && ( - sd->add_drop[i].race & (1<<status->race) || - sd->add_drop[i].race & (1<<(status->mode&MD_BOSS?RC_BOSS:RC_NONBOSS)) + sd->add_drop[i].race & (1<<mstatus->race) || + sd->add_drop[i].race & (1<<(mstatus->mode&MD_BOSS?RC_BOSS:RC_NONBOSS)) ))) { //check if the bonus item drop rate should be multiplied with mob level/10 [Lupus] @@ -2424,8 +2422,9 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type) if (rnd()%10000 >= drop_rate) continue; - itemid = (sd->add_drop[i].id > 0) ? sd->add_drop[i].id : itemdb_searchrandomid(sd->add_drop[i].group); - mob_item_drop(md, dlist, mob_setdropitem(itemid,1,NULL), 0, drop_rate, homkillonly); + itemid = (sd->add_drop[i].id > 0) ? sd->add_drop[i].id : itemdb->chain_item(sd->add_drop[i].group,&drop_rate); + if( itemid ) + mob->item_drop(md, dlist, mob->setdropitem(itemid,1,NULL), 0, drop_rate, homkillonly); } } @@ -2440,10 +2439,10 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type) // process items looted by the mob if(md->lootitem) { for(i = 0; i < md->lootitem_count; i++) - mob_item_drop(md, dlist, mob_setlootitem(&md->lootitem[i]), 1, 10000, homkillonly); + mob->item_drop(md, dlist, mob->setlootitem(&md->lootitem[i]), 1, 10000, homkillonly); } if (dlist->item) //There are drop items. - iTimer->add_timer(tick + (!battle_config.delay_battle_damage?500:0), mob_delay_item_drop, 0, (intptr_t)dlist); + timer->add(tick + (!battle_config.delay_battle_damage?500:0), mob->delay_item_drop, 0, (intptr_t)dlist); else //No drops ers_free(item_drop_list_ers, dlist); } else if (md->lootitem && md->lootitem_count) { //Loot MUST drop! @@ -2456,18 +2455,17 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type) dlist->third_charid = (third_sd ? third_sd->status.char_id : 0); dlist->item = NULL; for(i = 0; i < md->lootitem_count; i++) - mob_item_drop(md, dlist, mob_setlootitem(&md->lootitem[i]), 1, 10000, homkillonly); - iTimer->add_timer(tick + (!battle_config.delay_battle_damage?500:0), mob_delay_item_drop, 0, (intptr_t)dlist); + mob->item_drop(md, dlist, mob->setlootitem(&md->lootitem[i]), 1, 10000, homkillonly); + timer->add(tick + (!battle_config.delay_battle_damage?500:0), mob->delay_item_drop, 0, (intptr_t)dlist); } if(mvp_sd && md->db->mexp > 0 && !md->special_state.ai) { int log_mvp[2] = {0}; unsigned int mexp; - struct item item; double exp; //mapflag: noexp check [Lorky] - if (map[m].flag.nobaseexp || type&2) + if (map->list[m].flag.nobaseexp || type&2) exp =1; else { exp = md->db->mexp; @@ -2482,10 +2480,11 @@ 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[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)); @@ -2504,7 +2503,7 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type) struct item_data *data; if(mdrop_id[i] <= 0) continue; - if(! (data = itemdb_exists(mdrop_id[i])) ) + if(! (data = itemdb->exists(mdrop_id[i])) ) continue; temp = mdrop_p[i]; @@ -2515,7 +2514,7 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type) memset(&item,0,sizeof(item)); item.nameid=mdrop_id[i]; - item.identify= itemdb_isidentified2(data); + item.identify= itemdb->isidentified2(data); clif->mvp_item(mvp_sd,item.nameid); log_mvp[0] = item.nameid; @@ -2524,12 +2523,12 @@ 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, data->jname, temp/100.); //MSG: "'%s' won %s's %s (chance: %0.02f%%)" - intif_broadcast(message,strlen(message)+1,0); + 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); - iMap->addflooritem(&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); + map->addflooritem(&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] @@ -2541,7 +2540,7 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type) logs->mvpdrop(mvp_sd, md->class_, log_mvp); } - if (type&2 && !sd && md->class_ == MOBID_EMPERIUM) + if (type&2 && !sd && md->class_ == MOBID_EMPERIUM && md->guardian_data) //Emperium destroyed by script. Discard mvp character. [Skotlex] mvp_sd = NULL; @@ -2559,58 +2558,58 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type) if( sd ) { if( sd->mission_mobid == md->class_) { //TK_MISSION [Skotlex] - if( ++sd->mission_count >= 100 && (temp = mob_get_random_id(0, 0xE, sd->status.base_level)) ) { + if( ++sd->mission_count >= 100 && (temp = mob->get_random_id(0, 0xE, sd->status.base_level)) ) { pc->addfame(sd, 1); sd->mission_mobid = temp; - pc_setglobalreg(sd,"TK_MISSION_ID", temp); + pc_setglobalreg(sd,script->add_str("TK_MISSION_ID"), temp); sd->mission_count = 0; clif->mission_info(sd, temp, 0); } - pc_setglobalreg(sd,"TK_MISSION_COUNT", sd->mission_count); + pc_setglobalreg(sd,script->add_str("TK_MISSION_COUNT"), sd->mission_count); } if( sd->status.party_id ) - iMap->foreachinrange(quest_update_objective_sub,&md->bl,AREA_SIZE,BL_PC,sd->status.party_id,md->class_); + map->foreachinrange(quest->update_objective_sub,&md->bl,AREA_SIZE,BL_PC,sd->status.party_id,md->class_); else if( sd->avail_quests ) - quest_update_objective(sd, md->class_); + quest->update_objective(sd, md->class_); - if( sd->md && src && src->type != BL_HOM && mob_db(md->class_)->lv > sd->status.base_level/2 ) - mercenary_kills(sd->md); + if( sd->md && src && src->type != BL_HOM && mob->db(md->class_)->lv > sd->status.base_level/2 ) + mercenary->kills(sd->md); } if( md->npc_event[0] && !md->state.npc_killmonster ) { if( sd && battle_config.mob_npc_event_type ) { pc->setparam(sd, SP_KILLERRID, sd->bl.id); - npc_event(sd,md->npc_event,0); + npc->event(sd,md->npc_event,0); } else if( mvp_sd ) { pc->setparam(mvp_sd, SP_KILLERRID, sd?sd->bl.id:0); - npc_event(mvp_sd,md->npc_event,0); + npc->event(mvp_sd,md->npc_event,0); } else - npc_event_do(md->npc_event); + npc->event_do(md->npc_event); } else if( mvp_sd && !md->state.npc_killmonster ) { pc->setparam(mvp_sd, SP_KILLEDRID, md->class_); - npc_script_event(mvp_sd, NPCE_KILLNPC); // PCKillNPC [Lance] + npc->script_event(mvp_sd, NPCE_KILLNPC); // PCKillNPC [Lance] } md->status.hp = 1; } if(md->deletetimer != INVALID_TIMER) { - iTimer->delete_timer(md->deletetimer,mob_timer_delete); + timer->delete(md->deletetimer,mob->timer_delete); md->deletetimer = INVALID_TIMER; } /** * Only loops if necessary (e.g. a poring would never need to loop) **/ if( md->can_summon ) - mob_deleteslave(md); + mob->deleteslave(md); - iMap->freeblock_unlock(); + map->freeblock_unlock(); if( !rebirth ) { if( pcdb_checkid(md->vd->class_) ) {//Player mobs are not removed automatically by the client. - /* first we set them dead, then we delay the outsight effect */ + /* first we set them dead, then we delay the out sight effect */ clif->clearunit_area(&md->bl,CLR_DEAD); clif->clearunit_delayed(&md->bl, CLR_OUTSIGHT,tick+3000); } else @@ -2622,23 +2621,23 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type) } - if(!md->spawn) //Tell status_damage to remove it from memory. + if(!md->spawn) //Tell status->damage to remove it from memory. return 5; // Note: Actually, it's 4. Oh well... // MvP tomb [GreenBox] - if (battle_config.mvp_tomb_enabled && md->spawn->state.boss) - mvptomb_create(md, mvp_sd ? mvp_sd->status.name : NULL, time(NULL)); + if (battle_config.mvp_tomb_enabled && md->spawn->state.boss && map->list[md->bl.m].flag.notomb != 1) + mob->mvptomb_create(md, mvp_sd ? mvp_sd->status.name : NULL, time(NULL)); if( !rebirth ) { - status_change_clear(&md->bl,1); - mob_setdelayspawn(md); //Set respawning. + status->change_clear(&md->bl,1); + mob->setdelayspawn(md); //Set respawning. } return 3; //Remove from map. } void mob_revive(struct mob_data *md, unsigned int hp) { - unsigned int tick = iTimer->gettick(); + int64 tick = timer->gettick(); md->state.skillstate = MSS_IDLE; md->last_thinktime = tick; md->next_walktime = tick+rnd()%50+5000; @@ -2647,10 +2646,10 @@ void mob_revive(struct mob_data *md, unsigned int hp) memset(md->dmglog, 0, sizeof(md->dmglog)); // Reset the damage done on the rebirthed monster, otherwise will grant full exp + damage done. [Valaris] md->tdmg = 0; if (!md->bl.prev) - iMap->addblock(&md->bl); + map->addblock(&md->bl); clif->spawn(&md->bl); skill->unit_move(&md->bl,tick,1); - mobskill_use(md, tick, MSC_SPAWN); + mob->skill_use(md, tick, MSC_SPAWN); if (battle_config.show_mob_info&3) clif->charnameack (0, &md->bl); } @@ -2663,35 +2662,29 @@ int mob_guardian_guildchange(struct mob_data *md) if (!md->guardian_data) return 0; - if (md->guardian_data->castle->guild_id == 0) + if( md->guardian_data->castle->guild_id == 0 ) { //Castle with no owner? Delete the guardians. - if (md->class_ == MOBID_EMPERIUM) - { //But don't delete the emperium, just clear it's guild-data - md->guardian_data->guild_id = 0; - md->guardian_data->emblem_id = 0; - md->guardian_data->guild_name[0] = '\0'; - } else { + if( md->class_ == MOBID_EMPERIUM ) //But don't delete the emperium, just clear it's guild-data + md->guardian_data->g = NULL; + else { if (md->guardian_data->number >= 0 && md->guardian_data->number < MAX_GUARDIANS && md->guardian_data->castle->guardian[md->guardian_data->number].visible) guild->castledatasave(md->guardian_data->castle->castle_id, 10+md->guardian_data->number, 0); - unit_free(&md->bl,CLR_OUTSIGHT); //Remove guardian. + unit->free(&md->bl,CLR_OUTSIGHT); //Remove guardian. } return 0; } g = guild->search(md->guardian_data->castle->guild_id); - if (g == NULL) + if( g == NULL ) { //Properly remove guardian info from Castle data. - ShowError("mob_guardian_guildchange: New Guild (id %d) does not exists!\n", md->guardian_data->guild_id); + ShowError("mob_guardian_guildchange: New Guild (id %d) does not exists!\n", md->guardian_data->castle->guild_id); if (md->guardian_data->number >= 0 && md->guardian_data->number < MAX_GUARDIANS) guild->castledatasave(md->guardian_data->castle->castle_id, 10+md->guardian_data->number, 0); - unit_free(&md->bl,CLR_OUTSIGHT); + unit->free(&md->bl,CLR_OUTSIGHT); return 0; } - md->guardian_data->guild_id = g->guild_id; - md->guardian_data->emblem_id = g->emblem_id; - md->guardian_data->guardup_lv = guild->checkskill(g,GD_GUARDUP); - memcpy(md->guardian_data->guild_name, g->name, NAME_LENGTH); + md->guardian_data->g = g; return 1; } @@ -2706,16 +2699,16 @@ int mob_random_class (int *value, size_t count) // no count specified, look into the array manually, but take only max 5 elements if (count < 1) { count = 0; - while(count < 5 && mobdb_checkid(value[count])) count++; + while(count < 5 && mob->db_checkid(value[count])) count++; if(count < 1) // nothing found return 0; } else { // check if at least the first value is valid - if(mobdb_checkid(value[0]) == 0) + if(mob->db_checkid(value[0]) == 0) return 0; } //Pick a random value, hoping it exists. [Skotlex] - return mobdb_checkid(value[rnd()%count]); + return mob->db_checkid(value[rnd()%count]); } /*========================================== @@ -2723,8 +2716,8 @@ int mob_random_class (int *value, size_t count) *------------------------------------------*/ int mob_class_change (struct mob_data *md, int class_) { - unsigned int tick = iTimer->gettick(); - int i, c, hp_rate; + int64 tick = timer->gettick(), c = 0; + int i, hp_rate; nullpo_ret(md); @@ -2741,7 +2734,7 @@ int mob_class_change (struct mob_data *md, int class_) if( md->special_state.ai > 1 ) return 0; //Marine Spheres and Floras. - if( mob_is_clone(md->class_) ) + if( mob->is_clone(md->class_) ) return 0; //Clones if( md->class_ == class_ ) @@ -2749,7 +2742,7 @@ int mob_class_change (struct mob_data *md, int class_) hp_rate = get_percentage(md->status.hp, md->status.max_hp); md->class_ = class_; - md->db = mob_db(class_); + md->db = mob->db(class_); if (battle_config.override_mob_names==1) memcpy(md->name,md->db->name,NAME_LENGTH); else @@ -2757,10 +2750,10 @@ int mob_class_change (struct mob_data *md, int class_) mob_stop_attack(md); mob_stop_walking(md, 0); - unit_skillcastcancel(&md->bl, 0); - status_set_viewdata(&md->bl, class_); + unit->skillcastcancel(&md->bl, 0); + status->set_viewdata(&md->bl, class_); clif->class_change(&md->bl, md->vd->class_, 1); - status_calc_mob(md, 1); + status_calc_mob(md, SCO_FIRST); md->ud.state.speed_changed = 1; //Speed change update. if (battle_config.monster_class_change_recover) { @@ -2793,13 +2786,25 @@ void mob_heal(struct mob_data *md,unsigned int heal) { if (battle_config.show_mob_info&3) clif->charnameack (0, &md->bl); + +#if PACKETVER >= 20120404 + if( !(md->status.mode&MD_BOSS) ){ + int i; + for(i = 0; i < DAMAGELOG_SIZE; i++){ // must show hp bar to all char who already hit the mob. + if( md->dmglog[i].id ) { + struct map_session_data *sd = map->charid2sd(md->dmglog[i].id); + if( sd && check_distance_bl(&md->bl, &sd->bl, AREA_SIZE) ) // check if in range + clif->monster_hp_bar(md,sd); + } + } + } +#endif } /*========================================== * Added by RoVeRT *------------------------------------------*/ -int mob_warpslave_sub(struct block_list *bl,va_list ap) -{ +int mob_warpslave_sub(struct block_list *bl,va_list ap) { struct mob_data *md=(struct mob_data *)bl; struct block_list *master; short x,y,range=0; @@ -2809,8 +2814,8 @@ int mob_warpslave_sub(struct block_list *bl,va_list ap) if(md->master_id!=master->id) return 0; - iMap->search_freecell(master, 0, &x, &y, range, range, 0); - unit_warp(&md->bl, master->m, x, y,CLR_RESPAWN); + map->search_freecell(master, 0, &x, &y, range, range, 0); + unit->warp(&md->bl, master->m, x, y,CLR_TELEPORT); return 1; } @@ -2819,16 +2824,15 @@ int mob_warpslave_sub(struct block_list *bl,va_list ap) * Warps slaves. Range is the area around the master that they can * appear in randomly. *------------------------------------------*/ -int mob_warpslave(struct block_list *bl, int range) -{ +int mob_warpslave(struct block_list *bl, int range) { if (range < 1) range = 1; //Min range needed to avoid crashes and stuff. [Skotlex] - return iMap->foreachinmap(mob_warpslave_sub, bl->m, BL_MOB, bl, range); + return map->foreachinmap(mob->warpslave_sub, bl->m, BL_MOB, bl, range); } /*========================================== - * Counts slave sub, curently checking if mob master is the given ID. + * Counts slave sub, currently checking if mob master is the given ID. *------------------------------------------*/ int mob_countslave_sub(struct block_list *bl,va_list ap) { @@ -2845,9 +2849,8 @@ int mob_countslave_sub(struct block_list *bl,va_list ap) /*========================================== * Counts the number of slaves a mob has on the map. *------------------------------------------*/ -int mob_countslave(struct block_list *bl) -{ - return iMap->foreachinmap(mob_countslave_sub, bl->m, BL_MOB,bl->id); +int mob_countslave(struct block_list *bl) { + return map->foreachinmap(mob->countslave_sub, bl->m, BL_MOB,bl->id); } /*========================================== @@ -2870,14 +2873,14 @@ int mob_summonslave(struct mob_data *md2,int *value,int amount,uint16 skill_id) data.state.size = md2->special_state.size; data.state.ai = md2->special_state.ai; - if(mobdb_checkid(value[0]) == 0) + if(mob->db_checkid(value[0]) == 0) return 0; /** * Flags this monster is able to summon; saves a worth amount of memory upon deletion **/ md2->can_summon = 1; - while(count < 5 && mobdb_checkid(value[count])) count++; + while(count < 5 && mob->db_checkid(value[count])) count++; if(count < 1) return 0; if (amount > 0 && amount < count) { //Do not start on 0, pick some random sub subset [Skotlex] k = rnd()%count; @@ -2891,10 +2894,10 @@ int mob_summonslave(struct mob_data *md2,int *value,int amount,uint16 skill_id) for(;k<amount;k++) { short x,y; data.class_ = value[k%count]; //Summon slaves in round-robin fashion. [Skotlex] - if (mobdb_checkid(data.class_) == 0) + if (mob->db_checkid(data.class_) == 0) continue; - if (iMap->search_freecell(&md2->bl, 0, &x, &y, MOB_SLAVEDISTANCE, MOB_SLAVEDISTANCE, 0)) { + if (map->search_freecell(&md2->bl, 0, &x, &y, MOB_SLAVEDISTANCE, MOB_SLAVEDISTANCE, 0)) { data.x = x; data.y = y; } else { @@ -2908,15 +2911,15 @@ int mob_summonslave(struct mob_data *md2,int *value,int amount,uint16 skill_id) else strcpy(data.name,"--ja--"); - if (!mob_parse_dataset(&data)) + if (!mob->parse_dataset(&data)) continue; - md= mob_spawn_dataset(&data); + md= mob->spawn_dataset(&data); if(skill_id == NPC_SUMMONSLAVE){ md->master_id=md2->bl.id; md->special_state.ai = md2->special_state.ai; } - mob_spawn(md); + mob->spawn(md); if (hp_rate) //Scale HP md->status.hp = md->status.max_hp*hp_rate/100; @@ -2927,17 +2930,17 @@ int mob_summonslave(struct mob_data *md2,int *value,int amount,uint16 skill_id) switch (battle_config.slaves_inherit_mode) { case 1: //Always aggressive if (!(md->status.mode&MD_AGGRESSIVE)) - sc_start4(&md->bl, SC_MODECHANGE, 100,1,0, MD_AGGRESSIVE, 0, 0); + sc_start4(NULL, &md->bl, SC_MODECHANGE, 100,1,0, MD_AGGRESSIVE, 0, 0); break; case 2: //Always passive if (md->status.mode&MD_AGGRESSIVE) - sc_start4(&md->bl, SC_MODECHANGE, 100,1,0, 0, MD_AGGRESSIVE, 0); + sc_start4(NULL, &md->bl, SC_MODECHANGE, 100,1,0, 0, MD_AGGRESSIVE, 0); break; default: //Copy master. if (md2->status.mode&MD_AGGRESSIVE) - sc_start4(&md->bl, SC_MODECHANGE, 100,1,0, MD_AGGRESSIVE, 0, 0); + sc_start4(NULL, &md->bl, SC_MODECHANGE, 100,1,0, MD_AGGRESSIVE, 0, 0); else - sc_start4(&md->bl, SC_MODECHANGE, 100,1,0, 0, MD_AGGRESSIVE, 0); + sc_start4(NULL, &md->bl, SC_MODECHANGE, 100,1,0, 0, MD_AGGRESSIVE, 0); break; } } @@ -2954,8 +2957,8 @@ int mob_summonslave(struct mob_data *md2,int *value,int amount,uint16 skill_id) *------------------------------------------*/ int mob_skill_id2skill_idx(int class_,uint16 skill_id) { - int i, max = mob_db(class_)->maxskill; - struct mob_skill *ms=mob_db(class_)->skill; + int i, max = mob->db(class_)->maxskill; + struct mob_skill *ms=mob->db(class_)->skill; if(ms==NULL) return -1; @@ -2993,8 +2996,7 @@ int mob_getfriendhprate_sub(struct block_list *bl,va_list ap) (*fr) = bl; return 1; } -static struct block_list *mob_getfriendhprate(struct mob_data *md,int min_rate,int max_rate) -{ +struct block_list *mob_getfriendhprate(struct mob_data *md,int min_rate,int max_rate) { struct block_list *fr=NULL; int type = BL_MOB; @@ -3003,17 +3005,15 @@ static struct block_list *mob_getfriendhprate(struct mob_data *md,int min_rate,i if (md->special_state.ai) //Summoned creatures. [Skotlex] type = BL_PC; - iMap->foreachinrange(mob_getfriendhprate_sub, &md->bl, 8, type,md,min_rate,max_rate,&fr); + map->foreachinrange(mob->getfriendhprate_sub, &md->bl, 8, type,md,min_rate,max_rate,&fr); return fr; } /*========================================== * Check hp rate of its master *------------------------------------------*/ -struct block_list *mob_getmasterhpltmaxrate(struct mob_data *md,int rate) -{ - if( md && md->master_id > 0 ) - { - struct block_list *bl = iMap->id2bl(md->master_id); +struct block_list *mob_getmasterhpltmaxrate(struct mob_data *md,int rate) { + if( md && md->master_id > 0 ) { + struct block_list *bl = map->id2bl(md->master_id); if( bl && get_percentage(status_get_hp(bl), status_get_max_hp(bl)) < rate ) return bl; } @@ -3055,25 +3055,24 @@ int mob_getfriendstatus_sub(struct block_list *bl,va_list ap) return 0; } -struct mob_data *mob_getfriendstatus(struct mob_data *md,int cond1,int cond2) -{ +struct mob_data *mob_getfriendstatus(struct mob_data *md,int cond1,int cond2) { struct mob_data* fr = NULL; nullpo_ret(md); - iMap->foreachinrange(mob_getfriendstatus_sub, &md->bl, 8,BL_MOB, md,cond1,cond2,&fr); + map->foreachinrange(mob->getfriendstatus_sub, &md->bl, 8,BL_MOB, md,cond1,cond2,&fr); return fr; } /*========================================== * Skill use judging *------------------------------------------*/ -int mobskill_use(struct mob_data *md, unsigned int tick, int event) -{ +int mobskill_use(struct mob_data *md, int64 tick, int event) { struct mob_skill *ms; struct block_list *fbl = NULL; //Friend bl, which can either be a BL_PC or BL_MOB depending on the situation. [Skotlex] struct block_list *bl; struct mob_data *fmd = NULL; int i,j,n; + short skill_target; nullpo_ret(md); nullpo_ret(ms = md->db->skill); @@ -3139,20 +3138,20 @@ int mobskill_use(struct mob_data *md, unsigned int tick, int event) } flag ^= (ms[i].cond1 == MSC_MYSTATUSOFF); break; case MSC_FRIENDHPLTMAXRATE: // friend HP < maxhp% - flag = ((fbl = mob_getfriendhprate(md, 0, ms[i].cond2)) != NULL); break; + flag = ((fbl = mob->getfriendhprate(md, 0, ms[i].cond2)) != NULL); break; case MSC_FRIENDHPINRATE : - flag = ((fbl = mob_getfriendhprate(md, ms[i].cond2, ms[i].val[0])) != NULL); break; + flag = ((fbl = mob->getfriendhprate(md, ms[i].cond2, ms[i].val[0])) != NULL); break; case MSC_FRIENDSTATUSON: // friend status[num] on case MSC_FRIENDSTATUSOFF: // friend status[num] off - flag = ((fmd = mob_getfriendstatus(md, ms[i].cond1, ms[i].cond2)) != NULL); break; + flag = ((fmd = mob->getfriendstatus(md, ms[i].cond1, ms[i].cond2)) != NULL); break; case MSC_SLAVELT: // slave < num - flag = (mob_countslave(&md->bl) < c2 ); break; + flag = (mob->countslave(&md->bl) < c2 ); break; case MSC_ATTACKPCGT: // attack pc > num - flag = (unit_counttargeted(&md->bl) > c2); break; + flag = (unit->counttargeted(&md->bl) > c2); break; case MSC_SLAVELE: // slave <= num - flag = (mob_countslave(&md->bl) <= c2 ); break; + flag = (mob->countslave(&md->bl) <= c2 ); break; case MSC_ATTACKPCGE: // attack pc >= num - flag = (unit_counttargeted(&md->bl) >= c2); break; + flag = (unit->counttargeted(&md->bl) >= c2); break; case MSC_AFTERSKILL: flag = (md->ud.skill_id == c2); break; case MSC_RUDEATTACKED: @@ -3160,9 +3159,9 @@ int mobskill_use(struct mob_data *md, unsigned int tick, int event) if (flag) md->state.attacked_count = 0; //Rude attacked count should be reset after the skill condition is met. Thanks to Komurka [Skotlex] break; case MSC_MASTERHPLTMAXRATE: - flag = ((fbl = mob_getmasterhpltmaxrate(md, ms[i].cond2)) != NULL); break; + flag = ((fbl = mob->getmasterhpltmaxrate(md, ms[i].cond2)) != NULL); break; case MSC_MASTERATTACKED: - flag = (md->master_id > 0 && (fbl=iMap->id2bl(md->master_id)) && unit_counttargeted(fbl) > 0); break; + flag = (md->master_id > 0 && (fbl=map->id2bl(md->master_id)) && unit->counttargeted(fbl) > 0); break; case MSC_ALCHEMIST: flag = (md->state.alchemist); break; @@ -3172,10 +3171,12 @@ int mobskill_use(struct mob_data *md, unsigned int tick, int event) if (!flag) continue; //Skill requisite failed to be fulfilled. + //Execute skill + skill_target = (md->db->status.mode&MD_RANDOMTARGET)? MST_RANDOM : ms[i].target; if (skill->get_casttype(ms[i].skill_id) == CAST_GROUND) {//Ground skill. short x, y; - switch (ms[i].target) { + switch (skill_target) { case MST_RANDOM: //Pick a random enemy within skill range. bl = battle->get_enemy(&md->bl, DEFAULT_ENEMY_TYPE(md), skill->get_range2(&md->bl, ms[i].skill_id, ms[i].skill_lv)); @@ -3185,12 +3186,12 @@ int mobskill_use(struct mob_data *md, unsigned int tick, int event) case MST_AROUND6: case MST_AROUND7: case MST_AROUND8: - bl = iMap->id2bl(md->target_id); + bl = map->id2bl(md->target_id); break; case MST_MASTER: bl = &md->bl; if (md->master_id) - bl = iMap->id2bl(md->master_id); + bl = map->id2bl(md->master_id); if (bl) //Otherwise, fall through. break; case MST_FRIEND: @@ -3205,34 +3206,34 @@ int mobskill_use(struct mob_data *md, unsigned int tick, int event) x = bl->x; y = bl->y; // Look for an area to cast the spell around... - if (ms[i].target >= MST_AROUND1 || ms[i].target >= MST_AROUND5) { - j = ms[i].target >= MST_AROUND1? - (ms[i].target-MST_AROUND1) +1: - (ms[i].target-MST_AROUND5) +1; - iMap->search_freecell(&md->bl, md->bl.m, &x, &y, j, j, 3); + if (skill_target >= MST_AROUND1 || skill_target >= MST_AROUND5) { + j = skill_target >= MST_AROUND1? + (skill_target-MST_AROUND1) +1: + (skill_target-MST_AROUND5) +1; + map->search_freecell(&md->bl, md->bl.m, &x, &y, j, j, 3); } md->skill_idx = i; - iMap->freeblock_lock(); - if( !battle->check_range(&md->bl,bl,skill->get_range2(&md->bl, ms[i].skill_id,ms[i].skill_lv)) || - !unit_skilluse_pos2(&md->bl, x, y,ms[i].skill_id, ms[i].skill_lv,ms[i].casttime, ms[i].cancel) ) - { - iMap->freeblock_unlock(); + map->freeblock_lock(); + if( !battle->check_range(&md->bl,bl,skill->get_range2(&md->bl, ms[i].skill_id,ms[i].skill_lv)) + || !unit->skilluse_pos2(&md->bl, x, y,ms[i].skill_id, ms[i].skill_lv,ms[i].casttime, ms[i].cancel) + ) { + map->freeblock_unlock(); continue; } } else { - //Targetted skill - switch (ms[i].target) { + //Targeted skill + switch (skill_target) { case MST_RANDOM: //Pick a random enemy within skill range. bl = battle->get_enemy(&md->bl, DEFAULT_ENEMY_TYPE(md), skill->get_range2(&md->bl, ms[i].skill_id, ms[i].skill_lv)); break; case MST_TARGET: - bl = iMap->id2bl(md->target_id); + bl = map->id2bl(md->target_id); break; case MST_MASTER: bl = &md->bl; if (md->master_id) - bl = iMap->id2bl(md->master_id); + bl = map->id2bl(md->master_id); if (bl) //Otherwise, fall through. break; case MST_FRIEND: @@ -3250,17 +3251,17 @@ int mobskill_use(struct mob_data *md, unsigned int tick, int event) if (!bl) continue; md->skill_idx = i; - iMap->freeblock_lock(); - if( !battle->check_range(&md->bl,bl,skill->get_range2(&md->bl, ms[i].skill_id,ms[i].skill_lv)) || - !unit_skilluse_id2(&md->bl, bl->id,ms[i].skill_id, ms[i].skill_lv,ms[i].casttime, ms[i].cancel) ) - { - iMap->freeblock_unlock(); + map->freeblock_lock(); + if( !battle->check_range(&md->bl,bl,skill->get_range2(&md->bl, ms[i].skill_id,ms[i].skill_lv)) + || !unit->skilluse_id2(&md->bl, bl->id,ms[i].skill_id, ms[i].skill_lv,ms[i].casttime, ms[i].cancel) + ) { + map->freeblock_unlock(); continue; } } //Skill used. Post-setups... if ( ms[ i ].msg_id ){ //Display color message [SnakeDrak] - struct mob_chat *mc = mob_chat(ms[i].msg_id); + struct mob_chat *mc = mob->chat(ms[i].msg_id); char temp[CHAT_SIZE_MAX]; char name[NAME_LENGTH]; snprintf(name, sizeof name,"%s", md->name); @@ -3274,7 +3275,7 @@ int mobskill_use(struct mob_data *md, unsigned int tick, int event) md->skilldelay[j]=tick; } else md->skilldelay[i]=tick; - iMap->freeblock_unlock(); + map->freeblock_unlock(); return 1; } //No skill was used. @@ -3284,8 +3285,7 @@ int mobskill_use(struct mob_data *md, unsigned int tick, int event) /*========================================== * Skill use event processing *------------------------------------------*/ -int mobskill_event(struct mob_data *md, struct block_list *src, unsigned int tick, int flag) -{ +int mobskill_event(struct mob_data *md, struct block_list *src, int64 tick, int flag) { int target_id, res = 0; if(md->bl.prev == NULL || md->status.hp <= 0) @@ -3296,13 +3296,13 @@ int mobskill_event(struct mob_data *md, struct block_list *src, unsigned int tic md->target_id = src->id; if (flag == -1) - res = mobskill_use(md, tick, MSC_CASTTARGETED); + res = mob->skill_use(md, tick, MSC_CASTTARGETED); else if ((flag&0xffff) == MSC_SKILLUSED) - res = mobskill_use(md, tick, flag); + res = mob->skill_use(md, tick, flag); else if (flag&BF_SHORT) - res = mobskill_use(md, tick, MSC_CLOSEDATTACKED); + res = mob->skill_use(md, tick, MSC_CLOSEDATTACKED); else if (flag&BF_LONG && !(flag&BF_MAGIC)) //Long-attacked should not include magic. - res = mobskill_use(md, tick, MSC_LONGRANGEATTACKED); + res = mob->skill_use(md, tick, MSC_LONGRANGEATTACKED); if (!res) //Restore previous target only if skill condition failed to trigger. [Skotlex] @@ -3319,53 +3319,52 @@ int mob_is_clone(int class_) { if(class_ < MOB_CLONE_START || class_ > MOB_CLONE_END) return 0; - if (mob_db(class_) == mob_dummy) + if (mob->db(class_) == mob->dummy) return 0; return class_; } //Flag values: -//&1: Set special ai (fight mobs, not players) +//&1: Set special AI (fight mobs, not players) //If mode is not passed, a default aggressive mode is used. //If master_id is passed, clone is attached to him. //Returns: ID of newly crafted copy. -int mob_clone_spawn(struct map_session_data *sd, int16 m, int16 x, int16 y, const char *event, int master_id, int mode, int flag, unsigned int duration) -{ +int mob_clone_spawn(struct map_session_data *sd, int16 m, int16 x, int16 y, const char *event, int master_id, int mode, int flag, unsigned int duration) { int class_; int i,j,h,inf,skill_id, fd; struct mob_data *md; struct mob_skill *ms; struct mob_db* db; - struct status_data *status; + struct status_data *mstatus; nullpo_ret(sd); if(pc_isdead(sd) && master_id && flag&1) return 0; - ARR_FIND( MOB_CLONE_START, MOB_CLONE_END, class_, mob_db_data[class_] == NULL ); + ARR_FIND( MOB_CLONE_START, MOB_CLONE_END, class_, mob->db_data[class_] == NULL ); if(class_ >= MOB_CLONE_END) return 0; - db = mob_db_data[class_]=(struct mob_db*)aCalloc(1, sizeof(struct mob_db)); - status = &db->status; + db = mob->db_data[class_]=(struct mob_db*)aCalloc(1, sizeof(struct mob_db)); + mstatus = &db->status; strcpy(db->sprite,sd->status.name); strcpy(db->name,sd->status.name); strcpy(db->jname,sd->status.name); - db->lv=status_get_lv(&sd->bl); - memcpy(status, &sd->base_status, sizeof(struct status_data)); - status->rhw.atk2= status->dex + status->rhw.atk + status->rhw.atk2; //Max ATK - status->rhw.atk = status->dex; //Min ATK - if (status->lhw.atk) { - status->lhw.atk2= status->dex + status->lhw.atk + status->lhw.atk2; //Max ATK - status->lhw.atk = status->dex; //Min ATK + db->lv=status->get_lv(&sd->bl); + memcpy(mstatus, &sd->base_status, sizeof(struct status_data)); + mstatus->rhw.atk2= mstatus->dex + mstatus->rhw.atk + mstatus->rhw.atk2; //Max ATK + mstatus->rhw.atk = mstatus->dex; //Min ATK + if (mstatus->lhw.atk) { + mstatus->lhw.atk2= mstatus->dex + mstatus->lhw.atk + mstatus->lhw.atk2; //Max ATK + mstatus->lhw.atk = mstatus->dex; //Min ATK } if (mode) //User provided mode. - status->mode = mode; + mstatus->mode = mode; else if (flag&1) //Friendly Character, remove looting. - status->mode &= ~MD_LOOTER; - status->hp = status->max_hp; - status->sp = status->max_sp; + mstatus->mode &= ~MD_LOOTER; + mstatus->hp = mstatus->max_hp; + mstatus->sp = mstatus->max_sp; memcpy(&db->vd, &sd->vd, sizeof(struct view_data)); db->base_exp=1; db->job_exp=1; @@ -3384,18 +3383,18 @@ int mob_clone_spawn(struct map_session_data *sd, int16 m, int16 x, int16 y, cons //Go Backwards to give better priority to advanced skills. for (i=0,j = MAX_SKILL_TREE-1;j>=0 && i< MAX_MOBSKILL ;j--) { - int idx = skill_tree[pc->class2idx(sd->status.class_)][j].idx; - skill_id = skill_tree[pc->class2idx(sd->status.class_)][j].id; + int idx = pc->skill_tree[pc->class2idx(sd->status.class_)][j].idx; + skill_id = pc->skill_tree[pc->class2idx(sd->status.class_)][j].id; if (!skill_id || sd->status.skill[idx].lv < 1 || - (skill_db[idx].inf2&(INF2_WEDDING_SKILL|INF2_GUILD_SKILL)) + (skill->db[idx].inf2&(INF2_WEDDING_SKILL|INF2_GUILD_SKILL)) ) continue; - for(h = 0; h < map[sd->bl.m].zone->disabled_skills_count; h++) { - if( skill_id == map[sd->bl.m].zone->disabled_skills[h]->nameid && map[sd->bl.m].zone->disabled_skills[h]->subtype == MZS_CLONE ) { + for(h = 0; h < map->list[sd->bl.m].zone->disabled_skills_count; h++) { + if( skill_id == map->list[sd->bl.m].zone->disabled_skills[h]->nameid && map->list[sd->bl.m].zone->disabled_skills[h]->subtype == MZS_CLONE ) { break; } } - if( h < map[sd->bl.m].zone->disabled_skills_count ) + if( h < map->list[sd->bl.m].zone->disabled_skills_count ) continue; //Normal aggressive mob, disable skills that cannot help them fight //against players (those with flags UF_NOMOB and UF_NOPC are specific @@ -3420,7 +3419,7 @@ int mob_clone_spawn(struct map_session_data *sd, int16 m, int16 x, int16 y, cons ms[i].casttime = skill->cast_fix(&sd->bl,skill_id, ms[i].skill_lv); ms[i].delay = 5000+skill->delay_fix(&sd->bl,skill_id, ms[i].skill_lv); - inf = skill_db[idx].inf; + inf = skill->db[idx].inf; if (inf&INF_ATTACK_SKILL) { ms[i].target = MST_TARGET; ms[i].cond1 = MSC_ALWAYS; @@ -3509,7 +3508,7 @@ int mob_clone_spawn(struct map_session_data *sd, int16 m, int16 x, int16 y, cons sd->fd = fd; //Finally, spawn it. - md = mob_once_spawn_sub(&sd->bl, m, x, y, "--en--", class_, event, SZ_SMALL, AI_NONE); + md = mob->once_spawn_sub(&sd->bl, m, x, y, "--en--", class_, event, SZ_MEDIUM, AI_NONE); if (!md) return 0; //Failed? md->special_state.clone = 1; @@ -3522,12 +3521,12 @@ int mob_clone_spawn(struct map_session_data *sd, int16 m, int16 x, int16 y, cons if (duration) //Auto Delete after a while. { if( md->deletetimer != INVALID_TIMER ) - iTimer->delete_timer(md->deletetimer, mob_timer_delete); - md->deletetimer = iTimer->add_timer (iTimer->gettick() + duration, mob_timer_delete, md->bl.id, 0); + timer->delete(md->deletetimer, mob->timer_delete); + md->deletetimer = timer->add(timer->gettick() + duration, mob->timer_delete, md->bl.id, 0); } } - mob_spawn(md); + mob->spawn(md); return md->bl.id; } @@ -3536,11 +3535,11 @@ int mob_clone_delete(struct mob_data *md) { const int class_ = md->class_; if (class_ >= MOB_CLONE_START && class_ < MOB_CLONE_END - && mob_db_data[class_]!=NULL) { - aFree(mob_db_data[class_]); - mob_db_data[class_]=NULL; + && mob->db_data[class_]!=NULL) { + aFree(mob->db_data[class_]); + mob->db_data[class_]=NULL; //Clear references to the db - md->db = mob_dummy; + md->db = mob->dummy; md->vd = NULL; return 1; } @@ -3553,50 +3552,50 @@ int mob_clone_delete(struct mob_data *md) /*========================================== * Since un-setting [ mob ] up was used, it is an initial provisional value setup. *------------------------------------------*/ -static int mob_makedummymobdb(int class_) +int mob_makedummymobdb(int class_) { - if (mob_dummy != NULL) + if (mob->dummy != NULL) { - if (mob_db(class_) == mob_dummy) - return 1; //Using the mob_dummy data already. [Skotlex] + if (mob->db(class_) == mob->dummy) + return 1; //Using the mob->dummy data already. [Skotlex] if (class_ > 0 && class_ <= MAX_MOB_DB) { //Remove the mob data so that it uses the dummy data instead. - aFree(mob_db_data[class_]); - mob_db_data[class_] = NULL; + aFree(mob->db_data[class_]); + mob->db_data[class_] = NULL; } return 0; } //Initialize dummy data. - mob_dummy = (struct mob_db*)aCalloc(1, sizeof(struct mob_db)); //Initializing the dummy mob. - sprintf(mob_dummy->sprite,"DUMMY"); - sprintf(mob_dummy->name,"Dummy"); - sprintf(mob_dummy->jname,"Dummy"); - mob_dummy->lv=1; - mob_dummy->status.max_hp=1000; - mob_dummy->status.max_sp=1; - mob_dummy->status.rhw.range=1; - mob_dummy->status.rhw.atk=7; - mob_dummy->status.rhw.atk2=10; - mob_dummy->status.str=1; - mob_dummy->status.agi=1; - mob_dummy->status.vit=1; - mob_dummy->status.int_=1; - mob_dummy->status.dex=6; - mob_dummy->status.luk=2; - mob_dummy->status.speed=300; - mob_dummy->status.adelay=1000; - mob_dummy->status.amotion=500; - mob_dummy->status.dmotion=500; - mob_dummy->base_exp=2; - mob_dummy->job_exp=1; - mob_dummy->range2=10; - mob_dummy->range3=10; + mob->dummy = (struct mob_db*)aCalloc(1, sizeof(struct mob_db)); //Initializing the dummy mob. + sprintf(mob->dummy->sprite,"DUMMY"); + sprintf(mob->dummy->name,"Dummy"); + sprintf(mob->dummy->jname,"Dummy"); + mob->dummy->lv=1; + mob->dummy->status.max_hp=1000; + mob->dummy->status.max_sp=1; + mob->dummy->status.rhw.range=1; + mob->dummy->status.rhw.atk=7; + mob->dummy->status.rhw.atk2=10; + mob->dummy->status.str=1; + mob->dummy->status.agi=1; + mob->dummy->status.vit=1; + mob->dummy->status.int_=1; + mob->dummy->status.dex=6; + mob->dummy->status.luk=2; + mob->dummy->status.speed=300; + mob->dummy->status.adelay=1000; + mob->dummy->status.amotion=500; + mob->dummy->status.dmotion=500; + mob->dummy->base_exp=2; + mob->dummy->job_exp=1; + mob->dummy->range2=10; + mob->dummy->range3=10; return 0; } //Adjusts the drop rate of item according to the criteria given. [Skotlex] -static unsigned int mob_drop_adjust(int baserate, int rate_adjust, unsigned short rate_min, unsigned short rate_max) +unsigned int mob_drop_adjust(int baserate, int rate_adjust, unsigned short rate_min, unsigned short rate_max) { double rate = baserate; @@ -3612,13 +3611,13 @@ static unsigned int mob_drop_adjust(int baserate, int rate_adjust, unsigned shor } /** - * Check if global item drop rate is overriden for given item + * Check if global item drop rate is overridden for given item * in db/mob_item_ratio.txt * @param nameid ID of the item * @param mob_id ID of the monster * @param rate_adjust pointer to store ratio if found */ -static void item_dropratio_adjust(int nameid, int mob_id, int *rate_adjust) +void item_dropratio_adjust(int nameid, int mob_id, int *rate_adjust) { if( item_drop_ratio_db[nameid] ) { if( item_drop_ratio_db[nameid]->mob_id[0] ) { // only for listed mobs @@ -3631,14 +3630,23 @@ static void item_dropratio_adjust(int nameid, int mob_id, int *rate_adjust) *rate_adjust = item_drop_ratio_db[nameid]->drop_ratio; } } - +/* (mob_parse_dbrow)_cap_value */ +static inline int mob_parse_dbrow_cap_value(int class_, int min, int max, int value) { + if( value > max ) { + ShowError("mob_parse_dbrow: for class '%d', field value '%d' is higher than the maximum '%d'! capping...\n", class_, value, max); + return max; + } else if ( value < min ) { + ShowError("mob_parse_dbrow: for class '%d', field value '%d' is lower than the minimum '%d'! capping...\n", class_, value, min); + return min; + } + return value; +} /*========================================== * processes one mobdb entry *------------------------------------------*/ -static bool mob_parse_dbrow(char** str) -{ +bool mob_parse_dbrow(char** str) { struct mob_db *db, entry; - struct status_data *status; + struct status_data *mstatus; int class_, i, k; double exp, maxhp; struct mob_data data; @@ -3662,7 +3670,7 @@ static bool mob_parse_dbrow(char** str) memset(&entry, 0, sizeof(entry)); db = &entry; - status = &db->status; + mstatus = &db->status; db->vd.class_ = class_; safestrncpy(db->sprite, str[1], sizeof(db->sprite)); @@ -3670,8 +3678,8 @@ static bool mob_parse_dbrow(char** str) safestrncpy(db->name, str[3], sizeof(db->name)); db->lv = atoi(str[4]); db->lv = cap_value(db->lv, 1, USHRT_MAX); - status->max_hp = atoi(str[5]); - status->max_sp = atoi(str[6]); + mstatus->max_hp = atoi(str[5]); + mstatus->max_sp = atoi(str[6]); exp = (double)atoi(str[7]) * (double)battle_config.base_exp_rate / 100.; db->base_exp = (unsigned int)cap_value(exp, 0, UINT_MAX); @@ -3679,24 +3687,28 @@ static bool mob_parse_dbrow(char** str) exp = (double)atoi(str[8]) * (double)battle_config.job_exp_rate / 100.; db->job_exp = (unsigned int)cap_value(exp, 0, UINT_MAX); - status->rhw.range = atoi(str[9]); - status->rhw.atk = atoi(str[10]); - status->rhw.atk2 = atoi(str[11]); - status->def = atoi(str[12]); - status->mdef = atoi(str[13]); - status->str = atoi(str[14]); - status->agi = atoi(str[15]); - status->vit = atoi(str[16]); - status->int_ = atoi(str[17]); - status->dex = atoi(str[18]); - status->luk = atoi(str[19]); + mstatus->rhw.range = atoi(str[9]); + + mstatus->rhw.atk = mob_parse_dbrow_cap_value(class_,UINT16_MIN,UINT16_MAX,atoi(str[10])); + mstatus->rhw.atk2 = mob_parse_dbrow_cap_value(class_,UINT16_MIN,UINT16_MAX,atoi(str[11])); + + mstatus->def = mob_parse_dbrow_cap_value(class_,DEFTYPE_MIN,DEFTYPE_MAX,atoi(str[12])); + mstatus->mdef = mob_parse_dbrow_cap_value(class_,DEFTYPE_MIN,DEFTYPE_MAX,atoi(str[13])); + + mstatus->str = mob_parse_dbrow_cap_value(class_,UINT16_MIN,UINT16_MAX,atoi(str[14])); + mstatus->agi = mob_parse_dbrow_cap_value(class_,UINT16_MIN,UINT16_MAX,atoi(str[15])); + mstatus->vit = mob_parse_dbrow_cap_value(class_,UINT16_MIN,UINT16_MAX,atoi(str[16])); + mstatus->int_ = mob_parse_dbrow_cap_value(class_,UINT16_MIN,UINT16_MAX,atoi(str[17])); + mstatus->dex = mob_parse_dbrow_cap_value(class_,UINT16_MIN,UINT16_MAX,atoi(str[18])); + mstatus->luk = mob_parse_dbrow_cap_value(class_,UINT16_MIN,UINT16_MAX,atoi(str[19])); + //All status should be min 1 to prevent divisions by zero from some skills. [Skotlex] - if (status->str < 1) status->str = 1; - if (status->agi < 1) status->agi = 1; - if (status->vit < 1) status->vit = 1; - if (status->int_< 1) status->int_= 1; - if (status->dex < 1) status->dex = 1; - if (status->luk < 1) status->luk = 1; + if (mstatus->str < 1) mstatus->str = 1; + if (mstatus->agi < 1) mstatus->agi = 1; + if (mstatus->vit < 1) mstatus->vit = 1; + if (mstatus->int_< 1) mstatus->int_= 1; + if (mstatus->dex < 1) mstatus->dex = 1; + if (mstatus->luk < 1) mstatus->luk = 1; db->range2 = atoi(str[20]); db->range3 = atoi(str[21]); @@ -3711,52 +3723,52 @@ static bool mob_parse_dbrow(char** str) db->range3 = db->range2; } - status->size = atoi(str[22]); - status->race = atoi(str[23]); + mstatus->size = atoi(str[22]); + mstatus->race = atoi(str[23]); i = atoi(str[24]); //Element - status->def_ele = i%10; - status->ele_lv = i/20; - if (status->def_ele >= ELE_MAX) { - ShowError("mob_parse_dbrow: Invalid element type %d for monster ID %d (max=%d).\n", status->def_ele, class_, ELE_MAX-1); + mstatus->def_ele = i%10; + mstatus->ele_lv = i/20; + if (mstatus->def_ele >= ELE_MAX) { + ShowError("mob_parse_dbrow: Invalid element type %d for monster ID %d (max=%d).\n", mstatus->def_ele, class_, ELE_MAX-1); return false; } - if (status->ele_lv < 1 || status->ele_lv > 4) { - ShowError("mob_parse_dbrow: Invalid element level %d for monster ID %d, must be in range 1-4.\n", status->ele_lv, class_); + if (mstatus->ele_lv < 1 || mstatus->ele_lv > 4) { + ShowError("mob_parse_dbrow: Invalid element level %d for monster ID %d, must be in range 1-4.\n", mstatus->ele_lv, class_); return false; } - status->mode = (int)strtol(str[25], NULL, 0); + mstatus->mode = (int)strtol(str[25], NULL, 0); if (!battle_config.monster_active_enable) - status->mode &= ~MD_AGGRESSIVE; + mstatus->mode &= ~MD_AGGRESSIVE; - status->speed = atoi(str[26]); - status->aspd_rate = 1000; + mstatus->speed = atoi(str[26]); + mstatus->aspd_rate = 1000; i = atoi(str[27]); - status->adelay = cap_value(i, battle_config.monster_max_aspd*2, 4000); + mstatus->adelay = cap_value(i, battle_config.monster_max_aspd*2, 4000); i = atoi(str[28]); - status->amotion = cap_value(i, battle_config.monster_max_aspd, 2000); + mstatus->amotion = cap_value(i, battle_config.monster_max_aspd, 2000); //If the attack animation is longer than the delay, the client crops the attack animation! //On aegis there is no real visible effect of having a recharge-time less than amotion anyway. - if (status->adelay < status->amotion) - status->adelay = status->amotion; - status->dmotion = atoi(str[29]); + if (mstatus->adelay < mstatus->amotion) + mstatus->adelay = mstatus->amotion; + mstatus->dmotion = atoi(str[29]); if(battle_config.monster_damage_delay_rate != 100) - status->dmotion = status->dmotion * battle_config.monster_damage_delay_rate / 100; + mstatus->dmotion = mstatus->dmotion * battle_config.monster_damage_delay_rate / 100; // Fill in remaining status data by using a dummy monster. data.bl.type = BL_MOB; data.level = db->lv; - memcpy(&data.status, status, sizeof(struct status_data)); - status_calc_misc(&data.bl, status, db->lv); + memcpy(&data.status, mstatus, sizeof(struct status_data)); + status->calc_misc(&data.bl, mstatus, db->lv); // MVP EXP Bonus: MEXP - // Some new MVP's MEXP multipled by high exp-rate cause overflow. [LuzZza] + // Some new MVP's MEXP multiple by high exp-rate cause overflow. [LuzZza] exp = (double)atoi(str[30]) * (double)battle_config.mvp_exp_rate / 100.; db->mexp = (unsigned int)cap_value(exp, 0, UINT_MAX); //Now that we know if it is an mvp or not, apply battle_config modifiers [Skotlex] - maxhp = (double)status->max_hp; + maxhp = (double)mstatus->max_hp; if (db->mexp > 0) { //Mvp if (battle_config.mvp_hp_rate != 100) maxhp = maxhp * (double)battle_config.mvp_hp_rate / 100.; @@ -3764,12 +3776,12 @@ static bool mob_parse_dbrow(char** str) if (battle_config.monster_hp_rate != 100) maxhp = maxhp * (double)battle_config.monster_hp_rate / 100.; - status->max_hp = (unsigned int)cap_value(maxhp, 1, UINT_MAX); - if(status->max_sp < 1) status->max_sp = 1; + mstatus->max_hp = (unsigned int)cap_value(maxhp, 1, UINT_MAX); + if(mstatus->max_sp < 1) mstatus->max_sp = 1; //Since mobs always respawn with full life... - status->hp = status->max_hp; - status->sp = status->max_sp; + mstatus->hp = mstatus->max_hp; + mstatus->sp = mstatus->max_sp; // MVP Drops: MVP1id,MVP1per,MVP2id,MVP2per,MVP3id,MVP3per for(i = 0; i < MAX_MVP_DROP; i++) { @@ -3779,13 +3791,13 @@ static bool mob_parse_dbrow(char** str) db->mvpitem[i].p = 0; //No item.... continue; } - item_dropratio_adjust(db->mvpitem[i].nameid, class_, &rate_adjust); - db->mvpitem[i].p = mob_drop_adjust(atoi(str[32+i*2]), rate_adjust, battle_config.item_drop_mvp_min, battle_config.item_drop_mvp_max); + mob->item_dropratio_adjust(db->mvpitem[i].nameid, class_, &rate_adjust); + db->mvpitem[i].p = mob->drop_adjust(atoi(str[32+i*2]), rate_adjust, battle_config.item_drop_mvp_min, battle_config.item_drop_mvp_max); //calculate and store Max available drop chance of the MVP item if (db->mvpitem[i].p) { struct item_data *id; - id = itemdb_search(db->mvpitem[i].nameid); + id = itemdb->search(db->mvpitem[i].nameid); if (id->maxchance == -1 || (id->maxchance < db->mvpitem[i].p/10 + 1) ) { //item has bigger drop chance or sold in shops id->maxchance = db->mvpitem[i].p/10 + 1; //reduce MVP drop info to not spoil common drop rate @@ -3803,7 +3815,7 @@ static bool mob_parse_dbrow(char** str) db->dropitem[i].p = 0; //No drop. continue; } - id = itemdb_search(db->dropitem[i].nameid); + id = itemdb->search(db->dropitem[i].nameid); type = id->type; rate = atoi(str[k+1]); if( (class_ >= 1324 && class_ <= 1363) || (class_ >= 1938 && class_ <= 1946) ) @@ -3813,38 +3825,38 @@ static bool mob_parse_dbrow(char** str) ratemax = battle_config.item_drop_treasure_max; } else switch (type) - { // Added suport to restrict normal drops of MVP's [Reddozen] + { // Added support to restrict normal drops of MVP's [Reddozen] case IT_HEALING: - rate_adjust = (status->mode&MD_BOSS) ? battle_config.item_rate_heal_boss : battle_config.item_rate_heal; + rate_adjust = (mstatus->mode&MD_BOSS) ? battle_config.item_rate_heal_boss : battle_config.item_rate_heal; ratemin = battle_config.item_drop_heal_min; ratemax = battle_config.item_drop_heal_max; break; case IT_USABLE: case IT_CASH: - rate_adjust = (status->mode&MD_BOSS) ? battle_config.item_rate_use_boss : battle_config.item_rate_use; + rate_adjust = (mstatus->mode&MD_BOSS) ? battle_config.item_rate_use_boss : battle_config.item_rate_use; ratemin = battle_config.item_drop_use_min; ratemax = battle_config.item_drop_use_max; break; case IT_WEAPON: case IT_ARMOR: case IT_PETARMOR: - rate_adjust = (status->mode&MD_BOSS) ? battle_config.item_rate_equip_boss : battle_config.item_rate_equip; + rate_adjust = (mstatus->mode&MD_BOSS) ? battle_config.item_rate_equip_boss : battle_config.item_rate_equip; ratemin = battle_config.item_drop_equip_min; ratemax = battle_config.item_drop_equip_max; break; case IT_CARD: - rate_adjust = (status->mode&MD_BOSS) ? battle_config.item_rate_card_boss : battle_config.item_rate_card; + rate_adjust = (mstatus->mode&MD_BOSS) ? battle_config.item_rate_card_boss : battle_config.item_rate_card; ratemin = battle_config.item_drop_card_min; ratemax = battle_config.item_drop_card_max; break; default: - rate_adjust = (status->mode&MD_BOSS) ? battle_config.item_rate_common_boss : battle_config.item_rate_common; + rate_adjust = (mstatus->mode&MD_BOSS) ? battle_config.item_rate_common_boss : battle_config.item_rate_common; ratemin = battle_config.item_drop_common_min; ratemax = battle_config.item_drop_common_max; break; } - item_dropratio_adjust(id->nameid, class_, &rate_adjust); - db->dropitem[i].p = mob_drop_adjust(rate, rate_adjust, ratemin, ratemax); + mob->item_dropratio_adjust(id->nameid, class_, &rate_adjust); + db->dropitem[i].p = mob->drop_adjust(rate, rate_adjust, ratemin, ratemax); //calculate and store Max available drop chance of the item if( db->dropitem[i].p && (class_ < 1324 || class_ > 1363) && (class_ < 1938 || class_ > 1946) ) @@ -3865,68 +3877,62 @@ static bool mob_parse_dbrow(char** str) id->mob[k].id = class_; } } - // Finally insert monster's data into the database. - if (mob_db_data[class_] == NULL) - mob_db_data[class_] = (struct mob_db*)aCalloc(1, sizeof(struct mob_db)); + if (mob->db_data[class_] == NULL) + mob->db_data[class_] = (struct mob_db*)aMalloc(sizeof(struct mob_db)); else //Copy over spawn data - memcpy(&db->spawn, mob_db_data[class_]->spawn, sizeof(db->spawn)); + memcpy(&db->spawn, mob->db_data[class_]->spawn, sizeof(db->spawn)); - memcpy(mob_db_data[class_], db, sizeof(struct mob_db)); + memcpy(mob->db_data[class_], db, sizeof(struct mob_db)); return true; } /*========================================== * mob_db.txt reading *------------------------------------------*/ -static bool mob_readdb_sub(char* fields[], int columns, int current) -{ - return mob_parse_dbrow(fields); +bool mob_readdb_sub(char* fields[], int columns, int current) { + return mob->parse_dbrow(fields); } -static void mob_readdb(void) -{ +void mob_readdb(void) { const char* filename[] = { DBPATH"mob_db.txt", "mob_db2.txt" }; int fi; - for( fi = 0; fi < ARRAYLENGTH(filename); ++fi ) - { - if(fi > 0) - { - char path[256]; - sprintf(path, "%s/%s", iMap->db_path, filename[fi]); - if(!exists(path)) - { + for( fi = 0; fi < ARRAYLENGTH(filename); ++fi ) { + if(fi > 0) { + char filepath[256]; + sprintf(filepath, "%s/%s", map->db_path, filename[fi]); + if(!exists(filepath)) { continue; } } - sv->readdb(iMap->db_path, filename[fi], ',', 31+2*MAX_MVP_DROP+2*MAX_MOB_DROP, 31+2*MAX_MVP_DROP+2*MAX_MOB_DROP, -1, &mob_readdb_sub); + sv->readdb(map->db_path, filename[fi], ',', 31+2*MAX_MVP_DROP+2*MAX_MOB_DROP, 31+2*MAX_MVP_DROP+2*MAX_MOB_DROP, -1, mob->readdb_sub); } + mob->name_constants(); } /*========================================== * mob_db table reading *------------------------------------------*/ -static int mob_read_sqldb(void) -{ - const char* mob_db_name[] = { iMap->mob_db_db, iMap->mob_db2_db }; +int mob_read_sqldb(void) { + const char* mob_db_name[] = { map->mob_db_db, map->mob_db2_db }; int fi; for( fi = 0; fi < ARRAYLENGTH(mob_db_name); ++fi ) { uint32 lines = 0, count = 0; // retrieve all rows from the mob database - if( SQL_ERROR == SQL->Query(mmysql_handle, "SELECT * FROM `%s`", mob_db_name[fi]) ) { - Sql_ShowDebug(mmysql_handle); + if( SQL_ERROR == SQL->Query(map->mysql_handle, "SELECT * FROM `%s`", mob_db_name[fi]) ) { + Sql_ShowDebug(map->mysql_handle); continue; } // process rows one by one - while( SQL_SUCCESS == SQL->NextRow(mmysql_handle) ) { + while( SQL_SUCCESS == SQL->NextRow(map->mysql_handle) ) { // wrap the result into a TXT-compatible format char line[1024]; char* str[31+2*MAX_MVP_DROP+2*MAX_MOB_DROP]; @@ -3938,37 +3944,52 @@ static int mob_read_sqldb(void) { char* data; size_t len; - SQL->GetData(mmysql_handle, i, &data, &len); + SQL->GetData(map->mysql_handle, i, &data, &len); strcpy(p, data); str[i] = p; p+= len + 1; } - if (!mob_parse_dbrow(str)) + if (!mob->parse_dbrow(str)) continue; count++; } // free the query result - SQL->FreeResult(mmysql_handle); + SQL->FreeResult(map->mysql_handle); - ShowStatus("Done reading '"CL_WHITE"%lu"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", count, mob_db_name[fi]); + ShowStatus("Done reading '"CL_WHITE"%"PRIu32""CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", count, mob_db_name[fi]); } + mob->name_constants(); return 0; } +void mob_name_constants(void) { + int i; +#ifdef ENABLE_CASE_CHECK + script->parser_current_file = "Mob Database (Likely an invalid or conflicting SpriteName)"; +#endif // ENABLE_CASE_CHECK + for (i = 0; i < MAX_MOB_DB; i++) { + if (mob->db_data[i] && !mob->is_clone(i)) + script->set_constant2(mob->db_data[i]->sprite, i, 0); + } +#ifdef ENABLE_CASE_CHECK + script->parser_current_file = NULL; +#endif // ENABLE_CASE_CHECK +} + /*========================================== * MOB display graphic change data reading *------------------------------------------*/ -static bool mob_readdb_mobavail(char* str[], int columns, int current) +bool mob_readdb_mobavail(char* str[], int columns, int current) { int class_, k; class_=atoi(str[0]); - if(mob_db(class_) == mob_dummy) // invalid class (probably undefined in db) + if(mob->db(class_) == mob->dummy) // invalid class (probably undefined in db) { ShowWarning("mob_readdb_mobavail: Unknown mob id %d.\n", class_); return false; @@ -3976,24 +3997,24 @@ static bool mob_readdb_mobavail(char* str[], int columns, int current) k=atoi(str[1]); - memset(&mob_db_data[class_]->vd, 0, sizeof(struct view_data)); - mob_db_data[class_]->vd.class_=k; + memset(&mob->db_data[class_]->vd, 0, sizeof(struct view_data)); + mob->db_data[class_]->vd.class_=k; //Player sprites if(pcdb_checkid(k) && columns==12) { - mob_db_data[class_]->vd.sex=atoi(str[2]); - mob_db_data[class_]->vd.hair_style=atoi(str[3]); - mob_db_data[class_]->vd.hair_color=atoi(str[4]); - mob_db_data[class_]->vd.weapon=atoi(str[5]); - mob_db_data[class_]->vd.shield=atoi(str[6]); - mob_db_data[class_]->vd.head_top=atoi(str[7]); - mob_db_data[class_]->vd.head_mid=atoi(str[8]); - mob_db_data[class_]->vd.head_bottom=atoi(str[9]); - mob_db_data[class_]->option=atoi(str[10])&~(OPTION_HIDE|OPTION_CLOAK|OPTION_INVISIBLE); - mob_db_data[class_]->vd.cloth_color=atoi(str[11]); // Monster player dye option - Valaris + mob->db_data[class_]->vd.sex=atoi(str[2]); + mob->db_data[class_]->vd.hair_style=atoi(str[3]); + mob->db_data[class_]->vd.hair_color=atoi(str[4]); + mob->db_data[class_]->vd.weapon=atoi(str[5]); + mob->db_data[class_]->vd.shield=atoi(str[6]); + mob->db_data[class_]->vd.head_top=atoi(str[7]); + mob->db_data[class_]->vd.head_mid=atoi(str[8]); + mob->db_data[class_]->vd.head_bottom=atoi(str[9]); + mob->db_data[class_]->option=atoi(str[10])&~(OPTION_HIDE|OPTION_CLOAK|OPTION_INVISIBLE); + mob->db_data[class_]->vd.cloth_color=atoi(str[11]); // Monster player dye option - Valaris } else if(columns==3) - mob_db_data[class_]->vd.head_bottom=atoi(str[2]); // mob equipment [Valaris] + mob->db_data[class_]->vd.head_bottom=atoi(str[2]); // mob equipment [Valaris] else if( columns != 2 ) return false; @@ -4003,7 +4024,7 @@ static bool mob_readdb_mobavail(char* str[], int columns, int current) /*========================================== * Reading of random monster data *------------------------------------------*/ -static int mob_read_randommonster(void) +int mob_read_randommonster(void) { FILE *fp; char line[1024]; @@ -4020,8 +4041,8 @@ static int mob_read_randommonster(void) for( i = 0; i < ARRAYLENGTH(mobfile) && i < MAX_RANDOMMONSTER; i++ ) { unsigned int count = 0; - mob_db_data[0]->summonper[i] = 1002; // Default fallback value, in case the database does not provide one - sprintf(line, "%s/%s", iMap->db_path, mobfile[i]); + mob->db_data[0]->summonper[i] = 1002; // Default fallback value, in case the database does not provide one + sprintf(line, "%s/%s", map->db_path, mobfile[i]); fp=fopen(line,"r"); if(fp==NULL){ ShowError("can't read %s\n",line); @@ -4043,10 +4064,10 @@ static int mob_read_randommonster(void) continue; class_ = atoi(str[0]); - if(mob_db(class_) == mob_dummy) + if(mob->db(class_) == mob->dummy) continue; count++; - mob_db_data[class_]->summonper[i]=atoi(str[2]); + mob->db_data[class_]->summonper[i]=atoi(str[2]); if (i) { if( summon[i].qty < ARRAYLENGTH(summon[i].class_) ) //MvPs summon[i].class_[summon[i].qty++] = class_; @@ -4057,11 +4078,11 @@ static int mob_read_randommonster(void) } } if (i && !summon[i].qty) { //At least have the default here. - summon[i].class_[0] = mob_db_data[0]->summonper[i]; + summon[i].class_[0] = mob->db_data[0]->summonper[i]; summon[i].qty = 1; } fclose(fp); - ShowStatus("Done reading '"CL_WHITE"%lu"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n",count,mobfile[i]); + ShowStatus("Done reading '"CL_WHITE"%u"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n",count,mobfile[i]); } return 0; } @@ -4070,7 +4091,7 @@ static int mob_read_randommonster(void) * processes one mob_chat_db entry [SnakeDrak] * @param last_msg_id ensures that only one error message per mob id is printed *------------------------------------------*/ -static bool mob_parse_row_chatdb(char** str, const char* source, int line, int* last_msg_id) +bool mob_parse_row_chatdb(char** str, const char* source, int line, int* last_msg_id) { char* msg; struct mob_chat *ms; @@ -4088,14 +4109,14 @@ static bool mob_parse_row_chatdb(char** str, const char* source, int line, int* return false; } - if (mob_chat_db[msg_id] == NULL) - mob_chat_db[msg_id] = (struct mob_chat*)aCalloc(1, sizeof (struct mob_chat)); + if (mob->chat_db[msg_id] == NULL) + mob->chat_db[msg_id] = (struct mob_chat*)aCalloc(1, sizeof (struct mob_chat)); - ms = mob_chat_db[msg_id]; + ms = mob->chat_db[msg_id]; //MSG ID ms->msg_id=msg_id; //Color - ms->color=strtoul(str[1],NULL,0); + ms->color=(unsigned int)strtoul(str[1],NULL,0); //Message msg = str[2]; len = strlen(msg); @@ -4128,23 +4149,20 @@ static bool mob_parse_row_chatdb(char** str, const char* source, int line, int* /*========================================== * mob_chat_db.txt reading [SnakeDrak] *-------------------------------------------------------------------------*/ -static void mob_readchatdb(void) -{ +void mob_readchatdb(void) { char arc[]="mob_chat_db.txt"; uint32 lines=0, count=0; - char line[1024], path[256]; + char line[1024], filepath[256]; int i, tmp=0; FILE *fp; - sprintf(path, "%s/%s", iMap->db_path, arc); - fp=fopen(path, "r"); - if(fp == NULL) - { - ShowWarning("mob_readchatdb: File not found \"%s\", skipping.\n", path); + sprintf(filepath, "%s/%s", map->db_path, arc); + fp=fopen(filepath, "r"); + if(fp == NULL) { + ShowWarning("mob_readchatdb: File not found \"%s\", skipping.\n", filepath); return; } - while(fgets(line, sizeof(line), fp)) - { + while(fgets(line, sizeof(line), fp)) { char *str[3], *p, *np; int j=0; @@ -4172,19 +4190,19 @@ static void mob_readchatdb(void) continue; } - if( !mob_parse_row_chatdb(str, path, lines, &tmp) ) + if( !mob->parse_row_chatdb(str, filepath, lines, &tmp) ) continue; count++; } fclose(fp); - ShowStatus("Done reading '"CL_WHITE"%lu"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", count, arc); + ShowStatus("Done reading '"CL_WHITE"%"PRIu32""CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", count, arc); } /*========================================== * processes one mob_skill_db entry *------------------------------------------*/ -static bool mob_parse_row_mobskilldb(char** str, int columns, int current) +bool mob_parse_row_mobskilldb(char** str, int columns, int current) { static const struct { char str[32]; @@ -4266,7 +4284,7 @@ static bool mob_parse_row_mobskilldb(char** str, int columns, int current) mob_id = atoi(str[0]); - if (mob_id > 0 && mob_db(mob_id) == mob_dummy) + if (mob_id > 0 && mob->db(mob_id) == mob->dummy) { if (mob_id != last_mob_id) { ShowError("mob_parse_row_mobskilldb: Non existant Mob id %d\n", mob_id); @@ -4277,8 +4295,8 @@ static bool mob_parse_row_mobskilldb(char** str, int columns, int current) if( strcmp(str[1],"clear")==0 ){ if (mob_id < 0) return false; - memset(mob_db_data[mob_id]->skill,0,sizeof(struct mob_skill)); - mob_db_data[mob_id]->maxskill=0; + memset(mob->db_data[mob_id]->skill,0,sizeof(struct mob_skill)); + mob->db_data[mob_id]->maxskill=0; return true; } @@ -4287,11 +4305,11 @@ static bool mob_parse_row_mobskilldb(char** str, int columns, int current) memset(&gms, 0, sizeof (struct mob_skill)); ms = &gms; } else { - ARR_FIND( 0, MAX_MOBSKILL, i, (ms = &mob_db_data[mob_id]->skill[i])->skill_id == 0 ); + ARR_FIND( 0, MAX_MOBSKILL, i, (ms = &mob->db_data[mob_id]->skill[i])->skill_id == 0 ); if( i == MAX_MOBSKILL ) { if (mob_id != last_mob_id) { - ShowError("mob_parse_row_mobskilldb: Too many skills for monster %d[%s]\n", mob_id, mob_db_data[mob_id]->sprite); + ShowError("mob_parse_row_mobskilldb: Too many skills for monster %d[%s]\n", mob_id, mob->db_data[mob_id]->sprite); last_mob_id = mob_id; } return false; @@ -4313,7 +4331,7 @@ static bool mob_parse_row_mobskilldb(char** str, int columns, int current) if (mob_id < 0) ShowError("mob_parse_row_mobskilldb: Invalid Skill ID (%d) for all mobs\n", j); else - ShowError("mob_parse_row_mobskilldb: Invalid Skill ID (%d) for mob %d (%s)\n", j, mob_id, mob_db_data[mob_id]->sprite); + ShowError("mob_parse_row_mobskilldb: Invalid Skill ID (%d) for mob %d (%s)\n", j, mob_id, mob->db_data[mob_id]->sprite); return false; } ms->skill_id=j; @@ -4354,14 +4372,14 @@ static bool mob_parse_row_mobskilldb(char** str, int columns, int current) if ( skill->get_casttype2(sidx) == CAST_GROUND) {//Ground skill. if (ms->target > MST_AROUND) { ShowWarning("mob_parse_row_mobskilldb: Wrong mob skill target for ground skill %d (%s) for %s.\n", - ms->skill_id, skill_db[sidx].name, - mob_id < 0?"all mobs":mob_db_data[mob_id]->sprite); + ms->skill_id, skill->db[sidx].name, + mob_id < 0?"all mobs":mob->db_data[mob_id]->sprite); ms->target = MST_TARGET; } } else if (ms->target > MST_MASTER) { ShowWarning("mob_parse_row_mobskilldb: Wrong mob skill target 'around' for non-ground skill %d (%s) for %s.\n", - ms->skill_id, skill_db[sidx].name, - mob_id < 0?"all mobs":mob_db_data[mob_id]->sprite); + ms->skill_id, skill->db[sidx].name, + mob_id < 0?"all mobs":mob->db_data[mob_id]->sprite); ms->target = MST_TARGET; } @@ -4389,7 +4407,7 @@ static bool mob_parse_row_mobskilldb(char** str, int columns, int current) ms->val[4]=(int)strtol(str[16],NULL,0); if(ms->skill_id == NPC_EMOTION && mob_id>0 && - ms->val[1] == mob_db(mob_id)->status.mode) + ms->val[1] == mob->db(mob_id)->status.mode) { ms->val[1] = 0; ms->val[4] = 1; //request to return mode to normal. @@ -4408,7 +4426,7 @@ static bool mob_parse_row_mobskilldb(char** str, int columns, int current) else ms->emotion=-1; - if(str[18]!=NULL && mob_chat_db[atoi(str[18])]!=NULL) + if(str[18]!=NULL && mob->chat_db[atoi(str[18])]!=NULL) ms->msg_id=atoi(str[18]); else ms->msg_id=0; @@ -4418,9 +4436,9 @@ static bool mob_parse_row_mobskilldb(char** str, int columns, int current) mob_id *= -1; for (i = 1; i < MAX_MOB_DB; i++) { - if (mob_db_data[i] == NULL) + if (mob->db_data[i] == NULL) continue; - if (mob_db_data[i]->status.mode&MD_BOSS) + if (mob->db_data[i]->status.mode&MD_BOSS) { if (!(mob_id&2)) //Skill not for bosses continue; @@ -4428,15 +4446,15 @@ static bool mob_parse_row_mobskilldb(char** str, int columns, int current) if (!(mob_id&1)) //Skill not for normal enemies. continue; - ARR_FIND( 0, MAX_MOBSKILL, j, mob_db_data[i]->skill[j].skill_id == 0 ); + ARR_FIND( 0, MAX_MOBSKILL, j, mob->db_data[i]->skill[j].skill_id == 0 ); if(j==MAX_MOBSKILL) continue; - memcpy (&mob_db_data[i]->skill[j], ms, sizeof(struct mob_skill)); - mob_db_data[i]->maxskill=j+1; + memcpy (&mob->db_data[i]->skill[j], ms, sizeof(struct mob_skill)); + mob->db_data[i]->maxskill=j+1; } } else //Skill set on a single mob. - mob_db_data[mob_id]->maxskill=i+1; + mob->db_data[mob_id]->maxskill=i+1; return true; } @@ -4444,31 +4462,27 @@ static bool mob_parse_row_mobskilldb(char** str, int columns, int current) /*========================================== * mob_skill_db.txt reading *------------------------------------------*/ -static void mob_readskilldb(void) { +void mob_readskilldb(void) { const char* filename[] = { DBPATH"mob_skill_db.txt", "mob_skill_db2.txt" }; int fi; - if( battle_config.mob_skill_rate == 0 ) - { + if( battle_config.mob_skill_rate == 0 ) { ShowStatus("Mob skill use disabled. Not reading mob skills.\n"); return; } - for( fi = 0; fi < ARRAYLENGTH(filename); ++fi ) - { - if(fi > 0) - { - char path[256]; - sprintf(path, "%s/%s", iMap->db_path, filename[fi]); - if(!exists(path)) - { + for( fi = 0; fi < ARRAYLENGTH(filename); ++fi ) { + if(fi > 0) { + char filepath[256]; + sprintf(filepath, "%s/%s", map->db_path, filename[fi]); + if(!exists(filepath)) { continue; } } - sv->readdb(iMap->db_path, filename[fi], ',', 19, 19, -1, &mob_parse_row_mobskilldb); + sv->readdb(map->db_path, filename[fi], ',', 19, 19, -1, mob->parse_row_mobskilldb); } } @@ -4477,9 +4491,8 @@ static void mob_readskilldb(void) { * not overly sure if this is all correct * seems to work though... */ -static int mob_read_sqlskilldb(void) -{ - const char* mob_skill_db_name[] = { iMap->mob_skill_db_db, iMap->mob_skill_db2_db }; +int mob_read_sqlskilldb(void) { + const char* mob_skill_db_name[] = { map->mob_skill_db_db, map->mob_skill_db2_db }; int fi; if( battle_config.mob_skill_rate == 0 ) { @@ -4492,13 +4505,13 @@ static int mob_read_sqlskilldb(void) uint32 lines = 0, count = 0; // retrieve all rows from the mob skill database - if( SQL_ERROR == SQL->Query(mmysql_handle, "SELECT * FROM `%s`", mob_skill_db_name[fi]) ) { - Sql_ShowDebug(mmysql_handle); + if( SQL_ERROR == SQL->Query(map->mysql_handle, "SELECT * FROM `%s`", mob_skill_db_name[fi]) ) { + Sql_ShowDebug(map->mysql_handle); continue; } // process rows one by one - while( SQL_SUCCESS == SQL->NextRow(mmysql_handle) ) { + while( SQL_SUCCESS == SQL->NextRow(map->mysql_handle) ) { // wrap the result into a TXT-compatible format char* str[19]; char* dummy = ""; @@ -4506,20 +4519,20 @@ static int mob_read_sqlskilldb(void) ++lines; for( i = 0; i < 19; ++i ) { - SQL->GetData(mmysql_handle, i, &str[i], NULL); + SQL->GetData(map->mysql_handle, i, &str[i], NULL); if( str[i] == NULL ) str[i] = dummy; // get rid of NULL columns } - if (!mob_parse_row_mobskilldb(str, 19, count)) + if (!mob->parse_row_mobskilldb(str, 19, count)) continue; count++; } // free the query result - SQL->FreeResult(mmysql_handle); + SQL->FreeResult(map->mysql_handle); - ShowStatus("Done reading '"CL_WHITE"%lu"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", count, mob_skill_db_name[fi]); + ShowStatus("Done reading '"CL_WHITE"%"PRIu32""CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", count, mob_skill_db_name[fi]); } return 0; } @@ -4527,7 +4540,7 @@ static int mob_read_sqlskilldb(void) /*========================================== * mob_race2_db.txt reading *------------------------------------------*/ -static bool mob_readdb_race2(char* fields[], int columns, int current) +bool mob_readdb_race2(char* fields[], int columns, int current) { int race, mobid, i; @@ -4542,12 +4555,12 @@ static bool mob_readdb_race2(char* fields[], int columns, int current) for(i = 1; i<columns; i++) { mobid = atoi(fields[i]); - if (mob_db(mobid) == mob_dummy) + if (mob->db(mobid) == mob->dummy) { ShowWarning("mob_readdb_race2: Unknown mob id %d for race2 %d.\n", mobid, race); continue; } - mob_db_data[mobid]->race2 = race; + mob->db_data[mobid]->race2 = race; } return true; } @@ -4555,12 +4568,12 @@ static bool mob_readdb_race2(char* fields[], int columns, int current) /** * Read mob_item_ratio.txt */ -static bool mob_readdb_itemratio(char* str[], int columns, int current) +bool mob_readdb_itemratio(char* str[], int columns, int current) { int nameid, ratio, i; nameid = atoi(str[0]); - if( itemdb_exists(nameid) == NULL ) + if( itemdb->exists(nameid) == NULL ) { ShowWarning("itemdb_read_itemratio: Invalid item id %d.\n", nameid); return false; @@ -4581,33 +4594,36 @@ static bool mob_readdb_itemratio(char* str[], int columns, int current) /** * read all mob-related databases */ -static void mob_load(void) -{ - sv->readdb(iMap->db_path, "mob_item_ratio.txt", ',', 2, 2+MAX_ITEMRATIO_MOBS, -1, &mob_readdb_itemratio); // must be read before mobdb - mob_readchatdb(); - if (iMap->db_use_sqldbs) - { - mob_read_sqldb(); - mob_read_sqlskilldb(); +void mob_load(bool minimal) { + if (minimal) { + // Only read the mob db in minimal mode + mob->readdb(); + return; } - else - { - mob_readdb(); - mob_readskilldb(); + sv->readdb(map->db_path, "mob_item_ratio.txt", ',', 2, 2+MAX_ITEMRATIO_MOBS, -1, mob->readdb_itemratio); // must be read before mobdb + mob->readchatdb(); + if (map->db_use_sql_mob_db) { + mob->read_sqldb(); } - sv->readdb(iMap->db_path, "mob_avail.txt", ',', 2, 12, -1, &mob_readdb_mobavail); - mob_read_randommonster(); - sv->readdb(iMap->db_path, DBPATH"mob_race2_db.txt", ',', 2, 20, -1, &mob_readdb_race2); + if (map->db_use_sql_mob_skill_db) { + mob->read_sqlskilldb(); + } else { + mob->readdb(); + mob->readskilldb(); + } + sv->readdb(map->db_path, "mob_avail.txt", ',', 2, 12, -1, mob->readdb_mobavail); + mob->read_randommonster(); + sv->readdb(map->db_path, DBPATH"mob_race2_db.txt", ',', 2, 20, -1, mob->readdb_race2); } void mob_reload(void) { int i; - + //Mob skills need to be cleared before re-reading them. [Skotlex] for (i = 0; i < MAX_MOB_DB; i++) - if (mob_db_data[i]) { - memset(&mob_db_data[i]->skill,0,sizeof(mob_db_data[i]->skill)); - mob_db_data[i]->maxskill=0; + if (mob->db_data[i] && !mob->is_clone(i)) { + memset(&mob->db_data[i]->skill,0,sizeof(mob->db_data[i]->skill)); + mob->db_data[i]->maxskill=0; } // Clear item_drop_ratio_db @@ -4618,39 +4634,42 @@ void mob_reload(void) { } } - mob_load(); + mob->load(false); } void mob_clear_spawninfo() { //Clears spawn related information for a script reload. int i; for (i = 0; i < MAX_MOB_DB; i++) - if (mob_db_data[i]) - memset(&mob_db_data[i]->spawn,0,sizeof(mob_db_data[i]->spawn)); + if (mob->db_data[i]) + memset(&mob->db_data[i]->spawn,0,sizeof(mob->db_data[i]->spawn)); } /*========================================== * Circumference initialization of mob *------------------------------------------*/ -int do_init_mob(void) -{ //Initialize the mob database - memset(mob_db_data,0,sizeof(mob_db_data)); //Clear the array - mob_db_data[0] = (struct mob_db*)aCalloc(1, sizeof (struct mob_db)); //This mob is used for random spawns - mob_makedummymobdb(0); //The first time this is invoked, it creates the dummy mob - item_drop_ers = ers_new(sizeof(struct item_drop),"mob.c::item_drop_ers",ERS_OPT_NONE); +int do_init_mob(bool minimal) { + // Initialize the mob database + memset(mob->db_data,0,sizeof(mob->db_data)); //Clear the array + mob->db_data[0] = (struct mob_db*)aCalloc(1, sizeof (struct mob_db)); //This mob is used for random spawns + mob->makedummymobdb(0); //The first time this is invoked, it creates the dummy mob + item_drop_ers = ers_new(sizeof(struct item_drop),"mob.c::item_drop_ers",ERS_OPT_CLEAN); item_drop_list_ers = ers_new(sizeof(struct item_drop_list),"mob.c::item_drop_list_ers",ERS_OPT_NONE); - mob_load(); + mob->load(minimal); - iTimer->add_timer_func_list(mob_delayspawn,"mob_delayspawn"); - iTimer->add_timer_func_list(mob_delay_item_drop,"mob_delay_item_drop"); - iTimer->add_timer_func_list(mob_ai_hard,"mob_ai_hard"); - iTimer->add_timer_func_list(mob_ai_lazy,"mob_ai_lazy"); - iTimer->add_timer_func_list(mob_timer_delete,"mob_timer_delete"); - iTimer->add_timer_func_list(mob_spawn_guardian_sub,"mob_spawn_guardian_sub"); - iTimer->add_timer_func_list(mob_respawn,"mob_respawn"); - iTimer->add_timer_interval(iTimer->gettick()+MIN_MOBTHINKTIME,mob_ai_hard,0,0,MIN_MOBTHINKTIME); - iTimer->add_timer_interval(iTimer->gettick()+MIN_MOBTHINKTIME*10,mob_ai_lazy,0,0,MIN_MOBTHINKTIME*10); + if (minimal) + return 0; + + timer->add_func_list(mob->delayspawn,"mob_delayspawn"); + timer->add_func_list(mob->delay_item_drop,"mob_delay_item_drop"); + timer->add_func_list(mob->ai_hard,"mob_ai_hard"); + timer->add_func_list(mob->ai_lazy,"mob_ai_lazy"); + timer->add_func_list(mob->timer_delete,"mob_timer_delete"); + timer->add_func_list(mob->spawn_guardian_sub,"mob_spawn_guardian_sub"); + timer->add_func_list(mob->respawn,"mob_respawn"); + timer->add_interval(timer->gettick()+MIN_MOBTHINKTIME,mob->ai_hard,0,0,MIN_MOBTHINKTIME); + timer->add_interval(timer->gettick()+MIN_MOBTHINKTIME*10,mob->ai_lazy,0,0,MIN_MOBTHINKTIME*10); return 0; } @@ -4661,25 +4680,25 @@ int do_init_mob(void) int do_final_mob(void) { int i; - if (mob_dummy) + if (mob->dummy) { - aFree(mob_dummy); - mob_dummy = NULL; + aFree(mob->dummy); + mob->dummy = NULL; } for (i = 0; i <= MAX_MOB_DB; i++) { - if (mob_db_data[i] != NULL) + if (mob->db_data[i] != NULL) { - aFree(mob_db_data[i]); - mob_db_data[i] = NULL; + aFree(mob->db_data[i]); + mob->db_data[i] = NULL; } } for (i = 0; i <= MAX_MOB_CHAT; i++) { - if (mob_chat_db[i] != NULL) + if (mob->chat_db[i] != NULL) { - aFree(mob_chat_db[i]); - mob_chat_db[i] = NULL; + aFree(mob->chat_db[i]); + mob->chat_db[i] = NULL; } } for (i = 0; i < MAX_ITEMDB; i++) @@ -4694,3 +4713,116 @@ int do_final_mob(void) ers_destroy(item_drop_list_ers); return 0; } + +void mob_defaults(void) { + //Defines the Manuk/Splendide mob groups for the status reductions [Epoque] + const int mob_manuk[8] = { 1986, 1987, 1988, 1989, 1990, 1997, 1998, 1999 }; + const int mob_splendide[5] = { 1991, 1992, 1993, 1994, 1995 }; + + mob = &mob_s; + + memset(mob->db_data, 0, sizeof(mob->db_data)); + mob->dummy = NULL; + memset(mob->chat_db, 0, sizeof(mob->chat_db)); + + memcpy(mob->manuk, mob_manuk, sizeof(mob->manuk)); + memcpy(mob->splendide, mob_splendide, sizeof(mob->splendide)); + /* */ + mob->reload = mob_reload; + mob->init = do_init_mob; + mob->final = do_final_mob; + /* */ + mob->db = mob_db; + mob->chat = mob_chat; + mob->makedummymobdb = mob_makedummymobdb; + mob->spawn_guardian_sub = mob_spawn_guardian_sub; + mob->skill_id2skill_idx = mob_skill_id2skill_idx; + mob->db_searchname = mobdb_searchname; + mob->db_searchname_array_sub = mobdb_searchname_array_sub; + mob->mvptomb_create = mvptomb_create; + mob->mvptomb_destroy = mvptomb_destroy; + mob->db_searchname_array = mobdb_searchname_array; + mob->db_checkid = mobdb_checkid; + mob->get_viewdata = mob_get_viewdata; + mob->parse_dataset = mob_parse_dataset; + mob->spawn_dataset = mob_spawn_dataset; + mob->get_random_id = mob_get_random_id; + mob->ksprotected = mob_ksprotected; + mob->once_spawn_sub = mob_once_spawn_sub; + mob->once_spawn = mob_once_spawn; + mob->once_spawn_area = mob_once_spawn_area; + mob->spawn_guardian = mob_spawn_guardian; + mob->spawn_bg = mob_spawn_bg; + mob->can_reach = mob_can_reach; + mob->linksearch = mob_linksearch; + mob->delayspawn = mob_delayspawn; + mob->setdelayspawn = mob_setdelayspawn; + mob->count_sub = mob_count_sub; + mob->spawn = mob_spawn; + mob->can_changetarget = mob_can_changetarget; + mob->target = mob_target; + mob->ai_sub_hard_activesearch = mob_ai_sub_hard_activesearch; + mob->ai_sub_hard_changechase = mob_ai_sub_hard_changechase; + mob->ai_sub_hard_bg_ally = mob_ai_sub_hard_bg_ally; + mob->ai_sub_hard_lootsearch = mob_ai_sub_hard_lootsearch; + mob->warpchase_sub = mob_warpchase_sub; + mob->ai_sub_hard_slavemob = mob_ai_sub_hard_slavemob; + mob->unlocktarget = mob_unlocktarget; + mob->randomwalk = mob_randomwalk; + mob->warpchase = mob_warpchase; + mob->ai_sub_hard = mob_ai_sub_hard; + mob->ai_sub_hard_timer = mob_ai_sub_hard_timer; + mob->ai_sub_foreachclient = mob_ai_sub_foreachclient; + mob->ai_sub_lazy = mob_ai_sub_lazy; + mob->ai_lazy = mob_ai_lazy; + mob->ai_hard = mob_ai_hard; + mob->setdropitem = mob_setdropitem; + mob->setlootitem = mob_setlootitem; + mob->delay_item_drop = mob_delay_item_drop; + mob->item_drop = mob_item_drop; + mob->timer_delete = mob_timer_delete; + mob->deleteslave_sub = mob_deleteslave_sub; + mob->deleteslave = mob_deleteslave; + mob->respawn = mob_respawn; + mob->log_damage = mob_log_damage; + mob->damage = mob_damage; + mob->dead = mob_dead; + mob->revive = mob_revive; + mob->guardian_guildchange = mob_guardian_guildchange; + mob->random_class = mob_random_class; + mob->class_change = mob_class_change; + mob->heal = mob_heal; + mob->warpslave_sub = mob_warpslave_sub; + mob->warpslave = mob_warpslave; + mob->countslave_sub = mob_countslave_sub; + mob->countslave = mob_countslave; + mob->summonslave = mob_summonslave; + mob->getfriendhprate_sub = mob_getfriendhprate_sub; + mob->getfriendhprate = mob_getfriendhprate; + mob->getmasterhpltmaxrate = mob_getmasterhpltmaxrate; + mob->getfriendstatus_sub = mob_getfriendstatus_sub; + mob->getfriendstatus = mob_getfriendstatus; + mob->skill_use = mobskill_use; + mob->skill_event = mobskill_event; + mob->is_clone = mob_is_clone; + mob->clone_spawn = mob_clone_spawn; + mob->clone_delete = mob_clone_delete; + mob->drop_adjust = mob_drop_adjust; + mob->item_dropratio_adjust = item_dropratio_adjust; + mob->parse_dbrow = mob_parse_dbrow; + mob->readdb_sub = mob_readdb_sub; + mob->readdb = mob_readdb; + mob->read_sqldb = mob_read_sqldb; + mob->name_constants = mob_name_constants; + mob->readdb_mobavail = mob_readdb_mobavail; + mob->read_randommonster = mob_read_randommonster; + mob->parse_row_chatdb = mob_parse_row_chatdb; + mob->readchatdb = mob_readchatdb; + mob->parse_row_mobskilldb = mob_parse_row_mobskilldb; + mob->readskilldb = mob_readskilldb; + mob->read_sqlskilldb = mob_read_sqlskilldb; + mob->readdb_race2 = mob_readdb_race2; + mob->readdb_itemratio = mob_readdb_itemratio; + mob->load = mob_load; + mob->clear_spawninfo = mob_clear_spawninfo; +} diff --git a/src/map/mob.h b/src/map/mob.h index 34e5a81c0..c8d43dbb2 100644 --- a/src/map/mob.h +++ b/src/map/mob.h @@ -1,19 +1,19 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder +// Copyright (c) Hercules Dev Team, licensed under GNU GPL. +// See the LICENSE file +// Portions Copyright (c) Athena Dev Teams -#ifndef _MOB_H_ -#define _MOB_H_ +#ifndef MAP_MOB_H +#define MAP_MOB_H -#include "../common/mmo.h" // struct item -#include "guild.h" // struct guardian_data #include "map.h" // struct status_data, struct view_data, struct mob_skill -#include "status.h" // struct status data, struct status_change -#include "unit.h" // unit_stop_walking(), unit_stop_attack() -#include "npc.h" +#include "status.h" // struct status_data, struct status_change +#include "unit.h" // struct unit_data +#include "../common/cbasetypes.h" +#include "../common/mmo.h" // struct item #define MAX_RANDOMMONSTER 5 -// Change this to increase the table size in your mob_db to accomodate a larger mob database. +// Change this to increase the table size in your mob_db to accommodate a larger mob database. // Be sure to note that IDs 4001 to 4048 are reserved for advanced/baby/expanded classes. // Notice that the last 1000 entries are used for player clones, so always set this to desired value +1000 #define MAX_MOB_DB 4000 @@ -35,12 +35,10 @@ #define MOB_CLONE_START (MAX_MOB_DB-999) #define MOB_CLONE_END MAX_MOB_DB -//Used to determine default enemy type of mobs (for use in eachinrange calls) -#define DEFAULT_ENEMY_TYPE(md) (md->special_state.ai?BL_CHAR:BL_MOB|BL_PC|BL_HOM|BL_MER) +//Used to determine default enemy type of mobs (for use in each in range calls) +#define DEFAULT_ENEMY_TYPE(md) ((md)->special_state.ai?BL_CHAR:BL_MOB|BL_PC|BL_HOM|BL_MER) -//Externals for the status effects. [Epoque] -extern const int mob_manuk[8]; -extern const int mob_splendide[5]; +#define MAX_MOB_CHAT 250 //Max Skill's messages //Mob skill states. enum MobSkillState { @@ -64,8 +62,8 @@ enum MobDamageLogFlag }; enum size { - SZ_SMALL = 0, - SZ_MEDIUM, + SZ_MEDIUM = 0, + SZ_SMALL, SZ_BIG, }; @@ -92,7 +90,7 @@ struct mob_skill { struct mob_chat { unsigned short msg_id; - unsigned long color; + unsigned int color; char msg[CHAT_SIZE_MAX]; }; @@ -129,7 +127,7 @@ struct mob_data { char name[NAME_LENGTH]; struct { unsigned int size : 2; //Small/Big monsters. - unsigned int ai : 4; //Special ai for summoned monsters. + unsigned int ai : 4; //Special AI for summoned monsters. //0: Normal mob. //1: Standard summon, attacks mobs. //2: Alchemist Marine Sphere @@ -167,7 +165,7 @@ struct mob_data { int areanpc_id; //Required in OnTouchNPC (to avoid multiple area touchs) unsigned int bg_id; // BattleGround System - unsigned int next_walktime,last_thinktime,last_linktime,last_pcneartime,dmgtick; + int64 next_walktime, last_thinktime, last_linktime, last_pcneartime, dmgtick; short move_fail_count; short lootitem_count; short min_chase; @@ -176,7 +174,7 @@ struct mob_data { int master_id,master_dist; int8 skill_idx;// key of array - unsigned int skilldelay[MAX_MOBSKILL]; + int64 skilldelay[MAX_MOBSKILL]; char npc_event[EVENT_NAME_LENGTH]; /** * Did this monster summon something? @@ -243,78 +241,126 @@ struct item_drop_list { struct item_drop* item; // linked list of drops }; -struct mob_db* mob_db(int class_); -int mobdb_searchname(const char *str); -int mobdb_searchname_array(struct mob_db** data, int size, const char *str); -int mobdb_checkid(const int id); -struct view_data* mob_get_viewdata(int class_); - -struct mob_data *mob_once_spawn_sub(struct block_list *bl, int16 m, - short x, short y, const char *mobname, int class_, const char *event, unsigned int size, unsigned int ai); - -int mob_once_spawn(struct map_session_data* sd, int16 m, int16 x, int16 y, - const char* mobname, int class_, int amount, const char* event, unsigned int size, unsigned int ai); - -int mob_once_spawn_area(struct map_session_data* sd, int16 m, - int16 x0, int16 y0, int16 x1, int16 y1, const char* mobname, int class_, int amount, const char* event, unsigned int size, unsigned int ai); - -bool mob_ksprotected (struct block_list *src, struct block_list *target); - -int mob_spawn_guardian(const char* mapname, int16 x, int16 y, const char* mobname, int class_, const char* event, int guardian, bool has_index); // Spawning Guardians [Valaris] -int mob_spawn_bg(const char* mapname, int16 x, int16 y, const char* mobname, int class_, const char* event, unsigned int bg_id); -int mob_guardian_guildchange(struct mob_data *md); //Change Guardian's ownership. [Skotlex] - -int mob_randomwalk(struct mob_data *md,unsigned int tick); -int mob_warpchase(struct mob_data *md, struct block_list *target); -int mob_target(struct mob_data *md,struct block_list *bl,int dist); -int mob_unlocktarget(struct mob_data *md, unsigned int tick); -struct mob_data* mob_spawn_dataset(struct spawn_data *data); -int mob_spawn(struct mob_data *md); -int mob_delayspawn(int tid, unsigned int tick, int id, intptr_t data); -int mob_setdelayspawn(struct mob_data *md); -int mob_parse_dataset(struct spawn_data *data); -void mob_log_damage(struct mob_data *md, struct block_list *src, int damage); -void mob_damage(struct mob_data *md, struct block_list *src, int damage); -int mob_dead(struct mob_data *md, struct block_list *src, int type); -void mob_revive(struct mob_data *md, unsigned int hp); -void mob_heal(struct mob_data *md,unsigned int heal); - -#define mob_stop_walking(md, type) unit_stop_walking(&(md)->bl, type) -#define mob_stop_attack(md) unit_stop_attack(&(md)->bl) -#define mob_is_battleground(md) ( map[(md)->bl.m].flag.battleground && ((md)->class_ == MOBID_BARRICADE2 || ((md)->class_ >= MOBID_FOOD_STOR && (md)->class_ <= MOBID_PINK_CRYST)) ) -#define mob_is_gvg(md) (map[(md)->bl.m].flag.gvg_castle && ( (md)->class_ == MOBID_EMPERIUM || (md)->class_ == MOBID_BARRICADE1 || (md)->class_ == MOBID_GUARIDAN_STONE1 || (md)->class_ == MOBID_GUARIDAN_STONE2) ) -#define mob_is_treasure(md) (((md)->class_ >= MOBID_TREAS01 && (md)->class_ <= MOBID_TREAS40) || ((md)->class_ >= MOBID_TREAS41 && (md)->class_ <= MOBID_TREAS49)) - -void mob_clear_spawninfo(); -int do_init_mob(void); -int do_final_mob(void); -int mob_timer_delete(int tid, unsigned int tick, int id, intptr_t data); -int mob_deleteslave(struct mob_data *md); +#define mob_stop_walking(md, type) (unit->stop_walking(&(md)->bl, (type))) +#define mob_stop_attack(md) (unit->stop_attack(&(md)->bl)) -int mob_random_class (int *value, size_t count); -int mob_get_random_id(int type, int flag, int lv); -int mob_class_change(struct mob_data *md,int class_); -int mob_warpslave(struct block_list *bl, int range); -int mob_linksearch(struct block_list *bl,va_list ap); - -int mobskill_use(struct mob_data *md,unsigned int tick,int event); -int mobskill_event(struct mob_data *md,struct block_list *src,unsigned int tick, int flag); -int mobskill_castend_id( int tid, unsigned int tick, int id,int data ); -int mobskill_castend_pos( int tid, unsigned int tick, int id,int data ); -int mob_summonslave(struct mob_data *md2,int *value,int amount,uint16 skill_id); -int mob_countslave(struct block_list *bl); -int mob_count_sub(struct block_list *bl, va_list ap); - -int mob_is_clone(int class_); +#define mob_is_battleground(md) ( map->list[(md)->bl.m].flag.battleground && ((md)->class_ == MOBID_BARRICADE2 || ((md)->class_ >= MOBID_FOOD_STOR && (md)->class_ <= MOBID_PINK_CRYST)) ) +#define mob_is_gvg(md) (map->list[(md)->bl.m].flag.gvg_castle && ( (md)->class_ == MOBID_EMPERIUM || (md)->class_ == MOBID_BARRICADE1 || (md)->class_ == MOBID_GUARIDAN_STONE1 || (md)->class_ == MOBID_GUARIDAN_STONE2) ) +#define mob_is_treasure(md) (((md)->class_ >= MOBID_TREAS01 && (md)->class_ <= MOBID_TREAS40) || ((md)->class_ >= MOBID_TREAS41 && (md)->class_ <= MOBID_TREAS49)) -int mob_clone_spawn(struct map_session_data *sd, int16 m, int16 x, int16 y, const char *event, int master_id, int mode, int flag, unsigned int duration); -int mob_clone_delete(struct mob_data *md); +struct mob_interface { + //Dynamic mob database, allows saving of memory when there's big gaps in the mob_db [Skotlex] + struct mob_db *db_data[MAX_MOB_DB+1]; + struct mob_db *dummy; //Dummy mob to be returned when a non-existant one is requested. + //Dynamic mob chat database + struct mob_chat *chat_db[MAX_MOB_CHAT+1]; + //Defines the Manuk/Splendide mob groups for the status reductions [Epoque] + int manuk[8]; + int splendide[5]; + /* */ + int (*init) (bool mimimal); + int (*final) (void); + void (*reload) (void); + /* */ + struct mob_db* (*db) (int index); + struct mob_chat* (*chat) (short id); + int (*makedummymobdb) (int); + int (*spawn_guardian_sub) (int tid, int64 tick, int id, intptr_t data); + int (*skill_id2skill_idx) (int class_, uint16 skill_id); + int (*db_searchname) (const char *str); + int (*db_searchname_array_sub) (struct mob_db *monster, const char *str, int flag); + // MvP Tomb System + void (*mvptomb_create) (struct mob_data *md, char *killer, time_t time); + void (*mvptomb_destroy) (struct mob_data *md); + int (*db_searchname_array) (struct mob_db **data, int size, const char *str, int flag); + int (*db_checkid) (const int id); + struct view_data* (*get_viewdata) (int class_); + int (*parse_dataset) (struct spawn_data *data); + struct mob_data* (*spawn_dataset) (struct spawn_data *data); + int (*get_random_id) (int type, int flag, int lv); + bool (*ksprotected) (struct block_list *src, struct block_list *target); + struct mob_data* (*once_spawn_sub) (struct block_list *bl, int16 m, int16 x, int16 y, const char *mobname, int class_, const char *event, unsigned int size, unsigned int ai); + int (*once_spawn) (struct map_session_data *sd, int16 m, int16 x, int16 y, const char *mobname, int class_, int amount, const char *event, unsigned int size, unsigned int ai); + int (*once_spawn_area) (struct map_session_data *sd, int16 m, int16 x0, int16 y0, int16 x1, int16 y1, const char *mobname, int class_, int amount, const char *event, unsigned int size, unsigned int ai); + int (*spawn_guardian) (const char *mapname, short x, short y, const char *mobname, int class_, const char *event, int guardian, bool has_index); + int (*spawn_bg) (const char *mapname, short x, short y, const char *mobname, int class_, const char *event, unsigned int bg_id); + int (*can_reach) (struct mob_data *md, struct block_list *bl, int range, int state); + int (*linksearch) (struct block_list *bl, va_list ap); + int (*delayspawn) (int tid, int64 tick, int id, intptr_t data); + int (*setdelayspawn) (struct mob_data *md); + int (*count_sub) (struct block_list *bl, va_list ap); + int (*spawn) (struct mob_data *md); + int (*can_changetarget) (struct mob_data *md, struct block_list *target, int mode); + int (*target) (struct mob_data *md, struct block_list *bl, int dist); + int (*ai_sub_hard_activesearch) (struct block_list *bl, va_list ap); + int (*ai_sub_hard_changechase) (struct block_list *bl, va_list ap); + int (*ai_sub_hard_bg_ally) (struct block_list *bl, va_list ap); + int (*ai_sub_hard_lootsearch) (struct block_list *bl, va_list ap); + int (*warpchase_sub) (struct block_list *bl, va_list ap); + int (*ai_sub_hard_slavemob) (struct mob_data *md, int64 tick); + int (*unlocktarget) (struct mob_data *md, int64 tick); + int (*randomwalk) (struct mob_data *md, int64 tick); + int (*warpchase) (struct mob_data *md, struct block_list *target); + bool (*ai_sub_hard) (struct mob_data *md, int64 tick); + int (*ai_sub_hard_timer) (struct block_list *bl, va_list ap); + int (*ai_sub_foreachclient) (struct map_session_data *sd, va_list ap); + int (*ai_sub_lazy) (struct mob_data *md, va_list args); + int (*ai_lazy) (int tid, int64 tick, int id, intptr_t data); + int (*ai_hard) (int tid, int64 tick, int id, intptr_t data); + struct item_drop* (*setdropitem) (int nameid, int qty, struct item_data *data); + struct item_drop* (*setlootitem) (struct item *item); + int (*delay_item_drop) (int tid, int64 tick, int id, intptr_t data); + void (*item_drop) (struct mob_data *md, struct item_drop_list *dlist, struct item_drop *ditem, int loot, int drop_rate, unsigned short flag); + int (*timer_delete) (int tid, int64 tick, int id, intptr_t data); + int (*deleteslave_sub) (struct block_list *bl, va_list ap); + int (*deleteslave) (struct mob_data *md); + int (*respawn) (int tid, int64 tick, int id, intptr_t data); + void (*log_damage) (struct mob_data *md, struct block_list *src, int damage); + void (*damage) (struct mob_data *md, struct block_list *src, int damage); + int (*dead) (struct mob_data *md, struct block_list *src, int type); + void (*revive) (struct mob_data *md, unsigned int hp); + int (*guardian_guildchange) (struct mob_data *md); + int (*random_class) (int *value, size_t count); + int (*class_change) (struct mob_data *md, int class_); + void (*heal) (struct mob_data *md, unsigned int heal); + int (*warpslave_sub) (struct block_list *bl, va_list ap); + int (*warpslave) (struct block_list *bl, int range); + int (*countslave_sub) (struct block_list *bl, va_list ap); + int (*countslave) (struct block_list *bl); + int (*summonslave) (struct mob_data *md2, int *value, int amount, uint16 skill_id); + int (*getfriendhprate_sub) (struct block_list *bl, va_list ap); + struct block_list* (*getfriendhprate) (struct mob_data *md, int min_rate, int max_rate); + struct block_list* (*getmasterhpltmaxrate) (struct mob_data *md, int rate); + int (*getfriendstatus_sub) (struct block_list *bl, va_list ap); + struct mob_data* (*getfriendstatus) (struct mob_data *md, int cond1, int cond2); + int (*skill_use) (struct mob_data *md, int64 tick, int event); + int (*skill_event) (struct mob_data *md, struct block_list *src, int64 tick, int flag); + int (*is_clone) (int class_); + int (*clone_spawn) (struct map_session_data *sd, int16 m, int16 x, int16 y, const char *event, int master_id, int mode, int flag, unsigned int duration); + int (*clone_delete) (struct mob_data *md); + unsigned int (*drop_adjust) (int baserate, int rate_adjust, unsigned short rate_min, unsigned short rate_max); + void (*item_dropratio_adjust) (int nameid, int mob_id, int *rate_adjust); + bool (*parse_dbrow) (char **str); + bool (*readdb_sub) (char *fields[], int columns, int current); + void (*readdb) (void); + int (*read_sqldb) (void); + void (*name_constants) (void); + bool (*readdb_mobavail) (char *str[], int columns, int current); + int (*read_randommonster) (void); + bool (*parse_row_chatdb) (char **str, const char *source, int line, int *last_msg_id); + void (*readchatdb) (void); + bool (*parse_row_mobskilldb) (char **str, int columns, int current); + void (*readskilldb) (void); + int (*read_sqlskilldb) (void); + bool (*readdb_race2) (char *fields[], int columns, int current); + bool (*readdb_itemratio) (char *str[], int columns, int current); + void (*load) (bool minimal); + void (*clear_spawninfo) (); +}; -void mob_reload(void); +struct mob_interface *mob; -// MvP Tomb System -void mvptomb_create(struct mob_data *md, char *killer, time_t time); -void mvptomb_destroy(struct mob_data *md); +void mob_defaults(void); -#endif /* _MOB_H_ */ +#endif /* MAP_MOB_H */ diff --git a/src/map/npc.c b/src/map/npc.c index 46e6d0fd2..f1c6f4fbd 100644 --- a/src/map/npc.c +++ b/src/map/npc.c @@ -2,49 +2,46 @@ // See the LICENSE file // Portions Copyright (c) Athena Dev Teams -#include "../common/cbasetypes.h" -#include "../common/timer.h" -#include "../common/nullpo.h" -#include "../common/malloc.h" -#include "../common/showmsg.h" -#include "../common/strlib.h" -#include "../common/utils.h" -#include "../common/ers.h" -#include "../common/db.h" -#include "../common/socket.h" -#include "map.h" -#include "log.h" -#include "clif.h" -#include "intif.h" -#include "pc.h" -#include "status.h" -#include "itemdb.h" -#include "script.h" -#include "mob.h" -#include "pet.h" -#include "instance.h" -#include "battle.h" -#include "skill.h" -#include "unit.h" +#define HERCULES_CORE + +#include "../config/core.h" // NPC_SECURE_TIMEOUT_INPUT, NPC_SECURE_TIMEOUT_MENU, NPC_SECURE_TIMEOUT_NEXT, SECURE_NPCTIMEOUT, SECURE_NPCTIMEOUT_INTERVAL #include "npc.h" -#include "chat.h" +#include <errno.h> +#include <math.h> #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <math.h> #include <time.h> -#include <errno.h> - -struct npc_data* fake_nd; +#include "battle.h" +#include "chat.h" +#include "clif.h" +#include "instance.h" +#include "intif.h" +#include "itemdb.h" +#include "log.h" +#include "map.h" +#include "mob.h" +#include "pc.h" +#include "pet.h" +#include "script.h" +#include "skill.h" +#include "status.h" +#include "unit.h" +#include "../common/HPM.h" +#include "../common/cbasetypes.h" +#include "../common/db.h" +#include "../common/ers.h" +#include "../common/malloc.h" +#include "../common/nullpo.h" +#include "../common/showmsg.h" +#include "../common/socket.h" +#include "../common/strlib.h" +#include "../common/timer.h" +#include "../common/utils.h" -// linked list of npc source files -struct npc_src_list { - struct npc_src_list* next; - char name[4]; // dynamic array, the structure is allocated with extra bytes (string length) -}; -static struct npc_src_list* npc_src_files = NULL; +struct npc_interface npc_s; static int npc_id=START_NPC_NUM; static int npc_warp=0; @@ -54,50 +51,17 @@ static int npc_mob=0; static int npc_delay_mob=0; static int npc_cache_mob=0; -/// 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 && !iMap->blid_exists(npc_id) ) - return 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( !iMap->blid_exists(npc_id) ) - return npc_id++;// available - } - // full loop, nothing available - ShowFatalError("npc_get_new_npc_id: All ids are taken. Exiting..."); - exit(1); - } -} - -static DBMap* ev_db; // const char* event_name -> struct event_data* -static DBMap* npcname_db; // const char* npc_name -> struct npc_data* - -struct event_data { - struct npc_data *nd; - int pos; -}; - -static struct eri *timer_event_ers; //For the npc timer data. [Skotlex] - -/* hello */ static char *npc_last_path; static char *npc_last_ref; - -struct npc_path_data { - char* path; - unsigned short references; -}; struct npc_path_data *npc_last_npd; -static DBMap *npc_path_db; //For holding the view data of npc classes. [Skotlex] static struct view_data npc_viewdb[MAX_NPC_CLASS]; static struct view_data npc_viewdb2[MAX_NPC_CLASS2_END-MAX_NPC_CLASS2_START]; +/* for speedup */ +unsigned int npc_market_qty[MAX_INVENTORY]; + static struct script_event_s { //Holds pointers to the commonly executed scripts for speedup. [Skotlex] struct event_data *event[UCHAR_MAX]; @@ -119,7 +83,26 @@ struct view_data* npc_get_viewdata(int class_) return NULL; } -static int npc_isnear_sub(struct block_list* bl, va_list args) { +/// 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 + 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 + } + // full loop, nothing available + ShowFatalError("npc_get_new_npc_id: All ids are taken. Exiting..."); + exit(1); + } +} + +int npc_isnear_sub(struct block_list* bl, va_list args) { struct npc_data *nd = (struct npc_data*)bl; if( nd->option & (OPTION_HIDE|OPTION_INVISIBLE) ) @@ -129,12 +112,11 @@ static int npc_isnear_sub(struct block_list* bl, va_list args) { } bool npc_isnear(struct block_list * bl) { - - if( battle_config.min_npc_vendchat_distance > 0 && - iMap->foreachinrange(npc_isnear_sub,bl, battle_config.min_npc_vendchat_distance, BL_NPC) ) - return true; - - return false; + if( battle_config.min_npc_vendchat_distance > 0 + && map->foreachinrange(npc->isnear_sub,bl, battle_config.min_npc_vendchat_distance, BL_NPC) ) + return true; + + return false; } int npc_ontouch_event(struct map_session_data *sd, struct npc_data *nd) @@ -147,8 +129,8 @@ int npc_ontouch_event(struct map_session_data *sd, struct npc_data *nd) if( pc_ishiding(sd) ) return 1; // Can't trigger 'OnTouch_'. try 'OnTouch' later. - snprintf(name, ARRAYLENGTH(name), "%s::%s", nd->exname, script_config.ontouch_name); - return npc_event(sd,name,1); + snprintf(name, ARRAYLENGTH(name), "%s::%s", nd->exname, script->config.ontouch_name); + return npc->event(sd,name,1); } int npc_ontouch2_event(struct map_session_data *sd, struct npc_data *nd) @@ -158,8 +140,8 @@ int npc_ontouch2_event(struct map_session_data *sd, struct npc_data *nd) if( sd->areanpc_id == nd->bl.id ) return 0; - snprintf(name, ARRAYLENGTH(name), "%s::%s", nd->exname, script_config.ontouch2_name); - return npc_event(sd,name,2); + snprintf(name, ARRAYLENGTH(name), "%s::%s", nd->exname, script->config.ontouch2_name); + return npc->event(sd,name,2); } /*========================================== @@ -178,13 +160,13 @@ int npc_enable_sub(struct block_list *bl, va_list ap) if (nd->option&OPTION_INVISIBLE) return 1; - if( npc_ontouch_event(sd,nd) > 0 && npc_ontouch2_event(sd,nd) > 0 ) + if( npc->ontouch_event(sd,nd) > 0 && npc->ontouch2_event(sd,nd) > 0 ) { // failed to run OnTouch event, so just click the npc if (sd->npc_id != 0) return 0; pc_stop_walking(sd,1); - npc_click(sd,nd); + npc->click(sd,nd); } } return 0; @@ -195,7 +177,7 @@ int npc_enable_sub(struct block_list *bl, va_list ap) *------------------------------------------*/ int npc_enable(const char* name, int flag) { - struct npc_data* nd = npc_name2id(name); + struct npc_data* nd = npc->name2id(name); if ( nd == NULL ) { ShowError("npc_enable: Attempted to %s a non-existing NPC '%s' (flag=%d).\n", (flag&3) ? "show" : "hide", name, flag); @@ -222,8 +204,8 @@ int npc_enable(const char* name, int flag) } else clif->changeoption(&nd->bl); - if( flag&3 && (nd->u.scr.xs >= 0 || nd->u.scr.ys >= 0) ) //check if player standing on a OnTouchArea - iMap->foreachinarea( npc_enable_sub, nd->bl.m, nd->bl.x-nd->u.scr.xs, nd->bl.y-nd->u.scr.ys, nd->bl.x+nd->u.scr.xs, nd->bl.y+nd->u.scr.ys, BL_PC, nd ); + if( flag&3 && (nd->u.scr.xs >= 0 || nd->u.scr.ys >= 0) ) //check if player standing on a OnTouchArea + map->foreachinarea( npc->enable_sub, nd->bl.m, nd->bl.x-nd->u.scr.xs, nd->bl.y-nd->u.scr.ys, nd->bl.x+nd->u.scr.xs, nd->bl.y+nd->u.scr.ys, BL_PC, nd ); return 0; } @@ -233,19 +215,19 @@ int npc_enable(const char* name, int flag) *------------------------------------------*/ struct npc_data* npc_name2id(const char* name) { - return (struct npc_data *) strdb_get(npcname_db, name); + return (struct npc_data *) strdb_get(npc->name_db, name); } /** * For the Secure NPC Timeout option (check config/Secure.h) [RR] **/ -#ifdef SECURE_NPCTIMEOUT /** * Timer to check for idle time and timeout the dialog if necessary **/ -int npc_rr_secure_timeout_timer(int tid, unsigned int tick, int id, intptr_t data) { +int npc_rr_secure_timeout_timer(int tid, int64 tick, int id, intptr_t data) { +#ifdef SECURE_NPCTIMEOUT struct map_session_data* sd = NULL; unsigned int timeout = NPC_SECURE_TIMEOUT_NEXT; - if( (sd = iMap->id2sd(id)) == NULL || !sd->npc_id ) { + if( (sd = map->id2sd(id)) == NULL || !sd->npc_id ) { if( sd ) sd->npc_idle_timer = INVALID_TIMER; return 0;//Not logged in anymore OR no longer attached to a npc } @@ -276,10 +258,10 @@ int npc_rr_secure_timeout_timer(int tid, unsigned int tick, int id, intptr_t dat clif->scriptclear(sd,sd->npc_id); sd->npc_idle_timer = INVALID_TIMER; } else //Create a new instance of ourselves to continue - sd->npc_idle_timer = iTimer->add_timer(iTimer->gettick() + (SECURE_NPCTIMEOUT_INTERVAL*1000),npc_rr_secure_timeout_timer,sd->bl.id,0); + sd->npc_idle_timer = timer->add(timer->gettick() + (SECURE_NPCTIMEOUT_INTERVAL*1000),npc->secure_timeout_timer,sd->bl.id,0); +#endif return 0; } -#endif /*========================================== * Dequeue event and add timer for execution (100ms) @@ -294,7 +276,7 @@ int npc_event_dequeue(struct map_session_data* sd) sd->state.using_fake_npc = 0; } if (sd->st) { - script_free_state(sd->st); + script->free_state(sd->st); sd->st = NULL; } sd->npc_id = 0; @@ -313,24 +295,39 @@ int npc_event_dequeue(struct map_session_data* sd) return 1; } +/** + * @see DBCreateData + */ +DBData npc_event_export_create(DBKey key, va_list args) +{ + struct linkdb_node** head_ptr; + CREATE(head_ptr, struct linkdb_node*, 1); + *head_ptr = NULL; + return DB->ptr2data(head_ptr); +} + /*========================================== * exports a npc event label * called from npc_parse_script *------------------------------------------*/ -static int npc_event_export(struct npc_data *nd, int i) +int npc_event_export(struct npc_data *nd, int i) { char* lname = nd->u.scr.label_list[i].name; int pos = nd->u.scr.label_list[i].pos; if ((lname[0] == 'O' || lname[0] == 'o') && (lname[1] == 'N' || lname[1] == 'n')) { struct event_data *ev; + struct linkdb_node **label_linkdb = NULL; char buf[EVENT_NAME_LENGTH]; snprintf(buf, ARRAYLENGTH(buf), "%s::%s", nd->exname, lname); + if (strdb_exists(npc->ev_db, buf)) // There was already another event of the same name? + return 1; // generate the data and insert it CREATE(ev, struct event_data, 1); ev->nd = nd; ev->pos = pos; - if (strdb_put(ev_db, buf, ev)) // There was already another event of the same name? - return 1; + strdb_put(npc->ev_db, buf, ev); + label_linkdb = strdb_ensure(npc->ev_label_db, lname, npc->event_export_create); + linkdb_insert(label_linkdb, nd, ev); } return 0; } @@ -340,99 +337,80 @@ int npc_event_sub(struct map_session_data* sd, struct event_data* ev, const char /** * Exec name (NPC events) on player or global * Do on all NPC when called with foreach - * @see DBApply */ -int npc_event_doall_sub(DBKey key, DBData *data, va_list ap) +void npc_event_doall_sub(void *key, void *data, va_list ap) { - const char* p = key.str; - struct event_data* ev; + struct event_data* ev = data; int* c; const char* name; int rid; - nullpo_ret(ev = DB->data2ptr(data)); - nullpo_ret(c = va_arg(ap, int *)); - nullpo_ret(name = va_arg(ap, const char *)); + nullpo_retv(c = va_arg(ap, int*)); + nullpo_retv(name = va_arg(ap, const char*)); rid = va_arg(ap, int); - p = strchr(p, ':'); // match only the event name - if( p && strcmpi(name, p) == 0 /* && !ev->nd->src_id */ ) // Do not run on duplicates. [Paradox924X] + if (ev /* && !ev->nd->src_id */) // Do not run on duplicates. [Paradox924X] { - if(rid) // a player may only have 1 script running at the same time - npc_event_sub(iMap->id2sd(rid),ev,key.str); - else - run_script(ev->nd->u.scr.script,ev->pos,rid,ev->nd->bl.id); + if(rid) { // a player may only have 1 script running at the same time + char buf[EVENT_NAME_LENGTH]; + snprintf(buf, ARRAYLENGTH(buf), "%s::%s", ev->nd->exname, name); + npc->event_sub(map->id2sd(rid), ev, buf); + } + else { + script->run(ev->nd->u.scr.script, ev->pos, rid, ev->nd->bl.id); + } (*c)++; } - - return 0; } -/** - * @see DBApply - */ -static int npc_event_do_sub(DBKey key, DBData *data, va_list ap) +// runs the specified event (supports both single-npc and global events) +int npc_event_do(const char* name) { - const char* p = key.str; - struct event_data* ev; - int* c; - const char* name; - - nullpo_ret(ev = DB->data2ptr(data)); - nullpo_ret(c = va_arg(ap, int *)); - nullpo_ret(name = va_arg(ap, const char *)); - - if( p && strcmpi(name, p) == 0 ) { - run_script(ev->nd->u.scr.script,ev->pos,0,ev->nd->bl.id); - (*c)++; + if( name[0] == ':' && name[1] == ':' ) { + return npc->event_doall(name+2); // skip leading "::" + } + else { + struct event_data *ev = strdb_get(npc->ev_db, name); + if (ev) { + script->run(ev->nd->u.scr.script, ev->pos, 0, ev->nd->bl.id); + return 1; + } } - return 0; } -// runs the specified event (supports both single-npc and global events) -int npc_event_do(const char* name) +// runs the specified event, with a RID attached (global only) +int npc_event_doall_id(const char* name, int rid) { int c = 0; + struct linkdb_node **label_linkdb = strdb_get(npc->ev_label_db, name); - if( name[0] == ':' && name[1] == ':' ) - ev_db->foreach(ev_db,npc_event_doall_sub,&c,name,0); - else - ev_db->foreach(ev_db,npc_event_do_sub,&c,name); + if (label_linkdb == NULL) + return 0; + linkdb_foreach(label_linkdb, npc->event_doall_sub, &c, name, rid); return c; } // runs the specified event (global only) int npc_event_doall(const char* name) { - return npc_event_doall_id(name, 0); -} - -// runs the specified event, with a RID attached (global only) -int npc_event_doall_id(const char* name, int rid) -{ - int c = 0; - char buf[64]; - safesnprintf(buf, sizeof(buf), "::%s", name); - ev_db->foreach(ev_db,npc_event_doall_sub,&c,buf,rid); - return c; + return npc->event_doall_id(name, 0); } /*========================================== * Clock event execution * OnMinute/OnClock/OnHour/OnDay/OnDDHHMM *------------------------------------------*/ -int npc_event_do_clock(int tid, unsigned int tick, int id, intptr_t data) -{ +int npc_event_do_clock(int tid, int64 tick, int id, intptr_t data) { static struct tm ev_tm_b; // tracks previous execution time - time_t timer; + time_t clock; struct tm* t; char buf[64]; int c = 0; - timer = time(NULL); - t = localtime(&timer); + clock = time(NULL); + t = localtime(&clock); if (t->tm_min != ev_tm_b.tm_min ) { char* day; @@ -449,37 +427,40 @@ int npc_event_do_clock(int tid, unsigned int tick, int id, intptr_t data) } sprintf(buf,"OnMinute%02d",t->tm_min); - c += npc_event_doall(buf); + c += npc->event_doall(buf); sprintf(buf,"OnClock%02d%02d",t->tm_hour,t->tm_min); - c += npc_event_doall(buf); + c += npc->event_doall(buf); sprintf(buf,"On%s%02d%02d",day,t->tm_hour,t->tm_min); - c += npc_event_doall(buf); + c += npc->event_doall(buf); } if (t->tm_hour != ev_tm_b.tm_hour) { sprintf(buf,"OnHour%02d",t->tm_hour); - c += npc_event_doall(buf); + c += npc->event_doall(buf); } if (t->tm_mday != ev_tm_b.tm_mday) { sprintf(buf,"OnDay%02d%02d",t->tm_mon+1,t->tm_mday); - c += npc_event_doall(buf); + c += npc->event_doall(buf); } memcpy(&ev_tm_b,t,sizeof(ev_tm_b)); return c; } -/*========================================== - * OnInit Event execution (the start of the event and watch) - *------------------------------------------*/ -void npc_event_do_oninit(void) +/** + * OnInit event execution (the start of the event and watch) + * @param reload Is the server reloading? + **/ +void npc_event_do_oninit( bool reload ) { - ShowStatus("Event '"CL_WHITE"OnInit"CL_RESET"' executed with '"CL_WHITE"%d"CL_RESET"' NPCs."CL_CLL"\n", npc_event_doall("OnInit")); + ShowStatus("Event '"CL_WHITE"OnInit"CL_RESET"' executed with '"CL_WHITE"%d"CL_RESET"' NPCs."CL_CLL"\n", npc->event_doall("OnInit")); - iTimer->add_timer_interval(iTimer->gettick()+100,npc_event_do_clock,0,0,1000); + // This interval has already been added on startup + if( !reload ) + timer->add_interval(timer->gettick()+100,npc->event_do_clock,0,0,1000); } /*========================================== @@ -488,10 +469,10 @@ void npc_event_do_oninit(void) *------------------------------------------*/ int npc_timerevent_export(struct npc_data *nd, int i) { - int t = 0, k = 0; + int t = 0, len = 0; char *lname = nd->u.scr.label_list[i].name; int pos = nd->u.scr.label_list[i].pos; - if (sscanf(lname, "OnTimer%d%n", &t, &k) == 1 && lname[k] == '\0') { + if (sscanf(lname, "OnTimer%d%n", &t, &len) == 1 && lname[len] == '\0') { // Timer event struct npc_timerevent_list *te = nd->u.scr.timer_event; int j, k = nd->u.scr.timeramount; @@ -522,25 +503,22 @@ struct timer_event_data { /*========================================== * triger 'OnTimerXXXX' events *------------------------------------------*/ -int npc_timerevent(int tid, unsigned int tick, int id, intptr_t data) -{ +int npc_timerevent(int tid, int64 tick, int id, intptr_t data) { int old_rid, old_timer; - unsigned int old_tick; - struct npc_data* nd=(struct npc_data *)iMap->id2bl(id); + int64 old_tick; + struct npc_data* nd=(struct npc_data *)map->id2bl(id); struct npc_timerevent_list *te; struct timer_event_data *ted = (struct timer_event_data*)data; struct map_session_data *sd=NULL; - if( nd == NULL ) - { + if( nd == NULL ) { ShowError("npc_timerevent: NPC not found??\n"); return 0; } - if( ted->rid && !(sd = iMap->id2sd(ted->rid)) ) - { + if( ted->rid && !(sd = map->id2sd(ted->rid)) ) { ShowError("npc_timerevent: Attached player not found.\n"); - ers_free(timer_event_ers, ted); + ers_free(npc->timer_event_ers, ted); return 0; } @@ -550,9 +528,9 @@ int npc_timerevent(int tid, unsigned int tick, int id, intptr_t data) old_timer = nd->u.scr.timer; // Set the values of the timer - nd->u.scr.rid = sd?sd->bl.id:0; //attached rid - nd->u.scr.timertick = tick; //current time tick - nd->u.scr.timer = ted->time; //total time from beginning to now + nd->u.scr.rid = sd?sd->bl.id:0; //attached rid + nd->u.scr.timertick = tick; //current time tick + nd->u.scr.timer = ted->time; //total time from beginning to now // Locate the event te = nd->u.scr.timer_event + ted->next; @@ -561,13 +539,12 @@ int npc_timerevent(int tid, unsigned int tick, int id, intptr_t data) ted->next++; if( nd->u.scr.timeramount > ted->next ) { - int next; - next = nd->u.scr.timer_event[ ted->next ].timer - nd->u.scr.timer_event[ ted->next - 1 ].timer; + int next = nd->u.scr.timer_event[ ted->next ].timer - nd->u.scr.timer_event[ ted->next - 1 ].timer; ted->time += next; if( sd ) - sd->npc_timer_id = iTimer->add_timer(tick+next,npc_timerevent,id,(intptr_t)ted); + sd->npc_timer_id = timer->add(tick+next,npc->timerevent,id,(intptr_t)ted); else - nd->u.scr.timerid = iTimer->add_timer(tick+next,npc_timerevent,id,(intptr_t)ted); + nd->u.scr.timerid = timer->add(tick+next,npc->timerevent,id,(intptr_t)ted); } else { @@ -576,11 +553,11 @@ int npc_timerevent(int tid, unsigned int tick, int id, intptr_t data) else nd->u.scr.timerid = INVALID_TIMER; - ers_free(timer_event_ers, ted); + ers_free(npc->timer_event_ers, ted); } // Run the script - run_script(nd->u.scr.script,te->pos,nd->u.scr.rid,nd->bl.id); + script->run(nd->u.scr.script,te->pos,nd->u.scr.rid,nd->bl.id); nd->u.scr.rid = old_rid; // Attached-rid should be restored anyway. if( sd ) @@ -594,10 +571,9 @@ int npc_timerevent(int tid, unsigned int tick, int id, intptr_t data) /*========================================== * Start/Resume NPC timer *------------------------------------------*/ -int npc_timerevent_start(struct npc_data* nd, int rid) -{ +int npc_timerevent_start(struct npc_data* nd, int rid) { int j; - unsigned int tick = iTimer->gettick(); + int64 tick = timer->gettick(); struct map_session_data *sd = NULL; //Player to whom script is attached. nullpo_ret(nd); @@ -605,45 +581,41 @@ int npc_timerevent_start(struct npc_data* nd, int rid) // Check if there is an OnTimer Event ARR_FIND( 0, nd->u.scr.timeramount, j, nd->u.scr.timer_event[j].timer > nd->u.scr.timer ); - if( nd->u.scr.rid > 0 && !(sd = iMap->id2sd(nd->u.scr.rid)) ) - { // Failed to attach timer to this player. + if( nd->u.scr.rid > 0 && !(sd = map->id2sd(nd->u.scr.rid)) ) { + // Failed to attach timer to this player. ShowError("npc_timerevent_start: Attached player not found!\n"); return 1; } - // Check if timer is already started. - if( sd ) - { + if( sd ) { if( sd->npc_timer_id != INVALID_TIMER ) return 0; - } - else if( nd->u.scr.timerid != INVALID_TIMER || nd->u.scr.timertick ) + } else if( nd->u.scr.timerid != INVALID_TIMER || nd->u.scr.timertick ) return 0; - if (j < nd->u.scr.timeramount) - { + if (j < nd->u.scr.timeramount) { int next; struct timer_event_data *ted; // Arrange for the next event - ted = ers_alloc(timer_event_ers, struct timer_event_data); + ted = ers_alloc(npc->timer_event_ers, struct timer_event_data); ted->next = j; // Set event index ted->time = nd->u.scr.timer_event[j].timer; next = nd->u.scr.timer_event[j].timer - nd->u.scr.timer; if( sd ) { ted->rid = sd->bl.id; // Attach only the player if attachplayerrid was used. - sd->npc_timer_id = iTimer->add_timer(tick+next,npc_timerevent,nd->bl.id,(intptr_t)ted); + sd->npc_timer_id = timer->add(tick+next,npc->timerevent,nd->bl.id,(intptr_t)ted); } else { ted->rid = 0; nd->u.scr.timertick = tick; // Set when timer is started - nd->u.scr.timerid = iTimer->add_timer(tick+next,npc_timerevent,nd->bl.id,(intptr_t)ted); + nd->u.scr.timerid = timer->add(tick+next,npc->timerevent,nd->bl.id,(intptr_t)ted); } - } - else if (!sd) - { + + } else if (!sd) { nd->u.scr.timertick = tick; + } return 0; @@ -659,12 +631,10 @@ int npc_timerevent_stop(struct npc_data* nd) nullpo_ret(nd); - if( nd->u.scr.rid && !(sd = iMap->id2sd(nd->u.scr.rid)) ) - { + if( nd->u.scr.rid && !(sd = map->id2sd(nd->u.scr.rid)) ) { ShowError("npc_timerevent_stop: Attached player not found!\n"); return 1; } - tid = sd?&sd->npc_timer_id:&nd->u.scr.timerid; if( *tid == INVALID_TIMER && (sd || !nd->u.scr.timertick) ) // Nothing to stop return 0; @@ -672,16 +642,16 @@ int npc_timerevent_stop(struct npc_data* nd) // Delete timer if ( *tid != INVALID_TIMER ) { - td = iTimer->get_timer(*tid); + td = timer->get(*tid); if( td && td->data ) - ers_free(timer_event_ers, (void*)td->data); - iTimer->delete_timer(*tid,npc_timerevent); + ers_free(npc->timer_event_ers, (void*)td->data); + timer->delete(*tid,npc->timerevent); *tid = INVALID_TIMER; } if( !sd && nd->u.scr.timertick ) { - nd->u.scr.timer += DIFF_TICK(iTimer->gettick(),nd->u.scr.timertick); // Set 'timer' to the time that has passed since the beginning of the timers + nd->u.scr.timer += DIFF_TICK32(timer->gettick(),nd->u.scr.timertick); // Set 'timer' to the time that has passed since the beginning of the timers nd->u.scr.timertick = 0; // Set 'tick' to zero so that we know it's off. } @@ -696,19 +666,19 @@ void npc_timerevent_quit(struct map_session_data* sd) struct npc_data* nd; struct timer_event_data *ted; - // Check timer existance + // Check timer existence if( sd->npc_timer_id == INVALID_TIMER ) return; - if( !(td = iTimer->get_timer(sd->npc_timer_id)) ) + if( !(td = timer->get(sd->npc_timer_id)) ) { sd->npc_timer_id = INVALID_TIMER; return; } // Delete timer - nd = (struct npc_data *)iMap->id2bl(td->id); + nd = (struct npc_data *)map->id2bl(td->id); ted = (struct timer_event_data*)td->data; - iTimer->delete_timer(sd->npc_timer_id, npc_timerevent); + timer->delete(sd->npc_timer_id, npc->timerevent); sd->npc_timer_id = INVALID_TIMER; // Execute OnTimerQuit @@ -718,7 +688,7 @@ void npc_timerevent_quit(struct map_session_data* sd) struct event_data *ev; snprintf(buf, ARRAYLENGTH(buf), "%s::OnTimerQuit", nd->exname); - ev = (struct event_data*)strdb_get(ev_db, buf); + ev = (struct event_data*)strdb_get(npc->ev_db, buf); if( ev && ev->nd != nd ) { ShowWarning("npc_timerevent_quit: Unable to execute \"OnTimerQuit\", two NPCs have the same event name [%s]!\n",buf); @@ -727,7 +697,7 @@ void npc_timerevent_quit(struct map_session_data* sd) if( ev ) { int old_rid,old_timer; - unsigned int old_tick; + int64 old_tick; //Set timer related info. old_rid = (nd->u.scr.rid == sd->bl.id ? 0 : nd->u.scr.rid); // Detach rid if the last attached player logged off. @@ -735,11 +705,11 @@ void npc_timerevent_quit(struct map_session_data* sd) old_timer = nd->u.scr.timer; nd->u.scr.rid = sd->bl.id; - nd->u.scr.timertick = iTimer->gettick(); + nd->u.scr.timertick = timer->gettick(); nd->u.scr.timer = ted->time; //Execute label - run_script(nd->u.scr.script,ev->pos,sd->bl.id,nd->bl.id); + script->run(nd->u.scr.script,ev->pos,sd->bl.id,nd->bl.id); //Restore previous data. nd->u.scr.rid = old_rid; @@ -747,23 +717,22 @@ void npc_timerevent_quit(struct map_session_data* sd) nd->u.scr.timertick = old_tick; } } - ers_free(timer_event_ers, ted); + ers_free(npc->timer_event_ers, ted); } /*========================================== * Get the tick value of an NPC timer * If it's stopped, return stopped time *------------------------------------------*/ -int npc_gettimerevent_tick(struct npc_data* nd) -{ - int tick; +int64 npc_gettimerevent_tick(struct npc_data* nd) { + int64 tick; nullpo_ret(nd); // TODO: Get player attached timer's tick. Now we can just get it by using 'getnpctimer' inside OnTimer event. tick = nd->u.scr.timer; // The last time it's active(start, stop or event trigger) if( nd->u.scr.timertick ) // It's a running timer - tick += DIFF_TICK(iTimer->gettick(), nd->u.scr.timertick); + tick += DIFF_TICK(timer->gettick(), nd->u.scr.timertick); return tick; } @@ -785,11 +754,11 @@ int npc_settimerevent_tick(struct npc_data* nd, int newtimer) nd->u.scr.rid = 0; // Check if timer is started - flag = (nd->u.scr.timerid != INVALID_TIMER); + flag = (nd->u.scr.timerid != INVALID_TIMER || nd->u.scr.timertick); - if( flag ) npc_timerevent_stop(nd); + if( flag ) npc->timerevent_stop(nd); nd->u.scr.timer = newtimer; - if( flag ) npc_timerevent_start(nd, -1); + if( flag ) npc->timerevent_start(nd, -1); nd->u.scr.rid = old_rid; return 0; @@ -804,7 +773,7 @@ int npc_event_sub(struct map_session_data* sd, struct event_data* ev, const char ARR_FIND( 0, MAX_EVENTQUEUE, i, sd->eventqueue[i][0] == '\0' ); if( i < MAX_EVENTQUEUE ) { - safestrncpy(sd->eventqueue[i],eventname,50); //Event enqueued. + safestrncpy(sd->eventqueue[i],eventname,EVENT_NAME_LENGTH); //Event enqueued. return 0; } @@ -814,10 +783,10 @@ int npc_event_sub(struct map_session_data* sd, struct event_data* ev, const char if( ev->nd->option&OPTION_INVISIBLE ) { //Disabled npc, shouldn't trigger event. - npc_event_dequeue(sd); + npc->event_dequeue(sd); return 2; } - run_script(ev->nd->u.scr.script,ev->pos,sd->bl.id,ev->nd->bl.id); + script->run(ev->nd->u.scr.script,ev->pos,sd->bl.id,ev->nd->bl.id); return 0; } @@ -826,7 +795,7 @@ int npc_event_sub(struct map_session_data* sd, struct event_data* ev, const char *------------------------------------------*/ int npc_event(struct map_session_data* sd, const char* eventname, int ontouch) { - struct event_data* ev = (struct event_data*)strdb_get(ev_db, eventname); + struct event_data* ev = (struct event_data*)strdb_get(npc->ev_db, eventname); struct npc_data *nd; nullpo_ret(sd); @@ -847,20 +816,19 @@ int npc_event(struct map_session_data* sd, const char* eventname, int ontouch) break; } - return npc_event_sub(sd,ev,eventname); + return npc->event_sub(sd,ev,eventname); } /*========================================== * Sub chk then execute area event type *------------------------------------------*/ -int npc_touch_areanpc_sub(struct block_list *bl, va_list ap) -{ +int npc_touch_areanpc_sub(struct block_list *bl, va_list ap) { struct map_session_data *sd; int pc_id; char *name; nullpo_ret(bl); - nullpo_ret((sd = iMap->id2sd(bl->id))); + nullpo_ret((sd = map->id2sd(bl->id))); pc_id = va_arg(ap,int); name = va_arg(ap,char*); @@ -872,7 +840,7 @@ int npc_touch_areanpc_sub(struct block_list *bl, va_list ap) if( pc_id == sd->bl.id ) return 0; - npc_event(sd,name,1); + npc->event(sd,name,1); return 1; } @@ -881,9 +849,8 @@ int npc_touch_areanpc_sub(struct block_list *bl, va_list ap) * Chk if sd is still touching his assigned npc. * If not, it unsets it and searches for another player in range. *------------------------------------------*/ -int npc_touchnext_areanpc(struct map_session_data* sd, bool leavemap) -{ - struct npc_data *nd = iMap->id2nd(sd->touching_id); +int npc_touchnext_areanpc(struct map_session_data* sd, bool leavemap) { + struct npc_data *nd = map->id2nd(sd->touching_id); short xs, ys; if( !nd || nd->touching_id != sd->bl.id ) @@ -900,8 +867,8 @@ int npc_touchnext_areanpc(struct map_session_data* sd, bool leavemap) char name[EVENT_NAME_LENGTH]; nd->touching_id = sd->touching_id = 0; - snprintf(name, ARRAYLENGTH(name), "%s::%s", nd->exname, script_config.ontouch_name); - iMap->forcountinarea(npc_touch_areanpc_sub,nd->bl.m,nd->bl.x - xs,nd->bl.y - ys,nd->bl.x + xs,nd->bl.y + ys,1,BL_PC,sd->bl.id,name); + snprintf(name, ARRAYLENGTH(name), "%s::%s", nd->exname, script->config.ontouch_name); + map->forcountinarea(npc->touch_areanpc_sub,nd->bl.m,nd->bl.x - xs,nd->bl.y - ys,nd->bl.x + xs,nd->bl.y + ys,1,BL_PC,sd->bl.id,name); } return 0; } @@ -922,51 +889,53 @@ int npc_touch_areanpc(struct map_session_data* sd, int16 m, int16 x, int16 y) //if(sd->npc_id) // return 1; - for(i=0;i<map[m].npc_num;i++) { - if (map[m].npc[i]->option&OPTION_INVISIBLE) { + for(i=0;i<map->list[m].npc_num;i++) { + if (map->list[m].npc[i]->option&OPTION_INVISIBLE) { f=0; // a npc was found, but it is disabled; don't print warning continue; } - switch(map[m].npc[i]->subtype) { + switch(map->list[m].npc[i]->subtype) { case WARP: - xs=map[m].npc[i]->u.warp.xs; - ys=map[m].npc[i]->u.warp.ys; + xs=map->list[m].npc[i]->u.warp.xs; + ys=map->list[m].npc[i]->u.warp.ys; break; case SCRIPT: - xs=map[m].npc[i]->u.scr.xs; - ys=map[m].npc[i]->u.scr.ys; + xs=map->list[m].npc[i]->u.scr.xs; + ys=map->list[m].npc[i]->u.scr.ys; break; default: continue; } - if( x >= map[m].npc[i]->bl.x-xs && x <= map[m].npc[i]->bl.x+xs - && y >= map[m].npc[i]->bl.y-ys && y <= map[m].npc[i]->bl.y+ys ) + if( x >= map->list[m].npc[i]->bl.x-xs && x <= map->list[m].npc[i]->bl.x+xs + && y >= map->list[m].npc[i]->bl.y-ys && y <= map->list[m].npc[i]->bl.y+ys ) break; } - if( i == map[m].npc_num ) - { + if( i == map->list[m].npc_num ) { if( f == 1 ) // no npc found - ShowError("npc_touch_areanpc : stray NPC cell/NPC not found in the block on coordinates '%s',%d,%d\n", map[m].name, x, y); + ShowError("npc_touch_areanpc : stray NPC cell/NPC not found in the block on coordinates '%s',%d,%d\n", map->list[m].name, x, y); return 1; } - switch(map[m].npc[i]->subtype) { + switch(map->list[m].npc[i]->subtype) { case WARP: if( pc_ishiding(sd) || (sd->sc.count && sd->sc.data[SC_CAMOUFLAGE]) ) break; // hidden chars cannot use warps - pc->setpos(sd,map[m].npc[i]->u.warp.mapindex,map[m].npc[i]->u.warp.x,map[m].npc[i]->u.warp.y,CLR_OUTSIGHT); + pc->setpos(sd,map->list[m].npc[i]->u.warp.mapindex,map->list[m].npc[i]->u.warp.x,map->list[m].npc[i]->u.warp.y,CLR_OUTSIGHT); break; case SCRIPT: - for (j = i; j < map[m].npc_num; j++) { - if (map[m].npc[j]->subtype != WARP) { + for (j = i; j < map->list[m].npc_num; j++) { + if (map->list[m].npc[j]->subtype != WARP) { continue; } - if ((sd->bl.x >= (map[m].npc[j]->bl.x - map[m].npc[j]->u.warp.xs) && sd->bl.x <= (map[m].npc[j]->bl.x + map[m].npc[j]->u.warp.xs)) && - (sd->bl.y >= (map[m].npc[j]->bl.y - map[m].npc[j]->u.warp.ys) && sd->bl.y <= (map[m].npc[j]->bl.y + map[m].npc[j]->u.warp.ys))) { + if ((sd->bl.x >= (map->list[m].npc[j]->bl.x - map->list[m].npc[j]->u.warp.xs) + && sd->bl.x <= (map->list[m].npc[j]->bl.x + map->list[m].npc[j]->u.warp.xs)) + && (sd->bl.y >= (map->list[m].npc[j]->bl.y - map->list[m].npc[j]->u.warp.ys) + && sd->bl.y <= (map->list[m].npc[j]->bl.y + map->list[m].npc[j]->u.warp.ys)) + ) { if( pc_ishiding(sd) || (sd->sc.count && sd->sc.data[SC_CAMOUFLAGE]) ) break; // hidden chars cannot use warps - pc->setpos(sd,map[m].npc[j]->u.warp.mapindex,map[m].npc[j]->u.warp.x,map[m].npc[j]->u.warp.y,CLR_OUTSIGHT); + pc->setpos(sd,map->list[m].npc[j]->u.warp.mapindex,map->list[m].npc[j]->u.warp.x,map->list[m].npc[j]->u.warp.y,CLR_OUTSIGHT); found_warp = 1; break; } @@ -976,16 +945,16 @@ int npc_touch_areanpc(struct map_session_data* sd, int16 m, int16 x, int16 y) break; } - if( npc_ontouch_event(sd,map[m].npc[i]) > 0 && npc_ontouch2_event(sd,map[m].npc[i]) > 0 ) + if( npc->ontouch_event(sd,map->list[m].npc[i]) > 0 && npc->ontouch2_event(sd,map->list[m].npc[i]) > 0 ) { // failed to run OnTouch event, so just click the npc - struct unit_data *ud = unit_bl2ud(&sd->bl); + struct unit_data *ud = unit->bl2ud(&sd->bl); if( ud && ud->walkpath.path_pos < ud->walkpath.path_len ) { // Since walktimer always == INVALID_TIMER at this time, we stop walking manually. [Inkfish] clif->fixpos(&sd->bl); ud->walkpath.path_pos = ud->walkpath.path_len; } - sd->areanpc_id = map[m].npc[i]->bl.id; - npc_click(sd,map[m].npc[i]); + sd->areanpc_id = map->list[m].npc[i]->bl.id; + npc->click(sd,map->list[m].npc[i]); } break; } @@ -1001,46 +970,45 @@ int npc_touch_areanpc2(struct mob_data *md) struct event_data* ev; int xs, ys; - for( i = 0; i < map[m].npc_num; i++ ) { - if( map[m].npc[i]->option&OPTION_INVISIBLE ) + for( i = 0; i < map->list[m].npc_num; i++ ) { + if( map->list[m].npc[i]->option&OPTION_INVISIBLE ) continue; - switch( map[m].npc[i]->subtype ) { + switch( map->list[m].npc[i]->subtype ) { case WARP: if( !( battle_config.mob_warp&1 ) ) continue; - xs = map[m].npc[i]->u.warp.xs; - ys = map[m].npc[i]->u.warp.ys; + xs = map->list[m].npc[i]->u.warp.xs; + ys = map->list[m].npc[i]->u.warp.ys; break; case SCRIPT: - xs = map[m].npc[i]->u.scr.xs; - ys = map[m].npc[i]->u.scr.ys; + xs = map->list[m].npc[i]->u.scr.xs; + ys = map->list[m].npc[i]->u.scr.ys; break; default: continue; // Keep Searching } - if( x >= map[m].npc[i]->bl.x-xs && x <= map[m].npc[i]->bl.x+xs && y >= map[m].npc[i]->bl.y-ys && y <= map[m].npc[i]->bl.y+ys ) - { // In the npc touch area - switch( map[m].npc[i]->subtype ) - { + if( x >= map->list[m].npc[i]->bl.x-xs && x <= map->list[m].npc[i]->bl.x+xs && y >= map->list[m].npc[i]->bl.y-ys && y <= map->list[m].npc[i]->bl.y+ys ) { + // In the npc touch area + switch( map->list[m].npc[i]->subtype ) { case WARP: - xs = iMap->mapindex2mapid(map[m].npc[i]->u.warp.mapindex); + xs = map->mapindex2mapid(map->list[m].npc[i]->u.warp.mapindex); if( m < 0 ) break; // Cannot Warp between map servers - if( unit_warp(&md->bl, xs, map[m].npc[i]->u.warp.x, map[m].npc[i]->u.warp.y, CLR_OUTSIGHT) == 0 ) + if( unit->warp(&md->bl, xs, map->list[m].npc[i]->u.warp.x, map->list[m].npc[i]->u.warp.y, CLR_OUTSIGHT) == 0 ) return 1; // Warped break; case SCRIPT: - if( map[m].npc[i]->bl.id == md->areanpc_id ) + if( map->list[m].npc[i]->bl.id == md->areanpc_id ) break; // Already touch this NPC - snprintf(eventname, ARRAYLENGTH(eventname), "%s::OnTouchNPC", map[m].npc[i]->exname); - if( (ev = (struct event_data*)strdb_get(ev_db, eventname)) == NULL || ev->nd == NULL ) + snprintf(eventname, ARRAYLENGTH(eventname), "%s::OnTouchNPC", map->list[m].npc[i]->exname); + if( (ev = (struct event_data*)strdb_get(npc->ev_db, eventname)) == NULL || ev->nd == NULL ) break; // No OnTouchNPC Event - md->areanpc_id = map[m].npc[i]->bl.id; + md->areanpc_id = map->list[m].npc[i]->bl.id; id = md->bl.id; // Stores Unique ID - run_script(ev->nd->u.scr.script, ev->pos, md->bl.id, ev->nd->bl.id); - if( iMap->id2md(id) == NULL ) return 1; // Not Warped, but killed + script->run(ev->nd->u.scr.script, ev->pos, md->bl.id, ev->nd->bl.id); + if( map->id2md(id) == NULL ) return 1; // Not Warped, but killed break; } @@ -1055,8 +1023,7 @@ int npc_touch_areanpc2(struct mob_data *md) //Flag determines the type of object to check for: //&1: NPC Warps //&2: NPCs with on-touch events. -int npc_check_areanpc(int flag, int16 m, int16 x, int16 y, int16 range) -{ +int npc_check_areanpc(int flag, int16 m, int16 x, int16 y, int16 range) { int i; int x0,y0,x1,y1; int xs,ys; @@ -1064,49 +1031,49 @@ int npc_check_areanpc(int flag, int16 m, int16 x, int16 y, int16 range) if (range < 0) return 0; x0 = max(x-range, 0); y0 = max(y-range, 0); - x1 = min(x+range, map[m].xs-1); - y1 = min(y+range, map[m].ys-1); + x1 = min(x+range, map->list[m].xs-1); + y1 = min(y+range, map->list[m].ys-1); //First check for npc_cells on the range given i = 0; for (ys = y0; ys <= y1 && !i; ys++) { - for(xs = x0; xs <= x1 && !i; xs++){ - if (iMap->getcell(m,xs,ys,CELL_CHKNPC)) + for(xs = x0; xs <= x1 && !i; xs++) { + if (map->getcell(m,xs,ys,CELL_CHKNPC)) i = 1; } } if (!i) return 0; //No NPC_CELLs. //Now check for the actual NPC on said range. - for(i=0;i<map[m].npc_num;i++) { - if (map[m].npc[i]->option&OPTION_INVISIBLE) + for(i=0;i<map->list[m].npc_num;i++) { + if (map->list[m].npc[i]->option&OPTION_INVISIBLE) continue; - switch(map[m].npc[i]->subtype) { + switch(map->list[m].npc[i]->subtype) { case WARP: if (!(flag&1)) continue; - xs=map[m].npc[i]->u.warp.xs; - ys=map[m].npc[i]->u.warp.ys; + xs=map->list[m].npc[i]->u.warp.xs; + ys=map->list[m].npc[i]->u.warp.ys; break; case SCRIPT: if (!(flag&2)) continue; - xs=map[m].npc[i]->u.scr.xs; - ys=map[m].npc[i]->u.scr.ys; + xs=map->list[m].npc[i]->u.scr.xs; + ys=map->list[m].npc[i]->u.scr.ys; break; default: continue; } - if( x1 >= map[m].npc[i]->bl.x-xs && x0 <= map[m].npc[i]->bl.x+xs - && y1 >= map[m].npc[i]->bl.y-ys && y0 <= map[m].npc[i]->bl.y+ys ) + if( x1 >= map->list[m].npc[i]->bl.x-xs && x0 <= map->list[m].npc[i]->bl.x+xs + && y1 >= map->list[m].npc[i]->bl.y-ys && y0 <= map->list[m].npc[i]->bl.y+ys ) break; // found a npc } - if (i==map[m].npc_num) + if (i==map->list[m].npc_num) return 0; - return (map[m].npc[i]->bl.id); + return (map->list[m].npc[i]->bl.id); } /*========================================== @@ -1141,7 +1108,7 @@ struct npc_data* npc_checknear(struct map_session_data* sd, struct block_list* b *------------------------------------------*/ int npc_globalmessage(const char* name, const char* mes) { - struct npc_data* nd = npc_name2id(name); + struct npc_data* nd = npc->name2id(name); char temp[100]; if (!nd) @@ -1154,28 +1121,27 @@ int npc_globalmessage(const char* name, const char* mes) } // MvP tomb [GreenBox] -void run_tomb(struct map_session_data* sd, struct npc_data* nd) -{ +void run_tomb(struct map_session_data* sd, struct npc_data* nd) { char buffer[200]; - char time[10]; + char time[10]; - strftime(time, sizeof(time), "%H:%M", localtime(&nd->u.tomb.kill_time)); + strftime(time, sizeof(time), "%H:%M", localtime(&nd->u.tomb.kill_time)); // TODO: Find exact color? - snprintf(buffer, sizeof(buffer), msg_txt(657), nd->u.tomb.md->db->name); - clif->scriptmes(sd, nd->bl.id, buffer); + snprintf(buffer, sizeof(buffer), msg_txt(857), nd->u.tomb.md->db->name); // "[ ^EE0000%s^000000 ]" + clif->scriptmes(sd, nd->bl.id, buffer); - clif->scriptmes(sd, nd->bl.id, msg_txt(658)); + clif->scriptmes(sd, nd->bl.id, msg_txt(858)); // "Has met its demise" - snprintf(buffer, sizeof(buffer), msg_txt(659), time); - clif->scriptmes(sd, nd->bl.id, buffer); + snprintf(buffer, sizeof(buffer), msg_txt(859), time); // "Time of death : ^EE0000%s^000000" + clif->scriptmes(sd, nd->bl.id, buffer); - clif->scriptmes(sd, nd->bl.id, msg_txt(660)); + clif->scriptmes(sd, nd->bl.id, msg_txt(860)); // "Defeated by" - snprintf(buffer, sizeof(buffer), msg_txt(661), nd->u.tomb.killer_name[0] ? nd->u.tomb.killer_name : "Unknown"); - clif->scriptmes(sd, nd->bl.id, buffer); + snprintf(buffer, sizeof(buffer), msg_txt(861), nd->u.tomb.killer_name[0] ? nd->u.tomb.killer_name : msg_txt(15)); // "[^EE0000%s^000000]" / "Unknown" + clif->scriptmes(sd, nd->bl.id, buffer); - clif->scriptclose(sd, nd->bl.id); + clif->scriptclose(sd, nd->bl.id); } /*========================================== @@ -1186,14 +1152,27 @@ int npc_click(struct map_session_data* sd, struct npc_data* nd) { nullpo_retr(1, sd); + // This usually happens when the player clicked on a NPC that has the view id + // of a mob, to activate this kind of npc it's needed to be in a 2,2 range + // from it. If the OnTouch area of a npc, coincides with the 2,2 range of + // another it's expected that the OnTouch event be put first in stack, because + // unit_walktoxy_timer is executed before any other function in this case. + // So it's best practice to put an 'end;' before OnTouch events in npcs that + // have view ids of mobs to avoid this "issue" [Panikon] if (sd->npc_id != 0) { - ShowError("npc_click: npc_id != 0\n"); + // The player clicked a npc after entering an OnTouch area + if( sd->areanpc_id != sd->npc_id ) + ShowError("npc_click: npc_id != 0\n"); + return 1; } - if(!nd) return 1; - if ((nd = npc_checknear(sd,&nd->bl)) == NULL) + if( !nd ) return 1; + + if ((nd = npc->checknear(sd,&nd->bl)) == NULL) + return 1; + //Hidden/Disabled npc. if (nd->class_ < 0 || nd->option&(OPTION_INVISIBLE|OPTION_HIDE)) return 1; @@ -1206,10 +1185,14 @@ int npc_click(struct map_session_data* sd, struct npc_data* nd) clif->cashshop_show(sd,nd); break; case SCRIPT: - run_script(nd->u.scr.script,0,sd->bl.id,nd->bl.id); + if( nd->u.scr.shop && nd->u.scr.shop->items && nd->u.scr.trader ) { + if( !npc->trader_open(sd,nd) ) + return 1; + } else + script->run(nd->u.scr.script,0,sd->bl.id,nd->bl.id); break; case TOMB: - run_tomb(sd,nd); + npc->run_tomb(sd,nd); break; } @@ -1219,22 +1202,22 @@ int npc_click(struct map_session_data* sd, struct npc_data* nd) /*========================================== * *------------------------------------------*/ -int npc_scriptcont(struct map_session_data* sd, int id, bool closing) -{ +int npc_scriptcont(struct map_session_data* sd, int id, bool closing) { + struct block_list *target = map->id2bl(id); nullpo_retr(1, sd); if( id != sd->npc_id ){ - TBL_NPC* nd_sd=(TBL_NPC*)iMap->id2bl(sd->npc_id); - TBL_NPC* nd=(TBL_NPC*)iMap->id2bl(id); + TBL_NPC* nd_sd=(TBL_NPC*)map->id2bl(sd->npc_id); + TBL_NPC* nd = BL_CAST(BL_NPC, target); ShowDebug("npc_scriptcont: %s (sd->npc_id=%d) is not %s (id=%d).\n", nd_sd?(char*)nd_sd->name:"'Unknown NPC'", (int)sd->npc_id, nd?(char*)nd->name:"'Unknown NPC'", (int)id); return 1; } - - if(id != fake_nd->bl.id) { // Not item script - if ((npc_checknear(sd,iMap->id2bl(id))) == NULL){ - ShowWarning("npc_scriptcont: failed npc_checknear test.\n"); + + if(id != npc->fake_nd->bl.id) { // Not item script + if ((npc->checknear(sd,target)) == NULL){ + ShowWarning("npc_scriptcont: failed npc->checknear test.\n"); return 1; } } @@ -1245,19 +1228,22 @@ int npc_scriptcont(struct map_session_data* sd, int id, bool closing) /** * Update the last NPC iteration **/ - sd->npc_idle_tick = iTimer->gettick(); + sd->npc_idle_tick = timer->gettick(); #endif /** * WPE can get to this point with a progressbar; we deny it. **/ - if( sd->progressbar.npc_id && DIFF_TICK(sd->progressbar.timeout,iTimer->gettick()) > 0 ) + if( sd->progressbar.npc_id && DIFF_TICK(sd->progressbar.timeout,timer->gettick()) > 0 ) return 1; - + + if( !sd->st ) + return 1; + if( closing && sd->st->state == CLOSE ) sd->st->state = END; - run_script_main(sd->st); + script->run_main(sd->st); return 0; } @@ -1265,25 +1251,30 @@ int npc_scriptcont(struct map_session_data* sd, int id, bool closing) /*========================================== * Chk if valid call then open buy or selling list *------------------------------------------*/ -int npc_buysellsel(struct map_session_data* sd, int id, int type) -{ +int npc_buysellsel(struct map_session_data* sd, int id, int type) { struct npc_data *nd; nullpo_retr(1, sd); - if ((nd = npc_checknear(sd,iMap->id2bl(id))) == NULL) + if ((nd = npc->checknear(sd,map->id2bl(id))) == NULL) return 1; - if (nd->subtype!=SHOP) { - ShowError("no such shop npc : %d\n",id); + if ( nd->subtype != SHOP && !(nd->subtype == SCRIPT && nd->u.scr.shop && nd->u.scr.shop->items) ) { + + if( nd->subtype == SCRIPT ) + ShowError("npc_buysellsel: trader '%s' has no shop list!\n",nd->exname); + else + ShowError("npc_buysellsel: no such shop npc %d (%s)\n",id,nd->exname); + if (sd->npc_id == id) - sd->npc_id=0; + sd->npc_id = 0; return 1; } - if (nd->option & OPTION_INVISIBLE) // can't buy if npc is not visible (hack?) + + if (nd->option & OPTION_INVISIBLE) // can't buy if npc is not visible (hack?) return 1; - if( nd->class_ < 0 && !sd->state.callshop ) - {// not called through a script and is not a visible NPC so an invalid call + + if( nd->class_ < 0 && !sd->state.callshop ) {// not called through a script and is not a visible NPC so an invalid call return 1; } @@ -1296,92 +1287,114 @@ int npc_buysellsel(struct map_session_data* sd, int id, int type) } else { clif->selllist(sd); } + return 0; } + /*========================================== * Cash Shop Buy List *------------------------------------------*/ -int npc_cashshop_buylist(struct map_session_data *sd, int points, int count, unsigned short* item_list) -{ - int i, j, nameid, amount, new_, w, vt; - struct npc_data *nd = (struct npc_data *)iMap->id2bl(sd->npc_shopid); - - if( !nd || nd->subtype != CASHSHOP ) - return 1; - - if( sd->state.trading ) - return 4; - - new_ = 0; - w = 0; - vt = 0; // Global Value - - // Validating Process ---------------------------------------------------- - for( i = 0; i < count; i++ ) - { - nameid = item_list[i*2+1]; - amount = item_list[i*2+0]; - - if( !itemdb_exists(nameid) || amount <= 0 ) - return 5; - - ARR_FIND(0,nd->u.shop.count,j,nd->u.shop.shop_item[j].nameid == nameid); - if( j == nd->u.shop.count || nd->u.shop.shop_item[j].value <= 0 ) - return 5; - - if( !itemdb_isstackable(nameid) && amount > 1 ) - { - ShowWarning("Player %s (%d:%d) sent a hexed packet trying to buy %d of nonstackable item %d!\n", sd->status.name, sd->status.account_id, sd->status.char_id, amount, nameid); - amount = item_list[i*2+0] = 1; - } - - switch( pc->checkadditem(sd,nameid,amount) ) - { - case ADDITEM_NEW: - new_++; - break; - case ADDITEM_OVERAMOUNT: - return 3; - } - - vt += nd->u.shop.shop_item[j].value * amount; - w += itemdb_weight(nameid) * amount; - } - - if( w + sd->weight > sd->max_weight ) - return 3; - if( pc->inventoryblank(sd) < new_ ) - return 3; - if( points > vt ) points = vt; - - // Payment Process ---------------------------------------------------- - if( sd->kafraPoints < points || sd->cashPoints < (vt - points) ) - return 6; - pc->paycash(sd,vt,points); - - // Delivery Process ---------------------------------------------------- - for( i = 0; i < count; i++ ) - { - struct item item_tmp; - - nameid = item_list[i*2+1]; - amount = item_list[i*2+0]; - - memset(&item_tmp,0,sizeof(item_tmp)); - - if( !pet_create_egg(sd,nameid) ) - { - item_tmp.nameid = nameid; - item_tmp.identify = 1; - pc->additem(sd,&item_tmp,amount,LOG_TYPE_NPC); - } - } - - return 0; +int npc_cashshop_buylist(struct map_session_data *sd, int points, int count, unsigned short* item_list) { + int i, j, nameid, amount, new_, w, vt; + struct npc_data *nd = NULL; + struct npc_item_list *shop = NULL; + unsigned short shop_size = 0; + + if( sd->state.trading ) + return ERROR_TYPE_EXCHANGE; + + if( count <= 0 ) + return ERROR_TYPE_ITEM_ID; + + if( points < 0 ) + return ERROR_TYPE_MONEY; + + if( !(nd = (struct npc_data *)map->id2bl(sd->npc_shopid)) ) + return ERROR_TYPE_NPC; + + if( nd->subtype != CASHSHOP ) { + if( nd->subtype == SCRIPT && nd->u.scr.shop && nd->u.scr.shop->type != NST_ZENY && nd->u.scr.shop->type != NST_MARKET ) { + shop = nd->u.scr.shop->item; + shop_size = nd->u.scr.shop->items; + } else + return ERROR_TYPE_NPC; + } else { + shop = nd->u.shop.shop_item; + shop_size = nd->u.shop.count; + } + + new_ = 0; + w = 0; + vt = 0; // Global Value + + // Validating Process ---------------------------------------------------- + for( i = 0; i < count; i++ ) { + nameid = item_list[i*2+1]; + amount = item_list[i*2+0]; + + if( !itemdb->exists(nameid) || amount <= 0 ) + return ERROR_TYPE_ITEM_ID; + + ARR_FIND(0,shop_size,j,shop[j].nameid == nameid); + if( j == shop_size || shop[j].value <= 0 ) + return ERROR_TYPE_ITEM_ID; + + if( !itemdb->isstackable(nameid) && amount > 1 ) { + ShowWarning("Player %s (%d:%d) sent a hexed packet trying to buy %d of non-stackable item %d!\n", + sd->status.name, sd->status.account_id, sd->status.char_id, amount, nameid); + amount = item_list[i*2+0] = 1; + } + + switch( pc->checkadditem(sd,nameid,amount) ) { + case ADDITEM_NEW: + new_++; + break; + case ADDITEM_OVERAMOUNT: + return ERROR_TYPE_INVENTORY_WEIGHT; + } + + vt += shop[j].value * amount; + w += itemdb_weight(nameid) * amount; + } + + if( w + sd->weight > sd->max_weight ) + return ERROR_TYPE_INVENTORY_WEIGHT; + + if( pc->inventoryblank(sd) < new_ ) + return ERROR_TYPE_INVENTORY_WEIGHT; + + if( points > vt ) points = vt; + + // Payment Process ---------------------------------------------------- + if( nd->subtype == SCRIPT && nd->u.scr.shop->type == NST_CUSTOM ) { + if( !npc->trader_pay(nd,sd,vt,points) ) + return ERROR_TYPE_MONEY; + } else { + if( sd->kafraPoints < points || sd->cashPoints < (vt - points) ) + return ERROR_TYPE_MONEY; + pc->paycash(sd,vt,points); + } + // Delivery Process ---------------------------------------------------- + for( i = 0; i < count; i++ ) { + struct item item_tmp; + + nameid = item_list[i*2+1]; + amount = item_list[i*2+0]; + + memset(&item_tmp,0,sizeof(item_tmp)); + + if( !pet->create_egg(sd,nameid) ) { + item_tmp.nameid = nameid; + item_tmp.identify = 1; + pc->additem(sd,&item_tmp,amount,LOG_TYPE_NPC); + } + } + + return ERROR_TYPE_NONE; } //npc_buylist for script-controlled shops. -static int npc_buylist_sub(struct map_session_data* sd, int n, unsigned short* item_list, struct npc_data* nd) +int npc_buylist_sub(struct map_session_data* sd, int n, unsigned short* item_list, struct npc_data* nd) { char npc_ev[EVENT_NAME_LENGTH]; int i; @@ -1389,93 +1402,314 @@ static int npc_buylist_sub(struct map_session_data* sd, int n, unsigned short* i int key_amount = 0; // discard old contents - script_cleararray_pc(sd, "@bought_nameid", (void*)0); - script_cleararray_pc(sd, "@bought_quantity", (void*)0); + script->cleararray_pc(sd, "@bought_nameid", (void*)0); + script->cleararray_pc(sd, "@bought_quantity", (void*)0); // save list of bought items - for( i = 0; i < n; i++ ) - { - script_setarray_pc(sd, "@bought_nameid", i, (void*)(intptr_t)item_list[i*2+1], &key_nameid); - script_setarray_pc(sd, "@bought_quantity", i, (void*)(intptr_t)item_list[i*2], &key_amount); + for( i = 0; i < n; i++ ) { + script->setarray_pc(sd, "@bought_nameid", i, (void*)(intptr_t)item_list[i*2+1], &key_nameid); + script->setarray_pc(sd, "@bought_quantity", i, (void*)(intptr_t)item_list[i*2], &key_amount); } // invoke event snprintf(npc_ev, ARRAYLENGTH(npc_ev), "%s::OnBuyItem", nd->exname); - npc_event(sd, npc_ev, 0); + npc->event(sd, npc_ev, 0); return 0; } +/** + * Loads persistent NPC Market Data from SQL + **/ +void npc_market_fromsql(void) { + SqlStmt* stmt = SQL->StmtMalloc(map->mysql_handle); + char name[NAME_LENGTH+1]; + int itemid; + int amount; + + if ( SQL_ERROR == SQL->StmtPrepare(stmt, "SELECT `name`, `itemid`, `amount` FROM `%s`", map->npc_market_data_db) + || SQL_ERROR == SQL->StmtExecute(stmt) + ) { + SqlStmt_ShowDebug(stmt); + SQL->StmtFree(stmt); + return; + } + + SQL->StmtBindColumn(stmt, 0, SQLDT_STRING, &name[0], sizeof(name), NULL, NULL); + SQL->StmtBindColumn(stmt, 1, SQLDT_INT, &itemid, 0, NULL, NULL); + SQL->StmtBindColumn(stmt, 2, SQLDT_INT, &amount, 0, NULL, NULL); + + while ( SQL_SUCCESS == SQL->StmtNextRow(stmt) ) { + struct npc_data *nd = NULL; + unsigned short i; + + if( !(nd = npc->name2id(name)) ) { + ShowError("npc_market_fromsql: NPC '%s' not found! skipping...\n",name); + npc->market_delfromsql_sub(name, USHRT_MAX); + continue; + } else if ( nd->subtype != SCRIPT || !nd->u.scr.shop || !nd->u.scr.shop->items || nd->u.scr.shop->type != NST_MARKET ) { + ShowError("npc_market_fromsql: NPC '%s' is not proper for market, skipping...\n",name); + npc->market_delfromsql_sub(name, USHRT_MAX); + continue; + } + + for(i = 0; i < nd->u.scr.shop->items; i++) { + if( nd->u.scr.shop->item[i].nameid == itemid ) { + nd->u.scr.shop->item[i].qty = amount; + break; + } + } + + if( i == nd->u.scr.shop->items ) { + ShowError("npc_market_fromsql: NPC '%s' does not sell item %d (qty %d), deleting...\n",name,itemid,amount); + npc->market_delfromsql_sub(name, itemid); + continue; + } + + } + + SQL->StmtFree(stmt); +} +/** + * Saves persistent NPC Market Data into SQL + **/ +void npc_market_tosql(struct npc_data *nd, unsigned short index) { + if( SQL_ERROR == SQL->Query(map->mysql_handle, "REPLACE INTO `%s` VALUES ('%s','%d','%d')", + map->npc_market_data_db, nd->exname, nd->u.scr.shop->item[index].nameid, nd->u.scr.shop->item[index].qty) ) + Sql_ShowDebug(map->mysql_handle); +} +/** + * Removes persistent NPC Market Data from SQL + */ +void npc_market_delfromsql_sub(const char *npcname, unsigned short index) { + if( index == USHRT_MAX ) { + if( SQL_ERROR == SQL->Query(map->mysql_handle, "DELETE FROM `%s` WHERE `name`='%s'", map->npc_market_data_db, npcname) ) + Sql_ShowDebug(map->mysql_handle); + } else { + if( SQL_ERROR == SQL->Query(map->mysql_handle, "DELETE FROM `%s` WHERE `name`='%s' AND `itemid`='%d' LIMIT 1", + map->npc_market_data_db, npcname, index) ) + Sql_ShowDebug(map->mysql_handle); + } +} +/** + * Removes persistent NPC Market Data from SQL + **/ +void npc_market_delfromsql(struct npc_data *nd, unsigned short index) { + npc->market_delfromsql_sub(nd->exname, index == USHRT_MAX ? index : nd->u.scr.shop->item[index].nameid); +} +/** + * Judges whether to allow and spawn a trader's window. + **/ +bool npc_trader_open(struct map_session_data *sd, struct npc_data *nd) { + + if( !nd->u.scr.shop || !nd->u.scr.shop->items ) + return false; + + switch( nd->u.scr.shop->type ) { + case NST_ZENY: + sd->state.callshop = 1; + clif->npcbuysell(sd,nd->bl.id); + return true;/* we skip sd->npc_shopid, npc->buysell will set it then when the player selects */ + case NST_MARKET: { + unsigned short i; + + for(i = 0; i < nd->u.scr.shop->items; i++) { + if( nd->u.scr.shop->item[i].qty ) + break; + } + + /* nothing to display, no items available */ + if( i == nd->u.scr.shop->items ) { + clif->colormes(sd->fd,COLOR_RED, msg_txt(881)); + return false; + } + clif->npc_market_open(sd,nd); + } + break; + default: + clif->cashshop_show(sd,nd); + break; + } + + sd->npc_shopid = nd->bl.id; + + return true; +} +/** + * Creates (npc_data)->u.scr.shop and updates all duplicates across the server to match the created pointer + * + * @param master id of the original npc + **/ +void npc_trader_update(int master) { + DBIterator* iter; + struct block_list* bl; + struct npc_data *master_nd = map->id2nd(master); + + CREATE(master_nd->u.scr.shop,struct npc_shop_data,1); + + iter = db_iterator(map->id_db); + + for( bl = (struct block_list*)dbi_first(iter); dbi_exists(iter); bl = (struct block_list*)dbi_next(iter) ) { + if( bl->type == BL_NPC ) { + struct npc_data* nd = (struct npc_data*)bl; + + if( nd->src_id == master ) { + nd->u.scr.shop = master_nd->u.scr.shop; + } + } + } + + dbi_destroy(iter); +} +/** + * Tries to issue a CountFunds event to the shop. + * + * @param nd shop + * @param sd player + **/ +void npc_trader_count_funds(struct npc_data *nd, struct map_session_data *sd) { + char evname[EVENT_NAME_LENGTH]; + struct event_data *ev = NULL; + + npc->trader_funds[0] = npc->trader_funds[1] = 0;/* clear */ + + switch( nd->u.scr.shop->type ) { + case NST_CASH: + npc->trader_funds[0] = sd->cashPoints; + npc->trader_funds[1] = sd->kafraPoints; + return; + case NST_CUSTOM: + break; + default: + ShowError("npc_trader_count_funds: unsupported shop type %d\n",nd->u.scr.shop->type); + return; + } + + snprintf(evname, EVENT_NAME_LENGTH, "%s::OnCountFunds",nd->exname); + + if ( (ev = strdb_get(npc->ev_db, evname)) ) + script->run(ev->nd->u.scr.script, ev->pos, sd->bl.id, ev->nd->bl.id); + else + ShowError("npc_trader_count_funds: '%s' event '%s' not found, operation failed\n",nd->exname,evname); + + /* the callee will rely on npc->trader_funds, upon success script->run updates them */ +} +/** + * Tries to issue a payment to the NPC Event capable of handling it + * + * @param nd shop + * @param sd player + * @param price total cost + * @param points the amount input in the shop by the user to use from the secondary currency (if any is being employed) + * + * @return bool whether it was successful (if the script does not respond it will fail) + **/ +bool npc_trader_pay(struct npc_data *nd, struct map_session_data *sd, int price, int points) { + char evname[EVENT_NAME_LENGTH]; + struct event_data *ev = NULL; + + npc->trader_ok = false;/* clear */ + + snprintf(evname, EVENT_NAME_LENGTH, "%s::OnPayFunds",nd->exname); + + if ( (ev = strdb_get(npc->ev_db, evname)) ) { + pc->setreg(sd,script->add_str("@price"),price); + pc->setreg(sd,script->add_str("@points"),points); + + script->run(ev->nd->u.scr.script, ev->pos, sd->bl.id, ev->nd->bl.id); + } else + ShowError("npc_trader_pay: '%s' event '%s' not found, operation failed\n",nd->exname,evname); + + return npc->trader_ok;/* run script will deal with it */ +} /*========================================== * Cash Shop Buy *------------------------------------------*/ -int npc_cashshop_buy(struct map_session_data *sd, int nameid, int amount, int points) -{ - struct npc_data *nd = (struct npc_data *)iMap->id2bl(sd->npc_shopid); +int npc_cashshop_buy(struct map_session_data *sd, int nameid, int amount, int points) { + struct npc_data *nd = NULL; struct item_data *item; + struct npc_item_list *shop = NULL; int i, price, w; - + unsigned short shop_size = 0; + if( amount <= 0 ) - return 5; + return ERROR_TYPE_ITEM_ID; if( points < 0 ) - return 6; - - if( !nd || nd->subtype != CASHSHOP ) - return 1; + return ERROR_TYPE_MONEY; if( sd->state.trading ) - return 4; + return ERROR_TYPE_EXCHANGE; + + if( !(nd = (struct npc_data *)map->id2bl(sd->npc_shopid)) ) + return ERROR_TYPE_NPC; - if( (item = itemdb_exists(nameid)) == NULL ) - return 5; // Invalid Item + if( (item = itemdb->exists(nameid)) == NULL ) + return ERROR_TYPE_ITEM_ID; // Invalid Item - ARR_FIND(0, nd->u.shop.count, i, nd->u.shop.shop_item[i].nameid == nameid); - if( i == nd->u.shop.count ) - return 5; - if( nd->u.shop.shop_item[i].value <= 0 ) - return 5; + if( nd->subtype != CASHSHOP ) { + if( nd->subtype == SCRIPT && nd->u.scr.shop && nd->u.scr.shop->type != NST_ZENY && nd->u.scr.shop->type != NST_MARKET ) { + shop = nd->u.scr.shop->item; + shop_size = nd->u.scr.shop->items; + } else + return ERROR_TYPE_NPC; + } else { + shop = nd->u.shop.shop_item; + shop_size = nd->u.shop.count; + } + + ARR_FIND(0, shop_size, i, shop[i].nameid == nameid); + + if( i == shop_size ) + return ERROR_TYPE_ITEM_ID; + + if( shop[i].value <= 0 ) + return ERROR_TYPE_ITEM_ID; - if(!itemdb_isstackable(nameid) && amount > 1) - { - ShowWarning("Player %s (%d:%d) sent a hexed packet trying to buy %d of nonstackable item %d!\n", + if(!itemdb->isstackable(nameid) && amount > 1) { + ShowWarning("Player %s (%d:%d) sent a hexed packet trying to buy %d of non-stackable item %d!\n", sd->status.name, sd->status.account_id, sd->status.char_id, amount, nameid); amount = 1; } - switch( pc->checkadditem(sd, nameid, amount) ) - { + switch( pc->checkadditem(sd, nameid, amount) ) { case ADDITEM_NEW: if( pc->inventoryblank(sd) == 0 ) - return 3; + return ERROR_TYPE_INVENTORY_WEIGHT; break; case ADDITEM_OVERAMOUNT: - return 3; + return ERROR_TYPE_INVENTORY_WEIGHT; } w = item->weight * amount; if( w + sd->weight > sd->max_weight ) - return 3; + return ERROR_TYPE_INVENTORY_WEIGHT; - if( (double)nd->u.shop.shop_item[i].value * amount > INT_MAX ) - { + if( (double)shop[i].value * amount > INT_MAX ) { ShowWarning("npc_cashshop_buy: Item '%s' (%d) price overflow attempt!\n", item->name, nameid); ShowDebug("(NPC:'%s' (%s,%d,%d), player:'%s' (%d/%d), value:%d, amount:%d)\n", - nd->exname, map[nd->bl.m].name, nd->bl.x, nd->bl.y, sd->status.name, sd->status.account_id, sd->status.char_id, nd->u.shop.shop_item[i].value, amount); - return 5; + nd->exname, map->list[nd->bl.m].name, nd->bl.x, nd->bl.y, + sd->status.name, sd->status.account_id, sd->status.char_id, + shop[i].value, amount); + return ERROR_TYPE_ITEM_ID; } - price = nd->u.shop.shop_item[i].value * amount; + price = shop[i].value * amount; + if( points > price ) points = price; - if( (sd->kafraPoints < points) || (sd->cashPoints < price - points) ) - return 6; - - pc->paycash(sd, price, points); + if( nd->subtype == SCRIPT && nd->u.scr.shop->type == NST_CUSTOM ) { + if( !npc->trader_pay(nd,sd,price,points) ) + return ERROR_TYPE_MONEY; + } else { + if( (sd->kafraPoints < points) || (sd->cashPoints < price - points) ) + return ERROR_TYPE_MONEY; + + pc->paycash(sd, price, points); + } - if( !pet_create_egg(sd, nameid) ) - { + if( !pet->create_egg(sd, nameid) ) { struct item item_tmp; memset(&item_tmp, 0, sizeof(struct item)); item_tmp.nameid = nameid; @@ -1484,114 +1718,124 @@ int npc_cashshop_buy(struct map_session_data *sd, int nameid, int amount, int po pc->additem(sd,&item_tmp, amount, LOG_TYPE_NPC); } - return 0; + return ERROR_TYPE_NONE; } /// Player item purchase from npc shop. /// /// @param item_list 'n' pairs <amount,itemid> /// @return result code for clif->parse_NpcBuyListSend -int npc_buylist(struct map_session_data* sd, int n, unsigned short* item_list) -{ +int npc_buylist(struct map_session_data* sd, int n, unsigned short* item_list) { struct npc_data* nd; + struct npc_item_list *shop = NULL; double z; int i,j,w,skill_t,new_, idx = skill->get_index(MC_DISCOUNT); - + unsigned short shop_size = 0; + nullpo_retr(3, sd); nullpo_retr(3, item_list); - - nd = npc_checknear(sd,iMap->id2bl(sd->npc_shopid)); + + nd = npc->checknear(sd,map->id2bl(sd->npc_shopid)); if( nd == NULL ) return 3; - if( nd->subtype != SHOP ) - return 3; - + + if( nd->subtype != SHOP ) { + if( nd->subtype == SCRIPT && nd->u.scr.shop && nd->u.scr.shop->type == NST_ZENY ) { + shop = nd->u.scr.shop->item; + shop_size = nd->u.scr.shop->items; + } else + return 3; + } else { + shop = nd->u.shop.shop_item; + shop_size = nd->u.shop.count; + } + z = 0; w = 0; new_ = 0; // process entries in buy list, one by one for( i = 0; i < n; ++i ) { int nameid, amount, value; - + // find this entry in the shop's sell list - ARR_FIND( 0, nd->u.shop.count, j, - item_list[i*2+1] == nd->u.shop.shop_item[j].nameid || //Normal items - item_list[i*2+1] == itemdb_viewid(nd->u.shop.shop_item[j].nameid) //item_avail replacement - ); - - if( j == nd->u.shop.count ) + ARR_FIND( 0, shop_size, j, + item_list[i*2+1] == shop[j].nameid || //Normal items + item_list[i*2+1] == itemdb_viewid(shop[j].nameid) //item_avail replacement + ); + + if( j == shop_size ) return 3; // no such item in shop - + amount = item_list[i*2+0]; - nameid = item_list[i*2+1] = nd->u.shop.shop_item[j].nameid; //item_avail replacement - value = nd->u.shop.shop_item[j].value; - - if( !itemdb_exists(nameid) ) + nameid = item_list[i*2+1] = shop[j].nameid; //item_avail replacement + value = shop[j].value; + + if( !itemdb->exists(nameid) ) return 3; // item no longer in itemdb - - if( !itemdb_isstackable(nameid) && amount > 1 ) { + + if( !itemdb->isstackable(nameid) && amount > 1 ) { //Exploit? You can't buy more than 1 of equipment types o.O - ShowWarning("Player %s (%d:%d) sent a hexed packet trying to buy %d of nonstackable item %d!\n", - sd->status.name, sd->status.account_id, sd->status.char_id, amount, nameid); + ShowWarning("Player %s (%d:%d) sent a hexed packet trying to buy %d of non-stackable item %d!\n", + sd->status.name, sd->status.account_id, sd->status.char_id, amount, nameid); amount = item_list[i*2+0] = 1; } - + if( nd->master_nd ) { // Script-controlled shops decide by themselves, what can be bought and for what price. continue; } - + switch( pc->checkadditem(sd,nameid,amount) ) { case ADDITEM_EXIST: break; - + case ADDITEM_NEW: new_++; break; - + case ADDITEM_OVERAMOUNT: return 2; } - + value = pc->modifybuyvalue(sd,value); - + z += (double)value * amount; w += itemdb_weight(nameid) * amount; } - + if( nd->master_nd != NULL ) //Script-based shops. - return npc_buylist_sub(sd,n,item_list,nd->master_nd); - + return npc->buylist_sub(sd,n,item_list,nd->master_nd); + if( z > (double)sd->status.zeny ) return 1; // Not enough Zeny if( w + sd->weight > sd->max_weight ) return 2; // Too heavy if( pc->inventoryblank(sd) < new_ ) return 3; // Not enough space to store items - + pc->payzeny(sd,(int)z,LOG_TYPE_NPC, NULL); - + for( i = 0; i < n; ++i ) { int nameid = item_list[i*2+1]; int amount = item_list[i*2+0]; struct item item_tmp; - + if (itemdb_type(nameid) == IT_PETEGG) - pet_create_egg(sd, nameid); + pet->create_egg(sd, nameid); else { memset(&item_tmp,0,sizeof(item_tmp)); item_tmp.nameid = nameid; item_tmp.identify = 1; - + pc->additem(sd,&item_tmp,amount,LOG_TYPE_NPC); } } - + // custom merchant shop exp bonus if( battle_config.shop_exp > 0 && z > 0 && (skill_t = pc->checkskill2(sd,idx)) > 0 ) { if( sd->status.skill[idx].flag >= SKILL_FLAG_REPLACED_LV_0 ) skill_t = sd->status.skill[idx].flag - SKILL_FLAG_REPLACED_LV_0; - + if( skill_t > 0 ) { z = z * (double)skill_t * (double)battle_config.shop_exp/10000.; if( z < 1 ) @@ -1599,13 +1843,123 @@ int npc_buylist(struct map_session_data* sd, int n, unsigned short* item_list) pc->gainexp(sd,NULL,0,(int)z, false); } } - + return 0; } +/** + * parses incoming npc market purchase list + **/ +int npc_market_buylist(struct map_session_data* sd, unsigned short list_size, struct packet_npc_market_purchase *p) { + struct npc_data* nd; + struct npc_item_list *shop = NULL; + double z; + int i,j,w,new_; + unsigned short shop_size = 0; + + nullpo_retr(1, sd); + nullpo_retr(1, p); + + nd = npc->checknear(sd,map->id2bl(sd->npc_shopid)); + + if( nd == NULL || nd->subtype != SCRIPT || !list_size || !nd->u.scr.shop || nd->u.scr.shop->type != NST_MARKET ) + return 1; + + shop = nd->u.scr.shop->item; + shop_size = nd->u.scr.shop->items; + + z = 0; + w = 0; + new_ = 0; + + // process entries in buy list, one by one + for( i = 0; i < list_size; ++i ) { + int nameid, amount, value; + + // find this entry in the shop's sell list + ARR_FIND( 0, shop_size, j, + p->list[i].ITID == shop[j].nameid || //Normal items + p->list[i].ITID == itemdb_viewid(shop[j].nameid) //item_avail replacement + ); + + if( j == shop_size ) /* TODO find official response for this */ + return 1; // no such item in shop + + if( p->list[i].qty > shop[j].qty ) + return 1; + + amount = p->list[i].qty; + nameid = p->list[i].ITID = shop[j].nameid; //item_avail replacement + value = shop[j].value; + npc_market_qty[i] = j; + + if( !itemdb->exists(nameid) ) /* TODO find official response for this */ + return 1; // item no longer in itemdb + + if( !itemdb->isstackable(nameid) && amount > 1 ) { + //Exploit? You can't buy more than 1 of equipment types o.O + ShowWarning("Player %s (%d:%d) sent a hexed packet trying to buy %d of non-stackable item %d!\n", + sd->status.name, sd->status.account_id, sd->status.char_id, amount, nameid); + amount = p->list[i].qty = 1; + } + + switch( pc->checkadditem(sd,nameid,amount) ) { + case ADDITEM_EXIST: + break; + + case ADDITEM_NEW: + new_++; + break; + + case ADDITEM_OVERAMOUNT: /* TODO find official response for this */ + return 1; + } + + z += (double)value * amount; + w += itemdb_weight(nameid) * amount; + } + + if( z > (double)sd->status.zeny ) /* TODO find official response for this */ + return 1; // Not enough Zeny + + if( w + sd->weight > sd->max_weight ) /* TODO find official response for this */ + return 1; // Too heavy + + if( pc->inventoryblank(sd) < new_ ) /* TODO find official response for this */ + return 1; // Not enough space to store items + + pc->payzeny(sd,(int)z,LOG_TYPE_NPC, NULL); + + for( i = 0; i < list_size; ++i ) { + int nameid = p->list[i].ITID; + int amount = p->list[i].qty; + struct item item_tmp; + + j = npc_market_qty[i]; + + if( p->list[i].qty > shop[j].qty ) /* wohoo someone tampered with the packet. */ + return 1; + + shop[j].qty -= amount; + + npc->market_tosql(nd,j); + + if (itemdb_type(nameid) == IT_PETEGG) + pet->create_egg(sd, nameid); + else { + memset(&item_tmp,0,sizeof(item_tmp)); + item_tmp.nameid = nameid; + item_tmp.identify = 1; + + pc->additem(sd,&item_tmp,amount,LOG_TYPE_NPC); + } + } + + return 0; +} /// npc_selllist for script-controlled shops -static int npc_selllist_sub(struct map_session_data* sd, int n, unsigned short* item_list, struct npc_data* nd) +int npc_selllist_sub(struct map_session_data* sd, int n, unsigned short* item_list, struct npc_data* nd) { char npc_ev[EVENT_NAME_LENGTH]; char card_slot[NAME_LENGTH]; @@ -1618,17 +1972,17 @@ static int npc_selllist_sub(struct map_session_data* sd, int n, unsigned short* int key_card[MAX_SLOTS]; // discard old contents - script_cleararray_pc(sd, "@sold_nameid", (void*)0); - script_cleararray_pc(sd, "@sold_quantity", (void*)0); - script_cleararray_pc(sd, "@sold_refine", (void*)0); - script_cleararray_pc(sd, "@sold_attribute", (void*)0); - script_cleararray_pc(sd, "@sold_identify", (void*)0); + script->cleararray_pc(sd, "@sold_nameid", (void*)0); + script->cleararray_pc(sd, "@sold_quantity", (void*)0); + script->cleararray_pc(sd, "@sold_refine", (void*)0); + script->cleararray_pc(sd, "@sold_attribute", (void*)0); + script->cleararray_pc(sd, "@sold_identify", (void*)0); for( j = 0; j < MAX_SLOTS; j++ ) {// clear each of the card slot entries key_card[j] = 0; snprintf(card_slot, sizeof(card_slot), "@sold_card%d", j + 1); - script_cleararray_pc(sd, card_slot, (void*)0); + script->cleararray_pc(sd, card_slot, (void*)0); } // save list of to be sold items @@ -1636,26 +1990,26 @@ static int npc_selllist_sub(struct map_session_data* sd, int n, unsigned short* { idx = item_list[i*2]-2; - script_setarray_pc(sd, "@sold_nameid", i, (void*)(intptr_t)sd->status.inventory[idx].nameid, &key_nameid); - script_setarray_pc(sd, "@sold_quantity", i, (void*)(intptr_t)item_list[i*2+1], &key_amount); + script->setarray_pc(sd, "@sold_nameid", i, (void*)(intptr_t)sd->status.inventory[idx].nameid, &key_nameid); + script->setarray_pc(sd, "@sold_quantity", i, (void*)(intptr_t)item_list[i*2+1], &key_amount); - if( itemdb_isequip(sd->status.inventory[idx].nameid) ) + if( itemdb->isequip(sd->status.inventory[idx].nameid) ) {// process equipment based information into the arrays - script_setarray_pc(sd, "@sold_refine", i, (void*)(intptr_t)sd->status.inventory[idx].refine, &key_refine); - script_setarray_pc(sd, "@sold_attribute", i, (void*)(intptr_t)sd->status.inventory[idx].attribute, &key_attribute); - script_setarray_pc(sd, "@sold_identify", i, (void*)(intptr_t)sd->status.inventory[idx].identify, &key_identify); + script->setarray_pc(sd, "@sold_refine", i, (void*)(intptr_t)sd->status.inventory[idx].refine, &key_refine); + script->setarray_pc(sd, "@sold_attribute", i, (void*)(intptr_t)sd->status.inventory[idx].attribute, &key_attribute); + script->setarray_pc(sd, "@sold_identify", i, (void*)(intptr_t)sd->status.inventory[idx].identify, &key_identify); for( j = 0; j < MAX_SLOTS; j++ ) {// store each of the cards from the equipment in the array snprintf(card_slot, sizeof(card_slot), "@sold_card%d", j + 1); - script_setarray_pc(sd, card_slot, i, (void*)(intptr_t)sd->status.inventory[idx].card[j], &key_card[j]); + script->setarray_pc(sd, card_slot, i, (void*)(intptr_t)sd->status.inventory[idx].card[j], &key_card[j]); } } } // invoke event snprintf(npc_ev, ARRAYLENGTH(npc_ev), "%s::OnSellItem", nd->exname); - npc_event(sd, npc_ev, 0); + npc->event(sd, npc_ev, 0); return 0; } @@ -1664,19 +2018,24 @@ static int npc_selllist_sub(struct map_session_data* sd, int n, unsigned short* /// /// @param item_list 'n' pairs <index,amount> /// @return result code for clif->parse_NpcSellListSend -int npc_selllist(struct map_session_data* sd, int n, unsigned short* item_list) -{ +int npc_selllist(struct map_session_data* sd, int n, unsigned short* item_list) { double z; - int i,skill_t, idx = skill->get_index(MC_OVERCHARGE); + int i,skill_t, skill_idx = skill->get_index(MC_OVERCHARGE); struct npc_data *nd; nullpo_retr(1, sd); nullpo_retr(1, item_list); - if( ( nd = npc_checknear(sd, iMap->id2bl(sd->npc_shopid)) ) == NULL || nd->subtype != SHOP ) { + if( ( nd = npc->checknear(sd, map->id2bl(sd->npc_shopid)) ) == NULL ) { return 1; } + if( nd->subtype != SHOP ) { + if( !(nd->subtype == SCRIPT && nd->u.scr.shop && nd->u.scr.shop->type == NST_ZENY) ) + return 1; + } + + z = 0; // verify the sell list @@ -1706,7 +2065,7 @@ int npc_selllist(struct map_session_data* sd, int n, unsigned short* item_list) } if( nd->master_nd ) { // Script-controlled shops - return npc_selllist_sub(sd, n, item_list, nd->master_nd); + return npc->selllist_sub(sd, n, item_list, nd->master_nd); } // delete items @@ -1717,8 +2076,8 @@ int npc_selllist(struct map_session_data* sd, int n, unsigned short* item_list) amount = item_list[i*2+1]; if( sd->inventory_data[idx]->type == IT_PETEGG && sd->status.inventory[idx].card[0] == CARD0_PET ) { - if( search_petDB_index(sd->status.inventory[idx].nameid, PET_EGG) >= 0 ) { - intif_delete_petdata(MakeDWord(sd->status.inventory[idx].card[1], sd->status.inventory[idx].card[2])); + if( pet->search_petDB_index(sd->status.inventory[idx].nameid, PET_EGG) >= 0 ) { + intif->delete_petdata(MakeDWord(sd->status.inventory[idx].card[1], sd->status.inventory[idx].card[2])); } } @@ -1731,9 +2090,9 @@ int npc_selllist(struct map_session_data* sd, int n, unsigned short* item_list) pc->getzeny(sd, (int)z, LOG_TYPE_NPC, NULL); // custom merchant shop exp bonus - if( battle_config.shop_exp > 0 && z > 0 && ( skill_t = pc->checkskill2(sd,idx) ) > 0) { - if( sd->status.skill[idx].flag >= SKILL_FLAG_REPLACED_LV_0 ) - skill_t = sd->status.skill[idx].flag - SKILL_FLAG_REPLACED_LV_0; + if( battle_config.shop_exp > 0 && z > 0 && ( skill_t = pc->checkskill2(sd,skill_idx) ) > 0) { + if( sd->status.skill[skill_idx].flag >= SKILL_FLAG_REPLACED_LV_0 ) + skill_t = sd->status.skill[skill_idx].flag - SKILL_FLAG_REPLACED_LV_0; if( skill_t > 0 ) { z = z * (double)skill_t * (double)battle_config.shop_exp/10000.; @@ -1754,103 +2113,122 @@ int npc_remove_map(struct npc_data* nd) { if(nd->bl.prev == NULL || nd->bl.m < 0) return 1; //Not assigned to a map. - m = nd->bl.m; + m = nd->bl.m; clif->clearunit_area(&nd->bl,CLR_RESPAWN); - npc_unsetcells(nd); - iMap->delblock(&nd->bl); - //Remove npc from map[].npc list. [Skotlex] - ARR_FIND( 0, map[m].npc_num, i, map[m].npc[i] == nd ); - if( i == map[m].npc_num ) return 2; //failed to find it? - - map[m].npc_num--; - map[m].npc[i] = map[m].npc[map[m].npc_num]; - map[m].npc[map[m].npc_num] = NULL; + npc->unsetcells(nd); + map->delblock(&nd->bl); + //Remove npc from map->list[].npc list. [Skotlex] + ARR_FIND( 0, map->list[m].npc_num, i, map->list[m].npc[i] == nd ); + if( i == map->list[m].npc_num ) return 2; //failed to find it? + + map->list[m].npc_num--; + map->list[m].npc[i] = map->list[m].npc[map->list[m].npc_num]; + map->list[m].npc[map->list[m].npc_num] = NULL; return 0; } /** * @see DBApply */ -static int npc_unload_ev(DBKey key, DBData *data, va_list ap) +int npc_unload_ev(DBKey key, DBData *data, va_list ap) { struct event_data* ev = DB->data2ptr(data); char* npcname = va_arg(ap, char *); if(strcmp(ev->nd->exname,npcname)==0){ - db_remove(ev_db, key); + db_remove(npc->ev_db, key); return 1; } return 0; } +/** + * @see DBApply + */ +int npc_unload_ev_label(DBKey key, DBData *data, va_list ap) +{ + struct linkdb_node **label_linkdb = DB->data2ptr(data); + struct npc_data* nd = va_arg(ap, struct npc_data *); + + linkdb_erase(label_linkdb, nd); + + return 0; +} + //Chk if npc matches src_id, then unload. //Sub-function used to find duplicates. -static int npc_unload_dup_sub(struct npc_data* nd, va_list args) +int npc_unload_dup_sub(struct npc_data* nd, va_list args) { int src_id; src_id = va_arg(args, int); if (nd->src_id == src_id) - npc_unload(nd, true); + npc->unload(nd, true); return 0; } //Removes all npcs that are duplicates of the passed one. [Skotlex] -void npc_unload_duplicates(struct npc_data* nd) -{ - iMap->map_foreachnpc(npc_unload_dup_sub,nd->bl.id); +void npc_unload_duplicates(struct npc_data* nd) { + map->foreachnpc(npc->unload_dup_sub,nd->bl.id); } //Removes an npc from map and db. //Single is to free name (for duplicates). int npc_unload(struct npc_data* nd, bool single) { + unsigned int i; + nullpo_ret(nd); - npc_remove_map(nd); - iMap->deliddb(&nd->bl); + npc->remove_map(nd); + map->deliddb(&nd->bl); if( single ) - strdb_remove(npcname_db, nd->exname); + strdb_remove(npc->name_db, nd->exname); if (nd->chat_id) // remove npc chatroom object and kick users - chat_deletenpcchat(nd); + chat->delete_npc_chat(nd); #ifdef PCRE_SUPPORT - npc_chat_finalize(nd); // deallocate npc PCRE data structures + npc_chat->finalize(nd); // deallocate npc PCRE data structures #endif if( single && nd->path ) { struct npc_path_data* npd = NULL; if( nd->path && nd->path != npc_last_ref ) { - npd = strdb_get(npc_path_db, nd->path); + npd = strdb_get(npc->path_db, nd->path); } if( npd && --npd->references == 0 ) { - strdb_remove(npc_path_db, nd->path);/* remove from db */ + strdb_remove(npc->path_db, nd->path);/* remove from db */ aFree(nd->path);/* remove now that no other instances exist */ } } + + if( single && nd->bl.m != -1 ) + map->remove_questinfo(nd->bl.m,nd); - if( (nd->subtype == SHOP || nd->subtype == CASHSHOP) && nd->src_id == 0) //src check for duplicate shops [Orcao] + if( nd->src_id == 0 && ( nd->subtype == SHOP || nd->subtype == CASHSHOP ) ) //src check for duplicate shops [Orcao] aFree(nd->u.shop.shop_item); else if( nd->subtype == SCRIPT ) { struct s_mapiterator* iter; struct block_list* bl; - if( single ) - ev_db->foreach(ev_db,npc_unload_ev,nd->exname); //Clean up all events related + if( single ) { + npc->ev_db->foreach(npc->ev_db,npc->unload_ev,nd->exname); //Clean up all events related + npc->ev_label_db->foreach(npc->ev_label_db,npc->unload_ev_label,nd); + } iter = mapit_geteachpc(); for( bl = (struct block_list*)mapit->first(iter); mapit->exists(iter); bl = (struct block_list*)mapit->next(iter) ) { struct map_session_data *sd = ((TBL_PC*)bl); if( sd && sd->npc_timer_id != INVALID_TIMER ) { - const struct TimerData *td = iTimer->get_timer(sd->npc_timer_id); + const struct TimerData *td = timer->get(sd->npc_timer_id); if( td && td->id != nd->bl.id ) continue; if( td && td->data ) - ers_free(timer_event_ers, (void*)td->data); - iTimer->delete_timer(sd->npc_timer_id, npc_timerevent); + ers_free(npc->timer_event_ers, (void*)td->data); + timer->delete(sd->npc_timer_id, npc->timerevent); sd->npc_timer_id = INVALID_TIMER; } } @@ -1858,17 +2236,16 @@ int npc_unload(struct npc_data* nd, bool single) { if (nd->u.scr.timerid != INVALID_TIMER) { const struct TimerData *td; - td = iTimer->get_timer(nd->u.scr.timerid); + td = timer->get(nd->u.scr.timerid); if (td && td->data) - ers_free(timer_event_ers, (void*)td->data); - iTimer->delete_timer(nd->u.scr.timerid, npc_timerevent); + ers_free(npc->timer_event_ers, (void*)td->data); + timer->delete(nd->u.scr.timerid, npc->timerevent); } if (nd->u.scr.timer_event) aFree(nd->u.scr.timer_event); if (nd->src_id == 0) { if(nd->u.scr.script) { - script_stop_instances(nd->bl.id); - script_free_code(nd->u.scr.script); + script->free_code(nd->u.scr.script); nd->u.scr.script = NULL; } if (nd->u.scr.label_list) { @@ -1876,16 +2253,30 @@ int npc_unload(struct npc_data* nd, bool single) { nd->u.scr.label_list = NULL; nd->u.scr.label_list_num = 0; } + if(nd->u.scr.shop) { + if(nd->u.scr.shop->item) + aFree(nd->u.scr.shop->item); + aFree(nd->u.scr.shop); + } } if( nd->u.scr.guild_id ) guild->flag_remove(nd); } - if( nd->ud != &npc_base_ud ) { + if( nd->ud != &npc->base_ud ) { aFree(nd->ud); nd->ud = NULL; } + for( i = 0; i < nd->hdatac; i++ ) { + if( nd->hdata[i]->flag.free ) { + aFree(nd->hdata[i]->data); + } + aFree(nd->hdata[i]); + } + if( nd->hdata ) + aFree(nd->hdata); + aFree(nd); return 0; @@ -1896,9 +2287,9 @@ int npc_unload(struct npc_data* nd, bool single) { // /// Clears the npc source file list -static void npc_clearsrcfile(void) +void npc_clearsrcfile(void) { - struct npc_src_list* file = npc_src_files; + struct npc_src_list* file = npc->src_files; struct npc_src_list* file_tofree; while( file != NULL ) @@ -1907,7 +2298,7 @@ static void npc_clearsrcfile(void) file = file->next; aFree(file_tofree); } - npc_src_files = NULL; + npc->src_files = NULL; } /// Adds a npc source file (or removes all) @@ -1918,12 +2309,12 @@ void npc_addsrcfile(const char* name) if( strcmpi(name, "clear") == 0 ) { - npc_clearsrcfile(); + npc->clearsrcfile(); return; } // prevent multiple insert of source files - file = npc_src_files; + file = npc->src_files; while( file != NULL ) { if( strcmp(name, file->name) == 0 ) @@ -1936,7 +2327,7 @@ void npc_addsrcfile(const char* name) file->next = NULL; safestrncpy(file->name, name, strlen(name) + 1); if( file_prev == NULL ) - npc_src_files = file; + npc->src_files = file; else file_prev->next = file; } @@ -1944,12 +2335,12 @@ void npc_addsrcfile(const char* name) /// Removes a npc source file (or all) void npc_delsrcfile(const char* name) { - struct npc_src_list* file = npc_src_files; + struct npc_src_list* file = npc->src_files; struct npc_src_list* file_prev = NULL; if( strcmpi(name, "all") == 0 ) { - npc_clearsrcfile(); + npc->clearsrcfile(); return; } @@ -1957,8 +2348,8 @@ void npc_delsrcfile(const char* name) { if( strcmp(file->name, name) == 0 ) { - if( npc_src_files == file ) - npc_src_files = file->next; + if( npc->src_files == file ) + npc->src_files = file->next; else file_prev->next = file->next; aFree(file); @@ -1971,8 +2362,7 @@ void npc_delsrcfile(const char* name) /// Parses and sets the name and exname of a npc. /// Assumes that m, x and y are already set in nd. -static void npc_parsename(struct npc_data* nd, const char* name, const char* start, const char* buffer, const char* filepath) -{ +void npc_parsename(struct npc_data* nd, const char* name, const char* start, const char* buffer, const char* filepath) { const char* p; struct npc_data* dnd;// duplicate npc char newname[NAME_LENGTH]; @@ -1982,7 +2372,7 @@ static void npc_parsename(struct npc_data* nd, const char* name, const char* sta if( p ) { // <Display name>::<Unique name> size_t len = p-name; if( len > NAME_LENGTH ) { - ShowWarning("npc_parsename: Display name of '%s' is too long (len=%u) in file '%s', line'%d'. Truncating to %u characters.\n", name, (unsigned int)len, filepath, strline(buffer,start-buffer), NAME_LENGTH); + ShowWarning("npc_parsename: Display name of '%s' is too long (len=%u) in file '%s', line '%d'. Truncating to %u characters.\n", name, (unsigned int)len, filepath, strline(buffer,start-buffer), NAME_LENGTH); safestrncpy(nd->name, name, sizeof(nd->name)); } else { memcpy(nd->name, name, len); @@ -1990,23 +2380,23 @@ static void npc_parsename(struct npc_data* nd, const char* name, const char* sta } len = strlen(p+2); if( len > NAME_LENGTH ) - ShowWarning("npc_parsename: Unique name of '%s' is too long (len=%u) in file '%s', line'%d'. Truncating to %u characters.\n", name, (unsigned int)len, filepath, strline(buffer,start-buffer), NAME_LENGTH); + ShowWarning("npc_parsename: Unique name of '%s' is too long (len=%u) in file '%s', line '%d'. Truncating to %u characters.\n", name, (unsigned int)len, filepath, strline(buffer,start-buffer), NAME_LENGTH); safestrncpy(nd->exname, p+2, sizeof(nd->exname)); } else {// <Display name> size_t len = strlen(name); if( len > NAME_LENGTH ) - ShowWarning("npc_parsename: Name '%s' is too long (len=%u) in file '%s', line'%d'. Truncating to %u characters.\n", name, (unsigned int)len, filepath, strline(buffer,start-buffer), NAME_LENGTH); + ShowWarning("npc_parsename: Name '%s' is too long (len=%u) in file '%s', line '%d'. Truncating to %u characters.\n", name, (unsigned int)len, filepath, strline(buffer,start-buffer), NAME_LENGTH); safestrncpy(nd->name, name, sizeof(nd->name)); safestrncpy(nd->exname, name, sizeof(nd->exname)); } if( *nd->exname == '\0' || strstr(nd->exname,"::") != NULL ) {// invalid snprintf(newname, ARRAYLENGTH(newname), "0_%d_%d_%d", nd->bl.m, nd->bl.x, nd->bl.y); - ShowWarning("npc_parsename: Invalid unique name in file '%s', line'%d'. Renaming '%s' to '%s'.\n", filepath, strline(buffer,start-buffer), nd->exname, newname); + ShowWarning("npc_parsename: Invalid unique name in file '%s', line '%d'. Renaming '%s' to '%s'.\n", filepath, strline(buffer,start-buffer), nd->exname, newname); safestrncpy(nd->exname, newname, sizeof(nd->exname)); } - if( (dnd=npc_name2id(nd->exname)) != NULL ) {// duplicate unique name, generate new one + if( (dnd=npc->name2id(nd->exname)) != NULL ) {// duplicate unique name, generate new one char this_mapname[32]; char other_mapname[32]; int i = 0; @@ -2014,12 +2404,12 @@ static void npc_parsename(struct npc_data* nd, const char* name, const char* sta do { ++i; snprintf(newname, ARRAYLENGTH(newname), "%d_%d_%d_%d", i, nd->bl.m, nd->bl.x, nd->bl.y); - } while( npc_name2id(newname) != NULL ); + } while( npc->name2id(newname) != NULL ); - strcpy(this_mapname, (nd->bl.m==-1?"(not on a map)":mapindex_id2name(map[nd->bl.m].index))); - strcpy(other_mapname, (dnd->bl.m==-1?"(not on a map)":mapindex_id2name(map[dnd->bl.m].index))); + strcpy(this_mapname, (nd->bl.m == -1 ? "(not on a map)" : mapindex_id2name(map_id2index(nd->bl.m)))); + strcpy(other_mapname, (dnd->bl.m == -1 ? "(not on a map)" : mapindex_id2name(map_id2index(dnd->bl.m)))); - ShowWarning("npc_parsename: Duplicate unique name in file '%s', line'%d'. Renaming '%s' to '%s'.\n", filepath, strline(buffer,start-buffer), nd->exname, newname); + ShowWarning("npc_parsename: Duplicate unique name in file '%s', line '%d'. Renaming '%s' to '%s'.\n", filepath, strline(buffer,start-buffer), nd->exname, newname); ShowDebug("this npc:\n display name '%s'\n unique name '%s'\n map=%s, x=%d, y=%d\n", nd->name, nd->exname, this_mapname, nd->bl.x, nd->bl.y); ShowDebug("other npc in '%s' :\n display name '%s'\n unique name '%s'\n map=%s, x=%d, y=%d\n",dnd->path, dnd->name, dnd->exname, other_mapname, dnd->bl.x, dnd->bl.y); safestrncpy(nd->exname, newname, sizeof(nd->exname)); @@ -2028,9 +2418,9 @@ static void npc_parsename(struct npc_data* nd, const char* name, const char* sta if( npc_last_path != filepath ) { struct npc_path_data * npd = NULL; - if( !(npd = strdb_get(npc_path_db,filepath) ) ) { + if( !(npd = strdb_get(npc->path_db,filepath) ) ) { CREATE(npd, struct npc_path_data, 1); - strdb_put(npc_path_db, filepath, npd); + strdb_put(npc->path_db, filepath, npd); CREATE(npd->path, char, strlen(filepath)+1); safestrncpy(npd->path, filepath, strlen(filepath)+1); @@ -2051,27 +2441,74 @@ static void npc_parsename(struct npc_data* nd, const char* name, const char* sta } } +// Parse View +// Support for using Constants in place of NPC View IDs. +int npc_parseview(const char* w4, const char* start, const char* buffer, const char* filepath) { + int val = -1, i = 0; + char viewid[1024]; // Max size of name from const.txt, see script->read_constdb. + + // Extract view ID / constant + while (w4[i] != '\0') { + if (ISSPACE(w4[i]) || w4[i] == '/' || w4[i] == ',') + break; + + i++; + } + + safestrncpy(viewid, w4, i+=1); + + // Check if view id is not an ID (only numbers). + if(!npc->viewisid(viewid)) + { + // Check if constant exists and get its value. + if(!script->get_constant(viewid, &val)) { + ShowWarning("npc_parseview: Invalid NPC constant '%s' specified in file '%s', line'%d'. Defaulting to INVISIBLE_CLASS. \n", viewid, filepath, strline(buffer,start-buffer)); + val = INVISIBLE_CLASS; + } + } else { + // NPC has an ID specified for view id. + val = atoi(w4); + } + + return val; +} + +// View is ID +// Checks if given view is an ID or constant. +bool npc_viewisid(const char * viewid) +{ + if(atoi(viewid) != -1) + { + // Loop through view, looking for non-numeric character. + while (*viewid) { + if (ISDIGIT(*viewid++) == 0) return false; + } + } + + return true; +} + //Add then display an npc warp on map struct npc_data* npc_add_warp(char* name, short from_mapid, short from_x, short from_y, short xs, short ys, unsigned short to_mapindex, short to_x, short to_y) { int i, flag = 0; struct npc_data *nd; CREATE(nd, struct npc_data, 1); - nd->bl.id = npc_get_new_npc_id(); - iMap->addnpc(from_mapid, nd); + nd->bl.id = npc->get_new_npc_id(); + map->addnpc(from_mapid, nd); nd->bl.prev = nd->bl.next = NULL; nd->bl.m = from_mapid; nd->bl.x = from_x; nd->bl.y = from_y; safestrncpy(nd->exname, name, ARRAYLENGTH(nd->exname)); - if (npc_name2id(nd->exname) != NULL) + if (npc->name2id(nd->exname) != NULL) flag = 1; if (flag == 1) snprintf(nd->exname, ARRAYLENGTH(nd->exname), "warp_%d_%d_%d", from_mapid, from_x, from_y); - for( i = 0; npc_name2id(nd->exname) != NULL; ++i ) + for( i = 0; npc->name2id(nd->exname) != NULL; ++i ) snprintf(nd->exname, ARRAYLENGTH(nd->exname), "warp%d_%d_%d_%d", i, from_mapid, from_x, from_y); safestrncpy(nd->name, nd->exname, ARRAYLENGTH(nd->name)); @@ -2088,20 +2525,19 @@ struct npc_data* npc_add_warp(char* name, short from_mapid, short from_x, short nd->u.warp.ys = xs; nd->bl.type = BL_NPC; nd->subtype = WARP; - npc_setcells(nd); - iMap->addblock(&nd->bl); - status_set_viewdata(&nd->bl, nd->class_); - nd->ud = &npc_base_ud; - if( map[nd->bl.m].users ) + npc->setcells(nd); + map->addblock(&nd->bl); + status->set_viewdata(&nd->bl, nd->class_); + nd->ud = &npc->base_ud; + if( map->list[nd->bl.m].users ) clif->spawn(&nd->bl); - strdb_put(npcname_db, nd->exname, nd); + strdb_put(npc->name_db, nd->exname, nd); return nd; } /// Parses a warp npc. -static const char* npc_parse_warp(char* w1, char* w2, char* w3, char* w4, const char* start, const char* buffer, const char* filepath) -{ +const char* npc_parse_warp(char* w1, char* w2, char* w3, char* w4, const char* start, const char* buffer, const char* filepath, int *retval) { int x, y, xs, ys, to_x, to_y, m; unsigned short i; char mapname[32], to_mapname[32]; @@ -2110,34 +2546,36 @@ static const char* npc_parse_warp(char* w1, char* w2, char* w3, char* w4, const // w1=<from map name>,<fromX>,<fromY>,<facing> // w4=<spanx>,<spany>,<to map name>,<toX>,<toY> if( sscanf(w1, "%31[^,],%d,%d", mapname, &x, &y) != 3 - || sscanf(w4, "%d,%d,%31[^,],%d,%d", &xs, &ys, to_mapname, &to_x, &to_y) != 5 ) - { + || sscanf(w4, "%d,%d,%31[^,],%d,%d", &xs, &ys, to_mapname, &to_x, &to_y) != 5 + ) { ShowError("npc_parse_warp: Invalid warp definition in file '%s', line '%d'.\n * w1=%s\n * w2=%s\n * w3=%s\n * w4=%s\n", filepath, strline(buffer,start-buffer), w1, w2, w3, w4); + if (retval) *retval = EXIT_FAILURE; return strchr(start,'\n');// skip and continue } - m = iMap->mapname2mapid(mapname); - i = mapindex_name2id(to_mapname); - if( i == 0 ) - { + m = map->mapname2mapid(mapname); + i = mapindex->name2id(to_mapname); + if( i == 0 ) { ShowError("npc_parse_warp: Unknown destination map in file '%s', line '%d' : %s\n * w1=%s\n * w2=%s\n * w3=%s\n * w4=%s\n", filepath, strline(buffer,start-buffer), to_mapname, w1, w2, w3, w4); + if (retval) *retval = EXIT_FAILURE; return strchr(start,'\n');// skip and continue } - if( m != -1 && ( x < 0 || x >= map[m].xs || y < 0 || y >= map[m].ys ) ) { - ShowError("npc_parse_warp: out-of-bounds coordinates (\"%s\",%d,%d), map is %dx%d, in file '%s', line '%d'\n", map[m].name, x, y, map[m].xs, map[m].ys,filepath,strline(buffer,start-buffer)); + if( m != -1 && ( x < 0 || x >= map->list[m].xs || y < 0 || y >= map->list[m].ys ) ) { + ShowError("npc_parse_warp: out-of-bounds coordinates (\"%s\",%d,%d), map is %dx%d, in file '%s', line '%d'\n", map->list[m].name, x, y, map->list[m].xs, map->list[m].ys,filepath,strline(buffer,start-buffer)); + if (retval) *retval = EXIT_FAILURE; return strchr(start,'\n');;//try next } CREATE(nd, struct npc_data, 1); - nd->bl.id = npc_get_new_npc_id(); - iMap->addnpc(m, nd); + nd->bl.id = npc->get_new_npc_id(); + map->addnpc(m, nd); nd->bl.prev = nd->bl.next = NULL; nd->bl.m = m; nd->bl.x = x; nd->bl.y = y; - npc_parsename(nd, w3, start, buffer, filepath); + npc->parsename(nd, w3, start, buffer, filepath); if (!battle_config.warp_point_debug) nd->class_ = WARP_CLASS; @@ -2153,86 +2591,108 @@ static const char* npc_parse_warp(char* w1, char* w2, char* w3, char* w4, const npc_warp++; nd->bl.type = BL_NPC; nd->subtype = WARP; - npc_setcells(nd); - iMap->addblock(&nd->bl); - status_set_viewdata(&nd->bl, nd->class_); - nd->ud = &npc_base_ud; - if( map[nd->bl.m].users ) + npc->setcells(nd); + map->addblock(&nd->bl); + status->set_viewdata(&nd->bl, nd->class_); + nd->ud = &npc->base_ud; + if( map->list[nd->bl.m].users ) clif->spawn(&nd->bl); - strdb_put(npcname_db, nd->exname, nd); + strdb_put(npc->name_db, nd->exname, nd); return strchr(start,'\n');// continue } -/// Parses a shop/cashshop npc. -static const char* npc_parse_shop(char* w1, char* w2, char* w3, char* w4, const char* start, const char* buffer, const char* filepath) -{ +/** + * Parses a SHOP/CASHSHOP npc + * @param retval Pointer to the status, used to know whether there was an error or not, if so it will be EXIT_FAILURE + * @retval Parsing position (currently only '\n') + **/ +const char* npc_parse_shop(char* w1, char* w2, char* w3, char* w4, const char* start, const char* buffer, const char* filepath, int *retval) { //TODO: could be rewritten to NOT need this temp array [ultramage] - #define MAX_SHOPITEM 100 - struct npc_item_list items[MAX_SHOPITEM]; + // We could use nd->u.shop.shop_item to store directly the items, but this could lead + // to unecessary memory usage by the server, using a temp dynamic array is the + // best way to do this without having to do multiple reallocs [Panikon] + struct npc_item_list *items = NULL; + size_t items_count = 40; // Starting items size + char *p; int x, y, dir, m, i; struct npc_data *nd; enum npc_subtype type; - if( strcmp(w1,"-") == 0 ) {// 'floating' shop? + if( strcmp(w1,"-") == 0 ) { + // 'floating' shop x = y = dir = 0; m = -1; } else {// w1=<map name>,<x>,<y>,<facing> char mapname[32]; if( sscanf(w1, "%31[^,],%d,%d,%d", mapname, &x, &y, &dir) != 4 - || strchr(w4, ',') == NULL ) - { + || strchr(w4, ',') == NULL + ) { ShowError("npc_parse_shop: Invalid shop definition in file '%s', line '%d'.\n * w1=%s\n * w2=%s\n * w3=%s\n * w4=%s\n", filepath, strline(buffer,start-buffer), w1, w2, w3, w4); + if (retval) *retval = EXIT_FAILURE; return strchr(start,'\n');// skip and continue } - m = iMap->mapname2mapid(mapname); + m = map->mapname2mapid(mapname); } - if( m != -1 && ( x < 0 || x >= map[m].xs || y < 0 || y >= map[m].ys ) ) { - ShowError("npc_parse_shop: out-of-bounds coordinates (\"%s\",%d,%d), map is %dx%d, in file '%s', line '%d'\n", map[m].name, x, y, map[m].xs, map[m].ys,filepath,strline(buffer,start-buffer)); - return strchr(start,'\n');;//try next + if( m != -1 && ( x < 0 || x >= map->list[m].xs || y < 0 || y >= map->list[m].ys ) ) { + ShowError("npc_parse_shop: out-of-bounds coordinates (\"%s\",%d,%d), map is %dx%d, in file '%s', line '%d'\n", map->list[m].name, x, y, map->list[m].xs, map->list[m].ys,filepath,strline(buffer,start-buffer)); + if (retval) *retval = EXIT_FAILURE; + return strchr(start,'\n');//try next } - if( !strcasecmp(w2,"cashshop") ) + if( strcmp(w2,"cashshop") == 0 ) type = CASHSHOP; else type = SHOP; + items = aMalloc(sizeof(items[0])*items_count); + p = strchr(w4,','); - for( i = 0; i < ARRAYLENGTH(items) && p; ++i ) - { + for( i = 0; p; ++i ) { int nameid, value; struct item_data* id; - if( sscanf(p, ",%d:%d", &nameid, &value) != 2 ) - { + + if( i == items_count-1 ) { // Grow array + items_count *= 2; + items = aRealloc(items, sizeof(items[0])*items_count); + } + + if( sscanf(p, ",%d:%d", &nameid, &value) != 2 ) { ShowError("npc_parse_shop: Invalid item definition in file '%s', line '%d'. Ignoring the rest of the line...\n * w1=%s\n * w2=%s\n * w3=%s\n * w4=%s\n", filepath, strline(buffer,start-buffer), w1, w2, w3, w4); + if (retval) *retval = EXIT_FAILURE; break; } - if( (id = itemdb_exists(nameid)) == NULL ) - { + if( (id = itemdb->exists(nameid)) == NULL ) { ShowWarning("npc_parse_shop: Invalid sell item in file '%s', line '%d' (id '%d').\n", filepath, strline(buffer,start-buffer), nameid); p = strchr(p+1,','); + if (retval) *retval = EXIT_FAILURE; continue; } - if( value < 0 ) - { + if( value < 0 ) { + if( value != -1 ) + ShowWarning("npc_parse_shop: Item %s [%d] with invalid selling value '%d' in file '%s', line '%d', defaulting to buy price...\n", + id->name, nameid, value, filepath, strline(buffer,start-buffer)); + if( type == SHOP ) value = id->value_buy; else value = 0; // Cashshop doesn't have a "buy price" in the item_db } - if( type == SHOP && value == 0 ) - { // NPC selling items for free! + if( type == SHOP && value == 0 ) { + // NPC selling items for free! ShowWarning("npc_parse_shop: Item %s [%d] is being sold for FREE in file '%s', line '%d'.\n", id->name, nameid, filepath, strline(buffer,start-buffer)); + if (retval) *retval = EXIT_FAILURE; } - if( type == SHOP && value*0.75 < id->value_sell*1.24 ) - {// Exploit possible: you can buy and sell back with profit - ShowWarning("npc_parse_shop: Item %s [%d] discounted buying price (%d->%d) is less than overcharged selling price (%d->%d) at file '%s', line '%d'.\n", + if( type == SHOP && value*0.75 < id->value_sell*1.24 ) { + // Exploit possible: you can buy and sell back with profit + ShowWarning("npc_parse_shop: Item %s [%d] discounted buying price (%d->%d) is less than overcharged selling price (%d->%d) in file '%s', line '%d'.\n", id->name, nameid, value, (int)(value*0.75), id->value_sell, (int)(id->value_sell*1.24), filepath, strline(buffer,start-buffer)); + if (retval) *retval = EXIT_FAILURE; } //for logs filters, atcommands and iteminfo script command if( id->maxchance == 0 ) @@ -2242,95 +2702,79 @@ static const char* npc_parse_shop(char* w1, char* w2, char* w3, char* w4, const items[i].value = value; p = strchr(p+1,','); } - if( i == 0 ) - { + if( i == 0 ) { ShowWarning("npc_parse_shop: Ignoring empty shop in file '%s', line '%d'.\n", filepath, strline(buffer,start-buffer)); + aFree(items); + if (retval) *retval = EXIT_FAILURE; return strchr(start,'\n');// continue } CREATE(nd, struct npc_data, 1); CREATE(nd->u.shop.shop_item, struct npc_item_list, i); - memcpy(nd->u.shop.shop_item, items, sizeof(struct npc_item_list)*i); + memcpy(nd->u.shop.shop_item, items, sizeof(items[0])*i); + aFree(items); + nd->u.shop.count = i; nd->bl.prev = nd->bl.next = NULL; nd->bl.m = m; nd->bl.x = x; nd->bl.y = y; - nd->bl.id = npc_get_new_npc_id(); - npc_parsename(nd, w3, start, buffer, filepath); - nd->class_ = m==-1?-1:atoi(w4); + nd->bl.id = npc->get_new_npc_id(); + npc->parsename(nd, w3, start, buffer, filepath); + nd->class_ = m == -1 ? -1 : npc->parseview(w4, start, buffer, filepath); nd->speed = 200; ++npc_shop; nd->bl.type = BL_NPC; nd->subtype = type; if( m >= 0 ) {// normal shop npc - iMap->addnpc(m,nd); - iMap->addblock(&nd->bl); - status_set_viewdata(&nd->bl, nd->class_); - nd->ud = &npc_base_ud; + map->addnpc(m,nd); + map->addblock(&nd->bl); + status->set_viewdata(&nd->bl, nd->class_); + nd->ud = &npc->base_ud; nd->dir = dir; - if( map[nd->bl.m].users ) + if( map->list[nd->bl.m].users ) clif->spawn(&nd->bl); - } else {// 'floating' shop? - iMap->addiddb(&nd->bl); + } else {// 'floating' shop + map->addiddb(&nd->bl); } - strdb_put(npcname_db, nd->exname, nd); + strdb_put(npc->name_db, nd->exname, nd); return strchr(start,'\n');// continue } -/** - * NPC other label - * Not sure, seem to add label in a chainlink - * @see DBApply - */ -int npc_convertlabel_db(DBKey key, DBData *data, va_list ap) -{ - const char* lname = (const char*)key.str; - int lpos = DB->data2i(data); - struct npc_label_list** label_list; - int* label_list_num; - const char* filepath; - struct npc_label_list* label; - const char *p; - int len; - - nullpo_ret(label_list = va_arg(ap,struct npc_label_list**)); - nullpo_ret(label_list_num = va_arg(ap,int*)); - nullpo_ret(filepath = va_arg(ap,const char*)); - - // In case of labels not terminated with ':', for user defined function support - p = lname; - while( ISALNUM(*p) || *p == '_' ) - ++p; - len = p-lname; - - // here we check if the label fit into the buffer - if( len > 23 ) - { - ShowError("npc_parse_script: label name longer than 23 chars! '%s'\n (%s)", lname, filepath); - return 0; - } - - if( *label_list == NULL ) - { - *label_list = (struct npc_label_list *) aCalloc (1, sizeof(struct npc_label_list)); - *label_list_num = 0; - } else - *label_list = (struct npc_label_list *) aRealloc (*label_list, sizeof(struct npc_label_list)*(*label_list_num+1)); - label = *label_list+*label_list_num; +void npc_convertlabel_db(struct npc_label_list* label_list, const char *filepath) { + int i; + + for( i = 0; i < script->label_count; i++ ) { + const char* lname = script->get_str(script->labels[i].key); + int lpos = script->labels[i].pos; + struct npc_label_list* label; + const char *p; + size_t len; + + // In case of labels not terminated with ':', for user defined function support + p = lname; - safestrncpy(label->name, lname, sizeof(label->name)); - label->pos = lpos; - ++(*label_list_num); + while( ISALNUM(*p) || *p == '_' ) + ++p; + len = p-lname; - return 0; + // here we check if the label fit into the buffer + if( len > 23 ) { + ShowError("npc_parse_script: label name longer than 23 chars! (%s) in file '%s'.\n", lname, filepath); + return; + } + + label = &label_list[i]; + + safestrncpy(label->name, lname, sizeof(label->name)); + label->pos = lpos; + } } // Skip the contents of a script. -static const char* npc_skip_script(const char* start, const char* buffer, const char* filepath) -{ +const char* npc_skip_script(const char* start, const char* buffer, const char* filepath, int *retval) { const char* p; int curly_count; @@ -2339,16 +2783,16 @@ static const char* npc_skip_script(const char* start, const char* buffer, const // initial bracket (assumes the previous part is ok) p = strchr(start,'{'); - if( p == NULL ) - { - ShowError("npc_skip_script: Missing left curly in file '%s', line'%d'.", filepath, strline(buffer,start-buffer)); + if( p == NULL ) { + ShowError("npc_skip_script: Missing left curly in file '%s', line '%d'.\n", filepath, strline(buffer,start-buffer)); + if (retval) *retval = EXIT_FAILURE; return NULL;// can't continue } // skip everything for( curly_count = 1; curly_count > 0 ; ) { - p = skip_space(p+1) ; + p = script->skip_space(p+1) ; if( *p == '}' ) {// right curly --curly_count; @@ -2361,23 +2805,23 @@ static const char* npc_skip_script(const char* start, const char* buffer, const {// string for( ++p; *p != '"' ; ++p ) { - if( *p == '\\' && (unsigned char)p[-1] <= 0x7e ) + if( *p == '\\' && (unsigned char)p[-1] <= 0x7e ) { ++p;// escape sequence (not part of a multibyte character) - else if( *p == '\0' ) - { - script_error(buffer, filepath, 0, "Unexpected end of string.", p); + } else if( *p == '\0' ) { + script->error(buffer, filepath, 0, "Unexpected end of string.", p); + if (retval) *retval = EXIT_FAILURE; return NULL;// can't continue - } - else if( *p == '\n' ) - { - script_error(buffer, filepath, 0, "Unexpected newline at string.", p); + } else if( *p == '\n' ) { + script->error(buffer, filepath, 0, "Unexpected newline at string.", p); + if (retval) *retval = EXIT_FAILURE; return NULL;// can't continue } } } else if( *p == '\0' ) {// end of buffer - ShowError("Missing %d right curlys at file '%s', line '%d'.\n", curly_count, filepath, strline(buffer,p-buffer)); + ShowError("Missing %d right curlys in file '%s', line '%d'.\n", curly_count, filepath, strline(buffer,p-buffer)); + if (retval) *retval = EXIT_FAILURE; return NULL;// can't continue } } @@ -2390,10 +2834,10 @@ static const char* npc_skip_script(const char* start, const char* buffer, const /// -%TAB%script%TAB%<NPC Name>%TAB%-1,{<code>} /// <map name>,<x>,<y>,<facing>%TAB%script%TAB%<NPC Name>%TAB%<sprite id>,{<code>} /// <map name>,<x>,<y>,<facing>%TAB%script%TAB%<NPC Name>%TAB%<sprite id>,<triggerX>,<triggerY>,{<code>} -static const char* npc_parse_script(char* w1, char* w2, char* w3, char* w4, const char* start, const char* buffer, const char* filepath, bool runOnInit) { - int x, y, dir = 0, m, xs = 0, ys = 0, class_ = 0; // [Valaris] thanks to fov +const char* npc_parse_script(char* w1, char* w2, char* w3, char* w4, const char* start, const char* buffer, const char* filepath, int options, int *retval) { + int x, y, dir = 0, m, xs = 0, ys = 0; // [Valaris] thanks to fov char mapname[32]; - struct script_code *script; + struct script_code *scriptroot; int i; const char* end; const char* script_start; @@ -2407,15 +2851,13 @@ static const char* npc_parse_script(char* w1, char* w2, char* w3, char* w4, cons x = 0; y = 0; m = -1; - } - else - {// npc in a map - if( sscanf(w1, "%31[^,],%d,%d,%d", mapname, &x, &y, &dir) != 4 ) - { + } else {// npc in a map + if( sscanf(w1, "%31[^,],%d,%d,%d", mapname, &x, &y, &dir) != 4 ) { ShowError("npc_parse_script: Invalid placement format for a script in file '%s', line '%d'. Skipping the rest of file...\n * w1=%s\n * w2=%s\n * w3=%s\n * w4=%s\n", filepath, strline(buffer,start-buffer), w1, w2, w3, w4); + if (retval) *retval = EXIT_FAILURE; return NULL;// unknown format, don't continue } - m = iMap->mapname2mapid(mapname); + m = map->mapname2mapid(mapname); } script_start = strstr(start,",{"); @@ -2423,34 +2865,33 @@ static const char* npc_parse_script(char* w1, char* w2, char* w3, char* w4, cons if( strstr(w4,",{") == NULL || script_start == NULL || (end != NULL && script_start > end) ) { ShowError("npc_parse_script: Missing left curly ',{' in file '%s', line '%d'. Skipping the rest of the file.\n * w1=%s\n * w2=%s\n * w3=%s\n * w4=%s\n", filepath, strline(buffer,start-buffer), w1, w2, w3, w4); + if (retval) *retval = EXIT_FAILURE; return NULL;// can't continue } ++script_start; - end = npc_skip_script(script_start, buffer, filepath); + end = npc->skip_script(script_start, buffer, filepath, retval); if( end == NULL ) return NULL;// (simple) parse error, don't continue - script = parse_script(script_start, filepath, strline(buffer,script_start-buffer), SCRIPT_USE_LABEL_DB); + scriptroot = script->parse(script_start, filepath, strline(buffer,script_start-buffer), SCRIPT_USE_LABEL_DB, retval); label_list = NULL; label_list_num = 0; - if( script ) - { - DBMap* label_db = script_get_label_db(); - label_db->foreach(label_db, npc_convertlabel_db, &label_list, &label_list_num, filepath); - db_clear(label_db); // not needed anymore, so clear the db + if( script->label_count ) { + CREATE(label_list,struct npc_label_list,script->label_count); + label_list_num = script->label_count; + npc->convertlabel_db(label_list,filepath); } CREATE(nd, struct npc_data, 1); - if( sscanf(w4, "%d,%d,%d", &class_, &xs, &ys) == 3 ) + if( sscanf(w4, "%*[^,],%d,%d", &xs, &ys) == 2 ) {// OnTouch area defined nd->u.scr.xs = xs; nd->u.scr.ys = ys; } else {// no OnTouch area - class_ = atoi(w4); nd->u.scr.xs = -1; nd->u.scr.ys = -1; } @@ -2459,57 +2900,61 @@ static const char* npc_parse_script(char* w1, char* w2, char* w3, char* w4, cons nd->bl.m = m; nd->bl.x = x; nd->bl.y = y; - npc_parsename(nd, w3, start, buffer, filepath); - nd->bl.id = npc_get_new_npc_id(); - nd->class_ = class_; + npc->parsename(nd, w3, start, buffer, filepath); + nd->bl.id = npc->get_new_npc_id(); + nd->class_ = m == -1 ? -1 : npc->parseview(w4, start, buffer, filepath); nd->speed = 200; - nd->u.scr.script = script; + nd->u.scr.script = scriptroot; nd->u.scr.label_list = label_list; nd->u.scr.label_list_num = label_list_num; - + if( options&NPO_TRADER ) + nd->u.scr.trader = true; + nd->u.scr.shop = NULL; + ++npc_script; nd->bl.type = BL_NPC; nd->subtype = SCRIPT; if( m >= 0 ) { - iMap->addnpc(m, nd); - nd->ud = &npc_base_ud; + map->addnpc(m, nd); + nd->ud = &npc->base_ud; nd->dir = dir; - npc_setcells(nd); - iMap->addblock(&nd->bl); - if( class_ >= 0 ) { - status_set_viewdata(&nd->bl, nd->class_); - if( map[nd->bl.m].users ) + npc->setcells(nd); + map->addblock(&nd->bl); + if( nd->class_ >= 0 ) { + status->set_viewdata(&nd->bl, nd->class_); + if( map->list[nd->bl.m].users ) clif->spawn(&nd->bl); } } else { - // we skip iMap->addnpc, but still add it to the list of ID's - iMap->addiddb(&nd->bl); + // we skip map->addnpc, but still add it to the list of ID's + map->addiddb(&nd->bl); } - strdb_put(npcname_db, nd->exname, nd); + strdb_put(npc->name_db, nd->exname, nd); //----------------------------------------- // Loop through labels to export them as necessary for (i = 0; i < nd->u.scr.label_list_num; i++) { - if (npc_event_export(nd, i)) { - ShowWarning("npc_parse_script : duplicate event %s::%s (%s)\n", + if (npc->event_export(nd, i)) { + ShowWarning("npc_parse_script: duplicate event %s::%s in file '%s'.\n", nd->exname, nd->u.scr.label_list[i].name, filepath); + if (retval) *retval = EXIT_FAILURE; } - npc_timerevent_export(nd, i); + npc->timerevent_export(nd, i); } nd->u.scr.timerid = INVALID_TIMER; - if( runOnInit ) { + if( options&NPO_ONINIT ) { char evname[EVENT_NAME_LENGTH]; struct event_data *ev; snprintf(evname, ARRAYLENGTH(evname), "%s::OnInit", nd->exname); - if( ( ev = (struct event_data*)strdb_get(ev_db, evname) ) ) { + if( ( ev = (struct event_data*)strdb_get(npc->ev_db, evname) ) ) { //Execute OnInit - run_script(nd->u.scr.script,ev->pos,0,nd->bl.id); + script->run(nd->u.scr.script,ev->pos,0,nd->bl.id); } } @@ -2523,9 +2968,9 @@ static const char* npc_parse_script(char* w1, char* w2, char* w3, char* w4, cons /// shop/cashshop/npc: <map name>,<x>,<y>,<facing>%TAB%duplicate(<name of target>)%TAB%<NPC Name>%TAB%<sprite id> /// npc: -%TAB%duplicate(<name of target>)%TAB%<NPC Name>%TAB%<sprite id>,<triggerX>,<triggerY> /// npc: <map name>,<x>,<y>,<facing>%TAB%duplicate(<name of target>)%TAB%<NPC Name>%TAB%<sprite id>,<triggerX>,<triggerY> -const char* npc_parse_duplicate(char* w1, char* w2, char* w3, char* w4, const char* start, const char* buffer, const char* filepath) -{ - int x, y, dir, m, xs = -1, ys = -1, class_ = 0; +/// !!Only NPO_ONINIT is available trough options!! +const char* npc_parse_duplicate(char* w1, char* w2, char* w3, char* w4, const char* start, const char* buffer, const char* filepath, int options, int *retval) { + int x, y, dir, m, xs = -1, ys = -1; char mapname[32]; char srcname[128]; int i; @@ -2543,14 +2988,16 @@ const char* npc_parse_duplicate(char* w1, char* w2, char* w3, char* w4, const ch // get the npc being duplicated if( w2[length-1] != ')' || length <= 11 || length-11 >= sizeof(srcname) ) {// does not match 'duplicate(%127s)', name is empty or too long - ShowError("npc_parse_script: bad duplicate name in file '%s', line '%d' : %s\n", filepath, strline(buffer,start-buffer), w2); + ShowError("npc_parse_script: bad duplicate name in file '%s', line '%d': %s\n", filepath, strline(buffer,start-buffer), w2); + if (retval) *retval = EXIT_FAILURE; return end;// next line, try to continue } safestrncpy(srcname, w2+10, length-10); - dnd = npc_name2id(srcname); + dnd = npc->name2id(srcname); if( dnd == NULL) { - ShowError("npc_parse_script: original npc not found for duplicate in file '%s', line '%d' : %s\n", filepath, strline(buffer,start-buffer), srcname); + ShowError("npc_parse_script: original npc not found for duplicate in file '%s', line '%d': %s\n", filepath, strline(buffer,start-buffer), srcname); + if (retval) *retval = EXIT_FAILURE; return end;// next line, try to continue } src_id = dnd->bl.id; @@ -2561,24 +3008,28 @@ const char* npc_parse_duplicate(char* w1, char* w2, char* w3, char* w4, const ch x = y = dir = 0; m = -1; } else { - if( sscanf(w1, "%31[^,],%d,%d,%d", mapname, &x, &y, &dir) != 4 )// <map name>,<x>,<y>,<facing> - { + int fields = sscanf(w1, "%31[^,],%d,%d,%d", mapname, &x, &y, &dir); + if( type == WARP && fields == 3 ) { // <map name>,<x>,<y> + dir = 0; + } else if( fields != 4 ) {// <map name>,<x>,<y>,<facing> ShowError("npc_parse_duplicate: Invalid placement format for duplicate in file '%s', line '%d'. Skipping line...\n * w1=%s\n * w2=%s\n * w3=%s\n * w4=%s\n", filepath, strline(buffer,start-buffer), w1, w2, w3, w4); + if (retval) *retval = EXIT_FAILURE; return end;// next line, try to continue } - m = iMap->mapname2mapid(mapname); + m = map->mapname2mapid(mapname); } - if( m != -1 && ( x < 0 || x >= map[m].xs || y < 0 || y >= map[m].ys ) ) { - ShowError("npc_parse_duplicate: out-of-bounds coordinates (\"%s\",%d,%d), map is %dx%d, in file '%s', line '%d'\n", map[m].name, x, y, map[m].xs, map[m].ys,filepath,strline(buffer,start-buffer)); + if( m != -1 && ( x < 0 || x >= map->list[m].xs || y < 0 || y >= map->list[m].ys ) ) { + ShowError("npc_parse_duplicate: out-of-bounds coordinates (\"%s\",%d,%d), map is %dx%d, in file '%s', line '%d'\n", map->list[m].name, x, y, map->list[m].xs, map->list[m].ys,filepath,strline(buffer,start-buffer)); + if (retval) *retval = EXIT_FAILURE; return end;//try next } if( type == WARP && sscanf(w4, "%d,%d", &xs, &ys) == 2 );// <spanx>,<spany> - else if( type == SCRIPT && sscanf(w4, "%d,%d,%d", &class_, &xs, &ys) == 3);// <sprite id>,<triggerX>,<triggerY> - else if( type != WARP ) class_ = atoi(w4);// <sprite id> - else { + else if( type == SCRIPT && sscanf(w4, "%*[^,],%d,%d", &xs, &ys) == 2);// <sprite id>,<triggerX>,<triggerY> + else if( type == WARP ) { ShowError("npc_parse_duplicate: Invalid span format for duplicate warp in file '%s', line '%d'. Skipping line...\n * w1=%s\n * w2=%s\n * w3=%s\n * w4=%s\n", filepath, strline(buffer,start-buffer), w1, w2, w3, w4); + if (retval) *retval = EXIT_FAILURE; return end;// next line, try to continue } @@ -2588,9 +3039,9 @@ const char* npc_parse_duplicate(char* w1, char* w2, char* w3, char* w4, const ch nd->bl.m = m; nd->bl.x = x; nd->bl.y = y; - npc_parsename(nd, w3, start, buffer, filepath); - nd->bl.id = npc_get_new_npc_id(); - nd->class_ = class_; + npc->parsename(nd, w3, start, buffer, filepath); + nd->bl.id = npc->get_new_npc_id(); + nd->class_ = m == -1 ? -1 : npc->parseview(w4, start, buffer, filepath); nd->speed = 200; nd->src_id = src_id; nd->bl.type = BL_NPC; @@ -2603,6 +3054,8 @@ const char* npc_parse_duplicate(char* w1, char* w2, char* w3, char* w4, const ch nd->u.scr.script = dnd->u.scr.script; nd->u.scr.label_list = dnd->u.scr.label_list; nd->u.scr.label_list_num = dnd->u.scr.label_list_num; + nd->u.scr.shop = dnd->u.scr.shop; + nd->u.scr.trader = dnd->u.scr.trader; break; case SHOP: @@ -2628,21 +3081,21 @@ const char* npc_parse_duplicate(char* w1, char* w2, char* w3, char* w4, const ch //Add the npc to its location if( m >= 0 ) { - iMap->addnpc(m, nd); - nd->ud = &npc_base_ud; + map->addnpc(m, nd); + nd->ud = &npc->base_ud; nd->dir = dir; - npc_setcells(nd); - iMap->addblock(&nd->bl); - if( class_ >= 0 ) { - status_set_viewdata(&nd->bl, nd->class_); - if( map[nd->bl.m].users ) + npc->setcells(nd); + map->addblock(&nd->bl); + if( nd->class_ >= 0 ) { + status->set_viewdata(&nd->bl, nd->class_); + if( map->list[nd->bl.m].users ) clif->spawn(&nd->bl); } } else { - // we skip iMap->addnpc, but still add it to the list of ID's - iMap->addiddb(&nd->bl); + // we skip map->addnpc, but still add it to the list of ID's + map->addiddb(&nd->bl); } - strdb_put(npcname_db, nd->exname, nd); + strdb_put(npc->name_db, nd->exname, nd); if( type != SCRIPT ) return end; @@ -2650,43 +3103,58 @@ const char* npc_parse_duplicate(char* w1, char* w2, char* w3, char* w4, const ch //----------------------------------------- // Loop through labels to export them as necessary for (i = 0; i < nd->u.scr.label_list_num; i++) { - if (npc_event_export(nd, i)) { - ShowWarning("npc_parse_duplicate : duplicate event %s::%s (%s)\n", + if (npc->event_export(nd, i)) { + ShowWarning("npc_parse_duplicate: duplicate event %s::%s in file '%s'.\n", nd->exname, nd->u.scr.label_list[i].name, filepath); + if (retval) *retval = EXIT_FAILURE; } - npc_timerevent_export(nd, i); + npc->timerevent_export(nd, i); } nd->u.scr.timerid = INVALID_TIMER; + if( type == SCRIPT && options&NPO_ONINIT ) { + // From npc_parse_script + char evname[EVENT_NAME_LENGTH]; + struct event_data *ev; + + snprintf(evname, ARRAYLENGTH(evname), "%s::OnInit", nd->exname); + + if( ( ev = (struct event_data*)strdb_get(npc->ev_db, evname) ) ) { + + //Execute OnInit + script->run(nd->u.scr.script,ev->pos,0,nd->bl.id); + + } + } return end; } int npc_duplicate4instance(struct npc_data *snd, int16 m) { char newname[NAME_LENGTH]; - if( map[m].instance_id == -1 ) + if( m == -1 || map->list[m].instance_id == -1 ) return 1; - snprintf(newname, ARRAYLENGTH(newname), "dup_%d_%d", map[m].instance_id, snd->bl.id); - if( npc_name2id(newname) != NULL ) { // Name already in use - ShowError("npc_duplicate4instance: the npcname (%s) is already in use while trying to duplicate npc %s in instance %d.\n", newname, snd->exname, map[m].instance_id); + snprintf(newname, ARRAYLENGTH(newname), "dup_%d_%d", map->list[m].instance_id, snd->bl.id); + if( npc->name2id(newname) != NULL ) { // Name already in use + ShowError("npc_duplicate4instance: the npcname (%s) is already in use while trying to duplicate npc %s in instance %d.\n", newname, snd->exname, map->list[m].instance_id); return 1; } if( snd->subtype == WARP ) { // Adjust destination, if instanced struct npc_data *wnd = NULL; // New NPC - int dm = iMap->mapindex2mapid(snd->u.warp.mapindex), im; + int dm = map->mapindex2mapid(snd->u.warp.mapindex), im; if( dm < 0 ) return 1; - if( ( im = instance->mapid2imapid(dm, map[m].instance_id) ) == -1 ) { - ShowError("npc_duplicate4instance: warp (%s) leading to instanced map (%s), but instance map is not attached to current instance.\n", map[dm].name, snd->exname); + if( ( im = instance->mapid2imapid(dm, map->list[m].instance_id) ) == -1 ) { + ShowError("npc_duplicate4instance: warp (%s) leading to instanced map (%s), but instance map is not attached to current instance.\n", map->list[dm].name, snd->exname); return 1; } CREATE(wnd, struct npc_data, 1); - wnd->bl.id = npc_get_new_npc_id(); - iMap->addnpc(m, wnd); + wnd->bl.id = npc->get_new_npc_id(); + map->addnpc(m, wnd); wnd->bl.prev = wnd->bl.next = NULL; wnd->bl.m = m; wnd->bl.x = snd->bl.x; @@ -2702,18 +3170,18 @@ int npc_duplicate4instance(struct npc_data *snd, int16 m) { wnd->u.warp.ys = snd->u.warp.ys; wnd->bl.type = BL_NPC; wnd->subtype = WARP; - npc_setcells(wnd); - iMap->addblock(&wnd->bl); - status_set_viewdata(&wnd->bl, wnd->class_); - wnd->ud = &npc_base_ud; - if( map[wnd->bl.m].users ) + npc->setcells(wnd); + map->addblock(&wnd->bl); + status->set_viewdata(&wnd->bl, wnd->class_); + wnd->ud = &npc->base_ud; + if( map->list[wnd->bl.m].users ) clif->spawn(&wnd->bl); - strdb_put(npcname_db, wnd->exname, wnd); + strdb_put(npc->name_db, wnd->exname, wnd); } else { static char w1[50], w2[50], w3[50], w4[50]; const char* stat_buf = "- call from instancing subsystem -\n"; - snprintf(w1, sizeof(w1), "%s,%d,%d,%d", map[m].name, snd->bl.x, snd->bl.y, snd->dir); + snprintf(w1, sizeof(w1), "%s,%d,%d,%d", map->list[m].name, snd->bl.x, snd->bl.y, snd->dir); snprintf(w2, sizeof(w2), "duplicate(%s)", snd->exname); snprintf(w3, sizeof(w3), "%s::%s", snd->name, newname); @@ -2722,7 +3190,7 @@ int npc_duplicate4instance(struct npc_data *snd, int16 m) { else snprintf(w4, sizeof(w4), "%d", snd->class_); - npc_parse_duplicate(w1, w2, w3, w4, stat_buf, stat_buf, "INSTANCING"); + npc->parse_duplicate(w1, w2, w3, w4, stat_buf, stat_buf, "INSTANCING", NPO_NONE, NULL); } return 0; @@ -2746,14 +3214,14 @@ void npc_setcells(struct npc_data* nd) { return; // Other types doesn't have touch area } - if (m < 0 || xs < 0 || ys < 0 || map[m].cell == (struct mapcell *)0xdeadbeaf) //invalid range or map + if (m < 0 || xs < 0 || ys < 0 || map->list[m].cell == (struct mapcell *)0xdeadbeaf) //invalid range or map return; for (i = y-ys; i <= y+ys; i++) { for (j = x-xs; j <= x+xs; j++) { - if (iMap->getcell(m, j, i, CELL_CHKNOPASS)) + if (map->getcell(m, j, i, CELL_CHKNOPASS)) continue; - map[m].setcell(m, j, i, CELL_NPC, true); + map->list[m].setcell(m, j, i, CELL_NPC, true); } } } @@ -2762,7 +3230,7 @@ int npc_unsetcells_sub(struct block_list* bl, va_list ap) { struct npc_data *nd = (struct npc_data*)bl; int id = va_arg(ap,int); if (nd->bl.id == id) return 0; - npc_setcells(nd); + npc->setcells(nd); return 1; } @@ -2770,44 +3238,49 @@ void npc_unsetcells(struct npc_data* nd) { int16 m = nd->bl.m, x = nd->bl.x, y = nd->bl.y, xs, ys; int i,j, x0, x1, y0, y1; - if (nd->subtype == WARP) { - xs = nd->u.warp.xs; - ys = nd->u.warp.ys; - } else { - xs = nd->u.scr.xs; - ys = nd->u.scr.ys; + switch(nd->subtype) { + case WARP: + xs = nd->u.warp.xs; + ys = nd->u.warp.ys; + break; + case SCRIPT: + xs = nd->u.scr.xs; + ys = nd->u.scr.ys; + break; + default: + return; // Other types doesn't have touch area } - if (m < 0 || xs < 0 || ys < 0 || map[m].cell == (struct mapcell *)0xdeadbeaf) + if (m < 0 || xs < 0 || ys < 0 || map->list[m].cell == (struct mapcell *)0xdeadbeaf) return; //Locate max range on which we can locate npc cells //FIXME: does this really do what it's supposed to do? [ultramage] - for(x0 = x-xs; x0 > 0 && iMap->getcell(m, x0, y, CELL_CHKNPC); x0--); - for(x1 = x+xs; x1 < map[m].xs-1 && iMap->getcell(m, x1, y, CELL_CHKNPC); x1++); - for(y0 = y-ys; y0 > 0 && iMap->getcell(m, x, y0, CELL_CHKNPC); y0--); - for(y1 = y+ys; y1 < map[m].ys-1 && iMap->getcell(m, x, y1, CELL_CHKNPC); y1++); + for(x0 = x-xs; x0 > 0 && map->getcell(m, x0, y, CELL_CHKNPC); x0--); + for(x1 = x+xs; x1 < map->list[m].xs-1 && map->getcell(m, x1, y, CELL_CHKNPC); x1++); + for(y0 = y-ys; y0 > 0 && map->getcell(m, x, y0, CELL_CHKNPC); y0--); + for(y1 = y+ys; y1 < map->list[m].ys-1 && map->getcell(m, x, y1, CELL_CHKNPC); y1++); //Erase this npc's cells for (i = y-ys; i <= y+ys; i++) for (j = x-xs; j <= x+xs; j++) - map[m].setcell(m, j, i, CELL_NPC, false); + map->list[m].setcell(m, j, i, CELL_NPC, false); //Re-deploy NPC cells for other nearby npcs. - iMap->foreachinarea( npc_unsetcells_sub, m, x0, y0, x1, y1, BL_NPC, nd->bl.id ); + map->foreachinarea( npc->unsetcells_sub, m, x0, y0, x1, y1, BL_NPC, nd->bl.id ); } void npc_movenpc(struct npc_data* nd, int16 x, int16 y) { const int16 m = nd->bl.m; - if (m < 0 || nd->bl.prev == NULL) return; //Not on a map. + if (m < 0 || nd->bl.prev == NULL) return; //Not on a map. - x = cap_value(x, 0, map[m].xs-1); - y = cap_value(y, 0, map[m].ys-1); + x = cap_value(x, 0, map->list[m].xs-1); + y = cap_value(y, 0, map->list[m].ys-1); - iMap->foreachinrange(clif->outsight, &nd->bl, AREA_SIZE, BL_PC, &nd->bl); - iMap->moveblock(&nd->bl, x, y, iTimer->gettick()); - iMap->foreachinrange(clif->insight, &nd->bl, AREA_SIZE, BL_PC, &nd->bl); + map->foreachinrange(clif->outsight, &nd->bl, AREA_SIZE, BL_PC, &nd->bl); + map->moveblock(&nd->bl, x, y, timer->gettick()); + map->foreachinrange(clif->insight, &nd->bl, AREA_SIZE, BL_PC, &nd->bl); } /// Changes the display name of the npc. @@ -2819,7 +3292,7 @@ void npc_setdisplayname(struct npc_data* nd, const char* newname) nullpo_retv(nd); safestrncpy(nd->name, newname, sizeof(nd->name)); - if( map[nd->bl.m].users ) + if( map->list[nd->bl.m].users ) clif->charnameack(0, &nd->bl); } @@ -2827,25 +3300,24 @@ void npc_setdisplayname(struct npc_data* nd, const char* newname) /// /// @param nd Target npc /// @param class_ New display class -void npc_setclass(struct npc_data* nd, short class_) -{ +void npc_setclass(struct npc_data* nd, short class_) { nullpo_retv(nd); if( nd->class_ == class_ ) return; - if( map[nd->bl.m].users ) + if( map->list[nd->bl.m].users ) clif->clearunit_area(&nd->bl, CLR_OUTSIGHT);// fade out nd->class_ = class_; - status_set_viewdata(&nd->bl, class_); - if( map[nd->bl.m].users ) + status->set_viewdata(&nd->bl, class_); + if( map->list[nd->bl.m].users ) clif->spawn(&nd->bl);// fade in } // @commands (script based) int npc_do_atcmd_event(struct map_session_data* sd, const char* command, const char* message, const char* eventname) { - struct event_data* ev = (struct event_data*)strdb_get(ev_db, eventname); + struct event_data* ev = (struct event_data*)strdb_get(npc->ev_db, eventname); struct npc_data *nd; struct script_state *st; int i = 0, j = 0, k = 0; @@ -2859,7 +3331,6 @@ int npc_do_atcmd_event(struct map_session_data* sd, const char* command, const c } if( sd->npc_id != 0 ) { // Enqueue the event trigger. - int i; ARR_FIND( 0, MAX_EVENTQUEUE, i, sd->eventqueue[i][0] == '\0' ); if( i < MAX_EVENTQUEUE ) { safestrncpy(sd->eventqueue[i],eventname,50); //Event enqueued. @@ -2871,12 +3342,12 @@ int npc_do_atcmd_event(struct map_session_data* sd, const char* command, const c } if( ev->nd->option&OPTION_INVISIBLE ) { // Disabled npc, shouldn't trigger event. - npc_event_dequeue(sd); + npc->event_dequeue(sd); return 2; } - st = script_alloc_state(ev->nd->u.scr.script, ev->pos, sd->bl.id, ev->nd->bl.id); - setd_sub(st, NULL, ".@atcmd_command$", 0, (void *)command, NULL); + st = script->alloc_state(ev->nd->u.scr.script, ev->pos, sd->bl.id, ev->nd->bl.id); + script->setd_sub(st, NULL, ".@atcmd_command$", 0, (void *)command, NULL); // split atcmd parameters based on spaces temp = (char*)aMalloc(strlen(message) + 1); @@ -2889,7 +3360,7 @@ int npc_do_atcmd_event(struct map_session_data* sd, const char* command, const c temp[k] = '\0'; k = 0; if( temp[0] != '\0' ) { - setd_sub( st, NULL, ".@atcmd_parameters$", j++, (void *)temp, NULL ); + script->setd_sub( st, NULL, ".@atcmd_parameters$", j++, (void *)temp, NULL ); } } else { temp[k] = message[i]; @@ -2897,46 +3368,44 @@ int npc_do_atcmd_event(struct map_session_data* sd, const char* command, const c } } - setd_sub(st, NULL, ".@atcmd_numparameters", 0, (void *)__64BPTRSIZE(j), NULL); + script->setd_sub(st, NULL, ".@atcmd_numparameters", 0, (void *)h64BPTRSIZE(j), NULL); aFree(temp); - run_script_main(st); + script->run_main(st); return 0; } /// Parses a function. /// function%TAB%script%TAB%<function name>%TAB%{<code>} -static const char* npc_parse_function(char* w1, char* w2, char* w3, char* w4, const char* start, const char* buffer, const char* filepath) -{ +const char* npc_parse_function(char* w1, char* w2, char* w3, char* w4, const char* start, const char* buffer, const char* filepath, int *retval) { DBMap* func_db; DBData old_data; - struct script_code *script; + struct script_code *scriptroot; const char* end; const char* script_start; script_start = strstr(start,"\t{"); end = strchr(start,'\n'); - if( *w4 != '{' || script_start == NULL || (end != NULL && script_start > end) ) - { + if( *w4 != '{' || script_start == NULL || (end != NULL && script_start > end) ) { ShowError("npc_parse_function: Missing left curly '%%TAB%%{' in file '%s', line '%d'. Skipping the rest of the file.\n * w1=%s\n * w2=%s\n * w3=%s\n * w4=%s\n", filepath, strline(buffer,start-buffer), w1, w2, w3, w4); + if (retval) *retval = EXIT_FAILURE; return NULL;// can't continue } ++script_start; - end = npc_skip_script(script_start,buffer,filepath); + end = npc->skip_script(script_start,buffer,filepath, retval); if( end == NULL ) return NULL;// (simple) parse error, don't continue - script = parse_script(script_start, filepath, strline(buffer,start-buffer), SCRIPT_RETURN_EMPTY_SCRIPT); - if( script == NULL )// parse error, continue + scriptroot = script->parse(script_start, filepath, strline(buffer,start-buffer), SCRIPT_RETURN_EMPTY_SCRIPT, retval); + if( scriptroot == NULL )// parse error, continue return end; - func_db = script_get_userfunc_db(); - if (func_db->put(func_db, DB->str2key(w3), DB->ptr2data(script), &old_data)) - { + func_db = script->userfunc_db; + if (func_db->put(func_db, DB->str2key(w3), DB->ptr2data(scriptroot), &old_data)) { struct script_code *oldscript = (struct script_code*)DB->data2ptr(&old_data); - ShowInfo("npc_parse_function: Overwriting user function [%s] (%s:%d)\n", w3, filepath, strline(buffer,start-buffer)); - script_free_vars(oldscript->script_vars); + 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); aFree(oldscript); } @@ -2950,143 +3419,142 @@ static const char* npc_parse_function(char* w1, char* w2, char* w3, char* w4, co * Parse Mob 2 - Actually Spawns Mob * [Wizputer] *------------------------------------------*/ -void npc_parse_mob2(struct spawn_data* mob) +void npc_parse_mob2(struct spawn_data* mobspawn) { int i; - for( i = mob->active; i < mob->num; ++i ) { - struct mob_data* md = mob_spawn_dataset(mob); - md->spawn = mob; + for( i = mobspawn->active; i < mobspawn->num; ++i ) { + struct mob_data* md = mob->spawn_dataset(mobspawn); + md->spawn = mobspawn; md->spawn->active++; - mob_spawn(md); + mob->spawn(md); } } -static const char* npc_parse_mob(char* w1, char* w2, char* w3, char* w4, const char* start, const char* buffer, const char* filepath) -{ +const char* npc_parse_mob(char* w1, char* w2, char* w3, char* w4, const char* start, const char* buffer, const char* filepath, int *retval) { int num, class_, m,x,y,xs,ys, i,j; int mob_lv = -1, ai = -1, size = -1; char mapname[32], mobname[NAME_LENGTH]; - struct spawn_data mob, *data; + struct spawn_data mobspawn, *data; struct mob_db* db; - memset(&mob, 0, sizeof(struct spawn_data)); + memset(&mobspawn, 0, sizeof(struct spawn_data)); - mob.state.boss = !strcmpi(w2,"boss_monster"); + mobspawn.state.boss = (strcmp(w2,"boss_monster") == 0 ? 1 : 0); // w1=<map name>,<x>,<y>,<xs>,<ys> // w3=<mob name>{,<mob level>} // w4=<mob id>,<amount>,<delay1>,<delay2>,<event>{,<mob size>,<mob ai>} if( sscanf(w1, "%31[^,],%d,%d,%d,%d", mapname, &x, &y, &xs, &ys) < 3 - || sscanf(w3, "%23[^,],%d", mobname, &mob_lv) < 1 - || sscanf(w4, "%d,%d,%u,%u,%127[^,],%d,%d[^\t\r\n]", &class_, &num, &mob.delay1, &mob.delay2, mob.eventname, &size, &ai) < 2 ) - { + || sscanf(w3, "%23[^,],%d", mobname, &mob_lv) < 1 + || sscanf(w4, "%d,%d,%u,%u,%127[^,],%d,%d[^\t\r\n]", &class_, &num, &mobspawn.delay1, &mobspawn.delay2, mobspawn.eventname, &size, &ai) < 2 + ) { ShowError("npc_parse_mob: Invalid mob definition in file '%s', line '%d'.\n * w1=%s\n * w2=%s\n * w3=%s\n * w4=%s\n", filepath, strline(buffer,start-buffer), w1, w2, w3, w4); + if (retval) *retval = EXIT_FAILURE; return strchr(start,'\n');// skip and continue } - if( mapindex_name2id(mapname) == 0 ) - { + if( mapindex->name2id(mapname) == 0 ) { ShowError("npc_parse_mob: Unknown map '%s' in file '%s', line '%d'.\n", mapname, filepath, strline(buffer,start-buffer)); + if (retval) *retval = EXIT_FAILURE; return strchr(start,'\n');// skip and continue } - m = iMap->mapname2mapid(mapname); + m = map->mapname2mapid(mapname); if( m < 0 )//Not loaded on this map-server instance. return strchr(start,'\n');// skip and continue - mob.m = (unsigned short)m; + mobspawn.m = (unsigned short)m; - if( x < 0 || x >= map[mob.m].xs || y < 0 || y >= map[mob.m].ys ) - { - ShowError("npc_parse_mob: Spawn coordinates out of range: %s (%d,%d), map size is (%d,%d) - %s %s (file '%s', line '%d').\n", map[mob.m].name, x, y, (map[mob.m].xs-1), (map[mob.m].ys-1), w1, w3, filepath, strline(buffer,start-buffer)); + if( x < 0 || x >= map->list[mobspawn.m].xs || y < 0 || y >= map->list[mobspawn.m].ys ) { + ShowError("npc_parse_mob: Spawn coordinates out of range: %s (%d,%d), map size is (%d,%d) - %s %s in file '%s', line '%d'.\n", map->list[mobspawn.m].name, x, y, (map->list[mobspawn.m].xs-1), (map->list[mobspawn.m].ys-1), w1, w3, filepath, strline(buffer,start-buffer)); + if (retval) *retval = EXIT_FAILURE; return strchr(start,'\n');// skip and continue } // check monster ID if exists! - if( mobdb_checkid(class_) == 0 ) - { - ShowError("npc_parse_mob: Unknown mob ID %d (file '%s', line '%d').\n", class_, filepath, strline(buffer,start-buffer)); + if( mob->db_checkid(class_) == 0 ) { + ShowError("npc_parse_mob: Unknown mob ID %d in file '%s', line '%d'.\n", class_, filepath, strline(buffer,start-buffer)); + if (retval) *retval = EXIT_FAILURE; return strchr(start,'\n');// skip and continue } - if( num < 1 || num > 1000 ) - { - ShowError("npc_parse_mob: Invalid number of monsters %d, must be inside the range [1,1000] (file '%s', line '%d').\n", num, filepath, strline(buffer,start-buffer)); + if( num < 1 || num > 1000 ) { + ShowError("npc_parse_mob: Invalid number of monsters %d, must be inside the range [1,1000] in file '%s', line '%d'.\n", num, filepath, strline(buffer,start-buffer)); + if (retval) *retval = EXIT_FAILURE; return strchr(start,'\n');// skip and continue } - if( (mob.state.size < 0 || mob.state.size > 2) && size != -1 ) - { - ShowError("npc_parse_mob: Invalid size number %d for mob ID %d (file '%s', line '%d').\n", mob.state.size, class_, filepath, strline(buffer, start - buffer)); + if( (mobspawn.state.size < 0 || mobspawn.state.size > 2) && size != -1 ) { + ShowError("npc_parse_mob: Invalid size number %d for mob ID %d in file '%s', line '%d'.\n", mobspawn.state.size, class_, filepath, strline(buffer, start - buffer)); + if (retval) *retval = EXIT_FAILURE; return strchr(start, '\n'); } - if( (mob.state.ai < 0 || mob.state.ai > 4) && ai != -1 ) - { - ShowError("npc_parse_mob: Invalid ai %d for mob ID %d (file '%s', line '%d').\n", mob.state.ai, class_, filepath, strline(buffer, start - buffer)); + if( (mobspawn.state.ai < 0 || mobspawn.state.ai > 4) && ai != -1 ) { + ShowError("npc_parse_mob: Invalid ai %d for mob ID %d in file '%s', line '%d'.\n", mobspawn.state.ai, class_, filepath, strline(buffer, start - buffer)); + if (retval) *retval = EXIT_FAILURE; return strchr(start, '\n'); } - if( (mob_lv == 0 || mob_lv > MAX_LEVEL) && mob_lv != -1 ) - { - ShowError("npc_parse_mob: Invalid level %d for mob ID %d (file '%s', line '%d').\n", mob_lv, class_, filepath, strline(buffer, start - buffer)); + if( (mob_lv == 0 || mob_lv > MAX_LEVEL) && mob_lv != -1 ) { + ShowError("npc_parse_mob: Invalid level %d for mob ID %d in file '%s', line '%d'.\n", mob_lv, class_, filepath, strline(buffer, start - buffer)); + if (retval) *retval = EXIT_FAILURE; return strchr(start, '\n'); } - mob.num = (unsigned short)num; - mob.active = 0; - mob.class_ = (short) class_; - mob.x = (unsigned short)x; - mob.y = (unsigned short)y; - mob.xs = (signed short)xs; - mob.ys = (signed short)ys; + mobspawn.num = (unsigned short)num; + mobspawn.active = 0; + mobspawn.class_ = (short) class_; + mobspawn.x = (unsigned short)x; + mobspawn.y = (unsigned short)y; + mobspawn.xs = (signed short)xs; + mobspawn.ys = (signed short)ys; if (mob_lv > 0 && mob_lv <= MAX_LEVEL) - mob.level = mob_lv; + mobspawn.level = mob_lv; if (size > 0 && size <= 2) - mob.state.size = size; + mobspawn.state.size = size; if (ai > 0 && ai <= 4) - mob.state.ai = ai; + mobspawn.state.ai = ai; - if (mob.num > 1 && battle_config.mob_count_rate != 100) { - if ((mob.num = mob.num * battle_config.mob_count_rate / 100) < 1) - mob.num = 1; + if (mobspawn.num > 1 && battle_config.mob_count_rate != 100) { + if ((mobspawn.num = mobspawn.num * battle_config.mob_count_rate / 100) < 1) + mobspawn.num = 1; } - if (battle_config.force_random_spawn || (mob.x == 0 && mob.y == 0)) - { //Force a random spawn anywhere on the map. - mob.x = mob.y = 0; - mob.xs = mob.ys = -1; + if (battle_config.force_random_spawn || (mobspawn.x == 0 && mobspawn.y == 0)) { + //Force a random spawn anywhere on the map. + mobspawn.x = mobspawn.y = 0; + mobspawn.xs = mobspawn.ys = -1; } - if(mob.delay1>0xfffffff || mob.delay2>0xfffffff) { - ShowError("npc_parse_mob: Invalid spawn delays %u %u (file '%s', line '%d').\n", mob.delay1, mob.delay2, filepath, strline(buffer,start-buffer)); + if(mobspawn.delay1>0xfffffff || mobspawn.delay2>0xfffffff) { + ShowError("npc_parse_mob: Invalid spawn delays %u %u in file '%s', line '%d'.\n", mobspawn.delay1, mobspawn.delay2, filepath, strline(buffer,start-buffer)); + if (retval) *retval = EXIT_FAILURE; return strchr(start,'\n');// skip and continue } //Use db names instead of the spawn file ones. if(battle_config.override_mob_names==1) - strcpy(mob.name,"--en--"); + strcpy(mobspawn.name,"--en--"); else if (battle_config.override_mob_names==2) - strcpy(mob.name,"--ja--"); + strcpy(mobspawn.name,"--ja--"); else - safestrncpy(mob.name, mobname, sizeof(mob.name)); + safestrncpy(mobspawn.name, mobname, sizeof(mobspawn.name)); //Verify dataset. - if( !mob_parse_dataset(&mob) ) - { - ShowError("npc_parse_mob: Invalid dataset for monster ID %d (file '%s', line '%d').\n", class_, filepath, strline(buffer,start-buffer)); + if( !mob->parse_dataset(&mobspawn) ) { + ShowError("npc_parse_mob: Invalid dataset for monster ID %d in file '%s', line '%d'.\n", class_, filepath, strline(buffer,start-buffer)); + if (retval) *retval = EXIT_FAILURE; return strchr(start,'\n');// skip and continue } //Update mob spawn lookup database - db = mob_db(class_); - for( i = 0; i < ARRAYLENGTH(db->spawn); ++i ) - { - if (map[mob.m].index == db->spawn[i].mapindex) - { //Update total - db->spawn[i].qty += mob.num; + db = mob->db(class_); + for( i = 0; i < ARRAYLENGTH(db->spawn); ++i ) { + if (map_id2index(mobspawn.m) == db->spawn[i].mapindex) { + //Update total + db->spawn[i].qty += mobspawn.num; //Re-sort list for( j = i; j > 0 && db->spawn[j-1].qty < db->spawn[i].qty; --j ); - if( j != i ) - { + if( j != i ) { xs = db->spawn[i].mapindex; ys = db->spawn[i].qty; memmove(&db->spawn[j+1], &db->spawn[j], (i-j)*sizeof(db->spawn[0])); @@ -3095,33 +3563,33 @@ static const char* npc_parse_mob(char* w1, char* w2, char* w3, char* w4, const c } break; } - if (mob.num > db->spawn[i].qty) - { //Insert into list + if (mobspawn.num > db->spawn[i].qty) { + //Insert into list memmove(&db->spawn[i+1], &db->spawn[i], sizeof(db->spawn) -(i+1)*sizeof(db->spawn[0])); - db->spawn[i].mapindex = map[mob.m].index; - db->spawn[i].qty = mob.num; + db->spawn[i].mapindex = map_id2index(mobspawn.m); + db->spawn[i].qty = mobspawn.num; break; } } //Now that all has been validated. We allocate the actual memory that the re-spawn data will use. data = (struct spawn_data*)aMalloc(sizeof(struct spawn_data)); - memcpy(data, &mob, sizeof(struct spawn_data)); + memcpy(data, &mobspawn, sizeof(struct spawn_data)); // spawn / cache the new mobs - if( battle_config.dynamic_mobs && iMap->addmobtolist(data->m, data) >= 0 ) { + if( battle_config.dynamic_mobs && map->addmobtolist(data->m, data) >= 0 ) { data->state.dynamic = true; npc_cache_mob += data->num; // check if target map has players // (usually shouldn't occur when map server is just starting, // but not the case when we do @reloadscript - if( map[data->m].users > 0 ) { - npc_parse_mob2(data); + if( map->list[data->m].users > 0 ) { + npc->parse_mob2(data); } } else { data->state.dynamic = false; - npc_parse_mob2(data); + npc->parse_mob2(data); npc_delay_mob += data->num; } @@ -3134,7 +3602,7 @@ static const char* npc_parse_mob(char* w1, char* w2, char* w3, char* w4, const c * eg : bat_c01 mapflag battleground 2 * also chking if mapflag conflict with another *------------------------------------------*/ -const char* npc_parse_mapflag(char* w1, char* w2, char* w3, char* w4, const char* start, const char* buffer, const char* filepath) { +const char* npc_parse_mapflag(char* w1, char* w2, char* w3, char* w4, const char* start, const char* buffer, const char* filepath, int *retval) { int16 m; char mapname[32]; int state = 1; @@ -3143,12 +3611,14 @@ const char* npc_parse_mapflag(char* w1, char* w2, char* w3, char* w4, const char if( sscanf(w1, "%31[^,]", mapname) != 1 ) { ShowError("npc_parse_mapflag: Invalid mapflag definition in file '%s', line '%d'.\n * w1=%s\n * w2=%s\n * w3=%s\n * w4=%s\n", filepath, strline(buffer,start-buffer), w1, w2, w3, w4); + if (retval) *retval = EXIT_FAILURE; return strchr(start,'\n');// skip and continue } - m = iMap->mapname2mapid(mapname); - if( m < 0 ) - { - ShowWarning("npc_parse_mapflag: Unknown map in file '%s', line '%d' : %s\n * w1=%s\n * w2=%s\n * w3=%s\n * w4=%s\n", mapname, filepath, strline(buffer,start-buffer), w1, w2, w3, w4); + m = map->mapname2mapid(mapname); + if (m < 0) { + ShowWarning("npc_parse_mapflag: Unknown map in file '%s', line '%d': %s\n * w1=%s\n * w2=%s\n * w3=%s\n * w4=%s\n", + filepath, strline(buffer,start-buffer), mapname, w1, w2, w3, w4); + if (retval) *retval = EXIT_FAILURE; return strchr(start,'\n');// skip and continue } @@ -3160,77 +3630,80 @@ const char* npc_parse_mapflag(char* w1, char* w2, char* w3, char* w4, const char int savex, savey; if (state == 0) ; //Map flag disabled. - else if (!strcmpi(w4, "SavePoint")) { - map[m].save.map = 0; - map[m].save.x = -1; - map[m].save.y = -1; + else if (w4 && !strcmpi(w4, "SavePoint")) { + map->list[m].save.map = 0; + map->list[m].save.x = -1; + map->list[m].save.y = -1; } else if (sscanf(w4, "%31[^,],%d,%d", savemap, &savex, &savey) == 3) { - map[m].save.map = mapindex_name2id(savemap); - map[m].save.x = savex; - map[m].save.y = savey; - if (!map[m].save.map) { - ShowWarning("npc_parse_mapflag: Specified save point map '%s' for mapflag 'nosave' not found (file '%s', line '%d'), using 'SavePoint'.\n * w1=%s\n * w2=%s\n * w3=%s\n * w4=%s\n", savemap, filepath, strline(buffer,start-buffer), w1, w2, w3, w4); - map[m].save.x = -1; - map[m].save.y = -1; + map->list[m].save.map = mapindex->name2id(savemap); + map->list[m].save.x = savex; + map->list[m].save.y = savey; + if (!map->list[m].save.map) { + ShowWarning("npc_parse_mapflag: Specified save point map '%s' for mapflag 'nosave' not found in file '%s', line '%d', using 'SavePoint'.\n * w1=%s\n * w2=%s\n * w3=%s\n * w4=%s\n", savemap, filepath, strline(buffer,start-buffer), w1, w2, w3, w4); + if (retval) *retval = EXIT_FAILURE; + map->list[m].save.x = -1; + map->list[m].save.y = -1; } } - map[m].flag.nosave = state; + map->list[m].flag.nosave = state; } else if (!strcmpi(w3,"autotrade")) - map[m].flag.autotrade=state; + map->list[m].flag.autotrade=state; else if (!strcmpi(w3,"allowks")) - map[m].flag.allowks=state; // [Kill Steal Protection] + map->list[m].flag.allowks=state; // [Kill Steal Protection] else if (!strcmpi(w3,"town")) - map[m].flag.town=state; + map->list[m].flag.town=state; else if (!strcmpi(w3,"nomemo")) - map[m].flag.nomemo=state; + map->list[m].flag.nomemo=state; else if (!strcmpi(w3,"noteleport")) - map[m].flag.noteleport=state; + map->list[m].flag.noteleport=state; else if (!strcmpi(w3,"nowarp")) - map[m].flag.nowarp=state; + map->list[m].flag.nowarp=state; else if (!strcmpi(w3,"nowarpto")) - map[m].flag.nowarpto=state; + map->list[m].flag.nowarpto=state; else if (!strcmpi(w3,"noreturn")) - map[m].flag.noreturn=state; + map->list[m].flag.noreturn=state; else if (!strcmpi(w3,"monster_noteleport")) - map[m].flag.monster_noteleport=state; + map->list[m].flag.monster_noteleport=state; else if (!strcmpi(w3,"nobranch")) - map[m].flag.nobranch=state; + map->list[m].flag.nobranch=state; else if (!strcmpi(w3,"nopenalty")) { - map[m].flag.noexppenalty=state; - map[m].flag.nozenypenalty=state; + map->list[m].flag.noexppenalty=state; + map->list[m].flag.nozenypenalty=state; } else if (!strcmpi(w3,"pvp")) { struct map_zone_data *zone; - map[m].flag.pvp = state; - if( state && (map[m].flag.gvg || map[m].flag.gvg_dungeon || map[m].flag.gvg_castle) ) { - map[m].flag.gvg = 0; - map[m].flag.gvg_dungeon = 0; - map[m].flag.gvg_castle = 0; - ShowWarning("npc_parse_mapflag: You can't set PvP and GvG flags for the same map! Removing GvG flags from %s (file '%s', line '%d').\n", map[m].name, filepath, strline(buffer,start-buffer)); - } - if( state && map[m].flag.battleground ) { - map[m].flag.battleground = 0; - ShowWarning("npc_parse_mapflag: You can't set PvP and BattleGround flags for the same map! Removing BattleGround flag from %s (file '%s', line '%d').\n", map[m].name, filepath, strline(buffer,start-buffer)); - } - if( state && (zone = strdb_get(zone_db, MAP_ZONE_PVP_NAME)) && map[m].zone != zone ) { - iMap->zone_change(m,zone,start,buffer,filepath); + map->list[m].flag.pvp = state; + if( state && (map->list[m].flag.gvg || map->list[m].flag.gvg_dungeon || map->list[m].flag.gvg_castle) ) { + map->list[m].flag.gvg = 0; + map->list[m].flag.gvg_dungeon = 0; + map->list[m].flag.gvg_castle = 0; + ShowWarning("npc_parse_mapflag: You can't set PvP and GvG flags for the same map! Removing GvG flags from %s in file '%s', line '%d'.\n", map->list[m].name, filepath, strline(buffer,start-buffer)); + if (retval) *retval = EXIT_FAILURE; + } + if( state && map->list[m].flag.battleground ) { + map->list[m].flag.battleground = 0; + ShowWarning("npc_parse_mapflag: You can't set PvP and BattleGround flags for the same map! Removing BattleGround flag from %s in file '%s', line '%d'.\n", map->list[m].name, filepath, strline(buffer,start-buffer)); + if (retval) *retval = EXIT_FAILURE; + } + if( state && (zone = strdb_get(map->zone_db, MAP_ZONE_PVP_NAME)) && map->list[m].zone != zone ) { + map->zone_change(m,zone,start,buffer,filepath); } else if ( !state ) { - map[m].zone = &map_zone_pk; + map->list[m].zone = &map->zone_pk; } } else if (!strcmpi(w3,"pvp_noparty")) - map[m].flag.pvp_noparty=state; + map->list[m].flag.pvp_noparty=state; else if (!strcmpi(w3,"pvp_noguild")) - map[m].flag.pvp_noguild=state; + map->list[m].flag.pvp_noguild=state; else if (!strcmpi(w3, "pvp_nightmaredrop")) { char drop_arg1[16], drop_arg2[16]; int drop_per = 0; - if (sscanf(w4, "%[^,],%[^,],%d", drop_arg1, drop_arg2, &drop_per) == 3) { + if (sscanf(w4, "%15[^,],%15[^,],%d", drop_arg1, drop_arg2, &drop_per) == 3) { int drop_id = 0, drop_type = 0; if (!strcmpi(drop_arg1, "random")) drop_id = -1; - else if (itemdb_exists((drop_id = atoi(drop_arg1))) == NULL) + else if (itemdb->exists((drop_id = atoi(drop_arg1))) == NULL) drop_id = 0; if (!strcmpi(drop_arg2, "inventory")) drop_type = 1; @@ -3240,150 +3713,157 @@ const char* npc_parse_mapflag(char* w1, char* w2, char* w3, char* w4, const char drop_type = 3; if (drop_id != 0) { - RECREATE(map[m].drop_list, struct map_drop_list, ++map[m].drop_list_count); - map[m].drop_list[map[m].drop_list_count-1].drop_id = drop_id; - map[m].drop_list[map[m].drop_list_count-1].drop_type = drop_type; - map[m].drop_list[map[m].drop_list_count-1].drop_per = drop_per; - map[m].flag.pvp_nightmaredrop = 1; + RECREATE(map->list[m].drop_list, struct map_drop_list, ++map->list[m].drop_list_count); + map->list[m].drop_list[map->list[m].drop_list_count-1].drop_id = drop_id; + map->list[m].drop_list[map->list[m].drop_list_count-1].drop_type = drop_type; + map->list[m].drop_list[map->list[m].drop_list_count-1].drop_per = drop_per; + map->list[m].flag.pvp_nightmaredrop = 1; } } else if (!state) //Disable - map[m].flag.pvp_nightmaredrop = 0; + map->list[m].flag.pvp_nightmaredrop = 0; } else if (!strcmpi(w3,"pvp_nocalcrank")) - map[m].flag.pvp_nocalcrank=state; + map->list[m].flag.pvp_nocalcrank=state; else if (!strcmpi(w3,"gvg")) { struct map_zone_data *zone; - map[m].flag.gvg = state; - if( state && map[m].flag.pvp ) { - map[m].flag.pvp = 0; - ShowWarning("npc_parse_mapflag: You can't set PvP and GvG flags for the same map! Removing PvP flag from %s (file '%s', line '%d').\n", map[m].name, filepath, strline(buffer,start-buffer)); + map->list[m].flag.gvg = state; + if( state && map->list[m].flag.pvp ) { + map->list[m].flag.pvp = 0; + ShowWarning("npc_parse_mapflag: You can't set PvP and GvG flags for the same map! Removing PvP flag from %s in file '%s', line '%d'.\n", map->list[m].name, filepath, strline(buffer,start-buffer)); + if (retval) *retval = EXIT_FAILURE; } - if( state && map[m].flag.battleground ) { - map[m].flag.battleground = 0; - ShowWarning("npc_parse_mapflag: You can't set GvG and BattleGround flags for the same map! Removing BattleGround flag from %s (file '%s', line '%d').\n", map[m].name, filepath, strline(buffer,start-buffer)); + if( state && map->list[m].flag.battleground ) { + map->list[m].flag.battleground = 0; + ShowWarning("npc_parse_mapflag: You can't set GvG and BattleGround flags for the same map! Removing BattleGround flag from %s in file '%s', line '%d'.\n", map->list[m].name, filepath, strline(buffer,start-buffer)); + if (retval) *retval = EXIT_FAILURE; } - if( state && (zone = strdb_get(zone_db, MAP_ZONE_GVG_NAME)) && map[m].zone != zone ) { - iMap->zone_change(m,zone,start,buffer,filepath); + if( state && (zone = strdb_get(map->zone_db, MAP_ZONE_GVG_NAME)) && map->list[m].zone != zone ) { + map->zone_change(m,zone,start,buffer,filepath); } } else if (!strcmpi(w3,"gvg_noparty")) - map[m].flag.gvg_noparty=state; + map->list[m].flag.gvg_noparty=state; else if (!strcmpi(w3,"gvg_dungeon")) { - map[m].flag.gvg_dungeon=state; - if (state) map[m].flag.pvp=0; + map->list[m].flag.gvg_dungeon=state; + if (state) map->list[m].flag.pvp=0; } else if (!strcmpi(w3,"gvg_castle")) { - map[m].flag.gvg_castle=state; - if (state) map[m].flag.pvp=0; + map->list[m].flag.gvg_castle=state; + if (state) map->list[m].flag.pvp=0; } else if (!strcmpi(w3,"battleground")) { struct map_zone_data *zone; if( state ) { if( sscanf(w4, "%d", &state) == 1 ) - map[m].flag.battleground = state; + map->list[m].flag.battleground = state; else - map[m].flag.battleground = 1; // Default value + map->list[m].flag.battleground = 1; // Default value } else - map[m].flag.battleground = 0; + map->list[m].flag.battleground = 0; - if( map[m].flag.battleground && map[m].flag.pvp ) { - map[m].flag.pvp = 0; - ShowWarning("npc_parse_mapflag: You can't set PvP and BattleGround flags for the same map! Removing PvP flag from %s (file '%s', line '%d').\n", map[m].name, filepath, strline(buffer,start-buffer)); + if( map->list[m].flag.battleground && map->list[m].flag.pvp ) { + map->list[m].flag.pvp = 0; + ShowWarning("npc_parse_mapflag: You can't set PvP and BattleGround flags for the same map! Removing PvP flag from %s in file '%s', line '%d'.\n", map->list[m].name, filepath, strline(buffer,start-buffer)); + if (retval) *retval = EXIT_FAILURE; } - if( map[m].flag.battleground && (map[m].flag.gvg || map[m].flag.gvg_dungeon || map[m].flag.gvg_castle) ) { - map[m].flag.gvg = 0; - map[m].flag.gvg_dungeon = 0; - map[m].flag.gvg_castle = 0; - ShowWarning("npc_parse_mapflag: You can't set GvG and BattleGround flags for the same map! Removing GvG flag from %s (file '%s', line '%d').\n", map[m].name, filepath, strline(buffer,start-buffer)); + if( map->list[m].flag.battleground && (map->list[m].flag.gvg || map->list[m].flag.gvg_dungeon || map->list[m].flag.gvg_castle) ) { + map->list[m].flag.gvg = 0; + map->list[m].flag.gvg_dungeon = 0; + map->list[m].flag.gvg_castle = 0; + ShowWarning("npc_parse_mapflag: You can't set GvG and BattleGround flags for the same map! Removing GvG flag from %s in file '%s', line '%d'.\n", map->list[m].name, filepath, strline(buffer,start-buffer)); + if (retval) *retval = EXIT_FAILURE; } - if( state && (zone = strdb_get(zone_db, MAP_ZONE_BG_NAME)) && map[m].zone != zone ) { - iMap->zone_change(m,zone,start,buffer,filepath); + if( state && (zone = strdb_get(map->zone_db, MAP_ZONE_BG_NAME)) && map->list[m].zone != zone ) { + map->zone_change(m,zone,start,buffer,filepath); } } else if (!strcmpi(w3,"noexppenalty")) - map[m].flag.noexppenalty=state; + map->list[m].flag.noexppenalty=state; else if (!strcmpi(w3,"nozenypenalty")) - map[m].flag.nozenypenalty=state; + map->list[m].flag.nozenypenalty=state; else if (!strcmpi(w3,"notrade")) - map[m].flag.notrade=state; + map->list[m].flag.notrade=state; else if (!strcmpi(w3,"novending")) - map[m].flag.novending=state; + map->list[m].flag.novending=state; else if (!strcmpi(w3,"nodrop")) - map[m].flag.nodrop=state; + map->list[m].flag.nodrop=state; else if (!strcmpi(w3,"noskill")) - map[m].flag.noskill=state; + map->list[m].flag.noskill=state; else if (!strcmpi(w3,"noicewall")) - map[m].flag.noicewall=state; + map->list[m].flag.noicewall=state; else if (!strcmpi(w3,"snow")) - map[m].flag.snow=state; + map->list[m].flag.snow=state; else if (!strcmpi(w3,"clouds")) - map[m].flag.clouds=state; + map->list[m].flag.clouds=state; else if (!strcmpi(w3,"clouds2")) - map[m].flag.clouds2=state; + map->list[m].flag.clouds2=state; else if (!strcmpi(w3,"fog")) - map[m].flag.fog=state; + map->list[m].flag.fog=state; else if (!strcmpi(w3,"fireworks")) - map[m].flag.fireworks=state; + map->list[m].flag.fireworks=state; else if (!strcmpi(w3,"sakura")) - map[m].flag.sakura=state; + map->list[m].flag.sakura=state; else if (!strcmpi(w3,"leaves")) - map[m].flag.leaves=state; + map->list[m].flag.leaves=state; else if (!strcmpi(w3,"nightenabled")) - map[m].flag.nightenabled=state; + map->list[m].flag.nightenabled=state; else if (!strcmpi(w3,"noexp")) { - map[m].flag.nobaseexp=state; - map[m].flag.nojobexp=state; + map->list[m].flag.nobaseexp=state; + map->list[m].flag.nojobexp=state; } else if (!strcmpi(w3,"nobaseexp")) - map[m].flag.nobaseexp=state; + map->list[m].flag.nobaseexp=state; else if (!strcmpi(w3,"nojobexp")) - map[m].flag.nojobexp=state; + map->list[m].flag.nojobexp=state; else if (!strcmpi(w3,"noloot")) { - map[m].flag.nomobloot=state; - map[m].flag.nomvploot=state; + map->list[m].flag.nomobloot=state; + map->list[m].flag.nomvploot=state; } else if (!strcmpi(w3,"nomobloot")) - map[m].flag.nomobloot=state; + map->list[m].flag.nomobloot=state; else if (!strcmpi(w3,"nomvploot")) - map[m].flag.nomvploot=state; + map->list[m].flag.nomvploot=state; else if (!strcmpi(w3,"nocommand")) { if (state) { if (sscanf(w4, "%d", &state) == 1) - map[m].nocommand =state; + map->list[m].nocommand =state; else //No level specified, block everyone. - map[m].nocommand =100; + map->list[m].nocommand =100; } else - map[m].nocommand=0; + map->list[m].nocommand=0; } else if (!strcmpi(w3,"jexp")) { - map[m].jexp = (state) ? atoi(w4) : 100; - if( map[m].jexp < 0 ) map[m].jexp = 100; - map[m].flag.nojobexp = (map[m].jexp==0)?1:0; + map->list[m].jexp = (state) ? atoi(w4) : 100; + if( map->list[m].jexp < 0 ) map->list[m].jexp = 100; + map->list[m].flag.nojobexp = (map->list[m].jexp==0)?1:0; } else if (!strcmpi(w3,"bexp")) { - map[m].bexp = (state) ? atoi(w4) : 100; - if( map[m].bexp < 0 ) map[m].bexp = 100; - map[m].flag.nobaseexp = (map[m].bexp==0)?1:0; + map->list[m].bexp = (state) ? atoi(w4) : 100; + if( map->list[m].bexp < 0 ) map->list[m].bexp = 100; + map->list[m].flag.nobaseexp = (map->list[m].bexp==0)?1:0; } else if (!strcmpi(w3,"loadevent")) - map[m].flag.loadevent=state; + map->list[m].flag.loadevent=state; else if (!strcmpi(w3,"nochat")) - map[m].flag.nochat=state; + map->list[m].flag.nochat=state; else if (!strcmpi(w3,"partylock")) - map[m].flag.partylock=state; + map->list[m].flag.partylock=state; else if (!strcmpi(w3,"guildlock")) - map[m].flag.guildlock=state; + map->list[m].flag.guildlock=state; else if (!strcmpi(w3,"reset")) - map[m].flag.reset=state; + map->list[m].flag.reset=state; + else if (!strcmpi(w3,"notomb")) + map->list[m].flag.notomb=state; else if (!strcmpi(w3,"adjust_unit_duration")) { int skill_id, k; char skill_name[MAP_ZONE_MAPFLAG_LENGTH], modifier[MAP_ZONE_MAPFLAG_LENGTH]; - int len = strlen(w4); + size_t len = w4 ? strlen(w4) : 0; modifier[0] = '\0'; - memcpy(skill_name, w4, MAP_ZONE_MAPFLAG_LENGTH); + if( w4 ) + memcpy(skill_name, w4, MAP_ZONE_MAPFLAG_LENGTH); for(k = 0; k < len; k++) { if( skill_name[k] == '\t' ) { @@ -3394,50 +3874,55 @@ const char* npc_parse_mapflag(char* w1, char* w2, char* w3, char* w4, const char } if( modifier[0] == '\0' ) { - ShowWarning("npc_parse_mapflag: Missing 5th param for 'adjust_unit_duration' flag! removing flag from %s (file '%s', line '%d').\n", map[m].name, filepath, strline(buffer,start-buffer)); + ShowWarning("npc_parse_mapflag: Missing 5th param for 'adjust_unit_duration' flag! removing flag from %s in file '%s', line '%d'.\n", map->list[m].name, filepath, strline(buffer,start-buffer)); + if (retval) *retval = EXIT_FAILURE; } else if( !( skill_id = skill->name2id(skill_name) ) || !skill->get_unit_id( skill->name2id(skill_name), 0) ) { - ShowWarning("npc_parse_mapflag: Unknown skill (%s) for 'adjust_unit_duration' flag! removing flag from %s (file '%s', line '%d').\n",skill_name, map[m].name, filepath, strline(buffer,start-buffer)); + ShowWarning("npc_parse_mapflag: Unknown skill (%s) for 'adjust_unit_duration' flag! removing flag from %s in file '%s', line '%d'.\n",skill_name, map->list[m].name, filepath, strline(buffer,start-buffer)); + if (retval) *retval = EXIT_FAILURE; } else if ( atoi(modifier) < 1 || atoi(modifier) > USHRT_MAX ) { - ShowWarning("npc_parse_mapflag: Invalid modifier '%d' for skill '%s' for 'adjust_unit_duration' flag! removing flag from %s (file '%s', line '%d').\n", atoi(modifier), skill_name, map[m].name, filepath, strline(buffer,start-buffer)); + ShowWarning("npc_parse_mapflag: Invalid modifier '%d' for skill '%s' for 'adjust_unit_duration' flag! removing flag from %s in file '%s', line '%d'.\n", atoi(modifier), skill_name, map->list[m].name, filepath, strline(buffer,start-buffer)); + if (retval) *retval = EXIT_FAILURE; } else { - int idx = map[m].unit_count; + int idx = map->list[m].unit_count; - ARR_FIND(0, idx, k, map[m].units[k]->skill_id == skill_id); + ARR_FIND(0, idx, k, map->list[m].units[k]->skill_id == skill_id); if( k < idx ) { if( atoi(modifier) != 100 ) - map[m].units[k]->modifier = (unsigned short)atoi(modifier); + map->list[m].units[k]->modifier = (unsigned short)atoi(modifier); else { /* remove */ int cursor = 0; - aFree(map[m].units[k]); - map[m].units[k] = NULL; + aFree(map->list[m].units[k]); + map->list[m].units[k] = NULL; for( k = 0; k < idx; k++ ) { - if( map[m].units[k] == NULL ) + if( map->list[m].units[k] == NULL ) continue; - memmove(&map[m].units[cursor], &map[m].units[k], sizeof(struct mapflag_skill_adjust)); - + map->list[m].units[cursor] = map->list[m].units[k]; + cursor++; } - if( !( map[m].unit_count = cursor ) ) { - aFree(map[m].units); - map[m].units = NULL; + if( !( map->list[m].unit_count = cursor ) ) { + aFree(map->list[m].units); + map->list[m].units = NULL; } } } else if( atoi(modifier) != 100 ) { - RECREATE(map[m].units, struct mapflag_skill_adjust*, ++map[m].unit_count); - CREATE(map[m].units[idx],struct mapflag_skill_adjust,1); - map[m].units[idx]->skill_id = (unsigned short)skill_id; - map[m].units[idx]->modifier = (unsigned short)atoi(modifier); + RECREATE(map->list[m].units, struct mapflag_skill_adjust*, ++map->list[m].unit_count); + CREATE(map->list[m].units[idx],struct mapflag_skill_adjust,1); + map->list[m].units[idx]->skill_id = (unsigned short)skill_id; + map->list[m].units[idx]->modifier = (unsigned short)atoi(modifier); } } } else if (!strcmpi(w3,"adjust_skill_damage")) { int skill_id, k; char skill_name[MAP_ZONE_MAPFLAG_LENGTH], modifier[MAP_ZONE_MAPFLAG_LENGTH]; - int len = strlen(w4); + size_t len = w4 ? strlen(w4) : 0; modifier[0] = '\0'; - memcpy(skill_name, w4, MAP_ZONE_MAPFLAG_LENGTH); + + if( w4 ) + memcpy(skill_name, w4, MAP_ZONE_MAPFLAG_LENGTH); for(k = 0; k < len; k++) { if( skill_name[k] == '\t' ) { @@ -3448,78 +3933,95 @@ const char* npc_parse_mapflag(char* w1, char* w2, char* w3, char* w4, const char } if( modifier[0] == '\0' ) { - ShowWarning("npc_parse_mapflag: Missing 5th param for 'adjust_skill_damage' flag! removing flag from %s (file '%s', line '%d').\n", map[m].name, filepath, strline(buffer,start-buffer)); + ShowWarning("npc_parse_mapflag: Missing 5th param for 'adjust_skill_damage' flag! removing flag from %s in file '%s', line '%d'.\n", map->list[m].name, filepath, strline(buffer,start-buffer)); + if (retval) *retval = EXIT_FAILURE; } else if( !( skill_id = skill->name2id(skill_name) ) ) { - ShowWarning("npc_parse_mapflag: Unknown skill (%s) for 'adjust_skill_damage' flag! removing flag from %s (file '%s', line '%d').\n", skill_name, map[m].name, filepath, strline(buffer,start-buffer)); + ShowWarning("npc_parse_mapflag: Unknown skill (%s) for 'adjust_skill_damage' flag! removing flag from %s in file '%s', line '%d'.\n", skill_name, map->list[m].name, filepath, strline(buffer,start-buffer)); + if (retval) *retval = EXIT_FAILURE; } else if ( atoi(modifier) < 1 || atoi(modifier) > USHRT_MAX ) { - ShowWarning("npc_parse_mapflag: Invalid modifier '%d' for skill '%s' for 'adjust_skill_damage' flag! removing flag from %s (file '%s', line '%d').\n", atoi(modifier), skill_name, map[m].name, filepath, strline(buffer,start-buffer)); + ShowWarning("npc_parse_mapflag: Invalid modifier '%d' for skill '%s' for 'adjust_skill_damage' flag! removing flag from %s in file '%s', line '%d'.\n", atoi(modifier), skill_name, map->list[m].name, filepath, strline(buffer,start-buffer)); + if (retval) *retval = EXIT_FAILURE; } else { - int idx = map[m].skill_count; - - ARR_FIND(0, idx, k, map[m].skills[k]->skill_id == skill_id); + int idx = map->list[m].skill_count; + + ARR_FIND(0, idx, k, map->list[m].skills[k]->skill_id == skill_id); if( k < idx ) { if( atoi(modifier) != 100 ) - map[m].skills[k]->modifier = (unsigned short)atoi(modifier); + map->list[m].skills[k]->modifier = (unsigned short)atoi(modifier); else { /* remove */ int cursor = 0; - aFree(map[m].skills[k]); - map[m].skills[k] = NULL; + aFree(map->list[m].skills[k]); + map->list[m].skills[k] = NULL; for( k = 0; k < idx; k++ ) { - if( map[m].skills[k] == NULL ) + if( map->list[m].skills[k] == NULL ) continue; - memmove(&map[m].skills[cursor], &map[m].skills[k], sizeof(struct mapflag_skill_adjust)); - + map->list[m].skills[cursor] = map->list[m].skills[k]; + cursor++; } - if( !( map[m].skill_count = cursor ) ) { - aFree(map[m].skills); - map[m].skills = NULL; + if( !( map->list[m].skill_count = cursor ) ) { + aFree(map->list[m].skills); + map->list[m].skills = NULL; } } } else if( atoi(modifier) != 100 ) { - RECREATE(map[m].skills, struct mapflag_skill_adjust*, ++map[m].skill_count); - CREATE(map[m].skills[idx],struct mapflag_skill_adjust,1); - map[m].skills[idx]->skill_id = (unsigned short)skill_id; - map[m].skills[idx]->modifier = (unsigned short)atoi(modifier); + RECREATE(map->list[m].skills, struct mapflag_skill_adjust*, ++map->list[m].skill_count); + CREATE(map->list[m].skills[idx],struct mapflag_skill_adjust,1); + map->list[m].skills[idx]->skill_id = (unsigned short)skill_id; + map->list[m].skills[idx]->modifier = (unsigned short)atoi(modifier); } } } else if (!strcmpi(w3,"zone")) { struct map_zone_data *zone; - if( !(zone = strdb_get(zone_db, w4)) ) { - ShowWarning("npc_parse_mapflag: Invalid zone '%s'! removing flag from %s (file '%s', line '%d').\n", w4, map[m].name, filepath, strline(buffer,start-buffer)); - } else if( map[m].zone != zone ) { - iMap->zone_change(m,zone,start,buffer,filepath); + if( !(zone = strdb_get(map->zone_db, w4)) ) { + ShowWarning("npc_parse_mapflag: Invalid zone '%s'! removing flag from %s in file '%s', line '%d'.\n", w4, map->list[m].name, filepath, strline(buffer,start-buffer)); + if (retval) *retval = EXIT_FAILURE; + } else if( map->list[m].zone != zone ) { + map->zone_change(m,zone,start,buffer,filepath); } } else if ( !strcmpi(w3,"nomapchannelautojoin") ) { - map[m].flag.chsysnolocalaj = state; + map->list[m].flag.chsysnolocalaj = state; } else if ( !strcmpi(w3,"invincible_time_inc") ) { - map[m].invincible_time_inc = (state) ? atoi(w4) : 0; + map->list[m].invincible_time_inc = (state) ? atoi(w4) : 0; } else if ( !strcmpi(w3,"noknockback") ) { - map[m].flag.noknockback = state; + map->list[m].flag.noknockback = state; } else if ( !strcmpi(w3,"weapon_damage_rate") ) { - map[m].weapon_damage_rate = (state) ? atoi(w4) : 100; + map->list[m].weapon_damage_rate = (state) ? atoi(w4) : 100; } else if ( !strcmpi(w3,"magic_damage_rate") ) { - map[m].magic_damage_rate = (state) ? atoi(w4) : 100; + map->list[m].magic_damage_rate = (state) ? atoi(w4) : 100; } else if ( !strcmpi(w3,"misc_damage_rate") ) { - map[m].misc_damage_rate = (state) ? atoi(w4) : 100; + map->list[m].misc_damage_rate = (state) ? atoi(w4) : 100; } else if ( !strcmpi(w3,"short_damage_rate") ) { - map[m].short_damage_rate = (state) ? atoi(w4) : 100; + map->list[m].short_damage_rate = (state) ? atoi(w4) : 100; } else if ( !strcmpi(w3,"long_damage_rate") ) { - map[m].long_damage_rate = (state) ? atoi(w4) : 100; - } else - ShowError("npc_parse_mapflag: unrecognized mapflag '%s' (file '%s', line '%d').\n", w3, filepath, strline(buffer,start-buffer)); + map->list[m].long_damage_rate = (state) ? atoi(w4) : 100; + } else if ( !strcmpi(w3,"src4instance") ) { + map->list[m].flag.src4instance = (state) ? 1 : 0; + } else if ( !strcmpi(w3,"nocashshop") ) { + map->list[m].flag.nocashshop = (state) ? 1 : 0; + } else { + ShowError("npc_parse_mapflag: unrecognized mapflag '%s' in file '%s', line '%d'.\n", w3, filepath, strline(buffer,start-buffer)); + if (retval) *retval = EXIT_FAILURE; + } return strchr(start,'\n');// continue } -//Read file and create npc/func/mapflag/monster... accordingly. -//@runOnInit should we exec OnInit when it's done ? -void npc_parsesrcfile(const char* filepath, bool runOnInit) -{ +/** + * Parses a script file and creates NPCs/functions/mapflags/monsters/etc + * accordingly. + * + * @param filepath File name and path. + * @param runOnInit Whether the OnInit label should be called. + * @retval EXIT_SUCCESS if filepath was loaded correctly. + * @retval EXIT_FAILURE if there were errors/warnings when loading filepath. + */ +int npc_parsesrcfile(const char* filepath, bool runOnInit) { + int success = EXIT_SUCCESS; int16 m, x, y; int lines = 0; FILE* fp; @@ -3529,10 +4031,9 @@ void npc_parsesrcfile(const char* filepath, bool runOnInit) // read whole file to buffer fp = fopen(filepath, "rb"); - if( fp == NULL ) - { + if( fp == NULL ) { ShowError("npc_parsesrcfile: File not found '%s'.\n", filepath); - return; + return EXIT_FAILURE; } fseek(fp, 0, SEEK_END); len = ftell(fp); @@ -3540,103 +4041,118 @@ void npc_parsesrcfile(const char* filepath, bool runOnInit) fseek(fp, 0, SEEK_SET); len = fread(buffer, sizeof(char), len, fp); buffer[len] = '\0'; - if( ferror(fp) ) - { + if( ferror(fp) ) { ShowError("npc_parsesrcfile: Failed to read file '%s' - %s\n", filepath, strerror(errno)); aFree(buffer); fclose(fp); - return; + return EXIT_FAILURE; } fclose(fp); + if ((unsigned char)buffer[0] == 0xEF && (unsigned char)buffer[1] == 0xBB && (unsigned char)buffer[2] == 0xBF) { + // UTF-8 BOM. This is most likely an error on the user's part, because: + // - BOM is discouraged in UTF-8, and the only place where you see it is Notepad and such. + // - It's unlikely that the user wants to use UTF-8 data here, since we don't really support it, nor does the client by default. + // - If the user really wants to use UTF-8 (instead of latin1, EUC-KR, SJIS, etc), then they can still do it <without BOM>. + // More info at http://unicode.org/faq/utf_bom.html#bom5 and http://en.wikipedia.org/wiki/Byte_order_mark#UTF-8 + ShowError("npc_parsesrcfile: Detected unsupported UTF-8 BOM in file '%s'. Stopping (please consider using another character set.)\n", filepath); + aFree(buffer); + fclose(fp); + return EXIT_FAILURE; + } + // parse buffer - for( p = skip_space(buffer); p && *p ; p = skip_space(p) ) - { + for( p = script->skip_space(buffer); p && *p ; p = script->skip_space(p) ) { int pos[9]; char w1[2048], w2[2048], w3[2048], w4[2048]; int i, count; lines++; // w1<TAB>w2<TAB>w3<TAB>w4 - count = sv->parse(p, len+buffer-p, 0, '\t', pos, ARRAYLENGTH(pos), (e_svopt)(SV_TERMINATE_LF|SV_TERMINATE_CRLF)); + count = sv->parse(p, (int)(len+buffer-p), 0, '\t', pos, ARRAYLENGTH(pos), (e_svopt)(SV_TERMINATE_LF|SV_TERMINATE_CRLF)); if( count < 0 ) { ShowError("npc_parsesrcfile: Parse error in file '%s', line '%d'. Stopping...\n", filepath, strline(buffer,p-buffer)); + success = EXIT_FAILURE; break; } // fill w1 - if( pos[3]-pos[2] > ARRAYLENGTH(w1)-1 ) + if( pos[3]-pos[2] > ARRAYLENGTH(w1)-1 ) { ShowWarning("npc_parsesrcfile: w1 truncated, too much data (%d) in file '%s', line '%d'.\n", pos[3]-pos[2], filepath, strline(buffer,p-buffer)); + success = EXIT_FAILURE; + } i = min(pos[3]-pos[2], ARRAYLENGTH(w1)-1); memcpy(w1, p+pos[2], i*sizeof(char)); w1[i] = '\0'; // fill w2 - if( pos[5]-pos[4] > ARRAYLENGTH(w2)-1 ) + if( pos[5]-pos[4] > ARRAYLENGTH(w2)-1 ) { ShowWarning("npc_parsesrcfile: w2 truncated, too much data (%d) in file '%s', line '%d'.\n", pos[5]-pos[4], filepath, strline(buffer,p-buffer)); + success = EXIT_FAILURE; + } i = min(pos[5]-pos[4], ARRAYLENGTH(w2)-1); memcpy(w2, p+pos[4], i*sizeof(char)); w2[i] = '\0'; // fill w3 - if( pos[7]-pos[6] > ARRAYLENGTH(w3)-1 ) + if( pos[7]-pos[6] > ARRAYLENGTH(w3)-1 ) { ShowWarning("npc_parsesrcfile: w3 truncated, too much data (%d) in file '%s', line '%d'.\n", pos[7]-pos[6], filepath, strline(buffer,p-buffer)); + success = EXIT_FAILURE; + } i = min(pos[7]-pos[6], ARRAYLENGTH(w3)-1); memcpy(w3, p+pos[6], i*sizeof(char)); w3[i] = '\0'; // fill w4 (to end of line) - if( pos[1]-pos[8] > ARRAYLENGTH(w4)-1 ) + if( pos[1]-pos[8] > ARRAYLENGTH(w4)-1 ) { ShowWarning("npc_parsesrcfile: w4 truncated, too much data (%d) in file '%s', line '%d'.\n", pos[1]-pos[8], filepath, strline(buffer,p-buffer)); - if( pos[8] != -1 ) - { + success = EXIT_FAILURE; + } + if( pos[8] != -1 ) { i = min(pos[1]-pos[8], ARRAYLENGTH(w4)-1); memcpy(w4, p+pos[8], i*sizeof(char)); w4[i] = '\0'; - } - else + } else { w4[0] = '\0'; + } - if( count < 3 ) - {// Unknown syntax + if( count < 3 ) { + // Unknown syntax ShowError("npc_parsesrcfile: Unknown syntax in file '%s', line '%d'. Stopping...\n * w1=%s\n * w2=%s\n * w3=%s\n * w4=%s\n", filepath, strline(buffer,p-buffer), w1, w2, w3, w4); + success = EXIT_FAILURE; break; } - if( strcmp(w1,"-") !=0 && strcasecmp(w1,"function") != 0 ) + if( strcmp(w1,"-") != 0 && strcmp(w1,"function") != 0 ) {// w1 = <map name>,<x>,<y>,<facing> char mapname[MAP_NAME_LENGTH*2]; x = y = 0; sscanf(w1,"%23[^,],%hd,%hd[^,]",mapname,&x,&y); - if( !mapindex_name2id(mapname) ) - {// Incorrect map, we must skip the script info... + if( !mapindex->name2id(mapname) ) { + // Incorrect map, we must skip the script info... ShowError("npc_parsesrcfile: Unknown map '%s' in file '%s', line '%d'. Skipping line...\n", mapname, filepath, strline(buffer,p-buffer)); - if( strcasecmp(w2,"script") == 0 && count > 3 ) - { - if((p = npc_skip_script(p,buffer,filepath)) == NULL) - { + success = EXIT_FAILURE; + if( strcmp(w2,"script") == 0 && count > 3 ) { + if((p = npc->skip_script(p,buffer,filepath, &success)) == NULL) { break; } } p = strchr(p,'\n');// next line continue; } - m = iMap->mapname2mapid(mapname); - if( m < 0 ) - {// "mapname" is not assigned to this server, we must skip the script info... - if( strcasecmp(w2,"script") == 0 && count > 3 ) - { - if((p = npc_skip_script(p,buffer,filepath)) == NULL) - { + m = map->mapname2mapid(mapname); + if( m < 0 ) { + // "mapname" is not assigned to this server, we must skip the script info... + if( strcmp(w2,"script") == 0 && count > 3 ) { + if((p = npc->skip_script(p,buffer,filepath, &success)) == NULL) { break; } } p = strchr(p,'\n');// next line continue; } - if (x < 0 || x >= map[m].xs || y < 0 || y >= map[m].ys) { + if (x < 0 || x >= map->list[m].xs || y < 0 || y >= map->list[m].ys) { ShowError("npc_parsesrcfile: Unknown coordinates ('%d', '%d') for map '%s' in file '%s', line '%d'. Skipping line...\n", x, y, mapname, filepath, strline(buffer,p-buffer)); - if( strcasecmp(w2,"script") == 0 && count > 3 ) - { - if((p = npc_skip_script(p,buffer,filepath)) == NULL) - { + success = EXIT_FAILURE; + if( strcmp(w2,"script") == 0 && count > 3 ) { + if((p = npc->skip_script(p,buffer,filepath, &success)) == NULL) { break; } } @@ -3645,42 +4161,71 @@ void npc_parsesrcfile(const char* filepath, bool runOnInit) } } - if( strcasecmp(w2,"warp") == 0 && count > 3 ) + if( strcmp(w2,"mapflag") == 0 && count >= 3 ) { - p = npc_parse_warp(w1,w2,w3,w4, p, buffer, filepath); + p = npc->parse_mapflag(w1, w2, trim(w3), trim(w4), p, buffer, filepath, &success); } - else if( (!strcasecmp(w2,"shop") || !strcasecmp(w2,"cashshop")) && count > 3 ) + else if( count == 3 ) { + ShowError("npc_parsesrcfile: Unable to parse, probably a missing TAB in file '%s', line '%d'. Skipping line...\n * w1=%s\n * w2=%s\n * w3=%s\n * w4=%s\n", filepath, strline(buffer,p-buffer), w1, w2, w3, w4); + p = strchr(p,'\n');// skip and continue + success = EXIT_FAILURE; + } + else if( strcmp(w2,"script") == 0 ) { - p = npc_parse_shop(w1,w2,w3,w4, p, buffer, filepath); + if( strcmp(w1,"function") == 0 ) { + p = npc->parse_function(w1, w2, w3, w4, p, buffer, filepath, &success); + } else { +#ifdef ENABLE_CASE_CHECK + if( strcasecmp(w1, "function") == 0 ) DeprecationWarning("npc_parsesrcfile", w1, "function", filepath, strline(buffer, p-buffer)); // TODO +#endif // ENABLE_CASE_CHECK + p = npc->parse_script(w1,w2,w3,w4, p, buffer, filepath,runOnInit?NPO_ONINIT:NPO_NONE, &success); + } } - else if( strcasecmp(w2,"script") == 0 && count > 3 ) + else if( strcmp(w2,"trader") == 0 ) { + p = npc->parse_script(w1,w2,w3,w4, p, buffer, filepath,(runOnInit?NPO_ONINIT:NPO_NONE)|NPO_TRADER, &success); + } + else if( strcmp(w2,"warp") == 0 ) { - if( strcasecmp(w1,"function") == 0 ) - p = npc_parse_function(w1, w2, w3, w4, p, buffer, filepath); - else - p = npc_parse_script(w1,w2,w3,w4, p, buffer, filepath,runOnInit); + p = npc->parse_warp(w1,w2,w3,w4, p, buffer, filepath, &success); } - else if( (i=0, sscanf(w2,"duplicate%n",&i), (i > 0 && w2[i] == '(')) && count > 3 ) + else if( (i=0, sscanf(w2,"duplicate%n",&i), (i > 0 && w2[i] == '(')) ) { - p = npc_parse_duplicate(w1,w2,w3,w4, p, buffer, filepath); + p = npc->parse_duplicate(w1,w2,w3,w4, p, buffer, filepath, (runOnInit?NPO_ONINIT:NPO_NONE), &success); } - else if( (strcmpi(w2,"monster") == 0 || strcmpi(w2,"boss_monster") == 0) && count > 3 ) + else if( (strcmp(w2,"monster") == 0 || strcmp(w2,"boss_monster") == 0) ) { - p = npc_parse_mob(w1, w2, w3, w4, p, buffer, filepath); + p = npc->parse_mob(w1, w2, w3, w4, p, buffer, filepath, &success); } - else if( strcmpi(w2,"mapflag") == 0 && count >= 3 ) + else if( (strcmp(w2,"shop") == 0 || strcmp(w2,"cashshop") == 0) ) { - p = npc_parse_mapflag(w1, w2, trim(w3), trim(w4), p, buffer, filepath); + p = npc->parse_shop(w1,w2,w3,w4, p, buffer, filepath, &success); } else { +#ifdef ENABLE_CASE_CHECK + if( strcasecmp(w2, "warp") == 0 ) { DeprecationWarning("npc_parsesrcfile", w2, "warp", filepath, strline(buffer, p-buffer)); } // TODO + else if( strcasecmp(w2,"shop") == 0 ) { DeprecationWarning("npc_parsesrcfile", w2, "shop", filepath, strline(buffer, p-buffer)); } // TODO + else if( strcasecmp(w2,"cashshop") == 0 ) { DeprecationWarning("npc_parsesrcfile", w2, "cashshop", filepath, strline(buffer, p-buffer)); } // TODO + else if( strcasecmp(w2, "script") == 0 ) { DeprecationWarning("npc_parsesrcfile", w2, "script", filepath, strline(buffer, p-buffer)); } // TODO + else if( strcasecmp(w2,"trader") == 0 ) DeprecationWarning("npc_parsesrcfile", w2, "trader", filepath, strline(buffer, p-buffer)) // TODO + else if( strncasecmp(w2, "duplicate", 9) == 0 ) { + char temp[10]; + safestrncpy(temp, w2, 10); + DeprecationWarning("npc_parsesrcfile", temp, "duplicate", filepath, strline(buffer, p-buffer)); // TODO + } + else if( strcasecmp(w2,"monster") == 0 ) { DeprecationWarning("npc_parsesrcfile", w2, "monster", filepath, strline(buffer, p-buffer)); } // TODO: + else if( strcasecmp(w2,"boss_monster") == 0 ) { DeprecationWarning("npc_parsesrcfile", w2, "boss_monster", filepath, strline(buffer, p-buffer)); } // TODO + else if( strcasecmp(w2, "mapflag") == 0 ) { DeprecationWarning("npc_parsesrcfile", w2, "mapflag", filepath, strline(buffer, p-buffer)); } // TODO + else +#endif // ENABLE_CASE_CHECK ShowError("npc_parsesrcfile: Unable to parse, probably a missing or extra TAB in file '%s', line '%d'. Skipping line...\n * w1=%s\n * w2=%s\n * w3=%s\n * w4=%s\n", filepath, strline(buffer,p-buffer), w1, w2, w3, w4); p = strchr(p,'\n');// skip and continue + success = EXIT_FAILURE; } } aFree(buffer); - return; + return success; } int npc_script_event(struct map_session_data* sd, enum npce_event type) @@ -3693,7 +4238,7 @@ int npc_script_event(struct map_session_data* sd, enum npce_event type) return 0; } for (i = 0; i<script_event[type].event_count; i++) - npc_event_sub(sd,script_event[type].event[i],script_event[type].event_name[i]); + npc->event_sub(sd,script_event[type].event[i],script_event[type].event_name[i]); return i; } @@ -3704,14 +4249,14 @@ void npc_read_event_script(void) char *name; const char *event_name; } config[] = { - {"Login Event",script_config.login_event_name}, - {"Logout Event",script_config.logout_event_name}, - {"Load Map Event",script_config.loadmap_event_name}, - {"Base LV Up Event",script_config.baselvup_event_name}, - {"Job LV Up Event",script_config.joblvup_event_name}, - {"Die Event",script_config.die_event_name}, - {"Kill PC Event",script_config.kill_pc_event_name}, - {"Kill NPC Event",script_config.kill_mob_event_name}, + {"Login Event",script->config.login_event_name}, + {"Logout Event",script->config.logout_event_name}, + {"Load Map Event",script->config.loadmap_event_name}, + {"Base LV Up Event",script->config.baselvup_event_name}, + {"Job LV Up Event",script->config.joblvup_event_name}, + {"Die Event",script->config.die_event_name}, + {"Kill PC Event",script->config.kill_pc_event_name}, + {"Kill NPC Event",script->config.kill_mob_event_name}, }; for (i = 0; i < NPCE_MAX; i++) @@ -3724,7 +4269,7 @@ void npc_read_event_script(void) safestrncpy(name+2,config[i].event_name,62); script_event[i].event_count = 0; - iter = db_iterator(ev_db); + iter = db_iterator(npc->ev_db); for( data = iter->first(iter,&key); iter->exists(iter); data = iter->next(iter,&key) ) { const char* p = key.str; @@ -3737,11 +4282,15 @@ void npc_read_event_script(void) break; } - if( (p=strchr(p,':')) && p && strcmpi(name,p)==0 ) + if( (p=strchr(p,':')) && strcmp(name,p) == 0 ) { script_event[i].event[count] = ed; script_event[i].event_name[count] = key.str; script_event[i].event_count++; +#ifdef ENABLE_CASE_CHECK + } else if( p && strcasecmp(name, p) == 0 ) { + DeprecationWarning2("npc_read_event_script", p, name, config[i].event_name); // TODO +#endif // ENABLE_CASE_CHECK } } dbi_destroy(iter); @@ -3754,211 +4303,236 @@ void npc_read_event_script(void) } } -void npc_clear_pathlist(void) { - struct npc_path_data *npd = NULL; - DBIterator *path_list = db_iterator(npc_path_db); +/** + * @see DBApply + */ +int npc_path_db_clear_sub(DBKey key, DBData *data, va_list args) +{ + struct npc_path_data *npd = DB->data2ptr(data); + if (npd->path) + aFree(npd->path); + return 0; +} - /* free all npc_path_data filepaths */ - for( npd = dbi_first(path_list); dbi_exists(path_list); npd = dbi_next(path_list) ) { - if( npd->path ) - aFree(npd->path); - } +/** + * @see DBApply + */ +int npc_ev_label_db_clear_sub(DBKey key, DBData *data, va_list args) +{ + struct linkdb_node **label_linkdb = DB->data2ptr(data); + linkdb_final(label_linkdb); // linked data (struct event_data*) is freed when clearing ev_db + return 0; +} - dbi_destroy(path_list); +/** + * Main npc file processing + * @param npc_min Minimum npc id - used to know how many NPCs were loaded + **/ +void npc_process_files( int npc_min ) { + struct npc_src_list *file; // Current file + + ShowStatus("Loading NPCs...\r"); + for( file = npc->src_files; file != NULL; file = file->next ) { + ShowStatus("Loading NPC file: %s"CL_CLL"\r", file->name); + if (npc->parsesrcfile(file->name, false) != EXIT_SUCCESS) + map->retval = EXIT_FAILURE; + } + ShowInfo ("Done loading '"CL_WHITE"%d"CL_RESET"' NPCs:"CL_CLL"\n" + "\t-'"CL_WHITE"%d"CL_RESET"' Warps\n" + "\t-'"CL_WHITE"%d"CL_RESET"' Shops\n" + "\t-'"CL_WHITE"%d"CL_RESET"' Scripts\n" + "\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); } //Clear then reload npcs files int npc_reload(void) { - struct npc_src_list *nsl; int16 m, i; int npc_new_min = npc_id; struct s_mapiterator* iter; struct block_list* bl; + if (map->retval == EXIT_FAILURE) + map->retval = EXIT_SUCCESS; // Clear return status in case something failed before. + /* clear guild flag cache */ guild->flags_clear(); - npc_clear_pathlist(); + npc->path_db->clear(npc->path_db, npc->path_db_clear_sub); - db_clear(npc_path_db); - - db_clear(npcname_db); - db_clear(ev_db); + db_clear(npc->name_db); + 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; + //Remove all npcs/mobs. [Skotlex] iter = mapit_geteachiddb(); for( bl = (struct block_list*)mapit->first(iter); mapit->exists(iter); bl = (struct block_list*)mapit->next(iter) ) { switch(bl->type) { - case BL_NPC: - if( bl->id != fake_nd->bl.id )// don't remove fake_nd - npc_unload((struct npc_data *)bl, false); - break; - case BL_MOB: - unit_free(bl,CLR_OUTSIGHT); - break; + case BL_NPC: + if( bl->id != npc->fake_nd->bl.id )// don't remove fake_nd + npc->unload((struct npc_data *)bl, false); + break; + case BL_MOB: + unit->free(bl,CLR_OUTSIGHT); + break; } } mapit->free(iter); - if(battle_config.dynamic_mobs) - {// dynamic check by [random] - for (m = 0; m < iMap->map_num; m++) { + if(battle_config.dynamic_mobs) {// dynamic check by [random] + for (m = 0; m < map->count; m++) { for (i = 0; i < MAX_MOB_LIST_PER_MAP; i++) { - if (map[m].moblist[i] != NULL) { - aFree(map[m].moblist[i]); - map[m].moblist[i] = NULL; + if (map->list[m].moblist[i] != NULL) { + aFree(map->list[m].moblist[i]); + map->list[m].moblist[i] = NULL; } - if( map[m].mob_delete_timer != INVALID_TIMER ) + if( map->list[m].mob_delete_timer != INVALID_TIMER ) { // Mobs were removed anyway,so delete the timer [Inkfish] - iTimer->delete_timer(map[m].mob_delete_timer, iMap->removemobs_timer); - map[m].mob_delete_timer = INVALID_TIMER; + timer->delete(map->list[m].mob_delete_timer, map->removemobs_timer); + map->list[m].mob_delete_timer = INVALID_TIMER; } } + if (map->list[m].npc_num > 0) + ShowWarning("npc_reload: %d npcs weren't removed at map %s!\n", map->list[m].npc_num, map->list[m].name); } - if (map[m].npc_num > 0) - ShowWarning("npc_reload: %d npcs weren't removed at map %s!\n", map[m].npc_num, map[m].name); } // clear mob spawn lookup index - mob_clear_spawninfo(); + mob->clear_spawninfo(); npc_warp = npc_shop = npc_script = 0; npc_mob = npc_cache_mob = npc_delay_mob = 0; // reset mapflags - iMap->flags_init(); + map->flags_init(); - //TODO: the following code is copy-pasted from do_init_npc(); clean it up - // Reloading npcs now - for (nsl = npc_src_files; nsl; nsl = nsl->next) { - ShowStatus("Loading NPC file: %s"CL_CLL"\r", nsl->name); - npc_parsesrcfile(nsl->name,false); - } - ShowInfo ("Done loading '"CL_WHITE"%d"CL_RESET"' NPCs:"CL_CLL"\n" - "\t-'"CL_WHITE"%d"CL_RESET"' Warps\n" - "\t-'"CL_WHITE"%d"CL_RESET"' Shops\n" - "\t-'"CL_WHITE"%d"CL_RESET"' Scripts\n" - "\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_new_min, npc_warp, npc_shop, npc_script, npc_mob, npc_cache_mob, npc_delay_mob); - - instance->final(); + // Reprocess npc files and reload constants + itemdb->name_constants(); + npc_process_files( npc_new_min ); - iMap->zone_init(); - - npc->motd = npc_name2id("HerculesMOTD"); /* [Ind/Hercules] */ - - //Re-read the NPC Script Events cache. - npc_read_event_script(); + instance->reload(); + + map->zone_init(); - /* refresh guild castle flags on both woe setups */ - npc_event_doall("OnAgitInit"); - npc_event_doall("OnAgitInit2"); + npc->motd = npc->name2id("HerculesMOTD"); /* [Ind/Hercules] */ - //Execute the OnInit event for freshly loaded npcs. [Skotlex] - ShowStatus("Event '"CL_WHITE"OnInit"CL_RESET"' executed with '"CL_WHITE"%d"CL_RESET"' NPCs.\n",npc_event_doall("OnInit")); + //Re-read the NPC Script Events cache. + npc->read_event_script(); + // Execute main initialisation events + // The correct initialisation order is: + // OnInit -> OnInterIfInit -> OnInterIfInitOnce -> OnAgitInit -> OnAgitInit2 + npc->event_do_oninit( true ); + npc->market_fromsql(); // Execute rest of the startup events if connected to char-server. [Lance] - if(!CheckForCharServer()){ - ShowStatus("Event '"CL_WHITE"OnInterIfInit"CL_RESET"' executed with '"CL_WHITE"%d"CL_RESET"' NPCs.\n", npc_event_doall("OnInterIfInit")); - ShowStatus("Event '"CL_WHITE"OnInterIfInitOnce"CL_RESET"' executed with '"CL_WHITE"%d"CL_RESET"' NPCs.\n", npc_event_doall("OnInterIfInitOnce")); + // Executed when connection is established with char-server in chrif_connectack + if( !intif->CheckForCharServer() ) { + ShowStatus("Event '"CL_WHITE"OnInterIfInit"CL_RESET"' executed with '"CL_WHITE"%d"CL_RESET"' NPCs.\n", npc->event_doall("OnInterIfInit")); + ShowStatus("Event '"CL_WHITE"OnInterIfInitOnce"CL_RESET"' executed with '"CL_WHITE"%d"CL_RESET"' NPCs.\n", npc->event_doall("OnInterIfInitOnce")); } + // Refresh guild castle flags on both woe setups + // These events are only executed after receiving castle information from char-server + npc->event_doall("OnAgitInit"); + npc->event_doall("OnAgitInit2"); + return 0; } //Unload all npc in the given file -bool npc_unloadfile( const char* path ) { - DBIterator * iter = db_iterator(npcname_db); +bool npc_unloadfile( const char* filepath ) { + DBIterator * iter = db_iterator(npc->name_db); struct npc_data* nd = NULL; bool found = false; for( nd = dbi_first(iter); dbi_exists(iter); nd = dbi_next(iter) ) { - if( nd->path && strcasecmp(nd->path,path) == 0 ) { + if( nd->path && strcasecmp(nd->path,filepath) == 0 ) { // FIXME: This can break in case-sensitive file systems found = true; - npc_unload_duplicates(nd);/* unload any npcs which could duplicate this but be in a different file */ - npc_unload(nd, true); + npc->unload_duplicates(nd);/* unload any npcs which could duplicate this but be in a different file */ + npc->unload(nd, true); } } dbi_destroy(iter); if( found ) /* refresh event cache */ - npc_read_event_script(); + npc->read_event_script(); return found; } void do_clear_npc(void) { - db_clear(npcname_db); - db_clear(ev_db); + db_clear(npc->name_db); + db_clear(npc->ev_db); + npc->ev_label_db->clear(npc->ev_label_db, npc->ev_label_db_clear_sub); } /*========================================== * Destructor *------------------------------------------*/ int do_final_npc(void) { - npc_clear_pathlist(); - ev_db->destroy(ev_db, NULL); - npcname_db->destroy(npcname_db, NULL); - npc_path_db->destroy(npc_path_db, NULL); - ers_destroy(timer_event_ers); - npc_clearsrcfile(); + db_destroy(npc->ev_db); + npc->ev_label_db->destroy(npc->ev_label_db, npc->ev_label_db_clear_sub); + db_destroy(npc->name_db); + npc->path_db->destroy(npc->path_db, npc->path_db_clear_sub); + ers_destroy(npc->timer_event_ers); + npc->clearsrcfile(); return 0; } -static void npc_debug_warps_sub(struct npc_data* nd) -{ +void npc_debug_warps_sub(struct npc_data* nd) { int16 m; if (nd->bl.type != BL_NPC || nd->subtype != WARP || nd->bl.m < 0) return; - m = iMap->mapindex2mapid(nd->u.warp.mapindex); + m = map->mapindex2mapid(nd->u.warp.mapindex); if (m < 0) return; //Warps to another map, nothing to do about it. if (nd->u.warp.x == 0 && nd->u.warp.y == 0) return; // random warp - if (iMap->getcell(m, nd->u.warp.x, nd->u.warp.y, CELL_CHKNPC)) { + if (map->getcell(m, nd->u.warp.x, nd->u.warp.y, CELL_CHKNPC)) { ShowWarning("Warp %s at %s(%d,%d) warps directly on top of an area npc at %s(%d,%d)\n", nd->name, - map[nd->bl.m].name, nd->bl.x, nd->bl.y, - map[m].name, nd->u.warp.x, nd->u.warp.y + map->list[nd->bl.m].name, nd->bl.x, nd->bl.y, + map->list[m].name, nd->u.warp.x, nd->u.warp.y ); } - if (iMap->getcell(m, nd->u.warp.x, nd->u.warp.y, CELL_CHKNOPASS)) { + if (map->getcell(m, nd->u.warp.x, nd->u.warp.y, CELL_CHKNOPASS)) { ShowWarning("Warp %s at %s(%d,%d) warps to a non-walkable tile at %s(%d,%d)\n", nd->name, - map[nd->bl.m].name, nd->bl.x, nd->bl.y, - map[m].name, nd->u.warp.x, nd->u.warp.y + map->list[nd->bl.m].name, nd->bl.x, nd->bl.y, + map->list[m].name, nd->u.warp.x, nd->u.warp.y ); } } -static void npc_debug_warps(void) -{ +static void npc_debug_warps(void) { int16 m, i; - for (m = 0; m < iMap->map_num; m++) - for (i = 0; i < map[m].npc_num; i++) - npc_debug_warps_sub(map[m].npc[i]); + for (m = 0; m < map->count; m++) + for (i = 0; i < map->list[m].npc_num; i++) + npc->debug_warps_sub(map->list[m].npc[i]); } /*========================================== * npc initialization *------------------------------------------*/ -int do_init_npc(void) -{ - struct npc_src_list *file; +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 = iTimer->gettick(); + 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(); //Stock view data for normal npcs. memset(&npc_viewdb, 0, sizeof(npc_viewdb)); @@ -3969,58 +4543,58 @@ int do_init_npc(void) for( i = MAX_NPC_CLASS2_START; i < MAX_NPC_CLASS2_END; i++ ) npc_viewdb2[i - MAX_NPC_CLASS2_START].class_ = i; - ev_db = strdb_alloc((DBOptions)(DB_OPT_DUP_KEY|DB_OPT_RELEASE_DATA),2*NAME_LENGTH+2+1); - npcname_db = strdb_alloc(DB_OPT_BASE,NAME_LENGTH); - npc_path_db = strdb_alloc(DB_OPT_BASE|DB_OPT_DUP_KEY|DB_OPT_RELEASE_DATA,80); + npc->ev_db = strdb_alloc(DB_OPT_DUP_KEY|DB_OPT_RELEASE_DATA, EVENT_NAME_LENGTH); + npc->ev_label_db = strdb_alloc(DB_OPT_DUP_KEY|DB_OPT_RELEASE_DATA, NAME_LENGTH); + npc->name_db = strdb_alloc(DB_OPT_BASE, NAME_LENGTH); + npc->path_db = strdb_alloc(DB_OPT_DUP_KEY|DB_OPT_RELEASE_DATA, 0); - timer_event_ers = ers_new(sizeof(struct timer_event_data),"clif.c::timer_event_ers",ERS_OPT_NONE); + npc_last_npd = NULL; + npc_last_path = NULL; + npc_last_ref = NULL; - // process all npc files - ShowStatus("Loading NPCs...\r"); - for( file = npc_src_files; file != NULL; file = file->next ) { - ShowStatus("Loading NPC file: %s"CL_CLL"\r", file->name); - npc_parsesrcfile(file->name,false); + // Should be loaded before npc processing, otherwise labels could overwrite constant values + // and lead to undefined behavior [Panikon] + itemdb->name_constants(); + + if (!minimal) { + npc->timer_event_ers = ers_new(sizeof(struct timer_event_data),"clif.c::timer_event_ers",ERS_OPT_NONE); + + npc_process_files(START_NPC_NUM); } - ShowInfo ("Done loading '"CL_WHITE"%d"CL_RESET"' NPCs:"CL_CLL"\n" - "\t-'"CL_WHITE"%d"CL_RESET"' Warps\n" - "\t-'"CL_WHITE"%d"CL_RESET"' Shops\n" - "\t-'"CL_WHITE"%d"CL_RESET"' Scripts\n" - "\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 - START_NPC_NUM, npc_warp, npc_shop, npc_script, npc_mob, npc_cache_mob, npc_delay_mob); - iMap->zone_init(); + if (!minimal) { + map->zone_init(); - npc->motd = npc_name2id("HerculesMOTD"); /* [Ind/Hercules] */ + npc->motd = npc->name2id("HerculesMOTD"); /* [Ind/Hercules] */ - // set up the events cache - memset(script_event, 0, sizeof(script_event)); - npc_read_event_script(); + // set up the events cache + memset(script_event, 0, sizeof(script_event)); + npc->read_event_script(); - //Debug function to locate all endless loop warps. - if (battle_config.warp_point_debug) - npc_debug_warps(); + //Debug function to locate all endless loop warps. + if (battle_config.warp_point_debug) + npc->debug_warps(); - iTimer->add_timer_func_list(npc_event_do_clock,"npc_event_do_clock"); - iTimer->add_timer_func_list(npc_timerevent,"npc_timerevent"); + timer->add_func_list(npc->event_do_clock,"npc_event_do_clock"); + timer->add_func_list(npc->timerevent,"npc_timerevent"); + } // Init dummy NPC - fake_nd = (struct npc_data *)aCalloc(1,sizeof(struct npc_data)); - fake_nd->bl.m = -1; - fake_nd->bl.id = npc_get_new_npc_id(); - fake_nd->class_ = -1; - fake_nd->speed = 200; - strcpy(fake_nd->name,"FAKE_NPC"); - memcpy(fake_nd->exname, fake_nd->name, 9); + npc->fake_nd = (struct npc_data *)aCalloc(1,sizeof(struct npc_data)); + npc->fake_nd->bl.m = -1; + npc->fake_nd->bl.id = npc->get_new_npc_id(); + npc->fake_nd->class_ = -1; + npc->fake_nd->speed = 200; + strcpy(npc->fake_nd->name,"FAKE_NPC"); + memcpy(npc->fake_nd->exname, npc->fake_nd->name, 9); npc_script++; - fake_nd->bl.type = BL_NPC; - fake_nd->subtype = SCRIPT; + npc->fake_nd->bl.type = BL_NPC; + npc->fake_nd->subtype = SCRIPT; - strdb_put(npcname_db, fake_nd->exname, fake_nd); - fake_nd->u.scr.timerid = INVALID_TIMER; - iMap->addiddb(&fake_nd->bl); + strdb_put(npc->name_db, npc->fake_nd->exname, npc->fake_nd); + npc->fake_nd->u.scr.timerid = INVALID_TIMER; + map->addiddb(&npc->fake_nd->bl); // End of initialization return 0; @@ -4029,4 +4603,114 @@ void npc_defaults(void) { npc = &npc_s; npc->motd = NULL; + npc->ev_db = NULL; + npc->ev_label_db = NULL; + npc->name_db = NULL; + npc->path_db = NULL; + npc->timer_event_ers = NULL; + npc->fake_nd = NULL; + npc->src_files = NULL; + /* */ + npc->trader_ok = false; + npc->trader_funds[0] = npc->trader_funds[1] = 0; + /* */ + npc->init = do_init_npc; + npc->final = do_final_npc; + /* */ + npc->get_new_npc_id = npc_get_new_npc_id; + npc->get_viewdata = npc_get_viewdata; + npc->isnear_sub = npc_isnear_sub; + npc->isnear = npc_isnear; + npc->ontouch_event = npc_ontouch_event; + npc->ontouch2_event = npc_ontouch2_event; + npc->enable_sub = npc_enable_sub; + npc->enable = npc_enable; + npc->name2id = npc_name2id; + npc->event_dequeue = npc_event_dequeue; + npc->event_export_create = npc_event_export_create; + npc->event_export = npc_event_export; + npc->event_sub = npc_event_sub; + npc->event_doall_sub = npc_event_doall_sub; + npc->event_do = npc_event_do; + npc->event_doall_id = npc_event_doall_id; + npc->event_doall = npc_event_doall; + npc->event_do_clock = npc_event_do_clock; + npc->event_do_oninit = npc_event_do_oninit; + npc->timerevent_export = npc_timerevent_export; + npc->timerevent = npc_timerevent; + npc->timerevent_start = npc_timerevent_start; + npc->timerevent_stop = npc_timerevent_stop; + npc->timerevent_quit = npc_timerevent_quit; + npc->gettimerevent_tick = npc_gettimerevent_tick; + npc->settimerevent_tick = npc_settimerevent_tick; + npc->event = npc_event; + npc->touch_areanpc_sub = npc_touch_areanpc_sub; + npc->touchnext_areanpc = npc_touchnext_areanpc; + npc->touch_areanpc = npc_touch_areanpc; + npc->touch_areanpc2 = npc_touch_areanpc2; + npc->check_areanpc = npc_check_areanpc; + npc->checknear = npc_checknear; + npc->globalmessage = npc_globalmessage; + npc->run_tomb = run_tomb; + npc->click = npc_click; + npc->scriptcont = npc_scriptcont; + npc->buysellsel = npc_buysellsel; + npc->cashshop_buylist = npc_cashshop_buylist; + npc->buylist_sub = npc_buylist_sub; + npc->cashshop_buy = npc_cashshop_buy; + npc->buylist = npc_buylist; + npc->selllist_sub = npc_selllist_sub; + npc->selllist = npc_selllist; + npc->remove_map = npc_remove_map; + npc->unload_ev = npc_unload_ev; + npc->unload_ev_label = npc_unload_ev_label; + npc->unload_dup_sub = npc_unload_dup_sub; + npc->unload_duplicates = npc_unload_duplicates; + npc->unload = npc_unload; + npc->clearsrcfile = npc_clearsrcfile; + npc->addsrcfile = npc_addsrcfile; + npc->delsrcfile = npc_delsrcfile; + npc->parsename = npc_parsename; + npc->parseview = npc_parseview; + npc->viewisid = npc_viewisid; + npc->add_warp = npc_add_warp; + npc->parse_warp = npc_parse_warp; + npc->parse_shop = npc_parse_shop; + npc->convertlabel_db = npc_convertlabel_db; + npc->skip_script = npc_skip_script; + npc->parse_script = npc_parse_script; + npc->parse_duplicate = npc_parse_duplicate; + npc->duplicate4instance = npc_duplicate4instance; + npc->setcells = npc_setcells; + npc->unsetcells_sub = npc_unsetcells_sub; + npc->unsetcells = npc_unsetcells; + npc->movenpc = npc_movenpc; + npc->setdisplayname = npc_setdisplayname; + npc->setclass = npc_setclass; + npc->do_atcmd_event = npc_do_atcmd_event; + npc->parse_function = npc_parse_function; + npc->parse_mob2 = npc_parse_mob2; + npc->parse_mob = npc_parse_mob; + npc->parse_mapflag = npc_parse_mapflag; + npc->parsesrcfile = npc_parsesrcfile; + npc->script_event = npc_script_event; + npc->read_event_script = npc_read_event_script; + npc->path_db_clear_sub = npc_path_db_clear_sub; + npc->ev_label_db_clear_sub = npc_ev_label_db_clear_sub; + npc->reload = npc_reload; + npc->unloadfile = npc_unloadfile; + npc->do_clear_npc = do_clear_npc; + npc->debug_warps_sub = npc_debug_warps_sub; + npc->debug_warps = npc_debug_warps; + npc->secure_timeout_timer = npc_rr_secure_timeout_timer; + /* */ + npc->trader_count_funds = npc_trader_count_funds; + npc->trader_pay = npc_trader_pay; + npc->trader_update = npc_trader_update; + npc->market_buylist = npc_market_buylist; + npc->trader_open = npc_trader_open; + npc->market_fromsql = npc_market_fromsql; + npc->market_tosql = npc_market_tosql; + npc->market_delfromsql = npc_market_delfromsql; + npc->market_delfromsql_sub = npc_market_delfromsql_sub; } diff --git a/src/map/npc.h b/src/map/npc.h index 16e6fe74c..4c904e1ac 100644 --- a/src/map/npc.h +++ b/src/map/npc.h @@ -2,17 +2,32 @@ // See the LICENSE file // Portions Copyright (c) Athena Dev Teams -#ifndef _NPC_H_ -#define _NPC_H_ +#ifndef MAP_NPC_H +#define MAP_NPC_H #include "map.h" // struct block_list #include "status.h" // struct status_change #include "unit.h" // struct unit_data -struct block_list; -struct npc_data; +#include "../common/cbasetypes.h" +#include "../common/db.h" + +struct HPluginData; struct view_data; -struct unit_data npc_base_ud; +enum npc_parse_options { + NPO_NONE = 0x0, + NPO_ONINIT = 0x1, + NPO_TRADER = 0x2, +}; + +enum npc_shop_types { + NST_ZENY,/* default */ + NST_CASH,/* official npc cash shop */ + NST_MARKET,/* official npc market type */ + NST_CUSTOM, + /* */ + NST_MAX, +}; struct npc_timerevent_list { int timer,pos; @@ -22,9 +37,16 @@ struct npc_label_list { int pos; }; struct npc_item_list { - unsigned int nameid,value; + unsigned short nameid; + unsigned int value; + unsigned int qty; }; - +struct npc_shop_data { + unsigned char type;/* what am i */ + struct npc_item_list *item;/* list */ + unsigned short items;/* total */ +}; +struct npc_parse; struct npc_data { struct block_list bl; struct unit_data *ud; @@ -37,7 +59,7 @@ struct npc_data { char exname[NAME_LENGTH+1];// unique npc name int chat_id; int touching_id; - unsigned int next_walktime; + int64 next_walktime; uint8 dir; unsigned size : 2; @@ -46,7 +68,7 @@ struct npc_data { unsigned short level; unsigned short stat_point; - void* chatdb; // pointer to a npc_parse struct (see npc_chat.c) + struct npc_parse *chatdb; char* path;/* path dir */ enum npc_subtype subtype; int src_id; @@ -56,14 +78,17 @@ struct npc_data { short xs,ys; // OnTouch area radius int guild_id; int timer,timerid,timeramount,rid; - unsigned int timertick; + int64 timertick; struct npc_timerevent_list *timer_event; int label_list_num; struct npc_label_list *label_list; + /* */ + struct npc_shop_data *shop; + bool trader; } scr; - struct { + struct { /* TODO duck this as soon as the new shop formatting is deemed stable */ struct npc_item_list* shop_item; - int count; + unsigned short count; } shop; struct { short xs,ys; // OnTouch area radius @@ -76,14 +101,15 @@ struct npc_data { char killer_name[NAME_LENGTH]; } tomb; } u; + /* HPData Support for npc_data */ + struct HPluginData **hdata; + unsigned int hdatac; }; - #define START_NPC_NUM 110000000 -enum actor_classes -{ +enum actor_classes { WARP_CLASS = 45, HIDDEN_WARP_CLASS = 139, WARP_DEBUG_CLASS = 722, @@ -95,15 +121,11 @@ enum actor_classes #define MAX_NPC_CLASS 1000 // New NPC range #define MAX_NPC_CLASS2_START 10000 -#define MAX_NPC_CLASS2_END 10049 +#define MAX_NPC_CLASS2_END 10110 //Checks if a given id is a valid npc id. [Skotlex] //Since new npcs are added all the time, the max valid value is the one before the first mob (Scorpion = 1001) -#define npcdb_checkid(id) ( ( (id) >= 46 && (id) <= 125) || (id) == HIDDEN_WARP_CLASS || ( (id) > 400 && (id) < MAX_NPC_CLASS ) || (id) == INVISIBLE_CLASS || ( (id) > 10000 && (id) < 10049 ) ) - -#ifdef PCRE_SUPPORT -void npc_chat_finalize(struct npc_data* nd); -#endif +#define npcdb_checkid(id) ( ( (id) >= 46 && (id) <= 125) || (id) == HIDDEN_WARP_CLASS || ( (id) > 400 && (id) < MAX_NPC_CLASS ) || (id) == INVISIBLE_CLASS || ( (id) > MAX_NPC_CLASS2_START && (id) < MAX_NPC_CLASS2_END ) ) //Script NPC events. enum npce_event { @@ -117,89 +139,212 @@ enum npce_event { NPCE_KILLNPC, NPCE_MAX }; -struct view_data* npc_get_viewdata(int class_); -int npc_chat_sub(struct block_list* bl, va_list ap); -int npc_event_dequeue(struct map_session_data* sd); -int npc_event(struct map_session_data* sd, const char* eventname, int ontouch); -int npc_touch_areanpc(struct map_session_data* sd, int16 m, int16 x, int16 y); -int npc_touch_areanpc2(struct mob_data *md); // [Skotlex] -int npc_check_areanpc(int flag, int16 m, int16 x, int16 y, int16 range); -int npc_touchnext_areanpc(struct map_session_data* sd,bool leavemap); -int npc_click(struct map_session_data* sd, struct npc_data* nd); -int npc_scriptcont(struct map_session_data* sd, int id, bool closing); -struct npc_data* npc_checknear(struct map_session_data* sd, struct block_list* bl); -int npc_buysellsel(struct map_session_data* sd, int id, int type); -int npc_buylist(struct map_session_data* sd,int n, unsigned short* item_list); -int npc_selllist(struct map_session_data* sd, int n, unsigned short* item_list); -void npc_parse_mob2(struct spawn_data* mob); -const char* npc_parse_mapflag(char* w1, char* w2, char* w3, char* w4, const char* start, const char* buffer, const char* filepath); -struct npc_data* npc_add_warp(char* name, short from_mapid, short from_x, short from_y, short xs, short ys, unsigned short to_mapindex, short to_x, short to_y); -int npc_globalmessage(const char* name,const char* mes); - -void npc_setcells(struct npc_data* nd); -void npc_unsetcells(struct npc_data* nd); -void npc_movenpc(struct npc_data* nd, int16 x, int16 y); -int npc_enable(const char* name, int flag); -void npc_setdisplayname(struct npc_data* nd, const char* newname); -void npc_setclass(struct npc_data* nd, short class_); -struct npc_data* npc_name2id(const char* name); -bool npc_isnear(struct block_list * bl); - -int npc_get_new_npc_id(void); - -void npc_addsrcfile(const char* name); -void npc_delsrcfile(const char* name); -void npc_parsesrcfile(const char* filepath, bool runOnInit); -void do_clear_npc(void); -int do_final_npc(void); -int do_init_npc(void); -void npc_event_do_oninit(void); -int npc_do_ontimer(int npc_id, int option); - -int npc_event_do(const char* name); -int npc_event_doall(const char* name); -int npc_event_doall_id(const char* name, int rid); - -int npc_timerevent_start(struct npc_data* nd, int rid); -int npc_timerevent_stop(struct npc_data* nd); -void npc_timerevent_quit(struct map_session_data* sd); -int npc_gettimerevent_tick(struct npc_data* nd); -int npc_settimerevent_tick(struct npc_data* nd, int newtimer); -int npc_remove_map(struct npc_data* nd); -void npc_unload_duplicates (struct npc_data* nd); -int npc_unload(struct npc_data* nd, bool single); -int npc_reload(void); -void npc_read_event_script(void); -int npc_script_event(struct map_session_data* sd, enum npce_event type); - -int npc_duplicate4instance(struct npc_data *snd, int16 m); -int npc_cashshop_buy(struct map_session_data *sd, int nameid, int amount, int points); - -extern struct npc_data* fake_nd; - -int npc_cashshop_buylist(struct map_session_data *sd, int points, int count, unsigned short* item_list); -/** - * For the Secure NPC Timeout option (check config/Secure.h) [RR] - **/ -#ifdef SECURE_NPCTIMEOUT - int npc_rr_secure_timeout_timer(int tid, unsigned int tick, int id, intptr_t data); -#endif +// linked list of npc source files +struct npc_src_list { + struct npc_src_list* next; + char name[4]; // dynamic array, the structure is allocated with extra bytes (string length) +}; -// @commands (script-based) -int npc_do_atcmd_event(struct map_session_data* sd, const char* command, const char* message, const char* eventname); +struct event_data { + struct npc_data *nd; + int pos; +}; -bool npc_unloadfile( const char* path ); +struct npc_path_data { + char* path; + unsigned short references; +}; -/* npc.c interface (barely started/WIP) */ +/* npc.c interface */ struct npc_interface { /* */ struct npc_data *motd; + DBMap *ev_db; // const char* event_name -> struct event_data* + DBMap *ev_label_db; // const char* label_name (without leading "::") -> struct linkdb_node** (key: struct npc_data*; data: struct event_data*) + DBMap *name_db; // const char* npc_name -> struct npc_data* + DBMap *path_db; + struct eri *timer_event_ers; //For the npc timer data. [Skotlex] + struct npc_data *fake_nd; + struct npc_src_list *src_files; + struct unit_data base_ud; + /* npc trader global data, for ease of transition between the script, cleared on every usage */ + bool trader_ok; + int trader_funds[2]; + /* */ + int (*init) (bool minimal); + int (*final) (void); + /* */ + int (*get_new_npc_id) (void); + struct view_data* (*get_viewdata) (int class_); + int (*isnear_sub) (struct block_list *bl, va_list args); + bool (*isnear) (struct block_list *bl); + int (*ontouch_event) (struct map_session_data *sd, struct npc_data *nd); + int (*ontouch2_event) (struct map_session_data *sd, struct npc_data *nd); + int (*enable_sub) (struct block_list *bl, va_list ap); + int (*enable) (const char *name, int flag); + struct npc_data* (*name2id) (const char *name); + int (*event_dequeue) (struct map_session_data *sd); + DBData (*event_export_create) (DBKey key, va_list args); + int (*event_export) (struct npc_data *nd, int i); + int (*event_sub) (struct map_session_data *sd, struct event_data *ev, const char *eventname); + void (*event_doall_sub) (void *key, void *data, va_list ap); + int (*event_do) (const char *name); + int (*event_doall_id) (const char *name, int rid); + int (*event_doall) (const char *name); + int (*event_do_clock) (int tid, int64 tick, int id, intptr_t data); + void (*event_do_oninit) ( bool reload ); + int (*timerevent_export) (struct npc_data *nd, int i); + int (*timerevent) (int tid, int64 tick, int id, intptr_t data); + int (*timerevent_start) (struct npc_data *nd, int rid); + int (*timerevent_stop) (struct npc_data *nd); + void (*timerevent_quit) (struct map_session_data *sd); + int64 (*gettimerevent_tick) (struct npc_data *nd); + int (*settimerevent_tick) (struct npc_data *nd, int newtimer); + int (*event) (struct map_session_data *sd, const char *eventname, int ontouch); + int (*touch_areanpc_sub) (struct block_list *bl, va_list ap); + int (*touchnext_areanpc) (struct map_session_data *sd, bool leavemap); + int (*touch_areanpc) (struct map_session_data *sd, int16 m, int16 x, int16 y); + int (*touch_areanpc2) (struct mob_data *md); + int (*check_areanpc) (int flag, int16 m, int16 x, int16 y, int16 range); + struct npc_data* (*checknear) (struct map_session_data *sd, struct block_list *bl); + int (*globalmessage) (const char *name, const char *mes); + void (*run_tomb) (struct map_session_data *sd, struct npc_data *nd); + int (*click) (struct map_session_data *sd, struct npc_data *nd); + int (*scriptcont) (struct map_session_data *sd, int id, bool closing); + int (*buysellsel) (struct map_session_data *sd, int id, int type); + int (*cashshop_buylist) (struct map_session_data *sd, int points, int count, unsigned short *item_list); + int (*buylist_sub) (struct map_session_data *sd, int n, unsigned short *item_list, struct npc_data *nd); + int (*cashshop_buy) (struct map_session_data *sd, int nameid, int amount, int points); + int (*buylist) (struct map_session_data *sd, int n, unsigned short *item_list); + int (*selllist_sub) (struct map_session_data *sd, int n, unsigned short *item_list, struct npc_data *nd); + int (*selllist) (struct map_session_data *sd, int n, unsigned short *item_list); + int (*remove_map) (struct npc_data *nd); + int (*unload_ev) (DBKey key, DBData *data, va_list ap); + int (*unload_ev_label) (DBKey key, DBData *data, va_list ap); + int (*unload_dup_sub) (struct npc_data *nd, va_list args); + void (*unload_duplicates) (struct npc_data *nd); + int (*unload) (struct npc_data *nd, bool single); + void (*clearsrcfile) (void); + void (*addsrcfile) (const char *name); + void (*delsrcfile) (const char *name); + void (*parsename) (struct npc_data *nd, const char *name, const char *start, const char *buffer, const char *filepath); + int (*parseview) (const char *w4, const char *start, const char *buffer, const char *filepath); + bool (*viewisid) (const char *viewid); + struct npc_data* (*add_warp) (char *name, short from_mapid, short from_x, short from_y, short xs, short ys, unsigned short to_mapindex, short to_x, short to_y); + const char* (*parse_warp) (char *w1, char *w2, char *w3, char *w4, const char *start, const char *buffer, const char *filepath, int *retval); + const char* (*parse_shop) (char *w1, char *w2, char *w3, char *w4, const char *start, const char *buffer, const char *filepath, int *retval); + void (*convertlabel_db) (struct npc_label_list *label_list, const char *filepath); + const char* (*skip_script) (const char *start, const char *buffer, const char *filepath, int *retval); + const char* (*parse_script) (char *w1, char *w2, char *w3, char *w4, const char *start, const char *buffer, const char *filepath, int options, int *retval); + const char* (*parse_duplicate) (char* w1, char* w2, char* w3, char* w4, const char* start, const char* buffer, const char* filepath, int options, int *retval); + int (*duplicate4instance) (struct npc_data *snd, int16 m); + void (*setcells) (struct npc_data *nd); + int (*unsetcells_sub) (struct block_list *bl, va_list ap); + void (*unsetcells) (struct npc_data *nd); + void (*movenpc) (struct npc_data *nd, int16 x, int16 y); + void (*setdisplayname) (struct npc_data *nd, const char *newname); + void (*setclass) (struct npc_data *nd, short class_); + int (*do_atcmd_event) (struct map_session_data *sd, const char *command, const char *message, const char *eventname); + const char* (*parse_function) (char *w1, char *w2, char *w3, char *w4, const char *start, const char *buffer, const char *filepath, int *retval); + void (*parse_mob2) (struct spawn_data *mobspawn); + const char* (*parse_mob) (char *w1, char *w2, char *w3, char *w4, const char *start, const char *buffer, const char *filepath, int *retval); + const char* (*parse_mapflag) (char *w1, char *w2, char *w3, char *w4, const char *start, const char *buffer, const char *filepath, int *retval); + int (*parsesrcfile) (const char *filepath, bool runOnInit); + int (*script_event) (struct map_session_data *sd, enum npce_event type); + void (*read_event_script) (void); + int (*path_db_clear_sub) (DBKey key, DBData *data, va_list args); + int (*ev_label_db_clear_sub) (DBKey key, DBData *data, va_list args); + int (*reload) (void); + bool (*unloadfile) (const char *filepath); + void (*do_clear_npc) (void); + void (*debug_warps_sub) (struct npc_data *nd); + void (*debug_warps) (void); /* */ -} npc_s; + void (*trader_count_funds) (struct npc_data *nd, struct map_session_data *sd); + bool (*trader_pay) (struct npc_data *nd, struct map_session_data *sd, int price, int points); + void (*trader_update) (int master); + int (*market_buylist) (struct map_session_data* sd, unsigned short list_size, struct packet_npc_market_purchase *p); + bool (*trader_open) (struct map_session_data *sd, struct npc_data *nd); + void (*market_fromsql) (void); + void (*market_tosql) (struct npc_data *nd, unsigned short index); + void (*market_delfromsql) (struct npc_data *nd, unsigned short index); + void (*market_delfromsql_sub) (const char *npcname, unsigned short index); + /** + * For the Secure NPC Timeout option (check config/Secure.h) [RR] + **/ + int (*secure_timeout_timer) (int tid, int64 tick, int id, intptr_t data); +}; struct npc_interface *npc; void npc_defaults(void); -#endif /* _NPC_H_ */ + +/* comes from npc_chat.c */ +#ifdef PCRE_SUPPORT +#include "../../3rdparty/pcre/include/pcre.h" +/* Structure containing all info associated with a single pattern block */ +struct pcrematch_entry { + struct pcrematch_entry* next; + char* pattern; + pcre* pcre_; + pcre_extra* pcre_extra_; + char* label; +}; + +/* A set of patterns that can be activated and deactived with a single command */ +struct pcrematch_set { + struct pcrematch_set* prev; + struct pcrematch_set* next; + struct pcrematch_entry* head; + int setid; +}; + +/* + * Entire data structure hung off a NPC + */ +struct npc_parse { + struct pcrematch_set* active; + struct pcrematch_set* inactive; +}; + +struct npc_chat_interface { + int (*sub) (struct block_list* bl, va_list ap); + void (*finalize) (struct npc_data* nd); + void (*def_pattern) (struct npc_data* nd, int setid, const char* pattern, const char* label); + struct pcrematch_entry* (*create_pcrematch_entry) (struct pcrematch_set* set); + void (*delete_pcreset) (struct npc_data* nd, int setid); + void (*deactivate_pcreset) (struct npc_data* nd, int setid); + void (*activate_pcreset) (struct npc_data* nd, int setid); + struct pcrematch_set* (*lookup_pcreset) (struct npc_data* nd, int setid); + void (*finalize_pcrematch_entry) (struct pcrematch_entry* e); +}; + +struct npc_chat_interface *npc_chat; + +/** + * pcre interface (libpcre) + * so that plugins may share and take advantage of the core's pcre + * should be moved into core/perhaps its own file once hpm is enhanced for login/char + **/ +struct pcre_interface { + pcre *(*compile) (const char *pattern, int options, const char **errptr, int *erroffset, const unsigned char *tableptr); + pcre_extra *(*study) (const pcre *code, int options, const char **errptr); + int (*exec) (const pcre *code, const pcre_extra *extra, PCRE_SPTR subject, int length, int startoffset, int options, int *ovector, int ovecsize); + void (*free) (void *ptr); + int (*copy_substring) (const char *subject, int *ovector, int stringcount, int stringnumber, char *buffer, int buffersize); + void (*free_substring) (const char *stringptr); + int (*copy_named_substring) (const pcre *code, const char *subject, int *ovector, int stringcount, const char *stringname, char *buffer, int buffersize); + int (*get_substring) (const char *subject, int *ovector, int stringcount, int stringnumber, const char **stringptr); +}; + +struct pcre_interface *libpcre; + +/** + * Also defaults libpcre + **/ +void npc_chat_defaults(void); +#endif + +#endif /* MAP_NPC_H */ diff --git a/src/map/npc_chat.c b/src/map/npc_chat.c index c7faa2df6..8bc246819 100644 --- a/src/map/npc_chat.c +++ b/src/map/npc_chat.c @@ -2,25 +2,33 @@ // See the LICENSE file // Portions Copyright (c) Athena Dev Teams -#ifdef PCRE_SUPPORT +#define HERCULES_CORE -#include "../common/timer.h" -#include "../common/malloc.h" -#include "../common/nullpo.h" -#include "../common/showmsg.h" -#include "../common/strlib.h" +#ifdef PCRE_SUPPORT -#include "mob.h" // struct mob_data #include "npc.h" // struct npc_data -#include "pc.h" // struct map_session_data -#include "script.h" // set_var() - -#include "../../3rdparty/pcre/include/pcre.h" +#include <stdarg.h> #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <stdarg.h> + +#include "../../3rdparty/pcre/include/pcre.h" + +#include "mob.h" // struct mob_data +#include "pc.h" // struct map_session_data +#include "script.h" // set_var() +#include "../common/malloc.h" +#include "../common/nullpo.h" +#include "../common/showmsg.h" +#include "../common/strlib.h" +#include "../common/timer.h" + +/** + * interface sources + **/ +struct npc_chat_interface npc_chat_s; +struct pcre_interface libpcre_s; /** @@ -41,7 +49,7 @@ * * defpattern 1, "[^:]+: (.*) loves (.*)", "label"; * - * this defines a new pattern in set 1 using perl syntax + * this defines a new pattern in set 1 using perl syntax * (http://www.troubleshooters.com/codecorn/littperl/perlreg.htm) * and tells it to jump to the supplied label when the pattern * is matched. @@ -51,7 +59,7 @@ * before the script gets executed. * * activatepset 1; - * + * * This activates a set of patterns.. You can have many pattern * sets defined and many active all at once. This feature allows * you to set up "conversations" and ever changing expectations of @@ -70,47 +78,16 @@ * deletes a pset */ -/* Structure containing all info associated with a single pattern block */ -struct pcrematch_entry { - struct pcrematch_entry* next; - char* pattern; - pcre* pcre_; - pcre_extra* pcre_extra_; - char* label; -}; - -/* A set of patterns that can be activated and deactived with a single command */ -struct pcrematch_set { - struct pcrematch_set* prev; - struct pcrematch_set* next; - struct pcrematch_entry* head; - int setid; -}; - -/* - * Entire data structure hung off a NPC - * - * The reason I have done it this way (a void * in npc_data and then - * this) was to reduce the number of patches that needed to be applied - * to a ragnarok distribution to bring this code online. I - * also wanted people to be able to grab this one file to get updates - * without having to do a large number of changes. - */ -struct npc_parse { - struct pcrematch_set* active; - struct pcrematch_set* inactive; -}; - /** - * delete everythign associated with a entry + * delete everything associated with a entry * * This does NOT do the list management */ void finalize_pcrematch_entry(struct pcrematch_entry* e) { - pcre_free(e->pcre_); - pcre_free(e->pcre_extra_); + libpcre->free(e->pcre_); + libpcre->free(e->pcre_extra_); aFree(e->pattern); aFree(e->label); } @@ -118,12 +95,11 @@ void finalize_pcrematch_entry(struct pcrematch_entry* e) /** * Lookup (and possibly create) a new set of patterns by the set id */ -static struct pcrematch_set* lookup_pcreset(struct npc_data* nd, int setid) -{ +struct pcrematch_set* lookup_pcreset(struct npc_data* nd, int setid) { struct pcrematch_set *pcreset; - struct npc_parse *npcParse = (struct npc_parse *) nd->chatdb; - if (npcParse == NULL) - nd->chatdb = npcParse = (struct npc_parse *) aCalloc(sizeof(struct npc_parse), 1); + struct npc_parse *npcParse = nd->chatdb; + if (npcParse == NULL) + nd->chatdb = npcParse = (struct npc_parse *)aCalloc(sizeof(struct npc_parse), 1); pcreset = npcParse->active; @@ -132,7 +108,7 @@ static struct pcrematch_set* lookup_pcreset(struct npc_data* nd, int setid) break; pcreset = pcreset->next; } - if (pcreset == NULL) + if (pcreset == NULL) pcreset = npcParse->inactive; while (pcreset != NULL) { @@ -142,7 +118,7 @@ static struct pcrematch_set* lookup_pcreset(struct npc_data* nd, int setid) } if (pcreset == NULL) { - pcreset = (struct pcrematch_set *) aCalloc(sizeof(struct pcrematch_set), 1); + pcreset = (struct pcrematch_set *)aCalloc(sizeof(struct pcrematch_set), 1); pcreset->next = npcParse->inactive; if (pcreset->next != NULL) pcreset->next->prev = pcreset; @@ -159,11 +135,11 @@ static struct pcrematch_set* lookup_pcreset(struct npc_data* nd, int setid) * * if the setid does not exist, this will silently return */ -static void activate_pcreset(struct npc_data* nd, int setid) +void activate_pcreset(struct npc_data* nd, int setid) { struct pcrematch_set *pcreset; - struct npc_parse *npcParse = (struct npc_parse *) nd->chatdb; - if (npcParse == NULL) + struct npc_parse *npcParse = nd->chatdb; + if (npcParse == NULL) return; // Nothing to activate... pcreset = npcParse->inactive; while (pcreset != NULL) { @@ -177,7 +153,7 @@ static void activate_pcreset(struct npc_data* nd, int setid) pcreset->next->prev = pcreset->prev; if (pcreset->prev != NULL) pcreset->prev->next = pcreset->next; - else + else npcParse->inactive = pcreset->next; pcreset->prev = NULL; @@ -192,15 +168,15 @@ static void activate_pcreset(struct npc_data* nd, int setid) * * if the setid does not exist, this will silently return */ -static void deactivate_pcreset(struct npc_data* nd, int setid) +void deactivate_pcreset(struct npc_data* nd, int setid) { struct pcrematch_set *pcreset; - struct npc_parse *npcParse = (struct npc_parse *) nd->chatdb; - if (npcParse == NULL) + struct npc_parse *npcParse = nd->chatdb; + if (npcParse == NULL) return; // Nothing to deactivate... if (setid == -1) { while(npcParse->active != NULL) - deactivate_pcreset(nd, npcParse->active->setid); + npc_chat->deactivate_pcreset(nd, npcParse->active->setid); return; } pcreset = npcParse->active; @@ -215,7 +191,7 @@ static void deactivate_pcreset(struct npc_data* nd, int setid) pcreset->next->prev = pcreset->prev; if (pcreset->prev != NULL) pcreset->prev->next = pcreset->next; - else + else npcParse->active = pcreset->next; pcreset->prev = NULL; @@ -228,12 +204,12 @@ static void deactivate_pcreset(struct npc_data* nd, int setid) /** * delete a set of patterns. */ -static void delete_pcreset(struct npc_data* nd, int setid) +void delete_pcreset(struct npc_data* nd, int setid) { int active = 1; struct pcrematch_set *pcreset; - struct npc_parse *npcParse = (struct npc_parse *) nd->chatdb; - if (npcParse == NULL) + struct npc_parse *npcParse = nd->chatdb; + if (npcParse == NULL) return; // Nothing to deactivate... pcreset = npcParse->active; while (pcreset != NULL) { @@ -250,7 +226,7 @@ static void delete_pcreset(struct npc_data* nd, int setid) pcreset = pcreset->next; } } - if (pcreset == NULL) + if (pcreset == NULL) return; if (pcreset->next != NULL) @@ -268,8 +244,8 @@ static void delete_pcreset(struct npc_data* nd, int setid) while (pcreset->head) { struct pcrematch_entry* n = pcreset->head->next; - finalize_pcrematch_entry(pcreset->head); - aFree(pcreset->head); // Cleanin' the last ones.. [Lance] + npc_chat->finalize_pcrematch_entry(pcreset->head); + aFree(pcreset->head); // Cleaning the last ones.. [Lance] pcreset->head = n; } @@ -277,9 +253,9 @@ static void delete_pcreset(struct npc_data* nd, int setid) } /** - * create a new pattern entry + * create a new pattern entry */ -static struct pcrematch_entry* create_pcrematch_entry(struct pcrematch_set* set) +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; @@ -313,31 +289,31 @@ void npc_chat_def_pattern(struct npc_data* nd, int setid, const char* pattern, c const char *err; int erroff; - struct pcrematch_set * s = lookup_pcreset(nd, setid); - struct pcrematch_entry *e = create_pcrematch_entry(s); + struct pcrematch_set * s = npc_chat->lookup_pcreset(nd, setid); + struct pcrematch_entry *e = npc_chat->create_pcrematch_entry(s); e->pattern = aStrdup(pattern); e->label = aStrdup(label); - e->pcre_ = pcre_compile(pattern, PCRE_CASELESS, &err, &erroff, NULL); - e->pcre_extra_ = pcre_study(e->pcre_, 0, &err); + e->pcre_ = libpcre->compile(pattern, PCRE_CASELESS, &err, &erroff, NULL); + e->pcre_extra_ = libpcre->study(e->pcre_, 0, &err); } /** * Delete everything associated with a NPC concerning the pattern - * matching code + * matching code * - * this could be more efficent but.. how often do you do this? + * this could be more efficient but.. how often do you do this? */ void npc_chat_finalize(struct npc_data* nd) { - struct npc_parse *npcParse = (struct npc_parse *) nd->chatdb; + struct npc_parse *npcParse = nd->chatdb; if (npcParse == NULL) return; while(npcParse->active) - delete_pcreset(nd, npcParse->active->setid); + npc_chat->delete_pcreset(nd, npcParse->active->setid); while(npcParse->inactive) - delete_pcreset(nd, npcParse->inactive->setid); + npc_chat->delete_pcreset(nd, npcParse->inactive->setid); // Additional cleaning up [Lance] aFree(npcParse); @@ -348,8 +324,8 @@ void npc_chat_finalize(struct npc_data* nd) */ int npc_chat_sub(struct block_list* bl, va_list ap) { - struct npc_data* nd = (struct npc_data *) bl; - struct npc_parse* npcParse = (struct npc_parse *) nd->chatdb; + struct npc_data *nd = (struct npc_data *) bl; + struct npc_parse *npcParse = nd->chatdb; char* msg; int len, i; struct map_session_data* sd; @@ -368,13 +344,13 @@ int npc_chat_sub(struct block_list* bl, va_list ap) // iterate across all active sets for (pcreset = npcParse->active; pcreset != NULL; pcreset = pcreset->next) { - // interate across all patterns in that set + // n across all patterns in that set for (e = pcreset->head; e != NULL; e = e->next) { - int offsets[2*10 + 10]; // 1/3 reserved for temp space requred by pcre_exec + int offsets[2*10 + 10]; // 1/3 reserved for temp space required by pcre_exec // perform pattern match - int r = pcre_exec(e->pcre_, e->pcre_extra_, msg, len, 0, 0, offsets, ARRAYLENGTH(offsets)); + int r = libpcre->exec(e->pcre_, e->pcre_extra_, msg, len, 0, 0, offsets, ARRAYLENGTH(offsets)); if (r > 0) { // save out the matched strings @@ -382,20 +358,20 @@ int npc_chat_sub(struct block_list* bl, va_list ap) { char var[6], val[255]; snprintf(var, sizeof(var), "$@p%i$", i); - pcre_copy_substring(msg, offsets, r, i, val, sizeof(val)); - set_var(sd, var, val); + libpcre->copy_substring(msg, offsets, r, i, val, sizeof(val)); + script->set_var(sd, var, val); } // find the target label.. this sucks.. lst = nd->u.scr.label_list; ARR_FIND(0, nd->u.scr.label_list_num, i, strncmp(lst[i].name, e->label, sizeof(lst[i].name)) == 0); if (i == nd->u.scr.label_list_num) { - ShowWarning("Unable to find label: %s\n", e->label); + ShowWarning("npc_chat_sub: Unable to find label: %s\n", e->label); return 0; } // run the npc script - run_script(nd->u.scr.script,lst[i].pos,sd->bl.id,nd->bl.id); + script->run(nd->u.scr.script,lst[i].pos,sd->bl.id,nd->bl.id); return 0; } } @@ -404,48 +380,68 @@ int npc_chat_sub(struct block_list* bl, va_list ap) return 0; } -// Various script builtins used to support these functions +// Various script built-ins used to support these functions +BUILDIN(defpattern) { + int setid = script_getnum(st,2); + const char* pattern = script_getstr(st,3); + const char* label = script_getstr(st,4); + struct npc_data* nd = (struct npc_data *)map->id2bl(st->oid); + + npc_chat->def_pattern(nd, setid, pattern, label); -int buildin_defpattern(struct script_state* st) -{ - int setid = script->conv_num(st,& (st->stack->stack_data[st->start+2])); - const char* pattern = script->conv_str(st,& (st->stack->stack_data[st->start+3])); - const char* label = script->conv_str(st,& (st->stack->stack_data[st->start+4])); - struct npc_data* nd = (struct npc_data *)iMap->id2bl(st->oid); - - npc_chat_def_pattern(nd, setid, pattern, label); - - return 1; + return true; } -int buildin_activatepset(struct script_state* st) -{ - int setid = script->conv_num(st,& (st->stack->stack_data[st->start+2])); - struct npc_data* nd = (struct npc_data *)iMap->id2bl(st->oid); - - activate_pcreset(nd, setid); +BUILDIN(activatepset) { + int setid = script_getnum(st,2); + struct npc_data* nd = (struct npc_data *)map->id2bl(st->oid); - return 1; + npc_chat->activate_pcreset(nd, setid); + + return true; } -int buildin_deactivatepset(struct script_state* st) -{ - int setid = script->conv_num(st,& (st->stack->stack_data[st->start+2])); - struct npc_data* nd = (struct npc_data *)iMap->id2bl(st->oid); +BUILDIN(deactivatepset) { + int setid = script_getnum(st,2); + struct npc_data* nd = (struct npc_data *)map->id2bl(st->oid); - deactivate_pcreset(nd, setid); + npc_chat->deactivate_pcreset(nd, setid); - return 1; + return true; } -int buildin_deletepset(struct script_state* st) -{ - int setid = script->conv_num(st,& (st->stack->stack_data[st->start+2])); - struct npc_data* nd = (struct npc_data *)iMap->id2bl(st->oid); - - delete_pcreset(nd, setid); +BUILDIN(deletepset) { + int setid = script_getnum(st,2); + struct npc_data* nd = (struct npc_data *)map->id2bl(st->oid); - return 1; + npc_chat->delete_pcreset(nd, setid); + + return true; +} + +void npc_chat_defaults(void) { + npc_chat = &npc_chat_s; + + npc_chat->sub = npc_chat_sub; + npc_chat->finalize = npc_chat_finalize; + npc_chat->def_pattern = npc_chat_def_pattern; + npc_chat->create_pcrematch_entry = create_pcrematch_entry; + npc_chat->delete_pcreset = delete_pcreset; + npc_chat->deactivate_pcreset = deactivate_pcreset; + npc_chat->activate_pcreset = activate_pcreset; + npc_chat->lookup_pcreset = lookup_pcreset; + npc_chat->finalize_pcrematch_entry = finalize_pcrematch_entry; + + libpcre = &libpcre_s; + + libpcre->compile = pcre_compile; + libpcre->study = pcre_study; + libpcre->exec = pcre_exec; + libpcre->free = pcre_free; + libpcre->copy_substring = pcre_copy_substring; + libpcre->free_substring = pcre_free_substring; + libpcre->copy_named_substring = pcre_copy_named_substring; + libpcre->get_substring = pcre_get_substring; } #endif //PCRE_SUPPORT diff --git a/src/map/packets.h b/src/map/packets.h index c467090dd..810f341d4 100644 --- a/src/map/packets.h +++ b/src/map/packets.h @@ -3,8 +3,8 @@ //Included directly by clif.h in packet_loaddb() -#ifndef _PACKETS_H_ -#define _PACKETS_H_ +#ifndef MAP_PACKETS_H +#define MAP_PACKETS_H #ifndef packet #define packet(a,b,...) @@ -1613,7 +1613,7 @@ packet(0x020d,-1); //2009-10-27aRagexeRE #if PACKETVER >= 20091027 - packet(0x07f5,6,clif->pGMReqAccountName,2); + packet(0x07f5,6,clif->pGMFullStrip,2); packet(0x07f6,14); #endif @@ -1971,14 +1971,14 @@ packet(0x020d,-1); #ifndef PACKETVER_RE packet(0x091D,18,clif->pPartyBookingRegisterReq,2,4,6); #else - packet(0x08E5,41,clif->pPartyBookingRegisterReq,2,4); + packet(0x08E5,41,clif->pPartyRecruitRegisterReq,2,4); #endif packet(0x08E6,4); - packet(0x08E7,10,clif->pPartyBookingSearchReq,2); + packet(0x08E7,10,clif->pPartyRecruitSearchReq,2); packet(0x08E8,-1); - packet(0x08E9,2,clif->pPartyBookingDeleteReq,2); + packet(0x08E9,2,clif->pPartyRecruitDeleteReq,2); packet(0x08EA,4); - packet(0x08EB,39,clif->pPartyBookingUpdateReq,2); + packet(0x08EB,39,clif->pPartyRecruitUpdateReq,2); packet(0x08EC,73); packet(0x08ED,43); packet(0x08EE,6); @@ -2022,16 +2022,14 @@ packet(0x020d,-1); packet(0x0364,8,clif->pMoveFromKafra,2,4); packet(0x096A,6,clif->pGetCharNameRequest,2); packet(0x0368,6,clif->pSolveCharName,2); - packet(0x08E5,41,clif->pPartyBookingRegisterReq,2,4); + packet(0x08E5,41,clif->pPartyRecruitRegisterReq,2,4); packet(0x08d2,10); packet(0x0916,26,clif->pGuildInvite2,2); - packetKeys(0x1540e48,0x13041224,0x31247924); - #endif #ifndef PACKETVER_RE #if PACKETVER >= 20120604 - packet(0x0861,18,clif->pPartyBookingRegisterReq,2,4,6); + packet(0x0861,18,clif->pPartyRecruitRegisterReq,2,4,6); #endif #endif @@ -2065,10 +2063,36 @@ packet(0x020d,-1); packet(0x0886,2,clif->pReqCloseBuyingStore,0); #endif -//2012-07-16aRagExe (special thanks to Yommy!) +//2012-07-16aRagExe (special thanks to Yommy/Frost!) #if PACKETVER >= 20120716 + packet(0x0879,18,clif->pPartyBookingRegisterReq,2,4,6); + packet(0x023B,26,clif->pFriendsListAdd,2); + packet(0x0361,5,clif->pHomMenu,2,4); + packet(0x0819,36,clif->pStoragePassword,0); + packet(0x0802,26,clif->pPartyInvite2,2); + packet(0x022D,19,clif->pWantToConnection,2,6,10,14,18); + packet(0x0369,7,clif->pActionRequest,2,6); + packet(0x083C,10,clif->pUseSkillToId,2,4,6); + packet(0x0439,8,clif->pUseItem,2,4); + packet(0x0281,-1,clif->pItemListWindowSelected,2,4,8); + packet(0x0815,-1,clif->pReqOpenBuyingStore,2,4,8,9,89); + packet(0x0817,2,clif->pReqCloseBuyingStore,0); + packet(0x0360,6,clif->pReqClickBuyingStore,2); + packet(0x0940,-1,clif->pReqTradeBuyingStore,2,4,8,12); + packet(0x0811,-1,clif->pSearchStoreInfo,2,4,5,9,13,14,15); + packet(0x0835,2,clif->pSearchStoreInfoNextPage,0); + packet(0x0838,12,clif->pSearchStoreInfoListItemClick,2,6,10); + packet(0x0437,5,clif->pWalkToXY,2); + packet(0x035F,6,clif->pTickSend,2); + packet(0x0202,5,clif->pChangeDir,2,4); + packet(0x07E4,6,clif->pTakeItem,2); + packet(0x0362,6,clif->pDropItem,2,4); + packet(0x07EC,8,clif->pMoveToKafra,2,4); packet(0x0364,8,clif->pMoveFromKafra,2,4); - packetKeys(0x76052205, 0x22052205, 0x22052205); + packet(0x0438,10,clif->pUseSkillToPos,2,4,6,8); + packet(0x0366,90,clif->pUseSkillToPosMoreInfo,2,4,6,8,10); + packet(0x096A,6,clif->pGetCharNameRequest,2); + packet(0x0368,6,clif->pSolveCharName,2); #endif //2013-03-20Ragexe (Judas + Yommy) @@ -2094,7 +2118,11 @@ packet(0x020d,-1); packet(0x035F,6,clif->pReqClickBuyingStore,2); packet(0x0886,2,clif->pReqCloseBuyingStore,0); packet(0x0938,-1,clif->pReqOpenBuyingStore,2,4,8,9,89); - packet(0x085D,41,clif->pPartyBookingRegisterReq,2,4); +#ifdef PACKETVER_RE + packet(0x085D,41,clif->pPartyRecruitRegisterReq,2,4); +#else // not PACKETVER_RE + packet(0x085D,18,clif->pPartyBookingRegisterReq,2,4); +#endif // PACKETVER_RE //packet(0x095A,8); // unknown usage packet(0x0868,-1,clif->pItemListWindowSelected,2,4,8); packet(0x0888,19,clif->pWantToConnection,2,6,10,14,18); @@ -2103,7 +2131,6 @@ packet(0x020d,-1); packet(0x086F,26,clif->pFriendsListAdd,2); packet(0x093F,5,clif->pHomMenu,2,4); packet(0x0947,36,clif->pStoragePassword,0); - packetKeys(0x3F094C49, 0x55F86C1E, 0x58AA359A); // Shuffle End // New Packets @@ -2136,7 +2163,11 @@ packet(0x020d,-1); packet(0x0360,6,clif->pReqClickBuyingStore,2); packet(0x0817,2,clif->pReqCloseBuyingStore,0); packet(0x0815,-1,clif->pReqOpenBuyingStore,2,4,8,9,89); - packet(0x092D,41,clif->pPartyBookingRegisterReq,2,4); +#ifdef PACKETVER_RE + packet(0x092D,41,clif->pPartyRecruitRegisterReq,2,4); +#else // not PACKETVER_RE + packet(0x092D,18,clif->pPartyBookingRegisterReq,2,4); +#endif // PACKETVER_RE //packet(0x08AA,8); // CZ_JOIN_BATTLE_FIELD packet(0x0963,-1,clif->pItemListWindowSelected,2,4,8); packet(0x0943,19,clif->pWantToConnection,2,6,10,14,18); @@ -2171,7 +2202,11 @@ packet(0x020d,-1); packet(0x0368,6,clif->pReqClickBuyingStore,2); packet(0x086E,2,clif->pReqCloseBuyingStore,0); packet(0x0874,-1,clif->pReqOpenBuyingStore,2,4,8,9,89); - packet(0x089B,41,clif->pPartyBookingRegisterReq,2,4); +#ifdef PACKETVER_RE + packet(0x089B,41,clif->pPartyRecruitRegisterReq,2,4); +#else // not PACKETVER_RE + packet(0x089B,18,clif->pPartyBookingRegisterReq,2,4); +#endif // PACKETVER_RE //packet(0x0965,8); // CZ_JOIN_BATTLE_FIELD packet(0x086A,-1,clif->pItemListWindowSelected,2,4,8); packet(0x08A9,19,clif->pWantToConnection,2,6,10,14,18); @@ -2205,7 +2240,11 @@ packet(0x020d,-1); packet(0x0892,6,clif->pReqClickBuyingStore,2); packet(0x0964,2,clif->pReqCloseBuyingStore,0); packet(0x0869,-1,clif->pReqOpenBuyingStore,2,4,8,9,89); - packet(0x0874,41,clif->pPartyBookingRegisterReq,2,4); +#ifdef PACKETVER_RE + packet(0x0874,41,clif->pPartyRecruitRegisterReq,2,4); +#else // not PACKETVER_RE + packet(0x0874,18,clif->pPartyBookingRegisterReq,2,4); +#endif // PACKETVER_RE // packet(0x088E,8); // CZ_JOIN_BATTLE_FIELD packet(0x0958,-1,clif->pItemListWindowSelected,2,4,8); packet(0x0919,19,clif->pWantToConnection,2,6,10,14,18); @@ -2238,7 +2277,11 @@ packet(0x020d,-1); packet(0x0360,6,clif->pReqClickBuyingStore,2); packet(0x0817,2,clif->pReqCloseBuyingStore,0); packet(0x0815,-1,clif->pReqOpenBuyingStore,2,4,8,9,89); - packet(0x0365,41,clif->pPartyBookingRegisterReq,2,4); +#ifdef PACKETVER_RE + packet(0x0365,41,clif->pPartyRecruitRegisterReq,2,4); +#else // not PACKETVER_RE + packet(0x0365,18,clif->pPartyBookingRegisterReq,2,4); +#endif // PACKETVER_RE // packet(0x0363,8); // CZ_JOIN_BATTLE_FIELD packet(0x0281,-1,clif->pItemListWindowSelected,2,4,8); packet(0x022D,19,clif->pWantToConnection,2,6,10,14,18); @@ -2249,8 +2292,714 @@ packet(0x020d,-1); packet(0x0883,36,clif->pStoragePassword,0); #endif +//2013-06-12Ragexe (Shakto) +#if PACKETVER >= 20130612 + packet(0x087E,5,clif->pChangeDir,2,4); + packet(0x0919,19,clif->pWantToConnection,2,6,10,14,18); + packet(0x0940,26,clif->pFriendsListAdd,2); + packet(0x093A,5,clif->pHomMenu,2,4); + packet(0x0964,36,clif->pStoragePassword,0); +#endif + +//2013-06-18Ragexe (Shakto) +#if PACKETVER >= 20130618 + packet(0x0889,7,clif->pActionRequest,2,6); + packet(0x0951,10,clif->pUseSkillToId,2,4,6); + packet(0x088E,5,clif->pWalkToXY,2); + packet(0x0930,6,clif->pTickSend,2); + packet(0x08A6,5,clif->pChangeDir,2,4); + packet(0x0962,6,clif->pTakeItem,2); + packet(0x0917,6,clif->pDropItem,2,4); + packet(0x0885,8,clif->pMoveToKafra,2,4); + packet(0x0936,8,clif->pMoveFromKafra,2,4); + packet(0x096A,10,clif->pUseSkillToPos,2,4,6,8); + packet(0x094F,90,clif->pUseSkillToPosMoreInfo,2,4,6,8,10); + packet(0x0944,6,clif->pGetCharNameRequest,2); + packet(0x0945,6,clif->pSolveCharName,2); + packet(0x0890,12,clif->pSearchStoreInfoListItemClick,2,6,10); + packet(0x0363,2,clif->pSearchStoreInfoNextPage,0); + packet(0x0281,-1,clif->pSearchStoreInfo,2,4,5,9,13,14,15); + packet(0x0891,-1,clif->pReqTradeBuyingStore,2,4,8,12); + packet(0x0862,6,clif->pReqClickBuyingStore,2); + packet(0x085A,2,clif->pReqCloseBuyingStore,0); + packet(0x0932,-1,clif->pReqOpenBuyingStore,2,4,8,9,89); +#ifdef PACKETVER_RE + packet(0x08A7,41,clif->pPartyRecruitRegisterReq,2,4); +#else // not PACKETVER_RE + packet(0x08A7,18,clif->pPartyBookingRegisterReq,2,4); +#endif // PACKETVER_RE + // packet(0x087A,8); // CZ_JOIN_BATTLE_FIELD + packet(0x0942,-1,clif->pItemListWindowSelected,2,4,8); + packet(0x095B,19,clif->pWantToConnection,2,6,10,14,18); + packet(0x0887,26,clif->pPartyInvite2,2); + // packet(0x0878,4); // CZ_GANGSI_RANK + packet(0x0953,26,clif->pFriendsListAdd,2); + packet(0x02C4,5,clif->pHomMenu,2,4); + packet(0x0864,36,clif->pStoragePassword,0); +#endif + +//2013-06-26Ragexe (Shakto) +#if PACKETVER >= 20130626 + packet(0x0369,7,clif->pActionRequest,2,6); + packet(0x083C,10,clif->pUseSkillToId,2,4,6); + packet(0x0437,5,clif->pWalkToXY,2); + packet(0x035F,6,clif->pTickSend,2); + packet(0x094D,5,clif->pChangeDir,2,4); + packet(0x088B,6,clif->pTakeItem,2); + packet(0x0952,6,clif->pDropItem,2,4); + packet(0x0921,8,clif->pMoveToKafra,2,4); + packet(0x0817,8,clif->pMoveFromKafra,2,4); + packet(0x0438,10,clif->pUseSkillToPos,2,4,6,8); + packet(0x0366,90,clif->pUseSkillToPosMoreInfo,2,4,6,8,10); + packet(0x096A,6,clif->pGetCharNameRequest,2); + packet(0x0368,6,clif->pSolveCharName,2); + packet(0x0838,12,clif->pSearchStoreInfoListItemClick,2,6,10); + packet(0x0835,2,clif->pSearchStoreInfoNextPage,0); + packet(0x0819,-1,clif->pSearchStoreInfo,2,4,5,9,13,14,15); + packet(0x0811,-1,clif->pReqTradeBuyingStore,2,4,8,12); + packet(0x0360,6,clif->pReqClickBuyingStore,2); + packet(0x0365,2,clif->pReqCloseBuyingStore,0); + packet(0x0815,-1,clif->pReqOpenBuyingStore,2,4,8,9,89); +#ifdef PACKETVER_RE + packet(0x0894,41,clif->pPartyRecruitRegisterReq,2,4); +#else // not PACKETVER_RE + packet(0x0894,18,clif->pPartyBookingRegisterReq,2,4); +#endif // PACKETVER_RE + // packet(0x0860,8); // CZ_JOIN_BATTLE_FIELD + packet(0x08A5,-1,clif->pItemListWindowSelected,2,4,8); + packet(0x088C,19,clif->pWantToConnection,2,6,10,14,18); + packet(0x0895,26,clif->pPartyInvite2,2); + // packet(0x088F,4); // CZ_GANGSI_RANK + packet(0x08AB,26,clif->pFriendsListAdd,2); + packet(0x0960,5,clif->pHomMenu,2,4); + packet(0x0930,36,clif->pStoragePassword,0); +#endif + +/* Bank System [Yommy/Hercules] */ +#if PACKETVER >= 20130724 + packet(0x09A6,12); // ZC_BANKING_CHECK + packet(0x09A7,10,clif->pBankDeposit,2,4,6); + packet(0x09A8,16); // ZC_ACK_BANKING_DEPOSIT + packet(0x09A9,10,clif->pBankWithdraw,2,4,6); + packet(0x09AA,16); // ZC_ACK_BANKING_WITHDRAW + packet(0x09AB,6,clif->pBankCheck,2,4); + //// + packet(0x09B6,6,clif->pBankOpen,2,4); + packet(0x09B7,4); // ZC_ACK_OPEN_BANKING + packet(0x09B8,6,clif->pBankClose,2,4); + packet(0x09B9,4); // ZC_ACK_CLOSE_BANKING +#endif + +//2013-07-03Ragexe (Shakto) +#if PACKETVER >= 20130703 + packet(0x0930,5,clif->pChangeDir,2,4); + packet(0x07E4,6,clif->pTakeItem,2); + packet(0x0362,6,clif->pDropItem,2,4); + packet(0x07EC,8,clif->pMoveToKafra,2,4); + packet(0x0364,8,clif->pMoveFromKafra,2,4); + packet(0x0202,6,clif->pReqClickBuyingStore,2); + packet(0x0817,2,clif->pReqCloseBuyingStore,0); + packet(0x0815,-1,clif->pReqOpenBuyingStore,2,4,8,9,89); +#ifdef PACKETVER_RE + packet(0x0365,41,clif->pPartyRecruitRegisterReq,2,4); +#else // not PACKETVER_RE + packet(0x0365,18,clif->pPartyBookingRegisterReq,2,4); +#endif // PACKETVER_RE + // packet(0x0363,8); // CZ_JOIN_BATTLE_FIELD + packet(0x0281,-1,clif->pItemListWindowSelected,2,4,8); + packet(0x022D,19,clif->pWantToConnection,2,6,10,14,18); + packet(0x0802,26,clif->pPartyInvite2,2); + // packet(0x0436,4); // CZ_GANGSI_RANK + packet(0x0360,26,clif->pFriendsListAdd,2); + packet(0x094A,5,clif->pHomMenu,2,4); + packet(0x0873,36,clif->pStoragePassword,0); + packet(0x097C,4,clif->pRanklist); +#endif + +//2013-08-07Ragexe (Shakto) +#if PACKETVER >= 20130807 + packet(0x0369,7,clif->pActionRequest,2,6); + packet(0x083C,10,clif->pUseSkillToId,2,4,6); + packet(0x0437,5,clif->pWalkToXY,2); + packet(0x035F,6,clif->pTickSend,2); + packet(0x0202,5,clif->pChangeDir,2,4); + packet(0x07E4,6,clif->pTakeItem,2); + packet(0x0362,6,clif->pDropItem,2,4); + packet(0x07EC,8,clif->pMoveToKafra,2,4); + packet(0x0364,8,clif->pMoveFromKafra,2,4); + packet(0x0438,10,clif->pUseSkillToPos,2,4,6,8); + packet(0x0366,90,clif->pUseSkillToPosMoreInfo,2,4,6,8,10); + packet(0x096A,6,clif->pGetCharNameRequest,2); + packet(0x0368,6,clif->pSolveCharName,2); + packet(0x0838,12,clif->pSearchStoreInfoListItemClick,2,6,10); + packet(0x0835,2,clif->pSearchStoreInfoNextPage,0); + packet(0x0819,-1,clif->pSearchStoreInfo,2,4,5,9,13,14,15); + packet(0x0811,-1,clif->pReqTradeBuyingStore,2,4,8,12); + packet(0x0360,6,clif->pReqClickBuyingStore,2); + packet(0x0817,2,clif->pReqCloseBuyingStore,0); + packet(0x0815,-1,clif->pReqOpenBuyingStore,2,4,8,9,89); +#ifdef PACKETVER_RE + packet(0x0365,41,clif->pPartyRecruitRegisterReq,2,4); +#else // not PACKETVER_RE + packet(0x0365,18,clif->pPartyBookingRegisterReq,2,4); +#endif // PACKETVER_RE + // packet(0x0363,8); // CZ_JOIN_BATTLE_FIELD + packet(0x0281,-1,clif->pItemListWindowSelected,2,4,8); + packet(0x022D,19,clif->pWantToConnection,2,6,10,14,18); + packet(0x0802,26,clif->pPartyInvite2,2); + // packet(0x0436,4); // CZ_GANGSI_RANK + packet(0x023B,26,clif->pFriendsListAdd,2); + packet(0x0361,5,clif->pHomMenu,2,4); + packet(0x0887,36,clif->pStoragePassword,0); +#endif + +//2013-08-14aRagexe - Themon +#if PACKETVER >= 20130814 + packet(0x0874,7,clif->pActionRequest,2,6); + packet(0x0947,10,clif->pUseSkillToId,2,4,6); + packet(0x093A,5,clif->pWalkToXY,2); + packet(0x088A,6,clif->pTickSend,2); + packet(0x088C,5,clif->pChangeDir,2,4); + packet(0x0926,6,clif->pTakeItem,2); + packet(0x095F,6,clif->pDropItem,2,4); + packet(0x0202,8,clif->pMoveToKafra,2,4); + packet(0x0873,8,clif->pMoveFromKafra,2,4); + packet(0x0887,10,clif->pUseSkillToPos,2,4,6,8); + packet(0x0962,90,clif->pUseSkillToPosMoreInfo,2,4,6,8,10); + packet(0x0937,6,clif->pGetCharNameRequest,2); + packet(0x0923,6,clif->pSolveCharName,2); + packet(0x0868,12,clif->pSearchStoreInfoListItemClick,2,6,10); + packet(0x0941,2,clif->pSearchStoreInfoNextPage,0); + packet(0x0889,-1,clif->pSearchStoreInfo,2,4,5,9,13,14,15); + packet(0x0835,-1,clif->pReqTradeBuyingStore,2,4,8,12); + packet(0x0895,6,clif->pReqClickBuyingStore,2); + packet(0x094E,2,clif->pReqCloseBuyingStore,0); + packet(0x0936,-1,clif->pReqOpenBuyingStore,2,4,8,9,89); +#ifdef PACKETVER_RE + packet(0x0365,41,clif->pPartyRecruitRegisterReq,2,4); +#else // not PACKETVER_RE + packet(0x0959,18,clif->pPartyBookingRegisterReq,2,4); +#endif // PACKETVER_RE + // packet(0x0896,8); // CZ_JOIN_BATTLE_FIELD + packet(0x08A4,-1,clif->pItemListWindowSelected,2,4,8); + packet(0x0368,19,clif->pWantToConnection,2,6,10,14,18); + packet(0x0927,26,clif->pPartyInvite2,2); + // packet(0x0815,4); // CZ_GANGSI_RANK + packet(0x0281,26,clif->pFriendsListAdd,2); + packet(0x0958,5,clif->pHomMenu,2,4); + packet(0x0885,36,clif->pStoragePassword,0); +#endif + +// 2013-12-18bRagexe - Yommy +#if PACKETVER >= 20131218 + packet(0x0369,7,clif->pActionRequest,2,6); + packet(0x083C,10,clif->pUseSkillToId,2,4,6); + packet(0x0437,5,clif->pWalkToXY,2); + packet(0x035F,6,clif->pTickSend,2); + packet(0x0947,5,clif->pChangeDir,2,4); + packet(0x07E4,6,clif->pTakeItem,2); + packet(0x0362,6,clif->pDropItem,2,4); + packet(0x07EC,8,clif->pMoveToKafra,2,4); + packet(0x0364,8,clif->pMoveFromKafra,2,4); + packet(0x0438,10,clif->pUseSkillToPos,2,4,6,8); + packet(0x0366,90,clif->pUseSkillToPosMoreInfo,2,4,6,8,10); + packet(0x096A,6,clif->pGetCharNameRequest,2); + packet(0x0368,6,clif->pSolveCharName,2); + packet(0x0838,12,clif->pSearchStoreInfoListItemClick,2,6,10); + packet(0x0835,2,clif->pSearchStoreInfoNextPage,0); + packet(0x0819,-1,clif->pSearchStoreInfo,2,4,5,9,13,14,15); + packet(0x022D,-1,clif->pReqTradeBuyingStore,2,4,8,12); + packet(0x0360,6,clif->pReqClickBuyingStore,2); + packet(0x0817,2,clif->pReqCloseBuyingStore,0); + packet(0x0815,-1,clif->pReqOpenBuyingStore,2,4,8,9,89); + packet(0x0365,18,clif->pPartyBookingRegisterReq,2,4); + // packet(0x0363,8); // CZ_JOIN_BATTLE_FIELD + packet(0x0281,-1,clif->pItemListWindowSelected,2,4,8); + packet(0x092F,19,clif->pWantToConnection,2,6,10,14,18); + packet(0x0802,26,clif->pPartyInvite2,2); + // packet(0x087B,4); // CZ_GANGSI_RANK + packet(0x08AB,26,clif->pFriendsListAdd,2); + packet(0x0811,5,clif->pHomMenu,2,4); + packet(0x085C,36,clif->pStoragePassword,0); + /* New */ + packet(0x09d4,2,clif->pNPCShopClosed); + packet(0x09ce,102,clif->pGM_Monster_Item,2); + /* NPC Market */ + packet(0x09d8,2,clif->pNPCMarketClosed); + packet(0x09d6,-1,clif->pNPCMarketPurchase); +#endif + +// 2013-12-23cRagexe - Yommy +#if PACKETVER >= 20131223 + packet(0x0369,7,clif->pActionRequest,2,6); + packet(0x083C,10,clif->pUseSkillToId,2,4,6); + packet(0x0437,5,clif->pWalkToXY,2); + packet(0x035F,6,clif->pTickSend,2); + packet(0x0202,5,clif->pChangeDir,2,4); + packet(0x07E4,6,clif->pTakeItem,2); + packet(0x0362,6,clif->pDropItem,2,4); + packet(0x07EC,8,clif->pMoveToKafra,2,4); + packet(0x0364,8,clif->pMoveFromKafra,2,4); + packet(0x0438,10,clif->pUseSkillToPos,2,4,6,8); + packet(0x0366,90,clif->pUseSkillToPosMoreInfo,2,4,6,8,10); + packet(0x096A,6,clif->pGetCharNameRequest,2); + packet(0x0368,6,clif->pSolveCharName,2); + packet(0x0838,12,clif->pSearchStoreInfoListItemClick,2,6,10); + packet(0x0835,2,clif->pSearchStoreInfoNextPage,0); + packet(0x0819,-1,clif->pSearchStoreInfo,2,4,5,9,13,14,15); + packet(0x0811,-1,clif->pReqTradeBuyingStore,2,4,8,12); + packet(0x0360,6,clif->pReqClickBuyingStore,2); + packet(0x0817,2,clif->pReqCloseBuyingStore,0); + packet(0x0815,-1,clif->pReqOpenBuyingStore,2,4,8,9,89); + packet(0x0365,18,clif->pPartyBookingRegisterReq,2,4); + // packet(0x0363,8); // CZ_JOIN_BATTLE_FIELD + packet(0x0281,-1,clif->pItemListWindowSelected,2,4,8); + packet(0x022d,19,clif->pWantToConnection,2,6,10,14,18); + packet(0x0802,26,clif->pPartyInvite2,2); + // packet(0x0436,4); // CZ_GANGSI_RANK + packet(0x023B,26,clif->pFriendsListAdd,2); + packet(0x0361,5,clif->pHomMenu,2,4); + packet(0x08A4,36,clif->pStoragePassword,0); + packet(0x09df,7); +#endif + +// 2013-12-30aRagexe - Yommy +#if PACKETVER >= 20131230 + packet(0x0871,7,clif->pActionRequest,2,6); + packet(0x02C4,10,clif->pUseSkillToId,2,4,6); + packet(0x035F,5,clif->pWalkToXY,2); + packet(0x0438,6,clif->pTickSend,2); + packet(0x094A,5,clif->pChangeDir,2,4); + packet(0x092A,6,clif->pTakeItem,2); + packet(0x0860,6,clif->pDropItem,2,4); + packet(0x0968,8,clif->pMoveToKafra,2,4); + packet(0x0895,8,clif->pMoveFromKafra,2,4); + packet(0x091E,10,clif->pUseSkillToPos,2,4,6,8); + packet(0x096A,90,clif->pUseSkillToPosMoreInfo,2,4,6,8,10); + packet(0x0926,6,clif->pGetCharNameRequest,2); + packet(0x0898,6,clif->pSolveCharName,2); + packet(0x087B,12,clif->pSearchStoreInfoListItemClick,2,6,10); + packet(0x0369,2,clif->pSearchStoreInfoNextPage,0); + packet(0x093D,-1,clif->pSearchStoreInfo,2,4,5,9,13,14,15); + packet(0x087F,-1,clif->pReqTradeBuyingStore,2,4,8,12); + packet(0x0969,6,clif->pReqClickBuyingStore,2); + packet(0x094C,2,clif->pReqCloseBuyingStore,0); + packet(0x0365,-1,clif->pReqOpenBuyingStore,2,4,8,9,89); + packet(0x091F,18,clif->pPartyBookingRegisterReq,2,4); + // packet(0x093E,8); // CZ_JOIN_BATTLE_FIELD + packet(0x022D,-1,clif->pItemListWindowSelected,2,4,8); + packet(0x089C,19,clif->pWantToConnection,2,6,10,14,18); + packet(0x08A9,26,clif->pPartyInvite2,2); + // packet(0x087E,4); // CZ_GANGSI_RANK + packet(0x0943,26,clif->pFriendsListAdd,2); + packet(0x0949,5,clif->pHomMenu,2,4); + packet(0x091D,36,clif->pStoragePassword,0); +#endif + +// 2014 Packet Data + +// 2014-01-15eRagexe - YomRawr +#if PACKETVER >= 20140115 + packet(0x0369,7,clif->pActionRequest,2,6); + packet(0x083C,10,clif->pUseSkillToId,2,4,6); + packet(0x0437,5,clif->pWalkToXY,2); + packet(0x035F,6,clif->pTickSend,2); + packet(0x08A7,5,clif->pChangeDir,2,4); + packet(0x0940,6,clif->pTakeItem,2); + packet(0x0361,6,clif->pDropItem,2,4); + packet(0x088E,8,clif->pMoveToKafra,2,4); + packet(0x0367,8,clif->pMoveFromKafra,2,4); + packet(0x0438,10,clif->pUseSkillToPos,2,4,6,8); + packet(0x0366,90,clif->pUseSkillToPosMoreInfo,2,4,6,8,10); + packet(0x0802,6,clif->pGetCharNameRequest,2); + packet(0x0368,6,clif->pSolveCharName,2); + packet(0x0360,12,clif->pSearchStoreInfoListItemClick,2,6,10); + packet(0x0817,2,clif->pSearchStoreInfoNextPage,0); + packet(0x0815,-1,clif->pSearchStoreInfo,2,4,5,9,13,14,15); + packet(0x096A,-1,clif->pReqTradeBuyingStore,2,4,8,12); + packet(0x088A,6,clif->pReqClickBuyingStore,2); + packet(0x0965,2,clif->pReqCloseBuyingStore,0); + packet(0x0815,-1,clif->pReqOpenBuyingStore,2,4,8,9,89); + packet(0x096A,18,clif->pPartyBookingRegisterReq,2,4); + // packet(0x088A,8); // CZ_JOIN_BATTLE_FIELD + packet(0x0965,-1,clif->pItemListWindowSelected,2,4,8); + packet(0x0966,19,clif->pWantToConnection,2,6,10,14,18); + packet(0x095D,26,clif->pPartyInvite2,2); + // packet(0x095B,4); // CZ_GANGSI_RANK + packet(0x089B,26,clif->pFriendsListAdd,2); + packet(0x092D,5,clif->pHomMenu,2,4); + packet(0x0865,36,clif->pStoragePassword,0); +#endif + +// 2014-02-05bRagexe - Themon +#if PACKETVER >= 20140205 + packet(0x0369,7,clif->pActionRequest,2,6); + packet(0x083C,10,clif->pUseSkillToId,2,4,6); + packet(0x0437,5,clif->pWalkToXY,2); + packet(0x035F,6,clif->pTickSend,2); + packet(0x0202,5,clif->pChangeDir,2,4); + packet(0x07E4,6,clif->pTakeItem,2); + packet(0x0362,6,clif->pDropItem,2,4); + packet(0x07EC,8,clif->pMoveToKafra,2,4); + packet(0x0364,8,clif->pMoveFromKafra,2,4); + packet(0x0438,10,clif->pUseSkillToPos,2,4,6,8); + packet(0x0366,90,clif->pUseSkillToPosMoreInfo,2,4,6,8,10); + packet(0x096A,6,clif->pGetCharNameRequest,2); + packet(0x0368,6,clif->pSolveCharName,2); + packet(0x0838,12,clif->pSearchStoreInfoListItemClick,2,6,10); + packet(0x0835,2,clif->pSearchStoreInfoNextPage,0); + packet(0x0819,-1,clif->pSearchStoreInfo,2,4,5,9,13,14,15); + packet(0x0811,-1,clif->pReqTradeBuyingStore,2,4,8,12); + packet(0x0360,6,clif->pReqClickBuyingStore,2); + packet(0x0817,2,clif->pReqCloseBuyingStore,0); + packet(0x0815,-1,clif->pReqOpenBuyingStore,2,4,8,9,89); + packet(0x0365,18,clif->pPartyBookingRegisterReq,2,4); + // packet(0x0363,8); // CZ_JOIN_BATTLE_FIELD + packet(0x0281,-1,clif->pItemListWindowSelected,2,4,8); + packet(0x022D,19,clif->pWantToConnection,2,6,10,14,18); + packet(0x0802,26,clif->pPartyInvite2,2); + // packet(0x0436,4); // CZ_GANGSI_RANK + packet(0x023B,26,clif->pFriendsListAdd,2); + packet(0x0361,5,clif->pHomMenu,2,4); + packet(0x0938,36,clif->pStoragePassword,0); + packet(0x09DF,7); +#endif + +// 2014-03-05bRagexe - Themon +#if PACKETVER >= 20140305 + packet(0x0369,7,clif->pActionRequest,2,6); + packet(0x083C,10,clif->pUseSkillToId,2,4,6); + packet(0x0437,5,clif->pWalkToXY,2); + packet(0x035F,6,clif->pTickSend,2); + packet(0x0815,5,clif->pChangeDir,2,4); + packet(0x0202,6,clif->pTakeItem,2); + packet(0x0362,6,clif->pDropItem,2,4); + packet(0x07EC,8,clif->pMoveToKafra,2,4); + packet(0x0364,8,clif->pMoveFromKafra,2,4); + packet(0x0436,10,clif->pUseSkillToPos,2,4,6,8); + packet(0x0366,90,clif->pUseSkillToPosMoreInfo,2,4,6,8,10); + packet(0x096A,6,clif->pGetCharNameRequest,2); + packet(0x0368,6,clif->pSolveCharName,2); + packet(0x0838,12,clif->pSearchStoreInfoListItemClick,2,6,10); + packet(0x0835,2,clif->pSearchStoreInfoNextPage,0); + packet(0x0819,-1,clif->pSearchStoreInfo,2,4,5,9,13,14,15); + packet(0x0811,-1,clif->pReqTradeBuyingStore,2,4,8,12); + packet(0x0360,6,clif->pReqClickBuyingStore,2); + packet(0x0817,2,clif->pReqCloseBuyingStore,0); + packet(0x0361,-1,clif->pReqOpenBuyingStore,2,4,8,9,89); + packet(0x0365,18,clif->pPartyBookingRegisterReq,2,4); + // packet(0x0363,8); // CZ_JOIN_BATTLE_FIELD + packet(0x0281,-1,clif->pItemListWindowSelected,2,4,8); + packet(0x0438,19,clif->pWantToConnection,2,6,10,14,18); + packet(0x0802,26,clif->pPartyInvite2,2); + // packet(0x0878,4); // CZ_GANGSI_RANK + packet(0x07E4,26,clif->pFriendsListAdd,2); + packet(0x0934,5,clif->pHomMenu,2,4); + packet(0x095e,36,clif->pStoragePassword,0); + packet(0x09DF,7); +#endif + +// 2014-04-02gRagexe - Themon +#if PACKETVER >= 20140402 + packet(0x0946,7,clif->pActionRequest,2,6); + packet(0x0868,10,clif->pUseSkillToId,2,4,6); + packet(0x093F,5,clif->pWalkToXY,2); + packet(0x0950,6,clif->pTickSend,2); + packet(0x0360,5,clif->pChangeDir,2,4); + packet(0x0958,6,clif->pTakeItem,2); + packet(0x0882,6,clif->pDropItem,2,4); + packet(0x095C,8,clif->pMoveToKafra,2,4); + packet(0x085B,8,clif->pMoveFromKafra,2,4); + packet(0x0364,10,clif->pUseSkillToPos,2,4,6,8); + packet(0x092D,90,clif->pUseSkillToPosMoreInfo,2,4,6,8,10); + packet(0x088A,6,clif->pGetCharNameRequest,2); + packet(0x07EC,6,clif->pSolveCharName,2); + packet(0x0965,12,clif->pSearchStoreInfoListItemClick,2,6,10); + packet(0x085D,2,clif->pSearchStoreInfoNextPage,0); + packet(0x0933,-1,clif->pSearchStoreInfo,2,4,5,9,13,14,15); + packet(0x091F,-1,clif->pReqTradeBuyingStore,2,4,8,12); + packet(0x023B,6,clif->pReqClickBuyingStore,2); + packet(0x0867,2,clif->pReqCloseBuyingStore,0); + packet(0x0944,-1,clif->pReqOpenBuyingStore,2,4,8,9,89); + packet(0x08AC,18,clif->pPartyBookingRegisterReq,2,4); + // packet(0x094C,8); // CZ_JOIN_BATTLE_FIELD + packet(0x0883,-1,clif->pItemListWindowSelected,2,4,8); + packet(0x0920,19,clif->pWantToConnection,2,6,10,14,18); + packet(0x0890,26,clif->pPartyInvite2,2); + // packet(0x088C,4); // CZ_GANGSI_RANK + packet(0x089A,26,clif->pFriendsListAdd,2); + packet(0x0896,5,clif->pHomMenu,2,4); + packet(0x0926,36,clif->pStoragePassword,0); + packet(0x09DF,7); +#endif + +// 2014-04-16aRagexe - Themon +#if PACKETVER >= 20140416 + packet(0x0369,7,clif->pActionRequest,2,6); + packet(0x083C,10,clif->pUseSkillToId,2,4,6); + packet(0x0437,5,clif->pWalkToXY,2); + packet(0x035F,6,clif->pTickSend,2); + packet(0x0202,5,clif->pChangeDir,2,4); + packet(0x07E4,6,clif->pTakeItem,2); + packet(0x0362,6,clif->pDropItem,2,4); + packet(0x07EC,8,clif->pMoveToKafra,2,4); + packet(0x0364,8,clif->pMoveFromKafra,2,4); + packet(0x0438,10,clif->pUseSkillToPos,2,4,6,8); + packet(0x0366,90,clif->pUseSkillToPosMoreInfo,2,4,6,8,10); + packet(0x096A,6,clif->pGetCharNameRequest,2); + packet(0x0368,6,clif->pSolveCharName,2); + packet(0x0838,12,clif->pSearchStoreInfoListItemClick,2,6,10); + packet(0x0835,2,clif->pSearchStoreInfoNextPage,0); + packet(0x0819,-1,clif->pSearchStoreInfo,2,4,5,9,13,14,15); + packet(0x0811,-1,clif->pReqTradeBuyingStore,2,4,8,12); + packet(0x0360,6,clif->pReqClickBuyingStore,2); + packet(0x0817,2,clif->pReqCloseBuyingStore,0); + packet(0x0815,-1,clif->pReqOpenBuyingStore,2,4,8,9,89); + packet(0x0365,18,clif->pPartyBookingRegisterReq,2,4); + // packet(0x0363,8); // CZ_JOIN_BATTLE_FIELD + packet(0x0281,-1,clif->pItemListWindowSelected,2,4,8); + packet(0x022D,19,clif->pWantToConnection,2,6,10,14,18); + packet(0x0802,26,clif->pPartyInvite2,2); + // packet(0x0436,4); // CZ_GANGSI_RANK + packet(0x023B,26,clif->pFriendsListAdd,2); + packet(0x0361,5,clif->pHomMenu,2,4); + packet(0x095C,36,clif->pStoragePassword,0); + packet(0x09DF,7); +#endif + +/* PacketKeys: http://hercules.ws/board/topic/1105-hercules-wpe-free-june-14th-patch/ */ +#if PACKETVER >= 20110817 + packetKeys(0x053D5CED,0x3DED6DED,0x6DED6DED); /* Thanks to Shakto */ +#endif + +#if PACKETVER >= 20110824 + packetKeys(0x35C91401,0x262A5556,0x28FA03AA); /* Thanks to Shakto */ +#endif + +#if PACKETVER >= 20110831 + packetKeys(0x3AD67ED0,0x44703C69,0x6F876809); /* Thanks to Shakto */ +#endif + +#if PACKETVER >= 20110906 + packetKeys(0x3AD67ED0,0x44703C69,0x6F876809); /* Thanks to Shakto */ +#endif + +#if PACKETVER >= 20111005 + packetKeys(0x291E6762,0x77CD391A,0x60AC2F16); /* Thanks to Shakto */ +#endif + +#if PACKETVER >= 20111012 + packetKeys(0x7F3C2D29,0x59B01DE6,0x1DBB44CA); /* Thanks to Shakto */ +#endif + +#if PACKETVER >= 20111021 + packetKeys(0x357D55DC,0x5A8D759F,0x245C30F5); /* Thanks to Shakto */ +#endif + +#if PACKETVER >= 20111025 + packetKeys(0x50AE1A63,0x3CE579B5,0x29C10406); /* Thanks to Shakto */ +#endif + +#if PACKETVER >= 20111102 + packetKeys(0x5324329D,0x5D545D52,0x06137269); /* Thanks to Shakto */ +#endif + +#if PACKETVER >= 20111109 + packetKeys(0x0B642BDA,0x6ECB1D1C,0x61C7454B); /* Thanks to Shakto */ +#endif + +#if PACKETVER >= 20111122 + packetKeys(0x3B550F07,0x1F666C7C,0x60304EF5); /* Thanks to Shakto */ +#endif + +#if PACKETVER >= 20111207 + packetKeys(0x2A610886,0x3E09165E,0x57C11888); /* Thanks to Shakto */ +#endif + +#if PACKETVER >= 20111214 + packetKeys(0x5151306B,0x7AE32886,0x53060628); /* Thanks to Shakto */ +#endif + +#if PACKETVER >= 20111220 + packetKeys(0x05D53871,0x7D0027B4,0x29975333); /* Thanks to Shakto */ +#endif + +#if PACKETVER >= 20111228 + packetKeys(0x0FF87E93,0x6CFF7860,0x3A3D1DEC); /* Thanks to Shakto */ +#endif + +#if PACKETVER >= 20120104 + packetKeys(0x262034A1,0x674542A5,0x73A50BA5); /* Thanks to Shakto */ +#endif + +#if PACKETVER >= 20120111 + packetKeys(0x2B412AFC,0x4FF94487,0x6705339D); /* Thanks to Shakto */ +#endif + +#if PACKETVER >= 20120120 + packetKeys(0x504345D0,0x3D427B1B,0x794C2DCC); /* Thanks to Shakto */ +#endif + +#if PACKETVER >= 20120202 + packetKeys(0x2CFC0A71,0x2BA91D8D,0x087E39E0); /* Thanks to Shakto */ +#endif + +#if PACKETVER >= 20120207 + packetKeys(0x1D373F5D,0x5ACD604D,0x1C4D7C4D); /* Thanks to Shakto */ +#endif + +#if PACKETVER >= 20120214 + packetKeys(0x7A255EFA,0x30977276,0x2D4A0448); /* Thanks to Shakto */ +#endif + +#if PACKETVER >= 20120229 + packetKeys(0x520B4C64,0x2800407D,0x47651458); /* Thanks to Shakto */ +#endif + +#if PACKETVER >= 20120307 + packetKeys(0x382A6DEF,0x5CBE7202,0x61F46637); /* Thanks to Shakto */ +#endif + +#if PACKETVER >= 20120314 + packetKeys(0x689C1729,0x11812639,0x60F82967); /* Thanks to Shakto */ +#endif + +#if PACKETVER >= 20120321 + packetKeys(0x21F9683F,0x710C5CA5,0x1FD910E9); /* Thanks to Shakto */ +#endif + +#if PACKETVER >= 20120328 + packetKeys(0x75B8553B,0x37F20B12,0x385C2B40); /* Thanks to Shakto */ +#endif + +#if PACKETVER >= 20120404 + packetKeys(0x0036310C,0x2DCD0BED,0x1EE62A78); /* Thanks to Shakto */ +#endif + +#if PACKETVER >= 20120410 + packetKeys(0x01581359,0x452D6FFA,0x6AFB6E2E); /* Thanks to Shakto */ +#endif + +#if PACKETVER >= 20120418 + packetKeys(0x01540E48,0x13041224,0x31247924); /* Thanks to Shakto */ +#endif + +#if PACKETVER >= 20120424 + packetKeys(0x411D1DBB,0x4CBA4848,0x1A432FC4); /* Thanks to Shakto */ +#endif + +#if PACKETVER >= 20120509 + packetKeys(0x16CF3301,0x1F472B9B,0x0B4A3CD2); /* Thanks to Shakto */ +#endif + +#if PACKETVER >= 20120515 + packetKeys(0x4A715EF9,0x79103E4F,0x405C1238); /* Thanks to Shakto */ +#endif + +#if PACKETVER >= 20120525 + packetKeys(0x70EB4CCB,0x0487713C,0x398D4B08); /* Thanks to Shakto */ +#endif + +#if PACKETVER >= 20120605 + packetKeys(0x68CA3080,0x31B74BDD,0x505208F1); /* Thanks to Shakto */ +#endif + +#if PACKETVER >= 20120612 + packetKeys(0x32E45D64,0x35643564,0x35643564); /* Thanks to Shakto */ +#endif + +#if PACKETVER >= 20120618 + packetKeys(0x261F261F,0x261F261F,0x261F261F); /* Thanks to Shakto */ +#endif + +#if PACKETVER >= 20120702 + packetKeys(0x25733B31,0x53486CFD,0x398649BD); /* Thanks to Shakto */ +#endif + +#if PACKETVER >= 20120716 + packetKeys(0x76052205,0x22052205,0x22052205); /* Thanks to Shakto */ +#endif + +#if PACKETVER >= 20130320 + packetKeys(0x3F094C49,0x55F86C1E,0x58AA359A); /* Thanks to Shakto */ +#endif + +#if PACKETVER >= 20130514 + packetKeys(0x75794A38,0x58A96BC1,0x296E6FB8); /* Thanks to Shakto */ +#endif + +#if PACKETVER >= 20130522 + packetKeys(0x6948050B,0x06511D9D,0x725D4DF1); /* Thanks to Shakto */ +#endif + +#if PACKETVER >= 20130529 + packetKeys(0x023A6C87,0x14BF1F1E,0x5CC70CC9); /* Thanks to Shakto */ +#endif + +#if PACKETVER >= 20130605 + packetKeys(0x646E08D9,0x5F153AB5,0x61B509B5); /* Thanks to Shakto */ +#endif + #if PACKETVER >= 20130612 - packetKeys(0x6D166F66, 0x3C000FCF, 0x295B0FCB); /* Thanks to Shakto */ + packetKeys(0x6D166F66,0x3C000FCF,0x295B0FCB); /* Thanks to Shakto */ +#endif + +#if PACKETVER >= 20130618 + packetKeys(0x434115DE,0x34A10FE9,0x6791428E); /* Thanks to Shakto */ +#endif + +#if PACKETVER >= 20130626 + packetKeys(0x38F453EF,0x6A040FD8,0X65BD6668); /* Thanks to Shakto */ +#endif + +#if PACKETVER >= 20130703 + packetKeys(0x4FF90E23,0x0F1432F2,0x4CFA1EDA); /* Thanks to Shakto */ +#endif + +#if PACKETVER >= 20130807 + packetKeys(0x7E241DE0,0x5E805580,0x3D807D80); /* Thanks to Shakto */ +#endif + +#if PACKETVER >= 20130814 + packetKeys(0x23A23148,0x0C41420E,0x53785AD7); /* Themon */ +#endif + +#if PACKETVER >= 20131218 + packetKeys(0x6A596301,0x76866D0E,0x32294A45); +#endif + +#if PACKETVER >= 20131223 + packetKeys(0x631C511C,0x111C111C,0x111C111C); +#endif + +#if PACKETVER >= 20131230 + packetKeys(0x611B7097,0x01F957A1,0x768A0FCB); +#endif + +// 2014 Packet Keys + +#if PACKETVER >= 20140115 + packetKeys(0x63224335,0x0F3A1F27,0x6D217B24); /* Thanks to Yommy */ +#endif + +#if PACKETVER >= 20140205 + packetKeys(0x63DC7BDC,0x7BDC7BDC,0x7BDC7BDC); /* Themon */ +#endif + +#if PACKETVER >= 20140305 + packetKeys(0x116763F2,0x41117DAC,0x7FD13C45); /* Themon */ +#endif + +#if PACKETVER >= 20140402 + packetKeys(0x15D3271C,0x004D725B,0x111A3A37); /* Themon */ +#endif + +#if PACKETVER >= 20140416 + packetKeys(0x04810281,0x42814281,0x42814281); /* Themon */ +#endif + +#if defined(OBFUSCATIONKEY1) && defined(OBFUSCATIONKEY2) && defined(OBFUSCATIONKEY3) + packetKeys(OBFUSCATIONKEY1,OBFUSCATIONKEY2,OBFUSCATIONKEY3); #endif -#endif /* _PACKETS_H_ */ +#endif /* MAP_PACKETS_H */ diff --git a/src/map/packets_struct.h b/src/map/packets_struct.h index 083c00e31..b32baf53a 100644 --- a/src/map/packets_struct.h +++ b/src/map/packets_struct.h @@ -3,21 +3,20 @@ /* Hercules Renewal: Phase Two http://hercules.ws/board/topic/383-hercules-renewal-phase-two/ */ -#ifndef _PACKETS_STRUCT_H_ -#define _PACKETS_STRUCT_H_ +#ifndef MAP_PACKETS_STRUCT_H +#define MAP_PACKETS_STRUCT_H +#include "../common/cbasetypes.h" #include "../common/mmo.h" /** - * structs for data - */ -struct EQUIPSLOTINFO { - unsigned short card[4]; -}; -/** * **/ enum packet_headers { + banking_withdraw_ackType = 0x9aa, + banking_deposit_ackType = 0x9a8, + banking_checkType = 0x9a6, + cart_additem_ackType = 0x12c, sc_notickType = 0x196, #if PACKETVER < 20061218 additemType = 0xa0, @@ -38,7 +37,7 @@ enum packet_headers { idle_unitType = 0x2ee, #elif PACKETVER < 20101124 idle_unitType = 0x7f9, -#elif PACKETVER < 20140000 //actual 20120221 +#elif PACKETVER < 20150000 //actual 20120221 idle_unitType = 0x857, #else idle_unitType = 0x915, @@ -52,6 +51,15 @@ enum packet_headers { #endif status_change2Type = 0x43f, status_change_endType = 0x196, +#if PACKETVER < 20091103 + spawn_unit2Type = 0x7c, + idle_unit2Type = 0x78, +#endif +#if PACKETVER < 20071113 + damageType = 0x8a, +#else + damageType = 0x2e1, +#endif #if PACKETVER < 4 spawn_unitType = 0x79, #elif PACKETVER < 7 @@ -62,7 +70,7 @@ enum packet_headers { spawn_unitType = 0x2ed, #elif PACKETVER < 20101124 spawn_unitType = 0x7f8, -#elif PACKETVER < 20140000 //actual 20120221 +#elif PACKETVER < 20150000 //actual 20120221 spawn_unitType = 0x858, #else spawn_unitType = 0x90f, @@ -73,6 +81,8 @@ enum packet_headers { authokType = 0x2eb, #endif script_clearType = 0x8d6, + package_item_announceType = 0x7fd, + item_drop_announceType = 0x7fd, #if PACKETVER < 4 unit_walkingType = 0x7b, #elif PACKETVER < 7 @@ -83,7 +93,7 @@ enum packet_headers { unit_walkingType = 0x2ec, #elif PACKETVER < 20101124 unit_walkingType = 0x7f7, -#elif PACKETVER < 20140000 //actual 20120221 +#elif PACKETVER < 20150000 //actual 20120221 unit_walkingType = 0x856, #else unit_walkingType = 0x914, @@ -96,22 +106,192 @@ enum packet_headers { bgqueue_revokereqType = 0x8da, bgqueue_battlebeginackType = 0x8e0, bgqueue_notify_entryType = 0x8d9, - bgqueue_battlebegins = 0x8df, + bgqueue_battlebeginsType = 0x8df, + notify_bounditemType = 0x2d3, +#if PACKETVER < 20110718 + skill_entryType = 0x11f, +#elif PACKETVER < 20121212 + skill_entryType = 0x8c7, +#elif PACKETVER < 20130731 + skill_entryType = 0x99f, +#else + skill_entryType = 0x9ca, +#endif + graffiti_entryType = 0x1c9, #if PACKETVER > 20130000 /* not sure date */ dropflooritemType = 0x84b, #else dropflooritemType = 0x9e, #endif +#if PACKETVER >= 20120925 + inventorylistnormalType = 0x991, +#elif PACKETVER >= 20080102 + inventorylistnormalType = 0x2e8, +#elif PACKETVER >= 20071002 + inventorylistnormalType = 0x1ee, +#else + inventorylistnormalType = 0xa3, +#endif +#if PACKETVER >= 20120925 + inventorylistequipType = 0x992, +#elif PACKETVER >= 20080102 + inventorylistequipType = 0x2d0, +#elif PACKETVER >= 20071002 + inventorylistequipType = 0x295, +#else + inventorylistequipType = 0xa4, +#endif +#if PACKETVER >= 20120925 + storagelistnormalType = 0x995, +#elif PACKETVER >= 20080102 + storagelistnormalType = 0x2ea, +#elif PACKETVER >= 20071002 + storagelistnormalType = 0x295, +#else + storagelistnormalType = 0xa5, +#endif +#if PACKETVER >= 20120925 + storagelistequipType = 0x996, +#elif PACKETVER >= 20080102 + storagelistequipType = 0x2d1, +#elif PACKETVER >= 20071002 + storagelistequipType = 0x296, +#else + storagelistequipType = 0xa6, +#endif +#if PACKETVER >= 20120925 + cartlistnormalType = 0x993, +#elif PACKETVER >= 20080102 + cartlistnormalType = 0x2e9, +#elif PACKETVER >= 20071002 + cartlistnormalType = 0x1ef, +#else + cartlistnormalType = 0x123, +#endif +#if PACKETVER >= 20120925 + cartlistequipType = 0x994, +#elif PACKETVER >= 20080102 + cartlistequipType = 0x2d2, +#elif PACKETVER >= 20071002 + cartlistequipType = 0x297, +#else + cartlistequipType = 0x122, +#endif +#if PACKETVER >= 20120925 + equipitemType = 0x998, +#else + equipitemType = 0xa9, +#endif +#if PACKETVER >= 20120925 + equipitemackType = 0x999, +#else + equipitemackType = 0xaa, +#endif +#if PACKETVER >= 20120925 + unequipitemackType = 0x99a, +#else + unequipitemackType = 0xac, +#endif +#if PACKETVER >= 20120925 + viewequipackType = 0x997, +#elif PACKETVER >= 20101124 + viewequipackType = 0x859, +#else + viewequipackType = 0x2d7, +#endif + notifybindonequip = 0x2d3, monsterhpType = 0x977, maptypeproperty2Type = 0x99b, + npcmarketresultackType = 0x9d7, + npcmarketopenType = 0x9d5, +#if PACKETVER >= 20131223 + wisendType = 0x9df, +#else + wisendType = 0x98, +#endif }; +#if !defined(sun) && (!defined(__NETBSD__) || __NetBSD_Version__ >= 600000000) // NetBSD 5 and Solaris don't like pragma pack but accept the packed attribute #pragma pack(push, 1) +#endif // not NetBSD < 6 / Solaris + +/** + * structs for data + */ +struct EQUIPSLOTINFO { + unsigned short card[4]; +} __attribute__((packed)); + +struct NORMALITEM_INFO { + short index; + unsigned short ITID; + unsigned char type; +#if PACKETVER < 20120925 + uint8 IsIdentified; +#endif + short count; +#if PACKETVER >= 20120925 + unsigned int WearState; +#else + unsigned short WearState; +#endif +#if PACKETVER >= 5 + struct EQUIPSLOTINFO slot; +#endif +#if PACKETVER >= 20080102 + int HireExpireDate; +#endif +#if PACKETVER >= 20120925 + struct { + unsigned char IsIdentified : 1; + unsigned char PlaceETCTab : 1; + unsigned char SpareBits : 6; + } Flag; +#endif +} __attribute__((packed)); + +struct EQUIPITEM_INFO { + short index; + unsigned short ITID; + unsigned char type; +#if PACKETVER < 20120925 + uint8 IsIdentified; +#endif +#if PACKETVER >= 20120925 + unsigned int location; + unsigned int WearState; +#else + unsigned short location; + unsigned short WearState; +#endif +#if PACKETVER < 20120925 + uint8 IsDamaged; +#endif + unsigned char RefiningLevel; + struct EQUIPSLOTINFO slot; +#if PACKETVER >= 20071002 + int HireExpireDate; +#endif +#if PACKETVER >= 20080102 + unsigned short bindOnEquipType; +#endif +#if PACKETVER >= 20100629 + unsigned short wItemSpriteNumber; +#endif +#if PACKETVER >= 20120925 + struct { + unsigned char IsIdentified : 1; + unsigned char IsDamaged : 1; + unsigned char PlaceETCTab : 1; + unsigned char SpareBits : 5; + } Flag; +#endif +} __attribute__((packed)); struct packet_authok { short PacketType; unsigned int startTime; - char PosDir[3]; + unsigned char PosDir[3]; unsigned char xSize; unsigned char ySize; #if PACKETVER >= 20080102 @@ -138,8 +318,8 @@ struct packet_additem { unsigned short Index; unsigned short count; unsigned short nameid; - bool IsIdentified; - bool IsDamaged; + uint8 IsIdentified; + uint8 IsDamaged; unsigned char refiningLevel; struct EQUIPSLOTINFO slot; #if PACKETVER >= 20120925 @@ -164,14 +344,73 @@ struct packet_dropflooritem { #if PACKETVER >= 20130000 /* not sure date */ unsigned short type; #endif - bool IsIdentified; + uint8 IsIdentified; short xPos; short yPos; unsigned char subX; unsigned char subY; short count; } __attribute__((packed)); - +#if PACKETVER < 20091103 +struct packet_idle_unit2 { + short 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 isPKModeON; + unsigned char sex; + unsigned char PosDir[3]; + unsigned char xSize; + unsigned char ySize; + unsigned char state; + short clevel; +} __attribute__((packed)); +struct packet_spawn_unit2 { + short 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 isPKModeON; + unsigned char sex; + unsigned char PosDir[3]; + unsigned char xSize; + unsigned char ySize; +} __attribute__((packed)); +#endif struct packet_spawn_unit { short PacketType; #if PACKETVER >= 20091103 @@ -209,21 +448,21 @@ struct packet_spawn_unit { unsigned int GUID; short GEmblemVer; short honor; -#if PACKETVER >= 20091103 +#if PACKETVER > 7 int virtue; #else short virtue; #endif - bool isPKModeON; + uint8 isPKModeON; unsigned char sex; - char PosDir[3]; + unsigned char PosDir[3]; unsigned char xSize; unsigned char ySize; short clevel; #if PACKETVER >= 20080102 short font; #endif -#if PACKETVER >= 20140000 //actual 20120221 +#if PACKETVER >= 20150000 //actual 20120221 int maxHP; int HP; unsigned char isBoss; @@ -234,13 +473,15 @@ struct packet_unit_walking { short PacketType; #if PACKETVER >= 20091103 short PacketLength; +#endif +#if PACKETVER > 20071106 unsigned char objecttype; #endif unsigned int GID; short speed; short bodyState; short healthState; -#if PACKETVER < 20080102 +#if PACKETVER < 7 short effectState; #else int effectState; @@ -268,21 +509,21 @@ struct packet_unit_walking { unsigned int GUID; short GEmblemVer; short honor; -#if PACKETVER >= 20091103 +#if PACKETVER > 7 int virtue; #else short virtue; #endif - bool isPKModeON; + uint8 isPKModeON; unsigned char sex; - char MoveData[6]; + unsigned char MoveData[6]; unsigned char xSize; unsigned char ySize; short clevel; #if PACKETVER >= 20080102 short font; #endif -#if PACKETVER >= 20140000 //actual 20120221 +#if PACKETVER >= 20150000 //actual 20120221 int maxHP; int HP; unsigned char isBoss; @@ -326,14 +567,14 @@ struct packet_idle_unit { unsigned int GUID; short GEmblemVer; short honor; -#if PACKETVER >= 20091103 +#if PACKETVER > 7 int virtue; #else short virtue; #endif - bool isPKModeON; + uint8 isPKModeON; unsigned char sex; - char PosDir[3]; + unsigned char PosDir[3]; unsigned char xSize; unsigned char ySize; unsigned char state; @@ -341,7 +582,7 @@ struct packet_idle_unit { #if PACKETVER >= 20080102 short font; #endif -#if PACKETVER >= 20140000 //actual 20120221 +#if PACKETVER >= 20150000 //actual 20120221 int maxHP; int HP; unsigned char isBoss; @@ -356,7 +597,7 @@ struct packet_status_change { #if PACKETVER >= 20120618 unsigned int Total; #endif -#if PACKETVER >= 20090121 +#if PACKETVER >= 20090121 unsigned int Left; int val1; int val2; @@ -386,30 +627,30 @@ struct packet_maptypeproperty2 { short PacketType; short type; struct { - unsigned int party : 1; - unsigned int guild : 1; - unsigned int siege : 1; - unsigned int mineffect : 1; - unsigned int nolockon : 1; - unsigned int countpk : 1; - unsigned int nopartyformation : 1; - unsigned int bg : 1; - unsigned int noitemconsumption : 1; - unsigned int usecart : 1; - unsigned int summonstarmiracle : 1; - unsigned int SpareBits : 15; + 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 noitemconsumption : 1; // TODO: What does this do? (shows a "Nothing found in the selected map" message when set) + 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 } flag; } __attribute__((packed)); struct packet_bgqueue_ack { short PacketType; - short type; + unsigned char type; char bg_name[NAME_LENGTH]; } __attribute__((packed)); struct packet_bgqueue_notice_delete { short PacketType; - short type; + unsigned char type; char bg_name[NAME_LENGTH]; } __attribute__((packed)); @@ -437,7 +678,7 @@ struct packet_bgqueue_revoke_req { struct packet_bgqueue_battlebegin_ack { short PacketType; - short result; + unsigned char result; char bg_name[NAME_LENGTH]; char game_name[NAME_LENGTH]; } __attribute__((packed)); @@ -459,7 +700,267 @@ struct packet_script_clear { unsigned int 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; + char Name[NAME_LENGTH]; + char unknown; + unsigned short 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; + char Name[NAME_LENGTH]; + char monsterNameLen; + char monsterName[NAME_LENGTH]; +} __attribute__((packed)); + +struct packet_cart_additem_ack { + short PacketType; + char result; +} __attribute__((packed)); + +struct packet_banking_check { + short PacketType; + int64 Money; + short Reason; +} __attribute__((packed)); + +struct packet_banking_deposit_req { + short PacketType; + unsigned int AID; + int Money; +} __attribute__((packed)); + +struct packet_banking_withdraw_req { + short PacketType; + unsigned int AID; + int Money; +} __attribute__((packed)); + +struct packet_banking_deposit_ack { + short PacketType; + short Reason; + int64 Money; + int Balance; +} __attribute__((packed)); + +struct packet_banking_withdraw_ack { + short PacketType; + short Reason; + int64 Money; + int Balance; +} __attribute__((packed)); + +struct packet_itemlist_normal { + short PacketType; + short PacketLength; + struct NORMALITEM_INFO list[MAX_ITEMLIST]; +} __attribute__((packed)); + +struct packet_itemlist_equip { + short PacketType; + short PacketLength; + struct EQUIPITEM_INFO list[MAX_ITEMLIST]; +} __attribute__((packed)); + +struct packet_storelist_normal { + short PacketType; + short PacketLength; +#if PACKETVER >= 20120925 + char name[NAME_LENGTH]; +#endif + struct NORMALITEM_INFO list[MAX_ITEMLIST]; +} __attribute__((packed)); + +struct packet_storelist_equip { + short PacketType; + short PacketLength; +#if PACKETVER >= 20120925 + char name[NAME_LENGTH]; +#endif + struct EQUIPITEM_INFO list[MAX_ITEMLIST]; +} __attribute__((packed)); + +struct packet_equip_item { + short PacketType; + unsigned short index; +#if PACKETVER >= 20120925 + unsigned int wearLocation; +#else + unsigned short wearLocation; +#endif +} __attribute__((packed)); + +struct packet_equipitem_ack { + short PacketType; + unsigned short index; +#if PACKETVER >= 20120925 + unsigned int wearLocation; +#else + unsigned short wearLocation; +#endif +#if PACKETVER >= 20100629 + unsigned short wItemSpriteNumber; +#endif + unsigned char result; +} __attribute__((packed)); + +struct packet_unequipitem_ack { + short PacketType; + unsigned short index; +#if PACKETVER >= 20120925 + unsigned int wearLocation; +#else + unsigned short wearLocation; +#endif + unsigned char result; +} __attribute__((packed)); + +struct packet_viewequip_ack { + short PacketType; + short PacketLength; + char characterName[NAME_LENGTH]; + short job; + short head; + short accessory; + short accessory2; + short accessory3; +#if PACKETVER >= 20101124 + short robe; +#endif + short headpalette; + short bodypalette; + unsigned char sex; + struct EQUIPITEM_INFO list[MAX_INVENTORY]; +} __attribute__((packed)); + +struct packet_notify_bounditem { + short PacketType; + unsigned short index; +} __attribute__((packed)); + +struct packet_skill_entry { + short PacketType; +#if PACKETVER >= 20110718 + short PacketLength; +#endif + unsigned int AID; + unsigned int creatorAID; + short xPos; + short yPos; +#if PACKETVER >= 20121212 + int job; +#else + unsigned char job; +#endif +#if PACKETVER >= 20110718 + char RadiusRange; +#endif + unsigned char isVisible; +#if PACKETVER >= 20130731 + unsigned char 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; + char msg[80]; +} __attribute__((packed)); + +struct packet_damage { + short PacketType; + unsigned int GID; + unsigned int targetGID; + unsigned int startTime; + int attackMT; + int attackedMT; +#if PACKETVER < 20071113 + short damage; +#else + int damage; +#endif + short count; + unsigned char action; +#if PACKETVER < 20071113 + short leftDamage; +#else + int leftDamage; +#endif +} __attribute__((packed)); + +struct packet_gm_monster_item { + short PacketType; +#if PACKETVER >= 20131218 + char str[100]; +#else + char str[24]; +#endif +} __attribute__((packed)); + +struct packet_npc_market_purchase { + short PacketType; + short PacketLength; + struct { + unsigned short ITID; + int qty; + } 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_result_ack { + short PacketType; + short PacketLength; + unsigned char result; + struct { + unsigned short ITID; + unsigned short qty; + unsigned int 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; + /* 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; + // 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] + } list[1000];/* TODO: whats the actual max of this? */ +} __attribute__((packed)); + +struct packet_wis_end { + short PacketType; + char result; +#if PACKETVER >= 20131223 + unsigned int unknown;/* maybe AID, not sure what for (works sending as 0) */ +#endif +} __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 -#endif /* _PACKETS_STRUCT_H_ */ +#endif /* MAP_PACKETS_STRUCT_H */ diff --git a/src/map/party.c b/src/map/party.c index adcb35c5a..7cf340edb 100644 --- a/src/map/party.c +++ b/src/map/party.c @@ -1,46 +1,46 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder +// Copyright (c) Hercules Dev Team, licensed under GNU GPL. +// See the LICENSE file +// Portions Copyright (c) Athena Dev Teams -#include "../common/cbasetypes.h" -#include "../common/timer.h" -#include "../common/socket.h" // last_tick -#include "../common/nullpo.h" -#include "../common/malloc.h" -#include "../common/random.h" -#include "../common/showmsg.h" -#include "../common/utils.h" -#include "../common/strlib.h" +#define HERCULES_CORE +#include "../config/core.h" // GP_BOUND_ITEMS, RENEWAL_EXP #include "party.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + #include "atcommand.h" //msg_txt() -#include "pc.h" -#include "map.h" -#include "instance.h" #include "battle.h" -#include "intif.h" #include "clif.h" +#include "instance.h" +#include "intif.h" +#include "itemdb.h" #include "log.h" +#include "map.h" +#include "mob.h" // struct mob_data +#include "pc.h" #include "skill.h" #include "status.h" -#include "itemdb.h" - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - - -static DBMap* party_db; // int party_id -> struct party_data* (releases data) -static DBMap* party_booking_db; // int char_id -> struct party_booking_ad_info* (releases data) // Party Booking [Spiria] -static unsigned long party_booking_nextid = 1; +#include "../common/HPM.h" +#include "../common/cbasetypes.h" +#include "../common/malloc.h" +#include "../common/nullpo.h" +#include "../common/random.h" +#include "../common/showmsg.h" +#include "../common/socket.h" // last_tick +#include "../common/strlib.h" +#include "../common/timer.h" +#include "../common/utils.h" -int party_send_xy_timer(int tid, unsigned int tick, int id, intptr_t data); +struct party_interface party_s; /*========================================== * Fills the given party_member structure according to the sd provided. * Used when creating/adding people to a party. [Skotlex] *------------------------------------------*/ -static void party_fill_member(struct party_member* member, struct map_session_data* sd, unsigned int leader) -{ +void party_fill_member(struct party_member* member, struct map_session_data* sd, unsigned int leader) { member->account_id = sd->status.account_id; member->char_id = sd->status.char_id; safestrncpy(member->name, sd->status.name, NAME_LENGTH); @@ -52,8 +52,7 @@ static void party_fill_member(struct party_member* member, struct map_session_da } /// Get the member_id of a party member. /// Return -1 if not in party. -int party_getmemberid(struct party_data* p, struct map_session_data* sd) -{ +int party_getmemberid(struct party_data* p, struct map_session_data* sd) { int member_id; nullpo_retr(-1, p); if( sd == NULL ) @@ -66,7 +65,6 @@ int party_getmemberid(struct party_data* p, struct map_session_data* sd) return member_id; } - /*========================================== * Request an available sd of this party *------------------------------------------*/ @@ -81,10 +79,8 @@ struct map_session_data* party_getavailablesd(struct party_data *p) /*========================================== * Retrieves and validates the sd pointer for this party member [Skotlex] *------------------------------------------*/ - -static TBL_PC* party_sd_check(int party_id, int account_id, int char_id) -{ - TBL_PC* sd = iMap->id2sd(account_id); +TBL_PC* party_sd_check(int party_id, int account_id, int char_id) { + TBL_PC* sd = map->id2sd(account_id); if (!(sd && sd->status.char_id == char_id)) return NULL; @@ -93,7 +89,7 @@ static TBL_PC* party_sd_check(int party_id, int account_id, int char_id) sd->status.party_id = party_id;// auto-join if not in a party if (sd->status.party_id != party_id) { //If player belongs to a different party, kick him out. - intif_party_leave(party_id,account_id,char_id); + intif->party_leave(party_id,account_id,char_id); return NULL; } @@ -102,35 +98,30 @@ static TBL_PC* party_sd_check(int party_id, int account_id, int char_id) int party_db_final(DBKey key, DBData *data, va_list ap) { struct party_data *p; - if( ( p = DB->data2ptr(data) ) && p->instance ) - aFree(p->instance); + if( ( p = DB->data2ptr(data) ) ) { + int j; + + if( p->instance ) + aFree(p->instance); + + for( j = 0; j < p->hdatac; j++ ) { + if( p->hdata[j]->flag.free ) { + aFree(p->hdata[j]->data); + } + aFree(p->hdata[j]); + } + if( p->hdata ) + aFree(p->hdata); + } return 0; } -/*========================================== - * Destructor - * Called in map shutdown, cleanup var - *------------------------------------------*/ -void do_final_party(void) -{ - party_db->destroy(party_db,party_db_final); - party_booking_db->destroy(party_booking_db,NULL); // Party Booking [Spiria] -} -// Constructor, init vars -void do_init_party(void) -{ - party_db = idb_alloc(DB_OPT_RELEASE_DATA); - party_booking_db = idb_alloc(DB_OPT_RELEASE_DATA); // Party Booking [Spiria] - iTimer->add_timer_func_list(party_send_xy_timer, "party_send_xy_timer"); - iTimer->add_timer_interval(iTimer->gettick()+battle_config.party_update_interval, party_send_xy_timer, 0, 0, battle_config.party_update_interval); -} - /// Party data lookup using party id. struct party_data* party_search(int party_id) { if(!party_id) return NULL; - return (struct party_data*)idb_get(party_db,party_id); + return (struct party_data*)idb_get(party->db,party_id); } /// Party data lookup using party name. @@ -138,7 +129,7 @@ struct party_data* party_searchname(const char* str) { struct party_data* p; - DBIterator *iter = db_iterator(party_db); + DBIterator *iter = db_iterator(party->db); for( p = dbi_first(iter); dbi_exists(iter); p = dbi_next(iter) ) { if( strncmpi(p->party.name,str,NAME_LENGTH) == 0 ) @@ -170,22 +161,21 @@ int party_create(struct map_session_data *sd,char *name,int item,int item2) sd->party_creating = true; - party_fill_member(&leader, sd, 1); + party->fill_member(&leader, sd, 1); - intif_create_party(&leader,name,item,item2); + intif->create_party(&leader,name,item,item2); return 0; } -void party_created(int account_id,int char_id,int fail,int party_id,char *name) -{ +void party_created(int account_id,int char_id,int fail,int party_id,char *name) { struct map_session_data *sd; - sd=iMap->id2sd(account_id); + sd=map->id2sd(account_id); - if (!sd || sd->status.char_id != char_id || !sd->party_creating ) - { //Character logged off before creation ack? + if (!sd || sd->status.char_id != char_id || !sd->party_creating ) { + //Character logged off before creation ack? if (!fail) //break up party since player could not be added to it. - intif_party_leave(party_id,account_id,char_id); + intif->party_leave(party_id,account_id,char_id); return; } @@ -203,46 +193,43 @@ void party_created(int account_id,int char_id,int fail,int party_id,char *name) int party_request_info(int party_id, int char_id) { - return intif_request_partyinfo(party_id, char_id); + return intif->request_partyinfo(party_id, char_id); } /// Invoked (from char-server) when the party info is not found. -int party_recv_noinfo(int party_id, int char_id) -{ +int party_recv_noinfo(int party_id, int char_id) { party->broken(party_id); - if( char_id != 0 )// requester - { + if( char_id != 0 ) { + // requester struct map_session_data* sd; - sd = iMap->charid2sd(char_id); + sd = map->charid2sd(char_id); if( sd && sd->status.party_id == party_id ) sd->status.party_id = 0; } return 0; } -static void party_check_state(struct party_data *p) -{ +void party_check_state(struct party_data *p) { int i; 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 aport to skill usage and all that. + 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. switch (p->party.member[i].class_) { - case JOB_MONK: - case JOB_BABY_MONK: - case JOB_CHAMPION: - p->state.monk = 1; - break; - case JOB_STAR_GLADIATOR: - p->state.sg = 1; - break; - case JOB_SUPER_NOVICE: - case JOB_SUPER_BABY: - p->state.snovice = 1; - break; - case JOB_TAEKWON: - p->state.tk = 1; - break; + case JOB_MONK: + case JOB_BABY_MONK: + case JOB_CHAMPION: + p->state.monk = 1; + break; + case JOB_STAR_GLADIATOR: + p->state.sg = 1; + break; + case JOB_SUPER_NOVICE: + case JOB_SUPER_BABY: + p->state.snovice = 1; + break; + case JOB_TAEKWON: + p->state.tk = 1; + break; } } } @@ -261,7 +248,7 @@ int party_recv_info(struct party* sp, int char_id) nullpo_ret(sp); - p = (struct party_data*)idb_get(party_db, sp->party_id); + p = (struct party_data*)idb_get(party->db, sp->party_id); if( p != NULL ) {// diff members for( member_id = 0; member_id < MAX_PARTY; ++member_id ) { member = &p->party.member[member_id]; @@ -290,7 +277,7 @@ int party_recv_info(struct party* sp, int char_id) CREATE(p, struct party_data, 1); p->instance = NULL; p->instances = 0; - idb_put(party_db, sp->party_id, p); + idb_put(party->db, sp->party_id, p); } while( removed_count > 0 ) {// no longer in party member_id = removed[--removed_count]; @@ -306,9 +293,9 @@ int party_recv_info(struct party* sp, int char_id) member = &p->party.member[member_id]; if ( member->char_id == 0 ) continue;// empty - p->data[member_id].sd = party_sd_check(sp->party_id, member->account_id, member->char_id); + p->data[member_id].sd = party->sd_check(sp->party_id, member->account_id, member->char_id); } - party_check_state(p); + party->check_state(p); while( added_count > 0 ) { // new in party member_id = added[--added_count]; sd = p->data[member_id].sd; @@ -319,15 +306,17 @@ int party_recv_info(struct party* sp, int char_id) clif->party_option(p,sd,0x100); clif->party_info(p,NULL); for( j = 0; j < p->instances; j++ ) { - if( instances[p->instance[j]].idle_timer == INVALID_TIMER && instances[p->instance[j]].progress_timer == INVALID_TIMER ) - continue; - clif->instance_join(sd->fd, p->instance[j]); - break; + if( p->instance[j] >= 0 ) { + if( instance->list[p->instance[j]].idle_timer == INVALID_TIMER && instance->list[p->instance[j]].progress_timer == INVALID_TIMER ) + continue; + clif->instance_join(sd->fd, p->instance[j]); + break; + } } } - if( char_id != 0 )// requester - { - sd = iMap->charid2sd(char_id); + if( char_id != 0 ) { + // requester + sd = map->charid2sd(char_id); if( sd && sd->status.party_id == sp->party_id && party->getmemberid(p,sd) == -1 ) sd->status.party_id = 0;// was not in the party } @@ -396,8 +385,7 @@ int party_invite(struct map_session_data *sd,struct map_session_data *tsd) return 1; } -void party_reply_invite(struct map_session_data *sd,int party_id,int flag) -{ +void party_reply_invite(struct map_session_data *sd,int party_id,int flag) { struct map_session_data* tsd; struct party_member member; @@ -407,13 +395,13 @@ void party_reply_invite(struct map_session_data *sd,int party_id,int flag) sd->party_invite_account = 0; return; } - tsd = iMap->id2sd(sd->party_invite_account); + tsd = map->id2sd(sd->party_invite_account); if( flag == 1 && !sd->party_creating && !sd->party_joining ) {// accepted and allowed sd->party_joining = true; - party_fill_member(&member, sd, 0); - intif_party_addmember(sd->party_invite, &member); + party->fill_member(&member, sd, 0); + intif->party_addmember(sd->party_invite, &member); } else {// rejected or failure @@ -441,10 +429,12 @@ void party_member_joined(struct map_session_data *sd) int j; p->data[i].sd = sd; for( j = 0; j < p->instances; j++ ) { - if( instances[p->instance[j]].idle_timer == INVALID_TIMER && instances[p->instance[j]].progress_timer == INVALID_TIMER ) - continue; - clif->instance_join(sd->fd, p->instance[j]); - break; + if( p->instance[j] >= 0 ) { + if( instance->list[p->instance[j]].idle_timer == INVALID_TIMER && instance->list[p->instance[j]].progress_timer == INVALID_TIMER ) + continue; + clif->instance_join(sd->fd, p->instance[j]); + break; + } } } else sd->status.party_id = 0; //He does not belongs to the party really? @@ -452,19 +442,18 @@ void party_member_joined(struct map_session_data *sd) /// Invoked (from char-server) when a new member is added to the party. /// flag: 0-success, 1-failure -int party_member_added(int party_id,int account_id,int char_id, int flag) -{ - struct map_session_data *sd = iMap->id2sd(account_id),*sd2; +int party_member_added(int party_id,int account_id,int char_id, int flag) { + struct map_session_data *sd = map->id2sd(account_id),*sd2; struct party_data *p = party->search(party_id); int i, j; if(sd == NULL || sd->status.char_id != char_id || !sd->party_joining ) { if (!flag) //Char logged off before being accepted into party. - intif_party_leave(party_id,account_id,char_id); + intif->party_leave(party_id,account_id,char_id); return 0; } - sd2 = iMap->id2sd(sd->party_invite_account); + sd2 = map->id2sd(sd->party_invite_account); sd->party_joining = false; sd->party_invite = 0; @@ -472,7 +461,7 @@ int party_member_added(int party_id,int account_id,int char_id, int flag) if (!p) { ShowError("party_member_added: party %d not found.\n",party_id); - intif_party_leave(party_id,account_id,char_id); + intif->party_leave(party_id,account_id,char_id); return 0; } @@ -502,10 +491,12 @@ int party_member_added(int party_id,int account_id,int char_id, int flag) clif->charnameupdate(sd); //Update char name's display [Skotlex] for( j = 0; j < p->instances; j++ ) { - if( instances[p->instance[j]].idle_timer == INVALID_TIMER && instances[p->instance[j]].progress_timer == INVALID_TIMER ) - continue; - clif->instance_join(sd->fd, p->instance[j]); - break; + if( p->instance[j] >= 0 ) { + if( instance->list[p->instance[j]].idle_timer == INVALID_TIMER && instance->list[p->instance[j]].progress_timer == INVALID_TIMER ) + continue; + clif->instance_join(sd->fd, p->instance[j]); + break; + } } return 0; @@ -532,7 +523,7 @@ int party_removemember(struct map_session_data* sd, int account_id, char* name) if( i == MAX_PARTY ) return 0; // no such char in party - intif_party_leave(p->party.party_id,account_id,p->party.member[i].char_id); + intif->party_leave(p->party.party_id,account_id,p->party.member[i].char_id); return 1; } @@ -550,14 +541,14 @@ int party_leave(struct map_session_data *sd) if( i == MAX_PARTY ) return 0; - intif_party_leave(p->party.party_id,sd->status.account_id,sd->status.char_id); + intif->party_leave(p->party.party_id,sd->status.account_id,sd->status.char_id); return 1; } /// Invoked (from char-server) when a party member leaves the party. int party_member_withdraw(int party_id, int account_id, int char_id) { - struct map_session_data* sd = iMap->id2sd(account_id); + struct map_session_data* sd = map->id2sd(account_id); struct party_data* p = party->search(party_id); if( p ) { @@ -568,18 +559,26 @@ int party_member_withdraw(int party_id, int account_id, int char_id) memset(&p->party.member[i], 0, sizeof(p->party.member[0])); memset(&p->data[i], 0, sizeof(p->data[0])); p->party.count--; - party_check_state(p); + party->check_state(p); } } if( sd && sd->status.party_id == party_id && sd->status.char_id == char_id ) { +#ifdef GP_BOUND_ITEMS + pc->bound_clear(sd,IBT_PARTY); +#endif sd->status.party_id = 0; clif->charnameupdate(sd); //Update name display [Skotlex] //TODO: hp bars should be cleared too - if( p->instances ) + if( p && p->instances ) instance->check_kick(sd); } - + if (sd && sd->sc.data[SC_DANCING]) { + status_change_end(&sd->bl, SC_DANCING, INVALID_TIMER); + status_change_end(&sd->bl, SC_DRUMBATTLE, INVALID_TIMER); + status_change_end(&sd->bl, SC_NIBELUNGEN, INVALID_TIMER); + status_change_end(&sd->bl, SC_SIEGFRIED, INVALID_TIMER); + } return 0; } @@ -594,8 +593,10 @@ int party_broken(int party_id) return 0; for( j = 0; j < p->instances; j++ ) { - instance->destroy( p->instance[j] ); - instances[p->instance[j]].owner_id = 0; + if( p->instance[j] >= 0 ) { + instance->destroy( p->instance[j] ); + instance->list[p->instance[j]].owner_id = 0; + } } for( i = 0; i < MAX_PARTY; i++ ) { @@ -605,7 +606,19 @@ int party_broken(int party_id) } } - idb_remove(party_db,party_id); + if( p->instance ) + aFree(p->instance); + + for( j = 0; j < p->hdatac; j++ ) { + if( p->hdata[j]->flag.free ) { + aFree(p->hdata[j]->data); + } + aFree(p->hdata[j]); + } + if( p->hdata ) + aFree(p->hdata); + + idb_remove(party->db,party_id); return 0; } @@ -615,14 +628,13 @@ int party_changeoption(struct map_session_data *sd,int exp,int item) if( sd->status.party_id==0) return 0; - intif_party_changeoption(sd->status.party_id,sd->status.account_id,exp,item); + intif->party_changeoption(sd->status.party_id,sd->status.account_id,exp,item); return 0; } -int party_optionchanged(int party_id,int account_id,int exp,int item,int flag) -{ +int party_optionchanged(int party_id,int account_id,int exp,int item,int flag) { struct party_data *p; - struct map_session_data *sd=iMap->id2sd(account_id); + struct map_session_data *sd=map->id2sd(account_id); if( (p=party->search(party_id))==NULL) return 0; @@ -650,8 +662,7 @@ bool party_changeleader(struct map_session_data *sd, struct map_session_data *ts return false; } - if( map[sd->bl.m].flag.partylock ) - { + if( map->list[sd->bl.m].flag.partylock ) { clif->message(sd->fd, msg_txt(287)); return false; } @@ -683,7 +694,7 @@ bool party_changeleader(struct map_session_data *sd, struct map_session_data *ts clif->message(p->data[tmi].sd->fd, msg_txt(285)); //Update info. - intif_party_leaderchange(p->party.party_id,p->party.member[tmi].account_id,p->party.member[tmi].char_id); + intif->party_leaderchange(p->party.party_id,p->party.member[tmi].account_id,p->party.member[tmi].char_id); clif->party_info(p,NULL); return true; } @@ -692,7 +703,7 @@ bool party_changeleader(struct map_session_data *sd, struct map_session_data *ts /// - changes maps /// - logs in or out /// - gains a level (disabled) -int party_recv_movemap(int party_id,int account_id,int char_id, unsigned short map,int online,int lv) +int party_recv_movemap(int party_id,int account_id,int char_id, unsigned short mapid,int online,int lv) { struct party_member* m; struct party_data* p; @@ -710,11 +721,11 @@ int party_recv_movemap(int party_id,int account_id,int char_id, unsigned short m } m = &p->party.member[i]; - m->map = map; + m->map = mapid; m->online = online; m->lv = lv; //Check if they still exist on this map server - p->data[i].sd = party_sd_check(party_id, account_id, char_id); + p->data[i].sd = party->sd_check(party_id, account_id, char_id); clif->party_info(p,NULL); return 0; @@ -727,7 +738,7 @@ void party_send_movemap(struct map_session_data *sd) if( sd->status.party_id==0 ) return; - intif_party_changemap(sd,1); + intif->party_changemap(sd,1); p=party->search(sd->status.party_id); if (!p) return; @@ -755,7 +766,7 @@ void party_send_movemap(struct map_session_data *sd) void party_send_levelup(struct map_session_data *sd) { - intif_party_changemap(sd,1); + intif->party_changemap(sd,1); } int party_send_logout(struct map_session_data *sd) @@ -766,7 +777,7 @@ int party_send_logout(struct map_session_data *sd) if(!sd->status.party_id) return 0; - intif_party_changemap(sd,0); + intif->party_changemap(sd,0); p=party->search(sd->status.party_id); if(!p) return 0; @@ -783,7 +794,7 @@ int party_send_message(struct map_session_data *sd,const char *mes,int len) { if(sd->status.party_id==0) return 0; - intif_party_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 @@ -833,7 +844,7 @@ int party_skill_check(struct map_session_data *sd, int party_id, uint16 skill_id case TK_COUNTER: //Increase Triple Attack rate of Monks. if((p_sd->class_&MAPID_UPPERMASK) == MAPID_MONK && pc->checkskill(p_sd,MO_TRIPLEATTACK)) { - sc_start4(&p_sd->bl,SC_SKILLRATE_UP,100,MO_TRIPLEATTACK, + sc_start4(&p_sd->bl,&p_sd->bl,SC_SKILLRATE_UP,100,MO_TRIPLEATTACK, 50+50*skill_lv, //+100/150/200% rate 0,0,skill->get_time(SG_FRIEND, 1)); } @@ -842,7 +853,7 @@ int party_skill_check(struct map_session_data *sd, int party_id, uint16 skill_id if((p_sd->class_&MAPID_UPPERMASK) == MAPID_STAR_GLADIATOR && sd->sc.data[SC_COUNTERKICK_READY] && pc->checkskill(p_sd,SG_FRIEND)) { - sc_start4(&p_sd->bl,SC_SKILLRATE_UP,100,TK_COUNTER, + sc_start4(&p_sd->bl,&p_sd->bl,SC_SKILLRATE_UP,100,TK_COUNTER, 50+50*pc->checkskill(p_sd,SG_FRIEND), //+100/150/200% rate 0,0,skill->get_time(SG_FRIEND, 1)); } @@ -852,11 +863,10 @@ int party_skill_check(struct map_session_data *sd, int party_id, uint16 skill_id return 0; } -int party_send_xy_timer(int tid, unsigned int tick, int id, intptr_t data) -{ +int party_send_xy_timer(int tid, int64 tick, int id, intptr_t data) { struct party_data* p; - DBIterator *iter = db_iterator(party_db); + DBIterator *iter = db_iterator(party->db); // for each existing party, for( p = dbi_first(iter); dbi_exists(iter); p = dbi_next(iter) ) { @@ -871,7 +881,7 @@ int party_send_xy_timer(int tid, unsigned int tick, int id, intptr_t data) for( i = 0; i < MAX_PARTY; i++ ) { struct map_session_data* sd = p->data[i].sd; - if( !sd ) continue; + if( !sd || sd->bg_id ) continue; if( p->data[i].x != sd->bl.x || p->data[i].y != sd->bl.y ) {// perform position update @@ -948,7 +958,9 @@ int party_exp_share(struct party_data* p, struct block_list* src, unsigned int b for (i = 0; i < c; i++) { #ifdef RENEWAL_EXP if( !(src && src->type == BL_MOB && ((TBL_MOB*)src)->db->mexp) ){ - int rate = pc->level_penalty_mod(sd[i], (TBL_MOB*)src, 1); + struct mob_data *md = (TBL_MOB*)src; + 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); } @@ -1050,9 +1062,11 @@ int party_sub_count(struct block_list *bl, va_list ap) return 1; } -/// Executes 'func' for each party member on the same map and in range (0:whole map) -int party_foreachsamemap(int (*func)(struct block_list*,va_list),struct map_session_data *sd,int range,...) -{ +/** + * Arglist-based version of party_foreachsamemap + * @see party_foreachsamemap + */ +int party_vforeachsamemap(int (*func)(struct block_list*,va_list), struct map_session_data *sd, int range, va_list ap) { struct party_data *p; int i; int x0,y0,x1,y1; @@ -1083,138 +1097,220 @@ int party_foreachsamemap(int (*func)(struct block_list*,va_list),struct map_sess list[blockcount++]=&psd->bl; } - iMap->freeblock_lock(); + map->freeblock_lock(); - for(i=0;i<blockcount;i++) - { - va_list ap; - va_start(ap, range); - total += func(list[i], ap); - va_end(ap); + for(i=0;i<blockcount;i++) { + va_list ap_copy; + va_copy(ap_copy, ap); + total += func(list[i], ap_copy); + va_end(ap_copy); } - iMap->freeblock_unlock(); + map->freeblock_unlock(); return total; } +// Special check for Minstrel's and Wanderer's chorus skills. +int party_sub_count_chorus(struct block_list *bl, va_list ap) { + struct map_session_data *sd = (TBL_PC *)bl; + + if (sd->state.autotrade) + return 0; + + if (battle_config.idle_no_share && pc_isidle(sd)) + return 0; + + if ( (sd->class_&MAPID_THIRDMASK) != MAPID_MINSTRELWANDERER ) + return 0; + + return 1; +} + +/** + * Executes 'func' for each party member on the same map and within a 'range' cells area + * @param func Function to execute + * @param sd Reference character for party, map, area center + * @param range Area size (0 = whole map) + * @param ... Additional parameters to pass to func() + * @return Sum of the return values from func() + */ +int party_foreachsamemap(int (*func)(struct block_list*,va_list), struct map_session_data *sd, int range, ...) { + va_list ap; + int ret; + va_start(ap, range); + ret = party->vforeachsamemap(func, sd, range, ap); + va_end(ap); + return ret; +} + /*========================================== * Party Booking in KRO [Spiria] *------------------------------------------*/ -static struct party_booking_ad_info* create_party_booking_data(void) -{ +struct party_booking_ad_info* create_party_booking_data(void) { struct party_booking_ad_info *pb_ad; CREATE(pb_ad, struct party_booking_ad_info, 1); - pb_ad->index = party_booking_nextid++; + pb_ad->index = party->booking_nextid++; return pb_ad; } -#ifndef PARTY_RECRUIT -void party_booking_register(struct map_session_data *sd, short level, short mapid, short* job) -#else -void party_booking_register(struct map_session_data *sd, short level, const char *notice) -#endif -{ +void party_recruit_register(struct map_session_data *sd, short level, const char *notice) { +#ifdef PARTY_RECRUIT struct party_booking_ad_info *pb_ad; -#ifndef PARTY_RECRUIT - int i; -#endif - pb_ad = (struct party_booking_ad_info*)idb_get(party_booking_db, sd->status.char_id); + pb_ad = (struct party_booking_ad_info*)idb_get(party->booking_db, sd->status.char_id); if( pb_ad == NULL ) { - pb_ad = create_party_booking_data(); - idb_put(party_booking_db, sd->status.char_id, pb_ad); + pb_ad = party->create_booking_data(); + idb_put(party->booking_db, sd->status.char_id, pb_ad); } else {// already registered - clif->PartyBookingRegisterAck(sd, 2); + clif->PartyRecruitRegisterAck(sd, 2); return; } memcpy(pb_ad->charname,sd->status.name,NAME_LENGTH); pb_ad->expiretime = (int)time(NULL); pb_ad->p_detail.level = level; + safestrncpy(pb_ad->p_detail.notice, notice, PB_NOTICE_LENGTH); + + clif->PartyRecruitRegisterAck(sd, 0); + clif->PartyRecruitInsertNotify(sd, pb_ad); // Notice +#else + return; +#endif +} + +void party_booking_register(struct map_session_data *sd, short level, short mapid, short* job) { #ifndef PARTY_RECRUIT + struct party_booking_ad_info *pb_ad; + int i; + + pb_ad = (struct party_booking_ad_info*)idb_get(party->booking_db, sd->status.char_id); + + if( pb_ad == NULL ) + { + pb_ad = party->create_booking_data(); + idb_put(party->booking_db, sd->status.char_id, pb_ad); + } + else + {// already registered + clif->PartyBookingRegisterAck(sd, 2); + return; + } + + memcpy(pb_ad->charname,sd->status.name,NAME_LENGTH); + pb_ad->expiretime = (int)time(NULL); + pb_ad->p_detail.level = level; pb_ad->p_detail.mapid = mapid; - + for(i=0;i<PARTY_BOOKING_JOBS;i++) if(job[i] != 0xFF) pb_ad->p_detail.job[i] = job[i]; else pb_ad->p_detail.job[i] = -1; -#else - safestrncpy(pb_ad->p_detail.notice, notice, PB_NOTICE_LENGTH); -#endif - + clif->PartyBookingRegisterAck(sd, 0); clif->PartyBookingInsertNotify(sd, pb_ad); // Notice -} - -#ifndef PARTY_RECRUIT -void party_booking_update(struct map_session_data *sd, short* job) #else -void party_booking_update(struct map_session_data *sd, const char *notice) -#endif -{ -#ifndef PARTY_RECRUIT - int i; + return; #endif +} + +void party_recruit_update(struct map_session_data *sd, const char *notice) { +#ifdef PARTY_RECRUIT struct party_booking_ad_info *pb_ad; - pb_ad = (struct party_booking_ad_info*)idb_get(party_booking_db, sd->status.char_id); + pb_ad = (struct party_booking_ad_info*)idb_get(party->booking_db, sd->status.char_id); if( pb_ad == NULL ) return; pb_ad->expiretime = (int)time(NULL);// Update time. + if (notice != NULL) { + safestrncpy(pb_ad->p_detail.notice, notice, PB_NOTICE_LENGTH); + } + + clif->PartyRecruitUpdateNotify(sd, pb_ad); +#else + return; +#endif +} +void party_booking_update(struct map_session_data *sd, short* job) { #ifndef PARTY_RECRUIT + int i; + struct party_booking_ad_info *pb_ad; + + pb_ad = (struct party_booking_ad_info*)idb_get(party->booking_db, sd->status.char_id); + + if( pb_ad == NULL ) + return; + + pb_ad->expiretime = (int)time(NULL);// Update time. + for(i=0;i<PARTY_BOOKING_JOBS;i++) if(job[i] != 0xFF) pb_ad->p_detail.job[i] = job[i]; else pb_ad->p_detail.job[i] = -1; + + clif->PartyBookingUpdateNotify(sd, pb_ad); #else - if (notice != NULL) { - safestrncpy(pb_ad->p_detail.notice, notice, PB_NOTICE_LENGTH); - } + return; #endif - - clif->PartyBookingUpdateNotify(sd, pb_ad); } -#ifndef PARTY_RECRUIT -void party_booking_search(struct map_session_data *sd, short level, short mapid, short job, unsigned long lastindex, short resultcount) -#else -void party_booking_search(struct map_session_data *sd, short level, short mapid, unsigned long lastindex, short resultcount) -#endif -{ + +void party_recruit_search(struct map_session_data *sd, short level, short mapid, unsigned long lastindex, short resultcount) { +#ifdef PARTY_RECRUIT struct party_booking_ad_info *pb_ad; -#ifndef PARTY_RECRUIT - int i; -#endif int count = 0; struct party_booking_ad_info* result_list[PARTY_BOOKING_RESULTS]; bool more_result = false; - DBIterator* iter = db_iterator(party_booking_db); + DBIterator* iter = db_iterator(party->booking_db); memset(result_list, 0, sizeof(result_list)); for( pb_ad = dbi_first(iter); dbi_exists(iter); pb_ad = dbi_next(iter) ) { -#ifndef PARTY_RECRUIT - if (pb_ad->index < lastindex || (level && (pb_ad->p_detail.level < level-15 || pb_ad->p_detail.level > level))) - continue; -#else if ((level && (pb_ad->p_detail.level < level-15 || pb_ad->p_detail.level > level))) continue; -#endif if (count >= PARTY_BOOKING_RESULTS){ more_result = true; break; } + result_list[count] = pb_ad; + if( result_list[count] ) + { + count++; + } + } + dbi_destroy(iter); + clif->PartyRecruitSearchAck(sd->fd, result_list, count, more_result); +#else + return; +#endif +} +void party_booking_search(struct map_session_data *sd, short level, short mapid, short job, unsigned long lastindex, short resultcount) { #ifndef PARTY_RECRUIT + struct party_booking_ad_info *pb_ad; + int i; + int count = 0; + struct party_booking_ad_info* result_list[PARTY_BOOKING_RESULTS]; + bool more_result = false; + DBIterator* iter = db_iterator(party->booking_db); + + memset(result_list, 0, sizeof(result_list)); + + for( pb_ad = dbi_first(iter); dbi_exists(iter); pb_ad = dbi_next(iter) ) { + if (pb_ad->index < lastindex || (level && (pb_ad->p_detail.level < level-15 || pb_ad->p_detail.level > level))) + continue; + if (count >= PARTY_BOOKING_RESULTS){ + more_result = true; + break; + } if (mapid == 0 && job == -1) result_list[count] = pb_ad; else if (mapid == 0) { @@ -1225,9 +1321,6 @@ void party_booking_search(struct map_session_data *sd, short level, short mapid, if (pb_ad->p_detail.mapid == mapid) result_list[count] = pb_ad; } -#else - result_list[count] = pb_ad; -#endif if( result_list[count] ) { count++; @@ -1235,32 +1328,57 @@ void party_booking_search(struct map_session_data *sd, short level, short mapid, } dbi_destroy(iter); clif->PartyBookingSearchAck(sd->fd, result_list, count, more_result); +#else + return; +#endif } + bool party_booking_delete(struct map_session_data *sd) { struct party_booking_ad_info* pb_ad; - if((pb_ad = (struct party_booking_ad_info*)idb_get(party_booking_db, sd->status.char_id))!=NULL) + if((pb_ad = (struct party_booking_ad_info*)idb_get(party->booking_db, sd->status.char_id))!=NULL) { +#ifdef PARTY_RECRUIT + clif->PartyRecruitDeleteNotify(sd, pb_ad->index); +#else clif->PartyBookingDeleteNotify(sd, pb_ad->index); - idb_remove(party_booking_db,sd->status.char_id); +#endif + idb_remove(party->booking_db,sd->status.char_id); } return true; } +void do_final_party(void) { + party->db->destroy(party->db,party->db_final); + db_destroy(party->booking_db); // Party Booking [Spiria] +} +// Constructor, init vars +void do_init_party(bool minimal) { + if (minimal) + return; + party->db = idb_alloc(DB_OPT_RELEASE_DATA); + party->booking_db = idb_alloc(DB_OPT_RELEASE_DATA); // Party Booking [Spiria] + timer->add_func_list(party->send_xy_timer, "party_send_xy_timer"); + timer->add_interval(timer->gettick()+battle_config.party_update_interval, party->send_xy_timer, 0, 0, battle_config.party_update_interval); +} /*===================================== -* Default Functions : party.h +* Default Functions : party.h * Generated by HerculesInterfaceMaker * created by Susu *-------------------------------------*/ void party_defaults(void) { party = &party_s; + /* */ + party->db = NULL; + party->booking_db = NULL; + party->booking_nextid = 1; /* funcs */ - - party->do_init_party = do_init_party; - party->do_final_party = do_final_party; + party->init = do_init_party; + party->final = do_final_party; + /* */ party->search = party_search; party->searchname = party_searchname; party->getmemberid = party_getmemberid; @@ -1294,8 +1412,20 @@ void party_defaults(void) { party->share_loot = party_share_loot; party->send_dot_remove = party_send_dot_remove; party->sub_count = party_sub_count; + party->sub_count_chorus = party_sub_count_chorus; party->booking_register = party_booking_register; party->booking_update = party_booking_update; party->booking_search = party_booking_search; + party->recruit_register = party_recruit_register; + party->recruit_update = party_recruit_update; + party->recruit_search = party_recruit_search; party->booking_delete = party_booking_delete; + party->vforeachsamemap = party_vforeachsamemap; + party->foreachsamemap = party_foreachsamemap; + party->send_xy_timer = party_send_xy_timer; + party->fill_member = party_fill_member; + party->sd_check = party_sd_check; + party->check_state = party_check_state; + party->create_booking_data = create_party_booking_data; + party->db_final = party_db_final; } diff --git a/src/map/party.h b/src/map/party.h index e1f2d3a3b..d62db23a7 100644 --- a/src/map/party.h +++ b/src/map/party.h @@ -1,19 +1,22 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder -#ifndef _PARTY_H_ -#define _PARTY_H_ -#include "../common/mmo.h" // struct party -#include "../config/core.h" -struct block_list; -struct map_session_data; -struct party; -struct item; +// Copyright (c) Hercules Dev Team, licensed under GNU GPL. +// See the LICENSE file +// Portions Copyright (c) Athena Dev Teams + +#ifndef MAP_PARTY_H +#define MAP_PARTY_H #include <stdarg.h> +#include "map.h" // TBL_PC +#include "../common/cbasetypes.h" +#include "../common/db.h" +#include "../common/mmo.h" // struct party + #define PARTY_BOOKING_JOBS 6 #define PARTY_BOOKING_RESULTS 10 +struct HPluginData; + struct party_member_data { struct map_session_data *sd; unsigned int hp; //For HP,x,y refreshing. @@ -24,7 +27,7 @@ struct party_data { struct party party; struct party_member_data data[MAX_PARTY]; uint8 itemc; //For item distribution, position of last picker in party - unsigned short *instance; + short *instance; unsigned short instances; struct { unsigned monk : 1; //There's at least one monk in party? @@ -32,8 +35,14 @@ struct party_data { unsigned snovice :1; //There's a Super Novice unsigned tk : 1; //There's a taekwon } state; + + /* HPM Custom Struct */ + struct HPluginData **hdata; + unsigned int hdatac; }; +#define PB_NOTICE_LENGTH (36 + 1) + #ifndef PARTY_RECRUIT struct party_booking_detail { short level; @@ -42,44 +51,38 @@ struct party_booking_detail { }; struct party_booking_ad_info { - unsigned long index; + unsigned int index; char charname[NAME_LENGTH]; - long expiretime; + int expiretime; struct party_booking_detail p_detail; }; -#else -#define PB_NOTICE_LENGTH (36 + 1) +#else /* PARTY_RECRUIT */ struct party_booking_detail { short level; char notice[PB_NOTICE_LENGTH]; }; struct party_booking_ad_info { - unsigned long index; - long expiretime; + unsigned int index; + int expiretime; char charname[NAME_LENGTH]; struct party_booking_detail p_detail; }; -#endif - - -int party_foreachsamemap(int (*func)(struct block_list *,va_list),struct map_session_data *sd,int range,...); - -/*========================================== - * Party Booking in KRO [Spiria] - *------------------------------------------*/ +#endif /* PARTY_RECRUIT */ /*===================================== -* Interface : party.h +* Interface : party.h * Generated by HerculesInterfaceMaker * created by Susu *-------------------------------------*/ struct party_interface { - + DBMap* db; // int party_id -> struct party_data* (releases data) + DBMap* booking_db; // int char_id -> struct party_booking_ad_info* (releases data) // Party Booking [Spiria] + unsigned int booking_nextid; /* funcs */ - - void (*do_init_party) (void); - void (*do_final_party) (void); + void (*init) (bool minimal); + void (*final) (void); + /* */ struct party_data* (*search) (int party_id); struct party_data* (*searchname) (const char* str); int (*getmemberid) (struct party_data* p, struct map_session_data* sd); @@ -97,7 +100,7 @@ struct party_interface { void (*reply_invite) (struct map_session_data *sd,int party_id,int flag); int (*recv_noinfo) (int party_id, int char_id); int (*recv_info) (struct party* sp, int char_id); - int (*recv_movemap) (int party_id,int account_id,int char_id, unsigned short map,int online,int lv); + int (*recv_movemap) (int party_id,int account_id,int char_id, unsigned short mapid,int online,int lv); int (*broken) (int party_id); int (*optionchanged) (int party_id,int account_id,int exp,int item,int flag); int (*changeoption) (struct map_session_data *sd,int exp,int item); @@ -113,20 +116,31 @@ struct party_interface { int (*share_loot) (struct party_data* p, struct map_session_data* sd, struct item* item_data, int first_charid); int (*send_dot_remove) (struct map_session_data *sd); int (*sub_count) (struct block_list *bl, va_list ap); -#ifndef PARTY_RECRUIT + int (*sub_count_chorus) (struct block_list *bl, va_list ap); + /*========================================== + * Party Booking in KRO [Spiria] + *------------------------------------------*/ void (*booking_register) (struct map_session_data *sd, short level, short mapid, short* job); void (*booking_update) (struct map_session_data *sd, short* job); void (*booking_search) (struct map_session_data *sd, short level, short mapid, short job, unsigned long lastindex, short resultcount); -#else - void (*booking_register) (struct map_session_data *sd, short level, const char *notice); - void (*booking_update) (struct map_session_data *sd, const char *notice); - void (*booking_search) (struct map_session_data *sd, short level, short mapid, unsigned long lastindex, short resultcount); -#endif + /* PARTY_RECRUIT */ + void (*recruit_register) (struct map_session_data *sd, short level, const char *notice); + void (*recruit_update) (struct map_session_data *sd, const char *notice); + void (*recruit_search) (struct map_session_data *sd, short level, short mapid, unsigned long lastindex, short resultcount); bool (*booking_delete) (struct map_session_data *sd); -} party_s; + /* */ + int (*vforeachsamemap) (int (*func)(struct block_list *,va_list),struct map_session_data *sd,int range, va_list ap); + int (*foreachsamemap) (int (*func)(struct block_list *,va_list),struct map_session_data *sd,int range,...); + int (*send_xy_timer) (int tid, int64 tick, int id, intptr_t data); + void (*fill_member) (struct party_member* member, struct map_session_data* sd, unsigned int leader); + TBL_PC* (*sd_check) (int party_id, int account_id, int char_id); + void (*check_state) (struct party_data *p); + struct party_booking_ad_info* (*create_booking_data) (void); + int (*db_final) (DBKey key, DBData *data, va_list ap); +}; struct party_interface *party; void party_defaults(void); -#endif /* _PARTY_H_ */ +#endif /* MAP_PARTY_H */ diff --git a/src/map/path.c b/src/map/path.c index 95895cb2a..5a9ddf9c7 100644 --- a/src/map/path.c +++ b/src/map/path.c @@ -1,149 +1,67 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder +// Copyright (c) Hercules Dev Team, licensed under GNU GPL. +// See the LICENSE file +// Portions Copyright (c) Athena Dev Teams -#include "../common/cbasetypes.h" -#include "../common/nullpo.h" -#include "../common/random.h" -#include "../common/showmsg.h" -#include "../common/malloc.h" -#include "map.h" -#include "battle.h" +#define HERCULES_CORE + +#include "../config/core.h" // CELL_NOSTACK, CIRCULAR_AREA #include "path.h" #include <stdio.h> #include <stdlib.h> #include <string.h> +#include "map.h" +#include "../common/cbasetypes.h" +#include "../common/db.h" +#include "../common/malloc.h" +#include "../common/nullpo.h" +#include "../common/random.h" +#include "../common/showmsg.h" -#define MAX_HEAP 150 - -struct tmp_path { short x,y,dist,before,cost,flag;}; -#define calc_index(x,y) (((x)+(y)*MAX_WALKPATH) & (MAX_WALKPATH*MAX_WALKPATH-1)) - -const char walk_choices [3][3] = -{ - {1,0,7}, - {2,-1,6}, - {3,4,5}, -}; - -/*========================================== - * heap push (helper function) - *------------------------------------------*/ -static void push_heap_path(int *heap,struct tmp_path *tp,int index) -{ - int i,h; - - h = heap[0]; - heap[0]++; - - for( i = (h-1)/2; h > 0 && tp[index].cost < tp[heap[i+1]].cost; i = (h-1)/2 ) - heap[h+1] = heap[i+1], h = i; - - heap[h+1] = index; -} - -/*========================================== - * heap update (helper function) - * Move toward the root because cost has decreased. - *------------------------------------------*/ -static void update_heap_path(int *heap,struct tmp_path *tp,int index) -{ - int i,h; - - ARR_FIND( 0, heap[0], h, heap[h+1] == index ); - if( h == heap[0] ) - { - ShowError("update_heap_path bug\n"); - exit(EXIT_FAILURE); - } - - for( i = (h-1)/2; h > 0 && tp[index].cost < tp[heap[i+1]].cost; i = (h-1)/2 ) - heap[h+1] = heap[i+1], h = i; - - heap[h+1] = index; -} +#define SET_OPEN 0 +#define SET_CLOSED 1 -/*========================================== - * heap pop (helper function) - *------------------------------------------*/ -static int pop_heap_path(int *heap,struct tmp_path *tp) -{ - int i,h,k; - int ret,last; +#define DIR_NORTH 1 +#define DIR_WEST 2 +#define DIR_SOUTH 4 +#define DIR_EAST 8 - if( heap[0] <= 0 ) - return -1; - ret = heap[1]; - last = heap[heap[0]]; - heap[0]--; +struct path_interface path_s; - for( h = 0, k = 2; k < heap[0]; k = k*2+2 ) - { - if( tp[heap[k+1]].cost > tp[heap[k]].cost ) - k--; - heap[h+1] = heap[k+1], h = k; - } +/// @name Structures and defines for A* pathfinding +/// @{ - if( k == heap[0] ) - heap[h+1] = heap[k], h = k-1; +/// Path node +struct path_node { + struct path_node *parent; ///< pointer to parent (for path reconstruction) + short x; ///< X-coordinate + short y; ///< Y-coordinate + short g_cost; ///< Actual cost from start to this node + short f_cost; ///< g_cost + heuristic(this, goal) + short flag; ///< SET_OPEN / SET_CLOSED +}; - for( i = (h-1)/2; h > 0 && tp[heap[i+1]].cost > tp[last].cost; i = (h-1)/2 ) - heap[h+1] = heap[i+1], h = i; +/// Binary heap of path nodes +BHEAP_STRUCT_DECL(node_heap, struct path_node*); - heap[h+1]=last; +/// Comparator for binary heap of path nodes (minimum cost at top) +#define NODE_MINTOPCMP(i,j) ((i)->f_cost - (j)->f_cost) - return ret; -} +#define calc_index(x,y) (((x)+(y)*MAX_WALKPATH) & (MAX_WALKPATH*MAX_WALKPATH-1)) -/*========================================== - * calculate cost for the specified position - *------------------------------------------*/ -static int calc_cost(struct tmp_path *p,int16 x1,int16 y1) -{ - int xd = abs(x1 - p->x); - int yd = abs(y1 - p->y); - return (xd + yd)*10 + p->dist; -} +/// Estimates the cost from (x0,y0) to (x1,y1). +/// This is inadmissible (overestimating) heuristic used by game client. +#define heuristic(x0, y0, x1, y1) (MOVE_COST * (abs((x1) - (x0)) + abs((y1) - (y0)))) // Manhattan distance +/// @} -/*========================================== - * attach/adjust path if neccessary - *------------------------------------------*/ -static int add_path(int *heap,struct tmp_path *tp,int16 x,int16 y,int dist,int before,int cost) +// Translates dx,dy into walking direction +static const unsigned char walk_choices [3][3] = { - int i; - - i = calc_index(x,y); - - if( tp[i].x == x && tp[i].y == y ) - { - if( tp[i].dist > dist ) - { - tp[i].dist = dist; - tp[i].before = before; - tp[i].cost = cost; - if( tp[i].flag ) - push_heap_path(heap,tp,i); - else - update_heap_path(heap,tp,i); - tp[i].flag = 0; - } - return 0; - } - - if( tp[i].x || tp[i].y ) - return 1; - - tp[i].x = x; - tp[i].y = y; - tp[i].dist = dist; - tp[i].before = before; - tp[i].cost = cost; - tp[i].flag = 0; - push_heap_path(heap,tp,i); - - return 0; -} + {1,0,7}, + {2,-1,6}, + {3,4,5}, +}; /*========================================== * Find the closest reachable cell, 'count' cells away from (x0,y0) in direction (dx,dy). @@ -153,9 +71,9 @@ int path_blownpos(int16 m,int16 x0,int16 y0,int16 dx,int16 dy,int count) { struct map_data *md; - if( !map[m].cell ) + if( !map->list[m].cell ) return -1; - md = &map[m]; + md = &map->list[m]; if( count>25 ){ //Cap to prevent too much processing...? ShowWarning("path_blownpos: count too many %d !\n",count); @@ -168,21 +86,8 @@ int path_blownpos(int16 m,int16 x0,int16 y0,int16 dx,int16 dy,int count) } while( count > 0 && (dx != 0 || dy != 0) ) { - if( !md->getcellp(md,x0+dx,y0+dy,CELL_CHKPASS) ) {// attempt partial movement - int fx = ( dx != 0 && md->getcellp(md,x0+dx,y0,CELL_CHKPASS) ); - int fy = ( dy != 0 && md->getcellp(md,x0,y0+dy,CELL_CHKPASS) ); - if( fx && fy ) - { - if(rnd()&1) - dx=0; - else - dy=0; - } - if( !fx ) - dx=0; - if( !fy ) - dy=0; - } + if( !md->getcellp(md,x0+dx,y0+dy,CELL_CHKPASS) ) + break; x0 += dx; y0 += dy; @@ -206,9 +111,9 @@ bool path_search_long(struct shootpath_data *spd,int16 m,int16 x0,int16 y0,int16 if( spd == NULL ) spd = &s_spd; // use dummy output variable - if (!map[m].cell) + if (!map->list[m].cell) return false; - md = &map[m]; + md = &map->list[m]; dx = (x1 - x0); if (dx < 0) { @@ -262,164 +167,252 @@ bool path_search_long(struct shootpath_data *spd,int16 m,int16 x0,int16 y0,int16 return true; } +/// @name A* pathfinding related functions +/// @{ + +/// Pushes path_node to the binary node_heap. +/// Ensures there is enough space in array to store new element. +static void heap_push_node(struct node_heap *heap, struct path_node *node) +{ +#ifndef __clang_analyzer__ // TODO: Figure out why clang's static analyzer doesn't like this + BHEAP_ENSURE(*heap, 1, 256); + BHEAP_PUSH(*heap, node, NODE_MINTOPCMP, swap_ptr); +#endif // __clang_analyzer__ +} + +/// Updates path_node in the binary node_heap. +static int heap_update_node(struct node_heap *heap, struct path_node *node) +{ + int i; + ARR_FIND(0, BHEAP_LENGTH(*heap), i, BHEAP_DATA(*heap)[i] == node); + if (i == BHEAP_LENGTH(*heap)) { + ShowError("heap_update_node: node not found\n"); + return 1; + } + BHEAP_POPINDEX(*heap, i, NODE_MINTOPCMP, swap_ptr); + BHEAP_PUSH(*heap, node, NODE_MINTOPCMP, swap_ptr); + return 0; +} + +/// Path_node processing in A* pathfinding. +/// Adds new node to heap and updates/re-adds old ones if necessary. +static int add_path(struct node_heap *heap, struct path_node *tp, int16 x, int16 y, int g_cost, struct path_node *parent, int h_cost) +{ + int i = calc_index(x, y); + + if (tp[i].x == x && tp[i].y == y) { // We processed this node before + if (g_cost < tp[i].g_cost) { // New path to this node is better than old one + // Update costs and parent + tp[i].g_cost = g_cost; + tp[i].parent = parent; + tp[i].f_cost = g_cost + h_cost; + if (tp[i].flag == SET_CLOSED) { + heap_push_node(heap, &tp[i]); // Put it in open set again + } + else if (heap_update_node(heap, &tp[i])) { + return 1; + } + tp[i].flag = SET_OPEN; + } + return 0; + } + + if (tp[i].x || tp[i].y) // Index is already taken; see `tp` array FIXME for details + return 1; + + // New node + tp[i].x = x; + tp[i].y = y; + tp[i].g_cost = g_cost; + tp[i].parent = parent; + tp[i].f_cost = g_cost + h_cost; + tp[i].flag = SET_OPEN; + heap_push_node(heap, &tp[i]); + return 0; +} +///@} + /*========================================== * path search (x0,y0)->(x1,y1) * wpd: path info will be written here * flag: &1 = easy path search only * cell: type of obstruction to check for *------------------------------------------*/ -bool path_search(struct walkpath_data *wpd,int16 m,int16 x0,int16 y0,int16 x1,int16 y1,int flag,cell_chk cell) +bool path_search(struct walkpath_data *wpd, int16 m, int16 x0, int16 y0, int16 x1, int16 y1, int flag, cell_chk cell) { - int heap[MAX_HEAP+1]; - struct tmp_path tp[MAX_WALKPATH*MAX_WALKPATH]; - register int i,j,len,x,y,dx,dy; - int rp,xs,ys; + register int i, j, x, y, dx, dy; struct map_data *md; struct walkpath_data s_wpd; - if( wpd == NULL ) + if (wpd == NULL) wpd = &s_wpd; // use dummy output variable - if( !map[m].cell ) + if (!map->list[m].cell) return false; - md = &map[m]; + md = &map->list[m]; #ifdef CELL_NOSTACK //Do not check starting cell as that would get you stuck. - if( x0 < 0 || x0 >= md->xs || y0 < 0 || y0 >= md->ys ) + if (x0 < 0 || x0 >= md->xs || y0 < 0 || y0 >= md->ys) #else - if( x0 < 0 || x0 >= md->xs || y0 < 0 || y0 >= md->ys /*|| md->getcellp(md,x0,y0,cell)*/ ) + if (x0 < 0 || x0 >= md->xs || y0 < 0 || y0 >= md->ys /*|| md->getcellp(md,x0,y0,cell)*/) #endif return false; - if( x1 < 0 || x1 >= md->xs || y1 < 0 || y1 >= md->ys || md->getcellp(md,x1,y1,cell) ) + + // Check destination cell + if (x1 < 0 || x1 >= md->xs || y1 < 0 || y1 >= md->ys || md->getcellp(md,x1,y1,cell)) return false; - // calculate (sgn(x1-x0), sgn(y1-y0)) - dx = ((dx = x1-x0)) ? ((dx<0) ? -1 : 1) : 0; - dy = ((dy = y1-y0)) ? ((dy<0) ? -1 : 1) : 0; + if (flag&1) { + // Try finding direct path to target + // Direct path goes diagonally first, then in straight line. - // try finding direct path to target - x = x0; - y = y0; - i = 0; - while( i < ARRAYLENGTH(wpd->path) ) - { - wpd->path[i] = walk_choices[-dy + 1][dx + 1]; - i++; + // calculate (sgn(x1-x0), sgn(y1-y0)) + dx = ((dx = x1-x0)) ? ((dx<0) ? -1 : 1) : 0; + dy = ((dy = y1-y0)) ? ((dy<0) ? -1 : 1) : 0; - x += dx; - y += dy; + x = x0; // Current position = starting cell + y = y0; + i = 0; + while( i < ARRAYLENGTH(wpd->path) ) + { + wpd->path[i] = walk_choices[-dy + 1][dx + 1]; + i++; - if( x == x1 ) dx = 0; - if( y == y1 ) dy = 0; + x += dx; // Advance current position + y += dy; - if( dx == 0 && dy == 0 ) - break; // success - if( md->getcellp(md,x,y,cell) ) - break; // obstacle = failure - } + if( x == x1 ) dx = 0; // destination x reached, no longer move along x-axis + if( y == y1 ) dy = 0; // destination y reached, no longer move along y-axis - if( x == x1 && y == y1 ) - { //easy path successful. - wpd->path_len = i; - wpd->path_pos = 0; - return true; + if( dx == 0 && dy == 0 ) + break; // success + if( md->getcellp(md,x,y,cell) ) + break; // obstacle = failure + } + + if( x == x1 && y == y1 ) + { // easy path successful. + wpd->path_len = i; + wpd->path_pos = 0; + return true; + } + + return false; // easy path unsuccessful } + 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. + + BHEAP_STRUCT_VAR(node_heap, open_set); // 'Open' set + + // FIXME: This array is too small to ensure all paths shorter than MAX_WALKPATH + // can be found without node collision: calc_index(node1) = calc_index(node2). + // Figure out more proper size or another way to keep track of known nodes. + struct path_node tp[MAX_WALKPATH * MAX_WALKPATH]; + struct path_node *current, *it; + int xs = md->xs - 1; + int ys = md->ys - 1; + int len = 0; + memset(tp, 0, sizeof(tp)); + + // Start node + i = calc_index(x0, y0); + tp[i].parent = NULL; + tp[i].x = x0; + tp[i].y = y0; + tp[i].g_cost = 0; + tp[i].f_cost = heuristic(x0, y0, x1, y1); + tp[i].flag = SET_OPEN; + + heap_push_node(&open_set, &tp[i]); // Put start node to 'open' set + for(;;) + { + int e = 0; // error flag - if( flag&1 ) - return false; + // Saves allowed directions for the current cell. Diagonal directions + // are only allowed if both directions around it are allowed. This is + // to prevent cutting corner of nearby wall. + // For example, you can only go NW from the current cell, if you can + // go N *and* you can go W. Otherwise you need to walk around the + // (corner of the) non-walkable cell. + int allowed_dirs = 0; - memset(tp,0,sizeof(tp)); - - i=calc_index(x0,y0); - tp[i].x=x0; - tp[i].y=y0; - tp[i].dist=0; - tp[i].before=0; - tp[i].cost=calc_cost(&tp[i],x1,y1); - tp[i].flag=0; - heap[0]=0; - push_heap_path(heap,tp,calc_index(x0,y0)); - xs = md->xs - 1; // Place by subtracting a pre- - ys = md->ys-1; - - for(;;) - { - int e=0,f=0,dist,cost,dc[4]={0,0,0,0}; + int g_cost; - if(heap[0]==0) - return false; - rp = pop_heap_path(heap,tp); - x = tp[rp].x; - y = tp[rp].y; - dist = tp[rp].dist + 10; - cost = tp[rp].cost; + if (BHEAP_LENGTH(open_set) == 0) { + BHEAP_CLEAR(open_set); + return false; + } - if(x==x1 && y==y1) - break; + current = BHEAP_PEEK(open_set); // Look for the lowest f_cost node in the 'open' set + BHEAP_POP(open_set, NODE_MINTOPCMP, swap_ptr); // Remove it from 'open' set - // dc[0] : y++ Incremental cost at the time - // dc[1] : x-- - // dc[2] : y-- - // dc[3] : x++ + x = current->x; + y = current->y; + g_cost = current->g_cost; - if(y < ys && !md->getcellp(md,x ,y+1,cell)) { - f |= 1; dc[0] = (y >= y1 ? 20 : 0); - e+=add_path(heap,tp,x ,y+1,dist,rp,cost+dc[0]); // (x, y+1) - } - if(x > 0 && !md->getcellp(md,x-1,y ,cell)) { - f |= 2; dc[1] = (x <= x1 ? 20 : 0); - e+=add_path(heap,tp,x-1,y ,dist,rp,cost+dc[1]); // (x-1, y ) - } - if(y > 0 && !md->getcellp(md,x ,y-1,cell)) { - f |= 4; dc[2] = (y <= y1 ? 20 : 0); - e+=add_path(heap,tp,x ,y-1,dist,rp,cost+dc[2]); // (x , y-1) - } - if(x < xs && !md->getcellp(md,x+1,y ,cell)) { - f |= 8; dc[3] = (x >= x1 ? 20 : 0); - e+=add_path(heap,tp,x+1,y ,dist,rp,cost+dc[3]); // (x+1, y ) - } - if( (f & (2+1)) == (2+1) && !md->getcellp(md,x-1,y+1,cell)) - e+=add_path(heap,tp,x-1,y+1,dist+4,rp,cost+dc[1]+dc[0]-6); // (x-1, y+1) - if( (f & (2+4)) == (2+4) && !md->getcellp(md,x-1,y-1,cell)) - e+=add_path(heap,tp,x-1,y-1,dist+4,rp,cost+dc[1]+dc[2]-6); // (x-1, y-1) - if( (f & (8+4)) == (8+4) && !md->getcellp(md,x+1,y-1,cell)) - e+=add_path(heap,tp,x+1,y-1,dist+4,rp,cost+dc[3]+dc[2]-6); // (x+1, y-1) - if( (f & (8+1)) == (8+1) && !md->getcellp(md,x+1,y+1,cell)) - e+=add_path(heap,tp,x+1,y+1,dist+4,rp,cost+dc[3]+dc[0]-6); // (x+1, y+1) - tp[rp].flag=1; - if(e || heap[0]>=MAX_HEAP-5) - return false; - } + current->flag = SET_CLOSED; // Add current node to 'closed' set - if( !(x==x1 && y==y1) ) // will never happen... - return false; + if (x == x1 && y == y1) { + BHEAP_CLEAR(open_set); + break; + } - for(len=0,i=rp;len<100 && i!=calc_index(x0,y0);i=tp[i].before,len++); - if(len==100 || len>=sizeof(wpd->path)) - return false; + if (y < ys && !md->getcellp(md, x, y+1, cell)) allowed_dirs |= DIR_NORTH; + if (y > 0 && !md->getcellp(md, x, y-1, cell)) allowed_dirs |= DIR_SOUTH; + if (x < xs && !md->getcellp(md, x+1, y, cell)) allowed_dirs |= DIR_EAST; + if (x > 0 && !md->getcellp(md, x-1, y, cell)) allowed_dirs |= DIR_WEST; + +#define chk_dir(d) ((allowed_dirs & (d)) == (d)) + // Process neighbors of current node + // TODO: Processing order affects chosen path if there is more than one path with same cost. + // In few cases path found by server will be different than path found by game client. + if (chk_dir(DIR_SOUTH)) + e += add_path(&open_set, tp, x, y-1, g_cost + MOVE_COST, current, heuristic(x, y-1, x1, y1)); // (x, y-1) 4 + if (chk_dir(DIR_SOUTH|DIR_WEST) && !md->getcellp(md, x-1, y-1, cell)) + e += add_path(&open_set, tp, x-1, y-1, g_cost + MOVE_DIAGONAL_COST, current, heuristic(x-1, y-1, x1, y1)); // (x-1, y-1) 3 + if (chk_dir(DIR_WEST)) + e += add_path(&open_set, tp, x-1, y, g_cost + MOVE_COST, current, heuristic(x-1, y, x1, y1)); // (x-1, y) 2 + if (chk_dir(DIR_NORTH|DIR_WEST) && !md->getcellp(md, x-1, y+1, cell)) + e += add_path(&open_set, tp, x-1, y+1, g_cost + MOVE_DIAGONAL_COST, current, heuristic(x-1, y+1, x1, y1)); // (x-1, y+1) 1 + if (chk_dir(DIR_NORTH)) + e += add_path(&open_set, tp, x, y+1, g_cost + MOVE_COST, current, heuristic(x, y+1, x1, y1)); // (x, y+1) 0 + if (chk_dir(DIR_NORTH|DIR_EAST) && !md->getcellp(md, x+1, y+1, cell)) + e += add_path(&open_set, tp, x+1, y+1, g_cost + MOVE_DIAGONAL_COST, current, heuristic(x+1, y+1, x1, y1)); // (x+1, y+1) 7 + if (chk_dir(DIR_EAST)) + e += add_path(&open_set, tp, x+1, y, g_cost + MOVE_COST, current, heuristic(x+1, y, x1, y1)); // (x+1, y) 6 + if (chk_dir(DIR_SOUTH|DIR_EAST) && !md->getcellp(md, x+1, y-1, cell)) + e += add_path(&open_set, tp, x+1, y-1, g_cost + MOVE_DIAGONAL_COST, current, heuristic(x+1, y-1, x1, y1)); // (x+1, y-1) 5 +#undef chk_dir + if (e) { + BHEAP_CLEAR(open_set); + return false; + } + } - wpd->path_len = len; - wpd->path_pos = 0; - for(i=rp,j=len-1;j>=0;i=tp[i].before,j--) { - int dx = tp[i].x - tp[tp[i].before].x; - int dy = tp[i].y - tp[tp[i].before].y; - uint8 dir; - if( dx == 0 ) { - dir = (dy > 0 ? 0 : 4); - } else if( dx > 0 ) { - dir = (dy == 0 ? 6 : (dy < 0 ? 5 : 7) ); - } else { - dir = (dy == 0 ? 2 : (dy > 0 ? 1 : 3) ); + for (it = current; it->parent != NULL; it = it->parent, len++); + if (len > sizeof(wpd->path)) { + return false; } - wpd->path[j] = dir; - } - return true; + // Recreate path + wpd->path_len = len; + wpd->path_pos = 0; + for (it = current, j = len-1; j >= 0; it = it->parent, j--) { + dx = it->x - it->parent->x; + dy = it->y - it->parent->y; + wpd->path[j] = walk_choices[-dy + 1][dx + 1]; + } + return true; + } // A* end + + return false; } -//Distance functions, taken from http://www.flpcode.com/articles/article_fastdistance.shtml +//Distance functions, taken from http://www.flipcode.com/articles/article_fastdistance.shtml int check_distance(int dx, int dy, int distance) { #ifdef CIRCULAR_AREA @@ -439,7 +432,7 @@ unsigned int distance(int dx, int dy) if ( dx < 0 ) dx = -dx; if ( dy < 0 ) dy = -dy; - //There appears to be something wrong with the aproximation below when either dx/dy is 0! [Skotlex] + //There appears to be something wrong with the approximation below when either dx/dy is 0! [Skotlex] if ( dx == 0 ) return dy; if ( dy == 0 ) return dx; @@ -460,3 +453,12 @@ unsigned int distance(int dx, int dy) return (dx<dy?dy:dx); #endif } +void path_defaults(void) { + path = &path_s; + + path->blownpos = path_blownpos; + path->search_long = path_search_long; + path->search = path_search; + path->check_distance = check_distance; + path->distance = distance; +} diff --git a/src/map/path.h b/src/map/path.h index b1ca71955..8d02e6558 100644 --- a/src/map/path.h +++ b/src/map/path.h @@ -1,10 +1,15 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder +// Copyright (c) Hercules Dev Team, licensed under GNU GPL. +// See the LICENSE file +// Portions Copyright (c) Athena Dev Teams -#ifndef _PATH_H_ -#define _PATH_H_ +#ifndef MAP_PATH_H +#define MAP_PATH_H #include "map.h" // enum cell_chk +#include "../common/cbasetypes.h" + +#define MOVE_COST 10 +#define MOVE_DIAGONAL_COST 14 #define MAX_WALKPATH 32 @@ -19,25 +24,27 @@ struct shootpath_data { int y[MAX_WALKPATH]; }; -// calculates destination cell for knockback -int path_blownpos(int16 m,int16 x0,int16 y0,int16 dx,int16 dy,int count); - -// tries to find a walkable path -bool path_search(struct walkpath_data *wpd,int16 m,int16 x0,int16 y0,int16 x1,int16 y1,int flag,cell_chk cell); - -// tries to find a shootable path -bool path_search_long(struct shootpath_data *spd,int16 m,int16 x0,int16 y0,int16 x1,int16 y1,cell_chk cell); - +#define check_distance_bl(bl1, bl2, distance) (path->check_distance((bl1)->x - (bl2)->x, (bl1)->y - (bl2)->y, distance)) +#define check_distance_blxy(bl, x1, y1, distance) (path->check_distance((bl)->x - (x1), (bl)->y - (y1), distance)) +#define check_distance_xy(x0, y0, x1, y1, distance) (path->check_distance((x0) - (x1), (y0) - (y1), distance)) + +#define distance_bl(bl1, bl2) (path->distance((bl1)->x - (bl2)->x, (bl1)->y - (bl2)->y)) +#define distance_blxy(bl, x1, y1) (path->distance((bl)->x - (x1), (bl)->y - (y1))) +#define distance_xy(x0, y0, x1, y1) (path->distance((x0) - (x1), (y0) - (y1))) + +struct path_interface { + // calculates destination cell for knockback + int (*blownpos) (int16 m, int16 x0, int16 y0, int16 dx, int16 dy, int count); + // tries to find a walkable path + bool (*search) (struct walkpath_data *wpd, int16 m, int16 x0, int16 y0, int16 x1, int16 y1, int flag, cell_chk cell); + // tries to find a shootable path + bool (*search_long) (struct shootpath_data *spd, int16 m, int16 x0, int16 y0, int16 x1, int16 y1, cell_chk cell); + int (*check_distance) (int dx, int dy, int distance); + unsigned int (*distance) (int dx, int dy); +}; -// distance related functions -int check_distance(int dx, int dy, int distance); -#define check_distance_bl(bl1, bl2, distance) check_distance((bl1)->x - (bl2)->x, (bl1)->y - (bl2)->y, distance) -#define check_distance_blxy(bl, x1, y1, distance) check_distance((bl)->x-(x1), (bl)->y-(y1), distance) -#define check_distance_xy(x0, y0, x1, y1, distance) check_distance((x0)-(x1), (y0)-(y1), distance) +struct path_interface *path; -unsigned int distance(int dx, int dy); -#define distance_bl(bl1, bl2) distance((bl1)->x - (bl2)->x, (bl1)->y - (bl2)->y) -#define distance_blxy(bl, x1, y1) distance((bl)->x-(x1), (bl)->y-(y1)) -#define distance_xy(x0, y0, x1, y1) distance((x0)-(x1), (y0)-(y1)) +void path_defaults(void); -#endif /* _PATH_H_ */ +#endif /* MAP_PATH_H */ diff --git a/src/map/pc.c b/src/map/pc.c index b7644f2fb..a6619fad2 100644 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -2,90 +2,60 @@ // See the LICENSE file // Portions Copyright (c) Athena Dev Teams -#include "../common/cbasetypes.h" -#include "../common/core.h" // get_svn_revision() -#include "../common/malloc.h" -#include "../common/nullpo.h" -#include "../common/random.h" -#include "../common/showmsg.h" -#include "../common/socket.h" // session[] -#include "../common/strlib.h" // safestrncpy() -#include "../common/timer.h" -#include "../common/utils.h" -#include "../common/mmo.h" //NAME_LENGTH +#define HERCULES_CORE + +#include "../config/core.h" // DBPATH, GP_BOUND_ITEMS, MAX_SPIRITBALL, RENEWAL, RENEWAL_ASPD, RENEWAL_CAST, RENEWAL_DROP, RENEWAL_EXP, SECURE_NPCTIMEOUT +#include "pc.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> #include "atcommand.h" // get_atcommand_level() #include "battle.h" // battle_config #include "battleground.h" +#include "chat.h" #include "chrif.h" #include "clif.h" #include "date.h" // is_day_of_*() #include "duel.h" +#include "elemental.h" +#include "guild.h" // guild->search(), guild_request_info() +#include "homunculus.h" +#include "instance.h" #include "intif.h" #include "itemdb.h" #include "log.h" #include "mail.h" #include "map.h" -#include "path.h" -#include "homunculus.h" -#include "instance.h" #include "mercenary.h" -#include "elemental.h" +#include "mob.h" // struct mob_data #include "npc.h" // fake_nd -#include "pet.h" // pet_unlocktarget() #include "party.h" // party->search() -#include "guild.h" // guild->search(), guild_request_info() +#include "path.h" +#include "pc_groups.h" +#include "pet.h" // pet_unlocktarget() +#include "quest.h" #include "script.h" // script_config #include "skill.h" #include "status.h" // struct status_data -#include "pc.h" -#include "pc_groups.h" -#include "quest.h" - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <time.h> - - -#define PVP_CALCRANK_INTERVAL 1000 // PVP calculation interval -static unsigned int exp_table[CLASS_COUNT][2][MAX_LEVEL]; -static unsigned int max_level[CLASS_COUNT][2]; -static unsigned int statp[MAX_LEVEL+1]; -#if defined(RENEWAL_DROP) || defined(RENEWAL_EXP) -static unsigned int level_penalty[3][RC_MAX][MAX_LEVEL*2+1]; -#endif - -// h-files are for declarations, not for implementations... [Shinomori] -struct skill_tree_entry skill_tree[CLASS_COUNT][MAX_SKILL_TREE]; -// timer for night.day implementation -int day_timer_tid; -int night_timer_tid; - -struct fame_list smith_fame_list[MAX_FAME_LIST]; -struct fame_list chemist_fame_list[MAX_FAME_LIST]; -struct fame_list taekwon_fame_list[MAX_FAME_LIST]; - -static unsigned short equip_pos[EQI_MAX]={EQP_ACC_L,EQP_ACC_R,EQP_SHOES,EQP_GARMENT,EQP_HEAD_LOW,EQP_HEAD_MID,EQP_HEAD_TOP,EQP_ARMOR,EQP_HAND_L,EQP_HAND_R,EQP_COSTUME_HEAD_TOP,EQP_COSTUME_HEAD_MID,EQP_COSTUME_HEAD_LOW,EQP_COSTUME_GARMENT,EQP_AMMO}; - -//Links related info to the sd->hate_mob[]/sd->feel_map[] entries -const struct sg_data sg_info[MAX_PC_FEELHATE] = { - { SG_SUN_ANGER, SG_SUN_BLESS, SG_SUN_COMFORT, "PC_FEEL_SUN", "PC_HATE_MOB_SUN", is_day_of_sun }, - { SG_MOON_ANGER, SG_MOON_BLESS, SG_MOON_COMFORT, "PC_FEEL_MOON", "PC_HATE_MOB_MOON", is_day_of_moon }, - { SG_STAR_ANGER, SG_STAR_BLESS, SG_STAR_COMFORT, "PC_FEEL_STAR", "PC_HATE_MOB_STAR", is_day_of_star } - }; +#include "storage.h" +#include "../common/cbasetypes.h" +#include "../common/conf.h" +#include "../common/core.h" // get_svn_revision() +#include "../common/malloc.h" +#include "../common/mmo.h" // NAME_LENGTH, MAX_CARTS, NEW_CARTS +#include "../common/nullpo.h" +#include "../common/random.h" +#include "../common/showmsg.h" +#include "../common/socket.h" // session[] +#include "../common/strlib.h" // safestrncpy() +#include "../common/sysinfo.h" +#include "../common/timer.h" +#include "../common/utils.h" -/** - * Item Cool Down Delay Saving - * Struct item_cd is not a member of struct map_session_data - * to keep cooldowns in memory between player log-ins. - * All cooldowns are reset when server is restarted. - **/ -DBMap* itemcd_db = NULL; // char_id -> struct skill_cd -struct item_cd { - unsigned int tick[MAX_ITEMDELAYS];//tick - short nameid[MAX_ITEMDELAYS];//skill id -}; +struct pc_interface pc_s; //Converts a class to its array index for CLASS_COUNT defined arrays. //Note that it does not do a validity check for speed purposes, where parsing @@ -96,15 +66,48 @@ int pc_class2idx(int class_) { return class_; } -int pc_get_group_level(struct map_session_data *sd) { - return sd->group_level; +/** + * Creates a new dummy map session data. + * Used when there is no real player attached, but it is + * required to provide a session. + * Caller must release dummy on its own when it's no longer needed. + */ +struct map_session_data* pc_get_dummy_sd(void) +{ + struct map_session_data *dummy_sd; + CREATE(dummy_sd, struct map_session_data, 1); + dummy_sd->group = pcg->get_dummy_group(); // map_session_data.group is expected to be non-NULL at all times + return dummy_sd; } -static int pc_invincible_timer(int tid, unsigned int tick, int id, intptr_t data) +/** + * Sets player's group. + * Caller should handle error (preferably display message and disconnect). + * @param group_id Group ID + * @return 1 on error, 0 on success + */ +int pc_set_group(struct map_session_data *sd, int group_id) { + GroupSettings *group = pcg->id2group(group_id); + if (group == NULL) + return 1; + sd->group_id = group_id; + sd->group = group; + return 0; +} + +/** + * Checks if commands used by player should be logged. + */ +bool pc_should_log_commands(struct map_session_data *sd) +{ + return pcg->should_log_commands(sd->group); +} + +int pc_invincible_timer(int tid, int64 tick, int id, intptr_t data) { struct map_session_data *sd; - if( (sd=(struct map_session_data *)iMap->id2sd(id)) == NULL || sd->bl.type!=BL_PC ) + if( (sd=(struct map_session_data *)map->id2sd(id)) == NULL || sd->bl.type!=BL_PC ) return 1; if(sd->invincible_timer != tid){ @@ -120,11 +123,11 @@ static int pc_invincible_timer(int tid, unsigned int tick, int id, intptr_t data void pc_setinvincibletimer(struct map_session_data* sd, int val) { nullpo_retv(sd); - val += map[sd->bl.m].invincible_time_inc; + val += map->list[sd->bl.m].invincible_time_inc; if( sd->invincible_timer != INVALID_TIMER ) - iTimer->delete_timer(sd->invincible_timer,pc_invincible_timer); - sd->invincible_timer = iTimer->add_timer(iTimer->gettick()+val,pc_invincible_timer,sd->bl.id,0); + timer->delete(sd->invincible_timer,pc->invincible_timer); + sd->invincible_timer = timer->add(timer->gettick()+val,pc->invincible_timer,sd->bl.id,0); } void pc_delinvincibletimer(struct map_session_data* sd) @@ -133,18 +136,17 @@ void pc_delinvincibletimer(struct map_session_data* sd) if( sd->invincible_timer != INVALID_TIMER ) { - iTimer->delete_timer(sd->invincible_timer,pc_invincible_timer); + timer->delete(sd->invincible_timer,pc->invincible_timer); sd->invincible_timer = INVALID_TIMER; - skill->unit_move(&sd->bl,iTimer->gettick(),1); + skill->unit_move(&sd->bl,timer->gettick(),1); } } -static int pc_spiritball_timer(int tid, unsigned int tick, int id, intptr_t data) -{ +int pc_spiritball_timer(int tid, int64 tick, int id, intptr_t data) { struct map_session_data *sd; int i; - if( (sd=(struct map_session_data *)iMap->id2sd(id)) == NULL || sd->bl.type!=BL_PC ) + if( (sd=(struct map_session_data *)map->id2sd(id)) == NULL || sd->bl.type!=BL_PC ) return 1; if( sd->spiritball <= 0 ) @@ -184,21 +186,21 @@ int pc_addspiritball(struct map_session_data *sd,int interval,int max) if( sd->spiritball && sd->spiritball >= max ) { if(sd->spirit_timer[0] != INVALID_TIMER) - iTimer->delete_timer(sd->spirit_timer[0],pc_spiritball_timer); + timer->delete(sd->spirit_timer[0],pc->spiritball_timer); sd->spiritball--; if( sd->spiritball != 0 ) memmove(sd->spirit_timer+0, sd->spirit_timer+1, (sd->spiritball)*sizeof(int)); sd->spirit_timer[sd->spiritball] = INVALID_TIMER; } - tid = iTimer->add_timer(iTimer->gettick()+interval, pc_spiritball_timer, sd->bl.id, 0); - ARR_FIND(0, sd->spiritball, i, sd->spirit_timer[i] == INVALID_TIMER || DIFF_TICK(iTimer->get_timer(tid)->tick, iTimer->get_timer(sd->spirit_timer[i])->tick) < 0); + tid = timer->add(timer->gettick()+interval, pc->spiritball_timer, sd->bl.id, 0); + ARR_FIND(0, sd->spiritball, i, sd->spirit_timer[i] == INVALID_TIMER || DIFF_TICK(timer->get(tid)->tick, timer->get(sd->spirit_timer[i])->tick) < 0); if( i != sd->spiritball ) memmove(sd->spirit_timer+i+1, sd->spirit_timer+i, (sd->spiritball-i)*sizeof(int)); sd->spirit_timer[i] = tid; sd->spiritball++; if( (sd->class_&MAPID_THIRDMASK) == MAPID_ROYAL_GUARD ) - clif->millenniumshield(sd,sd->spiritball); + clif->millenniumshield(&sd->bl,sd->spiritball); else clif->spiritball(&sd->bl); @@ -226,7 +228,7 @@ int pc_delspiritball(struct map_session_data *sd,int count,int type) for(i=0;i<count;i++) { if(sd->spirit_timer[i] != INVALID_TIMER) { - iTimer->delete_timer(sd->spirit_timer[i],pc_spiritball_timer); + timer->delete(sd->spirit_timer[i],pc->spiritball_timer); sd->spirit_timer[i] = INVALID_TIMER; } } @@ -237,13 +239,13 @@ int pc_delspiritball(struct map_session_data *sd,int count,int type) if(!type) { if( (sd->class_&MAPID_THIRDMASK) == MAPID_ROYAL_GUARD ) - clif->millenniumshield(sd,sd->spiritball); + clif->millenniumshield(&sd->bl,sd->spiritball); else clif->spiritball(&sd->bl); } return 0; } -static int pc_check_banding( struct block_list *bl, va_list ap ) { +int pc_check_banding( struct block_list *bl, va_list ap ) { int *c, *b_sd; struct block_list *src; struct map_session_data *tsd; @@ -258,7 +260,7 @@ static int pc_check_banding( struct block_list *bl, va_list ap ) { if(pc_isdead(tsd)) return 0; - sc = status_get_sc(bl); + sc = status->get_sc(bl); if( bl == src ) return 0; @@ -283,14 +285,14 @@ int pc_banding(struct map_session_data *sd, uint16 skill_lv) { c = 0; memset(b_sd, 0, sizeof(b_sd)); - i = party_foreachsamemap(pc_check_banding,sd,range,&sd->bl,&c,&b_sd); + i = party->foreachsamemap(pc->check_banding,sd,range,&sd->bl,&c,&b_sd); - if( c < 1 ) //just recalc status no need to recalc hp - { // No more Royal Guards in Banding found. - if( (sc = status_get_sc(&sd->bl)) != NULL && sc->data[SC_BANDING] ) - { + if( c < 1 ) { + //just recalc status no need to recalc hp + if( (sc = status->get_sc(&sd->bl)) != NULL && sc->data[SC_BANDING] ) { + // No more Royal Guards in Banding found. sc->data[SC_BANDING]->val2 = 0; // Reset the counter - status_calc_bl(&sd->bl, status_sc2scb_flag(SC_BANDING)); + status_calc_bl(&sd->bl, status->sc2scb_flag(SC_BANDING)); } return 0; } @@ -300,9 +302,8 @@ int pc_banding(struct map_session_data *sd, uint16 skill_lv) { i++; // Get total HP of all Royal Guards in party. - for( j = 0; j < i; j++ ) - { - bsd = iMap->id2sd(b_sd[j]); + for( j = 0; j < i; j++ ) { + bsd = map->id2sd(b_sd[j]); if( bsd != NULL ) hp += status_get_hp(&bsd->bl); } @@ -311,9 +312,8 @@ int pc_banding(struct map_session_data *sd, uint16 skill_lv) { hp = hp / i; // If a Royal Guard have full HP, give more HP to others that haven't full HP. - for( j = 0; j < i; j++ ) - { - bsd = iMap->id2sd(b_sd[j]); + for( j = 0; j < i; j++ ) { + bsd = map->id2sd(b_sd[j]); if( bsd != NULL && (tmp_hp = hp - status_get_max_hp(&bsd->bl)) > 0 ) { extra_hp += tmp_hp; @@ -324,16 +324,13 @@ int pc_banding(struct map_session_data *sd, uint16 skill_lv) { if( extra_hp > 0 && tmp_qty > 0 ) hp += extra_hp / tmp_qty; - for( j = 0; j < i; j++ ) - { - bsd = iMap->id2sd(b_sd[j]); - if( bsd != NULL ) - { - status_set_hp(&bsd->bl,hp,0); // Set hp - if( (sc = status_get_sc(&bsd->bl)) != NULL && sc->data[SC_BANDING] ) - { + for( j = 0; j < i; j++ ) { + bsd = map->id2sd(b_sd[j]); + if( bsd != NULL ) { + status->set_hp(&bsd->bl,hp,0); // Set hp + if( (sc = status->get_sc(&bsd->bl)) != NULL && sc->data[SC_BANDING] ) { sc->data[SC_BANDING]->val2 = c; // Set the counter. It doesn't count your self. - status_calc_bl(&bsd->bl, status_sc2scb_flag(SC_BANDING)); // Set atk and def. + status_calc_bl(&bsd->bl, status->sc2scb_flag(SC_BANDING)); // Set atk and def. } } } @@ -344,22 +341,18 @@ int pc_banding(struct map_session_data *sd, uint16 skill_lv) { // Increases a player's fame points and displays a notice to him void pc_addfame(struct map_session_data *sd,int count) { + int ranktype = -1; nullpo_retv(sd); sd->status.fame += count; if(sd->status.fame > MAX_FAME) sd->status.fame = MAX_FAME; switch(sd->class_&MAPID_UPPERMASK){ - case MAPID_BLACKSMITH: // Blacksmith - clif->fame_blacksmith(sd,count); - break; - case MAPID_ALCHEMIST: // Alchemist - clif->fame_alchemist(sd,count); - break; - case MAPID_TAEKWON: // Taekwon - clif->fame_taekwon(sd,count); - break; + case MAPID_BLACKSMITH: ranktype = RANKTYPE_BLACKSMITH; break; + case MAPID_ALCHEMIST: ranktype = RANKTYPE_ALCHEMIST; break; + case MAPID_TAEKWON: ranktype = RANKTYPE_TAEKWON; break; } - chrif_updatefamelist(sd); + clif->update_rankingpoint(sd, ranktype, count); + chrif->updatefamelist(sd); } // Check whether a player ID is in the fame rankers' list of its job, returns his/her position if so, 0 else @@ -370,19 +363,19 @@ unsigned char pc_famerank(int char_id, int job) switch(job){ case MAPID_BLACKSMITH: // Blacksmith for(i = 0; i < MAX_FAME_LIST; i++){ - if(smith_fame_list[i].id == char_id) + if(pc->smith_fame_list[i].id == char_id) return i + 1; } break; case MAPID_ALCHEMIST: // Alchemist for(i = 0; i < MAX_FAME_LIST; i++){ - if(chemist_fame_list[i].id == char_id) + if(pc->chemist_fame_list[i].id == char_id) return i + 1; } break; case MAPID_TAEKWON: // Taekwon for(i = 0; i < MAX_FAME_LIST; i++){ - if(taekwon_fame_list[i].id == char_id) + if(pc->taekwon_fame_list[i].id == char_id) return i + 1; } break; @@ -392,20 +385,20 @@ unsigned char pc_famerank(int char_id, int job) } int pc_setrestartvalue(struct map_session_data *sd,int type) { - struct status_data *status, *b_status; + struct status_data *st, *bst; nullpo_ret(sd); - b_status = &sd->base_status; - status = &sd->battle_status; + bst = &sd->base_status; + st = &sd->battle_status; if (type&1) { //Normal resurrection - status->hp = 1; //Otherwise status_heal may fail if dead. - status_heal(&sd->bl, b_status->hp, 0, 1); - if( status->sp < b_status->sp ) - status_set_sp(&sd->bl, b_status->sp, 1); + st->hp = 1; //Otherwise status->heal may fail if dead. + status->heal(&sd->bl, bst->hp, 0, 1); + if( st->sp < bst->sp ) + status->set_sp(&sd->bl, bst->sp, 1); } else { //Just for saving on the char-server (with values as if respawned) - sd->status.hp = b_status->hp; - sd->status.sp = (status->sp < b_status->sp)?b_status->sp:status->sp; + sd->status.hp = bst->hp; + sd->status.sp = (st->sp < bst->sp) ? bst->sp : st->sp; } return 0; } @@ -413,9 +406,8 @@ int pc_setrestartvalue(struct map_session_data *sd,int type) { /*========================================== Rental System *------------------------------------------*/ -static int pc_inventory_rental_end(int tid, unsigned int tick, int id, intptr_t data) -{ - struct map_session_data *sd = iMap->id2sd(id); +int pc_inventory_rental_end(int tid, int64 tick, int id, intptr_t data) { + struct map_session_data *sd = map->id2sd(id); if( sd == NULL ) return 0; if( tid != sd->rental_timer ) @@ -432,17 +424,84 @@ int pc_inventory_rental_clear(struct map_session_data *sd) { if( sd->rental_timer != INVALID_TIMER ) { - iTimer->delete_timer(sd->rental_timer, pc_inventory_rental_end); + timer->delete(sd->rental_timer, pc->inventory_rental_end); sd->rental_timer = INVALID_TIMER; } return 1; } +/* 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; + /* Soon to be dropped, we got plans to integrate it with item db */ + switch( nameid ) { + case ITEMID_REINS_OF_MOUNT: + status_change_end(&sd->bl,SC_ALL_RIDING,INVALID_TIMER); + break; + case ITEMID_LOVE_ANGEL: + if( sd->status.font == 1 ) { + sd->status.font = 0; + clif->font(sd); + } + break; + case ITEMID_SQUIRREL: + if( sd->status.font == 2 ) { + sd->status.font = 0; + clif->font(sd); + } + break; + case ITEMID_GOGO: + if( sd->status.font == 3 ) { + sd->status.font = 0; + clif->font(sd); + } + break; + case ITEMID_PICTURE_DIARY: + if( sd->status.font == 4 ) { + sd->status.font = 0; + clif->font(sd); + } + break; + case ITEMID_MINI_HEART: + if( sd->status.font == 5 ) { + sd->status.font = 0; + clif->font(sd); + } + break; + case ITEMID_NEWCOMER: + if( sd->status.font == 6 ) { + sd->status.font = 0; + clif->font(sd); + } + break; + case ITEMID_KID: + if( sd->status.font == 7 ) { + sd->status.font = 0; + clif->font(sd); + } + break; + case ITEMID_MAGIC_CASTLE: + if( sd->status.font == 8 ) { + sd->status.font = 0; + clif->font(sd); + } + break; + case ITEMID_BULGING_HEAD: + if( sd->status.font == 9 ) { + sd->status.font = 0; + clif->font(sd); + } + break; + } + + clif->rental_expired(sd->fd, i, sd->status.inventory[i].nameid); + pc->delitem(sd, i, sd->status.inventory[i].amount, 0, 0, LOG_TYPE_OTHER); +} void pc_inventory_rentals(struct map_session_data *sd) { int i, c = 0; - unsigned int expire_tick, next_tick = UINT_MAX; + int64 expire_tick, next_tick = INT64_MAX; for( i = 0; i < MAX_INVENTORY; i++ ) { // Check for Rentals on Inventory @@ -452,14 +511,9 @@ void pc_inventory_rentals(struct map_session_data *sd) continue; if( sd->status.inventory[i].expire_time <= time(NULL) ) { - if( sd->status.inventory[i].nameid == ITEMID_REINS_OF_MOUNT - && sd->sc.data[SC_ALL_RIDING] ) { - status_change_end(&sd->bl,SC_ALL_RIDING,INVALID_TIMER); - } - clif->rental_expired(sd->fd, i, sd->status.inventory[i].nameid); - pc->delitem(sd, i, sd->status.inventory[i].amount, 0, 0, LOG_TYPE_OTHER); + pc->rental_expire(sd,i); } else { - expire_tick = (unsigned int)(sd->status.inventory[i].expire_time - time(NULL)) * 1000; + expire_tick = (int64)(sd->status.inventory[i].expire_time - time(NULL)) * 1000; clif->rental_time(sd->fd, sd->status.inventory[i].nameid, (int)(expire_tick / 1000)); next_tick = min(expire_tick, next_tick); c++; @@ -467,7 +521,7 @@ void pc_inventory_rentals(struct map_session_data *sd) } if( c > 0 ) // min(next_tick,3600000) 1 hour each timer to keep announcing to the owner, and to avoid a but with rental time > 15 days - sd->rental_timer = iTimer->add_timer(iTimer->gettick() + min(next_tick,3600000), pc_inventory_rental_end, sd->bl.id, 0); + sd->rental_timer = timer->add(timer->gettick() + min(next_tick,3600000), pc->inventory_rental_end, sd->bl.id, 0); else sd->rental_timer = INVALID_TIMER; } @@ -482,23 +536,15 @@ void pc_inventory_rental_add(struct map_session_data *sd, int seconds) if( sd->rental_timer != INVALID_TIMER ) { const struct TimerData * td; - td = iTimer->get_timer(sd->rental_timer); - if( DIFF_TICK(td->tick, iTimer->gettick()) > tick ) + td = timer->get(sd->rental_timer); + if( DIFF_TICK(td->tick, timer->gettick()) > tick ) { // Update Timer as this one ends first than the current one pc->inventory_rental_clear(sd); - sd->rental_timer = iTimer->add_timer(iTimer->gettick() + tick, pc_inventory_rental_end, sd->bl.id, 0); + sd->rental_timer = timer->add(timer->gettick() + tick, pc->inventory_rental_end, sd->bl.id, 0); } } else - sd->rental_timer = iTimer->add_timer(iTimer->gettick() + min(tick,3600000), pc_inventory_rental_end, sd->bl.id, 0); -} - -/** - * Determines if player can give / drop / trade / vend items - */ -bool pc_can_give_items(struct map_session_data *sd) -{ - return pc_has_permission(sd, PC_PERM_TRADE); + sd->rental_timer = timer->add(timer->gettick() + min(tick,3600000), pc->inventory_rental_end, sd->bl.id, 0); } /*========================================== @@ -542,8 +588,8 @@ int pc_makesavestatus(struct map_session_data *sd) sd->status.last_point.y = sd->bl.y; } - if(map[sd->bl.m].flag.nosave || map[sd->bl.m].instance_id >= 0){ - struct map_data *m=&map[sd->bl.m]; + if(map->list[sd->bl.m].flag.nosave || map->list[sd->bl.m].instance_id >= 0) { + struct map_data *m=&map->list[sd->bl.m]; if(m->save.map) memcpy(&sd->status.last_point,&m->save,sizeof(sd->status.last_point)); else @@ -581,7 +627,7 @@ int pc_setnewpc(struct map_session_data *sd, int account_id, int char_id, int lo sd->client_tick = client_tick; sd->state.active = 0; //to be set to 1 after player is fully authed and loaded. sd->bl.type = BL_PC; - sd->canlog_tick = iTimer->gettick(); + sd->canlog_tick = timer->gettick(); //Required to prevent homunculus copuing a base speed of 0. sd->battle_status.speed = sd->base_status.speed = DEFAULT_WALK_SPEED; return 0; @@ -596,16 +642,21 @@ int pc_equippoint(struct map_session_data *sd,int n) if(!sd->inventory_data[n]) return 0; - if (!itemdb_isequip2(sd->inventory_data[n])) + if (!itemdb->isequip2(sd->inventory_data[n])) return 0; //Not equippable by players. ep = sd->inventory_data[n]->equip; if(sd->inventory_data[n]->look == W_DAGGER || sd->inventory_data[n]->look == W_1HSWORD || sd->inventory_data[n]->look == W_1HAXE) { - if(ep == EQP_HAND_R && (pc->checkskill(sd,AS_LEFT) > 0 || (sd->class_&MAPID_UPPERMASK) == MAPID_ASSASSIN || - (sd->class_&MAPID_UPPERMASK) == MAPID_KAGEROUOBORO))//Kagerou and Oboro can dual wield daggers. [Rytech] - return EQP_ARMS; + if( (pc->checkskill(sd,AS_LEFT) > 0 || + (sd->class_&MAPID_UPPERMASK) == MAPID_ASSASSIN || + (sd->class_&MAPID_UPPERMASK) == MAPID_KAGEROUOBORO) ) { //Kagerou and Oboro can dual wield daggers. [Rytech] + if( ep == EQP_HAND_R ) + return EQP_ARMS; + if( ep == EQP_SHADOW_WEAPON ) + return EQP_SHADOW_ARMS; + } } return ep; } @@ -618,7 +669,7 @@ int pc_setinventorydata(struct map_session_data *sd) for(i=0;i<MAX_INVENTORY;i++) { id = sd->status.inventory[i].nameid; - sd->inventory_data[i] = id?itemdb_search(id):NULL; + sd->inventory_data[i] = id?itemdb->search(id):NULL; } return 0; } @@ -639,26 +690,26 @@ int pc_calcweapontype(struct map_session_data *sd) // dual-wield sd->status.weapon = 0; switch (sd->weapontype1){ - case W_DAGGER: - switch (sd->weapontype2) { - case W_DAGGER: sd->status.weapon = W_DOUBLE_DD; break; - case W_1HSWORD: sd->status.weapon = W_DOUBLE_DS; break; - case W_1HAXE: sd->status.weapon = W_DOUBLE_DA; break; - } - break; - case W_1HSWORD: - switch (sd->weapontype2) { - case W_DAGGER: sd->status.weapon = W_DOUBLE_DS; break; - case W_1HSWORD: sd->status.weapon = W_DOUBLE_SS; break; - case W_1HAXE: sd->status.weapon = W_DOUBLE_SA; break; - } - break; - case W_1HAXE: - switch (sd->weapontype2) { - case W_DAGGER: sd->status.weapon = W_DOUBLE_DA; break; - case W_1HSWORD: sd->status.weapon = W_DOUBLE_SA; break; - case W_1HAXE: sd->status.weapon = W_DOUBLE_AA; break; - } + case W_DAGGER: + switch (sd->weapontype2) { + case W_DAGGER: sd->status.weapon = W_DOUBLE_DD; break; + case W_1HSWORD: sd->status.weapon = W_DOUBLE_DS; break; + case W_1HAXE: sd->status.weapon = W_DOUBLE_DA; break; + } + break; + case W_1HSWORD: + switch (sd->weapontype2) { + case W_DAGGER: sd->status.weapon = W_DOUBLE_DS; break; + case W_1HSWORD: sd->status.weapon = W_DOUBLE_SS; break; + case W_1HAXE: sd->status.weapon = W_DOUBLE_SA; break; + } + break; + case W_1HAXE: + switch (sd->weapontype2) { + case W_DAGGER: sd->status.weapon = W_DOUBLE_DA; break; + case W_1HSWORD: sd->status.weapon = W_DOUBLE_SA; break; + case W_1HAXE: sd->status.weapon = W_DOUBLE_AA; break; + } } // unknown, default to right hand type if (!sd->status.weapon) @@ -681,7 +732,7 @@ int pc_setequipindex(struct map_session_data *sd) continue; if(sd->status.inventory[i].equip) { for(j=0;j<EQI_MAX;j++) - if(sd->status.inventory[i].equip & equip_pos[j]) + if(sd->status.inventory[i].equip & pc->equip_pos[j]) sd->equip_index[j] = i; if(sd->status.inventory[i].equip & EQP_HAND_R) @@ -701,7 +752,7 @@ int pc_setequipindex(struct map_session_data *sd) } } } - pc_calcweapontype(sd); + pc->calcweapontype(sd); return 0; } @@ -719,7 +770,7 @@ int pc_setequipindex(struct map_session_data *sd) // if( item->card[MAX_SLOTS - 1] && s < MAX_SLOTS - 1 ) // s = MAX_SLOTS - 1; // -// ARR_FIND( 0, s, i, item->card[i] && (data = itemdb_exists(item->card[i])) != NULL && data->flag.no_equip&flag ); +// ARR_FIND( 0, s, i, item->card[i] && (data = itemdb->exists(item->card[i])) != NULL && data->flag.no_equip&flag ); // return( i < s ) ? 0 : 1; //} @@ -857,12 +908,14 @@ int pc_isequip(struct map_session_data *sd,int n) if(item == NULL) return 0; - if(item->elv && sd->status.base_level < (unsigned int)item->elv) + if(item->elv && sd->status.base_level < (unsigned int)item->elv){ + clif->msg(sd, 0x6ED); return 0; -#ifdef RENEWAL - if(item->elvmax && sd->status.base_level > (unsigned int)item->elvmax) + } + if(item->elvmax && sd->status.base_level > (unsigned int)item->elvmax){ + clif->msg(sd, 0x6ED); return 0; -#endif + } if(item->sex != 2 && sd->status.sex != item->sex) return 0; @@ -902,10 +955,10 @@ int pc_isequip(struct map_session_data *sd,int n) return 0; //Not usable by upper class. [Inkfish] while( 1 ) { - if( item->class_upper&1 && !(sd->class_&(JOBL_UPPER|JOBL_THIRD|JOBL_BABY)) ) break; - if( item->class_upper&2 && sd->class_&(JOBL_UPPER|JOBL_THIRD) ) break; - if( item->class_upper&4 && sd->class_&JOBL_BABY ) break; - if( item->class_upper&8 && sd->class_&JOBL_THIRD ) break; + if( item->class_upper&ITEMUPPER_NORMAL && !(sd->class_&(JOBL_UPPER|JOBL_THIRD|JOBL_BABY)) ) break; + if( item->class_upper&ITEMUPPER_UPPER && sd->class_&(JOBL_UPPER|JOBL_THIRD) ) break; + if( item->class_upper&ITEMUPPER_BABY && sd->class_&JOBL_BABY ) break; + if( item->class_upper&ITEMUPPER_THIRD && sd->class_&JOBL_THIRD ) break; return 0; } @@ -918,14 +971,17 @@ int pc_isequip(struct map_session_data *sd,int n) *------------------------------------------*/ bool pc_authok(struct map_session_data *sd, int login_id2, time_t expiration_time, int group_id, struct mmo_charstatus *st, bool changing_mapservers) { int i; - unsigned long tick = iTimer->gettick(); + int64 tick = timer->gettick(); uint32 ip = session[sd->fd]->client_addr; sd->login_id2 = login_id2; - sd->group_id = group_id; - /* load user permissions */ - pc_group_pc_load(sd); + if (pc->set_group(sd, group_id) != 0) { + ShowWarning("pc_authok: %s (AID:%d) logged in with unknown group id (%d)! kicking...\n", + st->name, sd->status.account_id, group_id); + clif->authfail_fd(sd->fd, 0); + return false; + } memcpy(&sd->status, st, sizeof(*st)); @@ -965,6 +1021,7 @@ bool pc_authok(struct map_session_data *sd, int login_id2, time_t expiration_tim sd->npc_timer_id = INVALID_TIMER; sd->pvp_timer = INVALID_TIMER; sd->fontcolor_tid = INVALID_TIMER; + sd->expiration_tid = INVALID_TIMER; /** * For the Secure NPC Timeout option (check config/Secure.h) [RR] **/ @@ -985,6 +1042,8 @@ bool pc_authok(struct map_session_data *sd, int login_id2, time_t expiration_tim sd->cansendmail_tick = tick; sd->hchsysch_tick = tick; + sd->idletime = sockt->last_tick; + for(i = 0; i < MAX_SPIRITBALL; i++) sd->spirit_timer[i] = INVALID_TIMER; for(i = 0; i < ARRAYLENGTH(sd->autobonus); i++) @@ -1011,13 +1070,13 @@ bool pc_authok(struct map_session_data *sd, int login_id2, time_t expiration_tim if( sd->status.option & OPTION_INVISIBLE && !pc->can_use_command(sd, "@hide") ) sd->status.option &=~ OPTION_INVISIBLE; - status_change_init(&sd->bl); + status->change_init(&sd->bl); sd->sc.option = sd->status.option; //This is the actual option used in battle. //Set here because we need the inventory data for weapon sprite parsing. - status_set_viewdata(&sd->bl, sd->status.class_); - unit_dataset(&sd->bl); + status->set_viewdata(&sd->bl, sd->status.class_); + unit->dataset(&sd->bl); sd->guild_x = -1; sd->guild_y = -1; @@ -1037,6 +1096,11 @@ bool pc_authok(struct map_session_data *sd, int login_id2, time_t expiration_tim sd->state.dialog = 0; + sd->delayed_damage = 0; + + if( battle_config.item_check ) + sd->state.itemcheck = 1; + // Event Timers for( i = 0; i < MAX_EVENTTIMER; i++ ) sd->eventtimer[i] = INVALID_TIMER; @@ -1046,12 +1110,23 @@ bool pc_authok(struct map_session_data *sd, int login_id2, time_t expiration_tim for( i = 0; i < 3; i++ ) sd->hate_mob[i] = -1; - //warp player + sd->quest_log = NULL; + sd->num_quests = 0; + sd->avail_quests = 0; + sd->save_quest = false; + + sd->regs.vars = i64db_alloc(DB_OPT_BASE); + sd->regs.arrays = NULL; + sd->vars_dirty = false; + sd->vars_ok = false; + sd->vars_received = 0x0; + + //warp player if ((i=pc->setpos(sd,sd->status.last_point.map, sd->status.last_point.x, sd->status.last_point.y, CLR_OUTSIGHT)) != 0) { ShowError ("Last_point_map %s - id %d not found (error code %d)\n", mapindex_id2name(sd->status.last_point.map), sd->status.last_point.map, i); // try warping to a default map instead (church graveyard) - if (pc->setpos(sd, mapindex_name2id(MAP_PRONTERA), 273, 354, CLR_OUTSIGHT) != 0) { + if (pc->setpos(sd, mapindex->name2id(MAP_PRONTERA), 273, 354, CLR_OUTSIGHT) != 0) { // if we fail again clif->authfail_fd(sd->fd, 0); return false; @@ -1076,23 +1151,13 @@ bool pc_authok(struct map_session_data *sd, int login_id2, time_t expiration_tim if( !changing_mapservers ) { if (battle_config.display_version == 1) { - const char* svn = get_svn_revision(); - const char* git = get_git_hash(); char buf[256]; - if( git[0] != HERC_UNKNOWN_VER ) - sprintf(buf,"Git Hash: %s", git); - else if( svn[0] != HERC_UNKNOWN_VER ) - sprintf(buf,"SVN Revision: %s", svn); - else - sprintf(buf,"Unknown Version"); + sprintf(buf, msg_txt(1295), sysinfo->vcstype(), sysinfo->vcsrevision_src(), sysinfo->vcsrevision_scripts()); // %s revision '%s' (src) / '%s' (scripts) clif->message(sd->fd, buf); } - // message of the limited time of the account - if (expiration_time != 0) { // don't display if it's unlimited or unknow value - char tmpstr[1024]; - strftime(tmpstr, sizeof(tmpstr) - 1, msg_txt(501), localtime(&expiration_time)); // "Your account time limit is: %d-%m-%Y %H:%M:%S." - clif->wis_message(sd->fd, iMap->wisp_server_name, tmpstr, strlen(tmpstr)+1); + if (expiration_time != 0) { + sd->expiration_time = expiration_time; } /** @@ -1110,13 +1175,18 @@ bool pc_authok(struct map_session_data *sd, int login_id2, time_t expiration_tim * Check if player have any item cooldowns on **/ pc->itemcd_do(sd,true); - + +#ifdef GP_BOUND_ITEMS + if( sd->status.party_id == 0 ) + pc->bound_clear(sd,IBT_PARTY); +#endif + /* [Ind/Hercules] */ sd->sc_display = NULL; sd->sc_display_count = 0; // Request all registries (auth is considered completed whence they arrive) - intif_request_registry(sd,7); + intif->request_registry(sd,7); return true; } @@ -1141,7 +1211,7 @@ int pc_set_hate_mob(struct map_session_data *sd, int pos, struct block_list *bl) return 0; } - class_ = status_get_class(bl); + class_ = status->get_class(bl); if (!pcdb_checkid(class_)) { unsigned int max_hp = status_get_max_hp(bl); if ((pos == 1 && max_hp < 6000) || (pos == 2 && max_hp < 20000)) @@ -1150,7 +1220,7 @@ int pc_set_hate_mob(struct map_session_data *sd, int pos, struct block_list *bl) return 0; //Wrong size } sd->hate_mob[pos] = class_; - pc_setglobalreg(sd,sg_info[pos].hate_var,class_+1); + pc_setglobalreg(sd,script->add_str(pc->sg_info[pos].hate_var),class_+1); clif->hate_info(sd, pos, class_, 1); return 1; } @@ -1162,55 +1232,58 @@ int pc_reg_received(struct map_session_data *sd) { int i,j, idx = 0; - sd->change_level_2nd = pc_readglobalreg(sd,"jobchange_level"); - sd->change_level_3rd = pc_readglobalreg(sd,"jobchange_level_3rd"); - sd->die_counter = pc_readglobalreg(sd,"PC_DIE_COUNTER"); + sd->vars_ok = true; + + sd->change_level_2nd = pc_readglobalreg(sd,script->add_str("jobchange_level")); + sd->change_level_3rd = pc_readglobalreg(sd,script->add_str("jobchange_level_3rd")); + sd->die_counter = pc_readglobalreg(sd,script->add_str("PC_DIE_COUNTER")); // Cash shop - sd->cashPoints = pc_readaccountreg(sd,"#CASHPOINTS"); - sd->kafraPoints = pc_readaccountreg(sd,"#KAFRAPOINTS"); + sd->cashPoints = pc_readaccountreg(sd,script->add_str("#CASHPOINTS")); + sd->kafraPoints = pc_readaccountreg(sd,script->add_str("#KAFRAPOINTS")); // Cooking Exp - sd->cook_mastery = pc_readglobalreg(sd,"COOK_MASTERY"); + sd->cook_mastery = pc_readglobalreg(sd,script->add_str("COOK_MASTERY")); if( (sd->class_&MAPID_BASEMASK) == MAPID_TAEKWON ) { // Better check for class rather than skill to prevent "skill resets" from unsetting this - sd->mission_mobid = pc_readglobalreg(sd,"TK_MISSION_ID"); - sd->mission_count = pc_readglobalreg(sd,"TK_MISSION_COUNT"); + sd->mission_mobid = pc_readglobalreg(sd,script->add_str("TK_MISSION_ID")); + sd->mission_count = pc_readglobalreg(sd,script->add_str("TK_MISSION_COUNT")); } //SG map and mob read [Komurka] for(i=0;i<MAX_PC_FEELHATE;i++) { //for now - someone need to make reading from txt/sql - if ((j = pc_readglobalreg(sd,sg_info[i].feel_var))!=0) { + if ((j = pc_readglobalreg(sd,script->add_str(pc->sg_info[i].feel_var)))!=0) { sd->feel_map[i].index = j; - sd->feel_map[i].m = iMap->mapindex2mapid(j); + sd->feel_map[i].m = map->mapindex2mapid(j); } else { sd->feel_map[i].index = 0; sd->feel_map[i].m = -1; } - sd->hate_mob[i] = pc_readglobalreg(sd,sg_info[i].hate_var)-1; + sd->hate_mob[i] = pc_readglobalreg(sd,script->add_str(pc->sg_info[i].hate_var))-1; } if ((i = pc->checkskill(sd,RG_PLAGIARISM)) > 0) { - sd->cloneskill_id = pc_readglobalreg(sd,"CLONE_SKILL"); + sd->cloneskill_id = pc_readglobalreg(sd,script->add_str("CLONE_SKILL")); if (sd->cloneskill_id > 0 && (idx = skill->get_index(sd->cloneskill_id))) { sd->status.skill[idx].id = sd->cloneskill_id; - sd->status.skill[idx].lv = pc_readglobalreg(sd,"CLONE_SKILL_LV"); + sd->status.skill[idx].lv = pc_readglobalreg(sd,script->add_str("CLONE_SKILL_LV")); if (sd->status.skill[idx].lv > i) sd->status.skill[idx].lv = i; sd->status.skill[idx].flag = SKILL_FLAG_PLAGIARIZED; } } if ((i = pc->checkskill(sd,SC_REPRODUCE)) > 0) { - sd->reproduceskill_id = pc_readglobalreg(sd,"REPRODUCE_SKILL"); + sd->reproduceskill_id = pc_readglobalreg(sd,script->add_str("REPRODUCE_SKILL")); if( sd->reproduceskill_id > 0 && (idx = skill->get_index(sd->reproduceskill_id))) { sd->status.skill[idx].id = sd->reproduceskill_id; - sd->status.skill[idx].lv = pc_readglobalreg(sd,"REPRODUCE_SKILL_LV"); + sd->status.skill[idx].lv = pc_readglobalreg(sd,script->add_str("REPRODUCE_SKILL_LV")); if( i < sd->status.skill[idx].lv) sd->status.skill[idx].lv = i; sd->status.skill[idx].flag = SKILL_FLAG_PLAGIARIZED; } } + //Weird... maybe registries were reloaded? if (sd->state.active) return 0; @@ -1223,70 +1296,67 @@ int pc_reg_received(struct map_session_data *sd) // pet if (sd->status.pet_id > 0) - intif_request_petdata(sd->status.account_id, sd->status.char_id, sd->status.pet_id); + intif->request_petdata(sd->status.account_id, sd->status.char_id, sd->status.pet_id); // Homunculus [albator] if( sd->status.hom_id > 0 ) - intif_homunculus_requestload(sd->status.account_id, sd->status.hom_id); + intif->homunculus_requestload(sd->status.account_id, sd->status.hom_id); if( sd->status.mer_id > 0 ) - intif_mercenary_request(sd->status.mer_id, sd->status.char_id); + intif->mercenary_request(sd->status.mer_id, sd->status.char_id); if( sd->status.ele_id > 0 ) - intif_elemental_request(sd->status.ele_id, sd->status.char_id); + intif->elemental_request(sd->status.ele_id, sd->status.char_id); - iMap->addiddb(&sd->bl); - iMap->delnickdb(sd->status.char_id, sd->status.name); - if (!chrif_auth_finished(sd)) + map->addiddb(&sd->bl); + map->delnickdb(sd->status.char_id, sd->status.name); + if (!chrif->auth_finished(sd)) ShowError("pc_reg_received: Failed to properly remove player %d:%d from logging db!\n", sd->status.account_id, sd->status.char_id); pc->load_combo(sd); - status_calc_pc(sd,1); - chrif_scdata_request(sd->status.account_id, sd->status.char_id); + status_calc_pc(sd,SCO_FIRST|SCO_FORCE); + chrif->scdata_request(sd->status.account_id, sd->status.char_id); - intif_Mail_requestinbox(sd->status.char_id, 0); // MAIL SYSTEM - Request Mail Inbox - intif_request_questlog(sd); + intif->Mail_requestinbox(sd->status.char_id, 0); // MAIL SYSTEM - Request Mail Inbox + intif->request_questlog(sd); if (sd->state.connect_new == 0 && sd->fd) { //Character already loaded map! Gotta trigger LoadEndAck manually. sd->state.connect_new = 1; clif->pLoadEndAck(sd->fd, sd); } - pc->inventory_rentals(sd); - if( sd->sc.option & OPTION_INVISIBLE ) { sd->vd.class_ = INVISIBLE_CLASS; clif->message(sd->fd, msg_txt(11)); // Invisible: On // decrement the number of pvp players on the map - map[sd->bl.m].users_pvp--; + map->list[sd->bl.m].users_pvp--; - if( map[sd->bl.m].flag.pvp && !map[sd->bl.m].flag.pvp_nocalcrank && sd->pvp_timer != INVALID_TIMER ) {// unregister the player for ranking - iTimer->delete_timer( sd->pvp_timer, pc->calc_pvprank_timer ); + if( map->list[sd->bl.m].flag.pvp && !map->list[sd->bl.m].flag.pvp_nocalcrank && sd->pvp_timer != INVALID_TIMER ) {// unregister the player for ranking + timer->delete( sd->pvp_timer, pc->calc_pvprank_timer ); sd->pvp_timer = INVALID_TIMER; } clif->changeoption(&sd->bl); } if( npc->motd ) /* [Ind/Hercules] */ - run_script(npc->motd->u.scr.script, 0, sd->bl.id, fake_nd->bl.id); - + script->run(npc->motd->u.scr.script, 0, sd->bl.id, npc->fake_nd->bl.id); + return 1; } -static int pc_calc_skillpoint(struct map_session_data* sd) -{ +int pc_calc_skillpoint(struct map_session_data* sd) { int i,skill_lv,inf2,skill_point=0; nullpo_ret(sd); for(i=1;i<MAX_SKILL;i++){ if( (skill_lv = pc->checkskill2(sd,i)) > 0) { - inf2 = skill_db[i].inf2; + inf2 = skill->db[i].inf2; if((!(inf2&INF2_QUEST_SKILL) || battle_config.quest_skill_learn) && - !(inf2&(INF2_WEDDING_SKILL|INF2_SPIRIT_SKILL)) //Do not count wedding/link skills. [Skotlex] + !(inf2&(INF2_WEDDING_SKILL|INF2_SPIRIT_SKILL|INF2_GUILD_SKILL)) //Do not count wedding/link skills. [Skotlex] ) { if(sd->status.skill[i].flag == SKILL_FLAG_PERMANENT) skill_point += skill_lv; - else if(sd->status.skill[i].flag == SKILL_FLAG_REPLACED_LV_0) + else if(sd->status.skill[i].flag >= SKILL_FLAG_REPLACED_LV_0) skill_point += (sd->status.skill[i].flag - SKILL_FLAG_REPLACED_LV_0); } } @@ -1318,10 +1388,10 @@ int pc_calc_skilltree(struct map_session_data *sd) if( sd->status.skill[i].flag != SKILL_FLAG_PLAGIARIZED && sd->status.skill[i].flag != SKILL_FLAG_PERM_GRANTED ) //Don't touch these sd->status.skill[i].id = 0; //First clear skills. /* permanent skills that must be re-checked */ - if( sd->status.skill[i].flag == SKILL_FLAG_PERM_GRANTED ) { - switch( skill_db[i].nameid ) { + if( sd->status.skill[i].flag == SKILL_FLAG_PERMANENT ) { + switch( skill->db[i].nameid ) { case NV_TRICKDEAD: - if( (sd->class_&MAPID_UPPERMASK) != MAPID_NOVICE ) { + if( (sd->class_&(MAPID_BASEMASK|JOBL_2)) != MAPID_NOVICE ) { sd->status.skill[i].id = 0; sd->status.skill[i].lv = 0; sd->status.skill[i].flag = 0; @@ -1338,19 +1408,19 @@ int pc_calc_skilltree(struct map_session_data *sd) sd->status.skill[i].flag = SKILL_FLAG_PERMANENT; } - if( sd->sc.count && sd->sc.data[SC_SOULLINK] && sd->sc.data[SC_SOULLINK]->val2 == SL_BARDDANCER && skill_db[i].nameid >= DC_HUMMING && skill_db[i].nameid <= DC_SERVICEFORYOU ) + if( sd->sc.count && sd->sc.data[SC_SOULLINK] && sd->sc.data[SC_SOULLINK]->val2 == SL_BARDDANCER && skill->db[i].nameid >= DC_HUMMING && skill->db[i].nameid <= DC_SERVICEFORYOU ) { //Enable Bard/Dancer spirit linked skills. if( sd->status.sex ) { //Link dancer skills to bard. if( sd->status.skill[i-8].lv < 10 ) continue; - sd->status.skill[i].id = skill_db[i].nameid; + sd->status.skill[i].id = skill->db[i].nameid; sd->status.skill[i].lv = sd->status.skill[i-8].lv; // Set the level to the same as the linking skill sd->status.skill[i].flag = SKILL_FLAG_TEMPORARY; // Tag it as a non-savable, non-uppable, bonus skill } else { //Link bard skills to dancer. if( sd->status.skill[i].lv < 10 ) continue; - sd->status.skill[i-8].id = skill_db[i-8].nameid; + sd->status.skill[i-8].id = skill->db[i-8].nameid; sd->status.skill[i-8].lv = sd->status.skill[i].lv; // Set the level to the same as the linking skill sd->status.skill[i-8].flag = SKILL_FLAG_TEMPORARY; // Tag it as a non-savable, non-uppable, bonus skill } @@ -1359,7 +1429,7 @@ int pc_calc_skilltree(struct map_session_data *sd) if( pc_has_permission(sd, PC_PERM_ALL_SKILL) ) { for( i = 0; i < MAX_SKILL; i++ ) { - switch(skill_db[i].nameid) { + switch(skill->db[i].nameid) { /** * Dummy skills must be added here otherwise they'll be displayed in the, * skill tree and since they have no icons they'll give resource errors @@ -1378,23 +1448,22 @@ int pc_calc_skilltree(struct map_session_data *sd) case WL_SUMMON_ATK_GROUND: case LG_OVERBRAND_BRANDISH: case LG_OVERBRAND_PLUSATK: - case WM_SEVERE_RAINSTORM_MELEE: continue; default: break; } - if( skill_db[i].inf2&(INF2_NPC_SKILL|INF2_GUILD_SKILL) ) + if( skill->db[i].inf2&(INF2_NPC_SKILL|INF2_GUILD_SKILL) ) continue; //Only skills you can't have are npc/guild ones - if( skill_db[i].max > 0 ) - sd->status.skill[i].id = skill_db[i].nameid; + if( skill->db[i].max > 0 ) + sd->status.skill[i].id = skill->db[i].nameid; } return 0; } do { flag = 0; - for( i = 0; i < MAX_SKILL_TREE && (id = skill_tree[c][i].id) > 0; i++ ) { - int f, idx = skill_tree[c][i].idx; + for( i = 0; i < MAX_SKILL_TREE && (id = pc->skill_tree[c][i].id) > 0; i++ ) { + int f, idx = pc->skill_tree[c][i].idx; if( sd->status.skill[idx].id ) continue; //Skill already known. @@ -1403,26 +1472,26 @@ int pc_calc_skilltree(struct map_session_data *sd) int j; for(j = 0; j < MAX_PC_SKILL_REQUIRE; j++) { int k; - if((k=skill_tree[c][i].need[j].id)) { - int idx2 = skill_tree[c][i].need[j].idx; + if((k=pc->skill_tree[c][i].need[j].id)) { + int idx2 = pc->skill_tree[c][i].need[j].idx; if (sd->status.skill[idx2].id == 0 || sd->status.skill[idx2].flag == SKILL_FLAG_TEMPORARY || sd->status.skill[idx2].flag == SKILL_FLAG_PLAGIARIZED) k = 0; //Not learned. else if (sd->status.skill[idx2].flag >= SKILL_FLAG_REPLACED_LV_0) //Real lerned level k = sd->status.skill[idx2].flag - SKILL_FLAG_REPLACED_LV_0; else k = pc->checkskill2(sd,idx2); - if (k < skill_tree[c][i].need[j].lv) { + if (k < pc->skill_tree[c][i].need[j].lv) { f = 0; break; } } } - if( sd->status.job_level < skill_tree[c][i].joblv ) + if( sd->status.job_level < pc->skill_tree[c][i].joblv ) f = 0; // job level requirement wasn't satisfied } if( f ) { int inf2; - inf2 = skill_db[idx].inf2; + inf2 = skill->db[idx].inf2; if(!sd->status.skill[idx].lv && ( (inf2&INF2_QUEST_SKILL && !battle_config.quest_skill_learn) || @@ -1432,7 +1501,7 @@ int pc_calc_skilltree(struct map_session_data *sd) continue; //Cannot be learned via normal means. Note this check DOES allows raising already known skills. sd->status.skill[idx].id = id; - + if(inf2&INF2_SPIRIT_SKILL) { //Spirit skills cannot be learned, they will only show up on your tree when you get buffed. sd->status.skill[idx].lv = 1; // need to manually specify a skill level sd->status.skill[idx].flag = SKILL_FLAG_TEMPORARY; //So it is not saved, and tagged as a "bonus" skill. @@ -1451,9 +1520,9 @@ int pc_calc_skilltree(struct map_session_data *sd) - (c > 0) to avoid grant Novice Skill Tree in case of Skill Reset (need more logic) - (sd->status.skill_point == 0) to wait until all skill points are asigned to avoid problems with Job Change quest. */ - for( i = 0; i < MAX_SKILL_TREE && (id = skill_tree[c][i].id) > 0; i++ ) { - int idx = skill_tree[c][i].idx; - if( (skill_db[idx].inf2&(INF2_QUEST_SKILL|INF2_WEDDING_SKILL)) ) + for( i = 0; i < MAX_SKILL_TREE && (id = pc->skill_tree[c][i].id) > 0; i++ ) { + int idx = pc->skill_tree[c][i].idx; + if( (skill->db[idx].inf2&(INF2_QUEST_SKILL|INF2_WEDDING_SKILL)) ) continue; //Do not include Quest/Wedding skills. if( sd->status.skill[idx].id == 0 ) { @@ -1471,7 +1540,7 @@ int pc_calc_skilltree(struct map_session_data *sd) } //Checks if you can learn a new skill after having leveled up a skill. -static void pc_check_skilltree(struct map_session_data *sd, int skill_id) +void pc_check_skilltree(struct map_session_data *sd, int skill_id) { int i,id=0,flag; int c=0; @@ -1488,22 +1557,22 @@ static void pc_check_skilltree(struct map_session_data *sd, int skill_id) c = pc->class2idx(c); do { flag = 0; - for( i = 0; i < MAX_SKILL_TREE && (id=skill_tree[c][i].id)>0; i++ ) { - int j, f = 1, k, idx = skill_tree[c][i].idx; + for( i = 0; i < MAX_SKILL_TREE && (id=pc->skill_tree[c][i].id)>0; i++ ) { + int j, f = 1, k, idx = pc->skill_tree[c][i].idx; if( sd->status.skill[idx].id ) //Already learned continue; for( j = 0; j < MAX_PC_SKILL_REQUIRE; j++ ) { - if( (k = skill_tree[c][i].need[j].id) ) { - int idx2 = skill_tree[c][i].need[j].idx; + if( (k = pc->skill_tree[c][i].need[j].id) ) { + int idx2 = pc->skill_tree[c][i].need[j].idx; if( sd->status.skill[idx2].id == 0 || sd->status.skill[idx2].flag == SKILL_FLAG_TEMPORARY || sd->status.skill[idx2].flag == SKILL_FLAG_PLAGIARIZED ) k = 0; //Not learned. else if( sd->status.skill[idx2].flag >= SKILL_FLAG_REPLACED_LV_0) //Real lerned level k = sd->status.skill[idx2].flag - SKILL_FLAG_REPLACED_LV_0; else k = pc->checkskill2(sd,idx2); - if( k < skill_tree[c][i].need[j].lv ) { + if( k < pc->skill_tree[c][i].need[j].lv ) { f = 0; break; } @@ -1511,10 +1580,10 @@ static void pc_check_skilltree(struct map_session_data *sd, int skill_id) } if( !f ) continue; - if( sd->status.job_level < skill_tree[c][i].joblv ) + if( sd->status.job_level < pc->skill_tree[c][i].joblv ) continue; - j = skill_db[idx].inf2; + j = skill->db[idx].inf2; if( !sd->status.skill[idx].lv && ( (j&INF2_QUEST_SKILL && !battle_config.quest_skill_learn) || j&INF2_WEDDING_SKILL || @@ -1523,6 +1592,7 @@ static void pc_check_skilltree(struct map_session_data *sd, int skill_id) continue; //Cannot be learned via normal means. sd->status.skill[idx].id = id; + flag = 1; } } while(flag); @@ -1538,7 +1608,7 @@ int pc_clean_skilltree(struct map_session_data *sd) sd->status.skill[i].id = 0; sd->status.skill[i].lv = 0; sd->status.skill[i].flag = 0; - } else if (sd->status.skill[i].flag == SKILL_FLAG_REPLACED_LV_0) { + } else if (sd->status.skill[i].flag >= SKILL_FLAG_REPLACED_LV_0) { sd->status.skill[i].lv = sd->status.skill[i].flag - SKILL_FLAG_REPLACED_LV_0; sd->status.skill[i].flag = 0; } @@ -1555,13 +1625,14 @@ int pc_calc_skilltree_normalize_job(struct map_session_data *sd) if (!battle_config.skillup_limit || pc_has_permission(sd, PC_PERM_ALL_SKILL)) return c; - skill_point = pc_calc_skillpoint(sd); + skill_point = pc->calc_skillpoint(sd); - novice_skills = max_level[pc->class2idx(JOB_NOVICE)][1] - 1; + novice_skills = pc->max_level[pc->class2idx(JOB_NOVICE)][1] - 1; + sd->sktree.second = sd->sktree.third = 0; + // limit 1st class and above to novice job levels - if(skill_point < novice_skills) - { + if(skill_point < novice_skills) { c = MAPID_NOVICE; } // limit 2nd class and above to first class job levels (super novices are exempt) @@ -1574,7 +1645,7 @@ int pc_calc_skilltree_normalize_job(struct map_session_data *sd) { // if neither 2nd nor 3rd jobchange levels are known, we have to assume a default for 2nd if (!sd->change_level_3rd) - sd->change_level_2nd = max_level[pc->class2idx(pc->mapid2jobid(sd->class_&MAPID_UPPERMASK, sd->status.sex))][1]; + sd->change_level_2nd = pc->max_level[pc->class2idx(pc->mapid2jobid(sd->class_&MAPID_UPPERMASK, sd->status.sex))][1]; else sd->change_level_2nd = 1 + skill_point + sd->status.skill_point - (sd->status.job_level - 1) @@ -1589,11 +1660,12 @@ int pc_calc_skilltree_normalize_job(struct map_session_data *sd) } - pc_setglobalreg (sd, "jobchange_level", sd->change_level_2nd); + pc_setglobalreg (sd, script->add_str("jobchange_level"), sd->change_level_2nd); } if (skill_point < novice_skills + (sd->change_level_2nd - 1)) { c &= MAPID_BASEMASK; + sd->sktree.second = ( novice_skills + (sd->change_level_2nd - 1) ) - skill_point; } else if(sd->class_&JOBL_THIRD) { // limit 3rd class to 2nd class/trans job levels // regenerate change_level_3rd if (!sd->change_level_3rd) { @@ -1601,17 +1673,19 @@ int pc_calc_skilltree_normalize_job(struct map_session_data *sd) - (sd->status.job_level - 1) - (sd->change_level_2nd - 1) - novice_skills; - pc_setglobalreg (sd, "jobchange_level_3rd", sd->change_level_3rd); + pc_setglobalreg (sd, script->add_str("jobchange_level_3rd"), sd->change_level_3rd); } - if (skill_point < novice_skills + (sd->change_level_2nd - 1) + (sd->change_level_3rd - 1)) + if (skill_point < novice_skills + (sd->change_level_2nd - 1) + (sd->change_level_3rd - 1)) { c &= MAPID_UPPERMASK; + sd->sktree.third = (novice_skills + (sd->change_level_2nd - 1) + (sd->change_level_3rd - 1)) - skill_point; + } } } // restore non-limiting flags c |= sd->class_&(JOBL_UPPER|JOBL_BABY); - + return c; } @@ -1643,9 +1717,9 @@ int pc_updateweightstatus(struct map_session_data *sd) // start new status change if( new_overweight == 1 ) - sc_start(&sd->bl, SC_WEIGHTOVER50, 100, 0, 0); + sc_start(NULL,&sd->bl, SC_WEIGHTOVER50, 100, 0, 0); else if( new_overweight == 2 ) - sc_start(&sd->bl, SC_WEIGHTOVER90, 100, 0, 0); + sc_start(NULL,&sd->bl, SC_WEIGHTOVER90, 100, 0, 0); // update overweight status sd->regen.state.overweight = new_overweight; @@ -1679,8 +1753,15 @@ int pc_disguise(struct map_session_data *sd, int class_) { } else sd->disguise = class_; - status_set_viewdata(&sd->bl, class_); + status->set_viewdata(&sd->bl, class_); clif->changeoption(&sd->bl); + // We need to update the client so it knows that a costume is being used + if( sd->sc.option&OPTION_COSTUME ) { + clif->changelook(&sd->bl,LOOK_BASE,sd->vd.class_); + clif->changelook(&sd->bl,LOOK_WEAPON,0); + clif->changelook(&sd->bl,LOOK_SHIELD,0); + clif->changelook(&sd->bl,LOOK_CLOTHES_COLOR,sd->vd.cloth_color); + } if (sd->bl.prev != NULL) { clif->spawn(&sd->bl); @@ -1689,11 +1770,17 @@ 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; + + if( (cd = (struct chat_data*)map->id2bl(sd->chatID)) ) + clif->dispchat(cd,0); + } } return 1; } -static int pc_bonus_autospell(struct s_autospell *spell, int max, short id, short lv, short rate, short flag, short card_id) +int pc_bonus_autospell(struct s_autospell *spell, int max, short id, short lv, short rate, short flag, short card_id) { int i; @@ -1729,7 +1816,7 @@ static int pc_bonus_autospell(struct s_autospell *spell, int max, short id, shor return 1; } -static int pc_bonus_autospell_onskill(struct s_autospell *spell, int max, short src_skill, short id, short lv, short rate, short card_id) +int pc_bonus_autospell_onskill(struct s_autospell *spell, int max, short src_skill, short id, short lv, short rate, short card_id) { int i; @@ -1755,7 +1842,7 @@ static int pc_bonus_autospell_onskill(struct s_autospell *spell, int max, short return 1; } -static int pc_bonus_addeff(struct s_addeffect* effect, int max, enum sc_type id, short rate, short arrow_rate, unsigned char flag) +int pc_bonus_addeff(struct s_addeffect* effect, int max, enum sc_type id, short rate, short arrow_rate, unsigned char flag) { int i; if (!(flag&(ATF_SHORT|ATF_LONG))) @@ -1784,13 +1871,10 @@ static int pc_bonus_addeff(struct s_addeffect* effect, int max, enum sc_type id, return 1; } -static int pc_bonus_addeff_onskill(struct s_addeffectonskill* effect, int max, enum sc_type id, short rate, short skill, unsigned char target) -{ +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; - for( i = 0; i < max && effect[i].skill; i++ ) - { - if( effect[i].id == id && effect[i].skill == skill && effect[i].target == target ) - { + 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; return 1; } @@ -1801,14 +1885,14 @@ static int pc_bonus_addeff_onskill(struct s_addeffectonskill* effect, int max, e } effect[i].id = id; effect[i].rate = rate; - effect[i].skill = skill; + effect[i].skill = skill_id; effect[i].target = target; return 1; } -static int pc_bonus_item_drop(struct s_add_drop *drop, const short max, short id, short group, int race, int rate) -{ +int pc_bonus_item_drop(struct s_add_drop *drop, const short max, short id, short group, int race, int rate) { int i; + //Apply config rate adjustment settings. if (rate >= 0) { //Absolute drop. if (battle_config.item_rate_adddrop != 100) @@ -1855,8 +1939,7 @@ static int pc_bonus_item_drop(struct s_add_drop *drop, const short max, short id return 1; } -int pc_addautobonus(struct s_autobonus *bonus,char max,const char *script,short rate,unsigned int dur,short flag,const char *other_script,unsigned short pos,bool onskill) -{ +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; ARR_FIND(0, max, i, bonus[i].rate == 0); @@ -1886,7 +1969,7 @@ int pc_addautobonus(struct s_autobonus *bonus,char max,const char *script,short bonus[i].active = INVALID_TIMER; bonus[i].atk_type = flag; bonus[i].pos = pos; - bonus[i].bonus_script = aStrdup(script); + bonus[i].bonus_script = aStrdup(bonus_script); bonus[i].other_script = other_script?aStrdup(other_script):NULL; return 1; } @@ -1905,15 +1988,15 @@ int pc_delautobonus(struct map_session_data* sd, struct s_autobonus *autobonus,c if( autobonus[i].bonus_script ) { int j; - ARR_FIND( 0, EQI_MAX-1, j, sd->equip_index[j] >= 0 && sd->status.inventory[sd->equip_index[j]].equip == autobonus[i].pos ); - if( j < EQI_MAX-1 ) - script_run_autobonus(autobonus[i].bonus_script,sd->bl.id,sd->equip_index[j]); + ARR_FIND( 0, EQI_MAX, j, sd->equip_index[j] >= 0 && sd->status.inventory[sd->equip_index[j]].equip == autobonus[i].pos ); + if( j < EQI_MAX ) + script->run_autobonus(autobonus[i].bonus_script,sd->bl.id,sd->equip_index[j]); } continue; } else { // Logout / Unequipped an item with an activated bonus - iTimer->delete_timer(autobonus[i].active,pc->endautobonus); + timer->delete(autobonus[i].active,pc->endautobonus); autobonus[i].active = INVALID_TIMER; } } @@ -1936,21 +2019,20 @@ int pc_exeautobonus(struct map_session_data *sd,struct s_autobonus *autobonus) if( autobonus->other_script ) { int j; - ARR_FIND( 0, EQI_MAX-1, j, sd->equip_index[j] >= 0 && sd->status.inventory[sd->equip_index[j]].equip == autobonus->pos ); - if( j < EQI_MAX-1 ) - script_run_autobonus(autobonus->other_script,sd->bl.id,sd->equip_index[j]); + ARR_FIND( 0, EQI_MAX, j, sd->equip_index[j] >= 0 && sd->status.inventory[sd->equip_index[j]].equip == autobonus->pos ); + if( j < EQI_MAX ) + script->run_autobonus(autobonus->other_script,sd->bl.id,sd->equip_index[j]); } - autobonus->active = iTimer->add_timer(iTimer->gettick()+autobonus->duration, pc->endautobonus, sd->bl.id, (intptr_t)autobonus); + autobonus->active = timer->add(timer->gettick()+autobonus->duration, pc->endautobonus, sd->bl.id, (intptr_t)autobonus); sd->state.autobonus |= autobonus->pos; - status_calc_pc(sd,0); + status_calc_pc(sd,SCO_NONE); return 0; } -int pc_endautobonus(int tid, unsigned int tick, int id, intptr_t data) -{ - struct map_session_data *sd = iMap->id2sd(id); +int pc_endautobonus(int tid, int64 tick, int id, intptr_t data) { + struct map_session_data *sd = map->id2sd(id); struct s_autobonus *autobonus = (struct s_autobonus *)data; nullpo_ret(sd); @@ -1958,7 +2040,7 @@ int pc_endautobonus(int tid, unsigned int tick, int id, intptr_t data) autobonus->active = INVALID_TIMER; sd->state.autobonus &= ~autobonus->pos; - status_calc_pc(sd,0); + status_calc_pc(sd,SCO_NONE); return 0; } @@ -2030,13 +2112,12 @@ int pc_bonus_subele(struct map_session_data* sd, unsigned char ele, short rate, /*========================================== * Add a bonus(type) to player sd *------------------------------------------*/ -int pc_bonus(struct map_session_data *sd,int type,int val) -{ - struct status_data *status; +int pc_bonus(struct map_session_data *sd,int type,int val) { + struct status_data *bst; int bonus; nullpo_ret(sd); - status = &sd->base_status; + bst = &sd->base_status; switch(type){ case SP_STR: @@ -2050,58 +2131,57 @@ int pc_bonus(struct map_session_data *sd,int type,int val) break; case SP_ATK1: if(!sd->state.lr_flag) { - bonus = status->rhw.atk + val; - status->rhw.atk = cap_value(bonus, 0, USHRT_MAX); + bonus = bst->rhw.atk + val; + bst->rhw.atk = cap_value(bonus, 0, USHRT_MAX); } else if(sd->state.lr_flag == 1) { - bonus = status->lhw.atk + val; - status->lhw.atk = cap_value(bonus, 0, USHRT_MAX); + bonus = bst->lhw.atk + val; + bst->lhw.atk = cap_value(bonus, 0, USHRT_MAX); } break; case SP_ATK2: if(!sd->state.lr_flag) { - bonus = status->rhw.atk2 + val; - status->rhw.atk2 = cap_value(bonus, 0, USHRT_MAX); + bonus = bst->rhw.atk2 + val; + bst->rhw.atk2 = cap_value(bonus, 0, USHRT_MAX); } else if(sd->state.lr_flag == 1) { - bonus = status->lhw.atk2 + val; - status->lhw.atk2 = cap_value(bonus, 0, USHRT_MAX); + bonus = bst->lhw.atk2 + val; + bst->lhw.atk2 = cap_value(bonus, 0, USHRT_MAX); } break; case SP_BASE_ATK: if(sd->state.lr_flag != 2) { #ifdef RENEWAL - sd->bonus.eatk += val; - clif->updatestatus(sd,SP_ATK2); + bst->equip_atk += val; #else - bonus = status->batk + val; - status->batk = cap_value(bonus, 0, USHRT_MAX); + bonus = bst->batk + val; + bst->batk = cap_value(bonus, 0, USHRT_MAX); #endif } break; case SP_DEF1: if(sd->state.lr_flag != 2) { - bonus = status->def + val; + bonus = bst->def + val; #ifdef RENEWAL - status->def = cap_value(bonus, SHRT_MIN, SHRT_MAX); + bst->def = cap_value(bonus, SHRT_MIN, SHRT_MAX); #else - status->def = cap_value(bonus, CHAR_MIN, CHAR_MAX); + bst->def = cap_value(bonus, CHAR_MIN, CHAR_MAX); #endif } break; case SP_DEF2: if(sd->state.lr_flag != 2) { - bonus = status->def2 + val; - status->def2 = cap_value(bonus, SHRT_MIN, SHRT_MAX); + bonus = bst->def2 + val; + bst->def2 = cap_value(bonus, SHRT_MIN, SHRT_MAX); } break; case SP_MDEF1: if(sd->state.lr_flag != 2) { - bonus = status->mdef + val; + bonus = bst->mdef + val; #ifdef RENEWAL - status->mdef = cap_value(bonus, SHRT_MIN, SHRT_MAX); + bst->mdef = cap_value(bonus, SHRT_MIN, SHRT_MAX); #else - status->mdef = cap_value(bonus, CHAR_MIN, CHAR_MAX); + bst->mdef = cap_value(bonus, CHAR_MIN, CHAR_MAX); #endif if( sd->state.lr_flag == 3 ) {//Shield, used for royal guard sd->bonus.shieldmdef += bonus; @@ -2110,33 +2190,33 @@ int pc_bonus(struct map_session_data *sd,int type,int val) break; case SP_MDEF2: if(sd->state.lr_flag != 2) { - bonus = status->mdef2 + val; - status->mdef2 = cap_value(bonus, SHRT_MIN, SHRT_MAX); + bonus = bst->mdef2 + val; + bst->mdef2 = cap_value(bonus, SHRT_MIN, SHRT_MAX); } break; case SP_HIT: if(sd->state.lr_flag != 2) { - bonus = status->hit + val; - status->hit = cap_value(bonus, SHRT_MIN, SHRT_MAX); + bonus = bst->hit + val; + bst->hit = cap_value(bonus, SHRT_MIN, SHRT_MAX); } else sd->bonus.arrow_hit+=val; break; case SP_FLEE1: if(sd->state.lr_flag != 2) { - bonus = status->flee + val; - status->flee = cap_value(bonus, SHRT_MIN, SHRT_MAX); + bonus = bst->flee + val; + bst->flee = cap_value(bonus, SHRT_MIN, SHRT_MAX); } break; case SP_FLEE2: if(sd->state.lr_flag != 2) { - bonus = status->flee2 + val*10; - status->flee2 = cap_value(bonus, SHRT_MIN, SHRT_MAX); + bonus = bst->flee2 + val*10; + bst->flee2 = cap_value(bonus, SHRT_MIN, SHRT_MAX); } break; case SP_CRITICAL: if(sd->state.lr_flag != 2) { - bonus = status->cri + val*10; - status->cri = cap_value(bonus, SHRT_MIN, SHRT_MAX); + bonus = bst->cri + val*10; + bst->cri = cap_value(bonus, SHRT_MIN, SHRT_MAX); } else sd->bonus.arrow_cri += val*10; break; @@ -2145,8 +2225,7 @@ int pc_bonus(struct map_session_data *sd,int type,int val) ShowError("pc_bonus: SP_ATKELE: Invalid element %d\n", val); break; } - switch (sd->state.lr_flag) - { + switch (sd->state.lr_flag) { case 2: switch (sd->status.weapon) { case W_BOW: @@ -2156,7 +2235,7 @@ int pc_bonus(struct map_session_data *sd,int type,int val) case W_SHOTGUN: case W_GRENADE: //Become weapon element. - status->rhw.ele=val; + bst->rhw.ele=val; break; default: //Become arrow element. sd->bonus.arrow_ele=val; @@ -2164,10 +2243,10 @@ int pc_bonus(struct map_session_data *sd,int type,int val) } break; case 1: - status->lhw.ele=val; + bst->lhw.ele=val; break; default: - status->rhw.ele=val; + bst->rhw.ele=val; break; } break; @@ -2177,21 +2256,21 @@ int pc_bonus(struct map_session_data *sd,int type,int val) break; } if(sd->state.lr_flag != 2) - status->def_ele=val; + bst->def_ele=val; break; case SP_MAXHP: if(sd->state.lr_flag == 2) break; - val += (int)status->max_hp; + val += (int)bst->max_hp; //Negative bonuses will underflow, this will be handled in status_calc_pc through casting //If this is called outside of status_calc_pc, you'd better pray they do not underflow and end with UINT_MAX max_hp. - status->max_hp = (unsigned int)val; + bst->max_hp = (unsigned int)val; break; case SP_MAXSP: if(sd->state.lr_flag == 2) break; - val += (int)status->max_sp; - status->max_sp = (unsigned int)val; + val += (int)bst->max_sp; + bst->max_sp = (unsigned int)val; break; #ifndef RENEWAL_CAST case SP_VARCASTRATE: @@ -2222,14 +2301,14 @@ int pc_bonus(struct map_session_data *sd,int type,int val) case W_GATLING: case W_SHOTGUN: case W_GRENADE: - status->rhw.range += val; + bst->rhw.range += val; } break; case 1: - status->lhw.range += val; + bst->lhw.range += val; break; default: - status->rhw.range += val; + bst->rhw.range += val; break; } break; @@ -2248,9 +2327,9 @@ int pc_bonus(struct map_session_data *sd,int type,int val) case SP_ASPD_RATE: //Stackable increase - Made it linear as per rodatazone if(sd->state.lr_flag != 2) #ifndef RENEWAL_ASPD - status->aspd_rate -= 10*val; + bst->aspd_rate -= 10*val; #else - status->aspd_rate2 += val; + bst->aspd_rate2 += val; #endif break; case SP_HP_RECOV_RATE: @@ -2630,11 +2709,13 @@ int pc_bonus(struct map_session_data *sd,int type,int val) break; case SP_ADD_VARIABLECAST: if(sd->state.lr_flag != 2) - sd->bonus.add_varcast += val; - break; #endif + case SP_ADD_MONSTER_DROP_CHAINITEM: + if (sd->state.lr_flag != 2) + pc->bonus_item_drop(sd->add_drop, ARRAYLENGTH(sd->add_drop), 0, val, (1<<RC_BOSS)|(1<<RC_NONBOSS), 10000); + break; default: ShowWarning("pc_bonus: unknown type %d %d !\n",type,val); break; @@ -2652,593 +2733,591 @@ int pc_bonus2(struct map_session_data *sd,int type,int type2,int val) nullpo_ret(sd); switch(type){ - case SP_ADDELE: - if(type2 >= ELE_MAX) { - ShowError("pc_bonus2: SP_ADDELE: Invalid element %d\n", type2); + case SP_ADDELE: + if(type2 >= ELE_MAX) { + ShowError("pc_bonus2: SP_ADDELE: Invalid element %d\n", type2); + break; + } + if(!sd->state.lr_flag) + sd->right_weapon.addele[type2]+=val; + else if(sd->state.lr_flag == 1) + sd->left_weapon.addele[type2]+=val; + else if(sd->state.lr_flag == 2) + sd->arrow_addele[type2]+=val; break; - } - if(!sd->state.lr_flag) - sd->right_weapon.addele[type2]+=val; - else if(sd->state.lr_flag == 1) - sd->left_weapon.addele[type2]+=val; - else if(sd->state.lr_flag == 2) - sd->arrow_addele[type2]+=val; - break; - case SP_ADDRACE: - if(!sd->state.lr_flag) - sd->right_weapon.addrace[type2]+=val; - else if(sd->state.lr_flag == 1) - sd->left_weapon.addrace[type2]+=val; - else if(sd->state.lr_flag == 2) - sd->arrow_addrace[type2]+=val; - break; - case SP_ADDSIZE: - if(!sd->state.lr_flag) - sd->right_weapon.addsize[type2]+=val; - else if(sd->state.lr_flag == 1) - sd->left_weapon.addsize[type2]+=val; - else if(sd->state.lr_flag == 2) - sd->arrow_addsize[type2]+=val; - break; - case SP_SUBELE: - if(type2 >= ELE_MAX) { - ShowError("pc_bonus2: SP_SUBELE: Invalid element %d\n", type2); + case SP_ADDRACE: + if(!sd->state.lr_flag) + sd->right_weapon.addrace[type2]+=val; + else if(sd->state.lr_flag == 1) + sd->left_weapon.addrace[type2]+=val; + else if(sd->state.lr_flag == 2) + sd->arrow_addrace[type2]+=val; break; - } - if(sd->state.lr_flag != 2) - sd->subele[type2]+=val; - break; - case SP_SUBRACE: - if(sd->state.lr_flag != 2) - sd->subrace[type2]+=val; - break; - case SP_ADDEFF: - if (type2 > SC_MAX) { - ShowWarning("pc_bonus2 (Add Effect): %d is not supported.\n", type2); + case SP_ADDSIZE: + if(!sd->state.lr_flag) + sd->right_weapon.addsize[type2]+=val; + else if(sd->state.lr_flag == 1) + sd->left_weapon.addsize[type2]+=val; + else if(sd->state.lr_flag == 2) + sd->arrow_addsize[type2]+=val; break; - } - pc_bonus_addeff(sd->addeff, ARRAYLENGTH(sd->addeff), (sc_type)type2, - sd->state.lr_flag!=2?val:0, sd->state.lr_flag==2?val:0, 0); - break; - case SP_ADDEFF2: - if (type2 > SC_MAX) { - ShowWarning("pc_bonus2 (Add Effect2): %d is not supported.\n", type2); + case SP_SUBELE: + if(type2 >= ELE_MAX) { + ShowError("pc_bonus2: SP_SUBELE: Invalid element %d\n", type2); + break; + } + if(sd->state.lr_flag != 2) + sd->subele[type2]+=val; break; - } - pc_bonus_addeff(sd->addeff, ARRAYLENGTH(sd->addeff), (sc_type)type2, - sd->state.lr_flag!=2?val:0, sd->state.lr_flag==2?val:0, ATF_SELF); - break; - case SP_RESEFF: - if (type2 < SC_COMMON_MIN || type2 > SC_COMMON_MAX) { - ShowWarning("pc_bonus2 (Resist Effect): %d is not supported.\n", type2); + case SP_SUBRACE: + if(sd->state.lr_flag != 2) + sd->subrace[type2]+=val; break; - } - if(sd->state.lr_flag == 2) + case SP_ADDEFF: + if (type2 > SC_MAX) { + ShowWarning("pc_bonus2 (Add Effect): %d is not supported.\n", type2); + break; + } + pc->bonus_addeff(sd->addeff, ARRAYLENGTH(sd->addeff), (sc_type)type2, + sd->state.lr_flag!=2?val:0, sd->state.lr_flag==2?val:0, 0); break; - i = sd->reseff[type2-SC_COMMON_MIN]+val; - sd->reseff[type2-SC_COMMON_MIN]= cap_value(i, 0, 10000); - break; - case SP_MAGIC_ADDELE: - if(type2 >= ELE_MAX) { - ShowError("pc_bonus2: SP_MAGIC_ADDELE: Invalid element %d\n", type2); + case SP_ADDEFF2: + if (type2 > SC_MAX) { + ShowWarning("pc_bonus2 (Add Effect2): %d is not supported.\n", type2); + break; + } + pc->bonus_addeff(sd->addeff, ARRAYLENGTH(sd->addeff), (sc_type)type2, + sd->state.lr_flag!=2?val:0, sd->state.lr_flag==2?val:0, ATF_SELF); break; - } - if(sd->state.lr_flag != 2) - sd->magic_addele[type2]+=val; - break; - case SP_MAGIC_ADDRACE: - if(sd->state.lr_flag != 2) - sd->magic_addrace[type2]+=val; - break; - case SP_MAGIC_ADDSIZE: - if(sd->state.lr_flag != 2) - sd->magic_addsize[type2]+=val; - break; - case SP_MAGIC_ATK_ELE: - if(sd->state.lr_flag != 2) - sd->magic_atk_ele[type2]+=val; - break; - case SP_ADD_DAMAGE_CLASS: - switch (sd->state.lr_flag) { - case 0: //Right hand - ARR_FIND(0, ARRAYLENGTH(sd->right_weapon.add_dmg), i, sd->right_weapon.add_dmg[i].rate == 0 || sd->right_weapon.add_dmg[i].class_ == type2); - if (i == ARRAYLENGTH(sd->right_weapon.add_dmg)) - { - ShowWarning("pc_bonus2: Reached max (%d) number of add Class dmg bonuses per character!\n", ARRAYLENGTH(sd->right_weapon.add_dmg)); + case SP_RESEFF: + if (type2 < SC_COMMON_MIN || type2 > SC_COMMON_MAX) { + ShowWarning("pc_bonus2 (Resist Effect): %d is not supported.\n", type2); break; } - sd->right_weapon.add_dmg[i].class_ = type2; - sd->right_weapon.add_dmg[i].rate += val; - if (!sd->right_weapon.add_dmg[i].rate) //Shift the rest of elements up. - memmove(&sd->right_weapon.add_dmg[i], &sd->right_weapon.add_dmg[i+1], sizeof(sd->right_weapon.add_dmg) - (i+1)*sizeof(sd->right_weapon.add_dmg[0])); + if(sd->state.lr_flag == 2) + break; + i = sd->reseff[type2-SC_COMMON_MIN]+val; + sd->reseff[type2-SC_COMMON_MIN]= cap_value(i, 0, 10000); break; - case 1: //Left hand - ARR_FIND(0, ARRAYLENGTH(sd->left_weapon.add_dmg), i, sd->left_weapon.add_dmg[i].rate == 0 || sd->left_weapon.add_dmg[i].class_ == type2); - if (i == ARRAYLENGTH(sd->left_weapon.add_dmg)) - { - ShowWarning("pc_bonus2: Reached max (%d) number of add Class dmg bonuses per character!\n", ARRAYLENGTH(sd->left_weapon.add_dmg)); + case SP_MAGIC_ADDELE: + if(type2 >= ELE_MAX) { + ShowError("pc_bonus2: SP_MAGIC_ADDELE: Invalid element %d\n", type2); break; } - sd->left_weapon.add_dmg[i].class_ = type2; - sd->left_weapon.add_dmg[i].rate += val; - if (!sd->left_weapon.add_dmg[i].rate) //Shift the rest of elements up. - memmove(&sd->left_weapon.add_dmg[i], &sd->left_weapon.add_dmg[i+1], sizeof(sd->left_weapon.add_dmg) - (i+1)*sizeof(sd->left_weapon.add_dmg[0])); + if(sd->state.lr_flag != 2) + sd->magic_addele[type2]+=val; break; - } - break; - case SP_ADD_MAGIC_DAMAGE_CLASS: - if(sd->state.lr_flag == 2) + case SP_MAGIC_ADDRACE: + if(sd->state.lr_flag != 2) + sd->magic_addrace[type2]+=val; break; - ARR_FIND(0, ARRAYLENGTH(sd->add_mdmg), i, sd->add_mdmg[i].rate == 0 || sd->add_mdmg[i].class_ == type2); - if (i == ARRAYLENGTH(sd->add_mdmg)) - { - ShowWarning("pc_bonus2: Reached max (%d) number of add Class magic dmg bonuses per character!\n", ARRAYLENGTH(sd->add_mdmg)); + case SP_MAGIC_ADDSIZE: + if(sd->state.lr_flag != 2) + sd->magic_addsize[type2]+=val; break; - } - sd->add_mdmg[i].class_ = type2; - sd->add_mdmg[i].rate += val; - if (!sd->add_mdmg[i].rate) //Shift the rest of elements up. - memmove(&sd->add_mdmg[i], &sd->add_mdmg[i+1], sizeof(sd->add_mdmg) - (i+1)*sizeof(sd->add_mdmg[0])); - break; - case SP_ADD_DEF_CLASS: - if(sd->state.lr_flag == 2) + case SP_MAGIC_ATK_ELE: + if(sd->state.lr_flag != 2) + sd->magic_atk_ele[type2]+=val; break; - ARR_FIND(0, ARRAYLENGTH(sd->add_def), i, sd->add_def[i].rate == 0 || sd->add_def[i].class_ == type2); - if (i == ARRAYLENGTH(sd->add_def)) - { - ShowWarning("pc_bonus2: Reached max (%d) number of add Class def bonuses per character!\n", ARRAYLENGTH(sd->add_def)); + case SP_ADD_DAMAGE_CLASS: + switch (sd->state.lr_flag) { + case 0: //Right hand + ARR_FIND(0, ARRAYLENGTH(sd->right_weapon.add_dmg), i, sd->right_weapon.add_dmg[i].rate == 0 || sd->right_weapon.add_dmg[i].class_ == type2); + if (i == ARRAYLENGTH(sd->right_weapon.add_dmg)) { + ShowWarning("pc_bonus2: Reached max (%"PRIuS") number of add Class dmg bonuses per character!\n", + ARRAYLENGTH(sd->right_weapon.add_dmg)); + break; + } + sd->right_weapon.add_dmg[i].class_ = type2; + sd->right_weapon.add_dmg[i].rate += val; + if (!sd->right_weapon.add_dmg[i].rate) //Shift the rest of elements up. + memmove(&sd->right_weapon.add_dmg[i], &sd->right_weapon.add_dmg[i+1], sizeof(sd->right_weapon.add_dmg) - (i+1)*sizeof(sd->right_weapon.add_dmg[0])); + break; + case 1: //Left hand + ARR_FIND(0, ARRAYLENGTH(sd->left_weapon.add_dmg), i, sd->left_weapon.add_dmg[i].rate == 0 || sd->left_weapon.add_dmg[i].class_ == type2); + if (i == ARRAYLENGTH(sd->left_weapon.add_dmg)) { + ShowWarning("pc_bonus2: Reached max (%"PRIuS") number of add Class dmg bonuses per character!\n", + ARRAYLENGTH(sd->left_weapon.add_dmg)); + break; + } + sd->left_weapon.add_dmg[i].class_ = type2; + sd->left_weapon.add_dmg[i].rate += val; + if (!sd->left_weapon.add_dmg[i].rate) //Shift the rest of elements up. + memmove(&sd->left_weapon.add_dmg[i], &sd->left_weapon.add_dmg[i+1], sizeof(sd->left_weapon.add_dmg) - (i+1)*sizeof(sd->left_weapon.add_dmg[0])); + break; + } break; - } - sd->add_def[i].class_ = type2; - sd->add_def[i].rate += val; - if (!sd->add_def[i].rate) //Shift the rest of elements up. - memmove(&sd->add_def[i], &sd->add_def[i+1], sizeof(sd->add_def) - (i+1)*sizeof(sd->add_def[0])); - break; - case SP_ADD_MDEF_CLASS: - if(sd->state.lr_flag == 2) + case SP_ADD_MAGIC_DAMAGE_CLASS: + if(sd->state.lr_flag == 2) + break; + ARR_FIND(0, ARRAYLENGTH(sd->add_mdmg), i, sd->add_mdmg[i].rate == 0 || sd->add_mdmg[i].class_ == type2); + if (i == ARRAYLENGTH(sd->add_mdmg)) { + ShowWarning("pc_bonus2: Reached max (%"PRIuS") number of add Class magic dmg bonuses per character!\n", ARRAYLENGTH(sd->add_mdmg)); + break; + } + sd->add_mdmg[i].class_ = type2; + sd->add_mdmg[i].rate += val; + if (!sd->add_mdmg[i].rate) //Shift the rest of elements up. + memmove(&sd->add_mdmg[i], &sd->add_mdmg[i+1], sizeof(sd->add_mdmg) - (i+1)*sizeof(sd->add_mdmg[0])); break; - ARR_FIND(0, ARRAYLENGTH(sd->add_mdef), i, sd->add_mdef[i].rate == 0 || sd->add_mdef[i].class_ == type2); - if (i == ARRAYLENGTH(sd->add_mdef)) - { - ShowWarning("pc_bonus2: Reached max (%d) number of add Class mdef bonuses per character!\n", ARRAYLENGTH(sd->add_mdef)); + case SP_ADD_DEF_CLASS: + if(sd->state.lr_flag == 2) + break; + ARR_FIND(0, ARRAYLENGTH(sd->add_def), i, sd->add_def[i].rate == 0 || sd->add_def[i].class_ == type2); + if (i == ARRAYLENGTH(sd->add_def)) { + ShowWarning("pc_bonus2: Reached max (%"PRIuS") number of add Class def bonuses per character!\n", ARRAYLENGTH(sd->add_def)); + break; + } + sd->add_def[i].class_ = type2; + sd->add_def[i].rate += val; + if (!sd->add_def[i].rate) //Shift the rest of elements up. + memmove(&sd->add_def[i], &sd->add_def[i+1], sizeof(sd->add_def) - (i+1)*sizeof(sd->add_def[0])); break; - } - sd->add_mdef[i].class_ = type2; - sd->add_mdef[i].rate += val; - if (!sd->add_mdef[i].rate) //Shift the rest of elements up. - memmove(&sd->add_mdef[i], &sd->add_mdef[i+1], sizeof(sd->add_mdef) - (i+1)*sizeof(sd->add_mdef[0])); - break; - case SP_HP_DRAIN_RATE: - if(!sd->state.lr_flag) { - sd->right_weapon.hp_drain[RC_NONBOSS].rate += type2; - sd->right_weapon.hp_drain[RC_NONBOSS].per += val; - sd->right_weapon.hp_drain[RC_BOSS].rate += type2; - sd->right_weapon.hp_drain[RC_BOSS].per += val; - } - else if(sd->state.lr_flag == 1) { - sd->left_weapon.hp_drain[RC_NONBOSS].rate += type2; - sd->left_weapon.hp_drain[RC_NONBOSS].per += val; - sd->left_weapon.hp_drain[RC_BOSS].rate += type2; - sd->left_weapon.hp_drain[RC_BOSS].per += val; - } - break; - case SP_HP_DRAIN_VALUE: - if(!sd->state.lr_flag) { - sd->right_weapon.hp_drain[RC_NONBOSS].value += type2; - sd->right_weapon.hp_drain[RC_NONBOSS].type = val; - sd->right_weapon.hp_drain[RC_BOSS].value += type2; - sd->right_weapon.hp_drain[RC_BOSS].type = val; - } - else if(sd->state.lr_flag == 1) { - sd->left_weapon.hp_drain[RC_NONBOSS].value += type2; - sd->left_weapon.hp_drain[RC_NONBOSS].type = val; - sd->left_weapon.hp_drain[RC_BOSS].value += type2; - sd->left_weapon.hp_drain[RC_BOSS].type = val; - } - break; - case SP_SP_DRAIN_RATE: - if(!sd->state.lr_flag) { - sd->right_weapon.sp_drain[RC_NONBOSS].rate += type2; - sd->right_weapon.sp_drain[RC_NONBOSS].per += val; - sd->right_weapon.sp_drain[RC_BOSS].rate += type2; - sd->right_weapon.sp_drain[RC_BOSS].per += val; - } - else if(sd->state.lr_flag == 1) { - sd->left_weapon.sp_drain[RC_NONBOSS].rate += type2; - sd->left_weapon.sp_drain[RC_NONBOSS].per += val; - sd->left_weapon.sp_drain[RC_BOSS].rate += type2; - sd->left_weapon.sp_drain[RC_BOSS].per += val; - } - break; - case SP_SP_DRAIN_VALUE: - if(!sd->state.lr_flag) { - sd->right_weapon.sp_drain[RC_NONBOSS].value += type2; - sd->right_weapon.sp_drain[RC_NONBOSS].type = val; - sd->right_weapon.sp_drain[RC_BOSS].value += type2; - sd->right_weapon.sp_drain[RC_BOSS].type = val; - } - else if(sd->state.lr_flag == 1) { - sd->left_weapon.sp_drain[RC_NONBOSS].value += type2; - sd->left_weapon.sp_drain[RC_NONBOSS].type = val; - sd->left_weapon.sp_drain[RC_BOSS].value += type2; - sd->left_weapon.sp_drain[RC_BOSS].type = val; - } - break; - case SP_SP_VANISH_RATE: - if(sd->state.lr_flag != 2) { - sd->bonus.sp_vanish_rate += type2; - sd->bonus.sp_vanish_per += val; - } - break; - case SP_GET_ZENY_NUM: - if(sd->state.lr_flag != 2 && sd->bonus.get_zeny_rate < val) { - sd->bonus.get_zeny_rate = val; - sd->bonus.get_zeny_num = type2; - } - break; - case SP_ADD_GET_ZENY_NUM: - if(sd->state.lr_flag != 2) { - sd->bonus.get_zeny_rate += val; - sd->bonus.get_zeny_num += type2; - } - break; - case SP_WEAPON_COMA_ELE: - if(type2 >= ELE_MAX) { - ShowError("pc_bonus2: SP_WEAPON_COMA_ELE: Invalid element %d\n", type2); + case SP_ADD_MDEF_CLASS: + if(sd->state.lr_flag == 2) + break; + ARR_FIND(0, ARRAYLENGTH(sd->add_mdef), i, sd->add_mdef[i].rate == 0 || sd->add_mdef[i].class_ == type2); + if (i == ARRAYLENGTH(sd->add_mdef)) { + ShowWarning("pc_bonus2: Reached max (%"PRIuS") number of add Class mdef bonuses per character!\n", ARRAYLENGTH(sd->add_mdef)); + break; + } + sd->add_mdef[i].class_ = type2; + sd->add_mdef[i].rate += val; + if (!sd->add_mdef[i].rate) //Shift the rest of elements up. + memmove(&sd->add_mdef[i], &sd->add_mdef[i+1], sizeof(sd->add_mdef) - (i+1)*sizeof(sd->add_mdef[0])); break; - } - if(sd->state.lr_flag == 2) + case SP_HP_DRAIN_RATE: + if(!sd->state.lr_flag) { + sd->right_weapon.hp_drain[RC_NONBOSS].rate += type2; + sd->right_weapon.hp_drain[RC_NONBOSS].per += val; + sd->right_weapon.hp_drain[RC_BOSS].rate += type2; + sd->right_weapon.hp_drain[RC_BOSS].per += val; + } + else if(sd->state.lr_flag == 1) { + sd->left_weapon.hp_drain[RC_NONBOSS].rate += type2; + sd->left_weapon.hp_drain[RC_NONBOSS].per += val; + sd->left_weapon.hp_drain[RC_BOSS].rate += type2; + sd->left_weapon.hp_drain[RC_BOSS].per += val; + } break; - sd->weapon_coma_ele[type2] += val; - sd->special_state.bonus_coma = 1; - break; - case SP_WEAPON_COMA_RACE: - if(sd->state.lr_flag == 2) + case SP_HP_DRAIN_VALUE: + if(!sd->state.lr_flag) { + sd->right_weapon.hp_drain[RC_NONBOSS].value += type2; + sd->right_weapon.hp_drain[RC_NONBOSS].type = val; + sd->right_weapon.hp_drain[RC_BOSS].value += type2; + sd->right_weapon.hp_drain[RC_BOSS].type = val; + } + else if(sd->state.lr_flag == 1) { + sd->left_weapon.hp_drain[RC_NONBOSS].value += type2; + sd->left_weapon.hp_drain[RC_NONBOSS].type = val; + sd->left_weapon.hp_drain[RC_BOSS].value += type2; + sd->left_weapon.hp_drain[RC_BOSS].type = val; + } break; - sd->weapon_coma_race[type2] += val; - sd->special_state.bonus_coma = 1; - break; - case SP_WEAPON_ATK: - if(sd->state.lr_flag != 2) - sd->weapon_atk[type2]+=val; - break; - case SP_WEAPON_ATK_RATE: - if(sd->state.lr_flag != 2) - sd->weapon_atk_rate[type2]+=val; - break; - case SP_CRITICAL_ADDRACE: - if(sd->state.lr_flag != 2) - sd->critaddrace[type2] += val*10; - break; - case SP_ADDEFF_WHENHIT: - if (type2 > SC_MAX) { - ShowWarning("pc_bonus2 (Add Effect when hit): %d is not supported.\n", type2); + case SP_SP_DRAIN_RATE: + if(!sd->state.lr_flag) { + sd->right_weapon.sp_drain[RC_NONBOSS].rate += type2; + sd->right_weapon.sp_drain[RC_NONBOSS].per += val; + sd->right_weapon.sp_drain[RC_BOSS].rate += type2; + sd->right_weapon.sp_drain[RC_BOSS].per += val; + } + else if(sd->state.lr_flag == 1) { + sd->left_weapon.sp_drain[RC_NONBOSS].rate += type2; + sd->left_weapon.sp_drain[RC_NONBOSS].per += val; + sd->left_weapon.sp_drain[RC_BOSS].rate += type2; + sd->left_weapon.sp_drain[RC_BOSS].per += val; + } break; - } - if(sd->state.lr_flag != 2) - pc_bonus_addeff(sd->addeff2, ARRAYLENGTH(sd->addeff2), (sc_type)type2, val, 0, 0); - break; - case SP_SKILL_ATK: - if(sd->state.lr_flag == 2) + case SP_SP_DRAIN_VALUE: + if(!sd->state.lr_flag) { + sd->right_weapon.sp_drain[RC_NONBOSS].value += type2; + sd->right_weapon.sp_drain[RC_NONBOSS].type = val; + sd->right_weapon.sp_drain[RC_BOSS].value += type2; + sd->right_weapon.sp_drain[RC_BOSS].type = val; + } + else if(sd->state.lr_flag == 1) { + sd->left_weapon.sp_drain[RC_NONBOSS].value += type2; + sd->left_weapon.sp_drain[RC_NONBOSS].type = val; + sd->left_weapon.sp_drain[RC_BOSS].value += type2; + sd->left_weapon.sp_drain[RC_BOSS].type = val; + } break; - ARR_FIND(0, ARRAYLENGTH(sd->skillatk), i, sd->skillatk[i].id == 0 || sd->skillatk[i].id == type2); - if (i == ARRAYLENGTH(sd->skillatk)) - { //Better mention this so the array length can be updated. [Skotlex] - ShowDebug("run_script: bonus2 bSkillAtk reached it's limit (%d skills per character), bonus skill %d (+%d%%) lost.\n", ARRAYLENGTH(sd->skillatk), type2, val); + case SP_SP_VANISH_RATE: + if(sd->state.lr_flag != 2) { + sd->bonus.sp_vanish_rate += type2; + sd->bonus.sp_vanish_per = max(sd->bonus.sp_vanish_per,val); + sd->bonus.sp_vanish_trigger=0; + } break; - } - if (sd->skillatk[i].id == type2) - sd->skillatk[i].val += val; - else { - sd->skillatk[i].id = type2; - sd->skillatk[i].val = val; - } - break; - case SP_SKILL_HEAL: - if(sd->state.lr_flag == 2) + case SP_GET_ZENY_NUM: + if(sd->state.lr_flag != 2 && sd->bonus.get_zeny_rate < val) { + sd->bonus.get_zeny_rate = val; + sd->bonus.get_zeny_num = type2; + } break; - ARR_FIND(0, ARRAYLENGTH(sd->skillheal), i, sd->skillheal[i].id == 0 || sd->skillheal[i].id == type2); - if (i == ARRAYLENGTH(sd->skillheal)) - { // Better mention this so the array length can be updated. [Skotlex] - ShowDebug("run_script: bonus2 bSkillHeal reached it's limit (%d skills per character), bonus skill %d (+%d%%) lost.\n", ARRAYLENGTH(sd->skillheal), type2, val); + case SP_ADD_GET_ZENY_NUM: + if(sd->state.lr_flag != 2) { + sd->bonus.get_zeny_rate += val; + sd->bonus.get_zeny_num += type2; + } break; - } - if (sd->skillheal[i].id == type2) - sd->skillheal[i].val += val; - else { - sd->skillheal[i].id = type2; - sd->skillheal[i].val = val; - } - break; - case SP_SKILL_HEAL2: - if(sd->state.lr_flag == 2) + case SP_WEAPON_COMA_ELE: + if(type2 >= ELE_MAX) { + ShowError("pc_bonus2: SP_WEAPON_COMA_ELE: Invalid element %d\n", type2); + break; + } + if(sd->state.lr_flag == 2) + break; + sd->weapon_coma_ele[type2] += val; + sd->special_state.bonus_coma = 1; break; - ARR_FIND(0, ARRAYLENGTH(sd->skillheal2), i, sd->skillheal2[i].id == 0 || sd->skillheal2[i].id == type2); - if (i == ARRAYLENGTH(sd->skillheal2)) - { // Better mention this so the array length can be updated. [Skotlex] - ShowDebug("run_script: bonus2 bSkillHeal2 reached it's limit (%d skills per character), bonus skill %d (+%d%%) lost.\n", ARRAYLENGTH(sd->skillheal2), type2, val); + case SP_WEAPON_COMA_RACE: + if(sd->state.lr_flag == 2) + break; + sd->weapon_coma_race[type2] += val; + sd->special_state.bonus_coma = 1; break; - } - if (sd->skillheal2[i].id == type2) - sd->skillheal2[i].val += val; - else { - sd->skillheal2[i].id = type2; - sd->skillheal2[i].val = val; - } - break; - case SP_ADD_SKILL_BLOW: - if(sd->state.lr_flag == 2) + case SP_WEAPON_ATK: + if(sd->state.lr_flag != 2) + sd->weapon_atk[type2]+=val; break; - ARR_FIND(0, ARRAYLENGTH(sd->skillblown), i, sd->skillblown[i].id == 0 || sd->skillblown[i].id == type2); - if (i == ARRAYLENGTH(sd->skillblown)) - { //Better mention this so the array length can be updated. [Skotlex] - ShowDebug("run_script: bonus2 bSkillBlown reached it's limit (%d skills per character), bonus skill %d (+%d%%) lost.\n", ARRAYLENGTH(sd->skillblown), type2, val); + case SP_WEAPON_ATK_RATE: + if(sd->state.lr_flag != 2) + sd->weapon_atk_rate[type2]+=val; break; - } - if(sd->skillblown[i].id == type2) - sd->skillblown[i].val += val; - else { - sd->skillblown[i].id = type2; - sd->skillblown[i].val = val; - } - break; -#ifndef RENEWAL_CAST - case SP_VARCASTRATE: -#endif - case SP_CASTRATE: - if(sd->state.lr_flag == 2) + case SP_CRITICAL_ADDRACE: + if(sd->state.lr_flag != 2) + sd->critaddrace[type2] += val*10; break; - ARR_FIND(0, ARRAYLENGTH(sd->skillcast), i, sd->skillcast[i].id == 0 || sd->skillcast[i].id == type2); - if (i == ARRAYLENGTH(sd->skillcast)) - { //Better mention this so the array length can be updated. [Skotlex] - ShowDebug("run_script: bonus2 %s reached it's limit (%d skills per character), bonus skill %d (+%d%%) lost.\n", - -#ifndef RENEWAL_CAST - "bCastRate", -#else - "bVariableCastrate", -#endif - - ARRAYLENGTH(sd->skillcast), type2, val); + case SP_ADDEFF_WHENHIT: + if (type2 > SC_MAX) { + ShowWarning("pc_bonus2 (Add Effect when hit): %d is not supported.\n", type2); + break; + } + if(sd->state.lr_flag != 2) + pc->bonus_addeff(sd->addeff2, ARRAYLENGTH(sd->addeff2), (sc_type)type2, val, 0, 0); break; - } - if(sd->skillcast[i].id == type2) - sd->skillcast[i].val += val; - else { - sd->skillcast[i].id = type2; - sd->skillcast[i].val = val; - } - break; - - case SP_FIXCASTRATE: - if(sd->state.lr_flag == 2) + case SP_SKILL_ATK: + if(sd->state.lr_flag == 2) + break; + ARR_FIND(0, ARRAYLENGTH(sd->skillatk), i, sd->skillatk[i].id == 0 || sd->skillatk[i].id == type2); + if (i == ARRAYLENGTH(sd->skillatk)) { + //Better mention this so the array length can be updated. [Skotlex] + ShowDebug("script->run: bonus2 bSkillAtk reached it's limit (%"PRIuS" skills per character), bonus skill %d (+%d%%) lost.\n", + ARRAYLENGTH(sd->skillatk), type2, val); + break; + } + if (sd->skillatk[i].id == type2) + sd->skillatk[i].val += val; + else { + sd->skillatk[i].id = type2; + sd->skillatk[i].val = val; + } + break; + case SP_SKILL_HEAL: + if(sd->state.lr_flag == 2) + break; + ARR_FIND(0, ARRAYLENGTH(sd->skillheal), i, sd->skillheal[i].id == 0 || sd->skillheal[i].id == type2); + if (i == ARRAYLENGTH(sd->skillheal)) { + // Better mention this so the array length can be updated. [Skotlex] + ShowDebug("script->run: bonus2 bSkillHeal reached it's limit (%"PRIuS" skills per character), bonus skill %d (+%d%%) lost.\n", + ARRAYLENGTH(sd->skillheal), type2, val); + break; + } + if (sd->skillheal[i].id == type2) + sd->skillheal[i].val += val; + else { + sd->skillheal[i].id = type2; + sd->skillheal[i].val = val; + } + break; + case SP_SKILL_HEAL2: + if(sd->state.lr_flag == 2) + break; + ARR_FIND(0, ARRAYLENGTH(sd->skillheal2), i, sd->skillheal2[i].id == 0 || sd->skillheal2[i].id == type2); + if (i == ARRAYLENGTH(sd->skillheal2)) { + // Better mention this so the array length can be updated. [Skotlex] + ShowDebug("script->run: bonus2 bSkillHeal2 reached it's limit (%"PRIuS" skills per character), bonus skill %d (+%d%%) lost.\n", + ARRAYLENGTH(sd->skillheal2), type2, val); + break; + } + if (sd->skillheal2[i].id == type2) + sd->skillheal2[i].val += val; + else { + sd->skillheal2[i].id = type2; + sd->skillheal2[i].val = val; + } + break; + case SP_ADD_SKILL_BLOW: + if(sd->state.lr_flag == 2) + break; + ARR_FIND(0, ARRAYLENGTH(sd->skillblown), i, sd->skillblown[i].id == 0 || sd->skillblown[i].id == type2); + if (i == ARRAYLENGTH(sd->skillblown)) { + //Better mention this so the array length can be updated. [Skotlex] + ShowDebug("script->run: bonus2 bSkillBlown reached it's limit (%"PRIuS" skills per character), bonus skill %d (+%d%%) lost.\n", + ARRAYLENGTH(sd->skillblown), type2, val); + break; + } + if(sd->skillblown[i].id == type2) + sd->skillblown[i].val += val; + else { + sd->skillblown[i].id = type2; + sd->skillblown[i].val = val; + } break; + #ifndef RENEWAL_CAST + case SP_VARCASTRATE: + #endif + case SP_CASTRATE: + if(sd->state.lr_flag == 2) + break; + ARR_FIND(0, ARRAYLENGTH(sd->skillcast), i, sd->skillcast[i].id == 0 || sd->skillcast[i].id == type2); + if (i == ARRAYLENGTH(sd->skillcast)) { + //Better mention this so the array length can be updated. [Skotlex] + ShowDebug("script->run: bonus2 %s reached it's limit (%"PRIuS" skills per character), bonus skill %d (+%d%%) lost.\n", - ARR_FIND(0, ARRAYLENGTH(sd->skillfixcastrate), i, sd->skillfixcastrate[i].id == 0 || sd->skillfixcastrate[i].id == type2); + #ifndef RENEWAL_CAST + "bCastRate", + #else + "bVariableCastrate", + #endif - if (i == ARRAYLENGTH(sd->skillfixcastrate)) + ARRAYLENGTH(sd->skillcast), type2, val); + break; + } + if(sd->skillcast[i].id == type2) + sd->skillcast[i].val += val; + else { + sd->skillcast[i].id = type2; + sd->skillcast[i].val = val; + } + break; - { + case SP_FIXCASTRATE: + if(sd->state.lr_flag == 2) + break; - ShowDebug("run_script: bonus2 bFixedCastrate reached it's limit (%d skills per character), bonus skill %d (+%d%%) lost.\n", ARRAYLENGTH(sd->skillfixcastrate), type2, val); - break; - } + ARR_FIND(0, ARRAYLENGTH(sd->skillfixcastrate), i, sd->skillfixcastrate[i].id == 0 || sd->skillfixcastrate[i].id == type2); - if(sd->skillfixcastrate[i].id == type2) - sd->skillfixcastrate[i].val += val; + if (i == ARRAYLENGTH(sd->skillfixcastrate)) { + ShowDebug("script->run: bonus2 bFixedCastrate reached it's limit (%"PRIuS" skills per character), bonus skill %d (+%d%%) lost.\n", + ARRAYLENGTH(sd->skillfixcastrate), type2, val); + break; + } - else { - sd->skillfixcastrate[i].id = type2; - sd->skillfixcastrate[i].val = val; - } + if(sd->skillfixcastrate[i].id == type2) + sd->skillfixcastrate[i].val += val; - break; + else { + sd->skillfixcastrate[i].id = type2; + sd->skillfixcastrate[i].val = val; + } - case SP_HP_LOSS_RATE: - if(sd->state.lr_flag != 2) { - sd->hp_loss.value = type2; - sd->hp_loss.rate = val; - } - break; - case SP_HP_REGEN_RATE: - if(sd->state.lr_flag != 2) { - sd->hp_regen.value = type2; - sd->hp_regen.rate = val; - } - break; - case SP_ADDRACE2: - if (!(type2 > RC2_NONE && type2 < RC2_MAX)) break; - if(sd->state.lr_flag != 2) - sd->right_weapon.addrace2[type2] += val; - else - sd->left_weapon.addrace2[type2] += val; - break; - case SP_SUBSIZE: - if(sd->state.lr_flag != 2) - sd->subsize[type2]+=val; - break; - case SP_SUBRACE2: - if (!(type2 > RC2_NONE && type2 < RC2_MAX)) + + case SP_HP_LOSS_RATE: + if(sd->state.lr_flag != 2) { + sd->hp_loss.value = type2; + sd->hp_loss.rate = val; + } break; - if(sd->state.lr_flag != 2) - sd->subrace2[type2]+=val; - break; - case SP_ADD_ITEM_HEAL_RATE: - if(sd->state.lr_flag == 2) + case SP_HP_REGEN_RATE: + if(sd->state.lr_flag != 2) { + sd->hp_regen.value = type2; + sd->hp_regen.rate = val; + } break; - if (type2 < MAX_ITEMGROUP) { //Group bonus - sd->itemgrouphealrate[type2] += val; + case SP_ADDRACE2: + if (!(type2 > RC2_NONE && type2 < RC2_MAX)) + break; + if(sd->state.lr_flag != 2) + sd->right_weapon.addrace2[type2] += val; + else + sd->left_weapon.addrace2[type2] += val; break; - } - //Standard item bonus. - for(i=0; i < ARRAYLENGTH(sd->itemhealrate) && sd->itemhealrate[i].nameid && sd->itemhealrate[i].nameid != type2; i++); - if(i == ARRAYLENGTH(sd->itemhealrate)) { - ShowWarning("pc_bonus2: Reached max (%d) number of item heal bonuses per character!\n", ARRAYLENGTH(sd->itemhealrate)); + case SP_SUBSIZE: + if(sd->state.lr_flag != 2) + sd->subsize[type2]+=val; break; - } - sd->itemhealrate[i].nameid = type2; - sd->itemhealrate[i].rate += val; - break; - case SP_EXP_ADDRACE: - if(sd->state.lr_flag != 2) - sd->expaddrace[type2]+=val; - break; - case SP_SP_GAIN_RACE: - if(sd->state.lr_flag != 2) - sd->sp_gain_race[type2]+=val; - break; - case SP_ADD_MONSTER_DROP_ITEM: - if (sd->state.lr_flag != 2) - pc_bonus_item_drop(sd->add_drop, ARRAYLENGTH(sd->add_drop), type2, 0, (1<<RC_BOSS)|(1<<RC_NONBOSS), val); - break; - case SP_ADD_MONSTER_DROP_ITEMGROUP: - if (sd->state.lr_flag != 2) - pc_bonus_item_drop(sd->add_drop, ARRAYLENGTH(sd->add_drop), 0, type2, (1<<RC_BOSS)|(1<<RC_NONBOSS), val); - break; - case SP_SP_LOSS_RATE: - if(sd->state.lr_flag != 2) { - sd->sp_loss.value = type2; - sd->sp_loss.rate = val; - } - break; - case SP_SP_REGEN_RATE: - if(sd->state.lr_flag != 2) { - sd->sp_regen.value = type2; - sd->sp_regen.rate = val; - } - break; - case SP_HP_DRAIN_VALUE_RACE: - if(!sd->state.lr_flag) { - sd->right_weapon.hp_drain[type2].value += val; - } - else if(sd->state.lr_flag == 1) { - sd->left_weapon.hp_drain[type2].value += val; - } - break; - case SP_SP_DRAIN_VALUE_RACE: - if(!sd->state.lr_flag) { - sd->right_weapon.sp_drain[type2].value += val; - } - else if(sd->state.lr_flag == 1) { - sd->left_weapon.sp_drain[type2].value += val; - } - break; - case SP_IGNORE_MDEF_RATE: - if(sd->state.lr_flag != 2) - sd->ignore_mdef[type2] += val; - break; - case SP_IGNORE_DEF_RATE: - if(sd->state.lr_flag != 2) - sd->ignore_def[type2] += val; - break; - case SP_SP_GAIN_RACE_ATTACK: - if(sd->state.lr_flag != 2) - sd->sp_gain_race_attack[type2] = cap_value(sd->sp_gain_race_attack[type2] + val, 0, INT16_MAX); - break; - case SP_HP_GAIN_RACE_ATTACK: - if(sd->state.lr_flag != 2) - sd->hp_gain_race_attack[type2] = cap_value(sd->hp_gain_race_attack[type2] + val, 0, INT16_MAX); - break; - case SP_SKILL_USE_SP_RATE: //bonus2 bSkillUseSPrate,n,x; - if(sd->state.lr_flag == 2) + case SP_SUBRACE2: + if (!(type2 > RC2_NONE && type2 < RC2_MAX)) + break; + if(sd->state.lr_flag != 2) + sd->subrace2[type2]+=val; break; - ARR_FIND(0, ARRAYLENGTH(sd->skillusesprate), i, sd->skillusesprate[i].id == 0 || sd->skillusesprate[i].id == type2); - if (i == ARRAYLENGTH(sd->skillusesprate)) { - ShowDebug("run_script: bonus2 bSkillUseSPrate reached it's limit (%d skills per character), bonus skill %d (+%d%%) lost.\n", ARRAYLENGTH(sd->skillusesprate), type2, val); + case SP_ADD_ITEM_HEAL_RATE: + if(sd->state.lr_flag == 2) + break; + //Standard item bonus. + for(i=0; i < ARRAYLENGTH(sd->itemhealrate) && sd->itemhealrate[i].nameid && sd->itemhealrate[i].nameid != type2; i++); + if (i == ARRAYLENGTH(sd->itemhealrate)) { + ShowWarning("pc_bonus2: Reached max (%"PRIuS") number of item heal bonuses per character!\n", ARRAYLENGTH(sd->itemhealrate)); + break; + } + sd->itemhealrate[i].nameid = type2; + sd->itemhealrate[i].rate += val; break; - } - if (sd->skillusesprate[i].id == type2) - sd->skillusesprate[i].val += val; - else { - sd->skillusesprate[i].id = type2; - sd->skillusesprate[i].val = val; - } - break; - case SP_SKILL_COOLDOWN: - if(sd->state.lr_flag == 2) + case SP_EXP_ADDRACE: + if(sd->state.lr_flag != 2) + sd->expaddrace[type2]+=val; break; - ARR_FIND(0, ARRAYLENGTH(sd->skillcooldown), i, sd->skillcooldown[i].id == 0 || sd->skillcooldown[i].id == type2); - if (i == ARRAYLENGTH(sd->skillcooldown)) - { - ShowDebug("run_script: bonus2 bSkillCoolDown reached it's limit (%d skills per character), bonus skill %d (+%d%%) lost.\n", ARRAYLENGTH(sd->skillcooldown), type2, val); + case SP_SP_GAIN_RACE: + if(sd->state.lr_flag != 2) + sd->sp_gain_race[type2]+=val; break; - } - if (sd->skillcooldown[i].id == type2) - sd->skillcooldown[i].val += val; - else { - sd->skillcooldown[i].id = type2; - sd->skillcooldown[i].val = val; - } - break; - case SP_SKILL_FIXEDCAST: - if(sd->state.lr_flag == 2) + case SP_ADD_MONSTER_DROP_ITEM: + if (sd->state.lr_flag != 2) + pc->bonus_item_drop(sd->add_drop, ARRAYLENGTH(sd->add_drop), type2, 0, (1<<RC_BOSS)|(1<<RC_NONBOSS), val); break; - ARR_FIND(0, ARRAYLENGTH(sd->skillfixcast), i, sd->skillfixcast[i].id == 0 || sd->skillfixcast[i].id == type2); - if (i == ARRAYLENGTH(sd->skillfixcast)) - { - ShowDebug("run_script: bonus2 bSkillFixedCast reached it's limit (%d skills per character), bonus skill %d (+%d%%) lost.\n", ARRAYLENGTH(sd->skillfixcast), type2, val); + case SP_SP_LOSS_RATE: + if(sd->state.lr_flag != 2) { + sd->sp_loss.value = type2; + sd->sp_loss.rate = val; + } break; - } - if (sd->skillfixcast[i].id == type2) - sd->skillfixcast[i].val += val; - else { - sd->skillfixcast[i].id = type2; - sd->skillfixcast[i].val = val; - } - break; - case SP_SKILL_VARIABLECAST: - if(sd->state.lr_flag == 2) + case SP_SP_REGEN_RATE: + if(sd->state.lr_flag != 2) { + sd->sp_regen.value = type2; + sd->sp_regen.rate = val; + } break; - ARR_FIND(0, ARRAYLENGTH(sd->skillvarcast), i, sd->skillvarcast[i].id == 0 || sd->skillvarcast[i].id == type2); - if (i == ARRAYLENGTH(sd->skillvarcast)) - { - ShowDebug("run_script: bonus2 bSkillVariableCast reached it's limit (%d skills per character), bonus skill %d (+%d%%) lost.\n", ARRAYLENGTH(sd->skillvarcast), type2, val); + case SP_HP_DRAIN_VALUE_RACE: + if(!sd->state.lr_flag) { + sd->right_weapon.hp_drain[type2].value += val; + } + else if(sd->state.lr_flag == 1) { + sd->left_weapon.hp_drain[type2].value += val; + } break; - } - if (sd->skillvarcast[i].id == type2) - sd->skillvarcast[i].val += val; - else { - sd->skillvarcast[i].id = type2; - sd->skillvarcast[i].val = val; - } - break; -#ifdef RENEWAL_CAST - case SP_VARCASTRATE: - if(sd->state.lr_flag == 2) + case SP_SP_DRAIN_VALUE_RACE: + if(!sd->state.lr_flag) { + sd->right_weapon.sp_drain[type2].value += val; + } + else if(sd->state.lr_flag == 1) { + sd->left_weapon.sp_drain[type2].value += val; + } break; - ARR_FIND(0, ARRAYLENGTH(sd->skillcast), i, sd->skillcast[i].id == 0 || sd->skillcast[i].id == type2); - if (i == ARRAYLENGTH(sd->skillcast)) - { - ShowDebug("run_script: bonus2 bVariableCastrate reached it's limit (%d skills per character), bonus skill %d (+%d%%) lost.\n",ARRAYLENGTH(sd->skillcast), type2, val); + case SP_IGNORE_MDEF_RATE: + if(sd->state.lr_flag != 2) + sd->ignore_mdef[type2] += val; break; - } - if(sd->skillcast[i].id == type2) - sd->skillcast[i].val -= val; - else { - sd->skillcast[i].id = type2; - sd->skillcast[i].val -= val; - } - break; -#endif - case SP_SKILL_USE_SP: //bonus2 bSkillUseSP,n,x; - if(sd->state.lr_flag == 2) + case SP_IGNORE_DEF_RATE: + if(sd->state.lr_flag != 2) + sd->ignore_def[type2] += val; break; - ARR_FIND(0, ARRAYLENGTH(sd->skillusesp), i, sd->skillusesp[i].id == 0 || sd->skillusesp[i].id == type2); - if (i == ARRAYLENGTH(sd->skillusesp)) { - ShowDebug("run_script: bonus2 bSkillUseSP reached it's limit (%d skills per character), bonus skill %d (+%d%%) lost.\n", ARRAYLENGTH(sd->skillusesp), type2, val); + case SP_SP_GAIN_RACE_ATTACK: + if(sd->state.lr_flag != 2) + sd->sp_gain_race_attack[type2] = cap_value(sd->sp_gain_race_attack[type2] + val, 0, INT16_MAX); + break; + case SP_HP_GAIN_RACE_ATTACK: + if(sd->state.lr_flag != 2) + sd->hp_gain_race_attack[type2] = cap_value(sd->hp_gain_race_attack[type2] + val, 0, INT16_MAX); + break; + case SP_SKILL_USE_SP_RATE: //bonus2 bSkillUseSPrate,n,x; + if(sd->state.lr_flag == 2) + break; + ARR_FIND(0, ARRAYLENGTH(sd->skillusesprate), i, sd->skillusesprate[i].id == 0 || sd->skillusesprate[i].id == type2); + if (i == ARRAYLENGTH(sd->skillusesprate)) { + ShowDebug("script->run: bonus2 bSkillUseSPrate reached it's limit (%"PRIuS" skills per character), bonus skill %d (+%d%%) lost.\n", + ARRAYLENGTH(sd->skillusesprate), type2, val); + break; + } + if (sd->skillusesprate[i].id == type2) + sd->skillusesprate[i].val += val; + else { + sd->skillusesprate[i].id = type2; + sd->skillusesprate[i].val = val; + } + break; + case SP_SKILL_COOLDOWN: + if(sd->state.lr_flag == 2) + break; + ARR_FIND(0, ARRAYLENGTH(sd->skillcooldown), i, sd->skillcooldown[i].id == 0 || sd->skillcooldown[i].id == type2); + if (i == ARRAYLENGTH(sd->skillcooldown)) { + ShowDebug("script->run: bonus2 bSkillCoolDown reached it's limit (%"PRIuS" skills per character), bonus skill %d (+%d%%) lost.\n", + ARRAYLENGTH(sd->skillcooldown), type2, val); + break; + } + if (sd->skillcooldown[i].id == type2) + sd->skillcooldown[i].val += val; + else { + sd->skillcooldown[i].id = type2; + sd->skillcooldown[i].val = val; + } + break; + case SP_SKILL_FIXEDCAST: + if(sd->state.lr_flag == 2) + break; + ARR_FIND(0, ARRAYLENGTH(sd->skillfixcast), i, sd->skillfixcast[i].id == 0 || sd->skillfixcast[i].id == type2); + if (i == ARRAYLENGTH(sd->skillfixcast)) { + ShowDebug("script->run: bonus2 bSkillFixedCast reached it's limit (%"PRIuS" skills per character), bonus skill %d (+%d%%) lost.\n", + ARRAYLENGTH(sd->skillfixcast), type2, val); + break; + } + if (sd->skillfixcast[i].id == type2) + sd->skillfixcast[i].val += val; + else { + sd->skillfixcast[i].id = type2; + sd->skillfixcast[i].val = val; + } + break; + case SP_SKILL_VARIABLECAST: + if(sd->state.lr_flag == 2) + break; + ARR_FIND(0, ARRAYLENGTH(sd->skillvarcast), i, sd->skillvarcast[i].id == 0 || sd->skillvarcast[i].id == type2); + if (i == ARRAYLENGTH(sd->skillvarcast)) { + ShowDebug("script->run: bonus2 bSkillVariableCast reached it's limit (%"PRIuS" skills per character), bonus skill %d (+%d%%) lost.\n", + ARRAYLENGTH(sd->skillvarcast), type2, val); + break; + } + if (sd->skillvarcast[i].id == type2) + sd->skillvarcast[i].val += val; + else { + sd->skillvarcast[i].id = type2; + sd->skillvarcast[i].val = val; + } + break; + #ifdef RENEWAL_CAST + case SP_VARCASTRATE: + if(sd->state.lr_flag == 2) + break; + ARR_FIND(0, ARRAYLENGTH(sd->skillcast), i, sd->skillcast[i].id == 0 || sd->skillcast[i].id == type2); + if (i == ARRAYLENGTH(sd->skillcast)) { + ShowDebug("script->run: bonus2 bVariableCastrate reached it's limit (%"PRIuS" skills per character), bonus skill %d (+%d%%) lost.\n", + ARRAYLENGTH(sd->skillcast), type2, val); + break; + } + if(sd->skillcast[i].id == type2) + sd->skillcast[i].val -= val; + else { + sd->skillcast[i].id = type2; + sd->skillcast[i].val -= val; + } + break; + #endif + case SP_SKILL_USE_SP: //bonus2 bSkillUseSP,n,x; + if(sd->state.lr_flag == 2) + break; + ARR_FIND(0, ARRAYLENGTH(sd->skillusesp), i, sd->skillusesp[i].id == 0 || sd->skillusesp[i].id == type2); + if (i == ARRAYLENGTH(sd->skillusesp)) { + ShowDebug("script->run: bonus2 bSkillUseSP reached it's limit (%"PRIuS" skills per character), bonus skill %d (+%d%%) lost.\n", + ARRAYLENGTH(sd->skillusesp), type2, val); + break; + } + if (sd->skillusesp[i].id == type2) + sd->skillusesp[i].val += val; + else { + sd->skillusesp[i].id = type2; + sd->skillusesp[i].val = val; + } + break; + case SP_ADD_MONSTER_DROP_CHAINITEM: + if (sd->state.lr_flag != 2) + pc->bonus_item_drop(sd->add_drop, ARRAYLENGTH(sd->add_drop), 0, val, 1<<type2, 10000); + break; + default: + ShowWarning("pc_bonus2: unknown type %d %d %d!\n",type,type2,val); break; - } - if (sd->skillusesp[i].id == type2) - sd->skillusesp[i].val += val; - else { - sd->skillusesp[i].id = type2; - sd->skillusesp[i].val = val; - } - break; - default: - ShowWarning("pc_bonus2: unknown type %d %d %d!\n",type,type2,val); - break; } return 0; } @@ -3248,161 +3327,185 @@ int pc_bonus3(struct map_session_data *sd,int type,int type2,int type3,int val) nullpo_ret(sd); switch(type){ - case SP_ADD_MONSTER_DROP_ITEM: - if(sd->state.lr_flag != 2) - pc_bonus_item_drop(sd->add_drop, ARRAYLENGTH(sd->add_drop), type2, 0, 1<<type3, val); - break; - case SP_ADD_CLASS_DROP_ITEM: - if(sd->state.lr_flag != 2) - pc_bonus_item_drop(sd->add_drop, ARRAYLENGTH(sd->add_drop), type2, 0, -type3, val); - break; - case SP_AUTOSPELL: - if(sd->state.lr_flag != 2) - { - int target = skill->get_inf(type2); //Support or Self (non-auto-target) skills should pick self. - target = target&INF_SUPPORT_SKILL || (target&INF_SELF_SKILL && !(skill->get_inf2(type2)&INF2_NO_TARGET_SELF)); - pc_bonus_autospell(sd->autospell, ARRAYLENGTH(sd->autospell), - target?-type2:type2, type3, val, 0, current_equip_card_id); - } - break; - case SP_AUTOSPELL_WHENHIT: - if(sd->state.lr_flag != 2) - { - int target = skill->get_inf(type2); //Support or Self (non-auto-target) skills should pick self. - target = target&INF_SUPPORT_SKILL || (target&INF_SELF_SKILL && !(skill->get_inf2(type2)&INF2_NO_TARGET_SELF)); - pc_bonus_autospell(sd->autospell2, ARRAYLENGTH(sd->autospell2), - target?-type2:type2, type3, val, BF_NORMAL|BF_SKILL, current_equip_card_id); - } - break; - case SP_SP_DRAIN_RATE: - if(!sd->state.lr_flag) { - sd->right_weapon.sp_drain[RC_NONBOSS].rate += type2; - sd->right_weapon.sp_drain[RC_NONBOSS].per += type3; - sd->right_weapon.sp_drain[RC_NONBOSS].type = val; - sd->right_weapon.sp_drain[RC_BOSS].rate += type2; - sd->right_weapon.sp_drain[RC_BOSS].per += type3; - sd->right_weapon.sp_drain[RC_BOSS].type = val; - - } - else if(sd->state.lr_flag == 1) { - sd->left_weapon.sp_drain[RC_NONBOSS].rate += type2; - sd->left_weapon.sp_drain[RC_NONBOSS].per += type3; - sd->left_weapon.sp_drain[RC_NONBOSS].type = val; - sd->left_weapon.sp_drain[RC_BOSS].rate += type2; - sd->left_weapon.sp_drain[RC_BOSS].per += type3; - sd->left_weapon.sp_drain[RC_BOSS].type = val; - } - break; - case SP_HP_DRAIN_RATE_RACE: - if(!sd->state.lr_flag) { - sd->right_weapon.hp_drain[type2].rate += type3; - sd->right_weapon.hp_drain[type2].per += val; - } - else if(sd->state.lr_flag == 1) { - sd->left_weapon.hp_drain[type2].rate += type3; - sd->left_weapon.hp_drain[type2].per += val; - } - break; - case SP_SP_DRAIN_RATE_RACE: - if(!sd->state.lr_flag) { - sd->right_weapon.sp_drain[type2].rate += type3; - sd->right_weapon.sp_drain[type2].per += val; - } - else if(sd->state.lr_flag == 1) { - sd->left_weapon.sp_drain[type2].rate += type3; - sd->left_weapon.sp_drain[type2].per += val; - } - break; - case SP_ADD_MONSTER_DROP_ITEMGROUP: - if (sd->state.lr_flag != 2) - pc_bonus_item_drop(sd->add_drop, ARRAYLENGTH(sd->add_drop), 0, type2, 1<<type3, val); - break; + case SP_ADD_MONSTER_DROP_ITEM: + if(sd->state.lr_flag != 2) + pc->bonus_item_drop(sd->add_drop, ARRAYLENGTH(sd->add_drop), type2, 0, 1<<type3, val); + break; + case SP_ADD_CLASS_DROP_ITEM: + if(sd->state.lr_flag != 2) + pc->bonus_item_drop(sd->add_drop, ARRAYLENGTH(sd->add_drop), type2, 0, -type3, val); + break; + case SP_AUTOSPELL: + if(sd->state.lr_flag != 2) + { + int target = skill->get_inf(type2); //Support or Self (non-auto-target) skills should pick self. + target = target&INF_SUPPORT_SKILL || (target&INF_SELF_SKILL && !(skill->get_inf2(type2)&INF2_NO_TARGET_SELF)); + pc->bonus_autospell(sd->autospell, ARRAYLENGTH(sd->autospell), + target?-type2:type2, type3, val, 0, status->current_equip_card_id); + } + break; + case SP_AUTOSPELL_WHENHIT: + if(sd->state.lr_flag != 2) + { + int target = skill->get_inf(type2); //Support or Self (non-auto-target) skills should pick self. + target = target&INF_SUPPORT_SKILL || (target&INF_SELF_SKILL && !(skill->get_inf2(type2)&INF2_NO_TARGET_SELF)); + pc->bonus_autospell(sd->autospell2, ARRAYLENGTH(sd->autospell2), + target?-type2:type2, type3, val, BF_NORMAL|BF_SKILL, status->current_equip_card_id); + } + break; + case SP_SP_DRAIN_RATE: + if(!sd->state.lr_flag) { + sd->right_weapon.sp_drain[RC_NONBOSS].rate += type2; + sd->right_weapon.sp_drain[RC_NONBOSS].per += type3; + sd->right_weapon.sp_drain[RC_NONBOSS].type = val; + sd->right_weapon.sp_drain[RC_BOSS].rate += type2; + sd->right_weapon.sp_drain[RC_BOSS].per += type3; + sd->right_weapon.sp_drain[RC_BOSS].type = val; - case SP_ADDEFF: - if (type2 > SC_MAX) { - ShowWarning("pc_bonus3 (Add Effect): %d is not supported.\n", type2); + } + else if(sd->state.lr_flag == 1) { + sd->left_weapon.sp_drain[RC_NONBOSS].rate += type2; + sd->left_weapon.sp_drain[RC_NONBOSS].per += type3; + sd->left_weapon.sp_drain[RC_NONBOSS].type = val; + sd->left_weapon.sp_drain[RC_BOSS].rate += type2; + sd->left_weapon.sp_drain[RC_BOSS].per += type3; + sd->left_weapon.sp_drain[RC_BOSS].type = val; + } + break; + case SP_HP_DRAIN_RATE_RACE: + if(!sd->state.lr_flag) { + sd->right_weapon.hp_drain[type2].rate += type3; + sd->right_weapon.hp_drain[type2].per += val; + } + else if(sd->state.lr_flag == 1) { + sd->left_weapon.hp_drain[type2].rate += type3; + sd->left_weapon.hp_drain[type2].per += val; + } + break; + case SP_SP_DRAIN_RATE_RACE: + if(!sd->state.lr_flag) { + sd->right_weapon.sp_drain[type2].rate += type3; + sd->right_weapon.sp_drain[type2].per += val; + } + else if(sd->state.lr_flag == 1) { + sd->left_weapon.sp_drain[type2].rate += type3; + sd->left_weapon.sp_drain[type2].per += val; + } + break; + case SP_ADDEFF: + if (type2 > SC_MAX) { + ShowWarning("pc_bonus3 (Add Effect): %d is not supported.\n", type2); + break; + } + pc->bonus_addeff(sd->addeff, ARRAYLENGTH(sd->addeff), (sc_type)type2, + sd->state.lr_flag!=2?type3:0, sd->state.lr_flag==2?type3:0, val); break; - } - pc_bonus_addeff(sd->addeff, ARRAYLENGTH(sd->addeff), (sc_type)type2, - sd->state.lr_flag!=2?type3:0, sd->state.lr_flag==2?type3:0, val); - break; - case SP_ADDEFF_WHENHIT: - if (type2 > SC_MAX) { - ShowWarning("pc_bonus3 (Add Effect when hit): %d is not supported.\n", type2); + case SP_ADDEFF_WHENHIT: + if (type2 > SC_MAX) { + ShowWarning("pc_bonus3 (Add Effect when hit): %d is not supported.\n", type2); + break; + } + if(sd->state.lr_flag != 2) + pc->bonus_addeff(sd->addeff2, ARRAYLENGTH(sd->addeff2), (sc_type)type2, type3, 0, val); break; - } - if(sd->state.lr_flag != 2) - pc_bonus_addeff(sd->addeff2, ARRAYLENGTH(sd->addeff2), (sc_type)type2, type3, 0, val); - break; - case SP_ADDEFF_ONSKILL: - if( type3 > SC_MAX ) { - ShowWarning("pc_bonus3 (Add Effect on skill): %d is not supported.\n", type3); + case SP_ADDEFF_ONSKILL: + if( type3 > SC_MAX ) { + ShowWarning("pc_bonus3 (Add Effect on skill): %d is not supported.\n", type3); + break; + } + if( sd->state.lr_flag != 2 ) + pc->bonus_addeff_onskill(sd->addeff3, ARRAYLENGTH(sd->addeff3), (sc_type)type3, val, type2, ATF_TARGET); break; - } - if( sd->state.lr_flag != 2 ) - pc_bonus_addeff_onskill(sd->addeff3, ARRAYLENGTH(sd->addeff3), (sc_type)type3, val, type2, ATF_TARGET); - break; - case SP_ADDELE: - if (type2 > ELE_MAX) { - ShowWarning("pc_bonus3 (SP_ADDELE): element %d is out of range.\n", type2); + case SP_ADDELE: + if (type2 > ELE_MAX) { + ShowWarning("pc_bonus3 (SP_ADDELE): element %d is out of range.\n", type2); + break; + } + if (sd->state.lr_flag != 2) + pc_bonus_addele(sd, (unsigned char)type2, type3, val); break; - } - if (sd->state.lr_flag != 2) - pc_bonus_addele(sd, (unsigned char)type2, type3, val); - break; - case SP_SUBELE: - if (type2 > ELE_MAX) { - ShowWarning("pc_bonus3 (SP_SUBELE): element %d is out of range.\n", type2); + case SP_SUBELE: + if (type2 > ELE_MAX) { + ShowWarning("pc_bonus3 (SP_SUBELE): element %d is out of range.\n", type2); + break; + } + if (sd->state.lr_flag != 2) + pc_bonus_subele(sd, (unsigned char)type2, type3, val); + break; + case SP_SP_VANISH_RATE: + if(sd->state.lr_flag != 2) { + sd->bonus.sp_vanish_rate += type2; + sd->bonus.sp_vanish_per = max(sd->bonus.sp_vanish_per,type3); + sd->bonus.sp_vanish_trigger=val; + } break; - } - if (sd->state.lr_flag != 2) - pc_bonus_subele(sd, (unsigned char)type2, type3, val); - break; - default: - ShowWarning("pc_bonus3: unknown type %d %d %d %d!\n",type,type2,type3,val); - break; + default: + ShowWarning("pc_bonus3: unknown type %d %d %d %d!\n",type,type2,type3,val); + break; } return 0; } -int pc_bonus4(struct map_session_data *sd,int type,int type2,int type3,int type4,int val) -{ +int pc_bonus4(struct map_session_data *sd,int type,int type2,int type3,int type4,int val) { nullpo_ret(sd); - switch(type){ + switch(type) { case SP_AUTOSPELL: if(sd->state.lr_flag != 2) - pc_bonus_autospell(sd->autospell, ARRAYLENGTH(sd->autospell), (val&1?type2:-type2), (val&2?-type3:type3), type4, 0, current_equip_card_id); + pc->bonus_autospell(sd->autospell, ARRAYLENGTH(sd->autospell), (val&1?type2:-type2), (val&2?-type3:type3), type4, 0, status->current_equip_card_id); break; case SP_AUTOSPELL_WHENHIT: if(sd->state.lr_flag != 2) - pc_bonus_autospell(sd->autospell2, ARRAYLENGTH(sd->autospell2), (val&1?type2:-type2), (val&2?-type3:type3), type4, BF_NORMAL|BF_SKILL, current_equip_card_id); + pc->bonus_autospell(sd->autospell2, ARRAYLENGTH(sd->autospell2), (val&1?type2:-type2), (val&2?-type3:type3), type4, BF_NORMAL|BF_SKILL, status->current_equip_card_id); break; case SP_AUTOSPELL_ONSKILL: - if(sd->state.lr_flag != 2) - { + if(sd->state.lr_flag != 2) { int target = skill->get_inf(type2); //Support or Self (non-auto-target) skills should pick self. target = target&INF_SUPPORT_SKILL || (target&INF_SELF_SKILL && !(skill->get_inf2(type2)&INF2_NO_TARGET_SELF)); - pc_bonus_autospell_onskill(sd->autospell3, ARRAYLENGTH(sd->autospell3), type2, target?-type3:type3, type4, val, current_equip_card_id); + pc->bonus_autospell_onskill(sd->autospell3, ARRAYLENGTH(sd->autospell3), type2, target?-type3:type3, type4, val, status->current_equip_card_id); } break; case SP_ADDEFF_ONSKILL: if( type2 > SC_MAX ) { - ShowWarning("pc_bonus3 (Add Effect on skill): %d is not supported.\n", type2); + ShowWarning("pc_bonus4 (Add Effect on skill): %d is not supported.\n", type2); break; } if( sd->state.lr_flag != 2 ) - pc_bonus_addeff_onskill(sd->addeff3, ARRAYLENGTH(sd->addeff3), (sc_type)type3, type4, type2, val); + pc->bonus_addeff_onskill(sd->addeff3, ARRAYLENGTH(sd->addeff3), (sc_type)type3, type4, type2, val); + break; + + case SP_SET_DEF_RACE: //bonus4 bSetDefRace,n,x,r,y; + if( type2 > RC_MAX ) { + ShowWarning("pc_bonus4 (DEF_SET): %d is not supported.\n", type2); + break; + } + if(sd->state.lr_flag == 2) + break; + sd->def_set_race[type2].rate = type3; + sd->def_set_race[type2].tick = type4; + sd->def_set_race[type2].value = val; + break; + + case SP_SET_MDEF_RACE: //bonus4 bSetMDefRace,n,x,r,y; + if( type2 > RC_MAX ) { + ShowWarning("pc_bonus4 (MDEF_SET): %d is not supported.\n", type2); + break; + } + if(sd->state.lr_flag == 2) + break; + sd->mdef_set_race[type2].rate = type3; + sd->mdef_set_race[type2].tick = type4; + sd->mdef_set_race[type2].value = val; break; default: @@ -3413,29 +3516,28 @@ int pc_bonus4(struct map_session_data *sd,int type,int type2,int type3,int type4 return 0; } -int pc_bonus5(struct map_session_data *sd,int type,int type2,int type3,int type4,int type5,int val) -{ +int pc_bonus5(struct map_session_data *sd,int type,int type2,int type3,int type4,int type5,int val) { nullpo_ret(sd); switch(type){ - case SP_AUTOSPELL: - if(sd->state.lr_flag != 2) - pc_bonus_autospell(sd->autospell, ARRAYLENGTH(sd->autospell), (val&1?type2:-type2), (val&2?-type3:type3), type4, type5, current_equip_card_id); - break; + case SP_AUTOSPELL: + if(sd->state.lr_flag != 2) + pc->bonus_autospell(sd->autospell, ARRAYLENGTH(sd->autospell), (val&1?type2:-type2), (val&2?-type3:type3), type4, type5, status->current_equip_card_id); + break; - case SP_AUTOSPELL_WHENHIT: - if(sd->state.lr_flag != 2) - pc_bonus_autospell(sd->autospell2, ARRAYLENGTH(sd->autospell2), (val&1?type2:-type2), (val&2?-type3:type3), type4, type5, current_equip_card_id); - break; + case SP_AUTOSPELL_WHENHIT: + if(sd->state.lr_flag != 2) + pc->bonus_autospell(sd->autospell2, ARRAYLENGTH(sd->autospell2), (val&1?type2:-type2), (val&2?-type3:type3), type4, type5, status->current_equip_card_id); + break; - case SP_AUTOSPELL_ONSKILL: - if(sd->state.lr_flag != 2) - pc_bonus_autospell_onskill(sd->autospell3, ARRAYLENGTH(sd->autospell3), type2, (val&1?-type3:type3), (val&2?-type4:type4), type5, current_equip_card_id); - break; + case SP_AUTOSPELL_ONSKILL: + if(sd->state.lr_flag != 2) + pc->bonus_autospell_onskill(sd->autospell3, ARRAYLENGTH(sd->autospell3), type2, (val&1?-type3:type3), (val&2?-type4:type4), type5, status->current_equip_card_id); + break; - default: - ShowWarning("pc_bonus5: unknown type %d %d %d %d %d %d!\n",type,type2,type3,type4,type5,val); - break; + default: + ShowWarning("pc_bonus5: unknown type %d %d %d %d %d %d!\n",type,type2,type3,type4,type5,val); + break; } return 0; @@ -3452,7 +3554,7 @@ int pc_skill(TBL_PC* sd, int id, int level, int flag) { uint16 index = 0; nullpo_ret(sd); - if( !(index = skill->get_index(id)) || skill_db[index].name == NULL) { + if( !(index = skill->get_index(id)) || skill->db[index].name == NULL) { ShowError("pc_skill: Skill with id %d does not exist in the skill database\n", id); return 0; } @@ -3475,8 +3577,8 @@ int pc_skill(TBL_PC* sd, int id, int level, int flag) { clif->deleteskill(sd,id); } else clif->addskill(sd,id); - if( !skill_db[index].inf ) //Only recalculate for passive skills. - status_calc_pc(sd, 0); + if( !skill->db[index].inf ) //Only recalculate for passive skills. + status_calc_pc(sd, SCO_NONE); break; case 1: //Item bonus skill. if( sd->status.skill[index].id == id ) { @@ -3509,8 +3611,8 @@ int pc_skill(TBL_PC* sd, int id, int level, int flag) { clif->deleteskill(sd,id); } else clif->addskill(sd,id); - if( !skill_db[index].inf ) //Only recalculate for passive skills. - status_calc_pc(sd, 0); + if( !skill->db[index].inf ) //Only recalculate for passive skills. + status_calc_pc(sd, SCO_NONE); break; default: //Unknown flag? return 0; @@ -3579,13 +3681,12 @@ int pc_insert_card(struct map_session_data* sd, int idx_card, int idx_equip) /*========================================== * Update buying value by skills *------------------------------------------*/ -int pc_modifybuyvalue(struct map_session_data *sd,int orig_value) -{ - int skill,val = orig_value,rate1 = 0,rate2 = 0; - if((skill=pc->checkskill(sd,MC_DISCOUNT))>0) // merchant discount - rate1 = 5+skill*2-((skill==10)? 1:0); - if((skill=pc->checkskill(sd,RG_COMPULSION))>0) // rogue discount - rate2 = 5+skill*4; +int pc_modifybuyvalue(struct map_session_data *sd,int orig_value) { + int skill_lv,val = orig_value,rate1 = 0,rate2 = 0; + if((skill_lv=pc->checkskill(sd,MC_DISCOUNT))>0) // merchant discount + rate1 = 5+skill_lv*2-((skill_lv==10)? 1:0); + if((skill_lv=pc->checkskill(sd,RG_COMPULSION))>0) // rogue discount + rate2 = 5+skill_lv*4; if(rate1 < rate2) rate1 = rate2; if(rate1) val = (int)((double)orig_value*(double)(100-rate1)/100.); @@ -3598,11 +3699,10 @@ int pc_modifybuyvalue(struct map_session_data *sd,int orig_value) /*========================================== * Update selling value by skills *------------------------------------------*/ -int pc_modifysellvalue(struct map_session_data *sd,int orig_value) -{ - int skill,val = orig_value,rate = 0; - if((skill=pc->checkskill(sd,MC_OVERCHARGE))>0) //OverCharge - rate = 5+skill*2-((skill==10)? 1:0); +int pc_modifysellvalue(struct map_session_data *sd,int orig_value) { + int skill_lv,val = orig_value,rate = 0; + if((skill_lv=pc->checkskill(sd,MC_OVERCHARGE))>0) //OverCharge + rate = 5+skill_lv*2-((skill_lv==10)? 1:0); if(rate) val = (int)((double)orig_value*(double)(100+rate)/100.); if(val < 0) val = 0; @@ -3625,9 +3725,9 @@ int pc_checkadditem(struct map_session_data *sd,int nameid,int amount) if(amount > MAX_AMOUNT) return ADDITEM_OVERAMOUNT; - data = itemdb_search(nameid); + data = itemdb->search(nameid); - if(!itemdb_isstackable2(data)) + if(!itemdb->isstackable2(data)) return ADDITEM_NEW; if( data->stack.inventory && amount > data->stack.amount ) @@ -3688,7 +3788,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,strlen(output)); } return 0; @@ -3723,14 +3823,14 @@ int pc_paycash(struct map_session_data *sd, int price, int points) return -1; } - pc_setaccountreg(sd, "#CASHPOINTS", sd->cashPoints-cash); - pc_setaccountreg(sd, "#KAFRAPOINTS", sd->kafraPoints-points); + pc_setaccountreg(sd, script->add_str("#CASHPOINTS"), sd->cashPoints-cash); + pc_setaccountreg(sd, script->add_str("#KAFRAPOINTS"), sd->kafraPoints-points); if( battle_config.cashshop_show_points ) { char output[128]; sprintf(output, msg_txt(504), points, cash, sd->kafraPoints, sd->cashPoints); - clif->disp_onlyself(sd, output, strlen(output)); + clif_disp_onlyself(sd, output, strlen(output)); } return cash+points; } @@ -3750,12 +3850,12 @@ int pc_getcash(struct map_session_data *sd, int cash, int points) cash = MAX_ZENY-sd->cashPoints; } - pc_setaccountreg(sd, "#CASHPOINTS", sd->cashPoints+cash); + pc_setaccountreg(sd, script->add_str("#CASHPOINTS"), sd->cashPoints+cash); if( battle_config.cashshop_show_points ) { sprintf(output, msg_txt(505), cash, sd->cashPoints); - clif->disp_onlyself(sd, output, strlen(output)); + clif_disp_onlyself(sd, output, strlen(output)); } return cash; } @@ -3773,12 +3873,12 @@ int pc_getcash(struct map_session_data *sd, int cash, int points) points = MAX_ZENY-sd->kafraPoints; } - pc_setaccountreg(sd, "#KAFRAPOINTS", sd->kafraPoints+points); + pc_setaccountreg(sd, script->add_str("#KAFRAPOINTS"), sd->kafraPoints+points); if( battle_config.cashshop_show_points ) { sprintf(output, msg_txt(506), points, sd->kafraPoints); - clif->disp_onlyself(sd, output, strlen(output)); + clif_disp_onlyself(sd, output, strlen(output)); } return points; } @@ -3816,22 +3916,29 @@ 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,strlen(output)); } return 0; } -/*========================================== - * Searching a specified itemid in inventory and return his stored index - *------------------------------------------*/ -int pc_search_inventory(struct map_session_data *sd,int item_id) -{ +/** + * Searches for the specified item ID in inventory and return its inventory index. + * + * If the item is found, the returned value is guaranteed to be a valid index + * (non-negative, smaller than MAX_INVENTORY). + * + * @param sd Character to search on. + * @param item_id The item ID to search. + * @return the inventory index of the first instance of the requested item. + * @retval INDEX_NOT_FOUND if the item wasn't found. + */ +int pc_search_inventory(struct map_session_data *sd, int item_id) { int i; - nullpo_retr(-1, sd); + nullpo_retr(INDEX_NOT_FOUND, sd); ARR_FIND( 0, MAX_INVENTORY, i, sd->status.inventory[i].nameid == item_id && (sd->status.inventory[i].amount > 0 || item_id == 0) ); - return ( i < MAX_INVENTORY ) ? i : -1; + return ( i < MAX_INVENTORY ) ? i : INDEX_NOT_FOUND; } /*========================================== @@ -3840,11 +3947,11 @@ int pc_search_inventory(struct map_session_data *sd,int item_id) 0 = success 1 = invalid itemid not found or negative amount 2 = overweight - 3 = ? + 3 = ? 4 = no free place found 5 = max amount reached - 6 = ? - 7 = stack limitation + 6 = ? + 7 = stack limitation *------------------------------------------*/ int pc_additem(struct map_session_data *sd,struct item *item_data,int amount,e_log_pick_type log_type) { @@ -3860,7 +3967,7 @@ int pc_additem(struct map_session_data *sd,struct item *item_data,int amount,e_l if( amount > MAX_AMOUNT ) return 5; - data = itemdb_search(item_data->nameid); + data = itemdb->search(item_data->nameid); if( data->stack.inventory && amount > data->stack.amount ) {// item stack limitation @@ -3871,14 +3978,37 @@ int pc_additem(struct map_session_data *sd,struct item *item_data,int amount,e_l if(sd->weight + w > sd->max_weight) return 2; + if( item_data->bound ) { + switch( (enum e_item_bound_type)item_data->bound ) { + case IBT_CHARACTER: + case IBT_ACCOUNT: + break; /* no restrictions */ + case IBT_PARTY: + if( !sd->status.party_id ) { + ShowError("pc_additem: can't add party_bound item to character without party!\n"); + ShowError("pc_additem: %s - x%d %s (%d)\n",sd->status.name,amount,data->jname,data->nameid); + return 7;/* need proper code? */ + } + break; + case IBT_GUILD: + if( !sd->status.guild_id ) { + ShowError("pc_additem: can't add guild_bound item to character without guild!\n"); + ShowError("pc_additem: %s - x%d %s (%d)\n",sd->status.name,amount,data->jname,data->nameid); + return 7;/* need proper code? */ + } + break; + } + } + i = MAX_INVENTORY; - if( itemdb_isstackable2(data) && item_data->expire_time == 0 ) - { // Stackable | Non Rental - for( i = 0; i < MAX_INVENTORY; i++ ) - { - if( sd->status.inventory[i].nameid == item_data->nameid && memcmp(&sd->status.inventory[i].card, &item_data->card, sizeof(item_data->card)) == 0 ) - { + // Stackable | Non Rental + if( itemdb->isstackable2(data) && item_data->expire_time == 0 ) { + for( i = 0; i < MAX_INVENTORY; i++ ) { + if( sd->status.inventory[i].nameid == item_data->nameid && + sd->status.inventory[i].bound == item_data->bound && + sd->status.inventory[i].expire_time == 0 && + memcmp(&sd->status.inventory[i].card, &item_data->card, sizeof(item_data->card)) == 0 ) { if( amount > MAX_AMOUNT - sd->status.inventory[i].amount || ( data->stack.inventory && amount > data->stack.amount - sd->status.inventory[i].amount ) ) return 5; sd->status.inventory[i].amount += amount; @@ -3888,25 +4018,26 @@ int pc_additem(struct map_session_data *sd,struct item *item_data,int amount,e_l } } - if( i >= MAX_INVENTORY ) - { + if ( i >= MAX_INVENTORY ) { i = pc->search_inventory(sd,0); - if( i < 0 ) + if (i == INDEX_NOT_FOUND) return 4; memcpy(&sd->status.inventory[i], item_data, sizeof(sd->status.inventory[0])); - // clear equips field first, just in case + // clear equip and favorite fields first, just in case if( item_data->equip ) sd->status.inventory[i].equip = 0; + if( item_data->favorite ) + sd->status.inventory[i].favorite = 0; sd->status.inventory[i].amount = amount; sd->inventory_data[i] = data; clif->additem(sd,i,amount,0); } -#ifdef NSI_UNIQUE_ID - if( !itemdb_isstackable2(data) && !item_data->unique_id ) - sd->status.inventory[i].unique_id = itemdb_unique_id(0,0); -#endif + + if( !itemdb->isstackable2(data) && !item_data->unique_id ) + sd->status.inventory[i].unique_id = itemdb->unique_id(sd); + logs->pick_pc(sd, log_type, amount, &sd->status.inventory[i],sd->inventory_data[i]); sd->weight += w; @@ -3918,8 +4049,7 @@ int pc_additem(struct map_session_data *sd,struct item *item_data,int amount,e_l /* rental item check */ if( item_data->expire_time ) { if( time(NULL) > item_data->expire_time ) { - clif->rental_expired(sd->fd, i, sd->status.inventory[i].nameid); - pc->delitem(sd, i, sd->status.inventory[i].amount, 1, 0, LOG_TYPE_OTHER); + pc->rental_expire(sd,i); } else { int seconds = (int)( item_data->expire_time - time(NULL) ); clif->rental_time(sd->fd, sd->status.inventory[i].nameid, seconds); @@ -3989,8 +4119,7 @@ int pc_dropitem(struct map_session_data *sd,int n,int amount) ) return 0; - if( map[sd->bl.m].flag.nodrop ) - { + if( map->list[sd->bl.m].flag.nodrop ) { clif->message (sd->fd, msg_txt(271)); return 0; //Can't drop items in nodrop mapflag maps. } @@ -4001,7 +4130,7 @@ int pc_dropitem(struct map_session_data *sd,int n,int amount) return 0; } - if (!iMap->addflooritem(&sd->status.inventory[n], amount, sd->bl.m, sd->bl.x, sd->bl.y, 0, 0, 0, 2)) + if (!map->addflooritem(&sd->status.inventory[n], amount, sd->bl.m, sd->bl.x, sd->bl.y, 0, 0, 0, 2)) return 0; pc->delitem(sd, n, amount, 1, 0, LOG_TYPE_PICKDROP_PLAYER); @@ -4018,7 +4147,7 @@ int pc_dropitem(struct map_session_data *sd,int n,int amount) int pc_takeitem(struct map_session_data *sd,struct flooritem_data *fitem) { int flag=0; - unsigned int tick = iTimer->gettick(); + int64 tick = timer->gettick(); struct map_session_data *first_sd = NULL,*second_sd = NULL,*third_sd = NULL; struct party_data *p=NULL; @@ -4031,9 +4160,8 @@ int pc_takeitem(struct map_session_data *sd,struct flooritem_data *fitem) if (sd->status.party_id) p = party->search(sd->status.party_id); - if(fitem->first_get_charid > 0 && fitem->first_get_charid != sd->status.char_id) - { - first_sd = iMap->charid2sd(fitem->first_get_charid); + if(fitem->first_get_charid > 0 && fitem->first_get_charid != sd->status.char_id) { + first_sd = map->charid2sd(fitem->first_get_charid); if(DIFF_TICK(tick,fitem->first_get_tick) < 0) { if (!(p && p->party.item&1 && first_sd && first_sd->status.party_id == sd->status.party_id @@ -4041,9 +4169,8 @@ int pc_takeitem(struct map_session_data *sd,struct flooritem_data *fitem) return 0; } else - if(fitem->second_get_charid > 0 && fitem->second_get_charid != sd->status.char_id) - { - second_sd = iMap->charid2sd(fitem->second_get_charid); + if(fitem->second_get_charid > 0 && fitem->second_get_charid != sd->status.char_id) { + second_sd = map->charid2sd(fitem->second_get_charid); if(DIFF_TICK(tick, fitem->second_get_tick) < 0) { if(!(p && p->party.item&1 && ((first_sd && first_sd->status.party_id == sd->status.party_id) || @@ -4052,9 +4179,8 @@ int pc_takeitem(struct map_session_data *sd,struct flooritem_data *fitem) return 0; } else - if(fitem->third_get_charid > 0 && fitem->third_get_charid != sd->status.char_id) - { - third_sd = iMap->charid2sd(fitem->third_get_charid); + if(fitem->third_get_charid > 0 && fitem->third_get_charid != sd->status.char_id) { + third_sd = map->charid2sd(fitem->third_get_charid); if(DIFF_TICK(tick,fitem->third_get_tick) < 0) { if(!(p && p->party.item&1 && ((first_sd && first_sd->status.party_id == sd->status.party_id) || @@ -4076,7 +4202,7 @@ int pc_takeitem(struct map_session_data *sd,struct flooritem_data *fitem) //Display pickup animation. pc_stop_attack(sd); clif->takeitem(&sd->bl,&fitem->bl); - iMap->clearflooritem(&fitem->bl); + map->clearflooritem(&fitem->bl); return 1; } @@ -4104,96 +4230,97 @@ int pc_isUseitem(struct map_session_data *sd,int n) if( !item->script ) //if it has no script, you can't really consume it! return 0; - if( (item->item_usage.flag&NOUSE_SITTING) && (pc_issit(sd) == 1) && (pc->get_group_level(sd) < item->item_usage.override) ) { - clif->msgtable(sd->fd,664); + if( (item->item_usage.flag&INR_SITTING) && (pc_issit(sd) == 1) && (pc_get_group_level(sd) < item->item_usage.override) ) { + clif->msgtable(sd->fd,0x297); //clif->colormes(sd->fd,COLOR_WHITE,msg_txt(1474)); return 0; // You cannot use this item while sitting. } - switch( nameid ) //@TODO, lot oh harcoded nameid here - { - case 605: // Anodyne - if( map_flag_gvg(sd->bl.m) ) + if (sd->state.storage_flag && item->type != IT_CASH) { + clif->colormes(sd->fd, COLOR_RED, msg_txt(1475)); + return 0; // You cannot use this item while storage is open. + } + + switch( nameid ) { // TODO: Is there no better way to handle this, other than hardcoding item IDs? + case ITEMID_ANODYNE: + if( map_flag_gvg2(sd->bl.m) ) return 0; - case 606: + case ITEMID_ALOEBERA: if( pc_issit(sd) ) return 0; break; - case 601: // Fly Wing - case 12212: // Giant Fly Wing - if( map[sd->bl.m].flag.noteleport || map_flag_gvg(sd->bl.m) ) - { + case ITEMID_WING_OF_FLY: + case ITEMID_GIANT_FLY_WING: + if( map->list[sd->bl.m].flag.noteleport || map_flag_gvg2(sd->bl.m) ) { clif->skill_mapinfomessage(sd,0); return 0; } - case 602: // ButterFly Wing - case 14527: // Dungeon Teleport Scroll - case 14581: // Dungeon Teleport Scroll - case 14582: // Yellow Butterfly Wing - case 14583: // Green Butterfly Wing - case 14584: // Red Butterfly Wing - case 14585: // Blue Butterfly Wing - case 14591: // Siege Teleport Scroll - if( sd->duel_group && !battle_config.duel_allow_teleport ) - { - clif->message(sd->fd, msg_txt(663)); + case ITEMID_WING_OF_BUTTERFLY: + case ITEMID_DUN_TELE_SCROLL1: + case ITEMID_DUN_TELE_SCROLL2: + case ITEMID_WOB_RUNE: // Yellow Butterfly Wing + case ITEMID_WOB_SCHWALTZ: // Green Butterfly Wing + case ITEMID_WOB_RACHEL: // Red Butterfly Wing + case ITEMID_WOB_LOCAL: // Blue Butterfly Wing + case ITEMID_SIEGE_TELEPORT_SCROLL: + if( sd->duel_group && !battle_config.duel_allow_teleport ) { + clif->message(sd->fd, msg_txt(863)); // "Duel: Can't use this item in duel." return 0; } - if( nameid != 601 && nameid != 12212 && map[sd->bl.m].flag.noreturn ) + if( nameid != ITEMID_WING_OF_FLY && nameid != ITEMID_GIANT_FLY_WING && map->list[sd->bl.m].flag.noreturn ) return 0; break; - case 604: // Dead Branch - case 12024: // Red Pouch - case 12103: // Bloody Branch - case 12109: // Poring Box - if( map[sd->bl.m].flag.nobranch || map_flag_gvg(sd->bl.m) ) + case ITEMID_BRANCH_OF_DEAD_TREE: + case ITEMID_RED_POUCH_OF_SURPRISE: + case ITEMID_BLOODY_DEAD_BRANCH: + case ITEMID_PORING_BOX: + if( map->list[sd->bl.m].flag.nobranch || map_flag_gvg2(sd->bl.m) ) return 0; break; - case 12210: // Bubble Gum - case 12264: // Comp Bubble Gum + case ITEMID_BUBBLE_GUM: + case ITEMID_COMP_BUBBLE_GUM: if( sd->sc.data[SC_CASH_RECEIVEITEM] ) return 0; break; - case 12208: // Battle Manual - case 12263: // Comp Battle Manual - case 12312: // Thick Battle Manual - case 12705: // Noble Nameplate - case 14532: // Battle_Manual25 - case 14533: // Battle_Manual100 - case 14545: // Battle_Manual300 + case ITEMID_BATTLE_MANUAL: + case ITEMID_COMP_BATTLE_MANUAL: + case ITEMID_THICK_MANUAL50: + case ITEMID_NOBLE_NAMEPLATE: + case ITEMID_BATTLE_MANUAL25: + case ITEMIDBATTLE_MANUAL100: + case ITEMID_BATTLE_MANUAL_X3: if( sd->sc.data[SC_CASH_PLUSEXP] ) return 0; break; - case 14592: // JOB_Battle_Manual + case ITEMID_JOB_MANUAL50: if( sd->sc.data[SC_CASH_PLUSONLYJOBEXP] ) return 0; break; // Mercenary Items - - case 12184: // Mercenary's Red Potion - case 12185: // Mercenary's Blue Potion - case 12241: // Mercenary's Concentration Potion - case 12242: // Mercenary's Awakening Potion - case 12243: // Mercenary's Berserk Potion + case ITEMID_MERCENARY_RED_POTION: + case ITEMID_MERCENARY_BLUE_POTION: + case ITEMID_M_CENTER_POTION: + case ITEMID_M_AWAKENING_POTION: + case ITEMID_M_BERSERK_POTION: if( sd->md == NULL || sd->md->db == NULL ) return 0; - if (sd->md->sc.data[SC_BERSERK] || sd->md->sc.data[SC_SATURDAY_NIGHT_FEVER] || sd->md->sc.data[SC__BLOODYLUST]) + if (sd->md->sc.data[SC_BERSERK]) return 0; - if( nameid == 12242 && sd->md->db->lv < 40 ) + if( nameid == ITEMID_M_AWAKENING_POTION && sd->md->db->lv < 40 ) return 0; - if( nameid == 12243 && sd->md->db->lv < 80 ) + if( nameid == ITEMID_M_BERSERK_POTION && sd->md->db->lv < 80 ) return 0; break; - case 12213: //Neuralizer - if( !map[sd->bl.m].flag.reset ) + case ITEMID_NEURALIZER: + if( !map->list[sd->bl.m].flag.reset ) return 0; break; } - if( nameid >= 12153 && nameid <= 12182 && sd->md != NULL ) - return 0; // Mercenary Scrolls + if( nameid >= ITEMID_BOW_MERCENARY_SCROLL1 && nameid <= ITEMID_SPEARMERCENARY_SCROLL10 && sd->md != NULL ) // Mercenary Scrolls + return 0; /** * Only Rune Knights may use runes @@ -4206,17 +4333,30 @@ int pc_isUseitem(struct map_session_data *sd,int n) else if( itemdb_is_poison(nameid) && (sd->class_&MAPID_THIRDMASK) != MAPID_GUILLOTINE_CROSS ) return 0; + if( item->package || item->group ) { + if( pc_is90overweight(sd) ) { + clif->msgtable(sd->fd,ITEM_CANT_OBTAIN_WEIGHT); + return 0; + } + if( !pc->inventoryblank(sd) ) { + clif->colormes(sd->fd,COLOR_RED,msg_txt(1477)); + return 0; + } + } + //Gender check if(item->sex != 2 && sd->status.sex != item->sex) return 0; //Required level check - if(item->elv && sd->status.base_level < (unsigned int)item->elv) + if(item->elv && sd->status.base_level < (unsigned int)item->elv){ + clif->msg(sd, 0x6EE); return 0; + } -#ifdef RENEWAL - if(item->elvmax && sd->status.base_level > (unsigned int)item->elvmax) + if(item->elvmax && sd->status.base_level > (unsigned int)item->elvmax){ + clif->msg(sd, 0x6EE); return 0; -#endif + } //Not equipable by class. [Skotlex] if (!( @@ -4224,20 +4364,29 @@ int pc_isUseitem(struct map_session_data *sd,int n) (item->class_base[sd->class_&JOBL_2_1?1:(sd->class_&JOBL_2_2?2:0)]) )) return 0; - //Not usable by upper class. [Inkfish] + + //Not usable by upper class. [Haru] while( 1 ) { - if( item->class_upper&1 && !(sd->class_&(JOBL_UPPER|JOBL_THIRD|JOBL_BABY)) ) break; - if( item->class_upper&2 && sd->class_&(JOBL_UPPER|JOBL_THIRD) ) break; - if( item->class_upper&4 && sd->class_&JOBL_BABY ) break; - if( item->class_upper&8 && sd->class_&JOBL_THIRD ) break; + // Normal classes (no upper, no baby, no third classes) + if( item->class_upper&ITEMUPPER_NORMAL && !(sd->class_&(JOBL_UPPER|JOBL_THIRD|JOBL_BABY)) ) break; +#ifdef RENEWAL + // Upper classes (no third classes) + if( item->class_upper&ITEMUPPER_UPPER && sd->class_&JOBL_UPPER && !(sd->class_&JOBL_THIRD) ) break; +#else + //pre-re has no use for the extra, so we maintain the previous for backwards compatibility + if( item->class_upper&ITEMUPPER_UPPER && sd->class_&(JOBL_UPPER|JOBL_THIRD) ) break; +#endif + // Baby classes (no third classes) + if( item->class_upper&ITEMUPPER_BABY && sd->class_&JOBL_BABY && !(sd->class_&JOBL_THIRD) ) break; + // Third classes (no upper, no baby classes) + if( item->class_upper&ITEMUPPER_THIRD && sd->class_&JOBL_THIRD && !(sd->class_&(JOBL_UPPER|JOBL_BABY)) ) break; + // Upper third classes + if( item->class_upper&ITEMUPPER_THURDUPPER && sd->class_&JOBL_THIRD && sd->class_&JOBL_UPPER ) break; + // Baby third classes + if( item->class_upper&ITEMUPPER_THIRDBABY && sd->class_&JOBL_THIRD && sd->class_&JOBL_BABY ) break; return 0; } - //Dead Branch & Bloody Branch & Porings Box - // FIXME: outdated, use constants or database - if( nameid == 604 || nameid == 12103 || nameid == 12109 ) - logs->branch(sd); - return 1; } @@ -4247,11 +4396,10 @@ int pc_isUseitem(struct map_session_data *sd,int n) * 0 = fail * 1 = success *------------------------------------------*/ -int pc_useitem(struct map_session_data *sd,int n) -{ - unsigned int tick = iTimer->gettick(); +int pc_useitem(struct map_session_data *sd,int n) { + int64 tick = timer->gettick(); int amount, nameid, i; - struct script_code *script; + struct script_code *item_script; nullpo_ret(sd); @@ -4266,7 +4414,7 @@ int pc_useitem(struct map_session_data *sd,int n) if( sd->status.inventory[n].nameid <= 0 || sd->status.inventory[n].amount <= 0 ) return 0; - if( !pc_isUseitem(sd,n) ) + if( !pc->isUseitem(sd,n) ) return 0; // Store information for later use before it is lost (via pc->delitem) [Paradox924X] @@ -4275,15 +4423,20 @@ int pc_useitem(struct map_session_data *sd,int n) if (nameid != ITEMID_NAUTHIZ && sd->sc.opt1 > 0 && sd->sc.opt1 != OPT1_STONEWAIT && sd->sc.opt1 != OPT1_BURNING) return 0; + // Statuses that don't let the player use items if (sd->sc.count && ( - sd->sc.data[SC_BERSERK] || sd->sc.data[SC__BLOODYLUST] || + sd->sc.data[SC_BERSERK] || (sd->sc.data[SC_GRAVITATION] && sd->sc.data[SC_GRAVITATION]->val3 == BCT_SELF) || sd->sc.data[SC_TRICKDEAD] || sd->sc.data[SC_HIDING] || sd->sc.data[SC__SHADOWFORM] || + sd->sc.data[SC__INVISIBILITY] || sd->sc.data[SC__MANHOLE] || sd->sc.data[SC_KG_KAGEHUMI] || sd->sc.data[SC_WHITEIMPRISON] || + sd->sc.data[SC_DEEP_SLEEP] || + sd->sc.data[SC_SATURDAY_NIGHT_FEVER] || + sd->sc.data[SC_COLD] || (sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOITEM) )) return 0; @@ -4305,18 +4458,17 @@ int pc_useitem(struct map_session_data *sd,int n) //perform a skill-use check before going through. [Skotlex] //resurrection was picked as testing skill, as a non-offensive, generic skill, it will do. //FIXME: Is this really needed here? It'll be checked in unit.c after all and this prevents skill items using when silenced [Inkfish] - if( sd->inventory_data[n]->flag.delay_consume && ( sd->ud.skilltimer != INVALID_TIMER /*|| !status_check_skilluse(&sd->bl, &sd->bl, ALL_RESURRECTION, 0)*/ ) ) + if( sd->inventory_data[n]->flag.delay_consume && ( sd->ud.skilltimer != INVALID_TIMER /*|| !status->check_skilluse(&sd->bl, &sd->bl, ALL_RESURRECTION, 0)*/ ) ) return 0; if( sd->inventory_data[n]->delay > 0 ) { - int i; ARR_FIND(0, MAX_ITEMDELAYS, i, sd->item_delay[i].nameid == nameid ); if( i == MAX_ITEMDELAYS ) /* item not found. try first empty now */ ARR_FIND(0, MAX_ITEMDELAYS, i, !sd->item_delay[i].nameid ); if( i < MAX_ITEMDELAYS ) { if( sd->item_delay[i].nameid ) {// found if( DIFF_TICK(sd->item_delay[i].tick, tick) > 0 ) { - int e_tick = DIFF_TICK(sd->item_delay[i].tick, tick)/1000; + int e_tick = (int)(DIFF_TICK(sd->item_delay[i].tick, tick)/1000); clif->msgtable_num(sd->fd, 0x746, e_tick + 1); // [%d] seconds left until you can use return 0; // Delay has not expired yet } @@ -4337,10 +4489,11 @@ int pc_useitem(struct map_session_data *sd,int n) } } - /* on restricted maps the item is consumed but the effect is not used */ - for(i = 0; i < map[sd->bl.m].zone->disabled_items_count; i++) { - if( map[sd->bl.m].zone->disabled_items[i] == nameid ) { - if( battle_config.item_restricted_consumption_type ) { + /* on restricted maps the item is consumed but the effect is not used */ + for(i = 0; i < map->list[sd->bl.m].zone->disabled_items_count; i++) { + if( map->list[sd->bl.m].zone->disabled_items[i] == nameid ) { + clif->msg(sd, ITEM_CANT_USE_AREA); // This item cannot be used within this area + if( battle_config.item_restricted_consumption_type && sd->status.inventory[n].expire_time == 0 ) { clif->useitemack(sd,n,sd->status.inventory[n].amount-1,true); pc->delitem(sd,n,1,1,0,LOG_TYPE_CONSUME); } @@ -4348,13 +4501,17 @@ int pc_useitem(struct map_session_data *sd,int n) } } + //Dead Branch & Bloody Branch & Porings Box + if( nameid == ITEMID_BRANCH_OF_DEAD_TREE || nameid == ITEMID_BLOODY_DEAD_BRANCH || nameid == ITEMID_PORING_BOX ) + logs->branch(sd); + sd->itemid = sd->status.inventory[n].nameid; sd->itemindex = n; if(sd->catch_target_class != -1) //Abort pet catching. sd->catch_target_class = -1; amount = sd->status.inventory[n].amount; - script = sd->inventory_data[n]->script; + item_script = sd->inventory_data[n]->script; //Check if the item is to be consumed immediately [Skotlex] if( sd->inventory_data[n]->flag.delay_consume ) clif->useitemack(sd,n,amount,true); @@ -4368,18 +4525,23 @@ int pc_useitem(struct map_session_data *sd,int n) if(sd->status.inventory[n].card[0]==CARD0_CREATE && pc->famerank(MakeDWord(sd->status.inventory[n].card[2],sd->status.inventory[n].card[3]), MAPID_ALCHEMIST)) { - potion_flag = 2; // Famous player's potions have 50% more efficiency + script->potion_flag = 2; // Famous player's potions have 50% more efficiency if (sd->sc.data[SC_SOULLINK] && sd->sc.data[SC_SOULLINK]->val2 == SL_ROGUE) - potion_flag = 3; //Even more effective potions. + script->potion_flag = 3; //Even more effective potions. } //Update item use time. sd->canuseitem_tick = tick + battle_config.item_use_interval; if( itemdb_iscashfood(nameid) ) sd->canusecashfood_tick = tick + battle_config.cashfood_use_interval; - - run_script(script,0,sd->bl.id,fake_nd->bl.id); - potion_flag = 0; + + script->current_item_id = nameid; + + script->run(item_script,0,sd->bl.id,npc->fake_nd->bl.id); + + script->current_item_id = 0; + script->potion_flag = 0; + return 1; } @@ -4399,35 +4561,35 @@ int pc_cart_additem(struct map_session_data *sd,struct item *item_data,int amoun if(item_data->nameid <= 0 || amount <= 0) return 1; - data = itemdb_search(item_data->nameid); + data = itemdb->search(item_data->nameid); if( data->stack.cart && amount > data->stack.amount ) {// item stack limitation return 1; } - if( !itemdb_cancartstore(item_data, pc->get_group_level(sd)) ) - { // Check item trade restrictions [Skotlex] + if( !itemdb_cancartstore(item_data, pc_get_group_level(sd)) || (item_data->bound > IBT_ACCOUNT && !pc_can_give_bound_items(sd))) + { // Check item trade restrictions [Skotlex] clif->message (sd->fd, msg_txt(264)); - return 1; + return 1;/* TODO: there is no official response to this? */ } if( (w = data->weight*amount) + sd->cart_weight > sd->cart_weight_max ) return 1; i = MAX_CART; - if( itemdb_isstackable2(data) && !item_data->expire_time ) + if( itemdb->isstackable2(data) && !item_data->expire_time ) { ARR_FIND( 0, MAX_CART, i, - sd->status.cart[i].nameid == item_data->nameid && - sd->status.cart[i].card[0] == item_data->card[0] && sd->status.cart[i].card[1] == item_data->card[1] && + sd->status.cart[i].nameid == item_data->nameid && sd->status.cart[i].bound == item_data->bound && + sd->status.cart[i].card[0] == item_data->card[0] && sd->status.cart[i].card[1] == item_data->card[1] && sd->status.cart[i].card[2] == item_data->card[2] && sd->status.cart[i].card[3] == item_data->card[3] ); }; if( i < MAX_CART ) {// item already in cart, stack it if( amount > MAX_AMOUNT - sd->status.cart[i].amount || ( data->stack.cart && amount > data->stack.amount - sd->status.cart[i].amount ) ) - return 1; // no room + return 2; // no room sd->status.cart[i].amount+=amount; clif->cart_additem(sd,i,amount,0); @@ -4436,7 +4598,7 @@ int pc_cart_additem(struct map_session_data *sd,struct item *item_data,int amoun {// item not stackable or not present, add it ARR_FIND( 0, MAX_CART, i, sd->status.cart[i].nameid == 0 ); if( i == MAX_CART ) - return 1; // no room + return 2; // no room memcpy(&sd->status.cart[i],item_data,sizeof(sd->status.cart[0])); sd->status.cart[i].amount=amount; @@ -4462,7 +4624,7 @@ int pc_cart_delitem(struct map_session_data *sd,int n,int amount,int type,e_log_ struct item_data * data; nullpo_retr(1, sd); - if( sd->status.cart[n].nameid == 0 || sd->status.cart[n].amount < amount || !(data = itemdb_exists(sd->status.cart[n].nameid)) ) + if( sd->status.cart[n].nameid == 0 || sd->status.cart[n].amount < amount || !(data = itemdb->exists(sd->status.cart[n].nameid)) ) return 1; logs->pick_pc(sd, log_type, -amount, &sd->status.cart[n],data); @@ -4490,6 +4652,7 @@ int pc_cart_delitem(struct map_session_data *sd,int n,int amount,int type,e_log_ int pc_putitemtocart(struct map_session_data *sd,int idx,int amount) { struct item *item_data; + int flag; nullpo_ret(sd); @@ -4501,10 +4664,10 @@ int pc_putitemtocart(struct map_session_data *sd,int idx,int amount) if( item_data->nameid == 0 || amount < 1 || item_data->amount < amount || sd->state.vending ) return 1; - if( pc->cart_additem(sd,item_data,amount,LOG_TYPE_NONE) == 0 ) + if( (flag = pc->cart_additem(sd,item_data,amount,LOG_TYPE_NONE)) == 0 ) return pc->delitem(sd,idx,amount,0,5,LOG_TYPE_NONE); - return 1; + return flag; } /*========================================== @@ -4546,13 +4709,45 @@ int pc_getitemfromcart(struct map_session_data *sd,int idx,int amount) if(item_data->nameid==0 || amount < 1 || item_data->amount<amount || sd->state.vending ) return 1; + if((flag = pc->additem(sd,item_data,amount,LOG_TYPE_NONE)) == 0) return pc->cart_delitem(sd,idx,amount,0,LOG_TYPE_NONE); - clif->additem(sd,0,0,flag); - return 1; + return flag; +} +void pc_bound_clear(struct map_session_data *sd, enum e_item_bound_type type) { + int i; + + switch( type ) { + /* both restricted to inventory */ + case IBT_PARTY: + case IBT_CHARACTER: + for( i = 0; i < MAX_INVENTORY; i++ ){ + if( sd->status.inventory[i].bound == type ) { + pc->delitem(sd,i,sd->status.inventory[i].amount,0,1,LOG_TYPE_OTHER); + } + } + break; + case IBT_ACCOUNT: + ShowError("Helllo! You reached pc_bound_clear for IBT_ACCOUNT, unfortunately no scenario was expected for this!\n"); + break; + case IBT_GUILD: { + struct guild_storage *gstor = gstorage->id2storage(sd->status.guild_id); + + for( i = 0; i < MAX_INVENTORY; i++ ){ + if(sd->status.inventory[i].bound == type) { + if( gstor ) + gstorage->additem(sd,gstor,&sd->status.inventory[i],sd->status.inventory[i].amount); + pc->delitem(sd,i,sd->status.inventory[i].amount,0,1,gstor?LOG_TYPE_GSTORAGE:LOG_TYPE_OTHER); + } + } + if( gstor ) + gstorage->close(sd); + } + break; + } + } - /*========================================== * Display item stolen msg to player sd *------------------------------------------*/ @@ -4567,7 +4762,7 @@ int pc_show_steal(struct block_list *bl,va_list ap) sd=va_arg(ap,struct map_session_data *); itemid=va_arg(ap,int); - if((item=itemdb_exists(itemid))==NULL) + if((item=itemdb->exists(itemid))==NULL) sprintf(output,"%s stole an Unknown Item (id: %i).",sd->status.name, itemid); else sprintf(output,"%s stole %s.",sd->status.name,item->jname); @@ -4598,11 +4793,11 @@ int pc_steal_item(struct map_session_data *sd,struct block_list *bl, uint16 skil if(md->state.steal_flag == UCHAR_MAX || ( md->sc.opt1 && md->sc.opt1 != OPT1_BURNING && md->sc.opt1 != OPT1_CRYSTALIZE ) ) //already stolen from / status change check return 0; - sd_status= status_get_status_data(&sd->bl); - md_status= status_get_status_data(bl); + sd_status= status->get_status_data(&sd->bl); + md_status= status->get_status_data(bl); if( md->master_id || md_status->mode&MD_BOSS || mob_is_treasure(md) || - map[bl->m].flag.nomobloot || // check noloot map flag [Lorky] + map->list[bl->m].flag.nomobloot || // check noloot map flag [Lorky] (battle_config.skill_steal_max_tries && //Reached limit of steal attempts. [Lupus] md->state.steal_flag++ >= battle_config.skill_steal_max_tries) ) { //Can't steal from @@ -4620,7 +4815,7 @@ int pc_steal_item(struct map_session_data *sd,struct block_list *bl, uint16 skil // Try dropping one item, in the order from first to last possible slot. // Droprate is affected by the skill success rate. for( i = 0; i < MAX_STEAL_DROP; i++ ) - if( md->db->dropitem[i].nameid > 0 && (data = itemdb_exists(md->db->dropitem[i].nameid)) && rnd() % 10000 < md->db->dropitem[i].p * rate/100. ) + if( md->db->dropitem[i].nameid > 0 && (data = itemdb->exists(md->db->dropitem[i].nameid)) && rnd() % 10000 < md->db->dropitem[i].p * rate/100. ) break; if( i == MAX_STEAL_DROP ) return 0; @@ -4629,7 +4824,7 @@ int pc_steal_item(struct map_session_data *sd,struct block_list *bl, uint16 skil memset(&tmp_item,0,sizeof(tmp_item)); tmp_item.nameid = itemid; tmp_item.amount = 1; - tmp_item.identify = itemdb_isidentified2(data); + tmp_item.identify = itemdb->isidentified2(data); flag = pc->additem(sd,&tmp_item,1,LOG_TYPE_PICKDROP_PLAYER); //TODO: Should we disable stealing when the item you stole couldn't be added to your inventory? Perhaps players will figure out a way to exploit this behaviour otherwise? @@ -4641,7 +4836,7 @@ int pc_steal_item(struct map_session_data *sd,struct block_list *bl, uint16 skil } if(battle_config.show_steal_in_same_party) - party_foreachsamemap(pc_show_steal,sd,AREA_SIZE,sd,tmp_item.nameid); + party->foreachsamemap(pc->show_steal,sd,AREA_SIZE,sd,tmp_item.nameid); //Logs items, Stolen from mobs [Lupus] logs->pick_mob(md, LOG_TYPE_STEAL, -1, &tmp_item, data); @@ -4651,20 +4846,21 @@ 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 != NULL)?sd->status.name :"GM", 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,0); + intif->broadcast(message, strlen(message)+1, BC_DEFAULT); } return 1; } -/*========================================== - * Stole zeny from bl (mob) - * return - * 0 = fail - * 1 = success - *------------------------------------------*/ -int pc_steal_coin(struct map_session_data *sd,struct block_list *target) -{ - int rate,skill; +/** + * Steals zeny from a monster through the RG_STEALCOIN skill. + * + * @param sd Source character + * @param target Target monster + * + * @return Amount of stolen zeny (0 in case of failure) + **/ +int pc_steal_coin(struct map_session_data *sd, struct block_list *target) { + int rate, skill_lv; struct mob_data *md; if(!sd || !target || target->type != BL_MOB) return 0; @@ -4676,16 +4872,14 @@ int pc_steal_coin(struct map_session_data *sd,struct block_list *target) if( mob_is_treasure(md) ) return 0; - // FIXME: This formula is either custom or outdated. - skill = pc->checkskill(sd,RG_STEALCOIN)*10; - rate = skill + (sd->status.base_level - md->level)*3 + sd->battle_status.dex*2 + sd->battle_status.luk*2; - if(rnd()%1000 < rate) - { - int amount = md->level*10 + rnd()%100; + skill_lv = pc->checkskill(sd, RG_STEALCOIN); + rate = skill_lv*10 + (sd->status.base_level - md->level)*2 + sd->battle_status.dex/2 + sd->battle_status.luk/2; + if(rnd()%1000 < rate) { + int amount = md->level * skill_lv / 10 + md->level*8 + rnd()%(md->level*2 + 1); // mob_lv * skill_lv / 10 + random [mob_lv*8; mob_lv*10] pc->getzeny(sd, amount, LOG_TYPE_STEAL, NULL); md->state.steal_coin_flag = 1; - return 1; + return amount; } return 0; } @@ -4697,13 +4891,13 @@ int pc_steal_coin(struct map_session_data *sd,struct block_list *target) * 1 - Invalid map index. * 2 - Map not in this map-server, and failed to locate alternate map-server. *------------------------------------------*/ -int pc_setpos(struct map_session_data* sd, unsigned short mapindex, int x, int y, clr_type clrtype) { +int pc_setpos(struct map_session_data* sd, unsigned short map_index, int x, int y, clr_type clrtype) { int16 m; nullpo_ret(sd); - if( !mapindex || !mapindex_id2name(mapindex) ) { - ShowDebug("pc_setpos: Passed mapindex(%d) is invalid!\n", mapindex); + if( !map_index || !mapindex_id2name(map_index) || ( m = map->mapindex2mapid(map_index) ) == -1 ) { + ShowDebug("pc_setpos: Passed mapindex(%d) is invalid!\n", map_index); return 1; } @@ -4711,53 +4905,68 @@ int pc_setpos(struct map_session_data* sd, unsigned short mapindex, int x, int y pc->setstand(sd); pc->setrestartvalue(sd,1); } - m = iMap->mapindex2mapid(mapindex); - if( map[m].flag.src4instance ) { + if( map->list[m].flag.src4instance ) { struct party_data *p; bool stop = false; int i = 0, j = 0; if( sd->instances ) { for( i = 0; i < sd->instances; i++ ) { - ARR_FIND(0, instances[sd->instance[i]].num_map, j, map[instances[sd->instance[i]].map[j]].instance_src_map == m && !map[instances[sd->instance[i]].map[j]].cName); - if( j != instances[sd->instance[i]].num_map ) - break; + if( sd->instance[i] >= 0 ) { + ARR_FIND(0, instance->list[sd->instance[i]].num_map, j, map->list[instance->list[sd->instance[i]].map[j]].instance_src_map == m && !map->list[instance->list[sd->instance[i]].map[j]].custom_name); + if( j != instance->list[sd->instance[i]].num_map ) + break; + } } if( i != sd->instances ) { - m = instances[sd->instance[i]].map[j]; - mapindex = map[m].index; + m = instance->list[sd->instance[i]].map[j]; + map_index = map_id2index(m); stop = true; } } if ( !stop && sd->status.party_id && (p = party->search(sd->status.party_id)) && p->instances ) { for( i = 0; i < p->instances; i++ ) { - ARR_FIND(0, instances[p->instance[i]].num_map, j, map[instances[p->instance[i]].map[j]].instance_src_map == m && !map[instances[p->instance[i]].map[j]].cName); - if( j != instances[p->instance[i]].num_map ) - break; + if( p->instance[i] >= 0 ) { + ARR_FIND(0, instance->list[p->instance[i]].num_map, j, map->list[instance->list[p->instance[i]].map[j]].instance_src_map == m && !map->list[instance->list[p->instance[i]].map[j]].custom_name); + if( j != instance->list[p->instance[i]].num_map ) + break; + } } if( i != p->instances ) { - m = instances[p->instance[i]].map[j]; - mapindex = map[m].index; + m = instance->list[p->instance[i]].map[j]; + map_index = map_id2index(m); stop = true; } } if ( !stop && sd->status.guild_id && sd->guild && sd->guild->instances ) { for( i = 0; i < sd->guild->instances; i++ ) { - ARR_FIND(0, instances[sd->guild->instance[i]].num_map, j, map[instances[sd->guild->instance[i]].map[j]].instance_src_map == m && !map[instances[sd->guild->instance[i]].map[j]].cName); - if( j != instances[sd->guild->instance[i]].num_map ) - break; + if( sd->guild->instance[i] >= 0 ) { + ARR_FIND(0, instance->list[sd->guild->instance[i]].num_map, j, map->list[instance->list[sd->guild->instance[i]].map[j]].instance_src_map == m && !map->list[instance->list[sd->guild->instance[i]].map[j]].custom_name); + if( j != instance->list[sd->guild->instance[i]].num_map ) + break; + } } if( i != sd->guild->instances ) { - m = instances[sd->guild->instance[i]].map[j]; - mapindex = map[m].index; - stop = true; + m = instance->list[sd->guild->instance[i]].map[j]; + map_index = map_id2index(m); + //stop = true; Uncomment if adding new checks } } + + /* we hit a instance, if empty we populate the spawn data */ + if( map->list[m].instance_id >= 0 && instance->list[map->list[m].instance_id].respawn.map == 0 && + instance->list[map->list[m].instance_id].respawn.x == 0 && + instance->list[map->list[m].instance_id].respawn.y == 0) { + instance->list[map->list[m].instance_id].respawn.map = map_index; + instance->list[map->list[m].instance_id].respawn.x = x; + instance->list[map->list[m].instance_id].respawn.y = y; + } } - sd->state.changemap = (sd->mapindex != mapindex); + sd->state.changemap = (sd->mapindex != map_index); sd->state.warping = 1; + sd->state.workinprogress = 0; if( sd->state.changemap ) { // Misc map-changing settings int i; sd->state.pmap = sd->bl.m; @@ -4765,13 +4974,13 @@ int pc_setpos(struct map_session_data* sd, unsigned short mapindex, int x, int y for( i = 0; i < sd->queues_count; i++ ) { struct hQueue *queue; if( (queue = script->queue(sd->queues[i])) && queue->onMapChange[0] != '\0' ) { - pc->setregstr(sd, add_str("QMapChangeTo"), map[m].name); - npc_event(sd, queue->onMapChange, 0); + pc->setregstr(sd, script->add_str("QMapChangeTo"), map->list[m].name); + npc->event(sd, queue->onMapChange, 0); } } - if( map[m].cell == (struct mapcell *)0xdeadbeaf ) - iMap->cellfromcache(&map[m]); + if( map->list[m].cell == (struct mapcell *)0xdeadbeaf ) + map->cellfromcache(&map->list[m]); if (sd->sc.count) { // Cancel some map related stuff. if (sd->sc.data[SC_JAILED]) return 1; //You may not get out! @@ -4781,11 +4990,15 @@ int pc_setpos(struct map_session_data* sd, unsigned short mapindex, int x, int y status_change_end(&sd->bl, SC_MOON_COMFORT, INVALID_TIMER); status_change_end(&sd->bl, SC_STAR_COMFORT, INVALID_TIMER); status_change_end(&sd->bl, SC_MIRACLE, INVALID_TIMER); + status_change_end(&sd->bl, SC_NEUTRALBARRIER_MASTER, INVALID_TIMER);//Will later check if this is needed. [Rytech] + status_change_end(&sd->bl, SC_NEUTRALBARRIER, INVALID_TIMER); + status_change_end(&sd->bl, SC_STEALTHFIELD_MASTER, INVALID_TIMER); + status_change_end(&sd->bl, SC_STEALTHFIELD, INVALID_TIMER); if (sd->sc.data[SC_KNOWLEDGE]) { struct status_change_entry *sce = sd->sc.data[SC_KNOWLEDGE]; if (sce->timer != INVALID_TIMER) - iTimer->delete_timer(sce->timer, status_change_timer); - sce->timer = iTimer->add_timer(iTimer->gettick() + skill->get_time(SG_KNOWLEDGE, sce->val1), status_change_timer, sd->bl.id, SC_KNOWLEDGE); + timer->delete(sce->timer, status->change_timer); + sce->timer = timer->add(timer->gettick() + skill->get_time(SG_KNOWLEDGE, sce->val1), status->change_timer, sd->bl.id, SC_KNOWLEDGE); } status_change_end(&sd->bl, SC_PROPERTYWALK, INVALID_TIMER); status_change_end(&sd->bl, SC_CLOAKING, INVALID_TIMER); @@ -4800,76 +5013,75 @@ int pc_setpos(struct map_session_data* sd, unsigned short mapindex, int x, int y skill->clear_unitgroup(&sd->bl); party->send_dot_remove(sd); //minimap dot fix [Kevin] guild->send_dot_remove(sd); - bg_send_dot_remove(sd); + bg->send_dot_remove(sd); if (sd->regen.state.gc) sd->regen.state.gc = 0; // make sure vending is allowed here - if (sd->state.vending && map[m].flag.novending) { + if (sd->state.vending && map->list[m].flag.novending) { clif->message (sd->fd, msg_txt(276)); // "You can't open a shop on this map" vending->close(sd); } - if( hChSys.local && map[sd->bl.m].channel && idb_exists(map[sd->bl.m].channel->users, sd->status.char_id) ) { - clif->chsys_left(map[sd->bl.m].channel,sd); + if( hChSys.local && map->list[sd->bl.m].channel && idb_exists(map->list[sd->bl.m].channel->users, sd->status.char_id) ) { + clif->chsys_left(map->list[sd->bl.m].channel,sd); } - } if( m < 0 ) { uint32 ip; uint16 port; //if can't find any map-servers, just abort setting position. - if(!sd->mapindex || iMap->mapname2ipport(mapindex,&ip,&port)) + if(!sd->mapindex || map->mapname2ipport(map_index,&ip,&port)) return 2; if (sd->npc_id) - npc_event_dequeue(sd); - npc_script_event(sd, NPCE_LOGOUT); + npc->event_dequeue(sd); + npc->script_event(sd, NPCE_LOGOUT); //remove from map, THEN change x/y coordinates - unit_remove_map_pc(sd,clrtype); - sd->mapindex = mapindex; + unit->remove_map_pc(sd,clrtype); + sd->mapindex = map_index; sd->bl.x=x; sd->bl.y=y; pc->clean_skilltree(sd); - chrif_save(sd,2); - chrif_changemapserver(sd, ip, (short)port); + chrif->save(sd,2); + chrif->changemapserver(sd, ip, (short)port); //Free session data from this map server [Kevin] - unit_free_pc(sd); + unit->free_pc(sd); return 0; } - if( x < 0 || x >= map[m].xs || y < 0 || y >= map[m].ys ) { - ShowError("pc_setpos: attempt to place player %s (%d:%d) on invalid coordinates (%s-%d,%d)\n", sd->status.name, sd->status.account_id, sd->status.char_id, mapindex_id2name(mapindex),x,y); + if( x < 0 || x >= map->list[m].xs || y < 0 || y >= map->list[m].ys ) { + ShowError("pc_setpos: attempt to place player %s (%d:%d) on invalid coordinates (%s-%d,%d)\n", sd->status.name, sd->status.account_id, sd->status.char_id, mapindex_id2name(map_index),x,y); x = y = 0; // make it random } if( x == 0 && y == 0 ) {// pick a random walkable cell do { - x=rnd()%(map[m].xs-2)+1; - y=rnd()%(map[m].ys-2)+1; - } while(iMap->getcell(m,x,y,CELL_CHKNOPASS)); + x=rnd()%(map->list[m].xs-2)+1; + y=rnd()%(map->list[m].ys-2)+1; + } while(map->getcell(m,x,y,CELL_CHKNOPASS)); } - if (sd->state.vending && iMap->getcell(m,x,y,CELL_CHKNOVENDING)) { + if (sd->state.vending && map->getcell(m,x,y,CELL_CHKNOVENDING)) { clif->message (sd->fd, msg_txt(204)); // "You can't open a shop on this cell." vending->close(sd); } if(sd->bl.prev != NULL){ - unit_remove_map_pc(sd,clrtype); + unit->remove_map_pc(sd,clrtype); clif->changemap(sd,m,x,y); // [MouseJstr] } else if(sd->state.active) //Tag player for rewarping after map-loading is done. [Skotlex] sd->state.rewarp = 1; - sd->mapindex = mapindex; + sd->mapindex = map_index; sd->bl.m = m; sd->bl.x = sd->ud.to_x = x; sd->bl.y = sd->ud.to_y = y; - if( sd->status.guild_id > 0 && map[m].flag.gvg_castle ) { // Increased guild castle regen [Valaris] + if( sd->status.guild_id > 0 && map->list[m].flag.gvg_castle ) { // Increased guild castle regen [Valaris] struct guild_castle *gc = guild->mapindex2gc(sd->mapindex); if(gc && gc->guild_id == sd->status.guild_id) sd->regen.state.gc = 1; @@ -4895,6 +5107,10 @@ int pc_setpos(struct map_session_data* sd, unsigned short mapindex, int x, int y sd->md->bl.y = sd->md->ud.to_y = y; sd->md->ud.dir = sd->ud.dir; } + + /* given autotrades have no clients you have to trigger this manually otherwise they get stuck in memory limbo bugreport:7495 */ + if( sd->state.autotrade ) + clif->pLoadEndAck(0,sd); return 0; } @@ -4906,8 +5122,7 @@ int pc_setpos(struct map_session_data* sd, unsigned short mapindex, int x, int y * 0 = fail or FIXME success (from pc->setpos) * x(1|2) = fail *------------------------------------------*/ -int pc_randomwarp(struct map_session_data *sd, clr_type type) -{ +int pc_randomwarp(struct map_session_data *sd, clr_type type) { int x,y,i=0; int16 m; @@ -4915,16 +5130,16 @@ int pc_randomwarp(struct map_session_data *sd, clr_type type) m=sd->bl.m; - if (map[sd->bl.m].flag.noteleport) //Teleport forbidden + if (map->list[sd->bl.m].flag.noteleport) //Teleport forbidden return 0; - do{ - x=rnd()%(map[m].xs-2)+1; - y=rnd()%(map[m].ys-2)+1; - }while(iMap->getcell(m,x,y,CELL_CHKNOPASS) && (i++)<1000 ); + do { + x=rnd()%(map->list[m].xs-2)+1; + y=rnd()%(map->list[m].ys-2)+1; + } while( map->getcell(m,x,y,CELL_CHKNOPASS) && (i++) < 1000 ); if (i < 1000) - return pc->setpos(sd,map[sd->bl.m].index,x,y,type); + return pc->setpos(sd,map_id2index(sd->bl.m),x,y,type); return 0; } @@ -4933,14 +5148,13 @@ int pc_randomwarp(struct map_session_data *sd, clr_type type) * Records a memo point at sd's current position * pos - entry to replace, (-1: shift oldest entry out) *------------------------------------------*/ -int pc_memo(struct map_session_data* sd, int pos) -{ - int skill; +int pc_memo(struct map_session_data* sd, int pos) { + int skill_lv; nullpo_ret(sd); // check mapflags - if( sd->bl.m >= 0 && (map[sd->bl.m].flag.nomemo || map[sd->bl.m].flag.nowarpto) && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE) ) { + if( sd->bl.m >= 0 && (map->list[sd->bl.m].flag.nomemo || map->list[sd->bl.m].flag.nowarpto) && !pc_has_permission(sd, PC_PERM_WARP_ANYWHERE) ) { clif->skill_mapinfomessage(sd, 1); // "Saved point cannot be memorized." return 0; } @@ -4950,12 +5164,12 @@ int pc_memo(struct map_session_data* sd, int pos) return 0; // invalid input // check required skill level - skill = pc->checkskill(sd, AL_WARP); - if( skill < 1 ) { + skill_lv = pc->checkskill(sd, AL_WARP); + if( skill_lv < 1 ) { clif->skill_memomessage(sd,2); // "You haven't learned Warp." return 0; } - if( skill < 2 || skill - 2 < pos ) { + if( skill_lv < 2 || skill_lv - 2 < pos ) { clif->skill_memomessage(sd,1); // "Skill Level is not high enough." return 0; } @@ -5009,14 +5223,14 @@ int pc_checkskill2(struct map_session_data *sd,uint16 index) { ShowError("pc_checkskill: Invalid skill index %d (char_id=%d).\n", index, sd->status.char_id); return 0; } - if( skill_db[index].nameid >= GD_SKILLBASE && skill_db[index].nameid < GD_MAX ) { + if( skill->db[index].nameid >= GD_SKILLBASE && skill->db[index].nameid < GD_MAX ) { struct guild *g; if( sd->status.guild_id>0 && (g=sd->guild)!=NULL) - return guild->checkskill(g,skill_db[index].nameid); + return guild->checkskill(g,skill->db[index].nameid); return 0; } - if(sd->status.skill[index].id == skill_db[index].nameid) + if(sd->status.skill[index].id == skill->db[index].nameid) return (sd->status.skill[index].lv); return 0; @@ -5041,9 +5255,11 @@ int pc_checkallowskill(struct map_session_data *sd) SC_DANCING, SC_GS_GATLINGFEVER, #ifdef RENEWAL + SC_LKCONCENTRATION, SC_EDP, #endif - SC_FEARBREEZE + SC_FEARBREEZE, + SC_EXEEDBREAK, }; const enum sc_type scs_list[] = { SC_AUTOGUARD, @@ -5057,12 +5273,12 @@ int pc_checkallowskill(struct map_session_data *sd) if(!sd->sc.count) return 0; - for (i = 0; i < ARRAYLENGTH(scw_list); i++) - { // Skills requiring specific weapon types + for (i = 0; i < ARRAYLENGTH(scw_list); i++) { + // Skills requiring specific weapon types if( scw_list[i] == SC_DANCING && !battle_config.dancing_weaponswitch_fix ) continue; - if(sd->sc.data[scw_list[i]] && - !pc_check_weapontype(sd,skill->get_weapontype(status_sc2skill(scw_list[i])))) + if( sd->sc.data[scw_list[i]] + && !pc_check_weapontype(sd,skill->get_weapontype(status->sc2skill(scw_list[i])))) status_change_end(&sd->bl, scw_list[i], INVALID_TIMER); } @@ -5091,7 +5307,7 @@ int pc_checkequip(struct map_session_data *sd,int pos) nullpo_retr(-1, sd); for(i=0;i<EQI_MAX;i++){ - if(pos & equip_pos[i]) + if(pos & pc->equip_pos[i]) return sd->equip_index[i]; } @@ -5132,6 +5348,7 @@ int pc_jobid2mapid(unsigned short b_class) case JOB_STAR_GLADIATOR: return MAPID_STAR_GLADIATOR; case JOB_KAGEROU: case JOB_OBORO: return MAPID_KAGEROUOBORO; + case JOB_REBELLION: return MAPID_REBELLION; case JOB_DEATH_KNIGHT: return MAPID_DEATH_KNIGHT; //2-2 Jobs case JOB_CRUSADER: return MAPID_CRUSADER; @@ -5272,6 +5489,7 @@ int pc_mapid2jobid(unsigned short class_, int sex) case MAPID_ASSASSIN: return JOB_ASSASSIN; case MAPID_STAR_GLADIATOR: return JOB_STAR_GLADIATOR; case MAPID_KAGEROUOBORO: return sex?JOB_KAGEROU:JOB_OBORO; + case MAPID_REBELLION: return JOB_REBELLION; case MAPID_DEATH_KNIGHT: return JOB_DEATH_KNIGHT; //2-2 Jobs case MAPID_CRUSADER: return JOB_CRUSADER; @@ -5382,107 +5600,107 @@ int pc_mapid2jobid(unsigned short class_, int sex) const char* job_name(int class_) { switch (class_) { - case JOB_NOVICE: - case JOB_SWORDMAN: - case JOB_MAGE: - case JOB_ARCHER: - case JOB_ACOLYTE: - case JOB_MERCHANT: - case JOB_THIEF: + case JOB_NOVICE: // 550 + case JOB_SWORDMAN: // 551 + case JOB_MAGE: // 552 + case JOB_ARCHER: // 553 + case JOB_ACOLYTE: // 554 + case JOB_MERCHANT: // 555 + case JOB_THIEF: // 556 return msg_txt(550 - JOB_NOVICE+class_); - case JOB_KNIGHT: - case JOB_PRIEST: - case JOB_WIZARD: - case JOB_BLACKSMITH: - case JOB_HUNTER: - case JOB_ASSASSIN: + case JOB_KNIGHT: // 557 + case JOB_PRIEST: // 558 + case JOB_WIZARD: // 559 + case JOB_BLACKSMITH: // 560 + case JOB_HUNTER: // 561 + case JOB_ASSASSIN: // 562 return msg_txt(557 - JOB_KNIGHT+class_); case JOB_KNIGHT2: return msg_txt(557); - case JOB_CRUSADER: - case JOB_MONK: - case JOB_SAGE: - case JOB_ROGUE: - case JOB_ALCHEMIST: - case JOB_BARD: - case JOB_DANCER: + case JOB_CRUSADER: // 563 + case JOB_MONK: // 564 + case JOB_SAGE: // 565 + case JOB_ROGUE: // 566 + case JOB_ALCHEMIST: // 567 + case JOB_BARD: // 568 + case JOB_DANCER: // 569 return msg_txt(563 - JOB_CRUSADER+class_); case JOB_CRUSADER2: return msg_txt(563); - case JOB_WEDDING: - case JOB_SUPER_NOVICE: - case JOB_GUNSLINGER: - case JOB_NINJA: - case JOB_XMAS: + case JOB_WEDDING: // 570 + case JOB_SUPER_NOVICE: // 571 + case JOB_GUNSLINGER: // 572 + case JOB_NINJA: // 573 + case JOB_XMAS: // 574 return msg_txt(570 - JOB_WEDDING+class_); case JOB_SUMMER: return msg_txt(621); - case JOB_NOVICE_HIGH: - case JOB_SWORDMAN_HIGH: - case JOB_MAGE_HIGH: - case JOB_ARCHER_HIGH: - case JOB_ACOLYTE_HIGH: - case JOB_MERCHANT_HIGH: - case JOB_THIEF_HIGH: + case JOB_NOVICE_HIGH: // 575 + case JOB_SWORDMAN_HIGH: // 576 + case JOB_MAGE_HIGH: // 577 + case JOB_ARCHER_HIGH: // 578 + case JOB_ACOLYTE_HIGH: // 579 + case JOB_MERCHANT_HIGH: // 580 + case JOB_THIEF_HIGH: // 581 return msg_txt(575 - JOB_NOVICE_HIGH+class_); - case JOB_LORD_KNIGHT: - case JOB_HIGH_PRIEST: - case JOB_HIGH_WIZARD: - case JOB_WHITESMITH: - case JOB_SNIPER: - case JOB_ASSASSIN_CROSS: + case JOB_LORD_KNIGHT: // 582 + case JOB_HIGH_PRIEST: // 583 + case JOB_HIGH_WIZARD: // 584 + case JOB_WHITESMITH: // 585 + case JOB_SNIPER: // 586 + case JOB_ASSASSIN_CROSS: // 587 return msg_txt(582 - JOB_LORD_KNIGHT+class_); case JOB_LORD_KNIGHT2: return msg_txt(582); - case JOB_PALADIN: - case JOB_CHAMPION: - case JOB_PROFESSOR: - case JOB_STALKER: - case JOB_CREATOR: - case JOB_CLOWN: - case JOB_GYPSY: + case JOB_PALADIN: // 588 + case JOB_CHAMPION: // 589 + case JOB_PROFESSOR: // 590 + case JOB_STALKER: // 591 + case JOB_CREATOR: // 592 + case JOB_CLOWN: // 593 + case JOB_GYPSY: // 594 return msg_txt(588 - JOB_PALADIN + class_); case JOB_PALADIN2: return msg_txt(588); - case JOB_BABY: - case JOB_BABY_SWORDMAN: - case JOB_BABY_MAGE: - case JOB_BABY_ARCHER: - case JOB_BABY_ACOLYTE: - case JOB_BABY_MERCHANT: - case JOB_BABY_THIEF: + case JOB_BABY: // 595 + case JOB_BABY_SWORDMAN: // 596 + case JOB_BABY_MAGE: // 597 + case JOB_BABY_ARCHER: // 598 + case JOB_BABY_ACOLYTE: // 599 + case JOB_BABY_MERCHANT: // 600 + case JOB_BABY_THIEF: // 601 return msg_txt(595 - JOB_BABY + class_); - case JOB_BABY_KNIGHT: - case JOB_BABY_PRIEST: - case JOB_BABY_WIZARD: - case JOB_BABY_BLACKSMITH: - case JOB_BABY_HUNTER: - case JOB_BABY_ASSASSIN: + case JOB_BABY_KNIGHT: // 602 + case JOB_BABY_PRIEST: // 603 + case JOB_BABY_WIZARD: // 604 + case JOB_BABY_BLACKSMITH: // 605 + case JOB_BABY_HUNTER: // 606 + case JOB_BABY_ASSASSIN: // 607 return msg_txt(602 - JOB_BABY_KNIGHT + class_); case JOB_BABY_KNIGHT2: return msg_txt(602); - case JOB_BABY_CRUSADER: - case JOB_BABY_MONK: - case JOB_BABY_SAGE: - case JOB_BABY_ROGUE: - case JOB_BABY_ALCHEMIST: - case JOB_BABY_BARD: - case JOB_BABY_DANCER: + case JOB_BABY_CRUSADER: // 608 + case JOB_BABY_MONK: // 609 + case JOB_BABY_SAGE: // 610 + case JOB_BABY_ROGUE: // 611 + case JOB_BABY_ALCHEMIST: // 612 + case JOB_BABY_BARD: // 613 + case JOB_BABY_DANCER: // 614 return msg_txt(608 - JOB_BABY_CRUSADER + class_); case JOB_BABY_CRUSADER2: @@ -5499,74 +5717,82 @@ const char* job_name(int class_) case JOB_SOUL_LINKER: return msg_txt(618); - case JOB_GANGSI: - case JOB_DEATH_KNIGHT: - case JOB_DARK_COLLECTOR: + case JOB_GANGSI: // 622 + case JOB_DEATH_KNIGHT: // 623 + case JOB_DARK_COLLECTOR: // 624 return msg_txt(622 - JOB_GANGSI+class_); - case JOB_RUNE_KNIGHT: - case JOB_WARLOCK: - case JOB_RANGER: - case JOB_ARCH_BISHOP: - case JOB_MECHANIC: - case JOB_GUILLOTINE_CROSS: + case JOB_RUNE_KNIGHT: // 625 + case JOB_WARLOCK: // 626 + case JOB_RANGER: // 627 + case JOB_ARCH_BISHOP: // 628 + case JOB_MECHANIC: // 629 + case JOB_GUILLOTINE_CROSS: // 630 return msg_txt(625 - JOB_RUNE_KNIGHT+class_); - case JOB_RUNE_KNIGHT_T: - case JOB_WARLOCK_T: - case JOB_RANGER_T: - case JOB_ARCH_BISHOP_T: - case JOB_MECHANIC_T: - case JOB_GUILLOTINE_CROSS_T: - return msg_txt(681 - JOB_RUNE_KNIGHT_T+class_); - - case JOB_ROYAL_GUARD: - case JOB_SORCERER: - case JOB_MINSTREL: - case JOB_WANDERER: - case JOB_SURA: - case JOB_GENETIC: - case JOB_SHADOW_CHASER: + case JOB_RUNE_KNIGHT_T: // 656 + case JOB_WARLOCK_T: // 657 + case JOB_RANGER_T: // 658 + case JOB_ARCH_BISHOP_T: // 659 + case JOB_MECHANIC_T: // 660 + case JOB_GUILLOTINE_CROSS_T: // 661 + return msg_txt(656 - JOB_RUNE_KNIGHT_T+class_); + + case JOB_ROYAL_GUARD: // 631 + case JOB_SORCERER: // 632 + case JOB_MINSTREL: // 633 + case JOB_WANDERER: // 634 + case JOB_SURA: // 635 + case JOB_GENETIC: // 636 + case JOB_SHADOW_CHASER: // 637 return msg_txt(631 - JOB_ROYAL_GUARD+class_); - case JOB_ROYAL_GUARD_T: - case JOB_SORCERER_T: - case JOB_MINSTREL_T: - case JOB_WANDERER_T: - case JOB_SURA_T: - case JOB_GENETIC_T: - case JOB_SHADOW_CHASER_T: - return msg_txt(687 - JOB_ROYAL_GUARD_T+class_); + case JOB_ROYAL_GUARD_T: // 662 + case JOB_SORCERER_T: // 663 + case JOB_MINSTREL_T: // 664 + case JOB_WANDERER_T: // 665 + case JOB_SURA_T: // 666 + case JOB_GENETIC_T: // 667 + case JOB_SHADOW_CHASER_T: // 668 + return msg_txt(662 - JOB_ROYAL_GUARD_T+class_); case JOB_RUNE_KNIGHT2: - case JOB_RUNE_KNIGHT_T2: return msg_txt(625); + case JOB_RUNE_KNIGHT_T2: + return msg_txt(656); + case JOB_ROYAL_GUARD2: - case JOB_ROYAL_GUARD_T2: return msg_txt(631); + case JOB_ROYAL_GUARD_T2: + return msg_txt(662); + case JOB_RANGER2: - case JOB_RANGER_T2: return msg_txt(627); + case JOB_RANGER_T2: + return msg_txt(658); + case JOB_MECHANIC2: - case JOB_MECHANIC_T2: return msg_txt(629); - case JOB_BABY_RUNE: - case JOB_BABY_WARLOCK: - case JOB_BABY_RANGER: - case JOB_BABY_BISHOP: - case JOB_BABY_MECHANIC: - case JOB_BABY_CROSS: - case JOB_BABY_GUARD: - case JOB_BABY_SORCERER: - case JOB_BABY_MINSTREL: - case JOB_BABY_WANDERER: - case JOB_BABY_SURA: - case JOB_BABY_GENETIC: - case JOB_BABY_CHASER: + case JOB_MECHANIC_T2: + return msg_txt(660); + + case JOB_BABY_RUNE: // 638 + case JOB_BABY_WARLOCK: // 639 + case JOB_BABY_RANGER: // 640 + case JOB_BABY_BISHOP: // 641 + case JOB_BABY_MECHANIC: // 642 + case JOB_BABY_CROSS: // 643 + case JOB_BABY_GUARD: // 644 + case JOB_BABY_SORCERER: // 645 + case JOB_BABY_MINSTREL: // 646 + case JOB_BABY_WANDERER: // 647 + case JOB_BABY_SURA: // 648 + case JOB_BABY_GENETIC: // 649 + case JOB_BABY_CHASER: // 650 return msg_txt(638 - JOB_BABY_RUNE+class_); case JOB_BABY_RUNE2: @@ -5581,56 +5807,57 @@ const char* job_name(int class_) case JOB_BABY_MECHANIC2: return msg_txt(642); - case JOB_SUPER_NOVICE_E: - case JOB_SUPER_BABY_E: + case JOB_SUPER_NOVICE_E: // 651 + case JOB_SUPER_BABY_E: // 652 return msg_txt(651 - JOB_SUPER_NOVICE_E+class_); - case JOB_KAGEROU: - case JOB_OBORO: + case JOB_KAGEROU: // 653 + case JOB_OBORO: // 654 return msg_txt(653 - JOB_KAGEROU+class_); - default: + case JOB_REBELLION: return msg_txt(655); + + default: + return msg_txt(620); // "Unknown Job" } } -int pc_follow_timer(int tid, unsigned int tick, int id, intptr_t data) -{ +int pc_follow_timer(int tid, int64 tick, int id, intptr_t data) { struct map_session_data *sd; struct block_list *tbl; - sd = iMap->id2sd(id); + sd = map->id2sd(id); nullpo_ret(sd); - if (sd->followtimer != tid){ + if (sd->followtimer != tid) { ShowError("pc_follow_timer %d != %d\n",sd->followtimer,tid); sd->followtimer = INVALID_TIMER; return 0; } sd->followtimer = INVALID_TIMER; - tbl = iMap->id2bl(sd->followtarget); + tbl = map->id2bl(sd->followtarget); - if (tbl == NULL || pc_isdead(sd) || status_isdead(tbl)) - { + if (tbl == NULL || pc_isdead(sd) || status->isdead(tbl)) { pc->stop_following(sd); return 0; } // either player or target is currently detached from map blocks (could be teleporting), // but still connected to this map, so we'll just increment the timer and check back later - if (sd->bl.prev != NULL && tbl->prev != NULL && - sd->ud.skilltimer == INVALID_TIMER && sd->ud.attacktimer == INVALID_TIMER && sd->ud.walktimer == INVALID_TIMER) - { - if((sd->bl.m == tbl->m) && unit_can_reach_bl(&sd->bl,tbl, AREA_SIZE, 0, NULL, NULL)) { + if (sd->bl.prev != NULL && tbl->prev != NULL + && sd->ud.skilltimer == INVALID_TIMER && sd->ud.attacktimer == INVALID_TIMER && sd->ud.walktimer == INVALID_TIMER + ) { + if((sd->bl.m == tbl->m) && unit->can_reach_bl(&sd->bl,tbl, AREA_SIZE, 0, NULL, NULL)) { if (!check_distance_bl(&sd->bl, tbl, 5)) - unit_walktobl(&sd->bl, tbl, 5, 0); + unit->walktobl(&sd->bl, tbl, 5, 0); } else pc->setpos(sd, map_id2index(tbl->m), tbl->x, tbl->y, CLR_TELEPORT); } - sd->followtimer = iTimer->add_timer( + sd->followtimer = timer->add( tick + 1000, // increase time a bit to loosen up map's load - pc_follow_timer, sd->bl.id, 0); + pc->follow_timer, sd->bl.id, 0); return 0; } @@ -5639,27 +5866,26 @@ int pc_stop_following (struct map_session_data *sd) nullpo_ret(sd); if (sd->followtimer != INVALID_TIMER) { - iTimer->delete_timer(sd->followtimer,pc_follow_timer); + timer->delete(sd->followtimer,pc->follow_timer); sd->followtimer = INVALID_TIMER; } sd->followtarget = -1; sd->ud.target_to = 0; - unit_stop_walking(&sd->bl, 1); + unit->stop_walking(&sd->bl, 1); return 0; } -int pc_follow(struct map_session_data *sd,int target_id) -{ - struct block_list *bl = iMap->id2bl(target_id); +int pc_follow(struct map_session_data *sd,int target_id) { + struct block_list *bl = map->id2bl(target_id); if (bl == NULL /*|| bl->type != BL_PC*/) return 1; if (sd->followtimer != INVALID_TIMER) pc->stop_following(sd); sd->followtarget = target_id; - pc_follow_timer(INVALID_TIMER, iTimer->gettick(), sd->bl.id, 0); + pc->follow_timer(INVALID_TIMER, timer->gettick(), sd->bl.id, 0); return 0; } @@ -5683,29 +5909,29 @@ int pc_checkbaselevelup(struct map_session_data *sd) { } while ((next=pc->nextbaseexp(sd)) > 0 && sd->status.base_exp >= next); if (battle_config.pet_lv_rate && sd->pd) //<Skotlex> update pet's level - status_calc_pet(sd->pd,0); + status_calc_pet(sd->pd,SCO_NONE); clif->updatestatus(sd,SP_STATUSPOINT); clif->updatestatus(sd,SP_BASELEVEL); clif->updatestatus(sd,SP_BASEEXP); clif->updatestatus(sd,SP_NEXTBASEEXP); - status_calc_pc(sd,0); + status_calc_pc(sd,SCO_FORCE); status_percent_heal(&sd->bl,100,100); if((sd->class_&MAPID_UPPERMASK) == MAPID_SUPER_NOVICE) { - sc_start(&sd->bl,status_skill2sc(PR_KYRIE),100,1,skill->get_time(PR_KYRIE,1)); - sc_start(&sd->bl,status_skill2sc(PR_IMPOSITIO),100,1,skill->get_time(PR_IMPOSITIO,1)); - sc_start(&sd->bl,status_skill2sc(PR_MAGNIFICAT),100,1,skill->get_time(PR_MAGNIFICAT,1)); - sc_start(&sd->bl,status_skill2sc(PR_GLORIA),100,1,skill->get_time(PR_GLORIA,1)); - sc_start(&sd->bl,status_skill2sc(PR_SUFFRAGIUM),100,1,skill->get_time(PR_SUFFRAGIUM,1)); + sc_start(NULL,&sd->bl,status->skill2sc(PR_KYRIE),100,1,skill->get_time(PR_KYRIE,1)); + sc_start(NULL,&sd->bl,status->skill2sc(PR_IMPOSITIO),100,1,skill->get_time(PR_IMPOSITIO,1)); + sc_start(NULL,&sd->bl,status->skill2sc(PR_MAGNIFICAT),100,1,skill->get_time(PR_MAGNIFICAT,1)); + sc_start(NULL,&sd->bl,status->skill2sc(PR_GLORIA),100,1,skill->get_time(PR_GLORIA,1)); + sc_start(NULL,&sd->bl,status->skill2sc(PR_SUFFRAGIUM),100,1,skill->get_time(PR_SUFFRAGIUM,1)); if (sd->state.snovice_dead_flag) sd->state.snovice_dead_flag = 0; //Reenable steelbody resurrection on dead. } else if( (sd->class_&MAPID_BASEMASK) == MAPID_TAEKWON ) { - sc_start(&sd->bl,status_skill2sc(AL_INCAGI),100,10,600000); - sc_start(&sd->bl,status_skill2sc(AL_BLESSING),100,10,600000); + sc_start(NULL,&sd->bl,status->skill2sc(AL_INCAGI),100,10,600000); + sc_start(NULL,&sd->bl,status->skill2sc(AL_BLESSING),100,10,600000); } clif->misceffect(&sd->bl,0); - npc_script_event(sd, NPCE_BASELVUP); //LORDALFA - LVLUPEVENT + npc->script_event(sd, NPCE_BASELVUP); //LORDALFA - LVLUPEVENT if(sd->status.party_id) party->send_levelup(sd); @@ -5715,7 +5941,6 @@ int pc_checkbaselevelup(struct map_session_data *sd) { } void pc_baselevelchanged(struct map_session_data *sd) { -#ifdef RENEWAL int i; for( i = 0; i < EQI_MAX; i++ ) { if( sd->equip_index[i] >= 0 ) { @@ -5723,9 +5948,8 @@ void pc_baselevelchanged(struct map_session_data *sd) { pc->unequipitem(sd, sd->equip_index[i], 3); } } -#endif - } + int pc_checkjoblevelup(struct map_session_data *sd) { unsigned int next = pc->nextjobexp(sd); @@ -5749,29 +5973,28 @@ int pc_checkjoblevelup(struct map_session_data *sd) clif->updatestatus(sd,SP_JOBEXP); clif->updatestatus(sd,SP_NEXTJOBEXP); clif->updatestatus(sd,SP_SKILLPOINT); - status_calc_pc(sd,0); + status_calc_pc(sd,SCO_FORCE); clif->misceffect(&sd->bl,1); if (pc->checkskill(sd, SG_DEVIL) && !pc->nextjobexp(sd)) clif->status_change(&sd->bl,SI_DEVIL1, 1, 0, 0, 0, 1); //Permanent blind effect from SG_DEVIL. - npc_script_event(sd, NPCE_JOBLVUP); + npc->script_event(sd, NPCE_JOBLVUP); return 1; } -/*========================================== - * Alters experienced based on self bonuses that do not get even shared to the party. - *------------------------------------------*/ -static void pc_calcexp(struct map_session_data *sd, unsigned int *base_exp, unsigned int *job_exp, struct block_list *src) -{ +/** + * 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 *status = status_get_status_data(src); + struct status_data *st = status->get_status_data(src); - if (sd->expaddrace[status->race]) - bonus += sd->expaddrace[status->race]; - bonus += sd->expaddrace[status->mode&MD_BOSS?RC_BOSS:RC_NONBOSS]; + if (sd->expaddrace[st->race]) + bonus += sd->expaddrace[st->race]; + bonus += sd->expaddrace[st->mode&MD_BOSS?RC_BOSS:RC_NONBOSS]; - if (battle_config.pk_mode && - (int)(status_get_lv(src) - sd->status.base_level) >= 20) + 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] if (sd->sc.data[SC_CASH_PLUSEXP]) @@ -5784,27 +6007,36 @@ static void pc_calcexp(struct map_session_data *sd, unsigned int *base_exp, unsi *job_exp = (unsigned int) cap_value(*job_exp + (double)*job_exp * bonus/100., 1, UINT_MAX); + if( sd->status.mod_exp != 100 ) { + *base_exp = (unsigned int) cap_value((double)*base_exp * sd->status.mod_exp/100., 1, UINT_MAX); + *job_exp = (unsigned int) cap_value((double)*job_exp * sd->status.mod_exp/100., 1, UINT_MAX); + + } + return; } -/*========================================== - * Give x exp at sd player and calculate remaining exp for next lvl - *------------------------------------------*/ -int pc_gainexp(struct map_session_data *sd, struct block_list *src, unsigned int base_exp,unsigned int job_exp,bool quest) -{ + +/** + * Gives a determined EXP amount to sd and calculates remaining EXP for next level + * @param src if is NULL no bonuses are taken into account + * @param is_quest Used to let client know that the EXP was from a quest (clif->displayexp) PACKETVER >= 20091027 + * @retval true success + **/ +bool pc_gainexp(struct map_session_data *sd, struct block_list *src, unsigned int base_exp,unsigned int job_exp,bool is_quest) { float nextbp=0, nextjp=0; unsigned int nextb=0, nextj=0; nullpo_ret(sd); if(sd->bl.prev == NULL || pc_isdead(sd)) - return 0; + return false; - if(!battle_config.pvp_exp && map[sd->bl.m].flag.pvp) // [MouseJstr] - return 0; // no exp on pvp maps + if(!battle_config.pvp_exp && map->list[sd->bl.m].flag.pvp) // [MouseJstr] + return false; // no exp on pvp maps 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); nextb = pc->nextbaseexp(sd); nextj = pc->nextjobexp(sd); @@ -5831,7 +6063,8 @@ int pc_gainexp(struct map_session_data *sd, struct block_list *src, unsigned int } } - //Cap exp to the level up requirement of the previous level when you are at max level, otherwise cap at UINT_MAX (this is required for some S. Novice bonuses). [Skotlex] + // Cap exp to the level up requirement of the previous level when you are at max level, + // otherwise cap at UINT_MAX (this is required for some S. Novice bonuses). [Skotlex] if (base_exp) { nextb = nextb?UINT_MAX:pc->thisbaseexp(sd); if(sd->status.base_exp > nextb - base_exp) @@ -5852,18 +6085,21 @@ int pc_gainexp(struct map_session_data *sd, struct block_list *src, unsigned int clif->updatestatus(sd,SP_JOBEXP); } +#if PACKETVER >= 20091027 if(base_exp) - clif->displayexp(sd, base_exp, SP_BASEEXP, quest); + clif->displayexp(sd, base_exp, SP_BASEEXP, is_quest); if(job_exp) - clif->displayexp(sd, job_exp, SP_JOBEXP, quest); + clif->displayexp(sd, job_exp, SP_JOBEXP, is_quest); +#endif + if(sd->state.showexp) { 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,strlen(output)); } - return 1; + return true; } /*========================================== @@ -5871,12 +6107,12 @@ int pc_gainexp(struct map_session_data *sd, struct block_list *src, unsigned int *------------------------------------------*/ unsigned int pc_maxbaselv(struct map_session_data *sd) { - return max_level[pc->class2idx(sd->status.class_)][0]; + return pc->max_level[pc->class2idx(sd->status.class_)][0]; } unsigned int pc_maxjoblv(struct map_session_data *sd) { - return max_level[pc->class2idx(sd->status.class_)][1]; + return pc->max_level[pc->class2idx(sd->status.class_)][1]; } /*========================================== @@ -5891,7 +6127,7 @@ unsigned int pc_nextbaseexp(struct map_session_data *sd) if(sd->status.base_level>=pc->maxbaselv(sd) || sd->status.base_level<=0) return 0; - return exp_table[pc->class2idx(sd->status.class_)][0][sd->status.base_level-1]; + return pc->exp_table[pc->class2idx(sd->status.class_)][0][sd->status.base_level-1]; } //Base exp needed for this level. @@ -5900,7 +6136,7 @@ unsigned int pc_thisbaseexp(struct map_session_data *sd) if(sd->status.base_level>pc->maxbaselv(sd) || sd->status.base_level<=1) return 0; - return exp_table[pc->class2idx(sd->status.class_)][0][sd->status.base_level-2]; + return pc->exp_table[pc->class2idx(sd->status.class_)][0][sd->status.base_level-2]; } @@ -5918,7 +6154,7 @@ unsigned int pc_nextjobexp(struct map_session_data *sd) if(sd->status.job_level>=pc->maxjoblv(sd) || sd->status.job_level<=0) return 0; - return exp_table[pc->class2idx(sd->status.class_)][1][sd->status.job_level-1]; + return pc->exp_table[pc->class2idx(sd->status.class_)][1][sd->status.job_level-1]; } //Job exp needed for this level. @@ -5926,41 +6162,41 @@ unsigned int pc_thisjobexp(struct map_session_data *sd) { if(sd->status.job_level>pc->maxjoblv(sd) || sd->status.job_level<=1) return 0; - return exp_table[pc->class2idx(sd->status.class_)][1][sd->status.job_level-2]; + return pc->exp_table[pc->class2idx(sd->status.class_)][1][sd->status.job_level-2]; } /// Returns the value of the specified stat. -static int pc_getstat(struct map_session_data* sd, int type) +int pc_getstat(struct map_session_data* sd, int type) { nullpo_retr(-1, sd); switch( type ) { - case SP_STR: return sd->status.str; - case SP_AGI: return sd->status.agi; - case SP_VIT: return sd->status.vit; - case SP_INT: return sd->status.int_; - case SP_DEX: return sd->status.dex; - case SP_LUK: return sd->status.luk; - default: - return -1; + case SP_STR: return sd->status.str; + case SP_AGI: return sd->status.agi; + case SP_VIT: return sd->status.vit; + case SP_INT: return sd->status.int_; + case SP_DEX: return sd->status.dex; + case SP_LUK: return sd->status.luk; + default: + return -1; } } /// Sets the specified stat to the specified value. /// Returns the new value. -static int pc_setstat(struct map_session_data* sd, int type, int val) +int pc_setstat(struct map_session_data* sd, int type, int val) { nullpo_retr(-1, sd); switch( type ) { - case SP_STR: sd->status.str = val; break; - case SP_AGI: sd->status.agi = val; break; - case SP_VIT: sd->status.vit = val; break; - case SP_INT: sd->status.int_ = val; break; - case SP_DEX: sd->status.dex = val; break; - case SP_LUK: sd->status.luk = val; break; - default: - return -1; + case SP_STR: sd->status.str = val; break; + case SP_AGI: sd->status.agi = val; break; + case SP_VIT: sd->status.vit = val; break; + case SP_INT: sd->status.int_ = val; break; + case SP_DEX: sd->status.dex = val; break; + case SP_LUK: sd->status.luk = val; break; + default: + return -1; } return val; @@ -5970,7 +6206,7 @@ static int pc_setstat(struct map_session_data* sd, int type, int val) int pc_gets_status_point(int level) { if (battle_config.use_statpoint_table) //Use values from "db/statpoint.txt" - return (statp[level+1] - statp[level]); + return (pc->statp[level+1] - pc->statp[level]); else //Default increase return ((level+15) / 5); } @@ -5985,7 +6221,7 @@ int pc_need_status_point(struct map_session_data* sd, int type, int val) if ( val == 0 ) return 0; - low = pc_getstat(sd,type); + low = pc->getstat(sd,type); if ( low >= pc_maxparameter(sd) && val > 0 ) return 0; // Official servers show '0' when max is reached @@ -6005,60 +6241,103 @@ int pc_need_status_point(struct map_session_data* sd, int type, int val) return sp; } -/// Raises a stat by 1. -/// Obeys max_parameter limits. -/// Subtracts stat points. -/// -/// @param type The stat to change (see enum _sp) -int pc_statusup(struct map_session_data* sd, int type) -{ - int max, need, val; +/** + * Returns the value the specified stat can be increased by with the current + * amount of available status points for the current character's class. + * + * @param sd The target character. + * @param type Stat to verify. + * @return Maximum value the stat could grow by. + */ +int pc_maxparameterincrease(struct map_session_data* sd, int type) { + int base, final, status_points = sd->status.status_point; + + base = final = pc->getstat(sd, type); + + while (final <= pc_maxparameter(sd) && status_points >= 0) { +#ifdef RENEWAL // renewal status point cost formula + status_points -= (final < 100) ? (2 + (final - 1) / 10) : (16 + 4 * ((final - 100) / 5)); +#else + status_points -= ( 1 + (final + 9) / 10 ); +#endif + final++; + } + final--; + + return final > base ? final-base : 0; +} + +/** + * Raises a stat by the specified amount. + * + * Obeys max_parameter limits. + * Subtracts status points according to the cost of the increased stat points. + * + * @param sd The target character. + * @param type The stat to change (see enum status_point_types) + * @param increase The stat increase (strictly positive) amount. + * @retval true if the stat was increased by any amount. + * @retval false if there were no changes. + */ +bool pc_statusup(struct map_session_data* sd, int type, int increase) { + int max_increase = 0, current = 0, needed_points = 0, final_value = 0; nullpo_ret(sd); // check conditions - need = pc->need_status_point(sd,type,1); - if( type < SP_STR || type > SP_LUK || need < 0 || need > sd->status.status_point ) - { - clif->statusupack(sd,type,0,0); - return 1; + if (type < SP_STR || type > SP_LUK || increase <= 0) { + clif->statusupack(sd, type, 0, 0); + return false; } // check limits - max = pc_maxparameter(sd); - if( pc_getstat(sd,type) >= max ) - { - clif->statusupack(sd,type,0,0); - return 1; + current = pc->getstat(sd, type); + max_increase = pc->maxparameterincrease(sd, type); + increase = cap_value(increase, 0, max_increase); // cap to the maximum status points available + if (increase <= 0 || current + increase > pc_maxparameter(sd)) { + clif->statusupack(sd, type, 0, 0); + return false; + } + + // check status points + needed_points = pc->need_status_point(sd, type, increase); + if (needed_points < 0 || needed_points > sd->status.status_point) { // Sanity check + clif->statusupack(sd, type, 0, 0); + return false; } // set new values - val = pc_setstat(sd, type, pc_getstat(sd,type) + 1); - sd->status.status_point -= need; + final_value = pc->setstat(sd, type, current + increase); + sd->status.status_point -= needed_points; - status_calc_pc(sd,0); + status_calc_pc(sd, SCO_NONE); // update increase cost indicator - if( need != pc->need_status_point(sd,type,1) ) - clif->updatestatus(sd, SP_USTR + type-SP_STR); + clif->updatestatus(sd, SP_USTR + type-SP_STR); // update statpoint count - clif->updatestatus(sd,SP_STATUSPOINT); + clif->updatestatus(sd, SP_STATUSPOINT); // update stat value - clif->statusupack(sd,type,1,val); // required - if( val > 255 ) - clif->updatestatus(sd,type); // send after the 'ack' to override the truncated value + clif->statusupack(sd, type, 1, final_value); // required + if (final_value > 255) + clif->updatestatus(sd, type); // send after the 'ack' to override the truncated value - return 0; + return true; } -/// Raises a stat by the specified amount. -/// Obeys max_parameter limits. -/// Does not subtract stat points. -/// -/// @param type The stat to change (see enum _sp) -/// @param val The stat increase amount. +/** + * Raises a stat by the specified amount. + * + * Obeys max_parameter limits. + * Does not subtract status points for the cost of the modified stat points. + * + * @param sd The target character. + * @param type The stat to change (see enum status_point_types) + * @param val The stat increase (or decrease) amount. + * @return the stat increase amount. + * @retval 0 if no changes were made. + */ int pc_statusup2(struct map_session_data* sd, int type, int val) { int max, need; @@ -6067,16 +6346,16 @@ int pc_statusup2(struct map_session_data* sd, int type, int val) if( type < SP_STR || type > SP_LUK ) { clif->statusupack(sd,type,0,0); - return 1; + return 0; } need = pc->need_status_point(sd,type,1); // set new value max = pc_maxparameter(sd); - val = pc_setstat(sd, type, cap_value(pc_getstat(sd,type) + val, 1, max)); + val = pc->setstat(sd, type, cap_value(pc->getstat(sd,type) + val, 1, max)); - status_calc_pc(sd,0); + status_calc_pc(sd,SCO_NONE); // update increase cost indicator if( need != pc->need_status_point(sd,type,1) ) @@ -6087,7 +6366,7 @@ int pc_statusup2(struct map_session_data* sd, int type, int val) if( val > 255 ) clif->updatestatus(sd,type); // send after the 'ack' to override the truncated value - return 0; + return val; } /*========================================== @@ -6110,7 +6389,7 @@ int pc_skillup(struct map_session_data *sd,uint16 skill_id) { if( !(index = skill->get_index(skill_id)) ) return 0; - + if( sd->status.skill_point > 0 && sd->status.skill[index].id && sd->status.skill[index].flag == SKILL_FLAG_PERMANENT && //Don't allow raising while you have granted skills. [Skotlex] @@ -6118,34 +6397,29 @@ int pc_skillup(struct map_session_data *sd,uint16 skill_id) { { sd->status.skill[index].lv++; sd->status.skill_point--; - if( !skill_db[index].inf ) - status_calc_pc(sd,0); // Only recalculate for passive skills. + if( !skill->db[index].inf ) + status_calc_pc(sd,SCO_NONE); // Only recalculate for passive skills. else if( sd->status.skill_point == 0 && (sd->class_&MAPID_UPPERMASK) == MAPID_TAEKWON && sd->status.base_level >= 90 && pc->famerank(sd->status.char_id, MAPID_TAEKWON) ) pc->calc_skilltree(sd); // Required to grant all TK Ranger skills. else - pc_check_skilltree(sd, skill_id); // Check if a new skill can Lvlup + pc->check_skilltree(sd, skill_id); // Check if a new skill can Lvlup - clif->skillup(sd,skill_id); + clif->skillup(sd,skill_id, sd->status.skill[index].lv, 1); clif->updatestatus(sd,SP_SKILLPOINT); if( skill_id == GN_REMODELING_CART ) /* cart weight info was updated by status_calc_pc */ clif->updatestatus(sd,SP_CARTINFO); if (!pc_has_permission(sd, PC_PERM_ALL_SKILL)) // may skill everything at any time anyways, and this would cause a huge slowdown clif->skillinfoblock(sd); - }else if( battle_config.skillup_limit ){ - int pts = 0, i, id; - for(i = 0; i < MAX_SKILL_TREE && (id=skill_tree[pc_class2idx(sd->status.class_)][i].id) > 0 ; i++){ - int inf2 = skill->get_inf2(id); - if ( inf2&INF2_QUEST_SKILL || (inf2&(INF2_WEDDING_SKILL|INF2_SPIRIT_SKILL)) || id == NV_BASIC ) - continue; - if( sd->status.skill[id].id && sd->status.skill[id].flag == SKILL_FLAG_PERMANENT ) - pts += pc_checkskill(sd, id); + } else if( battle_config.skillup_limit ){ + if( sd->sktree.second ) + clif->msg_value(sd, 0x61E, sd->sktree.second); + else if( sd->sktree.third ) + clif->msg_value(sd, 0x61F, sd->sktree.third); + else if( pc->calc_skillpoint(sd) < 9 ) { + /* TODO: official response? */ + clif->colormes(sd->fd,COLOR_RED,"You need the basic skills"); } - if( pts < sd->change_level_2nd ) - clif->msg_value(sd, 0x61E, sd->change_level_2nd-pts); - else if( pts < (sd->change_level_3rd + sd->change_level_2nd) ) - clif->msg_value(sd, 0x61F, sd->change_level_3rd - (pts - sd->change_level_2nd)); } - return 0; } @@ -6170,22 +6444,22 @@ int pc_allskillup(struct map_session_data *sd) if (pc_has_permission(sd, PC_PERM_ALL_SKILL)) { //Get ALL skills except npc/guild ones. [Skotlex] //and except SG_DEVIL [Komurka] and MO_TRIPLEATTACK and RG_SNATCHER [ultramage] for(i=0;i<MAX_SKILL;i++){ - switch( skill_db[i].nameid ) { + switch( skill->db[i].nameid ) { case SG_DEVIL: case MO_TRIPLEATTACK: case RG_SNATCHER: continue; default: - if( !(skill_db[i].inf2&(INF2_NPC_SKILL|INF2_GUILD_SKILL)) ) - if ( ( sd->status.skill[i].lv = skill_db[i].max ) )//Nonexistant skills should return a max of 0 anyway. - sd->status.skill[i].id = skill_db[i].nameid; + if( !(skill->db[i].inf2&(INF2_NPC_SKILL|INF2_GUILD_SKILL)) ) + if ( ( sd->status.skill[i].lv = skill->db[i].max ) )//Nonexistant skills should return a max of 0 anyway. + sd->status.skill[i].id = skill->db[i].nameid; } } } else { int inf2; - for(i=0;i < MAX_SKILL_TREE && (id=skill_tree[pc->class2idx(sd->status.class_)][i].id)>0;i++){ - int idx = skill_tree[pc->class2idx(sd->status.class_)][i].idx; - inf2 = skill_db[idx].inf2; + for(i=0;i < MAX_SKILL_TREE && (id=pc->skill_tree[pc->class2idx(sd->status.class_)][i].id)>0;i++){ + int idx = pc->skill_tree[pc->class2idx(sd->status.class_)][i].idx; + inf2 = skill->db[idx].inf2; if ( (inf2&INF2_QUEST_SKILL && !battle_config.quest_skill_learn) || (inf2&(INF2_WEDDING_SKILL|INF2_SPIRIT_SKILL)) || @@ -6197,7 +6471,7 @@ int pc_allskillup(struct map_session_data *sd) sd->status.skill[idx].lv = skill->tree_get_max(id, sd->status.class_); // celest } } - status_calc_pc(sd,0); + status_calc_pc(sd,SCO_NONE); //Required because if you could level up all skills previously, //the update will not be sent as only the lv variable changes. clif->skillinfoblock(sd); @@ -6287,7 +6561,7 @@ int pc_resetlvl(struct map_session_data* sd,int type) if ((type == 1 || type == 2 || type == 3) && sd->status.party_id) party->send_levelup(sd); - status_calc_pc(sd,0); + status_calc_pc(sd,SCO_FORCE); clif->skillinfoblock(sd); return 0; @@ -6302,33 +6576,33 @@ int pc_resetstate(struct map_session_data* sd) if (battle_config.use_statpoint_table) { // New statpoint table used here - Dexity if (sd->status.base_level > MAX_LEVEL) - { //statp[] goes out of bounds, can't reset! + { //pc->statp[] goes out of bounds, can't reset! ShowError("pc_resetstate: Can't reset stats of %d:%d, the base level (%d) is greater than the max level supported (%d)\n", sd->status.account_id, sd->status.char_id, sd->status.base_level, MAX_LEVEL); return 0; } - sd->status.status_point = statp[sd->status.base_level] + ( sd->class_&JOBL_UPPER ? 52 : 0 ); // extra 52+48=100 stat points + sd->status.status_point = pc->statp[sd->status.base_level] + ( sd->class_&JOBL_UPPER ? 52 : 0 ); // extra 52+48=100 stat points } else { int add=0; - add += pc->need_status_point(sd, SP_STR, 1-pc_getstat(sd, SP_STR)); - add += pc->need_status_point(sd, SP_AGI, 1-pc_getstat(sd, SP_AGI)); - add += pc->need_status_point(sd, SP_VIT, 1-pc_getstat(sd, SP_VIT)); - add += pc->need_status_point(sd, SP_INT, 1-pc_getstat(sd, SP_INT)); - add += pc->need_status_point(sd, SP_DEX, 1-pc_getstat(sd, SP_DEX)); - add += pc->need_status_point(sd, SP_LUK, 1-pc_getstat(sd, SP_LUK)); + add += pc->need_status_point(sd, SP_STR, 1-pc->getstat(sd, SP_STR)); + add += pc->need_status_point(sd, SP_AGI, 1-pc->getstat(sd, SP_AGI)); + add += pc->need_status_point(sd, SP_VIT, 1-pc->getstat(sd, SP_VIT)); + add += pc->need_status_point(sd, SP_INT, 1-pc->getstat(sd, SP_INT)); + add += pc->need_status_point(sd, SP_DEX, 1-pc->getstat(sd, SP_DEX)); + add += pc->need_status_point(sd, SP_LUK, 1-pc->getstat(sd, SP_LUK)); sd->status.status_point+=add; } - pc_setstat(sd, SP_STR, 1); - pc_setstat(sd, SP_AGI, 1); - pc_setstat(sd, SP_VIT, 1); - pc_setstat(sd, SP_INT, 1); - pc_setstat(sd, SP_DEX, 1); - pc_setstat(sd, SP_LUK, 1); + pc->setstat(sd, SP_STR, 1); + pc->setstat(sd, SP_AGI, 1); + pc->setstat(sd, SP_VIT, 1); + pc->setstat(sd, SP_INT, 1); + pc->setstat(sd, SP_DEX, 1); + pc->setstat(sd, SP_LUK, 1); clif->updatestatus(sd,SP_STR); clif->updatestatus(sd,SP_AGI); @@ -6349,10 +6623,10 @@ int pc_resetstate(struct map_session_data* sd) if( sd->mission_mobid ) { //bugreport:2200 sd->mission_mobid = 0; sd->mission_count = 0; - pc_setglobalreg(sd,"TK_MISSION_ID", 0); + pc_setglobalreg(sd,script->add_str("TK_MISSION_ID"), 0); } - status_calc_pc(sd,0); + status_calc_pc(sd,SCO_NONE); return 1; } @@ -6382,7 +6656,7 @@ int pc_resetskill(struct map_session_data* sd, int flag) if( pc->checkskill(sd, SG_DEVIL) && !pc->nextjobexp(sd) ) //Remove perma blindness due to skill-reset. [Skotlex] clif->sc_end(&sd->bl, sd->bl.id, SELF, SI_DEVIL1); i = sd->sc.option; - if( i&OPTION_RIDING && (!pc->checkskill(sd, KN_RIDING) || (sd->class_&MAPID_THIRDMASK) == MAPID_RUNE_KNIGHT) ) + if( i&OPTION_RIDING && pc->checkskill(sd, KN_RIDING) ) i &= ~OPTION_RIDING; if( i&OPTION_FALCON && pc->checkskill(sd, HT_FALCON) ) i &= ~OPTION_FALCON; @@ -6405,7 +6679,7 @@ int pc_resetskill(struct map_session_data* sd, int flag) pc->setoption(sd, i); if( homun_alive(sd->hd) && pc->checkskill(sd, AM_CALLHOMUN) ) - homun->vaporize(sd, 0); + homun->vaporize(sd, HOM_ST_REST); } for( i = 1; i < MAX_SKILL; i++ ) { @@ -6413,22 +6687,22 @@ int pc_resetskill(struct map_session_data* sd, int flag) lv = sd->status.skill[i].lv; if (lv < 1) continue; - inf2 = skill_db[i].inf2; + inf2 = skill->db[i].inf2; if( inf2&(INF2_WEDDING_SKILL|INF2_SPIRIT_SKILL) ) //Avoid reseting wedding/linker skills. continue; - skill_id = skill_db[i].nameid; + skill_id = skill->db[i].nameid; // Don't reset trick dead if not a novice/baby - if( skill_id == NV_TRICKDEAD && (sd->class_&MAPID_UPPERMASK) != MAPID_NOVICE ) { + if( skill_id == NV_TRICKDEAD && (sd->class_&(MAPID_BASEMASK|JOBL_2)) != MAPID_NOVICE ) { sd->status.skill[i].lv = 0; sd->status.skill[i].flag = 0; continue; } // do not reset basic skill - if( skill_id == NV_BASIC && (sd->class_&MAPID_UPPERMASK) != MAPID_NOVICE ) + if( skill_id == NV_BASIC && (sd->class_&(MAPID_BASEMASK|JOBL_2)) != MAPID_NOVICE ) continue; if( sd->status.skill[i].flag == SKILL_FLAG_PERM_GRANTED ) @@ -6447,8 +6721,7 @@ int pc_resetskill(struct map_session_data* sd, int flag) } if( sd->status.skill[i].flag == SKILL_FLAG_PERMANENT ) skill_point += lv; - else - if( sd->status.skill[i].flag == SKILL_FLAG_REPLACED_LV_0 ) + else if( sd->status.skill[i].flag >= SKILL_FLAG_REPLACED_LV_0 ) skill_point += (sd->status.skill[i].flag - SKILL_FLAG_REPLACED_LV_0); if( !(flag&2) ) {// reset @@ -6461,10 +6734,25 @@ int pc_resetskill(struct map_session_data* sd, int flag) sd->status.skill_point += skill_point; + + if( !(flag&2) ) { + // Remove all SCs that can't be inactivated without a skill + if( sd->sc.data[SC_STORMKICK_READY] ) + status_change_end(&sd->bl, SC_STORMKICK_READY, INVALID_TIMER); + if( sd->sc.data[SC_DOWNKICK_READY] ) + status_change_end(&sd->bl, SC_DOWNKICK_READY, INVALID_TIMER); + if( sd->sc.data[SC_TURNKICK_READY] ) + status_change_end(&sd->bl, SC_TURNKICK_READY, INVALID_TIMER); + if( sd->sc.data[SC_COUNTERKICK_READY] ) + status_change_end(&sd->bl, SC_COUNTERKICK_READY, INVALID_TIMER); + if( sd->sc.data[SC_DODGE_READY] ) + status_change_end(&sd->bl, SC_DODGE_READY, INVALID_TIMER); + } + if( flag&1 ) { clif->updatestatus(sd,SP_SKILLPOINT); clif->skillinfoblock(sd); - status_calc_pc(sd,0); + status_calc_pc(sd,SCO_FORCE); } return skill_point; @@ -6482,7 +6770,7 @@ int pc_resetfeel(struct map_session_data* sd) { sd->feel_map[i].m = -1; sd->feel_map[i].index = 0; - pc_setglobalreg(sd,sg_info[i].feel_var,0); + pc_setglobalreg(sd,script->add_str(pc->sg_info[i].feel_var),0); } return 0; @@ -6496,7 +6784,7 @@ int pc_resethate(struct map_session_data* sd) for (i=0; i<3; i++) { sd->hate_mob[i] = -1; - pc_setglobalreg(sd,sg_info[i].hate_var,0); + pc_setglobalreg(sd,script->add_str(pc->sg_info[i].hate_var),0); } return 0; } @@ -6551,7 +6839,7 @@ void pc_respawn(struct map_session_data* sd, clr_type clrtype) { if( !pc_isdead(sd) ) return; // not applicable - if( sd->bg_id && bg_member_respawn(sd) ) + if( sd->bg_id && bg->member_respawn(sd) ) return; // member revived by battleground pc->setstand(sd); @@ -6560,9 +6848,8 @@ void pc_respawn(struct map_session_data* sd, clr_type clrtype) clif->resurrection(&sd->bl, 1); //If warping fails, send a normal stand up packet. } -static int pc_respawn_timer(int tid, unsigned int tick, int id, intptr_t data) -{ - struct map_session_data *sd = iMap->id2sd(id); +int pc_respawn_timer(int tid, int64 tick, int id, intptr_t data) { + struct map_session_data *sd = map->id2sd(id); if( sd != NULL ) { sd->pvp_point=0; @@ -6589,86 +6876,89 @@ void pc_damage(struct map_session_data *sd,struct block_list *src,unsigned int h skill->sit(sd,0); } - if( sd->progressbar.npc_id ) + if( sd->progressbar.npc_id ){ clif->progressbar_abort(sd); + sd->state.workinprogress = 0; + } if( sd->status.pet_id > 0 && sd->pd && battle_config.pet_damage_support ) - pet_target_check(sd,src,1); + pet->target_check(sd,src,1); if( sd->status.ele_id > 0 ) - elemental_set_target(sd,src); + elemental->set_target(sd,src); - sd->canlog_tick = iTimer->gettick(); + sd->canlog_tick = timer->gettick(); } /*========================================== * Invoked when a player has negative current hp *------------------------------------------*/ int pc_dead(struct map_session_data *sd,struct block_list *src) { - int i=0,j=0,k=0; - unsigned int tick = iTimer->gettick(); + int i=0,j=0; + int64 tick = timer->gettick(); - for(k = 0; k < 5; k++) - if (sd->devotion[k]){ - struct map_session_data *devsd = iMap->id2sd(sd->devotion[k]); + for(j = 0; j < 5; j++) { + if (sd->devotion[j]){ + struct map_session_data *devsd = map->id2sd(sd->devotion[j]); if (devsd) status_change_end(&devsd->bl, SC_DEVOTION, INVALID_TIMER); - sd->devotion[k] = 0; + sd->devotion[j] = 0; } + } if(sd->status.pet_id > 0 && sd->pd) { struct pet_data *pd = sd->pd; - if( !map[sd->bl.m].flag.noexppenalty ) { - pet_set_intimate(pd, pd->pet.intimate - pd->petDB->die); + if( !map->list[sd->bl.m].flag.noexppenalty ) { + pet->set_intimate(pd, pd->pet.intimate - pd->petDB->die); if( pd->pet.intimate < 0 ) pd->pet.intimate = 0; clif->send_petdata(sd,sd->pd,1,pd->pet.intimate); } if( sd->pd->target_id ) // Unlock all targets... - pet_unlocktarget(sd->pd); + pet->unlocktarget(sd->pd); } if (sd->status.hom_id > 0){ - if(battle_config.homunculus_auto_vapor && sd->hd && !sd->hd->sc.data[SC_LIGHT_OF_REGENE]) - homun->vaporize(sd, 0); + if(battle_config.homunculus_auto_vapor && sd->hd) + homun->vaporize(sd, HOM_ST_REST); } if( sd->md ) - merc_delete(sd->md, 3); // Your mercenary soldier has ran away. + mercenary->delete(sd->md, 3); // Your mercenary soldier has ran away. if( sd->ed ) - elemental_delete(sd->ed, 0); + elemental->delete(sd->ed, 0); // Leave duel if you die [LuzZza] if(battle_config.duel_autoleave_when_die) { if(sd->duel_group > 0) - duel_leave(sd->duel_group, sd); + duel->leave(sd->duel_group, sd); if(sd->duel_invite > 0) - duel_reject(sd->duel_invite, sd); + duel->reject(sd->duel_invite, sd); } if (sd->npc_id && sd->st && sd->st->state != RUN) - npc_event_dequeue(sd); + npc->event_dequeue(sd); - pc_setglobalreg(sd,"PC_DIE_COUNTER",sd->die_counter+1); + pc_setglobalreg(sd,script->add_str("PC_DIE_COUNTER"),sd->die_counter+1); pc->setparam(sd, SP_KILLERRID, src?src->id:0); if( sd->bg_id ) {/* TODO: purge when bgqueue is deemed ok */ - struct battleground_data *bg; - if( (bg = bg_team_search(sd->bg_id)) != NULL && bg->die_event[0] ) - npc_event(sd, bg->die_event, 0); + struct battleground_data *bgd; + if( (bgd = bg->team_search(sd->bg_id)) != NULL && bgd->die_event[0] ) + npc->event(sd, bgd->die_event, 0); } for( i = 0; i < sd->queues_count; i++ ) { struct hQueue *queue; if( (queue = script->queue(sd->queues[i])) && queue->onDeath[0] != '\0' ) - npc_event(sd, queue->onDeath, 0); + npc->event(sd, queue->onDeath, 0); } - npc_script_event(sd,NPCE_DIE); + npc->script_event(sd,NPCE_DIE); // Clear anything NPC-related when you die and was interacting with one. - if (sd->npc_id || sd->npc_shopid) { + if ( (sd->npc_id || sd->npc_shopid) && sd->state.dialog) { if (sd->state.using_fake_npc) { clif->clearunit_single(sd->npc_id, CLR_OUTSIGHT, sd->fd); sd->state.using_fake_npc = 0; @@ -6710,14 +7000,14 @@ int pc_dead(struct map_session_data *sd,struct block_list *src) { { struct mob_data *md=(struct mob_data *)src; if(md->target_id==sd->bl.id) - mob_unlocktarget(md,tick); + mob->unlocktarget(md,tick); if(battle_config.mobs_level_up && md->status.hp && (unsigned int)md->level < pc->maxbaselv(sd) && !md->guardian_data && !md->special_state.ai// Guardians/summons should not level. [Skotlex] ) { // monster level up [Valaris] clif->misceffect(&md->bl,0); md->level++; - status_calc_mob(md, 0); + status_calc_mob(md, SCO_NONE); status_percent_heal(src,10,0); if( battle_config.show_mob_info&4 ) @@ -6743,12 +7033,12 @@ int pc_dead(struct map_session_data *sd,struct block_list *src) { if (src && src->type == BL_PC) { struct map_session_data *ssd = (struct map_session_data *)src; pc->setparam(ssd, SP_KILLEDRID, sd->bl.id); - npc_script_event(ssd, NPCE_KILLPC); + npc->script_event(ssd, NPCE_KILLPC); if (battle_config.pk_mode&2) { ssd->status.manner -= 5; if(ssd->status.manner < 0) - sc_start(src,SC_NOCHAT,100,0,0); + sc_start(NULL,src,SC_NOCHAT,100,0,0); #if 0 // PK/Karma system code (not enabled yet) [celest] // originally from Kade Online, so i don't know if any of these is correct ^^; @@ -6775,9 +7065,9 @@ int pc_dead(struct map_session_data *sd,struct block_list *src) { } } - if(battle_config.bone_drop==2 - || (battle_config.bone_drop==1 && map[sd->bl.m].flag.pvp)) - { + if( battle_config.bone_drop==2 + || (battle_config.bone_drop==1 && map->list[sd->bl.m].flag.pvp) + ) { struct item item_tmp; memset(&item_tmp,0,sizeof(item_tmp)); item_tmp.nameid=ITEMID_SKULL_; @@ -6786,12 +7076,11 @@ int pc_dead(struct map_session_data *sd,struct block_list *src) { item_tmp.card[1]=0; item_tmp.card[2]=GetWord(sd->status.char_id,0); // CharId item_tmp.card[3]=GetWord(sd->status.char_id,1); - iMap->addflooritem(&item_tmp,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0); + map->addflooritem(&item_tmp,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0); } // activate Steel body if a super novice dies at 99+% exp [celest] - if ((sd->class_&MAPID_UPPERMASK) == MAPID_SUPER_NOVICE && !sd->state.snovice_dead_flag) - { + if ((sd->class_&MAPID_UPPERMASK) == MAPID_SUPER_NOVICE && !sd->state.snovice_dead_flag) { unsigned int next = pc->nextbaseexp(sd); if( next == 0 ) next = pc->thisbaseexp(sd); if( get_percentage(sd->status.base_exp,next) >= 99 ) { @@ -6801,79 +7090,86 @@ int pc_dead(struct map_session_data *sd,struct block_list *src) { clif->resurrection(&sd->bl, 1); if(battle_config.pc_invincible_time) pc->setinvincibletimer(sd, battle_config.pc_invincible_time); - sc_start(&sd->bl,status_skill2sc(MO_STEELBODY),100,1,skill->get_time(MO_STEELBODY,1)); - if(map_flag_gvg(sd->bl.m)) - pc_respawn_timer(INVALID_TIMER, iTimer->gettick(), sd->bl.id, 0); + sc_start(NULL,&sd->bl,status->skill2sc(MO_STEELBODY),100,1,skill->get_time(MO_STEELBODY,1)); + if(map_flag_gvg2(sd->bl.m)) + pc->respawn_timer(INVALID_TIMER, timer->gettick(), sd->bl.id, 0); return 0; } } // changed penalty options, added death by player if pk_mode [Valaris] - if(battle_config.death_penalty_type - && (sd->class_&MAPID_UPPERMASK) != MAPID_NOVICE // only novices will receive no penalty - && !map[sd->bl.m].flag.noexppenalty && !map_flag_gvg(sd->bl.m) - && !sd->sc.data[SC_BABY] && !sd->sc.data[SC_CASH_DEATHPENALTY]) - { - unsigned int base_penalty =0; + if( battle_config.death_penalty_type + && (sd->class_&MAPID_UPPERMASK) != MAPID_NOVICE // only novices will receive no penalty + && !map->list[sd->bl.m].flag.noexppenalty && !map_flag_gvg2(sd->bl.m) + && !sd->sc.data[SC_BABY] && !sd->sc.data[SC_CASH_DEATHPENALTY] + ) { + unsigned int base_penalty = 0; if (battle_config.death_penalty_base > 0) { + switch (battle_config.death_penalty_type) { case 1: base_penalty = (unsigned int) ((double)pc->nextbaseexp(sd) * (double)battle_config.death_penalty_base/10000); - break; + break; case 2: base_penalty = (unsigned int) ((double)sd->status.base_exp * (double)battle_config.death_penalty_base/10000); - break; + break; } + if(base_penalty) { if (battle_config.pk_mode && src && src->type==BL_PC) base_penalty*=2; + if( sd->status.mod_death != 100 ) + base_penalty = base_penalty * sd->status.mod_death / 100; sd->status.base_exp -= min(sd->status.base_exp, base_penalty); clif->updatestatus(sd,SP_BASEEXP); } } - if(battle_config.death_penalty_job > 0) - { + + if(battle_config.death_penalty_job > 0) { base_penalty = 0; + switch (battle_config.death_penalty_type) { case 1: base_penalty = (unsigned int) ((double)pc->nextjobexp(sd) * (double)battle_config.death_penalty_job/10000); - break; + break; case 2: base_penalty = (unsigned int) ((double)sd->status.job_exp * (double)battle_config.death_penalty_job/10000); - break; + break; } + if(base_penalty) { if (battle_config.pk_mode && src && src->type==BL_PC) base_penalty*=2; + if( sd->status.mod_death != 100 ) + base_penalty = base_penalty * sd->status.mod_death / 100; sd->status.job_exp -= min(sd->status.job_exp, base_penalty); clif->updatestatus(sd,SP_JOBEXP); } } - if(battle_config.zeny_penalty > 0 && !map[sd->bl.m].flag.nozenypenalty) - { + + if(battle_config.zeny_penalty > 0 && !map->list[sd->bl.m].flag.nozenypenalty) { base_penalty = (unsigned int)((double)sd->status.zeny * (double)battle_config.zeny_penalty / 10000.); if(base_penalty) pc->payzeny(sd, base_penalty, LOG_TYPE_PICKDROP_PLAYER, NULL); } } - if(map[sd->bl.m].flag.pvp_nightmaredrop) - { // Moved this outside so it works when PVP isn't enabled and during pk mode [Ancyker] - for(j=0;j<map[sd->bl.m].drop_list_count;j++){ - int id = map[sd->bl.m].drop_list[j].drop_id; - int type = map[sd->bl.m].drop_list[j].drop_type; - int per = map[sd->bl.m].drop_list[j].drop_per; + if(map->list[sd->bl.m].flag.pvp_nightmaredrop) { + // Moved this outside so it works when PVP isn't enabled and during pk mode [Ancyker] + for(j=0;j<map->list[sd->bl.m].drop_list_count;j++){ + int id = map->list[sd->bl.m].drop_list[j].drop_id; + int type = map->list[sd->bl.m].drop_list[j].drop_type; + int per = map->list[sd->bl.m].drop_list[j].drop_per; if(id == 0) continue; if(id == -1){ - int eq_num=0,eq_n[MAX_INVENTORY]; + int eq_num=0,eq_n[MAX_INVENTORY],k; memset(eq_n,0,sizeof(eq_n)); for(i=0;i<MAX_INVENTORY;i++){ if( (type == 1 && !sd->status.inventory[i].equip) || (type == 2 && sd->status.inventory[i].equip) || type == 3) { - int k; ARR_FIND( 0, MAX_INVENTORY, k, eq_n[k] <= 0 ); if( k < MAX_INVENTORY ) eq_n[k] = i; @@ -6906,10 +7202,20 @@ int pc_dead(struct map_session_data *sd,struct block_list *src) { } } } + + // Remove autotrade to prevent autotrading from save point + if( (sd->state.standalone || sd->state.autotrade) + && (map->list[sd->bl.m].flag.pvp || map->list[sd->bl.m].flag.gvg) + ) { + sd->state.autotrade = 0; + sd->state.standalone = 0; + pc->autotrade_update(sd,PAUC_REMOVE); + map->quit(sd); + } + // pvp // disable certain pvp functions on pk_mode [Valaris] - if( map[sd->bl.m].flag.pvp && !battle_config.pk_mode && !map[sd->bl.m].flag.pvp_nocalcrank ) - { + if( map->list[sd->bl.m].flag.pvp && !battle_config.pk_mode && !map->list[sd->bl.m].flag.pvp_nocalcrank ) { sd->pvp_point -= 5; sd->pvp_lost++; if( src && src->type == BL_PC ) @@ -6920,30 +7226,26 @@ int pc_dead(struct map_session_data *sd,struct block_list *src) { } if( sd->pvp_point < 0 ) { - iTimer->add_timer(tick+1000, pc_respawn_timer,sd->bl.id,0); + timer->add(tick+1, pc->respawn_timer,sd->bl.id,0); return 1|8; } } //GvG - if( map_flag_gvg(sd->bl.m) ) - { - iTimer->add_timer(tick+1000, pc_respawn_timer, sd->bl.id, 0); + if( map_flag_gvg2(sd->bl.m) ) { + timer->add(tick+1, pc->respawn_timer, sd->bl.id, 0); return 1|8; - } - else if( sd->bg_id ) - { - struct battleground_data *bg = bg_team_search(sd->bg_id); - if( bg && bg->mapindex > 0 ) - { // Respawn by BG - iTimer->add_timer(tick+1000, pc_respawn_timer, sd->bl.id, 0); + } else if( sd->bg_id ) { + struct battleground_data *bgd = bg->team_search(sd->bg_id); + if( bgd && bgd->mapindex > 0 ) { // Respawn by BG + timer->add(tick+1000, pc->respawn_timer, sd->bl.id, 0); return 1|8; } } - //Reset "can log out" tick. if( battle_config.prevent_logout ) - sd->canlog_tick = iTimer->gettick() - battle_config.prevent_logout; + sd->canlog_tick = timer->gettick() - battle_config.prevent_logout; + return 1; } @@ -6956,10 +7258,10 @@ void pc_revive(struct map_session_data *sd,unsigned int hp, unsigned int sp) { pc->setinvincibletimer(sd, battle_config.pc_invincible_time); if( sd->state.gmaster_flag ) { - guild->aura_refresh(sd,GD_LEADERSHIP,guild->checkskill(sd->state.gmaster_flag,GD_LEADERSHIP)); - guild->aura_refresh(sd,GD_GLORYWOUNDS,guild->checkskill(sd->state.gmaster_flag,GD_GLORYWOUNDS)); - guild->aura_refresh(sd,GD_SOULCOLD,guild->checkskill(sd->state.gmaster_flag,GD_SOULCOLD)); - guild->aura_refresh(sd,GD_HAWKEYES,guild->checkskill(sd->state.gmaster_flag,GD_HAWKEYES)); + guild->aura_refresh(sd,GD_LEADERSHIP,guild->checkskill(sd->guild,GD_LEADERSHIP)); + guild->aura_refresh(sd,GD_GLORYWOUNDS,guild->checkskill(sd->guild,GD_GLORYWOUNDS)); + guild->aura_refresh(sd,GD_SOULCOLD,guild->checkskill(sd->guild,GD_SOULCOLD)); + guild->aura_refresh(sd,GD_HAWKEYES,guild->checkskill(sd->guild,GD_HAWKEYES)); } } // script @@ -7007,6 +7309,9 @@ int pc_readparam(struct map_session_data* sd,int type) case SP_KILLEDRID: val = sd->killedrid; break; case SP_SLOTCHANGE: val = sd->status.slotchange; break; case SP_CHARRENAME: val = sd->status.rename; break; + case SP_MOD_EXP: val = sd->status.mod_exp; break; + case SP_MOD_DROP: val = sd->status.mod_drop; break; + case SP_MOD_DEATH: val = sd->status.mod_death; break; case SP_CRITICAL: val = sd->battle_status.cri/10; break; case SP_ASPD: val = (2000-sd->battle_status.amotion)/10; break; case SP_BASE_ATK: val = sd->battle_status.batk; break; @@ -7020,7 +7325,7 @@ int pc_readparam(struct map_session_data* sd,int type) case SP_DEFELE: val = sd->battle_status.def_ele; break; #ifndef RENEWAL_CAST case SP_VARCASTRATE: -#endif +#endif case SP_CASTRATE: val = sd->castrate+=val; break; @@ -7139,7 +7444,7 @@ int pc_setparam(struct map_session_data *sd,int type,int val) clif->updatestatus(sd, SP_NEXTBASEEXP); clif->updatestatus(sd, SP_STATUSPOINT); clif->updatestatus(sd, SP_BASEEXP); - status_calc_pc(sd, 0); + status_calc_pc(sd, SCO_FORCE); if(sd->status.party_id) { party->send_levelup(sd); @@ -7156,7 +7461,7 @@ int pc_setparam(struct map_session_data *sd,int type,int val) // clif->updatestatus(sd, SP_JOBLEVEL); // Gets updated at the bottom clif->updatestatus(sd, SP_NEXTJOBEXP); clif->updatestatus(sd, SP_JOBEXP); - status_calc_pc(sd, 0); + status_calc_pc(sd, SCO_FORCE); break; case SP_SKILLPOINT: sd->status.skill_point = val; @@ -7238,7 +7543,13 @@ int pc_setparam(struct map_session_data *sd,int type,int val) break; case SP_MANNER: sd->status.manner = val; - break; + if( val < 0 ) + sc_start(NULL, &sd->bl, SC_NOCHAT, 100, 0, 0); + else { + status_change_end(&sd->bl, SC_NOCHAT, INVALID_TIMER); + clif->manner_message(sd, 5); + } + return 1; // status_change_start/status_change_end already sends packets warning the client case SP_FAME: sd->status.fame = val; break; @@ -7254,6 +7565,15 @@ int pc_setparam(struct map_session_data *sd,int type,int val) case SP_CHARRENAME: sd->status.rename = val; return 1; + case SP_MOD_EXP: + sd->status.mod_exp = val; + return 1; + case SP_MOD_DROP: + sd->status.mod_drop = val; + return 1; + case SP_MOD_DEATH: + sd->status.mod_death = val; + return 1; default: ShowError("pc_setparam: Attempted to set unknown parameter '%d'.\n", type); return 0; @@ -7289,7 +7609,7 @@ void pc_heal(struct map_session_data *sd,unsigned int hp,unsigned int sp, int ty *------------------------------------------*/ int pc_itemheal(struct map_session_data *sd,int itemid, int hp,int sp) { - int bonus; + int bonus, tmp; if(hp) { int i; @@ -7297,22 +7617,22 @@ int pc_itemheal(struct map_session_data *sd,int itemid, int hp,int sp) + pc->checkskill(sd,SM_RECOVERY)*10 + pc->checkskill(sd,AM_LEARNINGPOTION)*5; // A potion produced by an Alchemist in the Fame Top 10 gets +50% effect [DracoRPG] - if (potion_flag > 1) - bonus += bonus*(potion_flag-1)*50/100; + if (script->potion_flag > 1) + bonus += bonus*(script->potion_flag-1)*50/100; //All item bonuses. bonus += sd->bonus.itemhealrate2; - //Item Group bonuses - bonus += bonus*itemdb_group_bonus(sd, itemid)/100; //Individual item bonuses. - for(i = 0; i < ARRAYLENGTH(sd->itemhealrate) && sd->itemhealrate[i].nameid; i++) - { - if (sd->itemhealrate[i].nameid == itemid) { + for(i = 0; i < ARRAYLENGTH(sd->itemhealrate) && sd->itemhealrate[i].nameid; i++) { + struct item_data *it = itemdb->exists(sd->itemhealrate[i].nameid); + if (sd->itemhealrate[i].nameid == itemid || (it && it->group && itemdb->in_group(it->group,itemid))) { bonus += bonus*sd->itemhealrate[i].rate/100; break; } } - if(bonus!=100) - hp = hp * bonus / 100; + + tmp = hp*bonus/100; + if(bonus != 100 && tmp > hp) + hp = tmp; // Recovery Potion if( sd->sc.data[SC_HEALPLUS] ) @@ -7322,10 +7642,12 @@ int pc_itemheal(struct map_session_data *sd,int itemid, int hp,int sp) bonus = 100 + (sd->battle_status.int_<<1) + pc->checkskill(sd,MG_SRECOVERY)*10 + pc->checkskill(sd,AM_LEARNINGPOTION)*5; - if (potion_flag > 1) - bonus += bonus*(potion_flag-1)*50/100; - if(bonus != 100) - sp = sp * bonus / 100; + if (script->potion_flag > 1) + bonus += bonus*(script->potion_flag-1)*50/100; + + tmp = sp*bonus/100; + if(bonus != 100 && tmp > sp) + sp = tmp; } if( sd->sc.count ) { if ( sd->sc.data[SC_CRITICALWOUND] ) { @@ -7333,6 +7655,11 @@ int pc_itemheal(struct map_session_data *sd,int itemid, int hp,int sp) sp -= sp * sd->sc.data[SC_CRITICALWOUND]->val2 / 100; } + if( sd->sc.data[SC_VITALITYACTIVATION] ){ + hp += hp / 2; // 1.5 times + sp -= sp / 2; + } + if ( sd->sc.data[SC_DEATHHURT] ) { hp -= hp * 20 / 100; sp -= sp * 20 / 100; @@ -7348,7 +7675,7 @@ int pc_itemheal(struct map_session_data *sd,int itemid, int hp,int sp) #endif } - return status_heal(&sd->bl, hp, sp, 1); + return status->heal(&sd->bl, hp, sp, 1); } /*========================================== @@ -7390,7 +7717,7 @@ int pc_percentheal(struct map_session_data *sd,int hp,int sp) return 0; } -static int jobchange_killclone(struct block_list *bl, va_list ap) +int jobchange_killclone(struct block_list *bl, va_list ap) { struct mob_data *md; int flag; @@ -7441,12 +7768,12 @@ int pc_jobchange(struct map_session_data *sd,int job, int upper) // changing from 1st to 2nd job if ((b_class&JOBL_2) && !(sd->class_&JOBL_2) && (b_class&MAPID_UPPERMASK) != MAPID_SUPER_NOVICE) { sd->change_level_2nd = sd->status.job_level; - pc_setglobalreg (sd, "jobchange_level", sd->change_level_2nd); + pc_setglobalreg (sd, script->add_str("jobchange_level"), sd->change_level_2nd); } // changing from 2nd to 3rd job else if((b_class&JOBL_THIRD) && !(sd->class_&JOBL_THIRD)) { sd->change_level_3rd = sd->status.job_level; - pc_setglobalreg (sd, "jobchange_level_3rd", sd->change_level_3rd); + pc_setglobalreg (sd, script->add_str("jobchange_level_3rd"), sd->change_level_3rd); } if(sd->cloneskill_id) { @@ -7458,8 +7785,8 @@ int pc_jobchange(struct map_session_data *sd,int job, int upper) clif->deleteskill(sd,sd->cloneskill_id); } sd->cloneskill_id = 0; - pc_setglobalreg(sd, "CLONE_SKILL", 0); - pc_setglobalreg(sd, "CLONE_SKILL_LV", 0); + pc_setglobalreg(sd, script->add_str("CLONE_SKILL"), 0); + pc_setglobalreg(sd, script->add_str("CLONE_SKILL_LV"), 0); } if(sd->reproduceskill_id) { @@ -7471,16 +7798,16 @@ int pc_jobchange(struct map_session_data *sd,int job, int upper) clif->deleteskill(sd,sd->reproduceskill_id); } sd->reproduceskill_id = 0; - pc_setglobalreg(sd, "REPRODUCE_SKILL",0); - pc_setglobalreg(sd, "REPRODUCE_SKILL_LV",0); + pc_setglobalreg(sd, script->add_str("REPRODUCE_SKILL"),0); + pc_setglobalreg(sd, script->add_str("REPRODUCE_SKILL_LV"),0); } if ( (b_class&MAPID_UPPERMASK) != (sd->class_&MAPID_UPPERMASK) ) { //Things to remove when changing class tree. const int class_ = pc->class2idx(sd->status.class_); short id; - for(i = 0; i < MAX_SKILL_TREE && (id = skill_tree[class_][i].id) > 0; i++) { + for(i = 0; i < MAX_SKILL_TREE && (id = pc->skill_tree[class_][i].id) > 0; i++) { //Remove status specific to your current tree skills. - enum sc_type sc = status_skill2sc(id); + enum sc_type sc = status->skill2sc(id); if (sc > SC_COMMON_MAX && sd->sc.data[sc]) status_change_end(&sd->bl, sc, INVALID_TIMER); } @@ -7522,7 +7849,7 @@ int pc_jobchange(struct map_session_data *sd,int job, int upper) if (sd->disguise != -1) pc->disguise(sd, -1); - status_set_viewdata(&sd->bl, job); + status->set_viewdata(&sd->bl, job); clif->changelook(&sd->bl,LOOK_BASE,sd->vd.class_); // move sprite update to prevent client crashes with incompatible equipment [Valaris] if(sd->vd.cloth_color) clif->changelook(&sd->bl,LOOK_CLOTHES_COLOR,sd->vd.cloth_color); @@ -7532,11 +7859,11 @@ int pc_jobchange(struct map_session_data *sd,int job, int upper) clif->skillinfoblock(sd); if (sd->ed) - elemental_delete(sd->ed, 0); + elemental->delete(sd->ed, 0); if (sd->state.vending) vending->close(sd); - iMap->foreachinmap(jobchange_killclone, sd->bl.m, BL_MOB, sd->bl.id); + map->foreachinmap(pc->jobchange_killclone, sd->bl.m, BL_MOB, sd->bl.id); //Remove peco/cart/falcon i = sd->sc.option; @@ -7563,27 +7890,27 @@ int pc_jobchange(struct map_session_data *sd,int job, int upper) pc->setoption(sd, i); if(homun_alive(sd->hd) && !pc->checkskill(sd, AM_CALLHOMUN)) - homun->vaporize(sd, 0); + homun->vaporize(sd, HOM_ST_REST); if(sd->status.manner < 0) clif->changestatus(sd,SP_MANNER,sd->status.manner); - status_calc_pc(sd,0); + status_calc_pc(sd,SCO_FORCE); pc->checkallowskill(sd); pc->equiplookall(sd); //if you were previously famous, not anymore. if (fame_flag) { - chrif_save(sd,0); - chrif_buildfamelist(); + chrif->save(sd,0); + chrif->buildfamelist(); } else if (sd->status.fame > 0) { //It may be that now they are famous? switch (sd->class_&MAPID_UPPERMASK) { case MAPID_BLACKSMITH: case MAPID_ALCHEMIST: case MAPID_TAEKWON: - chrif_save(sd,0); - chrif_buildfamelist(); + chrif->save(sd,0); + chrif->buildfamelist(); break; } } @@ -7617,7 +7944,7 @@ int pc_changelook(struct map_session_data *sd,int type,int val) switch(type){ case LOOK_BASE: - status_set_viewdata(&sd->bl, val); + status->set_viewdata(&sd->bl, val); clif->changelook(&sd->bl,LOOK_BASE,sd->vd.class_); clif->changelook(&sd->bl,LOOK_WEAPON,sd->status.weapon); if (sd->vd.cloth_color) @@ -7631,7 +7958,7 @@ int pc_changelook(struct map_session_data *sd,int type,int val) if (sd->status.hair != val) { sd->status.hair=val; if (sd->status.guild_id) //Update Guild Window. [Skotlex] - intif_guild_change_memberinfo(sd->status.guild_id,sd->status.account_id,sd->status.char_id, + intif->guild_change_memberinfo(sd->status.guild_id,sd->status.account_id,sd->status.char_id, GMI_HAIR,&sd->status.hair,sizeof(sd->status.hair)); } break; @@ -7653,7 +7980,7 @@ int pc_changelook(struct map_session_data *sd,int type,int val) if (sd->status.hair_color != val) { sd->status.hair_color=val; if (sd->status.guild_id) //Update Guild Window. [Skotlex] - intif_guild_change_memberinfo(sd->status.guild_id,sd->status.account_id,sd->status.char_id, + intif->guild_change_memberinfo(sd->status.guild_id,sd->status.account_id,sd->status.char_id, GMI_HAIR_COLOR,&sd->status.hair_color,sizeof(sd->status.hair_color)); } break; @@ -7691,11 +8018,11 @@ int pc_setoption(struct map_session_data *sd,int type) if( (type&OPTION_RIDING && !(p_type&OPTION_RIDING)) || (type&OPTION_DRAGON && !(p_type&OPTION_DRAGON) && pc->checkskill(sd,RK_DRAGONTRAINING) > 0) ) { // Mounting clif->sc_load(&sd->bl,sd->bl.id,AREA,SI_RIDING, 0, 0, 0); - status_calc_pc(sd,0); + status_calc_pc(sd,SCO_NONE); } else if( (!(type&OPTION_RIDING) && p_type&OPTION_RIDING) || (!(type&OPTION_DRAGON) && p_type&OPTION_DRAGON) ) { // Dismount clif->sc_end(&sd->bl,sd->bl.id,AREA,SI_RIDING); - status_calc_pc(sd,0); + status_calc_pc(sd,SCO_NONE); } #ifndef NEW_CARTS @@ -7703,11 +8030,11 @@ int pc_setoption(struct map_session_data *sd,int type) clif->cartlist(sd); clif->updatestatus(sd, SP_CARTINFO); if(pc->checkskill(sd, MC_PUSHCART) < 10) - status_calc_pc(sd,0); //Apply speed penalty. + status_calc_pc(sd,SCO_NONE); //Apply speed penalty. } else if( !( type&OPTION_CART ) && p_type&OPTION_CART ){ //Cart Off clif->clearcart(sd->fd); if(pc->checkskill(sd, MC_PUSHCART) < 10) - status_calc_pc(sd,0); //Remove speed penalty. + status_calc_pc(sd,SCO_NONE); //Remove speed penalty. } #endif @@ -7716,25 +8043,24 @@ int pc_setoption(struct map_session_data *sd,int type) else if (!(type&OPTION_FALCON) && p_type&OPTION_FALCON) //Falcon OFF clif->sc_end(&sd->bl,sd->bl.id,AREA,SI_FALCON); - if( (sd->class_&MAPID_THIRDMASK) == MAPID_RANGER ) { - if( type&OPTION_WUGRIDER && !(p_type&OPTION_WUGRIDER) ) { // Mounting - clif->sc_load(&sd->bl,sd->bl.id,AREA,SI_WUGRIDER, 0, 0, 0); - status_calc_pc(sd,0); - } else if( !(type&OPTION_WUGRIDER) && p_type&OPTION_WUGRIDER ) { // Dismount - clif->sc_end(&sd->bl,sd->bl.id,AREA,SI_WUGRIDER); - status_calc_pc(sd,0); - } + if( type&OPTION_WUGRIDER && !(p_type&OPTION_WUGRIDER) ) { // Mounting + clif->sc_load(&sd->bl,sd->bl.id,AREA,SI_WUGRIDER, 0, 0, 0); + status_calc_pc(sd,SCO_NONE); + } else if( !(type&OPTION_WUGRIDER) && p_type&OPTION_WUGRIDER ) { // Dismount + clif->sc_end(&sd->bl,sd->bl.id,AREA,SI_WUGRIDER); + status_calc_pc(sd,SCO_NONE); } - if( (sd->class_&MAPID_THIRDMASK) == MAPID_MECHANIC ) { + + if( (type&OPTION_MADOGEAR && !(p_type&OPTION_MADOGEAR)) + || (!(type&OPTION_MADOGEAR) && p_type&OPTION_MADOGEAR) ) { int i; - if( type&OPTION_MADOGEAR && !(p_type&OPTION_MADOGEAR) ) - status_calc_pc(sd, 0); - else if( !(type&OPTION_MADOGEAR) && p_type&OPTION_MADOGEAR ) - status_calc_pc(sd, 0); - for( i = 0; i < SC_MAX; i++ ){ - if ( !sd->sc.data[i] || !status_get_sc_type(i) ) + status_calc_pc(sd, SCO_NONE); + + // End all SCs that can be reset when mado is taken off + for( i = 0; i < SC_MAX; i++ ) { + if ( !sd->sc.data[i] || !status->get_sc_type(i) ) continue; - if ( status_get_sc_type(i)&SC_MADO_NO_RESET ) + if ( status->get_sc_type(i)&SC_MADO_NO_RESET ) continue; switch (i) { case SC_BERSERK: @@ -7755,7 +8081,7 @@ int pc_setoption(struct map_session_data *sd,int type) return 0; //Disguises break sprite changes if (new_look < 0) { //Restore normal look. - status_set_viewdata(&sd->bl, sd->status.class_); + status->set_viewdata(&sd->bl, sd->status.class_); new_look = sd->vd.class_; } @@ -7773,7 +8099,7 @@ int pc_setoption(struct map_session_data *sd,int type) *------------------------------------------*/ int pc_setcart(struct map_session_data *sd,int type) { #ifndef NEW_CARTS - int cart[6] = {0x0000,OPTION_CART1,OPTION_CART2,OPTION_CART3,OPTION_CART4,OPTION_CART5}; + int cart[6] = {OPTION_NOTHING,OPTION_CART1,OPTION_CART2,OPTION_CART3,OPTION_CART4,OPTION_CART5}; int option; #endif nullpo_ret(sd); @@ -7801,7 +8127,7 @@ int pc_setcart(struct map_session_data *sd,int type) { if( !sd->sc.data[SC_PUSH_CART] ) /* first time, so fill cart data */ clif->cartlist(sd); clif->updatestatus(sd, SP_CARTINFO); - sc_start(&sd->bl, SC_PUSH_CART, 100, type, 0); + sc_start(NULL,&sd->bl, SC_PUSH_CART, 100, type, 0); clif->sc_load(&sd->bl, sd->bl.id, AREA, SI_ON_PUSH_CART, type, 0, 0); if( sd->sc.data[SC_PUSH_CART] )/* forcefully update */ sd->sc.data[SC_PUSH_CART]->val1 = type; @@ -7809,7 +8135,7 @@ int pc_setcart(struct map_session_data *sd,int type) { } if(pc->checkskill(sd, MC_PUSHCART) < 10) - status_calc_pc(sd,0); //Recalc speed penalty. + status_calc_pc(sd,SCO_NONE); //Recalc speed penalty. #else // Update option option = sd->sc.option; @@ -7851,375 +8177,322 @@ int pc_setriding(TBL_PC* sd, int flag) return 0; } -/*========================================== - * Give player a mado - *------------------------------------------*/ -int pc_setmadogear(TBL_PC* sd, int flag) -{ - if( flag ){ - if( pc->checkskill(sd,NC_MADOLICENCE) > 0 ) +/** + * Gives player a mado + * @param flag 1 Set mado + **/ +void pc_setmadogear( struct map_session_data *sd, int flag ) { + if( flag ) { + if( (sd->class_&MAPID_THIRDMASK) == MAPID_MECHANIC ) pc->setoption(sd, sd->sc.option|OPTION_MADOGEAR); - } else if( pc_ismadogear(sd) ){ - pc->setoption(sd, sd->sc.option&~OPTION_MADOGEAR); - } + } else if( pc_ismadogear(sd) ) + pc->setoption(sd, sd->sc.option&~OPTION_MADOGEAR); - return 0; -} - -/*========================================== - * Check if player can drop an item - *------------------------------------------*/ -int pc_candrop(struct map_session_data *sd, struct item *item) -{ - if( item && item->expire_time ) - return 0; - if( !pc->can_give_items(sd) ) //check if this GM level can drop items - return 0; - return (itemdb_isdropable(item, pc->get_group_level(sd))); + return; } -/*========================================== - * Read ram register for player sd - * get val (int) from reg for player sd - *------------------------------------------*/ -int pc_readreg(struct map_session_data* sd, int reg) -{ - int i; +/** + * Determines whether a player can attack based on status changes + * Why not use status_check_skilluse? + * "src MAY be null to indicate we shouldn't check it, this is a ground-based skill attack." + * Even ground-based attacks should be blocked by these statuses + * Called from unit_attack and unit_attack_timer_sub + * @retval true Can attack + **/ +bool pc_can_attack( struct map_session_data *sd, int target_id ) { + nullpo_retr(false, sd); - nullpo_ret(sd); + if( sd->sc.data[SC_BASILICA] || + sd->sc.data[SC__SHADOWFORM] || + sd->sc.data[SC__MANHOLE] || + sd->sc.data[SC_CURSEDCIRCLE_ATKER] || + sd->sc.data[SC_CURSEDCIRCLE_TARGET] || + sd->sc.data[SC_COLD] || + sd->sc.data[SC_ALL_RIDING] || // The client doesn't let you, this is to make cheat-safe + sd->sc.data[SC_TRICKDEAD] || + (sd->sc.data[SC_SIREN] && sd->sc.data[SC_SIREN]->val2 == target_id) || + sd->sc.data[SC_BLADESTOP] || + sd->sc.data[SC_DEEP_SLEEP] || + sd->sc.data[SC_FALLENEMPIRE] ) + return false; - ARR_FIND( 0, sd->reg_num, i, sd->reg[i].index == reg ); - return ( i < sd->reg_num ) ? sd->reg[i].data : 0; + return true; } -/*========================================== - * Set ram register for player sd - * memo val(int) at reg for player sd - *------------------------------------------*/ -int pc_setreg(struct map_session_data* sd, int reg, int val) -{ - int i; - nullpo_ret(sd); - - ARR_FIND( 0, sd->reg_num, i, sd->reg[i].index == reg ); - if( i < sd->reg_num ) - {// overwrite existing entry - sd->reg[i].data = val; - return 1; - } +/** + * Determines whether a player can talk/whisper based on status changes + * Called from clif_parse_GlobalMessage and clif_parse_WisMessage + * @retval true Can talk + **/ +bool pc_can_talk( struct map_session_data *sd ) { + nullpo_retr(false, sd); - ARR_FIND( 0, sd->reg_num, i, sd->reg[i].data == 0 ); - if( i == sd->reg_num ) - {// nothing free, increase size - sd->reg_num++; - RECREATE(sd->reg, struct script_reg, sd->reg_num); - } - sd->reg[i].index = reg; - sd->reg[i].data = val; + if( sd->sc.data[SC_BERSERK] || + (sd->sc.data[SC_DEEP_SLEEP] && sd->sc.data[SC_DEEP_SLEEP]->val2) || + (sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOCHAT) ) + return false; - return 1; + return true; } /*========================================== - * Read ram register for player sd - * get val (str) from reg for player sd + * Check if player can drop an item *------------------------------------------*/ -char* pc_readregstr(struct map_session_data* sd, int reg) +int pc_candrop(struct map_session_data *sd, struct item *item) { - int i; + if( item && (item->expire_time || (item->bound && !pc_can_give_bound_items(sd))) ) + return 0; + if( !pc_can_give_items(sd) ) //check if this GM level can drop items + return 0; + return (itemdb_isdropable(item, pc_get_group_level(sd))); +} +/** + * For '@type' variables (temporary numeric char reg) + **/ +int pc_readreg(struct map_session_data* sd, int64 reg) { + return i64db_iget(sd->regs.vars, reg); +} +/** + * For '@type' variables (temporary numeric char reg) + **/ +void pc_setreg(struct map_session_data* sd, int64 reg, int val) { + unsigned int index = script_getvaridx(reg); + + if( val ) { + i64db_iput(sd->regs.vars, reg, val); + if( index ) + script->array_update(&sd->regs, reg, false); + } else { + i64db_remove(sd->regs.vars, reg); + if( index ) + script->array_update(&sd->regs, reg, true); + } +} - nullpo_ret(sd); +/** + * For '@type$' variables (temporary string char reg) + **/ +char* pc_readregstr(struct map_session_data* sd, int64 reg) { + struct script_reg_str *p = NULL; - ARR_FIND( 0, sd->regstr_num, i, sd->regstr[i].index == reg ); - return ( i < sd->regstr_num ) ? sd->regstr[i].data : NULL; + p = i64db_get(sd->regs.vars, reg); + + return p ? p->value : NULL; } -/*========================================== - * Set ram register for player sd - * memo val(str) at reg for player sd - *------------------------------------------*/ -int pc_setregstr(struct map_session_data* sd, int reg, const char* str) -{ - int i; - - nullpo_ret(sd); +/** + * For '@type$' variables (temporary string char reg) + **/ +void pc_setregstr(struct map_session_data* sd, int64 reg, const char* str) { + struct script_reg_str *p = NULL; + unsigned int index = script_getvaridx(reg); + DBData prev; - ARR_FIND( 0, sd->regstr_num, i, sd->regstr[i].index == reg ); - if( i < sd->regstr_num ) - {// found entry, update - if( str == NULL || *str == '\0' ) - {// empty string - if( sd->regstr[i].data != NULL ) - aFree(sd->regstr[i].data); - sd->regstr[i].data = NULL; - } - else if( sd->regstr[i].data ) - {// recreate - size_t len = strlen(str)+1; - RECREATE(sd->regstr[i].data, char, len); - memcpy(sd->regstr[i].data, str, len*sizeof(char)); + if( str[0] ) { + p = ers_alloc(pc->str_reg_ers, struct script_reg_str); + + p->value = aStrdup(str); + p->flag.type = 1; + + if( sd->regs.vars->put(sd->regs.vars, DB->i642key(reg), DB->ptr2data(p), &prev) ) { + p = DB->data2ptr(&prev); + if( p->value ) + aFree(p->value); + ers_free(pc->str_reg_ers, p); + } else { + if( index ) + script->array_update(&sd->regs, reg, false); } - else - {// create - sd->regstr[i].data = aStrdup(str); + } else { + if( sd->regs.vars->remove(sd->regs.vars, DB->i642key(reg), &prev) ) { + p = DB->data2ptr(&prev); + if( p->value ) + aFree(p->value); + ers_free(pc->str_reg_ers, p); + if( index ) + script->array_update(&sd->regs, reg, true); } - return 1; } - - if( str == NULL || *str == '\0' ) - return 1;// nothing to add, empty string - - ARR_FIND( 0, sd->regstr_num, i, sd->regstr[i].data == NULL ); - if( i == sd->regstr_num ) - {// nothing free, increase size - sd->regstr_num++; - RECREATE(sd->regstr, struct script_regstr, sd->regstr_num); - } - sd->regstr[i].index = reg; - sd->regstr[i].data = aStrdup(str); - - return 1; } - -int pc_readregistry(struct map_session_data *sd,const char *reg,int type) -{ - struct global_reg *sd_reg; - int i,max; - - nullpo_ret(sd); - switch (type) { - case 3: //Char reg - sd_reg = sd->save_reg.global; - max = sd->save_reg.global_num; - break; - case 2: //Account reg - sd_reg = sd->save_reg.account; - max = sd->save_reg.account_num; - break; - case 1: //Account2 reg - sd_reg = sd->save_reg.account2; - max = sd->save_reg.account2_num; - break; - default: - return 0; - } - if (max == -1) { - ShowError("pc_readregistry: Trying to read reg value %s (type %d) before it's been loaded!\n", reg, type); +/** + * Serves the following variable types: + * - 'type' (permanent nuneric char reg) + * - '#type' (permanent numeric account reg) + * - '##type' (permanent numeric account reg2) + **/ +int pc_readregistry(struct map_session_data *sd, int64 reg) { + struct script_reg_num *p = NULL; + + 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. - intif_request_registry(sd,type==3?4:type); + //intif->request_registry(sd,type==3?4:type); + set_eof(sd->fd); return 0; } + + p = i64db_get(sd->regs.vars, reg); - ARR_FIND( 0, max, i, strcmp(sd_reg[i].str,reg) == 0 ); - return ( i < max ) ? atoi(sd_reg[i].value) : 0; + return p ? p->value : 0; } - -char* pc_readregistry_str(struct map_session_data *sd,const char *reg,int type) -{ - struct global_reg *sd_reg; - int i,max; - - nullpo_ret(sd); - switch (type) { - case 3: //Char reg - sd_reg = sd->save_reg.global; - max = sd->save_reg.global_num; - break; - case 2: //Account reg - sd_reg = sd->save_reg.account; - max = sd->save_reg.account_num; - break; - case 1: //Account2 reg - sd_reg = sd->save_reg.account2; - max = sd->save_reg.account2_num; - break; - default: - return NULL; - } - if (max == -1) { - ShowError("pc_readregistry: Trying to read reg value %s (type %d) before it's been loaded!\n", reg, type); +/** + * Serves the following variable types: + * - 'type$' (permanent str char reg) + * - '#type$' (permanent str account reg) + * - '##type$' (permanent str account reg2) + **/ +char* pc_readregistry_str(struct map_session_data *sd, int64 reg) { + struct script_reg_str *p = NULL; + + 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. - intif_request_registry(sd,type==3?4:type); + //intif->request_registry(sd,type==3?4:type); + set_eof(sd->fd); return NULL; } - ARR_FIND( 0, max, i, strcmp(sd_reg[i].str,reg) == 0 ); - return ( i < max ) ? sd_reg[i].value : NULL; + p = i64db_get(sd->regs.vars, reg); + + return p ? p->value : NULL; } - -int pc_setregistry(struct map_session_data *sd,const char *reg,int val,int type) -{ - struct global_reg *sd_reg; - int i,*max, regmax; - - nullpo_ret(sd); - - switch( type ) - { - case 3: //Char reg - if( !strcmp(reg,"PC_DIE_COUNTER") && sd->die_counter != val ) - { - i = (!sd->die_counter && (sd->class_&MAPID_UPPERMASK) == MAPID_SUPER_NOVICE); - sd->die_counter = val; - if( i ) - status_calc_pc(sd,0); // Lost the bonus. - } - else if( !strcmp(reg,"COOK_MASTERY") && sd->cook_mastery != val ) - { - val = cap_value(val, 0, 1999); - sd->cook_mastery = val; - } - sd_reg = sd->save_reg.global; - max = &sd->save_reg.global_num; - regmax = GLOBAL_REG_NUM; - break; - case 2: //Account reg - if( !strcmp(reg,"#CASHPOINTS") && sd->cashPoints != val ) - { - val = cap_value(val, 0, MAX_ZENY); - sd->cashPoints = val; - } - else if( !strcmp(reg,"#KAFRAPOINTS") && sd->kafraPoints != val ) - { - val = cap_value(val, 0, MAX_ZENY); - sd->kafraPoints = val; - } - sd_reg = sd->save_reg.account; - max = &sd->save_reg.account_num; - regmax = ACCOUNT_REG_NUM; - break; - case 1: //Account2 reg - sd_reg = sd->save_reg.account2; - max = &sd->save_reg.account2_num; - regmax = ACCOUNT_REG2_NUM; - break; - default: - return 0; +/** + * Serves the following variable types: + * - 'type' (permanent nuneric char reg) + * - '#type' (permanent numeric account reg) + * - '##type' (permanent numeric account reg2) + **/ +int pc_setregistry(struct map_session_data *sd, int64 reg, int val) { + struct script_reg_num *p = NULL; + int i; + const char *regname = script->get_str( script_getvarid(reg) ); + unsigned int index = script_getvaridx(reg); + + /* 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 + if( !strcmp(regname,"PC_DIE_COUNTER") && sd->die_counter != val ) { + i = (!sd->die_counter && (sd->class_&MAPID_UPPERMASK) == MAPID_SUPER_NOVICE); + sd->die_counter = val; + if( i ) + status_calc_pc(sd,SCO_NONE); // Lost the bonus. + } else if( !strcmp(regname,"COOK_MASTERY") && sd->cook_mastery != val ) { + val = cap_value(val, 0, 1999); + sd->cook_mastery = val; + } + break; + case '#': + if( !strcmp(regname,"#CASHPOINTS") && sd->cashPoints != val ) { + val = cap_value(val, 0, MAX_ZENY); + sd->cashPoints = val; + } else if( !strcmp(regname,"#KAFRAPOINTS") && sd->kafraPoints != val ) { + val = cap_value(val, 0, MAX_ZENY); + sd->kafraPoints = val; + } + break; } - if (*max == -1) { - ShowError("pc_setregistry : refusing to set %s (type %d) until vars are received.\n", reg, type); - return 1; + + if ( !pc->reg_load && !sd->vars_ok ) { + ShowError("pc_setregistry : refusing to set %s until vars are received.\n", regname); + return 0; } - - // delete reg - if (val == 0) { - ARR_FIND( 0, *max, i, strcmp(sd_reg[i].str, reg) == 0 ); - if( i < *max ) - { - if (i != *max - 1) - memcpy(&sd_reg[i], &sd_reg[*max - 1], sizeof(struct global_reg)); - memset(&sd_reg[*max - 1], 0, sizeof(struct global_reg)); - (*max)--; - sd->state.reg_dirty |= 1<<(type-1); //Mark this registry as "need to be saved" + + if( (p = i64db_get(sd->regs.vars, reg) ) ) { + if( val ) { + if( !p->value && index ) /* its a entry that was deleted, so we reset array */ + script->array_update(&sd->regs, reg, false); + p->value = val; + } else { + p->value = 0; + if( index ) + script->array_update(&sd->regs, reg, true); + } + if( !pc->reg_load ) + p->flag.update = 1;/* either way, it will require either delete or replace */ + } else if( val ) { + DBData prev; + + if( index ) + script->array_update(&sd->regs, reg, false); + + p = ers_alloc(pc->num_reg_ers, struct script_reg_num); + + p->value = val; + if( !pc->reg_load ) + p->flag.update = 1; + + if( sd->regs.vars->put(sd->regs.vars, DB->i642key(reg), DB->ptr2data(p), &prev) ) { + p = DB->data2ptr(&prev); + ers_free(pc->num_reg_ers, p); } - return 1; } - // change value if found - ARR_FIND( 0, *max, i, strcmp(sd_reg[i].str, reg) == 0 ); - if( i < *max ) - { - safesnprintf(sd_reg[i].value, sizeof(sd_reg[i].value), "%d", val); - sd->state.reg_dirty |= 1<<(type-1); - return 1; - } - - // add value if not found - if (i < regmax) { - memset(&sd_reg[i], 0, sizeof(struct global_reg)); - safestrncpy(sd_reg[i].str, reg, sizeof(sd_reg[i].str)); - safesnprintf(sd_reg[i].value, sizeof(sd_reg[i].value), "%d", val); - (*max)++; - sd->state.reg_dirty |= 1<<(type-1); - return 1; - } - - ShowError("pc_setregistry : couldn't set %s, limit of registries reached (%d)\n", reg, regmax); + + if( !pc->reg_load && p ) + sd->vars_dirty = true; - return 0; + return 1; } +/** + * Serves the following variable types: + * - 'type$' (permanent str char reg) + * - '#type$' (permanent str account reg) + * - '##type$' (permanent str account reg2) + **/ +int pc_setregistry_str(struct map_session_data *sd, int64 reg, const char *val) { + struct script_reg_str *p = NULL; + const char *regname = script->get_str( script_getvarid(reg) ); + unsigned int index = script_getvaridx(reg); -int pc_setregistry_str(struct map_session_data *sd,const char *reg,const char *val,int type) -{ - struct global_reg *sd_reg; - int i,*max, regmax; - - nullpo_ret(sd); - if (reg[strlen(reg)-1] != '$') { - ShowError("pc_setregistry_str : reg %s must be string (end in '$') to use this!\n", reg); + if ( !pc->reg_load && !sd->vars_ok ) { + ShowError("pc_setregistry_str : refusing to set %s until vars are received.\n", regname); return 0; } - switch (type) { - case 3: //Char reg - sd_reg = sd->save_reg.global; - max = &sd->save_reg.global_num; - regmax = GLOBAL_REG_NUM; - break; - case 2: //Account reg - sd_reg = sd->save_reg.account; - max = &sd->save_reg.account_num; - regmax = ACCOUNT_REG_NUM; - break; - case 1: //Account2 reg - sd_reg = sd->save_reg.account2; - max = &sd->save_reg.account2_num; - regmax = ACCOUNT_REG2_NUM; - break; - default: - return 0; - } - if (*max == -1) { - ShowError("pc_setregistry_str : refusing to set %s (type %d) until vars are received.\n", reg, type); - return 0; - } - - // delete reg - if (!val || strcmp(val,"")==0) - { - ARR_FIND( 0, *max, i, strcmp(sd_reg[i].str, reg) == 0 ); - if( i < *max ) - { - if (i != *max - 1) - memcpy(&sd_reg[i], &sd_reg[*max - 1], sizeof(struct global_reg)); - memset(&sd_reg[*max - 1], 0, sizeof(struct global_reg)); - (*max)--; - sd->state.reg_dirty |= 1<<(type-1); //Mark this registry as "need to be saved" - if (type!=3) intif_saveregistry(sd,type); + if( (p = i64db_get(sd->regs.vars, reg) ) ) { + if( val[0] ) { + if( p->value ) + aFree(p->value); + else if ( index ) /* a entry that was deleted, so we reset */ + script->array_update(&sd->regs, reg, false); + p->value = aStrdup(val); + } else { + p->value = NULL; + if( index ) + script->array_update(&sd->regs, reg, true); } - return 1; - } + if( !pc->reg_load ) + p->flag.update = 1;/* either way, it will require either delete or replace */ + } else if( val[0] ) { + DBData prev; - // change value if found - ARR_FIND( 0, *max, i, strcmp(sd_reg[i].str, reg) == 0 ); - if( i < *max ) - { - safestrncpy(sd_reg[i].value, val, sizeof(sd_reg[i].value)); - sd->state.reg_dirty |= 1<<(type-1); //Mark this registry as "need to be saved" - if (type!=3) intif_saveregistry(sd,type); - return 1; - } + if( index ) + script->array_update(&sd->regs, reg, false); - // add value if not found - if (i < regmax) { - memset(&sd_reg[i], 0, sizeof(struct global_reg)); - safestrncpy(sd_reg[i].str, reg, sizeof(sd_reg[i].str)); - safestrncpy(sd_reg[i].value, val, sizeof(sd_reg[i].value)); - (*max)++; - sd->state.reg_dirty |= 1<<(type-1); //Mark this registry as "need to be saved" - if (type!=3) intif_saveregistry(sd,type); - return 1; + p = ers_alloc(pc->str_reg_ers, struct script_reg_str); + + p->value = aStrdup(val); + if( !pc->reg_load ) + p->flag.update = 1; + p->flag.type = 1; + + if( sd->regs.vars->put(sd->regs.vars, DB->i642key(reg), DB->ptr2data(p), &prev) ) { + p = DB->data2ptr(&prev); + if( p->value ) + aFree(p->value); + ers_free(pc->str_reg_ers, p); + } } - - ShowError("pc_setregistry : couldn't set %s, limit of registries reached (%d)\n", reg, regmax); - - return 0; + + if( !pc->reg_load && p ) + sd->vars_dirty = true; + + return 1; } /*========================================== * Exec eventtimer for player sd (retrieved from map_session (id)) *------------------------------------------*/ -static int pc_eventtimer(int tid, unsigned int tick, int id, intptr_t data) -{ - struct map_session_data *sd=iMap->id2sd(id); +int pc_eventtimer(int tid, int64 tick, int id, intptr_t data) { + struct map_session_data *sd=map->id2sd(id); char *p = (char *)data; int i; if(sd==NULL) @@ -8230,7 +8503,7 @@ static int pc_eventtimer(int tid, unsigned int tick, int id, intptr_t data) { sd->eventtimer[i] = INVALID_TIMER; sd->eventcount--; - npc_event(sd,p,0); + npc->event(sd,p,0); } else ShowError("pc_eventtimer: no such event timer\n"); @@ -8251,7 +8524,7 @@ int pc_addeventtimer(struct map_session_data *sd,int tick,const char *name) if( i == MAX_EVENTTIMER ) return 0; - sd->eventtimer[i] = iTimer->add_timer(iTimer->gettick()+tick, pc_eventtimer, sd->bl.id, (intptr_t)aStrdup(name)); + sd->eventtimer[i] = timer->add(timer->gettick()+tick, pc->eventtimer, sd->bl.id, (intptr_t)aStrdup(name)); sd->eventcount++; return 1; @@ -8273,13 +8546,13 @@ int pc_deleventtimer(struct map_session_data *sd,const char *name) // find the named event timer ARR_FIND( 0, MAX_EVENTTIMER, i, sd->eventtimer[i] != INVALID_TIMER && - (p = (char *)(iTimer->get_timer(sd->eventtimer[i])->data)) != NULL && + (p = (char *)(timer->get(sd->eventtimer[i])->data)) != NULL && strcmp(p, name) == 0 ); if( i == MAX_EVENTTIMER ) return 0; // not found - iTimer->delete_timer(sd->eventtimer[i],pc_eventtimer); + timer->delete(sd->eventtimer[i],pc->eventtimer); sd->eventtimer[i] = INVALID_TIMER; sd->eventcount--; aFree(p); @@ -8298,8 +8571,8 @@ int pc_addeventtimercount(struct map_session_data *sd,const char *name,int tick) for(i=0;i<MAX_EVENTTIMER;i++) if( sd->eventtimer[i] != INVALID_TIMER && strcmp( - (char *)(iTimer->get_timer(sd->eventtimer[i])->data), name)==0 ){ - iTimer->addtick_timer(sd->eventtimer[i],tick); + (char *)(timer->get(sd->eventtimer[i])->data), name)==0 ){ + timer->addtick(sd->eventtimer[i],tick); break; } @@ -8320,8 +8593,8 @@ int pc_cleareventtimer(struct map_session_data *sd) for(i=0;i<MAX_EVENTTIMER;i++) if( sd->eventtimer[i] != INVALID_TIMER ){ - char *p = (char *)(iTimer->get_timer(sd->eventtimer[i])->data); - iTimer->delete_timer(sd->eventtimer[i],pc_eventtimer); + char *p = (char *)(timer->get(sd->eventtimer[i])->data); + timer->delete(sd->eventtimer[i],pc->eventtimer); sd->eventtimer[i] = INVALID_TIMER; sd->eventcount--; if (p) aFree(p); @@ -8331,17 +8604,19 @@ int pc_cleareventtimer(struct map_session_data *sd) /* called when a item with combo is worn */ int pc_checkcombo(struct map_session_data *sd, struct item_data *data ) { int i, j, k, z; - int index, idx, success = 0; + int index, success = 0; + struct pc_combos *combo; for( i = 0; i < data->combos_count; i++ ) { /* ensure this isn't a duplicate combo */ - if( sd->combos.bonus != NULL ) { + if( sd->combos != NULL ) { int x; - ARR_FIND( 0, sd->combos.count, x, sd->combos.id[x] == data->combos[i]->id ); + + ARR_FIND( 0, sd->combo_count, x, sd->combos[x].id == data->combos[i]->id ); /* found a match, skip this combo */ - if( x < sd->combos.count ) + if( x < sd->combo_count ) continue; } @@ -8358,7 +8633,7 @@ int pc_checkcombo(struct map_session_data *sd, struct item_data *data ) { if(!sd->inventory_data[index]) continue; - + if ( itemdb_type(id) != IT_CARD ) { if ( sd->inventory_data[index]->nameid != id ) continue; @@ -8392,24 +8667,16 @@ int pc_checkcombo(struct map_session_data *sd, struct item_data *data ) { /* we got here, means all items in the combo are matching */ - idx = sd->combos.count; - - if( sd->combos.bonus == NULL ) { - CREATE(sd->combos.bonus, struct script_code *, 1); - CREATE(sd->combos.id, unsigned short, 1); - sd->combos.count = 1; - } else { - RECREATE(sd->combos.bonus, struct script_code *, ++sd->combos.count); - RECREATE(sd->combos.id, unsigned short, sd->combos.count); - } - - /* we simply copy the pointer */ - sd->combos.bonus[idx] = data->combos[i]->script; - /* save this combo's id */ - sd->combos.id[idx] = data->combos[i]->id; - + RECREATE(sd->combos, struct pc_combos, ++sd->combo_count); + + combo = &sd->combos[sd->combo_count - 1]; + + combo->bonus = data->combos[i]->script; + combo->id = data->combos[i]->id; + success++; } + return success; } @@ -8417,45 +8684,45 @@ 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; - if( sd->combos.bonus == NULL ) + if( !sd->combos ) return 0;/* nothing to do here, player has no combos */ + for( i = 0; i < data->combos_count; i++ ) { /* check if this combo exists in this user */ int x = 0, cursor = 0, j; - ARR_FIND( 0, sd->combos.count, x, sd->combos.id[x] == data->combos[i]->id ); + + ARR_FIND( 0, sd->combo_count, x, sd->combos[x].id == data->combos[i]->id ); /* no match, skip this combo */ - if( !(x < sd->combos.count) ) + if( x == sd->combo_count ) continue; - sd->combos.bonus[x] = NULL; - sd->combos.id[x] = 0; + sd->combos[x].bonus = NULL; + sd->combos[x].id = 0; + retval++; - for( j = 0, cursor = 0; j < sd->combos.count; j++ ) { - if( sd->combos.bonus[j] == NULL ) + + for( j = 0, cursor = 0; j < sd->combo_count; j++ ) { + if( sd->combos[j].bonus == NULL ) continue; if( cursor != j ) { - sd->combos.bonus[cursor] = sd->combos.bonus[j]; - sd->combos.id[cursor] = sd->combos.id[j]; + sd->combos[cursor].bonus = sd->combos[j].bonus; + sd->combos[cursor].id = sd->combos[j].id; } cursor++; } - /* check if combo requirements still fit */ - if( pc_checkcombo( sd, data ) ) - continue; - /* it's empty, we can clear all the memory */ - if( (sd->combos.count = cursor) == 0 ) { - aFree(sd->combos.bonus); - aFree(sd->combos.id); - sd->combos.bonus = NULL; - sd->combos.id = NULL; - return retval; /* we also can return at this point for we have no more combos to check */ + if( (sd->combo_count = cursor) == 0 ) { + aFree(sd->combos); + sd->combos = NULL; + break; } - } + + /* check if combo requirements still fit -- don't touch retval! */ + pc->checkcombo( sd, data ); return retval; } @@ -8467,16 +8734,16 @@ int pc_load_combo(struct map_session_data *sd) { if( sd->equip_index[i] < 0 || !(id = sd->inventory_data[idx] ) ) continue; if( id->combos_count ) - ret += pc_checkcombo(sd,id); + ret += pc->checkcombo(sd,id); if(!itemdb_isspecial(sd->status.inventory[idx].card[0])) { struct item_data *data; int j; for( j = 0; j < id->slot; j++ ) { if (!sd->status.inventory[idx].card[j]) continue; - if ( ( data = itemdb_exists(sd->status.inventory[idx].card[j]) ) != NULL ) { + if ( ( data = itemdb->exists(sd->status.inventory[idx].card[j]) ) != NULL ) { if( data->combos_count ) - ret += pc_checkcombo(sd,data); + ret += pc->checkcombo(sd,data); } } } @@ -8494,13 +8761,13 @@ int pc_equipitem(struct map_session_data *sd,int n,int req_pos) nullpo_ret(sd); if( n < 0 || n >= MAX_INVENTORY ) { - clif->equipitemack(sd,0,0,0); + clif->equipitemack(sd,0,0,EIA_FAIL); return 0; } - if( DIFF_TICK(sd->canequip_tick,iTimer->gettick()) > 0 ) + if( DIFF_TICK(sd->canequip_tick,timer->gettick()) > 0 ) { - clif->equipitemack(sd,n,0,0); + clif->equipitemack(sd,n,0,EIA_FAIL); return 0; } @@ -8511,27 +8778,38 @@ int pc_equipitem(struct map_session_data *sd,int n,int req_pos) ShowInfo("equip %d(%d) %x:%x\n",sd->status.inventory[n].nameid,n,id?id->equip:0,req_pos); if(!pc->isequip(sd,n) || !(pos&req_pos) || sd->status.inventory[n].equip != 0 || sd->status.inventory[n].attribute==1 ) { // [Valaris] // FIXME: pc->isequip: equip level failure uses 2 instead of 0 - clif->equipitemack(sd,n,0,0); // fail + clif->equipitemack(sd,n,0,EIA_FAIL); // fail return 0; } - if (sd->sc.data[SC_BERSERK] || sd->sc.data[SC_SATURDAY_NIGHT_FEVER] || sd->sc.data[SC__BLOODYLUST]) + if (sd->sc.data[SC_BERSERK] || sd->sc.data[SC_NO_SWITCH_EQUIP]) { - clif->equipitemack(sd,n,0,0); // fail + clif->equipitemack(sd,n,0,EIA_FAIL); // fail return 0; } + /* won't fail from this point onwards */ + if( id->flag.bindonequip && !sd->status.inventory[n].bound ) { + sd->status.inventory[n].bound = (unsigned char)IBT_CHARACTER; + clif->notify_bounditem(sd,n); + } + if(pos == EQP_ACC) { //Accesories should only go in one of the two, pos = req_pos&EQP_ACC; if (pos == EQP_ACC) //User specified both slots.. pos = sd->equip_index[EQI_ACC_R] >= 0 ? EQP_ACC_L : EQP_ACC_R; - } - - if(pos == EQP_ARMS && id->equip == EQP_HAND_R) - { //Dual wield capable weapon. + } else if(pos == EQP_ARMS && id->equip == EQP_HAND_R) { //Dual wield capable weapon. pos = (req_pos&EQP_ARMS); if (pos == EQP_ARMS) //User specified both slots, pick one for them. pos = sd->equip_index[EQI_HAND_R] >= 0 ? EQP_HAND_L : EQP_HAND_R; + } else if(pos == EQP_SHADOW_ACC) { //Accesories should only go in one of the two, + pos = req_pos&EQP_SHADOW_ACC; + if (pos == EQP_SHADOW_ACC) //User specified both slots.. + pos = sd->equip_index[EQI_SHADOW_ACC_R] >= 0 ? EQP_SHADOW_ACC_L : EQP_SHADOW_ACC_R; + } else if( pos == EQP_SHADOW_ARMS && id->equip == EQP_SHADOW_WEAPON) { //Dual wield capable weapon. + pos = (req_pos&EQP_SHADOW_ARMS); + if (pos == EQP_SHADOW_ARMS) //User specified both slots, pick one for them. + pos = sd->equip_index[EQI_SHADOW_WEAPON] >= 0 ? EQP_SHADOW_SHIELD : EQP_SHADOW_WEAPON; } if (pos&EQP_HAND_R && battle_config.use_weapon_skill_range&BL_PC) @@ -8544,7 +8822,7 @@ int pc_equipitem(struct map_session_data *sd,int n,int req_pos) } for(i=0;i<EQI_MAX;i++) { - if(pos & equip_pos[i]) { + if(pos & pc->equip_pos[i]) { if(sd->equip_index[i] >= 0) //Slot taken, remove item from there. pc->unequipitem(sd,sd->equip_index[i],2); @@ -8557,33 +8835,30 @@ int pc_equipitem(struct map_session_data *sd,int n,int req_pos) clif->arrow_fail(sd,3); } else - clif->equipitemack(sd,n,pos,1); + clif->equipitemack(sd,n,pos,EIA_SUCCESS); sd->status.inventory[n].equip=pos; - if(pos & EQP_HAND_R) { + if(pos & (EQP_HAND_R|EQP_SHADOW_WEAPON)) { if(id) sd->weapontype1 = id->look; else sd->weapontype1 = 0; - pc_calcweapontype(sd); + pc->calcweapontype(sd); clif->changelook(&sd->bl,LOOK_WEAPON,sd->status.weapon); } - if(pos & EQP_HAND_L) { + if(pos & (EQP_HAND_L|EQP_SHADOW_SHIELD)) { if(id) { if(id->type == IT_WEAPON) { sd->status.shield = 0; sd->weapontype2 = id->look; - } - else - if(id->type == IT_ARMOR) { + } else if(id->type == IT_ARMOR) { sd->status.shield = id->look; sd->weapontype2 = 0; } - } - else + } else sd->status.shield = sd->weapontype2 = 0; - pc_calcweapontype(sd); + pc->calcweapontype(sd); clif->changelook(&sd->bl,LOOK_SHIELD,sd->status.shield); } //Added check to prevent sending the same look on multiple slots -> @@ -8650,7 +8925,7 @@ int pc_equipitem(struct map_session_data *sd,int n,int req_pos) /* check for combos (MUST be before status_calc_pc) */ if ( id ) { if( id->combos_count ) - pc_checkcombo(sd,id); + pc->checkcombo(sd,id); if(itemdb_isspecial(sd->status.inventory[n].card[0])) ; //No cards else { @@ -8658,22 +8933,22 @@ int pc_equipitem(struct map_session_data *sd,int n,int req_pos) struct item_data *data; if (!sd->status.inventory[n].card[i]) continue; - if ( ( data = itemdb_exists(sd->status.inventory[n].card[i]) ) != NULL ) { + if ( ( data = itemdb->exists(sd->status.inventory[n].card[i]) ) != NULL ) { if( data->combos_count ) - pc_checkcombo(sd,data); + pc->checkcombo(sd,data); } } } } - status_calc_pc(sd,0); + status_calc_pc(sd,SCO_NONE); if (flag) //Update skill data clif->skillinfoblock(sd); //OnEquip script [Skotlex] if (id) { if (id->equip_script) - run_script(id->equip_script,0,sd->bl.id,fake_nd->bl.id); + script->run(id->equip_script,0,sd->bl.id,npc->fake_nd->bl.id); if(itemdb_isspecial(sd->status.inventory[n].card[0])) ; //No cards else { @@ -8681,9 +8956,9 @@ int pc_equipitem(struct map_session_data *sd,int n,int req_pos) struct item_data *data; if (!sd->status.inventory[n].card[i]) continue; - if ( ( data = itemdb_exists(sd->status.inventory[n].card[i]) ) != NULL ) { + if ( ( data = itemdb->exists(sd->status.inventory[n].card[i]) ) != NULL ) { if( data->equip_script ) - run_script(data->equip_script,0,sd->bl.id,fake_nd->bl.id); + script->run(data->equip_script,0,sd->bl.id,npc->fake_nd->bl.id); } } } @@ -8706,20 +8981,20 @@ int pc_unequipitem(struct map_session_data *sd,int n,int flag) { nullpo_ret(sd); if( n < 0 || n >= MAX_INVENTORY ) { - clif->unequipitemack(sd,0,0,0); + clif->unequipitemack(sd,0,0,UIA_FAIL); return 0; } // if player is berserk then cannot unequip - if (!(flag & 2) && sd->sc.count && (sd->sc.data[SC_BERSERK] || sd->sc.data[SC_SATURDAY_NIGHT_FEVER] || sd->sc.data[SC__BLOODYLUST])) + if (!(flag & 2) && sd->sc.count && (sd->sc.data[SC_BERSERK] || sd->sc.data[SC_NO_SWITCH_EQUIP]) ) { - clif->unequipitemack(sd,n,0,0); + clif->unequipitemack(sd,n,0,UIA_FAIL); return 0; } if( !(flag&2) && sd->sc.count && sd->sc.data[SC_KYOUGAKU] ) { - clif->unequipitemack(sd,n,0,0); + clif->unequipitemack(sd,n,0,UIA_FAIL); return 0; } @@ -8727,25 +9002,25 @@ int pc_unequipitem(struct map_session_data *sd,int n,int flag) { ShowInfo("unequip %d %x:%x\n",n,pc->equippoint(sd,n),sd->status.inventory[n].equip); if(!sd->status.inventory[n].equip){ //Nothing to unequip - clif->unequipitemack(sd,n,0,0); + clif->unequipitemack(sd,n,0,UIA_FAIL); return 0; } for(i=0;i<EQI_MAX;i++) { - if(sd->status.inventory[n].equip & equip_pos[i]) + if(sd->status.inventory[n].equip & pc->equip_pos[i]) sd->equip_index[i] = -1; } if(sd->status.inventory[n].equip & EQP_HAND_R) { sd->weapontype1 = 0; sd->status.weapon = sd->weapontype2; - pc_calcweapontype(sd); + pc->calcweapontype(sd); clif->changelook(&sd->bl,LOOK_WEAPON,sd->status.weapon); if( !battle_config.dancing_weaponswitch_fix ) status_change_end(&sd->bl, SC_DANCING, INVALID_TIMER); // Unequipping => stop dancing. } if(sd->status.inventory[n].equip & EQP_HAND_L) { sd->status.shield = sd->weapontype2 = 0; - pc_calcweapontype(sd); + pc->calcweapontype(sd); clif->changelook(&sd->bl,LOOK_SHIELD,sd->status.shield); } if(sd->status.inventory[n].equip & EQP_HEAD_LOW && pc->checkequip(sd,EQP_COSTUME_HEAD_LOW) == -1 ) { @@ -8789,7 +9064,7 @@ int pc_unequipitem(struct map_session_data *sd,int n,int flag) { clif->changelook(&sd->bl,LOOK_ROBE,sd->status.robe); } - clif->unequipitemack(sd,n,sd->status.inventory[n].equip,1); + clif->unequipitemack(sd,n,sd->status.inventory[n].equip,UIA_SUCCESS); if((sd->status.inventory[n].equip & EQP_ARMS) && sd->weapontype1 == 0 && sd->weapontype2 == 0 && (!sd->sc.data[SC_TK_SEVENWIND] || sd->sc.data[SC_ASPERSIO])) //Check for seven wind (but not level seven!) @@ -8810,7 +9085,7 @@ int pc_unequipitem(struct map_session_data *sd,int n,int flag) { /* check for combos (MUST be before status_calc_pc) */ if ( sd->inventory_data[n] ) { if( sd->inventory_data[n]->combos_count ) { - if( pc_removecombo(sd,sd->inventory_data[n]) ) + if( pc->removecombo(sd,sd->inventory_data[n]) ) status_cacl = true; } if(itemdb_isspecial(sd->status.inventory[n].card[0])) ; //No cards @@ -8819,9 +9094,9 @@ int pc_unequipitem(struct map_session_data *sd,int n,int flag) { struct item_data *data; if (!sd->status.inventory[n].card[i]) continue; - if ( ( data = itemdb_exists(sd->status.inventory[n].card[i]) ) != NULL ) { + if ( ( data = itemdb->exists(sd->status.inventory[n].card[i]) ) != NULL ) { if( data->combos_count ) { - if( pc_removecombo(sd,data) ) + if( pc->removecombo(sd,data) ) status_cacl = true; } } @@ -8831,7 +9106,7 @@ int pc_unequipitem(struct map_session_data *sd,int n,int flag) { if(flag&1 || status_cacl) { pc->checkallowskill(sd); - status_calc_pc(sd,0); + status_calc_pc(sd,SCO_NONE); } if(sd->sc.data[SC_CRUCIS] && !battle->check_undead(sd->battle_status.race,sd->battle_status.def_ele)) @@ -8840,7 +9115,7 @@ int pc_unequipitem(struct map_session_data *sd,int n,int flag) { //OnUnEquip script [Skotlex] if (sd->inventory_data[n]) { if (sd->inventory_data[n]->unequip_script) - run_script(sd->inventory_data[n]->unequip_script,0,sd->bl.id,fake_nd->bl.id); + script->run(sd->inventory_data[n]->unequip_script,0,sd->bl.id,npc->fake_nd->bl.id); if(itemdb_isspecial(sd->status.inventory[n].card[0])) ; //No cards else { @@ -8849,9 +9124,9 @@ int pc_unequipitem(struct map_session_data *sd,int n,int flag) { if (!sd->status.inventory[n].card[i]) continue; - if ( ( data = itemdb_exists(sd->status.inventory[n].card[i]) ) != NULL ) { + if ( ( data = itemdb->exists(sd->status.inventory[n].card[i]) ) != NULL ) { if( data->unequip_script ) - run_script(data->unequip_script,0,sd->bl.id,fake_nd->bl.id); + script->run(data->unequip_script,0,sd->bl.id,npc->fake_nd->bl.id); } } @@ -8868,31 +9143,85 @@ int pc_unequipitem(struct map_session_data *sd,int n,int flag) { *------------------------------------------*/ int pc_checkitem(struct map_session_data *sd) { - int i,id,calc_flag = 0; + int i, id, calc_flag = 0; nullpo_ret(sd); if( sd->state.vending ) //Avoid reorganizing items when we are vending, as that leads to exploits (pointed out by End of Exam) return 0; - if( battle_config.item_check ) { // check for invalid(ated) items + if( sd->state.itemcheck ) { // check for invalid(ated) items for( i = 0; i < MAX_INVENTORY; i++ ) { id = sd->status.inventory[i].nameid; - if( id && !itemdb_available(id) ) { + if (!id) + continue; + + if( !itemdb_available(id) ) { ShowWarning("Removed invalid/disabled item id %d from inventory (amount=%d, char_id=%d).\n", id, sd->status.inventory[i].amount, sd->status.char_id); pc->delitem(sd, i, sd->status.inventory[i].amount, 0, 0, LOG_TYPE_OTHER); + continue; } + + if ( !sd->status.inventory[i].unique_id && !itemdb->isstackable(id) ) + sd->status.inventory[i].unique_id = itemdb->unique_id(sd); } for( i = 0; i < MAX_CART; i++ ) { id = sd->status.cart[i].nameid; - if( id && !itemdb_available(id) ) { + if (!id) + continue; + + if( !itemdb_available(id) ) { ShowWarning("Removed invalid/disabled item id %d from cart (amount=%d, char_id=%d).\n", id, sd->status.cart[i].amount, sd->status.char_id); pc->cart_delitem(sd, i, sd->status.cart[i].amount, 0, LOG_TYPE_OTHER); + continue; + } + + if ( !sd->status.cart[i].unique_id && !itemdb->isstackable(id) ) + sd->status.cart[i].unique_id = itemdb->unique_id(sd); + } + + for( i = 0; i < MAX_STORAGE; i++ ) { + id = sd->status.storage.items[i].nameid; + + if (!id) + continue; + + if( id && !itemdb_available(id) ) { + ShowWarning("Removed invalid/disabled item id %d from storage (amount=%d, char_id=%d).\n", id, sd->status.storage.items[i].amount, sd->status.char_id); + storage->delitem(sd, i, sd->status.storage.items[i].amount); + storage->close(sd); + continue; } + + if ( !sd->status.storage.items[i].unique_id && !itemdb->isstackable(id) ) + sd->status.storage.items[i].unique_id = itemdb->unique_id(sd); } + + if (sd->guild) { + struct guild_storage *guild_storage = gstorage->id2storage2(sd->guild->guild_id); + if (guild_storage) { + for( i = 0; i < MAX_GUILD_STORAGE; i++ ) { + id = guild_storage->items[i].nameid; + + if (!id) + continue; + + if( !itemdb_available(id) ) { + ShowWarning("Removed invalid/disabled item id %d from guild storage (amount=%d, char_id=%d, guild_id=%d).\n", id, guild_storage->items[i].amount, sd->status.char_id, sd->guild->guild_id); + gstorage->delitem(sd, guild_storage, i, guild_storage->items[i].amount); + gstorage->close(sd); // force closing + continue; + } + + if (!guild_storage->items[i].unique_id && !itemdb->isstackable(id)) + guild_storage->items[i].unique_id = itemdb->unique_id(sd); + } + } + } + sd->state.itemcheck = 0; } for( i = 0; i < MAX_INVENTORY; i++) { @@ -8910,10 +9239,10 @@ int pc_checkitem(struct map_session_data *sd) } } - + if( calc_flag && sd->state.active ) { pc->checkallowskill(sd); - status_calc_pc(sd,0); + status_calc_pc(sd,SCO_NONE); } return 0; @@ -8939,17 +9268,16 @@ int pc_calc_pvprank_sub(struct block_list *bl,va_list ap) return 0; } /*========================================== - * Calculate new rank beetween all present players (iMap->foreachinarea) + * Calculate new rank beetween all present players (map->foreachinarea) * and display result *------------------------------------------*/ -int pc_calc_pvprank(struct map_session_data *sd) -{ +int pc_calc_pvprank(struct map_session_data *sd) { int old; struct map_data *m; - m=&map[sd->bl.m]; + m=&map->list[sd->bl.m]; old=sd->pvp_rank; sd->pvp_rank=1; - iMap->foreachinmap(pc_calc_pvprank_sub,sd->bl.m,BL_PC,sd); + map->foreachinmap(pc_calc_pvprank_sub,sd->bl.m,BL_PC,sd); if(old!=sd->pvp_rank || sd->pvp_lastusers!=m->users_pvp) clif->pvpset(sd,sd->pvp_rank,sd->pvp_lastusers=m->users_pvp,0); return sd->pvp_rank; @@ -8957,11 +9285,10 @@ int pc_calc_pvprank(struct map_session_data *sd) /*========================================== * Calculate next sd ranking calculation from config *------------------------------------------*/ -int pc_calc_pvprank_timer(int tid, unsigned int tick, int id, intptr_t data) -{ +int pc_calc_pvprank_timer(int tid, int64 tick, int id, intptr_t data) { struct map_session_data *sd; - sd=iMap->id2sd(id); + sd=map->id2sd(id); if(sd==NULL) return 0; sd->pvp_timer = INVALID_TIMER; @@ -8972,7 +9299,7 @@ int pc_calc_pvprank_timer(int tid, unsigned int tick, int id, intptr_t data) } if( pc->calc_pvprank(sd) > 0 ) - sd->pvp_timer = iTimer->add_timer(iTimer->gettick()+PVP_CALCRANK_INTERVAL,pc->calc_pvprank_timer,id,data); + sd->pvp_timer = timer->add(timer->gettick()+PVP_CALCRANK_INTERVAL,pc->calc_pvprank_timer,id,data); return 0; } @@ -9025,9 +9352,9 @@ int pc_divorce(struct map_session_data *sd) if( !sd->status.partner_id ) return -1; // Char is not married - if( (p_sd = iMap->charid2sd(sd->status.partner_id)) == NULL ) - { // Lets char server do the divorce - if( chrif_divorce(sd->status.char_id, sd->status.partner_id) ) + if( (p_sd = map->charid2sd(sd->status.partner_id)) == NULL ) { + // Lets char server do the divorce + if( chrif->divorce(sd->status.char_id, sd->status.partner_id) ) return -1; // No char server connected return 0; @@ -9053,11 +9380,10 @@ int pc_divorce(struct map_session_data *sd) /*========================================== * Get sd partner charid. (Married partner) *------------------------------------------*/ -struct map_session_data *pc_get_partner(struct map_session_data *sd) -{ +struct map_session_data *pc_get_partner(struct map_session_data *sd) { if (sd && pc->ismarried(sd)) // charid2sd returns NULL if not found - return iMap->charid2sd(sd->status.partner_id); + return map->charid2sd(sd->status.partner_id); return NULL; } @@ -9065,11 +9391,10 @@ struct map_session_data *pc_get_partner(struct map_session_data *sd) /*========================================== * Get sd father charid. (Need to be baby) *------------------------------------------*/ -struct map_session_data *pc_get_father (struct map_session_data *sd) -{ +struct map_session_data *pc_get_father(struct map_session_data *sd) { if (sd && sd->class_&JOBL_BABY && sd->status.father > 0) // charid2sd returns NULL if not found - return iMap->charid2sd(sd->status.father); + return map->charid2sd(sd->status.father); return NULL; } @@ -9077,11 +9402,10 @@ struct map_session_data *pc_get_father (struct map_session_data *sd) /*========================================== * Get sd mother charid. (Need to be baby) *------------------------------------------*/ -struct map_session_data *pc_get_mother (struct map_session_data *sd) -{ +struct map_session_data *pc_get_mother(struct map_session_data *sd) { if (sd && sd->class_&JOBL_BABY && sd->status.mother > 0) // charid2sd returns NULL if not found - return iMap->charid2sd(sd->status.mother); + return map->charid2sd(sd->status.mother); return NULL; } @@ -9089,11 +9413,10 @@ struct map_session_data *pc_get_mother (struct map_session_data *sd) /*========================================== * Get sd children charid. (Need to be married) *------------------------------------------*/ -struct map_session_data *pc_get_child (struct map_session_data *sd) -{ +struct map_session_data *pc_get_child(struct map_session_data *sd) { if (sd && pc->ismarried(sd) && sd->status.child > 0) // charid2sd returns NULL if not found - return iMap->charid2sd(sd->status.child); + return map->charid2sd(sd->status.child); return NULL; } @@ -9135,8 +9458,7 @@ void pc_bleeding (struct map_session_data *sd, unsigned int diff_tick) //Character regen. Flag is used to know which types of regen can take place. //&1: HP regen //&2: SP regen -void pc_regen (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; if (sd->hp_regen.value) { @@ -9156,7 +9478,7 @@ void pc_regen (struct map_session_data *sd, unsigned int diff_tick) } if (hp > 0 || sp > 0) - status_heal(&sd->bl, hp, sp, 0); + status->heal(&sd->bl, hp, sp, 0); return; } @@ -9164,11 +9486,10 @@ void pc_regen (struct map_session_data *sd, unsigned int diff_tick) /*========================================== * Memo player sd savepoint. (map,x,y) *------------------------------------------*/ -int pc_setsavepoint(struct map_session_data *sd, short mapindex,int x,int y) -{ +int pc_setsavepoint(struct map_session_data *sd, short map_index, int x, int y) { nullpo_ret(sd); - sd->status.save_point.map = mapindex; + sd->status.save_point.map = map_index; sd->status.save_point.x = x; sd->status.save_point.y = y; @@ -9176,10 +9497,9 @@ int pc_setsavepoint(struct map_session_data *sd, short mapindex,int x,int y) } /*========================================== - * Save 1 player data at autosave intervalle + * Save 1 player data at autosave intervall *------------------------------------------*/ -int pc_autosave(int tid, unsigned int tick, int id, intptr_t data) -{ +int pc_autosave(int tid, int64 tick, int id, intptr_t data) { int interval; struct s_mapiterator* iter; struct map_session_data* sd; @@ -9205,24 +9525,23 @@ int pc_autosave(int tid, unsigned int tick, int id, intptr_t data) last_save_id = sd->bl.id; save_flag = 2; - chrif_save(sd,0); + chrif->save(sd,0); break; } mapit->free(iter); - interval = iMap->autosave_interval/(iMap->usercount()+1); - if(interval < iMap->minsave_interval) - interval = iMap->minsave_interval; - iTimer->add_timer(iTimer->gettick()+interval,pc_autosave,0,0); + interval = map->autosave_interval/(map->usercount()+1); + if(interval < map->minsave_interval) + interval = map->minsave_interval; + timer->add(timer->gettick()+interval,pc->autosave,0,0); return 0; } -static int pc_daynight_timer_sub(struct map_session_data *sd,va_list ap) -{ - if (sd->state.night != iMap->night_flag && map[sd->bl.m].flag.nightenabled) { //Night/day state does not match. - clif->status_change(&sd->bl, SI_SKE, iMap->night_flag, 0, 0, 0, 0); //New night effect by dynamix [Skotlex] - sd->state.night = iMap->night_flag; +int pc_daynight_timer_sub(struct map_session_data *sd,va_list ap) { + 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; return 1; } return 0; @@ -9231,20 +9550,19 @@ static int pc_daynight_timer_sub(struct map_session_data *sd,va_list ap) * timer to do the day [Yor] * data: 0 = called by timer, 1 = gmcommand/script *------------------------------------------------*/ -int map_day_timer(int tid, unsigned int tick, int id, intptr_t data) -{ +int map_day_timer(int tid, int64 tick, int id, intptr_t data) { char tmp_soutput[1024]; - if (data == 0 && battle_config.day_duration <= 0) // if we want a day + if (data == 0 && battle_config.day_duration <= 0) // if we want a day return 0; - if (!iMap->night_flag) + if (!map->night_flag) return 0; //Already day. - iMap->night_flag = 0; // 0=day, 1=night [Yor] - iMap->map_foreachpc(pc_daynight_timer_sub); + map->night_flag = 0; // 0=day, 1=night [Yor] + map->foreachpc(pc->daynight_timer_sub); strcpy(tmp_soutput, (data == 0) ? msg_txt(502) : msg_txt(60)); // The day has arrived! - intif_broadcast(tmp_soutput, strlen(tmp_soutput) + 1, 0); + intif->broadcast(tmp_soutput, strlen(tmp_soutput) + 1, BC_DEFAULT); return 0; } @@ -9252,24 +9570,23 @@ int map_day_timer(int tid, unsigned int tick, int id, intptr_t data) * timer to do the night [Yor] * data: 0 = called by timer, 1 = gmcommand/script *------------------------------------------------*/ -int map_night_timer(int tid, unsigned int tick, int id, intptr_t data) -{ +int map_night_timer(int tid, int64 tick, int id, intptr_t data) { char tmp_soutput[1024]; - if (data == 0 && battle_config.night_duration <= 0) // if we want a night + if (data == 0 && battle_config.night_duration <= 0) // if we want a night return 0; - if (iMap->night_flag) + if (map->night_flag) return 0; //Already nigth. - iMap->night_flag = 1; // 0=day, 1=night [Yor] - iMap->map_foreachpc(pc_daynight_timer_sub); + map->night_flag = 1; // 0=day, 1=night [Yor] + map->foreachpc(pc->daynight_timer_sub); strcpy(tmp_soutput, (data == 0) ? msg_txt(503) : msg_txt(59)); // The night has fallen... - intif_broadcast(tmp_soutput, strlen(tmp_soutput) + 1, 0); + intif->broadcast(tmp_soutput, strlen(tmp_soutput) + 1, BC_DEFAULT); return 0; } -void pc_setstand(struct map_session_data *sd){ +void pc_setstand(struct map_session_data *sd) { nullpo_retv(sd); status_change_end(&sd->bl, SC_TENSIONRELAX, INVALID_TIMER); @@ -9283,23 +9600,23 @@ void pc_setstand(struct map_session_data *sd){ * Mechanic (MADO GEAR) **/ void pc_overheat(struct map_session_data *sd, int val) { - int heat = val, skill, + int heat = val, skill_lv, limit[] = { 10, 20, 28, 46, 66 }; if( !pc_ismadogear(sd) || sd->sc.data[SC_OVERHEAT] ) return; // already burning - skill = cap_value(pc->checkskill(sd,NC_MAINFRAME),0,4); + skill_lv = cap_value(pc->checkskill(sd,NC_MAINFRAME),0,4); if( sd->sc.data[SC_OVERHEAT_LIMITPOINT] ) { heat += sd->sc.data[SC_OVERHEAT_LIMITPOINT]->val1; status_change_end(&sd->bl,SC_OVERHEAT_LIMITPOINT,INVALID_TIMER); } heat = max(0,heat); // Avoid negative HEAT - if( heat >= limit[skill] ) - sc_start(&sd->bl,SC_OVERHEAT,100,0,1000); + if( heat >= limit[skill_lv] ) + sc_start(NULL,&sd->bl,SC_OVERHEAT,100,0,1000); else - sc_start(&sd->bl,SC_OVERHEAT_LIMITPOINT,100,heat,30000); + sc_start(NULL,&sd->bl,SC_OVERHEAT_LIMITPOINT,100,heat,30000); return; } @@ -9309,10 +9626,16 @@ void pc_overheat(struct map_session_data *sd, int val) { */ bool pc_isautolooting(struct map_session_data *sd, int nameid) { - int i; - if( !sd->state.autolooting ) + int i = 0; + + if (sd->state.autoloottype && sd->state.autoloottype&(1<<itemdb_type(nameid))) + return true; + + if (!sd->state.autolooting) return false; + ARR_FIND(0, AUTOLOOTITEM_SIZE, i, sd->state.autolootid[i] == nameid); + return (i != AUTOLOOTITEM_SIZE); } @@ -9325,12 +9648,11 @@ bool pc_can_use_command(struct map_session_data *sd, const char *command) { return atcommand->can_use(sd,command); } -static int pc_charm_timer(int tid, unsigned int tick, int id, intptr_t data) -{ +int pc_charm_timer(int tid, int64 tick, int id, intptr_t data) { struct map_session_data *sd; int i, type; - if( (sd=(struct map_session_data *)iMap->id2sd(id)) == NULL || sd->bl.type!=BL_PC ) + if( (sd=(struct map_session_data *)map->id2sd(id)) == NULL || sd->bl.type!=BL_PC ) return 1; ARR_FIND(1, 5, type, sd->charm[type] > 0); @@ -9373,15 +9695,15 @@ int pc_add_charm(struct map_session_data *sd,int interval,int max,int type) if( sd->charm[type] && sd->charm[type] >= max ) { if(sd->charm_timer[type][0] != INVALID_TIMER) - iTimer->delete_timer(sd->charm_timer[type][0],pc_charm_timer); + timer->delete(sd->charm_timer[type][0],pc->charm_timer); sd->charm[type]--; if( sd->charm[type] != 0 ) memmove(sd->charm_timer[type]+0, sd->charm_timer[type]+1, (sd->charm[type])*sizeof(int)); sd->charm_timer[type][sd->charm[type]] = INVALID_TIMER; } - tid = iTimer->add_timer(iTimer->gettick()+interval, pc_charm_timer, sd->bl.id, 0); - ARR_FIND(0, sd->charm[type], i, sd->charm_timer[type][i] == INVALID_TIMER || DIFF_TICK(iTimer->get_timer(tid)->tick, iTimer->get_timer(sd->charm_timer[type][i])->tick) < 0); + tid = timer->add(timer->gettick()+interval, pc->charm_timer, sd->bl.id, 0); + ARR_FIND(0, sd->charm[type], i, sd->charm_timer[type][i] == INVALID_TIMER || DIFF_TICK(timer->get(tid)->tick, timer->get(sd->charm_timer[type][i])->tick) < 0); if( i != sd->charm[type] ) memmove(sd->charm_timer[type]+i+1, sd->charm_timer[type]+i, (sd->charm[type]-i)*sizeof(int)); sd->charm_timer[type][i] = tid; @@ -9412,7 +9734,7 @@ int pc_del_charm(struct map_session_data *sd,int count,int type) for(i = 0; i < count; i++) { if(sd->charm_timer[type][i] != INVALID_TIMER) { - iTimer->delete_timer(sd->charm_timer[type][i],pc_charm_timer); + timer->delete(sd->charm_timer[type][i],pc->charm_timer); sd->charm_timer[type][i] = INVALID_TIMER; } } @@ -9424,19 +9746,13 @@ int pc_del_charm(struct map_session_data *sd,int count,int type) clif->charm(sd, type); return 0; } -#if defined(RENEWAL_DROP) || defined(RENEWAL_EXP) /*========================================== * Renewal EXP/Itemdrop rate modifier base on level penalty * 1=exp 2=itemdrop *------------------------------------------*/ -int pc_level_penalty_mod(struct map_session_data *sd, struct mob_data *md, int type) -{ - int diff, rate = 100, i; - - nullpo_ret(sd); - nullpo_ret(md); - - diff = md->level - sd->status.base_level; +int pc_level_penalty_mod(int diff, unsigned char race, unsigned short mode, int type) { +#if defined(RENEWAL_DROP) || defined(RENEWAL_EXP) + int rate = 100, i; if( diff < 0 ) diff = MAX_LEVEL + ( ~diff + 1 ); @@ -9444,22 +9760,24 @@ int pc_level_penalty_mod(struct map_session_data *sd, struct mob_data *md, int t for(i=0; i<RC_MAX; i++){ int tmp; - if( md->status.race != i ){ - if( md->status.mode&MD_BOSS && i < RC_BOSS ) + if( race != i ){ + if( mode&MD_BOSS && i < RC_BOSS ) i = RC_BOSS; else if( i <= RC_BOSS ) continue; } - if( (tmp=level_penalty[type][i][diff]) > 0 ){ + if( (tmp=pc->level_penalty[type][i][diff]) > 0 ){ rate = tmp; break; } } return rate; -} +#else + return 100; #endif +} int pc_split_str(char *str,char **val,int num) { int i; @@ -9516,59 +9834,271 @@ int pc_split_atoui(char* str, unsigned int* val, char sep, int max) val[j] = 0; return i; } +/* [Ind/Hercules] */ +void pc_read_skill_tree(void) { + config_t skill_tree_conf; + config_setting_t *skt = NULL, *inherit = NULL, *skills = NULL, *sk = NULL; +#ifdef RENEWAL + const char *config_filename = "db/re/skill_tree.conf"; // FIXME hardcoded name +#else + const char *config_filename = "db/pre-re/skill_tree.conf"; // FIXME hardcoded name +#endif + int i = 0, jnamelen = 0; + struct s_mapiterator *iter; + struct map_session_data *sd; + struct { + const char *name; + int id; + } jnames[] = { + { "Novice", JOB_NOVICE }, + { "Swordsman", JOB_SWORDMAN }, + { "Magician", JOB_MAGE }, + { "Archer", JOB_ARCHER }, + { "Acolyte", JOB_ACOLYTE }, + { "Merchant", JOB_MERCHANT }, + { "Thief", JOB_THIEF }, + { "Knight", JOB_KNIGHT }, + { "Priest", JOB_PRIEST }, + { "Wizard", JOB_WIZARD }, + { "Blacksmith", JOB_BLACKSMITH }, + { "Hunter", JOB_HUNTER }, + { "Assassin", JOB_ASSASSIN }, + { "Crusader", JOB_CRUSADER }, + { "Monk", JOB_MONK }, + { "Sage", JOB_SAGE }, + { "Rogue", JOB_ROGUE }, + { "Alchemist", JOB_ALCHEMIST }, + { "Bard", JOB_BARD }, + { "Dancer", JOB_DANCER }, + { "Super_Novice", JOB_SUPER_NOVICE }, + { "Gunslinger", JOB_GUNSLINGER }, + { "Ninja", JOB_NINJA }, + { "Novice_High", JOB_NOVICE_HIGH }, + { "Swordsman_High", JOB_SWORDMAN_HIGH }, + { "Magician_High", JOB_MAGE_HIGH }, + { "Archer_High", JOB_ARCHER_HIGH }, + { "Acolyte_High", JOB_ACOLYTE_HIGH }, + { "Merchant_High", JOB_MERCHANT_HIGH }, + { "Thief_High", JOB_THIEF_HIGH }, + { "Lord_Knight", JOB_LORD_KNIGHT }, + { "High_Priest", JOB_HIGH_PRIEST }, + { "High_Wizard", JOB_HIGH_WIZARD }, + { "Whitesmith", JOB_WHITESMITH }, + { "Sniper", JOB_SNIPER }, + { "Assassin_Cross", JOB_ASSASSIN_CROSS }, + { "Paladin", JOB_PALADIN }, + { "Champion", JOB_CHAMPION }, + { "Professor", JOB_PROFESSOR }, + { "Stalker", JOB_STALKER }, + { "Creator", JOB_CREATOR }, + { "Clown", JOB_CLOWN }, + { "Gypsy", JOB_GYPSY }, + { "Baby_Novice", JOB_BABY }, + { "Baby_Swordsman", JOB_BABY_SWORDMAN }, + { "Baby_Magician", JOB_BABY_MAGE }, + { "Baby_Archer", JOB_BABY_ARCHER }, + { "Baby_Acolyte", JOB_BABY_ACOLYTE }, + { "Baby_Merchant", JOB_BABY_MERCHANT }, + { "Baby_Thief", JOB_BABY_THIEF }, + { "Baby_Knight", JOB_BABY_KNIGHT }, + { "Baby_Priest", JOB_BABY_PRIEST }, + { "Baby_Wizard", JOB_BABY_WIZARD }, + { "Baby_Blacksmith", JOB_BABY_BLACKSMITH }, + { "Baby_Hunter", JOB_BABY_HUNTER }, + { "Baby_Assassin", JOB_BABY_ASSASSIN }, + { "Baby_Crusader", JOB_BABY_CRUSADER }, + { "Baby_Monk", JOB_BABY_MONK }, + { "Baby_Sage", JOB_BABY_SAGE }, + { "Baby_Rogue", JOB_BABY_ROGUE }, + { "Baby_Alchemist", JOB_BABY_ALCHEMIST }, + { "Baby_Bard", JOB_BABY_BARD }, + { "Baby_Dancer", JOB_BABY_DANCER }, + { "Super_Baby", JOB_SUPER_BABY }, + { "Taekwon", JOB_TAEKWON }, + { "Star_Gladiator", JOB_STAR_GLADIATOR }, + { "Soul_Linker", JOB_SOUL_LINKER }, + { "Gangsi", JOB_GANGSI }, + { "Death_Knight", JOB_DEATH_KNIGHT }, + { "Dark_Collector", JOB_DARK_COLLECTOR }, + { "Rune_Knight", JOB_RUNE_KNIGHT }, + { "Warlock", JOB_WARLOCK }, + { "Ranger", JOB_RANGER }, + { "Arch_Bishop", JOB_ARCH_BISHOP }, + { "Mechanic", JOB_MECHANIC }, + { "Guillotine_Cross", JOB_GUILLOTINE_CROSS }, + { "Rune_Knight_Trans", JOB_RUNE_KNIGHT_T }, + { "Warlock_Trans", JOB_WARLOCK_T }, + { "Ranger_Trans", JOB_RANGER_T }, + { "Arch_Bishop_Trans", JOB_ARCH_BISHOP_T }, + { "Mechanic_Trans", JOB_MECHANIC_T }, + { "Guillotine_Cross_Trans", JOB_GUILLOTINE_CROSS_T }, + { "Royal_Guard", JOB_ROYAL_GUARD }, + { "Sorcerer", JOB_SORCERER }, + { "Minstrel", JOB_MINSTREL }, + { "Wanderer", JOB_WANDERER }, + { "Sura", JOB_SURA }, + { "Genetic", JOB_GENETIC }, + { "Shadow_Chaser", JOB_SHADOW_CHASER }, + { "Royal_Guard_Trans", JOB_ROYAL_GUARD_T }, + { "Sorcerer_Trans", JOB_SORCERER_T }, + { "Minstrel_Trans", JOB_MINSTREL_T }, + { "Wanderer_Trans", JOB_WANDERER_T }, + { "Sura_Trans", JOB_SURA_T }, + { "Genetic_Trans", JOB_GENETIC_T }, + { "Shadow_Chaser_Trans", JOB_SHADOW_CHASER_T }, + { "Baby_Rune_Knight", JOB_BABY_RUNE }, + { "Baby_Warlock", JOB_BABY_WARLOCK }, + { "Baby_Ranger", JOB_BABY_RANGER }, + { "Baby_Arch_Bishop", JOB_BABY_BISHOP }, + { "Baby_Mechanic", JOB_BABY_MECHANIC }, + { "Baby_Guillotine_Cross", JOB_BABY_CROSS }, + { "Baby_Royal_Guard", JOB_BABY_GUARD }, + { "Baby_Sorcerer", JOB_BABY_SORCERER }, + { "Baby_Minstrel", JOB_BABY_MINSTREL }, + { "Baby_Wanderer", JOB_BABY_WANDERER }, + { "Baby_Sura", JOB_BABY_SURA }, + { "Baby_Genetic", JOB_BABY_GENETIC }, + { "Baby_Shadow_Chaser", JOB_BABY_CHASER }, + { "Expanded_Super_Novice", JOB_SUPER_NOVICE_E }, + { "Expanded_Super_Baby", JOB_SUPER_BABY_E }, + { "Kagerou", JOB_KAGEROU }, + { "Oboro", JOB_OBORO }, + { "Rebellion", JOB_REBELLION }, + }; + + if (libconfig->read_file(&skill_tree_conf, config_filename)) { + ShowError("can't read %s\n", config_filename); + return; + } + + jnamelen = ARRAYLENGTH(jnames); + + while( (skt = libconfig->setting_get_elem(skill_tree_conf.root,i++)) ) { + int k, idx; + const char *name = config_setting_name(skt); + + ARR_FIND(0, jnamelen, k, strcmpi(jnames[k].name,name) == 0 ); + + if( k == jnamelen ) { + ShowWarning("pc_read_skill_tree: '%s' unknown job name!\n",name); + continue; + } + + + if( ( skills = libconfig->setting_get_member(skt,"skills") ) ) { + int c = 0; + + idx = pc->class2idx(jnames[k].id); + + while( ( sk = libconfig->setting_get_elem(skills,c++) ) ) { + const char *sk_name = config_setting_name(sk); + int skill_id; + + if( ( skill_id = skill->name2id(sk_name) ) ) { + int skidx, offset = 0, h = 0, rlen = 0, rskid = 0; + + ARR_FIND( 0, MAX_SKILL_TREE, skidx, pc->skill_tree[idx][skidx].id == 0 || pc->skill_tree[idx][skidx].id == skill_id ); + if (skidx == MAX_SKILL_TREE) { + ShowWarning("pc_read_skill_tree: Unable to load skill %d (%s) into '%s's tree. Maximum number of skills per class has been reached.\n", skill_id, sk_name, name); + continue; + } else if (pc->skill_tree[idx][skidx].id) { + ShowNotice("pc_read_skill_tree: Overwriting %d for '%s' (%d)\n", skill_id, name, jnames[k].id); + } + + pc->skill_tree[idx][skidx].id = skill_id; + pc->skill_tree[idx][skidx].idx = skill->get_index(skill_id); + + if( config_setting_is_group(sk) ) { + int max = 0, jlevel = 0; + libconfig->setting_lookup_int(sk, "MaxLevel", &max); + libconfig->setting_lookup_int(sk, "MinJobLevel", &jlevel); + pc->skill_tree[idx][skidx].max = (unsigned char)max; + pc->skill_tree[idx][skidx].joblv = (unsigned char)jlevel; + rlen = libconfig->setting_length(sk); + offset += jlevel ? 2 : 1; + } else { + pc->skill_tree[idx][skidx].max = (unsigned char)libconfig->setting_get_int(sk); + pc->skill_tree[idx][skidx].joblv = 0; + } + + for( h = offset; h < rlen && h < MAX_PC_SKILL_REQUIRE; h++ ) { + config_setting_t *rsk = libconfig->setting_get_elem(sk,h); + if( rsk && ( rskid = skill->name2id(config_setting_name(rsk)) ) ) { + pc->skill_tree[idx][skidx].need[h].id = rskid; + pc->skill_tree[idx][skidx].need[h].idx = skill->get_index(rskid); + pc->skill_tree[idx][skidx].need[h].lv = (unsigned char)libconfig->setting_get_int(rsk); + } else if( rsk ) { + ShowWarning("pc_read_skill_tree: unknown requirement '%s' for '%s' in '%s'\n",config_setting_name(rsk),sk_name,name); + } else { + ShowWarning("pc_read_skill_tree: error for '%s' in '%s'\n",sk_name,name); + } + } + + } else { + ShowWarning("pc_read_skill_tree: unknown skill '%s' in '%s'\n",sk_name,name); + } + } + } + } + + i = 0; + while( (skt = libconfig->setting_get_elem(skill_tree_conf.root,i++)) ) { + int k, idx, v = 0; + const char *name = config_setting_name(skt); + const char *iname; -/*========================================== - * sub DB reading. - * Function used to read skill_tree.txt - *------------------------------------------*/ -static bool pc_readdb_skilltree(char* fields[], int columns, int current) -{ - unsigned char joblv = 0, skill_lv; - uint16 skill_id; - int idx, class_; - unsigned int i, offset = 3, skill_idx; + + ARR_FIND(0, jnamelen, k, strcmpi(jnames[k].name,name) == 0 ); + + if( k == jnamelen ) { + ShowWarning("pc_read_skill_tree: '%s' unknown job name!\n",name); + continue; + } + idx = pc->class2idx(jnames[k].id); - class_ = atoi(fields[0]); - skill_id = (uint16)atoi(fields[1]); - skill_lv = (unsigned char)atoi(fields[2]); + if( ( inherit = libconfig->setting_get_member(skt,"inherit") ) ) { + while( ( iname = libconfig->setting_get_string_elem(inherit, v++) ) ) { + int b = 0, a, d, f, fidx; - if(columns==4+MAX_PC_SKILL_REQUIRE*2) - {// job level requirement extra column - joblv = (unsigned char)atoi(fields[3]); - offset++; - } + ARR_FIND(0, jnamelen, b, strcmpi(jnames[b].name,iname) == 0 ); + + if( b == jnamelen ) { + ShowWarning("pc_read_skill_tree: '%s' trying to inherit unknown '%s'!\n",name,iname); + continue; + } + + fidx = pc->class2idx(jnames[b].id); + + ARR_FIND( 0, MAX_SKILL_TREE, d, pc->skill_tree[fidx][d].id == 0 ); - if(!pcdb_checkid(class_)) - { - ShowWarning("pc_readdb_skilltree: Invalid job class %d specified.\n", class_); - return false; - } - idx = pc->class2idx(class_); + for( f = 0; f < d; f++ ) { + + ARR_FIND( 0, MAX_SKILL_TREE, a, pc->skill_tree[idx][a].id == 0 || pc->skill_tree[idx][a].id == pc->skill_tree[fidx][f].id ); - //This is to avoid adding two lines for the same skill. [Skotlex] - ARR_FIND( 0, MAX_SKILL_TREE, skill_idx, skill_tree[idx][skill_idx].id == 0 || skill_tree[idx][skill_idx].id == skill_id ); - if( skill_idx == MAX_SKILL_TREE ) { - ShowWarning("pc_readdb_skilltree: Unable to load skill %hu into job %d's tree. Maximum number of skills per class has been reached.\n", skill_id, class_); - return false; - } else if(skill_tree[idx][skill_idx].id) { - ShowNotice("pc_readdb_skilltree: Overwriting skill %hu for job class %d.\n", skill_id, class_); + if( a == MAX_SKILL_TREE ) { + ShowWarning("pc_read_skill_tree: '%s' can't inherit '%s', skill tree is full!\n", name,iname); + break; + } else if ( pc->skill_tree[idx][a].id || ( pc->skill_tree[idx][a].id == NV_TRICKDEAD && ((pc->jobid2mapid(jnames[k].id)&(MAPID_BASEMASK|JOBL_2))!=MAPID_NOVICE) ) ) /* we skip trickdead for non-novices */ + continue;/* skip */ + + memcpy(&pc->skill_tree[idx][a],&pc->skill_tree[fidx][f],sizeof(pc->skill_tree[fidx][f])); + } + + } + } + } + + libconfig->destroy(&skill_tree_conf); - skill_tree[idx][skill_idx].id = skill_id; - skill_tree[idx][skill_idx].idx = skill->get_index(skill_id); - skill_tree[idx][skill_idx].max = skill_lv; - skill_tree[idx][skill_idx].joblv = joblv; - - for(i = 0; i < MAX_PC_SKILL_REQUIRE; i++) { - skill_tree[idx][skill_idx].need[i].id = atoi(fields[i*2+offset]); - skill_tree[idx][skill_idx].need[i].idx = skill->get_index(atoi(fields[i*2+offset])); - skill_tree[idx][skill_idx].need[i].lv = atoi(fields[i*2+offset+1]); - } - return true; + /* lets update all players skill tree */ + iter = mapit_getallusers(); + for( sd = (TBL_PC*)mapit->first(iter); mapit->exists(iter); sd = (TBL_PC*)mapit->next(iter) ) + clif->skillinfoblock(sd); + mapit->free(iter); } +bool pc_readdb_levelpenalty(char* fields[], int columns, int current) { #if defined(RENEWAL_DROP) || defined(RENEWAL_EXP) -static bool pc_readdb_levelpenalty(char* fields[], int columns, int current) -{ int type, race, diff; type = atoi(fields[0]); @@ -9590,11 +10120,10 @@ static bool pc_readdb_levelpenalty(char* fields[], int columns, int current) if( diff < 0 ) diff = min(MAX_LEVEL + ( ~(diff) + 1 ), MAX_LEVEL*2); - level_penalty[type][race][diff] = atoi(fields[3]); - + pc->level_penalty[type][race][diff] = atoi(fields[3]); +#endif return true; } -#endif /*========================================== * pc DB reading. @@ -9602,26 +10131,24 @@ static bool pc_readdb_levelpenalty(char* fields[], int columns, int current) * skill_tree.txt - skill tree for every class * attr_fix.txt - elemental adjustment table *------------------------------------------*/ -int pc_readdb(void) -{ +int pc_readdb(void) { int i,j,k; unsigned int count = 0; FILE *fp; char line[24000],*p; - //reset - memset(exp_table,0,sizeof(exp_table)); - memset(max_level,0,sizeof(max_level)); + //reset + memset(pc->exp_table,0,sizeof(pc->exp_table)); + memset(pc->max_level,0,sizeof(pc->max_level)); - sprintf(line, "%s/"DBPATH"exp.txt", iMap->db_path); + sprintf(line, "%s/"DBPATH"exp.txt", map->db_path); fp=fopen(line, "r"); if(fp==NULL){ ShowError("can't read %s\n", line); return 1; } - while(fgets(line, sizeof(line), fp)) - { + while(fgets(line, sizeof(line), fp)) { int jobs[CLASS_COUNT], job_count, job, job_id; int type; unsigned int ui,maxlv; @@ -9652,23 +10179,23 @@ int pc_readdb(void) count++; job = jobs[0] = pc->class2idx(job_id); //We send one less and then one more because the last entry in the exp array should hold 0. - max_level[job][type] = pc_split_atoui(split[3], exp_table[job][type],',',maxlv-1)+1; + pc->max_level[job][type] = pc_split_atoui(split[3], pc->exp_table[job][type],',',maxlv-1)+1; //Reverse check in case the array has a bunch of trailing zeros... [Skotlex] //The reasoning behind the -2 is this... if the max level is 5, then the array //should look like this: //0: x, 1: x, 2: x: 3: x 4: 0 <- last valid value is at 3. - while ((ui = max_level[job][type]) >= 2 && exp_table[job][type][ui-2] <= 0) - max_level[job][type]--; - if (max_level[job][type] < maxlv) { - ShowWarning("pc_readdb: Specified max %u for job %d, but that job's exp table only goes up to level %u.\n", maxlv, job_id, max_level[job][type]); + while ((ui = pc->max_level[job][type]) >= 2 && pc->exp_table[job][type][ui-2] <= 0) + pc->max_level[job][type]--; + if (pc->max_level[job][type] < maxlv) { + ShowWarning("pc_readdb: Specified max %u for job %d, but that job's exp table only goes up to level %u.\n", maxlv, job_id, pc->max_level[job][type]); ShowInfo("Filling the missing values with the last exp entry.\n"); //Fill the requested values with the last entry. - ui = (max_level[job][type] <= 2? 0: max_level[job][type]-2); + ui = (pc->max_level[job][type] <= 2? 0: pc->max_level[job][type]-2); for (; ui+2 < maxlv; ui++) - exp_table[job][type][ui] = exp_table[job][type][ui-1]; - max_level[job][type] = maxlv; + pc->exp_table[job][type][ui] = pc->exp_table[job][type][ui-1]; + pc->max_level[job][type] = maxlv; } -// ShowDebug("%s - Class %d: %d\n", type?"Job":"Base", job_id, max_level[job][type]); +// ShowDebug("%s - Class %d: %d\n", type?"Job":"Base", job_id, pc->max_level[job][type]); for (i = 1; i < job_count; i++) { job_id = jobs[i]; if (!pcdb_checkid(job_id)) { @@ -9676,9 +10203,9 @@ int pc_readdb(void) continue; } job = pc->class2idx(job_id); - memcpy(exp_table[job][type], exp_table[jobs[0]][type], sizeof(exp_table[0][0])); - max_level[job][type] = maxlv; -// ShowDebug("%s - Class %d: %u\n", type?"Job":"Base", job_id, max_level[job][type]); + memcpy(pc->exp_table[job][type], pc->exp_table[jobs[0]][type], sizeof(pc->exp_table[0][0])); + pc->max_level[job][type] = maxlv; +// ShowDebug("%s - Class %d: %u\n", type?"Job":"Base", job_id, pc->max_level[job][type]); } } fclose(fp); @@ -9687,29 +10214,28 @@ int pc_readdb(void) if (i == JOB_WEDDING || i == JOB_XMAS || i == JOB_SUMMER) continue; //Classes that do not need exp tables. j = pc->class2idx(i); - if (!max_level[j][0]) + if (!pc->max_level[j][0]) ShowWarning("Class %s (%d) does not has a base exp table.\n", pc->job_name(i), i); - if (!max_level[j][1]) + if (!pc->max_level[j][1]) ShowWarning("Class %s (%d) does not has a job exp table.\n", pc->job_name(i), i); } - ShowStatus("Done reading '"CL_WHITE"%lu"CL_RESET"' entries in '"CL_WHITE"%s/"DBPATH"%s"CL_RESET"'.\n",count,iMap->db_path,"exp.txt"); + ShowStatus("Done reading '"CL_WHITE"%u"CL_RESET"' entries in '"CL_WHITE"%s/"DBPATH"%s"CL_RESET"'.\n",count,map->db_path,"exp.txt"); count = 0; // Reset and read skilltree - memset(skill_tree,0,sizeof(skill_tree)); - sv->readdb(iMap->db_path, DBPATH"skill_tree.txt", ',', 3+MAX_PC_SKILL_REQUIRE*2, 4+MAX_PC_SKILL_REQUIRE*2, -1, &pc_readdb_skilltree); - + memset(pc->skill_tree,0,sizeof(pc->skill_tree)); + pc->read_skill_tree(); #if defined(RENEWAL_DROP) || defined(RENEWAL_EXP) - sv->readdb(iMap->db_path, "re/level_penalty.txt", ',', 4, 4, -1, &pc_readdb_levelpenalty); + sv->readdb(map->db_path, "re/level_penalty.txt", ',', 4, 4, -1, pc->readdb_levelpenalty); for( k=1; k < 3; k++ ){ // fill in the blanks for( j = 0; j < RC_MAX; j++ ){ int tmp = 0; for( i = 0; i < MAX_LEVEL*2; i++ ){ if( i == MAX_LEVEL+1 ) - tmp = level_penalty[k][j][0];// reset - if( level_penalty[k][j][i] > 0 ) - tmp = level_penalty[k][j][i]; + tmp = pc->level_penalty[k][j][0];// reset + if( pc->level_penalty[k][j][i] > 0 ) + tmp = pc->level_penalty[k][j][i]; else - level_penalty[k][j][i] = tmp; + pc->level_penalty[k][j][i] = tmp; } } } @@ -9719,9 +10245,9 @@ int pc_readdb(void) for(i=0;i<4;i++) for(j=0;j<ELE_MAX;j++) for(k=0;k<ELE_MAX;k++) - attr_fix_table[i][j][k]=100; + battle->attr_fix_table[i][j][k]=100; - sprintf(line, "%s/"DBPATH"attr_fix.txt", iMap->db_path); + sprintf(line, "%s/"DBPATH"attr_fix.txt", map->db_path); fp=fopen(line,"r"); if(fp==NULL){ @@ -9754,9 +10280,11 @@ int pc_readdb(void) for(j=0,p=line;j<n && j<ELE_MAX && p;j++){ while(*p==32 && *p>0) p++; - attr_fix_table[lv-1][i][j]=atoi(p); - if(battle_config.attr_recover == 0 && attr_fix_table[lv-1][i][j] < 0) - attr_fix_table[lv-1][i][j] = 0; + battle->attr_fix_table[lv-1][i][j]=atoi(p); +#ifndef RENEWAL + if(battle_config.attr_recover == 0 && battle->attr_fix_table[lv-1][i][j] < 0) + battle->attr_fix_table[lv-1][i][j] = 0; +#endif p=strchr(p,','); if(p) *p++=0; } @@ -9765,13 +10293,13 @@ int pc_readdb(void) } } fclose(fp); - ShowStatus("Done reading '"CL_WHITE"%lu"CL_RESET"' entries in '"CL_WHITE"%s/"DBPATH"%s"CL_RESET"'.\n",count,iMap->db_path,"attr_fix.txt"); + ShowStatus("Done reading '"CL_WHITE"%u"CL_RESET"' entries in '"CL_WHITE"%s/"DBPATH"%s"CL_RESET"'.\n",count,map->db_path,"attr_fix.txt"); count = 0; - // reset then read statspoint - memset(statp,0,sizeof(statp)); + // reset then read statspoint + memset(pc->statp,0,sizeof(pc->statp)); i=1; - sprintf(line, "%s/"DBPATH"statpoint.txt", iMap->db_path); + sprintf(line, "%s/"DBPATH"statpoint.txt", map->db_path); fp=fopen(line,"r"); if(fp == NULL){ ShowWarning("Can't read '"CL_WHITE"%s"CL_RESET"'... Generating DB.\n",line); @@ -9782,24 +10310,24 @@ int pc_readdb(void) int stat; if(line[0]=='/' && line[1]=='/') continue; - if ((stat=strtoul(line,NULL,10))<0) + if ((stat=(int)strtol(line,NULL,10))<0) stat=0; if (i > MAX_LEVEL) break; count++; - statp[i]=stat; + pc->statp[i]=stat; i++; } fclose(fp); - ShowStatus("Done reading '"CL_WHITE"%lu"CL_RESET"' entries in '"CL_WHITE"%s/"DBPATH"%s"CL_RESET"'.\n",count,iMap->db_path,"statpoint.txt"); + ShowStatus("Done reading '"CL_WHITE"%u"CL_RESET"' entries in '"CL_WHITE"%s/"DBPATH"%s"CL_RESET"'.\n",count,map->db_path,"statpoint.txt"); } // generate the remaining parts of the db if necessary k = battle_config.use_statpoint_table; //save setting battle_config.use_statpoint_table = 0; //temporarily disable to force pc->gets_status_point use default values - statp[0] = 45; // seed value + pc->statp[0] = 45; // seed value for (; i <= MAX_LEVEL; i++) - statp[i] = statp[i-1] + pc->gets_status_point(i-1); + pc->statp[i] = pc->statp[i-1] + pc->gets_status_point(i-1); battle_config.use_statpoint_table = k; //restore setting return 0; @@ -9810,26 +10338,26 @@ void pc_itemcd_do(struct map_session_data *sd, bool load) { struct item_cd* cd = NULL; if( load ) { - if( !(cd = idb_get(itemcd_db, sd->status.char_id)) ) { + if( !(cd = idb_get(pc->itemcd_db, sd->status.char_id)) ) { // no skill cooldown is associated with this character return; } for(i = 0; i < MAX_ITEMDELAYS; i++) { - if( cd->nameid[i] && DIFF_TICK(iTimer->gettick(),cd->tick[i]) < 0 ) { + if( cd->nameid[i] && DIFF_TICK(timer->gettick(),cd->tick[i]) < 0 ) { sd->item_delay[cursor].tick = cd->tick[i]; sd->item_delay[cursor].nameid = cd->nameid[i]; cursor++; } } - idb_remove(itemcd_db,sd->status.char_id); + idb_remove(pc->itemcd_db,sd->status.char_id); } else { - if( !(cd = idb_get(itemcd_db,sd->status.char_id)) ) { + if( !(cd = idb_get(pc->itemcd_db,sd->status.char_id)) ) { // create a new skill cooldown object for map storage CREATE( cd, struct item_cd, 1 ); - idb_put( itemcd_db, sd->status.char_id, cd ); + idb_put( pc->itemcd_db, sd->status.char_id, cd ); } for(i = 0; i < MAX_ITEMDELAYS; i++) { - if( sd->item_delay[i].nameid && DIFF_TICK(iTimer->gettick(),sd->item_delay[i].tick) < 0 ) { + if( sd->item_delay[i].nameid && DIFF_TICK(timer->gettick(),sd->item_delay[i].tick) < 0 ) { cd->tick[cursor] = sd->item_delay[i].tick; cd->nameid[cursor] = sd->item_delay[i].nameid; cursor++; @@ -9839,79 +10367,456 @@ void pc_itemcd_do(struct map_session_data *sd, bool load) { return; } -/*========================================== - * pc Init/Terminate - *------------------------------------------*/ -void do_final_pc(void) { +void pc_bank_deposit(struct map_session_data *sd, int money) { + unsigned int limit_check = money+sd->status.bank_vault; + + if( money <= 0 || limit_check > MAX_BANK_ZENY ) { + clif->bank_deposit(sd,BDA_OVERFLOW); + return; + } else if ( money > sd->status.zeny ) { + clif->bank_deposit(sd,BDA_NO_MONEY); + return; + } - db_destroy(itemcd_db); + if( pc->payzeny(sd,money, LOG_TYPE_BANK, NULL) ) + clif->bank_deposit(sd,BDA_NO_MONEY); + else { + sd->status.bank_vault += money; + if( map->save_settings&256 ) + chrif->save(sd,0); + clif->bank_deposit(sd,BDA_SUCCESS); + } +} +void pc_bank_withdraw(struct map_session_data *sd, int money) { + unsigned int limit_check = money+sd->status.zeny; + + if( money <= 0 ) { + clif->bank_withdraw(sd,BWA_UNKNOWN_ERROR); + return; + } else if ( money > sd->status.bank_vault ) { + clif->bank_withdraw(sd,BWA_NO_MONEY); + return; + } else if ( limit_check > MAX_ZENY ) { + /* no official response for this scenario exists. */ + clif->colormes(sd->fd,COLOR_RED,msg_txt(1482)); + return; + } + + if( pc->getzeny(sd,money, LOG_TYPE_BANK, NULL) ) + clif->bank_withdraw(sd,BWA_NO_MONEY); + else { + sd->status.bank_vault -= money; + if( map->save_settings&256 ) + chrif->save(sd,0); + clif->bank_withdraw(sd,BWA_SUCCESS); + } +} +/* status change data arrived from char-server */ +void pc_scdata_received(struct map_session_data *sd) { + pc->inventory_rentals(sd); + clif->show_modifiers(sd); + + if (sd->expiration_time != 0) { // don't display if it's unlimited or unknow value + time_t exp_time = sd->expiration_time; + char tmpstr[1024]; + strftime(tmpstr, sizeof(tmpstr) - 1, msg_txt(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); + + pc->expire_check(sd); + } + + if( sd->state.standalone ) { + clif->pLoadEndAck(0,sd); + pc->autotrade_populate(sd); + pc->autotrade_start(sd); + } +} +int pc_expiration_timer(int tid, int64 tick, int id, intptr_t data) { + struct map_session_data *sd = map->id2sd(id); + + if( !sd ) return 0; + + sd->expiration_tid = INVALID_TIMER; + + if( sd->fd ) + clif->authfail_fd(sd->fd,10); + + map->quit(sd); + + return 0; +} +/* this timer exists only when a character with a expire timer > 24h is online */ +/* it loops thru online players once an hour to check whether a new < 24h is available */ +int pc_global_expiration_timer(int tid, int64 tick, int id, intptr_t data) { + struct s_mapiterator* iter; + struct map_session_data* sd; - do_final_pc_groups(); + iter = mapit_getallusers(); - ers_destroy(pc_sc_display_ers); - return; + for( sd = (TBL_PC*)mapit->first(iter); mapit->exists(iter); sd = (TBL_PC*)mapit->next(iter) ) { + if( sd->expiration_time ) + pc->expire_check(sd); + } + + mapit->free(iter); + + return 0; } +void pc_expire_check(struct map_session_data *sd) { + /* ongoing timer */ + if( sd->expiration_tid != INVALID_TIMER ) + return; + + /* not within the next 24h, enable the global check */ + if( sd->expiration_time > ( time(NULL) + ( ( 60 * 60 ) * 24 ) ) ) { + + /* global check not running, enable */ + if( pc->expiration_tid == INVALID_TIMER ) { + /* starts in 1h, repeats every hour */ + pc->expiration_tid = timer->add_interval(timer->gettick() + ((1000*60)*60), pc->global_expiration_timer, 0, 0, ((1000*60)*60)); + } + + return; + } -int do_init_pc(void) { + sd->expiration_tid = timer->add(timer->gettick() + (int64)(sd->expiration_time - time(NULL))*1000, pc->expiration_timer, sd->bl.id, 0); +} +/** + * Loads autotraders + ***/ +void pc_autotrade_load(void) { + struct map_session_data *sd; + char *data; + + if (SQL_ERROR == SQL->Query(map->mysql_handle, "SELECT `account_id`,`char_id`,`sex`,`title` FROM `%s`",map->autotrade_merchants_db)) + Sql_ShowDebug(map->mysql_handle); + + while( SQL_SUCCESS == SQL->NextRow(map->mysql_handle) ) { + int account_id, char_id; + char title[MESSAGE_SIZE]; + unsigned char sex; + + SQL->GetData(map->mysql_handle, 0, &data, NULL); account_id = atoi(data); + SQL->GetData(map->mysql_handle, 1, &data, NULL); char_id = atoi(data); + SQL->GetData(map->mysql_handle, 2, &data, NULL); sex = atoi(data); + SQL->GetData(map->mysql_handle, 3, &data, NULL); safestrncpy(title, data, sizeof(title)); - itemcd_db = idb_alloc(DB_OPT_RELEASE_DATA); + CREATE(sd, TBL_PC, 1); + + pc->setnewpc(sd, account_id, char_id, 0, 0, sex, 0); + + safestrncpy(sd->message, title, MESSAGE_SIZE); + + sd->state.standalone = 1; + sd->group = pcg->get_dummy_group(); + + chrif->authreq(sd,true); + } + + SQL->FreeResult(map->mysql_handle); +} +/** + * Loads vending data and sets it up, is triggered when char server data that pc_autotrade_load requested arrives + **/ +void pc_autotrade_start(struct map_session_data *sd) { + unsigned int count = 0; + int i; + char *data; - pc->readdb(); + 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); - iTimer->add_timer_func_list(pc_invincible_timer, "pc_invincible_timer"); - iTimer->add_timer_func_list(pc_eventtimer, "pc_eventtimer"); - iTimer->add_timer_func_list(pc_inventory_rental_end, "pc_inventory_rental_end"); - iTimer->add_timer_func_list(pc->calc_pvprank_timer, "pc->calc_pvprank_timer"); - iTimer->add_timer_func_list(pc_autosave, "pc_autosave"); - iTimer->add_timer_func_list(pc_spiritball_timer, "pc_spiritball_timer"); - iTimer->add_timer_func_list(pc_follow_timer, "pc_follow_timer"); - iTimer->add_timer_func_list(pc->endautobonus, "pc->endautobonus"); - iTimer->add_timer_func_list(pc_charm_timer, "pc_charm_timer"); + while( SQL_SUCCESS == SQL->NextRow(map->mysql_handle) ) { + int itemkey, amount, price; + + SQL->GetData(map->mysql_handle, 0, &data, NULL); itemkey = atoi(data); + SQL->GetData(map->mysql_handle, 1, &data, NULL); amount = atoi(data); + SQL->GetData(map->mysql_handle, 2, &data, NULL); price = atoi(data); - iTimer->add_timer(iTimer->gettick() + iMap->autosave_interval, pc_autosave, 0, 0); + ARR_FIND(0, MAX_CART, i, sd->status.cart[i].id == itemkey); + + if( i != MAX_CART && itemdb_cantrade(&sd->status.cart[i], 0, 0) ) { + if( amount > sd->status.cart[i].amount ) + amount = sd->status.cart[i].amount; + + if( amount ) { + sd->vending[count].index = i; + sd->vending[count].amount = amount; + sd->vending[count].value = cap_value(price, 0, (unsigned int)battle_config.vending_max_value); - // 0=day, 1=night [Yor] - iMap->night_flag = battle_config.night_at_start ? 1 : 0; + count++; + } + } + } + + if( !count ) { + pc->autotrade_update(sd,PAUC_REMOVE); + map->quit(sd); + } else { + sd->state.autotrade = 1; + sd->vender_id = ++vending->next_id; + sd->vend_num = count; + sd->state.vending = true; + idb_put(vending->db, sd->status.char_id, sd); + if( map->list[sd->bl.m].users ) + clif->showvendingboard(&sd->bl,sd->message,0); + } +} +/** + * Perform a autotrade action + **/ +void pc_autotrade_update(struct map_session_data *sd, enum e_pc_autotrade_update_action action) { + int i; + + /* 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)) + Sql_ShowDebug(map->mysql_handle); + } + + switch( action ) { + case PAUC_REMOVE: + if (SQL_ERROR == SQL->Query(map->mysql_handle, "DELETE FROM `%s` WHERE `char_id` = '%d' LIMIT 1",map->autotrade_merchants_db,sd->status.char_id)) + Sql_ShowDebug(map->mysql_handle); + break; + case PAUC_START: { + char title[MESSAGE_SIZE*2+1]; + + SQL->EscapeStringLen(map->mysql_handle, title, sd->message, strnlen(sd->message, MESSAGE_SIZE)); + + if (SQL_ERROR == SQL->Query(map->mysql_handle, "INSERT INTO `%s` (`account_id`,`char_id`,`sex`,`title`) VALUES ('%d','%d','%d','%s')", + map->autotrade_merchants_db, + sd->status.account_id, + sd->status.char_id, + sd->status.sex, + title + )) + Sql_ShowDebug(map->mysql_handle); + } + /* yes we want it to fall */ + case PAUC_REFRESH: + for( i = 0; i < sd->vend_num; i++ ) { + if( sd->vending[i].amount == 0 ) + continue; + + if (SQL_ERROR == SQL->Query(map->mysql_handle, "INSERT INTO `%s` (`char_id`,`itemkey`,`amount`,`price`) VALUES ('%d','%d','%d','%d')", + map->autotrade_data_db, + sd->status.char_id, + sd->status.cart[sd->vending[i].index].id, + sd->vending[i].amount, + sd->vending[i].value + )) + Sql_ShowDebug(map->mysql_handle); + } + break; + } +} +/** + * Handles characters upon @autotrade usage + **/ +void pc_autotrade_prepare(struct map_session_data *sd) { + struct autotrade_vending *data; + int i, cursor = 0; + int account_id, char_id; + char title[MESSAGE_SIZE]; + unsigned char sex; + + CREATE(data, struct autotrade_vending, 1); + + memcpy(data->vending, sd->vending, sizeof(sd->vending)); + + for(i = 0; i < sd->vend_num; i++) { + if( sd->vending[i].amount ) { + memcpy(&data->list[cursor],&sd->status.cart[sd->vending[i].index],sizeof(struct item)); + cursor++; + } + } + + data->vend_num = (unsigned char)cursor; + + idb_put(pc->at_db, sd->status.char_id, data); + + account_id = sd->status.account_id; + char_id = sd->status.char_id; + sex = sd->status.sex; + safestrncpy(title, sd->message, sizeof(title)); + + sd->npc_id = 0; + sd->npc_shopid = 0; + if (sd->st) { + sd->st->state = END; + sd->st = NULL; + } + map->quit(sd); + chrif->auth_delete(account_id, char_id, ST_LOGOUT); + + CREATE(sd, TBL_PC, 1); + + pc->setnewpc(sd, account_id, char_id, 0, 0, sex, 0); + + safestrncpy(sd->message, title, MESSAGE_SIZE); + + sd->state.standalone = 1; + sd->group = pcg->get_dummy_group(); + + chrif->authreq(sd,true); +} +/** + * Prepares autotrade data from pc->at_db from a player that has already returned from char server + **/ +void pc_autotrade_populate(struct map_session_data *sd) { + struct autotrade_vending *data; + int i, j, k, cursor = 0; + + if( !(data = idb_get(pc->at_db,sd->status.char_id)) ) + return; + + for(i = 0; i < data->vend_num; i++) { + if( !data->vending[i].amount ) + continue; + + for(j = 0; j < MAX_CART; j++) { + if( !memcmp((char*)(&data->list[i]) + sizeof(data->list[0].id), (char*)(&sd->status.cart[j]) + sizeof(data->list[0].id), sizeof(struct item) - sizeof(data->list[0].id)) ) { + if( cursor ) { + ARR_FIND(0, cursor, k, sd->vending[k].index == j); + if( k != cursor ) + continue; + } + break; + } + } + + if( j != MAX_CART ) { + sd->vending[cursor].index = j; + sd->vending[cursor].amount = data->vending[i].amount; + sd->vending[cursor].value = data->vending[i].value; + + cursor++; + } + } + + sd->vend_num = cursor; + + pc->autotrade_update(sd,PAUC_START); + + idb_remove(pc->at_db, sd->status.char_id); +} +void do_final_pc(void) { + + db_destroy(pc->itemcd_db); + db_destroy(pc->at_db); + + pcg->final(); + + ers_destroy(pc->sc_display_ers); + ers_destroy(pc->num_reg_ers); + ers_destroy(pc->str_reg_ers); + return; +} + +void do_init_pc(bool minimal) { + if (minimal) + return; + + pc->itemcd_db = idb_alloc(DB_OPT_RELEASE_DATA); + pc->at_db = idb_alloc(DB_OPT_RELEASE_DATA); + + pc->readdb(); + + timer->add_func_list(pc->invincible_timer, "pc_invincible_timer"); + timer->add_func_list(pc->eventtimer, "pc_eventtimer"); + timer->add_func_list(pc->inventory_rental_end, "pc_inventory_rental_end"); + timer->add_func_list(pc->calc_pvprank_timer, "pc_calc_pvprank_timer"); + timer->add_func_list(pc->autosave, "pc_autosave"); + timer->add_func_list(pc->spiritball_timer, "pc_spiritball_timer"); + timer->add_func_list(pc->follow_timer, "pc_follow_timer"); + timer->add_func_list(pc->endautobonus, "pc_endautobonus"); + timer->add_func_list(pc->charm_timer, "pc_charm_timer"); + timer->add_func_list(pc->global_expiration_timer,"pc_global_expiration_timer"); + timer->add_func_list(pc->expiration_timer,"pc_expiration_timer"); + + timer->add(timer->gettick() + map->autosave_interval, pc->autosave, 0, 0); + + // 0=day, 1=night [Yor] + map->night_flag = battle_config.night_at_start ? 1 : 0; + if (battle_config.day_duration > 0 && battle_config.night_duration > 0) { int day_duration = battle_config.day_duration; int night_duration = battle_config.night_duration; // add night/day timer [Yor] - iTimer->add_timer_func_list(pc->map_day_timer, "pc->map_day_timer"); - iTimer->add_timer_func_list(pc->map_night_timer, "pc->map_night_timer"); - - pc->day_timer_tid = iTimer->add_timer_interval(iTimer->gettick() + (iMap->night_flag ? 0 : day_duration) + night_duration, pc->map_day_timer, 0, 0, day_duration + night_duration); - pc->night_timer_tid = iTimer->add_timer_interval(iTimer->gettick() + day_duration + (iMap->night_flag ? night_duration : 0), pc->map_night_timer, 0, 0, day_duration + night_duration); + timer->add_func_list(pc->map_day_timer, "pc_map_day_timer"); + timer->add_func_list(pc->map_night_timer, "pc_map_night_timer"); + + pc->day_timer_tid = timer->add_interval(timer->gettick() + (map->night_flag ? 0 : day_duration) + night_duration, pc->map_day_timer, 0, 0, day_duration + night_duration); + pc->night_timer_tid = timer->add_interval(timer->gettick() + day_duration + (map->night_flag ? night_duration : 0), pc->map_night_timer, 0, 0, day_duration + night_duration); } - - do_init_pc_groups(); - pc_sc_display_ers = ers_new(sizeof(struct sc_display_entry), "pc.c:pc_sc_display_ers", ERS_OPT_NONE); + pcg->init(); + + pc->sc_display_ers = ers_new(sizeof(struct sc_display_entry), "pc.c:sc_display_ers", ERS_OPT_FLEX_CHUNK); + pc->num_reg_ers = ers_new(sizeof(struct script_reg_num), "pc.c::num_reg_ers", ERS_OPT_CLEAN|ERS_OPT_FLEX_CHUNK); + pc->str_reg_ers = ers_new(sizeof(struct script_reg_str), "pc.c::str_reg_ers", ERS_OPT_CLEAN|ERS_OPT_FLEX_CHUNK); - return 0; + ers_chunk_size(pc->sc_display_ers, 150); + ers_chunk_size(pc->num_reg_ers, 300); + ers_chunk_size(pc->str_reg_ers, 50); } - /*===================================== -* Default Functions : pc.h +* Default Functions : pc.h * Generated by HerculesInterfaceMaker * created by Susu *-------------------------------------*/ void pc_defaults(void) { + const struct sg_data sg_info[MAX_PC_FEELHATE] = { + { SG_SUN_ANGER, SG_SUN_BLESS, SG_SUN_COMFORT, "PC_FEEL_SUN", "PC_HATE_MOB_SUN", is_day_of_sun }, + { SG_MOON_ANGER, SG_MOON_BLESS, SG_MOON_COMFORT, "PC_FEEL_MOON", "PC_HATE_MOB_MOON", is_day_of_moon }, + { SG_STAR_ANGER, SG_STAR_BLESS, SG_STAR_COMFORT, "PC_FEEL_STAR", "PC_HATE_MOB_STAR", is_day_of_star } + }; + unsigned int equip_pos[EQI_MAX]={EQP_ACC_L,EQP_ACC_R,EQP_SHOES,EQP_GARMENT,EQP_HEAD_LOW,EQP_HEAD_MID,EQP_HEAD_TOP,EQP_ARMOR,EQP_HAND_L,EQP_HAND_R,EQP_COSTUME_HEAD_TOP,EQP_COSTUME_HEAD_MID,EQP_COSTUME_HEAD_LOW,EQP_COSTUME_GARMENT,EQP_AMMO, EQP_SHADOW_ARMOR, EQP_SHADOW_WEAPON, EQP_SHADOW_SHIELD, EQP_SHADOW_SHOES, EQP_SHADOW_ACC_R, EQP_SHADOW_ACC_L }; + pc = &pc_s; /* vars */ - // timer for night.day - pc->day_timer_tid = day_timer_tid; - pc->night_timer_tid = night_timer_tid; - + pc->at_db = NULL; + pc->itemcd_db = NULL; + /* */ + pc->day_timer_tid = INVALID_TIMER; + pc->night_timer_tid = INVALID_TIMER; + /* respecting order */ + memset(pc->exp_table, 0, sizeof(pc->exp_table) + + sizeof(pc->max_level) + + sizeof(pc->statp) + + sizeof(pc->level_penalty) + + sizeof(pc->skill_tree) + + sizeof(pc->smith_fame_list) + + sizeof(pc->chemist_fame_list) + + sizeof(pc->taekwon_fame_list) + ); + /* */ + memcpy(pc->equip_pos, &equip_pos, sizeof(pc->equip_pos)); + /* */ + memcpy(pc->sg_info, sg_info, sizeof(pc->sg_info)); + /* */ + pc->sc_display_ers = NULL; + /* */ + pc->expiration_tid = INVALID_TIMER; + /* */ + pc->num_reg_ers = NULL; + pc->str_reg_ers = NULL; + /* */ + pc->reg_load = false; /* funcs */ - + pc->init = do_init_pc; + pc->final = do_final_pc; + + pc->get_dummy_sd = pc_get_dummy_sd; pc->class2idx = pc_class2idx; - pc->get_group_level = pc_get_group_level; - pc->can_give_items = pc_can_give_items; pc->can_use_command = pc_can_use_command; - + pc->set_group = pc_set_group; + pc->should_log_commands = pc_should_log_commands; + pc->setrestartvalue = pc_setrestartvalue; pc->makesavestatus = pc_makesavestatus; pc->respawn = pc_respawn; @@ -9998,6 +10903,7 @@ void pc_defaults(void) { pc->thisjobexp = pc_thisjobexp; pc->gets_status_point = pc_gets_status_point; pc->need_status_point = pc_need_status_point; + pc->maxparameterincrease = pc_maxparameterincrease; pc->statusup = pc_statusup; pc->statusup2 = pc_statusup2; pc->skillup = pc_skillup; @@ -10063,6 +10969,8 @@ void pc_defaults(void) { pc->setstand = pc_setstand; pc->candrop = pc_candrop; + pc->can_talk = pc_can_talk; + pc->can_attack = pc_can_attack; pc->jobid2mapid = pc_jobid2mapid; // Skotlex pc->mapid2jobid = pc_mapid2jobid; // Skotlex @@ -10079,8 +10987,6 @@ void pc_defaults(void) { pc->set_hate_mob = pc_set_hate_mob; pc->readdb = pc_readdb; - pc->do_init_pc = do_init_pc; - pc->do_final_pc = do_final_pc; pc->map_day_timer = map_day_timer; // by [yor] pc->map_night_timer = map_night_timer; // by [yor] // Rental System @@ -10103,7 +11009,56 @@ void pc_defaults(void) { pc->del_charm = pc_del_charm; pc->baselevelchanged = pc_baselevelchanged; -#if defined(RENEWAL_DROP) || defined(RENEWAL_EXP) pc->level_penalty_mod = pc_level_penalty_mod; -#endif + + pc->calc_skillpoint = pc_calc_skillpoint; + + pc->invincible_timer = pc_invincible_timer; + pc->spiritball_timer = pc_spiritball_timer; + pc->check_banding = pc_check_banding; + pc->inventory_rental_end = pc_inventory_rental_end; + pc->check_skilltree = pc_check_skilltree; + pc->bonus_autospell = pc_bonus_autospell; + pc->bonus_autospell_onskill = pc_bonus_autospell_onskill; + pc->bonus_addeff = pc_bonus_addeff; + pc->bonus_addeff_onskill = pc_bonus_addeff_onskill; + pc->bonus_item_drop = pc_bonus_item_drop; + pc->calcexp = pc_calcexp; + pc->respawn_timer = pc_respawn_timer; + pc->jobchange_killclone = jobchange_killclone; + pc->getstat = pc_getstat; + pc->setstat = pc_setstat; + pc->eventtimer = pc_eventtimer; + pc->daynight_timer_sub = pc_daynight_timer_sub; + pc->charm_timer = pc_charm_timer; + pc->readdb_levelpenalty = pc_readdb_levelpenalty; + pc->autosave = pc_autosave; + pc->follow_timer = pc_follow_timer; + pc->read_skill_tree = pc_read_skill_tree; + pc->isUseitem = pc_isUseitem; + pc->show_steal = pc_show_steal; + pc->checkcombo = pc_checkcombo; + pc->calcweapontype = pc_calcweapontype; + pc->removecombo = pc_removecombo; + + pc->bank_withdraw = pc_bank_withdraw; + pc->bank_deposit = pc_bank_deposit; + + pc->rental_expire = pc_rental_expire; + pc->scdata_received = pc_scdata_received; + + pc->bound_clear = pc_bound_clear; + + pc->expiration_timer = pc_expiration_timer; + pc->global_expiration_timer = pc_global_expiration_timer; + pc->expire_check = pc_expire_check; + + /** + * Autotrade persistency [Ind/Hercules <3] + **/ + pc->autotrade_load = pc_autotrade_load; + pc->autotrade_update = pc_autotrade_update; + pc->autotrade_start = pc_autotrade_start; + pc->autotrade_prepare = pc_autotrade_prepare; + pc->autotrade_populate = pc_autotrade_populate; } diff --git a/src/map/pc.h b/src/map/pc.h index 43d5d40c7..bec4522df 100644 --- a/src/map/pc.h +++ b/src/map/pc.h @@ -1,28 +1,36 @@ // Copyright (c) Hercules Dev Team, licensed under GNU GPL. // See the LICENSE file // Portions Copyright (c) Athena Dev Teams -#ifndef _PC_H_ -#define _PC_H_ -#include "../common/mmo.h" // JOB_*, MAX_FAME_LIST, struct fame_list, struct mmo_charstatus -#include "../common/ers.h" -#include "../common/timer.h" // INVALID_TIMER -#include "atcommand.h" // AtCommandType -#include "battle.h" // battle_config -#include "battleground.h" + +#ifndef MAP_PC_H +#define MAP_PC_H + +#include "../config/core.h" // AUTOLOOTITEM_SIZE, RENEWAL, SECURE_NPCTIMEOUT + +#include "battle.h" // battle +#include "battleground.h" // enum bg_queue_types #include "buyingstore.h" // struct s_buyingstore -#include "itemdb.h" // MAX_ITEMGROUP -#include "map.h" // RC_MAX -#include "script.h" // struct script_reg, struct script_regstr +#include "itemdb.h" // MAX_ITEMDELAYS +#include "log.h" // struct e_log_pick_type +#include "map.h" // RC_MAX, ELE_MAX +#include "pc_groups.h" // GroupSettings +#include "script.h" // struct reg_db #include "searchstore.h" // struct s_search_store_info -#include "status.h" // OPTION_*, struct weapon_atk -#include "unit.h" // unit_stop_attack(), unit_stop_walking() +#include "status.h" // enum sc_type, OPTION_* +#include "unit.h" // struct unit_data, struct view_data #include "vending.h" // struct s_vending -#include "mob.h" -#include "log.h" -#include "pc_groups.h" +#include "../common/cbasetypes.h" +#include "../common/ers.h" // struct eri +#include "../common/mmo.h" // JOB_*, MAX_FAME_LIST, struct fame_list, struct mmo_charstatus, NEW_CARTS + +/** + * Defines + **/ #define MAX_PC_BONUS 10 #define MAX_PC_SKILL_REQUIRE 5 #define MAX_PC_FEELHATE 3 +#define PVP_CALCRANK_INTERVAL 1000 // PVP calculation interval + //Equip indexes constants. (eg: sd->equip_index[EQI_AMMO] returns the index //where the arrows are equipped) enum equip_index { @@ -41,6 +49,12 @@ enum equip_index { EQI_COSTUME_LOW, EQI_COSTUME_GARMENT, EQI_AMMO, + EQI_SHADOW_ARMOR, + EQI_SHADOW_WEAPON, + EQI_SHADOW_SHIELD, + EQI_SHADOW_SHOES, + EQI_SHADOW_ACC_R, + EQI_SHADOW_ACC_L, EQI_MAX }; struct weapon_data { @@ -102,6 +116,12 @@ enum npc_timeout_type { NPCT_MENU = 1, NPCT_WAIT = 2, }; + +struct pc_combos { + struct script_code *bonus;/* the script of the combo */ + unsigned short id;/* this combo id */ +}; + struct map_session_data { struct block_list bl; struct unit_data ud; @@ -126,7 +146,6 @@ struct map_session_data { unsigned int abra_flag : 2; // Abracadabra bugfix by Aru unsigned int autocast : 1; // Autospell flag [Inkfish] unsigned int autotrade : 1; //By Fantik - unsigned int reg_dirty : 4; //By Skotlex (marks whether registry variables have been saved or not yet) unsigned int showdelay :1; unsigned int showexp :1; unsigned int showzeny :1; @@ -153,15 +172,22 @@ struct map_session_data { short pmap; // Previous map on Map Change unsigned short autoloot; unsigned short autolootid[AUTOLOOTITEM_SIZE]; // [Zephyrus] + unsigned short autoloottype; unsigned int autolooting : 1; //performance-saver, autolooting state for @alootid unsigned short autobonus; //flag to indicate if an autobonus is activated. [Inkfish] - struct guild *gmaster_flag; + unsigned int gmaster_flag : 1; unsigned int prevend : 1;//used to flag wheather you've spent 40sp to open the vending or not. unsigned int warping : 1;//states whether you're in the middle of a warp processing unsigned int permanent_speed : 1; // When 1, speed cannot be changed through status_calc_pc(). unsigned int dialog : 1; unsigned int prerefining : 1; unsigned int workinprogress : 3; // 1 = disable skill/item, 2 = disable npc interaction, 3 = disable both + unsigned int hold_recalc : 1; + unsigned int snovice_call_flag : 3; //Summon Angel (stage 1~3) + unsigned int hpmeter_visible : 1; + unsigned int itemcheck : 1; + unsigned int standalone : 1;/* [Ind/Hercules <3] */ + unsigned int loggingout : 1; } state; struct { unsigned char no_weapon_damage, no_magic_damage, no_misc_damage; @@ -177,12 +203,13 @@ struct map_session_data { } special_state; int login_id1, login_id2; unsigned short class_; //This is the internal job ID used by the map server to simplify comparisons/queries/etc. [Skotlex] - int group_id, group_pos, group_level; - unsigned int permissions;/* group permissions */ - bool group_log_command; + + /// Groups & permissions + int group_id; + GroupSettings *group; + unsigned int extra_temp_permissions; /* permissions from @addperm */ struct mmo_charstatus status; - struct registry save_reg; struct item_data* inventory_data[MAX_INVENTORY]; // direct pointers to itemdb entries (faster than doing item_id lookups) short equip_index[EQI_MAX]; unsigned int weight,max_weight; @@ -199,10 +226,10 @@ struct map_session_data { char npc_str[CHATBOX_SIZE]; // for passing npc input box text to script engine int npc_timer_id; //For player attached npc timers. [Skotlex] unsigned int chatID; - time_t idletime; - struct{ + int64 idletime; + struct { int npc_id; - unsigned int timeout; + int64 timeout; } progressbar; //Progress Bar [Inkfish] struct{ char name[NAME_LENGTH]; @@ -214,22 +241,21 @@ struct map_session_data { uint16 skill_id_old,skill_lv_old; uint16 skill_id_dance,skill_lv_dance; short cook_mastery; // range: [0,1999] [Inkfish] - unsigned char blockskill[MAX_SKILL]; + bool blockskill[MAX_SKILL]; int cloneskill_id, reproduceskill_id; int menuskill_id, menuskill_val, menuskill_val2; int invincible_timer; - unsigned int canlog_tick; - unsigned int canuseitem_tick; // [Skotlex] - unsigned int canusecashfood_tick; - unsigned int canequip_tick; // [Inkfish] - unsigned int cantalk_tick; - unsigned int canskill_tick; // used to prevent abuse from no-delay ACT files - unsigned int cansendmail_tick; // [Mail System Flood Protection] - unsigned int ks_floodprotect_tick; // [Kill Steal Protection] - unsigned int bloodylust_tick; // bloodylust player timer [out/in re full-heal protection] + int64 canlog_tick; + int64 canuseitem_tick; // [Skotlex] + int64 canusecashfood_tick; + int64 canequip_tick; // [Inkfish] + int64 cantalk_tick; + int64 canskill_tick; /// used to prevent abuse from no-delay ACT files + int64 cansendmail_tick; /// Mail System Flood Protection + int64 ks_floodprotect_tick; /// [Kill Steal Protection] struct { short nameid; - unsigned int tick; + int64 tick; } item_delay[MAX_ITEMDELAYS]; // [Paradox924X] short weapontype1,weapontype2; short disguise; // [Valaris] @@ -256,7 +282,6 @@ struct map_session_data { int expaddrace[RC_MAX]; int ignore_mdef[RC_MAX]; int ignore_def[RC_MAX]; - int itemgrouphealrate[MAX_ITEMGROUP]; short sp_gain_race[RC_MAX]; short sp_gain_race_attack[RC_MAX]; short hp_gain_race_attack[RC_MAX]; @@ -286,6 +311,10 @@ struct map_session_data { short flag, rate; unsigned char ele; } subele2[MAX_PC_BONUS]; + struct { + short value; + int rate, tick; + } def_set_race[RC_MAX], mdef_set_race[RC_MAX]; // zeroed structures end here // manually zeroed structures start here. struct s_autobonus autobonus[MAX_PC_BONUS], autobonus2[MAX_PC_BONUS], autobonus3[MAX_PC_BONUS]; //Auto script on attack, when attacked, on skill usage @@ -319,14 +348,13 @@ struct map_session_data { short add_heal_rate, add_heal2_rate; short sp_gain_value, hp_gain_value, magic_sp_gain_value, magic_hp_gain_value; short sp_vanish_rate; - short sp_vanish_per; + short sp_vanish_per, sp_vanish_trigger; unsigned short unbreakable; // chance to prevent ANY equipment breaking [celest] unsigned short unbreakable_equip; //100% break resistance on certain equipment unsigned short unstripable_equip; int fixcastrate,varcastrate; int add_fixcast,add_varcast; int ematk; // matk bonus from equipment - int eatk; // atk bonus from equipment } bonus; // zeroed vars end here. int castrate,delayrate,hprate,sprate,dsprate; @@ -345,10 +373,6 @@ struct map_session_data { short mission_mobid; //Stores the target mob_id for TK_MISSION int die_counter; //Total number of times you've died int devotion[5]; //Stores the account IDs of chars devoted to. - int reg_num; //Number of registries (type numeric) - int regstr_num; //Number of registries (type string) - struct script_reg *reg; - struct script_regstr *regstr; int trade_partner; struct { struct { @@ -421,12 +445,11 @@ struct map_session_data { bool changed; // if true, should sync with charserver on next mailbox request } mail; - //Quest log system [Kevin] [Inkfish] - int num_quests; - int avail_quests; - int quest_index[MAX_QUEST_DB]; - struct quest quest_log[MAX_QUEST_DB]; - bool save_quest; + // Quest log system + int num_quests; ///< Number of entries in quest_log + int avail_quests; ///< Number of Q_ACTIVE and Q_INACTIVE entries in quest log (index of the first Q_COMPLETE entry) + struct quest *quest_log; ///< Quest log entries (note: Q_COMPLETE quests follow the first <avail_quests>th enties + bool save_quest; ///< Whether the quest_log entries were modified and are waitin to be saved // temporary debug [flaviojs] const char* debug_file; @@ -434,7 +457,6 @@ struct map_session_data { const char* debug_func; unsigned int bg_id; - unsigned short user_font; /** * For the Secure NPC Timeout option (check config/Secure.h) [RR] @@ -452,17 +474,14 @@ struct map_session_data { * @info * - It is updated on every NPC iteration as mentioned above **/ - unsigned int npc_idle_tick; + int64 npc_idle_tick; /* */ enum npc_timeout_type npc_idle_type; #endif - struct { - struct script_code **bonus;/* the script */ - unsigned short *id;/* array of combo ids */ - unsigned char count; - } combos; - + struct pc_combos *combos; + unsigned char combo_count; + /** * Guarantees your friend request is legit (for bugreport:4629) **/ @@ -477,13 +496,13 @@ struct map_session_data { bool stealth; unsigned char fontcolor; unsigned int fontcolor_tid; - unsigned int hchsysch_tick; + int64 hchsysch_tick; /* [Ind/Hercules] */ struct sc_display_entry **sc_display; unsigned char sc_display_count; - unsigned short *instance; + short *instance; unsigned short instances; /* Possible Thanks to Yommy~! */ @@ -498,7 +517,31 @@ struct map_session_data { unsigned int queues_count; /* Made Possible Thanks to Yommy~! */ - unsigned int cryptKey; + unsigned int cryptKey; ///< Packet obfuscation key to be used for the next received packet + unsigned short (*parse_cmd_func)(int fd, struct map_session_data *sd); ///< parse_cmd_func used by this player + + unsigned char delayed_damage;//ref. counter bugreport:7307 [Ind/Hercules] + + /* HPM Custom Struct */ + struct HPluginData **hdata; + unsigned int hdatac; + + /* expiration_time timer id */ + int expiration_tid; + time_t expiration_time; + + /* */ + struct { + unsigned int second,third; + } sktree; + + /** + * Account/Char variables & array control of those variables + **/ + struct reg_db regs; + unsigned char vars_received;/* char loading is only complete when you get it all. */ + bool vars_ok; + bool vars_dirty; // temporary debugging of bug #3504 const char* delunit_prevfile; @@ -506,86 +549,14 @@ struct map_session_data { }; -struct eri *pc_sc_display_ers; - -//Update this max as necessary. 55 is the value needed for Super Baby currently -//Raised to 84 since Expanded Super Novice needs it. -#define MAX_SKILL_TREE 84 -//Total number of classes (for data storage) -#define CLASS_COUNT (JOB_MAX - JOB_NOVICE_HIGH + JOB_MAX_BASIC) - -enum weapon_type { - W_FIST, //Bare hands - W_DAGGER, //1 - W_1HSWORD, //2 - W_2HSWORD, //3 - W_1HSPEAR, //4 - W_2HSPEAR, //5 - W_1HAXE, //6 - W_2HAXE, //7 - W_MACE, //8 - W_2HMACE, //9 (unused) - W_STAFF, //10 - W_BOW, //11 - W_KNUCKLE, //12 - W_MUSICAL, //13 - W_WHIP, //14 - W_BOOK, //15 - W_KATAR, //16 - W_REVOLVER, //17 - W_RIFLE, //18 - W_GATLING, //19 - W_SHOTGUN, //20 - W_GRENADE, //21 - W_HUUMA, //22 - W_2HSTAFF, //23 - MAX_WEAPON_TYPE, - // dual-wield constants - W_DOUBLE_DD, // 2 daggers - W_DOUBLE_SS, // 2 swords - W_DOUBLE_AA, // 2 axes - W_DOUBLE_DS, // dagger + sword - W_DOUBLE_DA, // dagger + axe - W_DOUBLE_SA, // sword + axe -}; - -enum ammo_type { - A_ARROW = 1, - A_DAGGER, //2 - A_BULLET, //3 - A_SHELL, //4 - A_GRENADE, //5 - A_SHURIKEN, //6 - A_KUNAI, //7 - A_CANNONBALL, //8 - A_THROWWEAPON //9 -}; - -//Equip position constants -enum equip_pos { - EQP_HEAD_LOW = 0x0001, - EQP_HEAD_MID = 0x0200, //512 - EQP_HEAD_TOP = 0x0100, //256 - EQP_HAND_R = 0x0002, //2 - EQP_HAND_L = 0x0020, //32 - EQP_ARMOR = 0x0010, //16 - EQP_SHOES = 0x0040, //64 - EQP_GARMENT = 0x0004, //4 - EQP_ACC_L = 0x0008, //8 - EQP_ACC_R = 0x0080, //128 - EQP_COSTUME_HEAD_TOP = 0x0400, //1024 - EQP_COSTUME_HEAD_MID = 0x0800, //2048 - EQP_COSTUME_HEAD_LOW = 0x1000, //4096 - EQP_COSTUME_GARMENT = 0x2000, //8192 - EQP_AMMO = 0x8000, //32768 -}; - #define EQP_WEAPON EQP_HAND_R #define EQP_SHIELD EQP_HAND_L #define EQP_ARMS (EQP_HAND_R|EQP_HAND_L) #define EQP_HELM (EQP_HEAD_LOW|EQP_HEAD_MID|EQP_HEAD_TOP) #define EQP_ACC (EQP_ACC_L|EQP_ACC_R) #define EQP_COSTUME (EQP_COSTUME_HEAD_TOP|EQP_COSTUME_HEAD_MID|EQP_COSTUME_HEAD_LOW|EQP_COSTUME_GARMENT) +#define EQP_SHADOW_ACC (EQP_SHADOW_ACC_R|EQP_SHADOW_ACC_L) +#define EQP_SHADOW_ARMS (EQP_SHADOW_WEAPON|EQP_SHADOW_SHIELD) /// Equip positions that use a visible sprite #if PACKETVER < 20110111 @@ -598,7 +569,7 @@ enum equip_pos { #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(last_tick, (sd)->idletime) >= battle_config.idle_no_share ) +#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_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 ) @@ -620,9 +591,9 @@ enum equip_pos { #define pc_isfalcon(sd) ( (sd)->sc.option&OPTION_FALCON ) #define pc_isriding(sd) ( (sd)->sc.option&OPTION_RIDING ) #define pc_isinvisible(sd) ( (sd)->sc.option&OPTION_INVISIBLE ) -#define pc_is50overweight(sd) ( (sd)->weight*100 >= (sd)->max_weight*battle_config.natural_heal_weight_rate ) +#define pc_is50overweight(sd) ( (sd)->weight*100 >= (sd)->max_weight*battle->bc->natural_heal_weight_rate ) #define pc_is90overweight(sd) ( (sd)->weight*10 >= (sd)->max_weight*9 ) -#define pc_maxparameter(sd) ( ((((sd)->class_&MAPID_UPPERMASK) == MAPID_KAGEROUOBORO) || (sd)->class_&JOBL_THIRD ? ((sd)->class_&JOBL_BABY ? battle_config.max_baby_third_parameter : battle_config.max_third_parameter) : ((sd)->class_&JOBL_BABY ? battle_config.max_baby_parameter : battle_config.max_parameter)) ) +#define pc_maxparameter(sd) ( (((sd)->class_&MAPID_UPPERMASK) == MAPID_KAGEROUOBORO || ((sd)->class_&MAPID_UPPERMASK) == MAPID_REBELLION || ((sd)->class_&MAPID_THIRDMASK) == MAPID_SUPER_NOVICE_E) ? battle->bc->max_extended_parameter : (sd)->class_&JOBL_THIRD ? ((sd)->class_&JOBL_BABY ? battle->bc->max_baby_third_parameter : battle->bc->max_third_parameter) : ((sd)->class_&JOBL_BABY ? battle->bc->max_baby_parameter : battle->bc->max_parameter) ) /** * Ranger **/ @@ -633,8 +604,8 @@ enum equip_pos { // Rune Knight Dragon #define pc_isridingdragon(sd) ( (sd)->sc.option&OPTION_DRAGON ) -#define pc_stop_walking(sd, type) unit_stop_walking(&(sd)->bl, type) -#define pc_stop_attack(sd) unit_stop_attack(&(sd)->bl) +#define pc_stop_walking(sd, type) (unit->stop_walking(&(sd)->bl, (type))) +#define pc_stop_attack(sd) (unit->stop_attack(&(sd)->bl)) //Weapon check considering dual wielding. #define pc_check_weapontype(sd, type) ((type)&((sd)->status.weapon < MAX_WEAPON_TYPE? \ @@ -648,19 +619,20 @@ enum equip_pos { || ( (class_) >= JOB_RUNE_KNIGHT && (class_) <= JOB_MECHANIC_T2 ) \ || ( (class_) >= JOB_BABY_RUNE && (class_) <= JOB_BABY_MECHANIC2 ) \ || ( (class_) >= JOB_SUPER_NOVICE_E && (class_) <= JOB_SUPER_BABY_E ) \ -|| ( (class_) >= JOB_KAGEROU && (class_) < JOB_MAX ) \ +|| ( (class_) >= JOB_KAGEROU && (class_) <= JOB_OBORO ) \ +|| ( (class_) >= JOB_REBELLION && (class_) < JOB_MAX ) \ ) -#define pcdb_checkid(class_) pcdb_checkid_sub((unsigned int)class_) +#define pcdb_checkid(class_) pcdb_checkid_sub((unsigned int)(class_)) // clientside display macros (values to the left/right of the "+") #ifdef RENEWAL #define pc_leftside_atk(sd) ((sd)->battle_status.batk) - #define pc_rightside_atk(sd) ((sd)->battle_status.rhw.atk + (sd)->battle_status.lhw.atk + (sd)->battle_status.rhw.atk2 + (sd)->battle_status.lhw.atk2 + (sd)->bonus.eatk ) + #define pc_rightside_atk(sd) ((sd)->battle_status.rhw.atk + (sd)->battle_status.lhw.atk + (sd)->battle_status.rhw.atk2 + (sd)->battle_status.lhw.atk2 + (sd)->battle_status.equip_atk ) #define pc_leftside_def(sd) ((sd)->battle_status.def2) #define pc_rightside_def(sd) ((sd)->battle_status.def) #define pc_leftside_mdef(sd) ((sd)->battle_status.mdef2) #define pc_rightside_mdef(sd) ((sd)->battle_status.mdef) -#define pc_leftside_matk(sd) (status_base_matk(status_get_status_data(&(sd)->bl), (sd)->status.base_level)) +#define pc_leftside_matk(sd) (status->base_matk(status->get_status_data(&(sd)->bl), (sd)->status.base_level)) #define pc_rightside_matk(sd) ((sd)->battle_status.rhw.matk+(sd)->battle_status.lhw.matk+(sd)->bonus.ematk) #else #define pc_leftside_atk(sd) ((sd)->battle_status.batk + (sd)->battle_status.rhw.atk + (sd)->battle_status.lhw.atk) @@ -685,24 +657,27 @@ enum equip_pos { #define pc_get_group_id(sd) ( (sd)->group_id ) -#define pc_has_permission(sd, permission) ( ((sd)->permissions&permission) != 0 ) -#define pc_should_log_commands(sd) ( (sd)->group_log_command != false ) - #define pc_checkoverhp(sd) ((sd)->battle_status.hp == (sd)->battle_status.max_hp) #define pc_checkoversp(sd) ((sd)->battle_status.sp == (sd)->battle_status.max_sp) -#define pc_readglobalreg(sd,reg) pc->readregistry(sd,reg,3) -#define pc_setglobalreg(sd,reg,val) pc->setregistry(sd,reg,val,3) -#define pc_readglobalreg_str(sd,reg) pc->readregistry_str(sd,reg,3) -#define pc_setglobalreg_str(sd,reg,val) pc->setregistry_str(sd,reg,val,3) -#define pc_readaccountreg(sd,reg) pc->readregistry(sd,reg,2) -#define pc_setaccountreg(sd,reg,val) pc->setregistry(sd,reg,val,2) -#define pc_readaccountregstr(sd,reg) pc->readregistry_str(sd,reg,2) -#define pc_setaccountregstr(sd,reg,val) pc->setregistry_str(sd,reg,val,2) -#define pc_readaccountreg2(sd,reg) pc->readregistry(sd,reg,1) -#define pc_setaccountreg2(sd,reg,val) pc->setregistry(sd,reg,val,1) -#define pc_readaccountreg2str(sd,reg) pc->readregistry_str(sd,reg,1) -#define pc_setaccountreg2str(sd,reg,val) pc->setregistry_str(sd,reg,val,1) +#define pc_readglobalreg(sd,reg) (pc->readregistry((sd),(reg))) +#define pc_setglobalreg(sd,reg,val) (pc->setregistry((sd),(reg),(val))) +#define pc_readglobalreg_str(sd,reg) (pc->readregistry_str((sd),(reg))) +#define pc_setglobalreg_str(sd,reg,val) (pc->setregistry_str((sd),(reg),(val))) +#define pc_readaccountreg(sd,reg) (pc->readregistry((sd),(reg))) +#define pc_setaccountreg(sd,reg,val) (pc->setregistry((sd),(reg),(val))) +#define pc_readaccountregstr(sd,reg) (pc->readregistry_str((sd),(reg))) +#define pc_setaccountregstr(sd,reg,val) (pc->setregistry_str((sd),(reg),(val))) +#define pc_readaccountreg2(sd,reg) (pc->readregistry((sd),(reg))) +#define pc_setaccountreg2(sd,reg,val) (pc->setregistry((sd),(reg),(val))) +#define pc_readaccountreg2str(sd,reg) (pc->readregistry_str((sd),(reg))) +#define pc_setaccountreg2str(sd,reg,val) (pc->setregistry_str((sd),(reg),(val))) + +/* pc_groups easy access */ +#define pc_get_group_level(sd) ( (sd)->group->level ) +#define pc_has_permission(sd,permission) ( ((sd)->extra_temp_permissions&(permission)) != 0 || ((sd)->group->e_permissions&(permission)) != 0 ) +#define pc_can_give_items(sd) ( pc_has_permission((sd),PC_PERM_TRADE) ) +#define pc_can_give_bound_items(sd) ( pc_has_permission((sd),PC_PERM_TRADE_BOUND) ) struct skill_tree_entry { short id; @@ -716,54 +691,103 @@ struct skill_tree_entry { } need[MAX_PC_SKILL_REQUIRE]; }; // Celest -extern struct skill_tree_entry skill_tree[CLASS_COUNT][MAX_SKILL_TREE]; - struct sg_data { short anger_id; short bless_id; short comfort_id; char feel_var[NAME_LENGTH]; char hate_var[NAME_LENGTH]; - int (*day_func)(void); + bool (*day_func)(void); }; -extern const struct sg_data sg_info[MAX_PC_FEELHATE]; +enum { ADDITEM_EXIST , ADDITEM_NEW , ADDITEM_OVERAMOUNT }; -extern struct fame_list smith_fame_list[MAX_FAME_LIST]; -extern struct fame_list chemist_fame_list[MAX_FAME_LIST]; -extern struct fame_list taekwon_fame_list[MAX_FAME_LIST]; +/** + * Item Cool Down Delay Saving + * Struct item_cd is not a member of struct map_session_data + * to keep cooldowns in memory between player log-ins. + * All cooldowns are reset when server is restarted. + **/ +struct item_cd { + int64 tick[MAX_ITEMDELAYS];//tick + short nameid[MAX_ITEMDELAYS];//skill id +}; -enum {ADDITEM_EXIST,ADDITEM_NEW,ADDITEM_OVERAMOUNT}; +enum e_pc_autotrade_update_action { + PAUC_START, + PAUC_REFRESH, + PAUC_REMOVE, +}; + +/** + * Used to temporarily remember vending data + **/ +struct autotrade_vending { + struct item list[MAX_VENDING]; + struct s_vending vending[MAX_VENDING]; + unsigned char vend_num; +}; -#if defined(RENEWAL_DROP) || defined(RENEWAL_EXP) -#endif /*===================================== -* Interface : pc.h +* Interface : pc.h * Generated by HerculesInterfaceMaker * created by Susu *-------------------------------------*/ struct pc_interface { - /* vars */ - // timer for night.day + /* */ + DBMap *at_db;/* char id -> struct autotrade_vending */ + /* */ + DBMap* itemcd_db; + /* */ int day_timer_tid; int night_timer_tid; + /* */ + unsigned int exp_table[CLASS_COUNT][2][MAX_LEVEL]; + unsigned int max_level[CLASS_COUNT][2]; + unsigned int statp[MAX_LEVEL+1]; + unsigned int level_penalty[3][RC_MAX][MAX_LEVEL*2+1]; + unsigned int equip_pos[EQI_MAX]; + /* */ + struct skill_tree_entry skill_tree[CLASS_COUNT][MAX_SKILL_TREE]; + struct fame_list smith_fame_list[MAX_FAME_LIST]; + struct fame_list chemist_fame_list[MAX_FAME_LIST]; + struct fame_list taekwon_fame_list[MAX_FAME_LIST]; + struct sg_data sg_info[MAX_PC_FEELHATE]; + /* */ + struct eri *sc_display_ers; + /* global expiration timer id */ + int expiration_tid; + /** + * ERS for the bulk of pc vars + **/ + struct eri *num_reg_ers; + struct eri *str_reg_ers; + /* */ + bool reg_load; /* funcs */ + void (*init) (bool minimal); + void (*final) (void); + struct map_session_data* (*get_dummy_sd) (void); int (*class2idx) (int class_); - int (*get_group_level) (struct map_session_data *sd); - int (*getrefinebonus) (int lv,int type); + //int (*getrefinebonus) (int lv,int type); FIXME: This function does not exist, nor it is ever called bool (*can_give_items) (struct map_session_data *sd); - + bool (*can_give_bound_items) (struct map_session_data *sd); + bool (*can_talk) (struct map_session_data *sd); + bool (*can_attack) ( struct map_session_data *sd, int target_id ); + bool (*can_use_command) (struct map_session_data *sd, const char *command); - + int (*set_group) (struct map_session_data *sd, int group_id); + bool (*should_log_commands) (struct map_session_data *sd); + int (*setrestartvalue) (struct map_session_data *sd,int type); - int (*makesavestatus) (struct map_session_data *); + int (*makesavestatus) (struct map_session_data *sd); void (*respawn) (struct map_session_data* sd, clr_type clrtype); - int (*setnewpc) (struct map_session_data*,int,int,int,unsigned int,int,int); + int (*setnewpc) (struct map_session_data *sd, int account_id, int char_id, int login_id1, unsigned int client_tick, int sex, int fd); bool (*authok) (struct map_session_data *sd, int login_id2, time_t expiration_time, int group_id, struct mmo_charstatus *st, bool changing_mapservers); - void (*authfail) (struct map_session_data *); + void (*authfail) (struct map_session_data *sd); int (*reg_received) (struct map_session_data *sd); int (*isequip) (struct map_session_data *sd,int n); @@ -779,18 +803,19 @@ struct pc_interface { int (*calc_skilltree_normalize_job) (struct map_session_data *sd); int (*clean_skilltree) (struct map_session_data *sd); - int (*setpos) (struct map_session_data* sd, unsigned short mapindex, int x, int y, clr_type clrtype); - int (*setsavepoint) (struct map_session_data*,short,int,int); + int (*setpos) (struct map_session_data* sd, unsigned short map_index, int x, int y, clr_type clrtype); + int (*setsavepoint) (struct map_session_data *sd, short map_index, int x, int y); int (*randomwarp) (struct map_session_data *sd,clr_type type); int (*memo) (struct map_session_data* sd, int pos); - int (*checkadditem) (struct map_session_data*,int,int); - int (*inventoryblank) (struct map_session_data*); + int (*checkadditem) (struct map_session_data *sd,int nameid,int amount); + int (*inventoryblank) (struct map_session_data *sd); int (*search_inventory) (struct map_session_data *sd,int item_id); - int (*payzeny) (struct map_session_data*,int, enum e_log_pick_type type, struct map_session_data*); - int (*additem) (struct map_session_data*,struct item*,int,e_log_pick_type); - int (*getzeny) (struct map_session_data*,int, enum e_log_pick_type, struct map_session_data*); - int (*delitem) (struct map_session_data*,int,int,int,short,e_log_pick_type); + int (*payzeny) (struct map_session_data *sd,int zeny, enum e_log_pick_type type, struct map_session_data *tsd); + int (*additem) (struct map_session_data *sd,struct item *item_data,int amount,e_log_pick_type log_type); + int (*getzeny) (struct map_session_data *sd,int zeny, enum e_log_pick_type type, struct map_session_data *tsd); + int (*delitem) (struct map_session_data *sd,int n,int amount,int type, short reason, e_log_pick_type log_type); + // Special Shop System int (*paycash) (struct map_session_data *sd, int price, int points); int (*getcash) (struct map_session_data *sd, int cash, int points); @@ -801,8 +826,8 @@ struct pc_interface { int (*getitemfromcart) (struct map_session_data *sd,int idx,int amount); int (*cartitem_amount) (struct map_session_data *sd,int idx,int amount); - int (*takeitem) (struct map_session_data*,struct flooritem_data*); - int (*dropitem) (struct map_session_data*,int,int); + int (*takeitem) (struct map_session_data *sd,struct flooritem_data *fitem); + int (*dropitem) (struct map_session_data *sd,int n,int amount); bool (*isequipped) (struct map_session_data *sd, int nameid); bool (*can_Adopt) (struct map_session_data *p1_sd, struct map_session_data *p2_sd, struct map_session_data *b_sd); @@ -810,53 +835,54 @@ struct pc_interface { int (*updateweightstatus) (struct map_session_data *sd); - int (*addautobonus) (struct s_autobonus *bonus,char max,const char *script,short rate,unsigned int dur,short atk_type,const char *o_script,unsigned short pos,bool onskill); + int (*addautobonus) (struct s_autobonus *bonus,char max,const char *bonus_script,short rate,unsigned int dur,short atk_type,const char *o_script,unsigned short pos,bool onskill); int (*exeautobonus) (struct map_session_data* sd,struct s_autobonus *bonus); - int (*endautobonus) (int tid, unsigned int tick, int id, intptr_t data); + int (*endautobonus) (int tid, int64 tick, int id, intptr_t data); int (*delautobonus) (struct map_session_data* sd,struct s_autobonus *bonus,char max,bool restore); - int (*bonus) (struct map_session_data*,int,int); - int (*bonus2) (struct map_session_data *sd,int,int,int); - int (*bonus3) (struct map_session_data *sd,int,int,int,int); - int (*bonus4) (struct map_session_data *sd,int,int,int,int,int); - int (*bonus5) (struct map_session_data *sd,int,int,int,int,int,int); - int (*skill) (struct map_session_data* sd, int id, int level, int flag); + int (*bonus) (struct map_session_data *sd,int type,int val); + int (*bonus2) (struct map_session_data *sd,int type,int type2,int val); + int (*bonus3) (struct map_session_data *sd,int type,int type2,int type3,int val); + int (*bonus4) (struct map_session_data *sd,int type,int type2,int type3,int type4,int val); + int (*bonus5) (struct map_session_data *sd,int type,int type2,int type3,int type4,int type5,int val); + int (*skill) (struct map_session_data *sd, int id, int level, int flag); int (*insert_card) (struct map_session_data *sd,int idx_card,int idx_equip); int (*steal_item) (struct map_session_data *sd,struct block_list *bl, uint16 skill_lv); int (*steal_coin) (struct map_session_data *sd,struct block_list *bl); - int (*modifybuyvalue) (struct map_session_data*,int); - int (*modifysellvalue) (struct map_session_data*,int); + int (*modifybuyvalue) (struct map_session_data *sd,int orig_value); + int (*modifysellvalue) (struct map_session_data *sd,int orig_value); - int (*follow) (struct map_session_data*, int); // [MouseJstr] - int (*stop_following) (struct map_session_data*); + int (*follow) (struct map_session_data *sd, int target_id); // [MouseJstr] + int (*stop_following) (struct map_session_data *sd); unsigned int (*maxbaselv) (struct map_session_data *sd); unsigned int (*maxjoblv) (struct map_session_data *sd); int (*checkbaselevelup) (struct map_session_data *sd); int (*checkjoblevelup) (struct map_session_data *sd); - int (*gainexp) (struct map_session_data*,struct block_list*,unsigned int,unsigned int, bool); - unsigned int (*nextbaseexp) (struct map_session_data *); - unsigned int (*thisbaseexp) (struct map_session_data *); - unsigned int (*nextjobexp) (struct map_session_data *); - unsigned int (*thisjobexp) (struct map_session_data *); - int (*gets_status_point) (int); - int (*need_status_point) (struct map_session_data *,int,int); - int (*statusup) (struct map_session_data*,int); - int (*statusup2) (struct map_session_data*,int,int); - int (*skillup) (struct map_session_data*,uint16 skill_id); - int (*allskillup) (struct map_session_data*); - int (*resetlvl) (struct map_session_data*,int type); - int (*resetstate) (struct map_session_data*); - int (*resetskill) (struct map_session_data*, int); - int (*resetfeel) (struct map_session_data*); - int (*resethate) (struct map_session_data*); - int (*equipitem) (struct map_session_data*,int,int); - int (*unequipitem) (struct map_session_data*,int,int); - int (*checkitem) (struct map_session_data*); - int (*useitem) (struct map_session_data*,int); + bool (*gainexp) (struct map_session_data *sd, struct block_list *src, unsigned int base_exp, unsigned int job_exp, bool is_quest); + unsigned int (*nextbaseexp) (struct map_session_data *sd); + unsigned int (*thisbaseexp) (struct map_session_data *sd); + unsigned int (*nextjobexp) (struct map_session_data *sd); + unsigned int (*thisjobexp) (struct map_session_data *sd); + int (*gets_status_point) (int level); + int (*need_status_point) (struct map_session_data *sd,int type,int val); + int (*maxparameterincrease) (struct map_session_data* sd, int type); + bool (*statusup) (struct map_session_data *sd, int type, int increase); + int (*statusup2) (struct map_session_data *sd,int type,int val); + int (*skillup) (struct map_session_data *sd,uint16 skill_id); + int (*allskillup) (struct map_session_data *sd); + int (*resetlvl) (struct map_session_data *sd,int type); + int (*resetstate) (struct map_session_data *sd); + int (*resetskill) (struct map_session_data *sd, int flag); + int (*resetfeel) (struct map_session_data *sd); + int (*resethate) (struct map_session_data *sd); + int (*equipitem) (struct map_session_data *sd,int n,int req_pos); + int (*unequipitem) (struct map_session_data *sd,int n,int flag); + int (*checkitem) (struct map_session_data *sd); + int (*useitem) (struct map_session_data *sd,int n); int (*skillatk_bonus) (struct map_session_data *sd, uint16 skill_id); int (*skillheal_bonus) (struct map_session_data *sd, uint16 skill_id); @@ -867,26 +893,26 @@ struct pc_interface { void (*revive) (struct map_session_data *sd,unsigned int hp, unsigned int sp); void (*heal) (struct map_session_data *sd,unsigned int hp,unsigned int sp, int type); int (*itemheal) (struct map_session_data *sd,int itemid, int hp,int sp); - int (*percentheal) (struct map_session_data *sd,int,int); - int (*jobchange) (struct map_session_data *,int, int); - int (*setoption) (struct map_session_data *,int); + int (*percentheal) (struct map_session_data *sd,int hp,int sp); + int (*jobchange) (struct map_session_data *sd,int job, int upper); + int (*setoption) (struct map_session_data *sd,int type); int (*setcart) (struct map_session_data* sd, int type); int (*setfalcon) (struct map_session_data* sd, int flag); int (*setriding) (struct map_session_data* sd, int flag); - int (*setmadogear) (struct map_session_data* sd, int flag); - int (*changelook) (struct map_session_data *,int,int); + void (*setmadogear) (struct map_session_data* sd, int flag); + int (*changelook) (struct map_session_data *sd,int type,int val); int (*equiplookall) (struct map_session_data *sd); - int (*readparam) (struct map_session_data*,int); - int (*setparam) (struct map_session_data*,int,int); - int (*readreg) (struct map_session_data*,int); - int (*setreg) (struct map_session_data*,int,int); - char * (*readregstr) (struct map_session_data *sd,int reg); - int (*setregstr) (struct map_session_data *sd,int reg,const char *str); - int (*readregistry) (struct map_session_data*,const char*,int); - int (*setregistry) (struct map_session_data*,const char*,int,int); - char * (*readregistry_str) (struct map_session_data*,const char*,int); - int (*setregistry_str) (struct map_session_data*,const char*,const char*,int); + int (*readparam) (struct map_session_data *sd,int type); + int (*setparam) (struct map_session_data *sd,int type,int val); + int (*readreg) (struct map_session_data *sd, int64 reg); + void (*setreg) (struct map_session_data *sd, int64 reg,int val); + char * (*readregstr) (struct map_session_data *sd, int64 reg); + void (*setregstr) (struct map_session_data *sd, int64 reg, const char *str); + int (*readregistry) (struct map_session_data *sd, int64 reg); + int (*setregistry) (struct map_session_data *sd, int64 reg, int val); + char * (*readregistry_str) (struct map_session_data *sd, int64 reg); + int (*setregistry_str) (struct map_session_data *sd, int64 reg, const char *val); int (*addeventtimer) (struct map_session_data *sd,int tick,const char *name); int (*deleventtimer) (struct map_session_data *sd,const char *name); @@ -894,7 +920,7 @@ struct pc_interface { int (*addeventtimercount) (struct map_session_data *sd,const char *name,int tick); int (*calc_pvprank) (struct map_session_data *sd); - int (*calc_pvprank_timer) (int tid, unsigned int tick, int id, intptr_t data); + int (*calc_pvprank_timer) (int tid, int64 tick, int id, intptr_t data); int (*ismarried) (struct map_session_data *sd); int (*marriage) (struct map_session_data *sd,struct map_session_data *dstsd); @@ -918,17 +944,15 @@ struct pc_interface { void (*setinvincibletimer) (struct map_session_data* sd, int val); void (*delinvincibletimer) (struct map_session_data* sd); - int (*addspiritball) (struct map_session_data *sd,int,int); - int (*delspiritball) (struct map_session_data *sd,int,int); + int (*addspiritball) (struct map_session_data *sd,int interval,int max); + int (*delspiritball) (struct map_session_data *sd,int count,int type); void (*addfame) (struct map_session_data *sd,int count); unsigned char (*famerank) (int char_id, int job); int (*set_hate_mob) (struct map_session_data *sd, int pos, struct block_list *bl); int (*readdb) (void); - int (*do_init_pc) (void); - void (*do_final_pc) (void); - int (*map_day_timer) (int tid, unsigned int tick, int id, intptr_t data); // by [yor] - int (*map_night_timer) (int tid, unsigned int tick, int id, intptr_t data); // by [yor] + int (*map_day_timer) (int tid, int64 tick, int id, intptr_t data); // by [yor] + int (*map_night_timer) (int tid, int64 tick, int id, intptr_t data); // by [yor] // Rental System void (*inventory_rentals) (struct map_session_data *sd); int (*inventory_rental_clear) (struct map_session_data *sd); @@ -949,13 +973,61 @@ struct pc_interface { int (*del_charm) (struct map_session_data *sd,int count,int type); void (*baselevelchanged) (struct map_session_data *sd); -#if defined(RENEWAL_DROP) || defined(RENEWAL_EXP) - int (*level_penalty_mod) (struct map_session_data *sd, struct mob_data * md, int type); -#endif -} pc_s; + int (*level_penalty_mod) (int diff, unsigned char race, unsigned short mode, int type); + int (*calc_skillpoint) (struct map_session_data* sd); + + int (*invincible_timer) (int tid, int64 tick, int id, intptr_t data); + int (*spiritball_timer) (int tid, int64 tick, int id, intptr_t data); + int (*check_banding) ( struct block_list *bl, va_list ap ); + int (*inventory_rental_end) (int tid, int64 tick, int id, intptr_t data); + void (*check_skilltree) (struct map_session_data *sd, int skill_id); + int (*bonus_autospell) (struct s_autospell *spell, int max, short id, short lv, short rate, short flag, short card_id); + int (*bonus_autospell_onskill) (struct s_autospell *spell, int max, short src_skill, short id, short lv, short rate, short card_id); + int (*bonus_addeff) (struct s_addeffect* effect, int max, enum sc_type id, short rate, short arrow_rate, unsigned char flag); + int (*bonus_addeff_onskill) (struct s_addeffectonskill* effect, int max, enum sc_type id, short rate, short skill_id, unsigned char target); + int (*bonus_item_drop) (struct s_add_drop *drop, const short max, short id, short group, int race, int rate); + void (*calcexp) (struct map_session_data *sd, unsigned int *base_exp, unsigned int *job_exp, struct block_list *src); + int (*respawn_timer) (int tid, int64 tick, int id, intptr_t data); + int (*jobchange_killclone) (struct block_list *bl, va_list ap); + int (*getstat) (struct map_session_data* sd, int type); + int (*setstat) (struct map_session_data* sd, int type, int val); + int (*eventtimer) (int tid, int64 tick, int id, intptr_t data); + int (*daynight_timer_sub) (struct map_session_data *sd,va_list ap); + int (*charm_timer) (int tid, int64 tick, int id, intptr_t data); + bool (*readdb_levelpenalty) (char* fields[], int columns, int current); + int (*autosave) (int tid, int64 tick, int id, intptr_t data); + int (*follow_timer) (int tid, int64 tick, int id, intptr_t data); + void (*read_skill_tree) (void); + int (*isUseitem) (struct map_session_data *sd,int n); + int (*show_steal) (struct block_list *bl,va_list ap); + int (*checkcombo) (struct map_session_data *sd, struct item_data *data ); + int (*calcweapontype) (struct map_session_data *sd); + int (*removecombo) (struct map_session_data *sd, struct item_data *data ); + + void (*bank_deposit) (struct map_session_data *sd, int money); + void (*bank_withdraw) (struct map_session_data *sd, int money); + + void (*rental_expire) (struct map_session_data *sd, int i); + void (*scdata_received) (struct map_session_data *sd); + + void (*bound_clear) (struct map_session_data *sd, enum e_item_bound_type type); + + int (*expiration_timer) (int tid, int64 tick, int id, intptr_t data); + int (*global_expiration_timer) (int tid, int64 tick, int id, intptr_t data); + void (*expire_check) (struct map_session_data *sd); + + /** + * Autotrade persistency [Ind/Hercules <3] + **/ + void (*autotrade_load) (void); + void (*autotrade_update) (struct map_session_data *sd, enum e_pc_autotrade_update_action action); + void (*autotrade_start) (struct map_session_data *sd); + void (*autotrade_prepare) (struct map_session_data *sd); + void (*autotrade_populate) (struct map_session_data *sd); +}; struct pc_interface *pc; void pc_defaults(void); -#endif /* _PC_H_ */ +#endif /* MAP_PC_H */ diff --git a/src/map/pc_groups.c b/src/map/pc_groups.c index f1f69f7cb..e577c642f 100644 --- a/src/map/pc_groups.c +++ b/src/map/pc_groups.c @@ -2,48 +2,34 @@ // See the LICENSE file // Portions Copyright (c) Athena Dev Teams +#define HERCULES_CORE + +#include "pc_groups.h" + +#include "atcommand.h" // atcommand->exists(), atcommand->load_groups() +#include "clif.h" // clif->GM_kick() +#include "map.h" // mapiterator +#include "pc.h" // pc->set_group() +#include "../common/cbasetypes.h" #include "../common/conf.h" #include "../common/db.h" #include "../common/malloc.h" #include "../common/nullpo.h" #include "../common/showmsg.h" #include "../common/strlib.h" // strcmp -#include "../common/socket.h" -#include "atcommand.h" // AtCommandType -#include "pc_groups.h" -#include "pc.h" // e_pc_permission - -typedef struct GroupSettings GroupSettings; - -// Cached config settings/pointers for quick lookup -struct GroupSettings { - unsigned int id; // groups.[].id - int level; // groups.[].level - char name[60]; // copy of groups.[].name - unsigned int e_permissions; // packed groups.[].permissions - bool log_commands; // groups.[].log_commands - int group_pos;/* pos on load [Ind] */ - /// Following are used/avaialble only during config reading - config_setting_t *commands; // groups.[].commands - config_setting_t *permissions; // groups.[].permissions - config_setting_t *inherit; // groups.[].inherit - bool inheritance_done; // have all inheritance rules been evaluated? - config_setting_t *root; // groups.[] -}; - -int pc_group_max; /* known number of groups */ - -static DBMap* pc_group_db; // id -> GroupSettings -static DBMap* pc_groupname_db; // name -> GroupSettings +static GroupSettings dummy_group; ///< dummy group used in dummy map sessions @see pc_get_dummy_sd() + +struct pc_groups_interface pcg_s; /** - * @retval NULL if not found - * @private + * Returns dummy group. + * Used in dummy map sessions. + * @see pc_get_dummy_sd() */ -static inline GroupSettings* id2group(int group_id) +GroupSettings* pc_group_get_dummy_group(void) { - return (GroupSettings*)idb_get(pc_group_db, group_id); + return &dummy_group; } /** @@ -52,7 +38,7 @@ static inline GroupSettings* id2group(int group_id) */ static inline GroupSettings* name2group(const char* group_name) { - return (GroupSettings*)strdb_get(pc_groupname_db, group_name); + return strdb_get(pcg->name_db, group_name); } /** @@ -65,43 +51,43 @@ static void read_config(void) { const char *config_filename = "conf/groups.conf"; // FIXME hardcoded name int group_count = 0; - if (conf_read_file(&pc_group_config, config_filename)) + if (libconfig->read_file(&pc_group_config, config_filename)) return; - groups = config_lookup(&pc_group_config, "groups"); + groups = libconfig->lookup(&pc_group_config, "groups"); if (groups != NULL) { GroupSettings *group_settings = NULL; DBIterator *iter = NULL; int i, loop = 0; - group_count = config_setting_length(groups); + group_count = libconfig->setting_length(groups); for (i = 0; i < group_count; ++i) { int id = 0, level = 0; const char *groupname = NULL; int log_commands = 0; - config_setting_t *group = config_setting_get_elem(groups, i); + config_setting_t *group = libconfig->setting_get_elem(groups, i); - if (!config_setting_lookup_int(group, "id", &id)) { + if (!libconfig->setting_lookup_int(group, "id", &id)) { ShowConfigWarning(group, "pc_groups:read_config: \"groups\" list member #%d has undefined id, removing...", i); - config_setting_remove_elem(groups, i); + libconfig->setting_remove_elem(groups, i); --i; --group_count; continue; } - if (id2group(id) != NULL) { + if (pcg->exists(id)) { ShowConfigWarning(group, "pc_groups:read_config: duplicate group id %d, removing...", i); - config_setting_remove_elem(groups, i); + libconfig->setting_remove_elem(groups, i); --i; --group_count; continue; } - config_setting_lookup_int(group, "level", &level); - config_setting_lookup_bool(group, "log_commands", &log_commands); + libconfig->setting_lookup_int(group, "level", &level); + libconfig->setting_lookup_bool(group, "log_commands", &log_commands); - if (!config_setting_lookup_string(group, "name", &groupname)) { + if (!libconfig->setting_lookup_string(group, "name", &groupname)) { char temp[20]; config_setting_t *name = NULL; snprintf(temp, sizeof(temp), "Group %d", id); @@ -109,14 +95,16 @@ static void read_config(void) { !config_setting_set_string(name, temp)) { ShowError("pc_groups:read_config: failed to set missing group name, id=%d, skipping... (%s:%d)\n", id, config_setting_source_file(group), config_setting_source_line(group)); + --i; + --group_count; continue; } - config_setting_lookup_string(group, "name", &groupname); // Retrieve the pointer + libconfig->setting_lookup_string(group, "name", &groupname); // Retrieve the pointer } if (name2group(groupname) != NULL) { ShowConfigWarning(group, "pc_groups:read_config: duplicate group name %s, removing...", groupname); - config_setting_remove_elem(groups, i); + libconfig->setting_remove_elem(groups, i); --i; --group_count; continue; @@ -125,38 +113,39 @@ static void read_config(void) { CREATE(group_settings, GroupSettings, 1); group_settings->id = id; group_settings->level = level; - safestrncpy(group_settings->name, groupname, 60); + group_settings->name = aStrdup(groupname); group_settings->log_commands = (bool)log_commands; - group_settings->inherit = config_setting_get_member(group, "inherit"); - group_settings->commands = config_setting_get_member(group, "commands"); - group_settings->permissions = config_setting_get_member(group, "permissions"); + group_settings->inherit = libconfig->setting_get_member(group, "inherit"); + group_settings->commands = libconfig->setting_get_member(group, "commands"); + group_settings->permissions = libconfig->setting_get_member(group, "permissions"); group_settings->inheritance_done = false; group_settings->root = group; - group_settings->group_pos = i; + group_settings->index = i; - strdb_put(pc_groupname_db, groupname, group_settings); - idb_put(pc_group_db, id, group_settings); + strdb_put(pcg->name_db, groupname, group_settings); + idb_put(pcg->db, id, group_settings); } - group_count = config_setting_length(groups); // Save number of groups + group_count = libconfig->setting_length(groups); // Save number of groups + assert(group_count == db_size(pcg->db)); // Check if all commands and permissions exist - iter = db_iterator(pc_group_db); + iter = db_iterator(pcg->db); for (group_settings = dbi_first(iter); dbi_exists(iter); group_settings = dbi_next(iter)) { config_setting_t *commands = group_settings->commands, *permissions = group_settings->permissions; - int count = 0, i; + int count = 0; // Make sure there is "commands" group if (commands == NULL) - commands = group_settings->commands = config_setting_add(group_settings->root, "commands", CONFIG_TYPE_GROUP); - count = config_setting_length(commands); + commands = group_settings->commands = libconfig->setting_add(group_settings->root, "commands", CONFIG_TYPE_GROUP); + count = libconfig->setting_length(commands); for (i = 0; i < count; ++i) { - config_setting_t *command = config_setting_get_elem(commands, i); + config_setting_t *command = libconfig->setting_get_elem(commands, i); const char *name = config_setting_name(command); if (!atcommand->exists(name)) { ShowConfigWarning(command, "pc_groups:read_config: non-existent command name '%s', removing...", name); - config_setting_remove(commands, name); + libconfig->setting_remove(commands, name); --i; --count; } @@ -164,18 +153,18 @@ static void read_config(void) { // Make sure there is "permissions" group if (permissions == NULL) - permissions = group_settings->permissions = config_setting_add(group_settings->root, "permissions", CONFIG_TYPE_GROUP); - count = config_setting_length(permissions); + permissions = group_settings->permissions = libconfig->setting_add(group_settings->root, "permissions", CONFIG_TYPE_GROUP); + count = libconfig->setting_length(permissions); for(i = 0; i < count; ++i) { - config_setting_t *permission = config_setting_get_elem(permissions, i); + config_setting_t *permission = libconfig->setting_get_elem(permissions, i); const char *name = config_setting_name(permission); int j; - ARR_FIND(0, ARRAYLENGTH(pc_g_permission_name), j, strcmp(pc_g_permission_name[j].name, name) == 0); - if (j == ARRAYLENGTH(pc_g_permission_name)) { + ARR_FIND(0, pcg->permission_count, j, strcmp(pcg->permissions[j].name, name) == 0); + if (j == pcg->permission_count) { ShowConfigWarning(permission, "pc_groups:read_config: non-existent permission name '%s', removing...", name); - config_setting_remove(permissions, name); + libconfig->setting_remove(permissions, name); --i; --count; } @@ -186,7 +175,7 @@ static void read_config(void) { // Apply inheritance i = 0; // counter for processed groups while (i < group_count) { - iter = db_iterator(pc_group_db); + iter = db_iterator(pcg->db); for (group_settings = dbi_first(iter); dbi_exists(iter); group_settings = dbi_next(iter)) { config_setting_t *inherit = NULL, *commands = group_settings->commands, @@ -194,10 +183,10 @@ static void read_config(void) { int j, inherit_count = 0, done = 0; if (group_settings->inheritance_done) // group already processed - continue; + continue; if ((inherit = group_settings->inherit) == NULL || - (inherit_count = config_setting_length(inherit)) <= 0) { // this group does not inherit from others + (inherit_count = libconfig->setting_length(inherit)) <= 0) { // this group does not inherit from others ++i; group_settings->inheritance_done = true; continue; @@ -205,16 +194,16 @@ static void read_config(void) { for (j = 0; j < inherit_count; ++j) { GroupSettings *inherited_group = NULL; - const char *groupname = config_setting_get_string_elem(inherit, j); + const char *groupname = libconfig->setting_get_string_elem(inherit, j); if (groupname == NULL) { ShowConfigWarning(inherit, "pc_groups:read_config: \"inherit\" array member #%d is not a name, removing...", j); - config_setting_remove_elem(inherit,j); + libconfig->setting_remove_elem(inherit,j); continue; } if ((inherited_group = name2group(groupname)) == NULL) { ShowConfigWarning(inherit, "pc_groups:read_config: non-existent group name \"%s\", removing...", groupname); - config_setting_remove_elem(inherit,j); + libconfig->setting_remove_elem(inherit,j); continue; } if (!inherited_group->inheritance_done) @@ -222,15 +211,15 @@ static void read_config(void) { // Copy settings (commands/permissions) that are not defined yet if (inherited_group->commands != NULL) { - int i = 0, commands_count = config_setting_length(inherited_group->commands); - for (i = 0; i < commands_count; ++i) - config_setting_copy(commands, config_setting_get_elem(inherited_group->commands, i)); + int k = 0, commands_count = libconfig->setting_length(inherited_group->commands); + for (k = 0; k < commands_count; ++k) + libconfig->setting_copy(commands, libconfig->setting_get_elem(inherited_group->commands, k)); } if (inherited_group->permissions != NULL) { - int i = 0, permissions_count = config_setting_length(inherited_group->permissions); - for (i = 0; i < permissions_count; ++i) - config_setting_copy(permissions, config_setting_get_elem(inherited_group->permissions, i)); + int k = 0, permissions_count = libconfig->setting_length(inherited_group->permissions); + for (k = 0; k < permissions_count; ++k) + libconfig->setting_copy(permissions, libconfig->setting_get_elem(inherited_group->permissions, k)); } ++done; // copied commands and permissions from one of inherited groups @@ -249,131 +238,71 @@ static void read_config(void) { break; } } // while(i < group_count) - + // Pack permissions into GroupSettings.e_permissions for faster checking - iter = db_iterator(pc_group_db); + iter = db_iterator(pcg->db); for (group_settings = dbi_first(iter); dbi_exists(iter); group_settings = dbi_next(iter)) { config_setting_t *permissions = group_settings->permissions; - int i, count = config_setting_length(permissions); + int count = libconfig->setting_length(permissions); for (i = 0; i < count; ++i) { - config_setting_t *perm = config_setting_get_elem(permissions, i); + config_setting_t *perm = libconfig->setting_get_elem(permissions, i); const char *name = config_setting_name(perm); - int val = config_setting_get_bool(perm); + int val = libconfig->setting_get_bool(perm); int j; if (val == 0) // does not have this permission continue; - ARR_FIND(0, ARRAYLENGTH(pc_g_permission_name), j, strcmp(pc_g_permission_name[j].name, name) == 0); - group_settings->e_permissions |= pc_g_permission_name[j].permission; + ARR_FIND(0, pcg->permission_count, j, strcmp(pcg->permissions[j].name, name) == 0); + group_settings->e_permissions |= pcg->permissions[j].permission; } } dbi_destroy(iter); - } - ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' groups in '"CL_WHITE"%s"CL_RESET"'.\n", group_count, config_filename); - - - if( ( pc_group_max = group_count ) ) { - DBIterator *iter = db_iterator(pc_group_db); - GroupSettings *group_settings = NULL; - unsigned int* group_ids = aMalloc( pc_group_max * sizeof(unsigned int) ); - int i = 0; - for (group_settings = dbi_first(iter); dbi_exists(iter); group_settings = dbi_next(iter)) { - group_ids[i++] = group_settings->id; + // Atcommand permissions are processed by atcommand module. + // Fetch all groups and relevant config setting and send them + // to atcommand->load_group() for processing. + if (group_count > 0) { + GroupSettings **pc_groups = NULL; + config_setting_t **commands = NULL; + CREATE(pc_groups, GroupSettings*, group_count); + CREATE(commands, config_setting_t*, group_count); + i = 0; + iter = db_iterator(pcg->db); + for (group_settings = dbi_first(iter); dbi_exists(iter); group_settings = dbi_next(iter)) { + pc_groups[i] = group_settings; + commands[i] = group_settings->commands; + i++; + } + atcommand->load_groups(pc_groups, commands, group_count); + dbi_destroy(iter); + aFree(pc_groups); + aFree(commands); } - - if( atcommand->group_ids ) - aFree(atcommand->group_ids); - atcommand->group_ids = group_ids; - - atcommand->load_groups(); - - dbi_destroy(iter); } - - config_destroy(&pc_group_config); -} - -/** - * In group configuration file, setting for each command is either - * <commandname> : <bool> (only atcommand), or - * <commandname> : [ <bool>, <bool> ] ([ atcommand, charcommand ]) - * Maps AtCommandType enums to indexes of <commandname> value array, - * COMMAND_ATCOMMAND (1) being index 0, COMMAND_CHARCOMMAND (2) being index 1. - * @private - */ -static inline int AtCommandType2idx(AtCommandType type) { return (type-1); } -/** - * Checks if player group can use @/#command, used only during parse (only available during parse) - * @param group_id ID of the group - * @param command Command name without @/# and params - * @param type enum AtCommanndType { COMMAND_ATCOMMAND = 1, COMMAND_CHARCOMMAND = 2 } - */ -bool pc_group_can_use_command(int group_id, const char *command, AtCommandType type) { - int result = 0; - config_setting_t *commands = NULL; - GroupSettings *group = NULL; - - if (pc_group_has_permission(group_id, PC_PERM_USE_ALL_COMMANDS)) - return true; - - if ((group = id2group(group_id)) == NULL) - return false; + ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' groups in '"CL_WHITE"%s"CL_RESET"'.\n", group_count, config_filename); - commands = group->commands; - if (commands != NULL) { - config_setting_t *cmd = NULL; - - // <commandname> : <bool> (only atcommand) - if (type == COMMAND_ATCOMMAND && config_setting_lookup_bool(commands, command, &result)) - return (bool)result; - - // <commandname> : [ <bool>, <bool> ] ([ atcommand, charcommand ]) - if ((cmd = config_setting_get_member(commands, command)) != NULL && - config_setting_is_aggregate(cmd) && config_setting_length(cmd) == 2) - return (bool)config_setting_get_bool_elem(cmd, AtCommandType2idx(type)); - } - return false; -} -void pc_group_pc_load(struct map_session_data * sd) { - GroupSettings *group = NULL; - if ((group = id2group(sd->group_id)) == NULL) { - ShowWarning("pc_group_pc_load: %s (AID:%d) logged in with unknown group id (%d)! kicking...\n", - sd->status.name, - sd->status.account_id, - sd->group_id); - set_eof(sd->fd); - return; - } - sd->permissions = group->e_permissions; - sd->group_pos = group->group_pos; - sd->group_level = group->level; - sd->group_log_command = group->log_commands; + // All data is loaded now, discard config + libconfig->destroy(&pc_group_config); } + /** * Checks if player group has a permission - * @param group_id ID of the group + * @param group group * @param permission permission to check */ -bool pc_group_has_permission(int group_id, int permission) +bool pc_group_has_permission(GroupSettings *group, unsigned int permission) { - GroupSettings *group = NULL; - if ((group = id2group(group_id)) == NULL) - return false; return ((group->e_permissions&permission) != 0); } /** - * Checks commands used by player group should be logged - * @param group_id ID of the group + * Checks if commands used by player group should be logged + * @param group group */ -bool pc_group_should_log_commands(int group_id) +bool pc_group_should_log_commands(GroupSettings *group) { - GroupSettings *group = NULL; - if ((group = id2group(group_id)) == NULL) - return false; return group->log_commands; } @@ -384,71 +313,165 @@ bool pc_group_should_log_commands(int group_id) */ bool pc_group_exists(int group_id) { - return idb_exists(pc_group_db, group_id); + return idb_exists(pcg->db, group_id); } /** - * Group ID -> group name lookup. Used only in @who atcommands. - * @param group_id group id + * @retval NULL if not found + */ +GroupSettings* pc_group_id2group(int group_id) +{ + return idb_get(pcg->db, group_id); +} + +/** + * Group name lookup. Used only in @who atcommands. + * @param group group * @return group name * @public */ -const char* pc_group_id2name(int group_id) +const char* pc_group_get_name(GroupSettings *group) { - GroupSettings *group = id2group(group_id); - if (group == NULL) - return "Non-existent group!"; return group->name; } /** - * Group ID -> group level lookup. A way to provide backward compatibility with GM level system. - * @param group id + * Group level lookup. A way to provide backward compatibility with GM level system. + * @param group group * @return group level * @public */ -int pc_group_id2level(int group_id) +int pc_group_get_level(GroupSettings *group) { - GroupSettings *group = id2group(group_id); - if (group == NULL) - return 0; return group->level; } + /** - * Group ID -> group level lookup. - * @param group id + * Group -> index lookup. + * @param group group * @return group index * @public */ -int pc_group_id2idx(int group_id) +int pc_group_get_idx(GroupSettings *group) { - GroupSettings *group = id2group(group_id); - if (group == NULL) - return 0; - return group->group_pos; + return group->index; } /** + * Insert a new permission + * @return inserted key or 0 upon failure. + **/ +unsigned int pc_groups_add_permission(const char *name) { + uint64 key = 0x1; + unsigned char i; + + for(i = 0; i < pcg->permission_count; i++) { + if( strcmpi(name,pcg->permissions[i].name) == 0 ) { + ShowError("pc_groups_add_permission(%s): failed! duplicate permission name!\n",name); + return 0; + } + } + + if( i != 0 ) + key = (uint64)pcg->permissions[i - 1].permission << 1; + + if( key >= UINT_MAX ) { + ShowError("pc_groups_add_permission(%s): failed! not enough room, too many permissions!\n",name); + return 0; + } + + i = pcg->permission_count; + RECREATE(pcg->permissions, struct pc_groups_permission_table, ++pcg->permission_count); + + pcg->permissions[i].name = aStrdup(name); + pcg->permissions[i].permission = (unsigned int)key; + + return (unsigned int)key; +} +/** * Initialize PC Groups: allocate DBMaps and read config. * @public */ -void do_init_pc_groups(void) -{ - pc_group_db = idb_alloc(DB_OPT_RELEASE_DATA); - pc_groupname_db = stridb_alloc(DB_OPT_DUP_KEY, 0); +void do_init_pc_groups(void) { + const struct { + const char *name; + unsigned int permission; + } pc_g_defaults[] = { + { "can_trade", PC_PERM_TRADE }, + { "can_party", PC_PERM_PARTY }, + { "all_skill", PC_PERM_ALL_SKILL }, + { "all_equipment", PC_PERM_USE_ALL_EQUIPMENT }, + { "skill_unconditional", PC_PERM_SKILL_UNCONDITIONAL }, + { "join_chat", PC_PERM_JOIN_ALL_CHAT }, + { "kick_chat", PC_PERM_NO_CHAT_KICK }, + { "hide_session", PC_PERM_HIDE_SESSION }, + { "who_display_aid", PC_PERM_WHO_DISPLAY_AID }, + { "hack_info", PC_PERM_RECEIVE_HACK_INFO }, + { "any_warp", PC_PERM_WARP_ANYWHERE }, + { "view_hpmeter", PC_PERM_VIEW_HPMETER }, + { "view_equipment", PC_PERM_VIEW_EQUIPMENT }, + { "use_check", PC_PERM_USE_CHECK }, + { "use_changemaptype", PC_PERM_USE_CHANGEMAPTYPE }, + { "all_commands", PC_PERM_USE_ALL_COMMANDS }, + { "receive_requests", PC_PERM_RECEIVE_REQUESTS }, + { "show_bossmobs", PC_PERM_SHOW_BOSS }, + { "disable_pvm", PC_PERM_DISABLE_PVM }, + { "disable_pvp", PC_PERM_DISABLE_PVP }, + { "disable_commands_when_dead", PC_PERM_DISABLE_CMD_DEAD }, + { "hchsys_admin", PC_PERM_HCHSYS_ADMIN }, + { "can_trade_bound", PC_PERM_TRADE_BOUND }, + }; + unsigned char i, len = ARRAYLENGTH(pc_g_defaults); + + for(i = 0; i < len; i++) { + unsigned int p; + if( ( p = pc_groups_add_permission(pc_g_defaults[i].name) ) != pc_g_defaults[i].permission ) + ShowError("do_init_pc_groups: %s error : %d != %d\n",pc_g_defaults[i].name,p,pc_g_defaults[i].permission); + } + + /** + * Handle plugin-provided permissions + **/ + for(i = 0; i < pcg->HPMpermissions_count; i++) { + *pcg->HPMpermissions[i].mask = pc_groups_add_permission(pcg->HPMpermissions[i].name); + } + + pcg->db = idb_alloc(DB_OPT_RELEASE_DATA); + pcg->name_db = stridb_alloc(DB_OPT_DUP_KEY, 0); + read_config(); } /** + * @see DBApply + */ +static int group_db_clear_sub(DBKey key, DBData *data, va_list args) +{ + GroupSettings *group = DB->data2ptr(data); + if (group->name) + aFree(group->name); + return 0; +} + +/** * Finalize PC Groups: free DBMaps and config. * @public */ void do_final_pc_groups(void) { - if (pc_group_db != NULL) - db_destroy(pc_group_db); - if (pc_groupname_db != NULL ) - db_destroy(pc_groupname_db); + if (pcg->db != NULL) + pcg->db->destroy(pcg->db, group_db_clear_sub); + if (pcg->name_db != NULL) + db_destroy(pcg->name_db); + + if(pcg->permissions != NULL) { + unsigned char i; + for(i = 0; i < pcg->permission_count; i++) + aFree(pcg->permissions[i].name); + aFree(pcg->permissions); + pcg->permissions = NULL; + } + pcg->permission_count = 0; } /** @@ -457,18 +480,50 @@ void do_final_pc_groups(void) * @public */ void pc_groups_reload(void) { - struct map_session_data* sd = NULL; - struct s_mapiterator* iter; + struct map_session_data *sd = NULL; + struct s_mapiterator *iter; - do_final_pc_groups(); - do_init_pc_groups(); + pcg->final(); + pcg->init(); /* refresh online users permissions */ iter = mapit_getallusers(); - for (sd = (TBL_PC*)mapit->first(iter); mapit->exists(iter); sd = (TBL_PC*)mapit->next(iter)) { - pc_group_pc_load(sd); + for (sd = (TBL_PC*)mapit->first(iter); mapit->exists(iter); sd = (TBL_PC*)mapit->next(iter)) { + if (pc->set_group(sd, sd->group_id) != 0) { + ShowWarning("pc_groups_reload: %s (AID:%d) has unknown group id (%d)! kicking...\n", + sd->status.name, sd->status.account_id, pc_get_group_id(sd)); + clif->GM_kick(NULL, sd); + } } mapit->free(iter); +} +/** + * Connect Interface + **/ +void pc_groups_defaults(void) { + pcg = &pcg_s; + /* */ + pcg->db = NULL; + pcg->name_db = NULL; + /* */ + pcg->permissions = NULL; + pcg->permission_count = 0; + /* */ + pcg->HPMpermissions = NULL; + pcg->HPMpermissions_count = 0; + /* */ + pcg->init = do_init_pc_groups; + pcg->final = do_final_pc_groups; + pcg->reload = pc_groups_reload; + /* */ + pcg->get_dummy_group = pc_group_get_dummy_group; + pcg->exists = pc_group_exists; + pcg->id2group = pc_group_id2group; + pcg->has_permission = pc_group_has_permission; + pcg->should_log_commands = pc_group_should_log_commands; + pcg->get_name = pc_group_get_name; + pcg->get_level = pc_group_get_level; + pcg->get_idx = pc_group_get_idx; } diff --git a/src/map/pc_groups.h b/src/map/pc_groups.h index 0ce7b0d51..f52e2ba22 100644 --- a/src/map/pc_groups.h +++ b/src/map/pc_groups.h @@ -2,29 +2,17 @@ // See the LICENSE file // Portions Copyright (c) Athena Dev Teams -#ifndef _PC_GROUPS_H_ -#define _PC_GROUPS_H_ +#ifndef MAP_PC_GROUPS_H +#define MAP_PC_GROUPS_H -#include "atcommand.h" // AtCommandType - -extern int pc_group_max; - -bool pc_group_exists(int group_id); -bool pc_group_can_use_command(int group_id, const char *command, AtCommandType type); -bool pc_group_has_permission(int group_id, int permission); -bool pc_group_should_log_commands(int group_id); -const char* pc_group_id2name(int group_id); -int pc_group_id2level(int group_id); -int pc_group_id2idx(int group_id); -void pc_group_pc_load(struct map_session_data *); - -void do_init_pc_groups(void); -void do_final_pc_groups(void); -void pc_groups_reload(void); +#include "../common/cbasetypes.h" +#include "../common/conf.h" +#include "../common/db.h" +/// PC permissions enum e_pc_permission { - PC_PERM_NONE = 0, - PC_PERM_TRADE = 0x000001, + PC_PERM_NONE = 0, // #0 + PC_PERM_TRADE = 0x000001, // #1 PC_PERM_PARTY = 0x000002, PC_PERM_ALL_SKILL = 0x000004, PC_PERM_USE_ALL_EQUIPMENT = 0x000008, @@ -33,7 +21,7 @@ enum e_pc_permission { PC_PERM_NO_CHAT_KICK = 0x000040, PC_PERM_HIDE_SESSION = 0x000080, PC_PERM_WHO_DISPLAY_AID = 0x000100, - PC_PERM_RECEIVE_HACK_INFO = 0x000200, + PC_PERM_RECEIVE_HACK_INFO = 0x000200, // #10 PC_PERM_WARP_ANYWHERE = 0x000400, PC_PERM_VIEW_HPMETER = 0x000800, PC_PERM_VIEW_EQUIPMENT = 0x001000, @@ -41,39 +29,71 @@ enum e_pc_permission { PC_PERM_USE_CHANGEMAPTYPE = 0x004000, PC_PERM_USE_ALL_COMMANDS = 0x008000, PC_PERM_RECEIVE_REQUESTS = 0x010000, - PC_PERM_SHOW_BOSS = 0x020000, - PC_PERM_DISABLE_PVM = 0x040000, - PC_PERM_DISABLE_PVP = 0x080000, + PC_PERM_SHOW_BOSS = 0x020000, + PC_PERM_DISABLE_PVM = 0x040000, + PC_PERM_DISABLE_PVP = 0x080000, // #20 PC_PERM_DISABLE_CMD_DEAD = 0x100000, - PC_PERM_HCHSYS_ADMIN = 0x200000, + PC_PERM_HCHSYS_ADMIN = 0x200000, + PC_PERM_TRADE_BOUND = 0x400000, }; -static const struct { - const char *name; +// Cached config settings for quick lookup +struct GroupSettings { + unsigned int id; // groups.[].id + int level; // groups.[].level + char *name; // copy of groups.[].name + unsigned int e_permissions; // packed groups.[].permissions + bool log_commands; // groups.[].log_commands + int index; // internal index of the group (contiguous range starting at 0) [Ind] + /// Following are used/available only during config reading + config_setting_t *commands; // groups.[].commands + config_setting_t *permissions; // groups.[].permissions + config_setting_t *inherit; // groups.[].inherit + bool inheritance_done; // have all inheritance rules been evaluated? + config_setting_t *root; // groups.[] +}; + +typedef struct GroupSettings GroupSettings; + +struct pc_groups_permission_table { + char *name; unsigned int permission; -} pc_g_permission_name[] = { - { "can_trade", PC_PERM_TRADE }, - { "can_party", PC_PERM_PARTY }, - { "all_skill", PC_PERM_ALL_SKILL }, - { "all_equipment", PC_PERM_USE_ALL_EQUIPMENT }, - { "skill_unconditional", PC_PERM_SKILL_UNCONDITIONAL }, - { "join_chat", PC_PERM_JOIN_ALL_CHAT }, - { "kick_chat", PC_PERM_NO_CHAT_KICK }, - { "hide_session", PC_PERM_HIDE_SESSION }, - { "who_display_aid", PC_PERM_WHO_DISPLAY_AID }, - { "hack_info", PC_PERM_RECEIVE_HACK_INFO }, - { "any_warp", PC_PERM_WARP_ANYWHERE }, - { "view_hpmeter", PC_PERM_VIEW_HPMETER }, - { "view_equipment", PC_PERM_VIEW_EQUIPMENT }, - { "use_check", PC_PERM_USE_CHECK }, - { "use_changemaptype", PC_PERM_USE_CHANGEMAPTYPE }, - { "all_commands", PC_PERM_USE_ALL_COMMANDS }, - { "receive_requests", PC_PERM_RECEIVE_REQUESTS }, - { "show_bossmobs", PC_PERM_SHOW_BOSS }, - { "disable_pvm", PC_PERM_DISABLE_PVM }, - { "disable_pvp", PC_PERM_DISABLE_PVP }, - { "disable_commands_when_dead", PC_PERM_DISABLE_CMD_DEAD }, - { "hchsys_admin", PC_PERM_HCHSYS_ADMIN }, }; -#endif // _PC_GROUPS_H_ +/* used by plugins to list permissions */ +struct pc_groups_new_permission { + unsigned int pID;/* plugin identity (for the future unload during runtime support) */ + char *name;/* aStrdup' of the permission name */ + unsigned int *mask;/* pointer to the plugin val that will store the value of the mask */ +}; + +struct pc_groups_interface { + /* */ + DBMap* db; // id -> GroupSettings + DBMap* name_db; // name -> GroupSettings + /* */ + struct pc_groups_permission_table *permissions; + unsigned char permission_count; + /* */ + struct pc_groups_new_permission *HPMpermissions; + unsigned char HPMpermissions_count; + /* */ + void (*init) (void); + void (*final) (void); + void (*reload) (void); + /* */ + GroupSettings* (*get_dummy_group) (void); + bool (*exists) (int group_id); + GroupSettings* (*id2group) (int group_id); + bool (*has_permission) (GroupSettings *group, unsigned int permission); + bool (*should_log_commands) (GroupSettings *group); + const char* (*get_name) (GroupSettings *group); + int (*get_level) (GroupSettings *group); + int (*get_idx) (GroupSettings *group); +}; + +struct pc_groups_interface *pcg; + +void pc_groups_defaults(void); + +#endif /* MAP_PC_GROUPS_H */ diff --git a/src/map/pet.c b/src/map/pet.c index 00402f9d4..9275a6de5 100644 --- a/src/map/pet.c +++ b/src/map/pet.c @@ -2,46 +2,44 @@ // See the LICENSE file // Portions Copyright (c) Athena Dev Teams -#include "../common/db.h" -#include "../common/timer.h" -#include "../common/nullpo.h" -#include "../common/malloc.h" -#include "../common/random.h" -#include "../common/showmsg.h" -#include "../common/strlib.h" -#include "../common/utils.h" -#include "../common/ers.h" +#define HERCULES_CORE -#include "pc.h" -#include "status.h" -#include "map.h" -#include "path.h" -#include "intif.h" -#include "clif.h" -#include "chrif.h" #include "pet.h" -#include "itemdb.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "atcommand.h" // msg_txt() #include "battle.h" +#include "chrif.h" +#include "clif.h" +#include "intif.h" +#include "itemdb.h" +#include "log.h" +#include "map.h" #include "mob.h" #include "npc.h" +#include "path.h" +#include "pc.h" #include "script.h" #include "skill.h" +#include "status.h" #include "unit.h" -#include "atcommand.h" // msg_txt() -#include "log.h" - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> +#include "../common/db.h" +#include "../common/ers.h" +#include "../common/malloc.h" +#include "../common/nullpo.h" +#include "../common/random.h" +#include "../common/showmsg.h" +#include "../common/strlib.h" +#include "../common/timer.h" +#include "../common/utils.h" +struct pet_interface pet_s; #define MIN_PETTHINKTIME 100 -struct s_pet_db pet_db[MAX_PET_DB]; - -static struct eri *item_drop_ers; //For loot drops delay structures. -static struct eri *item_drop_list_ers; - int pet_hungry_val(struct pet_data *pd) { nullpo_ret(pd); @@ -69,21 +67,21 @@ void pet_set_intimate(struct pet_data *pd, int value) pd->pet.intimate = value; if( (intimate >= battle_config.pet_equip_min_friendly && pd->pet.intimate < battle_config.pet_equip_min_friendly) || (intimate < battle_config.pet_equip_min_friendly && pd->pet.intimate >= battle_config.pet_equip_min_friendly) ) - status_calc_pc(sd,0); + status_calc_pc(sd,SCO_NONE); } int pet_create_egg(struct map_session_data *sd, int item_id) { - int pet_id = search_petDB_index(item_id, PET_EGG); + int pet_id = pet->search_petDB_index(item_id, PET_EGG); if (pet_id < 0) return 0; //No pet egg here. if (!pc->inventoryblank(sd)) return 0; // Inventory full - sd->catch_target_class = pet_db[pet_id].class_; - intif_create_pet(sd->status.account_id, sd->status.char_id, - (short)pet_db[pet_id].class_, - (short)mob_db(pet_db[pet_id].class_)->lv, - (short)pet_db[pet_id].EggID, 0, - (short)pet_db[pet_id].intimate, - 100, 0, 1, pet_db[pet_id].jname); + sd->catch_target_class = pet->db[pet_id].class_; + intif->create_pet(sd->status.account_id, sd->status.char_id, + (short)pet->db[pet_id].class_, + (short)mob->db(pet->db[pet_id].class_)->lv, + (short)pet->db[pet_id].EggID, 0, + (short)pet->db[pet_id].intimate, + 100, 0, 1, pet->db[pet_id].jname); return 1; } @@ -100,37 +98,35 @@ int pet_unlocktarget(struct pet_data *pd) /*========================================== * Pet Attack Skill [Skotlex] *------------------------------------------*/ -int pet_attackskill(struct pet_data *pd, int target_id) -{ - if (!battle_config.pet_status_support || !pd->a_skill || +int pet_attackskill(struct pet_data *pd, int target_id) { + if (!battle_config.pet_status_support || !pd->a_skill || (battle_config.pet_equip_required && !pd->pet.equip)) return 0; - if (DIFF_TICK(pd->ud.canact_tick, iTimer->gettick()) > 0) + if (DIFF_TICK(pd->ud.canact_tick, timer->gettick()) > 0) return 0; - if (rnd()%100 < (pd->a_skill->rate +pd->pet.intimate*pd->a_skill->bonusrate/1000)) - { //Skotlex: Use pet's skill + if (rnd()%100 < (pd->a_skill->rate +pd->pet.intimate*pd->a_skill->bonusrate/1000)) { + //Skotlex: Use pet's skill int inf; struct block_list *bl; - bl=iMap->id2bl(target_id); - if(bl == NULL || pd->bl.m != bl->m || bl->prev == NULL || status_isdead(bl) || - !check_distance_bl(&pd->bl, bl, pd->db->range3)) + bl=map->id2bl(target_id); + if( bl == NULL || pd->bl.m != bl->m || bl->prev == NULL + || status->isdead(bl) || !check_distance_bl(&pd->bl, bl, pd->db->range3)) return 0; inf = skill->get_inf(pd->a_skill->id); if (inf & INF_GROUND_SKILL) - unit_skilluse_pos(&pd->bl, bl->x, bl->y, pd->a_skill->id, pd->a_skill->lv); - else //Offensive self skill? Could be stuff like GX. - unit_skilluse_id(&pd->bl,(inf&INF_SELF_SKILL?pd->bl.id:bl->id), pd->a_skill->id, pd->a_skill->lv); + unit->skilluse_pos(&pd->bl, bl->x, bl->y, pd->a_skill->id, pd->a_skill->lv); + else //Offensive self skill? Could be stuff like GX. + unit->skilluse_id(&pd->bl,(inf&INF_SELF_SKILL?pd->bl.id:bl->id), pd->a_skill->id, pd->a_skill->lv); return 1; //Skill invoked. } return 0; } -int pet_target_check(struct map_session_data *sd,struct block_list *bl,int type) -{ +int pet_target_check(struct map_session_data *sd,struct block_list *bl,int type) { struct pet_data *pd; int rate; @@ -138,17 +134,17 @@ int pet_target_check(struct map_session_data *sd,struct block_list *bl,int type) Assert((pd->msd == 0) || (pd->msd->pd == pd)); - if(bl == NULL || bl->type != BL_MOB || bl->prev == NULL || - pd->pet.intimate < battle_config.pet_support_min_friendly || - pd->pet.hungry < 1 || - pd->pet.class_ == status_get_class(bl)) + if( bl == NULL || bl->type != BL_MOB || bl->prev == NULL + || pd->pet.intimate < battle_config.pet_support_min_friendly + || pd->pet.hungry < 1 + || pd->pet.class_ == status->get_class(bl)) return 0; - if(pd->bl.m != bl->m || - !check_distance_bl(&pd->bl, bl, pd->db->range2)) + if( pd->bl.m != bl->m + || !check_distance_bl(&pd->bl, bl, pd->db->range2)) return 0; - if (!status_check_skilluse(&pd->bl, bl, 0, 0)) + if (!status->check_skilluse(&pd->bl, bl, 0, 0)) return 0; if(!type) { @@ -162,7 +158,7 @@ int pet_target_check(struct map_session_data *sd,struct block_list *bl,int type) if(pd->petDB->defence_attack_rate > 0 && rate <= 0) rate = 1; } - if(rnd()%10000 < rate) + if(rnd()%10000 < rate) { if(pd->target_id == 0 || rnd()%10000 < pd->petDB->change_target_rate) pd->target_id = bl->id; @@ -187,18 +183,17 @@ int pet_sc_check(struct map_session_data *sd, int type) || pd->recovery->type != type ) return 1; - pd->recovery->timer = iTimer->add_timer(iTimer->gettick()+pd->recovery->delay*1000,pet_recovery_timer,sd->bl.id,0); + pd->recovery->timer = timer->add(timer->gettick()+pd->recovery->delay*1000,pet->recovery_timer,sd->bl.id,0); return 0; } -static int pet_hungry(int tid, unsigned int tick, int id, intptr_t data) -{ +int pet_hungry(int tid, int64 tick, int id, intptr_t data) { struct map_session_data *sd; struct pet_data *pd; int interval; - sd=iMap->id2sd(id); + sd=map->id2sd(id); if(!sd) return 1; @@ -220,13 +215,13 @@ static int pet_hungry(int tid, unsigned int tick, int id, intptr_t data) { pet_stop_attack(pd); pd->pet.hungry = 0; - pet_set_intimate(pd, pd->pet.intimate - battle_config.pet_hungry_friendly_decrease); + pet->set_intimate(pd, pd->pet.intimate - battle_config.pet_hungry_friendly_decrease); if( pd->pet.intimate <= 0 ) { pd->pet.intimate = 0; pd->status.speed = pd->db->status.speed; } - status_calc_pet(pd, 0); + status_calc_pet(pd, SCO_NONE); clif->send_petdata(sd,pd,1,pd->pet.intimate); } clif->send_petdata(sd,pd,2,pd->pet.hungry); @@ -237,7 +232,7 @@ static int pet_hungry(int tid, unsigned int tick, int id, intptr_t data) interval = pd->petDB->hungry_delay; if(interval <= 0) interval = 1; - pd->pet_hungry_timer = iTimer->add_timer(tick+interval,pet_hungry,sd->bl.id,0); + pd->pet_hungry_timer = timer->add(tick+interval,pet->hungry,sd->bl.id,0); return 0; } @@ -248,14 +243,14 @@ int search_petDB_index(int key,int type) for( i = 0; i < MAX_PET_DB; i++ ) { - if(pet_db[i].class_ <= 0) + if(pet->db[i].class_ <= 0) continue; switch(type) { - case PET_CLASS: if(pet_db[i].class_ == key) return i; break; - case PET_CATCH: if(pet_db[i].itemID == key) return i; break; - case PET_EGG: if(pet_db[i].EggID == key) return i; break; - case PET_EQUIP: if(pet_db[i].AcceID == key) return i; break; - case PET_FOOD: if(pet_db[i].FoodID == key) return i; break; + case PET_CLASS: if(pet->db[i].class_ == key) return i; break; + case PET_CATCH: if(pet->db[i].itemID == key) return i; break; + case PET_EGG: if(pet->db[i].EggID == key) return i; break; + case PET_EQUIP: if(pet->db[i].AcceID == key) return i; break; + case PET_FOOD: if(pet->db[i].FoodID == key) return i; break; default: return -1; } @@ -267,14 +262,14 @@ int pet_hungry_timer_delete(struct pet_data *pd) { nullpo_ret(pd); if(pd->pet_hungry_timer != INVALID_TIMER) { - iTimer->delete_timer(pd->pet_hungry_timer,pet_hungry); + timer->delete(pd->pet_hungry_timer,pet->hungry); pd->pet_hungry_timer = INVALID_TIMER; } return 1; } -static int pet_performance(struct map_session_data *sd, struct pet_data *pd) +int pet_performance(struct map_session_data *sd, struct pet_data *pd) { int val; @@ -287,16 +282,16 @@ static int pet_performance(struct map_session_data *sd, struct pet_data *pd) pet_stop_walking(pd,2000<<8); clif->send_petdata(NULL, pd, 4, rnd()%val + 1); - pet_lootitem_drop(pd,NULL); + pet->lootitem_drop(pd,NULL); return 1; } -static int pet_return_egg(struct map_session_data *sd, struct pet_data *pd) +int pet_return_egg(struct map_session_data *sd, struct pet_data *pd) { struct item tmp_item; int flag; - pet_lootitem_drop(pd,sd); + pet->lootitem_drop(pd,sd); memset(&tmp_item,0,sizeof(tmp_item)); tmp_item.nameid = pd->petDB->EggID; tmp_item.identify = 1; @@ -306,135 +301,139 @@ static int pet_return_egg(struct map_session_data *sd, struct pet_data *pd) tmp_item.card[3] = pd->pet.rename_flag; if((flag = pc->additem(sd,&tmp_item,1,LOG_TYPE_OTHER))) { clif->additem(sd,0,0,flag); - iMap->addflooritem(&tmp_item,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0); + map->addflooritem(&tmp_item,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0); } - pd->pet.incuvate = 1; - unit_free(&pd->bl,CLR_OUTSIGHT); + pd->pet.incubate = 1; + unit->free(&pd->bl,CLR_OUTSIGHT); - status_calc_pc(sd,0); + status_calc_pc(sd,SCO_NONE); sd->status.pet_id = 0; return 1; } -int pet_data_init(struct map_session_data *sd, struct s_pet *pet) +int pet_data_init(struct map_session_data *sd, struct s_pet *petinfo) { struct pet_data *pd; int i=0,interval=0; nullpo_retr(1, sd); - Assert((sd->status.pet_id == 0 || sd->pd == 0) || sd->pd->msd == sd); + Assert((sd->status.pet_id == 0 || sd->pd == 0) || sd->pd->msd == sd); - if(sd->status.account_id != pet->account_id || sd->status.char_id != pet->char_id) { + if(sd->status.account_id != petinfo->account_id || sd->status.char_id != petinfo->char_id) { sd->status.pet_id = 0; return 1; } - if (sd->status.pet_id != pet->pet_id) { + if (sd->status.pet_id != petinfo->pet_id) { if (sd->status.pet_id) { - //Wrong pet?? Set incuvate to no and send it back for saving. - pet->incuvate = 1; - intif_save_petdata(sd->status.account_id,pet); + //Wrong pet?? Set incubate to no and send it back for saving. + petinfo->incubate = 1; + intif->save_petdata(sd->status.account_id,petinfo); sd->status.pet_id = 0; return 1; } //The pet_id value was lost? odd... restore it. - sd->status.pet_id = pet->pet_id; + sd->status.pet_id = petinfo->pet_id; } - i = search_petDB_index(pet->class_,PET_CLASS); + i = pet->search_petDB_index(petinfo->class_,PET_CLASS); if(i < 0) { sd->status.pet_id = 0; return 1; } sd->pd = pd = (struct pet_data *)aCalloc(1,sizeof(struct pet_data)); pd->bl.type = BL_PET; - pd->bl.id = npc_get_new_npc_id(); + pd->bl.id = npc->get_new_npc_id(); pd->msd = sd; - pd->petDB = &pet_db[i]; - pd->db = mob_db(pet->class_); - memcpy(&pd->pet, pet, sizeof(struct s_pet)); - status_set_viewdata(&pd->bl, pet->class_); - unit_dataset(&pd->bl); + pd->petDB = &pet->db[i]; + pd->db = mob->db(petinfo->class_); + memcpy(&pd->pet, petinfo, sizeof(struct s_pet)); + status->set_viewdata(&pd->bl, petinfo->class_); + unit->dataset(&pd->bl); pd->ud.dir = sd->ud.dir; pd->bl.m = sd->bl.m; pd->bl.x = sd->bl.x; pd->bl.y = sd->bl.y; - unit_calc_pos(&pd->bl, sd->bl.x, sd->bl.y, sd->ud.dir); + unit->calc_pos(&pd->bl, sd->bl.x, sd->bl.y, sd->ud.dir); pd->bl.x = pd->ud.to_x; pd->bl.y = pd->ud.to_y; - iMap->addiddb(&pd->bl); - status_calc_pet(pd,1); + map->addiddb(&pd->bl); + status_calc_pet(pd,SCO_FIRST); - pd->last_thinktime = iTimer->gettick(); + pd->last_thinktime = timer->gettick(); pd->state.skillbonus = 0; + if( battle_config.pet_status_support ) - run_script(pet_db[i].pet_script,0,sd->bl.id,0); - if( pd->petDB && pd->petDB->equip_script ) - status_calc_pc(sd,0); + script->run(pet->db[i].pet_script,0,sd->bl.id,0); + + if( pd->petDB ) { + if( pd->petDB->equip_script ) + status_calc_pc(sd,SCO_NONE); - if( battle_config.pet_hungry_delay_rate != 100 ) - interval = (pd->petDB->hungry_delay*battle_config.pet_hungry_delay_rate)/100; - else - interval = pd->petDB->hungry_delay; + if( battle_config.pet_hungry_delay_rate != 100 ) + interval = (pd->petDB->hungry_delay*battle_config.pet_hungry_delay_rate)/100; + else + interval = pd->petDB->hungry_delay; + } + if( interval <= 0 ) interval = 1; - pd->pet_hungry_timer = iTimer->add_timer(iTimer->gettick() + interval, pet_hungry, sd->bl.id, 0); + pd->pet_hungry_timer = timer->add(timer->gettick() + interval, pet->hungry, sd->bl.id, 0); return 0; } -int pet_birth_process(struct map_session_data *sd, struct s_pet *pet) +int pet_birth_process(struct map_session_data *sd, struct s_pet *petinfo) { nullpo_retr(1, sd); - Assert((sd->status.pet_id == 0 || sd->pd == 0) || sd->pd->msd == sd); + Assert((sd->status.pet_id == 0 || sd->pd == 0) || sd->pd->msd == sd); - if(sd->status.pet_id && pet->incuvate == 1) { + if(sd->status.pet_id && petinfo->incubate == 1) { sd->status.pet_id = 0; return 1; } - pet->incuvate = 0; - pet->account_id = sd->status.account_id; - pet->char_id = sd->status.char_id; - sd->status.pet_id = pet->pet_id; - if(pet_data_init(sd, pet)) { + petinfo->incubate = 0; + petinfo->account_id = sd->status.account_id; + petinfo->char_id = sd->status.char_id; + sd->status.pet_id = petinfo->pet_id; + if(pet->data_init(sd, petinfo)) { sd->status.pet_id = 0; return 1; } - intif_save_petdata(sd->status.account_id,pet); - if (iMap->save_settings&8) - chrif_save(sd,0); //is it REALLY Needed to save the char for hatching a pet? [Skotlex] + intif->save_petdata(sd->status.account_id,petinfo); + if (map->save_settings&8) + chrif->save(sd,0); //is it REALLY Needed to save the char for hatching a pet? [Skotlex] if(sd->bl.prev != NULL) { - iMap->addblock(&sd->pd->bl); + map->addblock(&sd->pd->bl); clif->spawn(&sd->pd->bl); clif->send_petdata(sd,sd->pd, 0,0); clif->send_petdata(sd,sd->pd, 5,battle_config.pet_hair_style); clif->send_petdata(NULL, sd->pd, 3, sd->pd->vd.head_bottom); clif->send_petstatus(sd); } - Assert((sd->status.pet_id == 0 || sd->pd == 0) || sd->pd->msd == sd); + Assert((sd->status.pet_id == 0 || sd->pd == 0) || sd->pd->msd == sd); return 0; } -int pet_recv_petdata(int account_id,struct s_pet *p,int flag) -{ +int pet_recv_petdata(int account_id,struct s_pet *p,int flag) { struct map_session_data *sd; - sd = iMap->id2sd(account_id); + sd = map->id2sd(account_id); if(sd == NULL) return 1; if(flag == 1) { sd->status.pet_id = 0; return 1; } - if(p->incuvate == 1) { + if(p->incubate == 1) { int i; //Delete egg from inventory. [Skotlex] for (i = 0; i < MAX_INVENTORY; i++) { @@ -447,12 +446,12 @@ int pet_recv_petdata(int account_id,struct s_pet *p,int flag) sd->status.pet_id = 0; return 1; } - if (!pet_birth_process(sd,p)) //Pet hatched. Delete egg. + if (!pet->birth_process(sd,p)) //Pet hatched. Delete egg. pc->delitem(sd,i,1,0,0,LOG_TYPE_OTHER); } else { - pet_data_init(sd,p); + pet->data_init(sd,p); if(sd->pd && sd->bl.prev != NULL) { - iMap->addblock(&sd->pd->bl); + map->addblock(&sd->pd->bl); clif->spawn(&sd->pd->bl); clif->send_petdata(sd,sd->pd,0,0); clif->send_petdata(sd,sd->pd,5,battle_config.pet_hair_style); @@ -472,7 +471,7 @@ int pet_select_egg(struct map_session_data *sd,short egg_index) return 0; //Forged packet! if(sd->status.inventory[egg_index].card[0] == CARD0_PET) - intif_request_petdata(sd->status.account_id, sd->status.char_id, MakeDWord(sd->status.inventory[egg_index].card[1], sd->status.inventory[egg_index].card[2]) ); + intif->request_petdata(sd->status.account_id, sd->status.char_id, MakeDWord(sd->status.inventory[egg_index].card[1], sd->status.inventory[egg_index].card[2]) ); else ShowError("wrong egg item inventory %d\n",egg_index); @@ -489,16 +488,15 @@ int pet_catch_process1(struct map_session_data *sd,int target_class) return 0; } -int pet_catch_process2(struct map_session_data* sd, int target_id) -{ +int pet_catch_process2(struct map_session_data* sd, int target_id) { struct mob_data* md; int i = 0, pet_catch_rate = 0; nullpo_retr(1, sd); - md = (struct mob_data*)iMap->id2bl(target_id); - if(!md || md->bl.type != BL_MOB || md->bl.prev == NULL) - { // Invalid inputs/state, abort capture. + md = (struct mob_data*)map->id2bl(target_id); + if(!md || md->bl.type != BL_MOB || md->bl.prev == NULL) { + // Invalid inputs/state, abort capture. clif->pet_roulette(sd,0); sd->catch_target_class = -1; sd->itemid = sd->itemindex = -1; @@ -507,7 +505,7 @@ int pet_catch_process2(struct map_session_data* sd, int target_id) //FIXME: delete taming item here, if this was an item-invoked capture and the item was flagged as delay-consume [ultramage] - i = search_petDB_index(md->class_,PET_CLASS); + i = pet->search_petDB_index(md->class_,PET_CLASS); //catch_target_class == 0 is used for universal lures (except bosses for now). [Skotlex] if (sd->catch_target_class == 0 && !(md->status.mode&MD_BOSS)) sd->catch_target_class = md->class_; @@ -518,7 +516,7 @@ int pet_catch_process2(struct map_session_data* sd, int target_id) return 1; } - pet_catch_rate = (pet_db[i].capture + (sd->status.base_level - md->level)*30 + sd->battle_status.luk*20)*(200 - get_percentage(md->status.hp, md->status.max_hp))/100; + pet_catch_rate = (pet->db[i].capture + (sd->status.base_level - md->level)*30 + sd->battle_status.luk*20)*(200 - get_percentage(md->status.hp, md->status.max_hp))/100; if(pet_catch_rate < 1) pet_catch_rate = 1; if(battle_config.pet_catch_rate != 100) @@ -526,11 +524,11 @@ int pet_catch_process2(struct map_session_data* sd, int target_id) if(rnd()%10000 < pet_catch_rate) { - unit_remove_map(&md->bl,CLR_OUTSIGHT); + unit->remove_map(&md->bl,CLR_OUTSIGHT,ALC_MARK); status_kill(&md->bl); clif->pet_roulette(sd,1); - intif_create_pet(sd->status.account_id,sd->status.char_id,pet_db[i].class_,mob_db(pet_db[i].class_)->lv, - pet_db[i].EggID,0,pet_db[i].intimate,100,0,1,pet_db[i].jname); + intif->create_pet(sd->status.account_id,sd->status.char_id,pet->db[i].class_,mob->db(pet->db[i].class_)->lv, + pet->db[i].EggID,0,pet->db[i].intimate,100,0,1,pet->db[i].jname); } else { @@ -541,29 +539,42 @@ int pet_catch_process2(struct map_session_data* sd, int target_id) return 0; } -int pet_get_egg(int account_id,int pet_id,int flag) -{ //This function is invoked when a new pet has been created, and at no other time! +/** + * Is invoked _only_ when a new pet has been created is a product of packet 0x3880 + * see mapif_pet_created@int_pet.c for more information + * Handles new pet data from inter-server and prepares item information + * to add pet egg + * + * pet_id - Should contain pet id otherwise means failure + * returns true on success + **/ +bool pet_get_egg(int account_id, short pet_class, int pet_id ) { struct map_session_data *sd; struct item tmp_item; - int i=0,ret=0; + int i = 0, ret = 0; - if(flag) - return 0; - - sd = iMap->id2sd(account_id); - if(sd == NULL) - return 0; + if( pet_id == 0 || pet_class == 0 ) + return false; - i = search_petDB_index(sd->catch_target_class,PET_CLASS); + sd = map->id2sd(account_id); + if( sd == NULL ) + return false; + + // i = pet->search_petDB_index(sd->catch_target_class,PET_CLASS); + // issue: 8150 + // Before this change in cases where more than one pet egg were requested in a short + // period of time it wasn't possible to know which kind of egg was being requested after + // the first request. [Panikon] + i = pet->search_petDB_index(pet_class,PET_CLASS); sd->catch_target_class = -1; if(i < 0) { - intif_delete_petdata(pet_id); - return 0; + intif->delete_petdata(pet_id); + return false; } memset(&tmp_item,0,sizeof(tmp_item)); - tmp_item.nameid = pet_db[i].EggID; + tmp_item.nameid = pet->db[i].EggID; tmp_item.identify = 1; tmp_item.card[0] = CARD0_PET; tmp_item.card[1] = GetWord(pet_id,0); @@ -571,16 +582,12 @@ int pet_get_egg(int account_id,int pet_id,int flag) tmp_item.card[3] = 0; //New pets are not named. if((ret = pc->additem(sd,&tmp_item,1,LOG_TYPE_PICKDROP_PLAYER))) { clif->additem(sd,0,0,ret); - iMap->addflooritem(&tmp_item,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0); + map->addflooritem(&tmp_item,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0); } - return 1; + return true; } -static int pet_unequipitem(struct map_session_data *sd, struct pet_data *pd); -static int pet_food(struct map_session_data *sd, struct pet_data *pd); -static int pet_ai_sub_hard_lootsearch(struct block_list *bl,va_list ap); - int pet_menu(struct map_session_data *sd,int menunum) { struct item_data *egg_id; @@ -589,12 +596,12 @@ int pet_menu(struct map_session_data *sd,int menunum) return 1; //You lost the pet already. - if(!sd->status.pet_id || sd->pd->pet.intimate <= 0 || sd->pd->pet.incuvate) + if(!sd->status.pet_id || sd->pd->pet.intimate <= 0 || sd->pd->pet.incubate) return 1; - egg_id = itemdb_exists(sd->pd->petDB->EggID); + egg_id = itemdb->exists(sd->pd->petDB->EggID); if (egg_id) { - if ((egg_id->flag.trade_restriction&0x01) && !pc->inventoryblank(sd)) { + if ((egg_id->flag.trade_restriction&ITR_NODROP) && !pc->inventoryblank(sd)) { clif->message(sd->fd, msg_txt(451)); // You can't return your pet because your inventory is full. return 1; } @@ -605,16 +612,16 @@ int pet_menu(struct map_session_data *sd,int menunum) clif->send_petstatus(sd); break; case 1: - pet_food(sd, sd->pd); + pet->food(sd, sd->pd); break; case 2: - pet_performance(sd, sd->pd); + pet->performance(sd, sd->pd); break; case 3: - pet_return_egg(sd, sd->pd); + pet->return_egg(sd, sd->pd); break; case 4: - pet_unequipitem(sd, sd->pd); + pet->unequipitem(sd, sd->pd); break; } return 0; @@ -658,8 +665,7 @@ int pet_change_name_ack(struct map_session_data *sd, char* name, int flag) return 1; } -int pet_equipitem(struct map_session_data *sd,int index) -{ +int pet_equipitem(struct map_session_data *sd,int index) { struct pet_data *pd; int nameid; @@ -670,33 +676,31 @@ int pet_equipitem(struct map_session_data *sd,int index) nameid = sd->status.inventory[index].nameid; if(pd->petDB->AcceID == 0 || nameid != pd->petDB->AcceID || pd->pet.equip != 0) { - clif->equipitemack(sd,0,0,0); + clif->equipitemack(sd,0,0,EIA_FAIL); return 1; } pc->delitem(sd,index,1,0,0,LOG_TYPE_OTHER); pd->pet.equip = nameid; - status_set_viewdata(&pd->bl, pd->pet.class_); //Updates view_data. + status->set_viewdata(&pd->bl, pd->pet.class_); //Updates view_data. clif->send_petdata(NULL, sd->pd, 3, sd->pd->vd.head_bottom); - if (battle_config.pet_equip_required) - { //Skotlex: start support timers if need - unsigned int tick = iTimer->gettick(); - if (pd->s_skill && pd->s_skill->timer == INVALID_TIMER) - { + if (battle_config.pet_equip_required) { + //Skotlex: start support timers if need + int64 tick = timer->gettick(); + if (pd->s_skill && pd->s_skill->timer == INVALID_TIMER) { if (pd->s_skill->id) - pd->s_skill->timer=iTimer->add_timer(tick+pd->s_skill->delay*1000, pet_skill_support_timer, sd->bl.id, 0); + pd->s_skill->timer=timer->add(tick+pd->s_skill->delay*1000, pet->skill_support_timer, sd->bl.id, 0); else - pd->s_skill->timer=iTimer->add_timer(tick+pd->s_skill->delay*1000, pet_heal_timer, sd->bl.id, 0); + pd->s_skill->timer=timer->add(tick+pd->s_skill->delay*1000, pet->heal_timer, sd->bl.id, 0); } if (pd->bonus && pd->bonus->timer == INVALID_TIMER) - pd->bonus->timer=iTimer->add_timer(tick+pd->bonus->delay*1000, pet_skill_bonus_timer, sd->bl.id, 0); + pd->bonus->timer=timer->add(tick+pd->bonus->delay*1000, pet->skill_bonus_timer, sd->bl.id, 0); } return 0; } -static int pet_unequipitem(struct map_session_data *sd, struct pet_data *pd) -{ +int pet_unequipitem(struct map_session_data *sd, struct pet_data *pd) { struct item tmp_item; int nameid,flag; @@ -705,33 +709,33 @@ static int pet_unequipitem(struct map_session_data *sd, struct pet_data *pd) nameid = pd->pet.equip; pd->pet.equip = 0; - status_set_viewdata(&pd->bl, pd->pet.class_); + status->set_viewdata(&pd->bl, pd->pet.class_); clif->send_petdata(NULL, sd->pd, 3, sd->pd->vd.head_bottom); memset(&tmp_item,0,sizeof(tmp_item)); tmp_item.nameid = nameid; tmp_item.identify = 1; if((flag = pc->additem(sd,&tmp_item,1,LOG_TYPE_OTHER))) { clif->additem(sd,0,0,flag); - iMap->addflooritem(&tmp_item,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0); + map->addflooritem(&tmp_item,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0); } if( battle_config.pet_equip_required ) { // Skotlex: halt support timers if needed if( pd->state.skillbonus ) { pd->state.skillbonus = 0; - status_calc_pc(sd,0); + status_calc_pc(sd,SCO_NONE); } if( pd->s_skill && pd->s_skill->timer != INVALID_TIMER ) { if( pd->s_skill->id ) - iTimer->delete_timer(pd->s_skill->timer, pet_skill_support_timer); + timer->delete(pd->s_skill->timer, pet->skill_support_timer); else - iTimer->delete_timer(pd->s_skill->timer, pet_heal_timer); + timer->delete(pd->s_skill->timer, pet->heal_timer); pd->s_skill->timer = INVALID_TIMER; } if( pd->bonus && pd->bonus->timer != INVALID_TIMER ) { - iTimer->delete_timer(pd->bonus->timer, pet_skill_bonus_timer); + timer->delete(pd->bonus->timer, pet->skill_bonus_timer); pd->bonus->timer = INVALID_TIMER; } } @@ -739,43 +743,40 @@ static int pet_unequipitem(struct map_session_data *sd, struct pet_data *pd) return 0; } -static int pet_food(struct map_session_data *sd, struct pet_data *pd) -{ - int i,k; +int pet_food(struct map_session_data *sd, struct pet_data *pd) { + int i, food_id; - k=pd->petDB->FoodID; - i=pc->search_inventory(sd,k); - if(i < 0) { - clif->pet_food(sd,k,0); + food_id = pd->petDB->FoodID; + i = pc->search_inventory(sd, food_id); + if(i == INDEX_NOT_FOUND) { + clif->pet_food(sd, food_id, 0); return 1; } pc->delitem(sd,i,1,0,0,LOG_TYPE_CONSUME); - if( pd->pet.hungry > 90 ) - pet_set_intimate(pd, pd->pet.intimate - pd->petDB->r_full); - else - { - if( battle_config.pet_friendly_rate != 100 ) - k = (pd->petDB->r_hungry * battle_config.pet_friendly_rate)/100; + if (pd->pet.hungry > 90) { + pet->set_intimate(pd, pd->pet.intimate - pd->petDB->r_full); + } else { + int add_intimate = 0; + if (battle_config.pet_friendly_rate != 100) + add_intimate = (pd->petDB->r_hungry * battle_config.pet_friendly_rate)/100; else - k = pd->petDB->r_hungry; - if( pd->pet.hungry > 75 ) - { - k = k >> 1; - if( k <= 0 ) - k = 1; + add_intimate = pd->petDB->r_hungry; + if (pd->pet.hungry > 75) { + add_intimate = add_intimate >> 1; + if (add_intimate <= 0) + add_intimate = 1; } - pet_set_intimate(pd, pd->pet.intimate + k); + pet->set_intimate(pd, pd->pet.intimate + add_intimate); } - if( pd->pet.intimate <= 0 ) - { + if (pd->pet.intimate <= 0) { pd->pet.intimate = 0; pet_stop_attack(pd); pd->status.speed = pd->db->status.speed; - } - else if( pd->pet.intimate > 1000 ) + } else if (pd->pet.intimate > 1000) { pd->pet.intimate = 1000; - status_calc_pet(pd, 0); + } + status_calc_pet(pd, SCO_NONE); pd->pet.hungry += pd->petDB->fullness; if( pd->pet.hungry > 100 ) pd->pet.hungry = 100; @@ -787,13 +788,12 @@ static int pet_food(struct map_session_data *sd, struct pet_data *pd) return 0; } -static int pet_randomwalk(struct pet_data *pd,unsigned int tick) -{ +int pet_randomwalk(struct pet_data *pd, int64 tick) { nullpo_ret(pd); Assert((pd->msd == 0) || (pd->msd->pd == pd)); - if(DIFF_TICK(pd->next_walktime,tick) < 0 && unit_can_move(&pd->bl)) { + if(DIFF_TICK(pd->next_walktime,tick) < 0 && unit->can_move(&pd->bl)) { const int retrycount=20; int i,x,y,c,d=12-pd->move_fail_count; if(d<5) d=5; @@ -801,7 +801,7 @@ static int pet_randomwalk(struct pet_data *pd,unsigned int tick) int r=rnd(); x=pd->bl.x+r%(d*2+1)-d; y=pd->bl.y+r/(d*2+1)%(d*2+1)-d; - if(iMap->getcell(pd->bl.m,x,y,CELL_CHKPASS) && unit_walktoxy(&pd->bl,x,y,0)){ + if(map->getcell(pd->bl.m,x,y,CELL_CHKPASS) && unit->walktoxy(&pd->bl,x,y,0)) { pd->move_fail_count=0; break; } @@ -817,7 +817,7 @@ static int pet_randomwalk(struct pet_data *pd,unsigned int tick) } for(i=c=0;i<pd->ud.walkpath.path_len;i++){ if(pd->ud.walkpath.path[i]&1) - c+=pd->status.speed*14/10; + c+=pd->status.speed*MOVE_DIAGONAL_COST/MOVE_COST; else c+=pd->status.speed; } @@ -828,8 +828,7 @@ static int pet_randomwalk(struct pet_data *pd,unsigned int tick) return 0; } -static int pet_ai_sub_hard(struct pet_data *pd, struct map_session_data *sd, unsigned int tick) -{ +int pet_ai_sub_hard(struct pet_data *pd, struct map_session_data *sd, int64 tick) { struct block_list *target = NULL; if(pd->bl.prev == NULL || sd == NULL || sd->bl.prev == NULL) @@ -847,14 +846,14 @@ static int pet_ai_sub_hard(struct pet_data *pd, struct map_session_data *sd, uns if(pd->pet.intimate <= 0) { //Pet should just... well, random walk. - pet_randomwalk(pd,tick); + pet->randomwalk(pd,tick); return 0; } if (!check_distance_bl(&sd->bl, &pd->bl, pd->db->range3)) { //Master too far, chase. if(pd->target_id) - pet_unlocktarget(pd); + pet->unlocktarget(pd); if(pd->ud.walktimer != INVALID_TIMER && pd->ud.target == sd->bl.id) return 0; //Already walking to him if (DIFF_TICK(tick, pd->ud.canmove_tick) < 0) @@ -862,8 +861,8 @@ static int pet_ai_sub_hard(struct pet_data *pd, struct map_session_data *sd, uns pd->status.speed = (sd->battle_status.speed>>1); if(pd->status.speed <= 0) pd->status.speed = 1; - if (!unit_walktobl(&pd->bl, &sd->bl, 3, 0)) - pet_randomwalk(pd,tick); + if (!unit->walktobl(&pd->bl, &sd->bl, 3, 0)) + pet->randomwalk(pd,tick); return 0; } @@ -876,18 +875,18 @@ static int pet_ai_sub_hard(struct pet_data *pd, struct map_session_data *sd, uns } if (pd->target_id) { - target= iMap->id2bl(pd->target_id); - if (!target || pd->bl.m != target->m || status_isdead(target) || - !check_distance_bl(&pd->bl, target, pd->db->range3)) - { + target= map->id2bl(pd->target_id); + if (!target || pd->bl.m != target->m || status->isdead(target) + || !check_distance_bl(&pd->bl, target, pd->db->range3) + ) { target = NULL; - pet_unlocktarget(pd); + pet->unlocktarget(pd); } } if(!target && pd->loot && pd->msd && pc_has_permission(pd->msd, PC_PERM_TRADE) && pd->loot->count < pd->loot->max && DIFF_TICK(tick,pd->ud.canact_tick)>0) { //Use half the pet's range of sight. - iMap->foreachinrange(pet_ai_sub_hard_lootsearch,&pd->bl, + map->foreachinrange(pet->ai_sub_hard_lootsearch,&pd->bl, pd->db->range2/2, BL_ITEM,pd,&target); } @@ -899,9 +898,9 @@ static int pet_ai_sub_hard(struct pet_data *pd, struct map_session_data *sd, uns if(pd->ud.walktimer != INVALID_TIMER && check_distance_blxy(&sd->bl, pd->ud.to_x,pd->ud.to_y, 3)) return 0; //Already walking to him - unit_calc_pos(&pd->bl, sd->bl.x, sd->bl.y, sd->ud.dir); - if(!unit_walktoxy(&pd->bl,pd->ud.to_x,pd->ud.to_y,0)) - pet_randomwalk(pd,tick); + unit->calc_pos(&pd->bl, sd->bl.x, sd->bl.y, sd->ud.dir); + if(!unit->walktoxy(&pd->bl,pd->ud.to_x,pd->ud.to_y,0)) + pet->randomwalk(pd,tick); return 0; } @@ -910,53 +909,51 @@ static int pet_ai_sub_hard(struct pet_data *pd, struct map_session_data *sd, uns (pd->ud.attacktimer != INVALID_TIMER || pd->ud.walktimer != INVALID_TIMER)) return 0; //Target already locked. - if (target->type != BL_ITEM) + if (target->type != BL_ITEM) { //enemy targetted if(!battle->check_range(&pd->bl,target,pd->status.rhw.range)) { //Chase - if(!unit_walktobl(&pd->bl, target, pd->status.rhw.range, 2)) - pet_unlocktarget(pd); //Unreachable target. + if(!unit->walktobl(&pd->bl, target, pd->status.rhw.range, 2)) + pet->unlocktarget(pd); //Unreachable target. return 0; } //Continuous attack. - unit_attack(&pd->bl, pd->target_id, 1); + unit->attack(&pd->bl, pd->target_id, 1); } else { //Item Targeted, attempt loot if (!check_distance_bl(&pd->bl, target, 1)) { //Out of range - if(!unit_walktobl(&pd->bl, target, 1, 1)) //Unreachable target. - pet_unlocktarget(pd); + if(!unit->walktobl(&pd->bl, target, 1, 1)) //Unreachable target. + pet->unlocktarget(pd); return 0; } else{ struct flooritem_data *fitem = (struct flooritem_data *)target; if(pd->loot->count < pd->loot->max){ memcpy(&pd->loot->item[pd->loot->count++],&fitem->item_data,sizeof(pd->loot->item[0])); pd->loot->weight += itemdb_weight(fitem->item_data.nameid)*fitem->item_data.amount; - iMap->clearflooritem(target); - } + map->clearflooritem(target); + } //Target is unlocked regardless of whether it was picked or not. - pet_unlocktarget(pd); + pet->unlocktarget(pd); } } return 0; } -static int pet_ai_sub_foreachclient(struct map_session_data *sd,va_list ap) -{ - unsigned int tick = va_arg(ap,unsigned int); +int pet_ai_sub_foreachclient(struct map_session_data *sd,va_list ap) { + int64 tick = va_arg(ap,int64); if(sd->status.pet_id && sd->pd) - pet_ai_sub_hard(sd->pd,sd,tick); + pet->ai_sub_hard(sd->pd,sd,tick); return 0; } -static int pet_ai_hard(int tid, unsigned int tick, int id, intptr_t data) -{ - iMap->map_foreachpc(pet_ai_sub_foreachclient,tick); +int pet_ai_hard(int tid, int64 tick, int id, intptr_t data) { + map->foreachpc(pet->ai_sub_foreachclient,tick); return 0; } -static int pet_ai_sub_hard_lootsearch(struct block_list *bl,va_list ap) +int pet_ai_sub_hard_lootsearch(struct block_list *bl,va_list ap) { struct pet_data* pd; struct flooritem_data *fitem = (struct flooritem_data *)bl; @@ -971,7 +968,7 @@ static int pet_ai_sub_hard_lootsearch(struct block_list *bl,va_list ap) if(sd_charid && sd_charid != pd->msd->status.char_id) return 0; - if(unit_can_reach_bl(&pd->bl,bl, pd->db->range2, 1, NULL, NULL) && + if(unit->can_reach_bl(&pd->bl,bl, pd->db->range2, 1, NULL, NULL) && ((*target) == NULL || //New target closer than previous one. !check_distance_bl(&pd->bl, *target, distance_bl(&pd->bl, bl)))) { @@ -983,21 +980,20 @@ static int pet_ai_sub_hard_lootsearch(struct block_list *bl,va_list ap) return 0; } -static int pet_delay_item_drop(int tid, unsigned int tick, int id, intptr_t data) -{ +int pet_delay_item_drop(int tid, int64 tick, int id, intptr_t data) { struct item_drop_list *list; struct item_drop *ditem, *ditem_prev; list=(struct item_drop_list *)data; ditem = list->item; while (ditem) { - iMap->addflooritem(&ditem->item_data,ditem->item_data.amount, + map->addflooritem(&ditem->item_data,ditem->item_data.amount, list->m,list->x,list->y, list->first_charid,list->second_charid,list->third_charid,0); ditem_prev = ditem; ditem = ditem->next; - ers_free(item_drop_ers, ditem_prev); + ers_free(pet->item_drop_ers, ditem_prev); } - ers_free(item_drop_list_ers, list); + ers_free(pet->item_drop_list_ers, list); return 0; } @@ -1009,7 +1005,7 @@ int pet_lootitem_drop(struct pet_data *pd,struct map_session_data *sd) struct item *it; if(!pd || !pd->loot || !pd->loot->count) return 0; - dlist = ers_alloc(item_drop_list_ers, struct item_drop_list); + dlist = ers_alloc(pet->item_drop_list_ers, struct item_drop_list); dlist->m = pd->bl.m; dlist->x = pd->bl.x; dlist->y = pd->bl.y; @@ -1023,14 +1019,14 @@ int pet_lootitem_drop(struct pet_data *pd,struct map_session_data *sd) if(sd){ if((flag = pc->additem(sd,it,it->amount,LOG_TYPE_PICKDROP_PLAYER))){ clif->additem(sd,0,0,flag); - ditem = ers_alloc(item_drop_ers, struct item_drop); + ditem = ers_alloc(pet->item_drop_ers, struct item_drop); memcpy(&ditem->item_data, it, sizeof(struct item)); ditem->next = dlist->item; dlist->item = ditem; } } else { - ditem = ers_alloc(item_drop_ers, struct item_drop); + ditem = ers_alloc(pet->item_drop_ers, struct item_drop); memcpy(&ditem->item_data, it, sizeof(struct item)); ditem->next = dlist->item; dlist->item = ditem; @@ -1040,30 +1036,29 @@ int pet_lootitem_drop(struct pet_data *pd,struct map_session_data *sd) memset(pd->loot->item,0,pd->loot->max * sizeof(struct item)); pd->loot->count = 0; pd->loot->weight = 0; - pd->ud.canact_tick = iTimer->gettick()+10000; //prevent picked up during 10*1000ms + pd->ud.canact_tick = timer->gettick()+10000; //prevent picked up during 10*1000ms if (dlist->item) - iTimer->add_timer(iTimer->gettick()+540,pet_delay_item_drop,0,(intptr_t)dlist); + timer->add(timer->gettick()+540,pet->delay_item_drop,0,(intptr_t)dlist); else - ers_free(item_drop_list_ers, dlist); + ers_free(pet->item_drop_list_ers, dlist); return 1; } /*========================================== * pet bonus giving skills [Valaris] / Rewritten by [Skotlex] - *------------------------------------------*/ -int pet_skill_bonus_timer(int tid, unsigned int tick, int id, intptr_t data) -{ - struct map_session_data *sd=iMap->id2sd(id); + *------------------------------------------*/ +int pet_skill_bonus_timer(int tid, int64 tick, int id, intptr_t data) { + struct map_session_data *sd=map->id2sd(id); struct pet_data *pd; int bonus; - int timer = 0; - + int duration = 0; + if(sd == NULL || sd->pd==NULL || sd->pd->bonus == NULL) return 1; pd=sd->pd; - + if(pd->bonus->timer != tid) { ShowError("pet_skill_bonus_timer %d != %d\n",pd->bonus->timer,tid); pd->bonus->timer = INVALID_TIMER; @@ -1073,30 +1068,29 @@ int pet_skill_bonus_timer(int tid, unsigned int tick, int id, intptr_t data) // determine the time for the next timer if (pd->state.skillbonus && pd->bonus->delay > 0) { bonus = 0; - timer = pd->bonus->delay*1000; // the duration until pet bonuses will be reactivated again + duration = pd->bonus->delay*1000; // the duration until pet bonuses will be reactivated again } else if (pd->pet.intimate) { bonus = 1; - timer = pd->bonus->duration*1000; // the duration for pet bonuses to be in effect + duration = pd->bonus->duration*1000; // the duration for pet bonuses to be in effect } else { //Lost pet... pd->bonus->timer = INVALID_TIMER; return 0; } - + if (pd->state.skillbonus != bonus) { pd->state.skillbonus = bonus; - status_calc_pc(sd, 0); + status_calc_pc(sd, SCO_NONE); } // wait for the next timer - pd->bonus->timer=iTimer->add_timer(tick+timer,pet_skill_bonus_timer,sd->bl.id,0); + pd->bonus->timer=timer->add(tick+duration,pet->skill_bonus_timer,sd->bl.id,0); return 0; } /*========================================== * pet recovery skills [Valaris] / Rewritten by [Skotlex] - *------------------------------------------*/ -int pet_recovery_timer(int tid, unsigned int tick, int id, intptr_t data) -{ - struct map_session_data *sd=iMap->id2sd(id); + *------------------------------------------*/ +int pet_recovery_timer(int tid, int64 tick, int id, intptr_t data) { + struct map_session_data *sd=map->id2sd(id); struct pet_data *pd; if(sd==NULL || sd->pd == NULL || sd->pd->recovery == NULL) @@ -1110,7 +1104,7 @@ int pet_recovery_timer(int tid, unsigned int tick, int id, intptr_t data) } if(sd->sc.data[pd->recovery->type]) - { //Display a heal animation? + { //Display a heal animation? //Detoxify is chosen for now. clif->skill_nodamage(&pd->bl,&sd->bl,TF_DETOXIFY,1,1); status_change_end(&sd->bl, pd->recovery->type, INVALID_TIMER); @@ -1122,10 +1116,9 @@ int pet_recovery_timer(int tid, unsigned int tick, int id, intptr_t data) return 0; } -int pet_heal_timer(int tid, unsigned int tick, int id, intptr_t data) -{ - struct map_session_data *sd=iMap->id2sd(id); - struct status_data *status; +int pet_heal_timer(int tid, int64 tick, int id, intptr_t data) { + struct map_session_data *sd=map->id2sd(id); + struct status_data *st; struct pet_data *pd; unsigned int rate = 100; @@ -1139,32 +1132,31 @@ int pet_heal_timer(int tid, unsigned int tick, int id, intptr_t data) return 0; } - status = status_get_status_data(&sd->bl); + st = status->get_status_data(&sd->bl); if(pc_isdead(sd) || - (rate = get_percentage(status->sp, status->max_sp)) > pd->s_skill->sp || - (rate = get_percentage(status->hp, status->max_hp)) > pd->s_skill->hp || + (rate = get_percentage(st->sp, st->max_sp)) > pd->s_skill->sp || + (rate = get_percentage(st->hp, st->max_hp)) > pd->s_skill->hp || (rate = (pd->ud.skilltimer != INVALID_TIMER)) //Another skill is in effect ) { //Wait (how long? 1 sec for every 10% of remaining) - pd->s_skill->timer=iTimer->add_timer(iTimer->gettick()+(rate>10?rate:10)*100,pet_heal_timer,sd->bl.id,0); + pd->s_skill->timer=timer->add(timer->gettick()+(rate>10?rate:10)*100,pet->heal_timer,sd->bl.id,0); return 0; } pet_stop_attack(pd); pet_stop_walking(pd,1); clif->skill_nodamage(&pd->bl,&sd->bl,AL_HEAL,pd->s_skill->lv,1); - status_heal(&sd->bl, pd->s_skill->lv,0, 0); - pd->s_skill->timer=iTimer->add_timer(tick+pd->s_skill->delay*1000,pet_heal_timer,sd->bl.id,0); + status->heal(&sd->bl, pd->s_skill->lv,0, 0); + pd->s_skill->timer=timer->add(tick+pd->s_skill->delay*1000,pet->heal_timer,sd->bl.id,0); return 0; } /*========================================== * pet support skills [Skotlex] - *------------------------------------------*/ -int pet_skill_support_timer(int tid, unsigned int tick, int id, intptr_t data) -{ - struct map_session_data *sd=iMap->id2sd(id); + *------------------------------------------*/ +int pet_skill_support_timer(int tid, int64 tick, int id, intptr_t data) { + struct map_session_data *sd=map->id2sd(id); struct pet_data *pd; - struct status_data *status; + struct status_data *st; short rate = 100; if(sd==NULL || sd->pd == NULL || sd->pd->s_skill == NULL) return 1; @@ -1176,80 +1168,77 @@ int pet_skill_support_timer(int tid, unsigned int tick, int id, intptr_t data) return 0; } - status = status_get_status_data(&sd->bl); + st = status->get_status_data(&sd->bl); if (DIFF_TICK(pd->ud.canact_tick, tick) > 0) { //Wait until the pet can act again. - pd->s_skill->timer=iTimer->add_timer(pd->ud.canact_tick,pet_skill_support_timer,sd->bl.id,0); + pd->s_skill->timer=timer->add(pd->ud.canact_tick,pet->skill_support_timer,sd->bl.id,0); return 0; } if(pc_isdead(sd) || - (rate = get_percentage(status->sp, status->max_sp)) > pd->s_skill->sp || - (rate = get_percentage(status->hp, status->max_hp)) > pd->s_skill->hp || + (rate = get_percentage(st->sp, st->max_sp)) > pd->s_skill->sp || + (rate = get_percentage(st->hp, st->max_hp)) > pd->s_skill->hp || (rate = (pd->ud.skilltimer != INVALID_TIMER)) //Another skill is in effect ) { //Wait (how long? 1 sec for every 10% of remaining) - pd->s_skill->timer=iTimer->add_timer(tick+(rate>10?rate:10)*100,pet_skill_support_timer,sd->bl.id,0); + pd->s_skill->timer=timer->add(tick+(rate>10?rate:10)*100,pet->skill_support_timer,sd->bl.id,0); return 0; } pet_stop_attack(pd); pet_stop_walking(pd,1); - pd->s_skill->timer=iTimer->add_timer(tick+pd->s_skill->delay*1000,pet_skill_support_timer,sd->bl.id,0); + pd->s_skill->timer=timer->add(tick+pd->s_skill->delay*1000,pet->skill_support_timer,sd->bl.id,0); if (skill->get_inf(pd->s_skill->id) & INF_GROUND_SKILL) - unit_skilluse_pos(&pd->bl, sd->bl.x, sd->bl.y, pd->s_skill->id, pd->s_skill->lv); + unit->skilluse_pos(&pd->bl, sd->bl.x, sd->bl.y, pd->s_skill->id, pd->s_skill->lv); else - unit_skilluse_id(&pd->bl, sd->bl.id, pd->s_skill->id, pd->s_skill->lv); + unit->skilluse_id(&pd->bl, sd->bl.id, pd->s_skill->id, pd->s_skill->lv); return 0; } /*========================================== * Pet read db data - * pet_db.txt - * pet_db2.txt - *------------------------------------------*/ + * pet->db.txt + * pet->db2.txt + *------------------------------------------*/ int read_petdb() { char* filename[] = {"pet_db.txt","pet_db2.txt"}; FILE *fp; - int nameid,i,j,k; + int nameid,i,j,k; // Remove any previous scripts in case reloaddb was invoked. for( j = 0; j < MAX_PET_DB; j++ ) { - if( pet_db[j].pet_script ) + if( pet->db[j].pet_script ) { - script_free_code(pet_db[j].pet_script); - pet_db[j].pet_script = NULL; + script->free_code(pet->db[j].pet_script); + pet->db[j].pet_script = NULL; } - if( pet_db[j].equip_script ) + if( pet->db[j].equip_script ) { - script_free_code(pet_db[j].equip_script); - pet_db[j].pet_script = NULL; + script->free_code(pet->db[j].equip_script); + pet->db[j].pet_script = NULL; } } // clear database - memset(pet_db,0,sizeof(pet_db)); + memset(pet->db,0,sizeof(pet->db)); j = 0; // entry counter - for( i = 0; i < ARRAYLENGTH(filename); i++ ) - { + for( i = 0; i < ARRAYLENGTH(filename); i++ ) { char line[1024]; int lines, entries; - sprintf(line, "%s/%s", iMap->db_path, filename[i]); + sprintf(line, "%s/%s", map->db_path, filename[i]); fp=fopen(line,"r"); - if( fp == NULL ) - { + if( fp == NULL ) { if( i == 0 ) ShowError("can't read %s\n",line); continue; } lines = entries = 0; - while( fgets(line, sizeof(line), fp) && j < MAX_PET_DB ) - { + while( fgets(line, sizeof(line), fp) && j < MAX_PET_DB ) { char *str[22], *p; lines++; @@ -1305,41 +1294,41 @@ int read_petdb() if( (nameid = atoi(str[0])) <= 0 ) continue; - if( !mobdb_checkid(nameid) ) + if( !mob->db_checkid(nameid) ) { ShowWarning("pet_db reading: Invalid mob-class %d, pet not read.\n", nameid); continue; } - pet_db[j].class_ = nameid; - safestrncpy(pet_db[j].name,str[1],NAME_LENGTH); - safestrncpy(pet_db[j].jname,str[2],NAME_LENGTH); - pet_db[j].itemID=atoi(str[3]); - pet_db[j].EggID=atoi(str[4]); - pet_db[j].AcceID=atoi(str[5]); - pet_db[j].FoodID=atoi(str[6]); - pet_db[j].fullness=atoi(str[7]); - pet_db[j].hungry_delay=atoi(str[8])*1000; - pet_db[j].r_hungry=atoi(str[9]); - if( pet_db[j].r_hungry <= 0 ) - pet_db[j].r_hungry=1; - pet_db[j].r_full=atoi(str[10]); - pet_db[j].intimate=atoi(str[11]); - pet_db[j].die=atoi(str[12]); - pet_db[j].capture=atoi(str[13]); - pet_db[j].speed=atoi(str[14]); - pet_db[j].s_perfor=(char)atoi(str[15]); - pet_db[j].talk_convert_class=atoi(str[16]); - pet_db[j].attack_rate=atoi(str[17]); - pet_db[j].defence_attack_rate=atoi(str[18]); - pet_db[j].change_target_rate=atoi(str[19]); - pet_db[j].pet_script = NULL; - pet_db[j].equip_script = NULL; + pet->db[j].class_ = nameid; + safestrncpy(pet->db[j].name,str[1],NAME_LENGTH); + safestrncpy(pet->db[j].jname,str[2],NAME_LENGTH); + pet->db[j].itemID=atoi(str[3]); + pet->db[j].EggID=atoi(str[4]); + pet->db[j].AcceID=atoi(str[5]); + pet->db[j].FoodID=atoi(str[6]); + pet->db[j].fullness=atoi(str[7]); + pet->db[j].hungry_delay=atoi(str[8])*1000; + pet->db[j].r_hungry=atoi(str[9]); + if( pet->db[j].r_hungry <= 0 ) + pet->db[j].r_hungry=1; + pet->db[j].r_full=atoi(str[10]); + pet->db[j].intimate=atoi(str[11]); + pet->db[j].die=atoi(str[12]); + pet->db[j].capture=atoi(str[13]); + pet->db[j].speed=atoi(str[14]); + pet->db[j].s_perfor=(char)atoi(str[15]); + pet->db[j].talk_convert_class=atoi(str[16]); + pet->db[j].attack_rate=atoi(str[17]); + pet->db[j].defence_attack_rate=atoi(str[18]); + pet->db[j].change_target_rate=atoi(str[19]); + pet->db[j].pet_script = NULL; + pet->db[j].equip_script = NULL; if( *str[20] ) - pet_db[j].pet_script = parse_script(str[20], filename[i], lines, 0); + pet->db[j].pet_script = script->parse(str[20], filename[i], lines, 0, NULL); if( *str[21] ) - pet_db[j].equip_script = parse_script(str[21], filename[i], lines, 0); + pet->db[j].equip_script = script->parse(str[21], filename[i], lines, 0, NULL); j++; entries++; @@ -1356,21 +1345,23 @@ int read_petdb() /*========================================== * Initialization process relationship skills *------------------------------------------*/ -int do_init_pet(void) -{ - read_petdb(); +int do_init_pet(bool minimal) { + if (minimal) + return 0; - item_drop_ers = ers_new(sizeof(struct item_drop),"pet.c::item_drop_ers",ERS_OPT_NONE); - item_drop_list_ers = ers_new(sizeof(struct item_drop_list),"pet.c::item_drop_list_ers",ERS_OPT_NONE); + pet->read_db(); + + pet->item_drop_ers = ers_new(sizeof(struct item_drop),"pet.c::item_drop_ers",ERS_OPT_NONE); + pet->item_drop_list_ers = ers_new(sizeof(struct item_drop_list),"pet.c::item_drop_list_ers",ERS_OPT_NONE); - iTimer->add_timer_func_list(pet_hungry,"pet_hungry"); - iTimer->add_timer_func_list(pet_ai_hard,"pet_ai_hard"); - iTimer->add_timer_func_list(pet_skill_bonus_timer,"pet_skill_bonus_timer"); // [Valaris] - iTimer->add_timer_func_list(pet_delay_item_drop,"pet_delay_item_drop"); - iTimer->add_timer_func_list(pet_skill_support_timer, "pet_skill_support_timer"); // [Skotlex] - iTimer->add_timer_func_list(pet_recovery_timer,"pet_recovery_timer"); // [Valaris] - iTimer->add_timer_func_list(pet_heal_timer,"pet_heal_timer"); // [Valaris] - iTimer->add_timer_interval(iTimer->gettick()+MIN_PETTHINKTIME,pet_ai_hard,0,0,MIN_PETTHINKTIME); + timer->add_func_list(pet->hungry,"pet_hungry"); + timer->add_func_list(pet->ai_hard,"pet_ai_hard"); + timer->add_func_list(pet->skill_bonus_timer,"pet_skill_bonus_timer"); // [Valaris] + timer->add_func_list(pet->delay_item_drop,"pet_delay_item_drop"); + timer->add_func_list(pet->skill_support_timer, "pet_skill_support_timer"); // [Skotlex] + timer->add_func_list(pet->recovery_timer,"pet_recovery_timer"); // [Valaris] + timer->add_func_list(pet->heal_timer,"pet_heal_timer"); // [Valaris] + timer->add_interval(timer->gettick()+MIN_PETTHINKTIME,pet->ai_hard,0,0,MIN_PETTHINKTIME); return 0; } @@ -1380,18 +1371,68 @@ int do_final_pet(void) int i; for( i = 0; i < MAX_PET_DB; i++ ) { - if( pet_db[i].pet_script ) + if( pet->db[i].pet_script ) { - script_free_code(pet_db[i].pet_script); - pet_db[i].pet_script = NULL; + script->free_code(pet->db[i].pet_script); + pet->db[i].pet_script = NULL; } - if( pet_db[i].equip_script ) + if( pet->db[i].equip_script ) { - script_free_code(pet_db[i].equip_script); - pet_db[i].equip_script = NULL; + script->free_code(pet->db[i].equip_script); + pet->db[i].equip_script = NULL; } } - ers_destroy(item_drop_ers); - ers_destroy(item_drop_list_ers); + ers_destroy(pet->item_drop_ers); + ers_destroy(pet->item_drop_list_ers); return 0; } +void pet_defaults(void) { + pet = &pet_s; + + memset(pet->db,0,sizeof(pet->db)); + pet->item_drop_ers = NULL; + pet->item_drop_list_ers = NULL; + + /* */ + pet->init = do_init_pet; + pet->final = do_final_pet; + + /* */ + pet->hungry_val = pet_hungry_val; + pet->set_intimate = pet_set_intimate; + pet->create_egg = pet_create_egg; + pet->unlocktarget = pet_unlocktarget; + pet->attackskill = pet_attackskill; + pet->target_check = pet_target_check; + pet->sc_check = pet_sc_check; + pet->hungry = pet_hungry; + pet->search_petDB_index = search_petDB_index; + pet->hungry_timer_delete = pet_hungry_timer_delete; + pet->performance = pet_performance; + pet->return_egg = pet_return_egg; + pet->data_init = pet_data_init; + pet->birth_process = pet_birth_process; + pet->recv_petdata = pet_recv_petdata; + pet->select_egg = pet_select_egg; + pet->catch_process1 = pet_catch_process1; + pet->catch_process2 = pet_catch_process2; + pet->get_egg = pet_get_egg; + pet->unequipitem = pet_unequipitem; + pet->food = pet_food; + pet->ai_sub_hard_lootsearch = pet_ai_sub_hard_lootsearch; + pet->menu = pet_menu; + pet->change_name = pet_change_name; + pet->change_name_ack = pet_change_name_ack; + pet->equipitem = pet_equipitem; + pet->randomwalk = pet_randomwalk; + pet->ai_sub_hard = pet_ai_sub_hard; + pet->ai_sub_foreachclient = pet_ai_sub_foreachclient; + pet->ai_hard = pet_ai_hard; + pet->delay_item_drop = pet_delay_item_drop; + pet->lootitem_drop = pet_lootitem_drop; + pet->skill_bonus_timer = pet_skill_bonus_timer; + pet->recovery_timer = pet_recovery_timer; + pet->heal_timer = pet_heal_timer; + pet->skill_support_timer = pet_skill_support_timer; + pet->read_db = read_petdb; +} diff --git a/src/map/pet.h b/src/map/pet.h index b46f55229..5c890ef85 100644 --- a/src/map/pet.h +++ b/src/map/pet.h @@ -1,11 +1,18 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder +// Copyright (c) Hercules Dev Team, licensed under GNU GPL. +// See the LICENSE file +// Portions Copyright (c) Athena Dev Teams -#ifndef _PET_H_ -#define _PET_H_ +#ifndef MAP_PET_H +#define MAP_PET_H -#define MAX_PET_DB 300 -#define MAX_PETLOOT_SIZE 30 +#include "map.h" // struct block_list +#include "status.h" // enum sc_type +#include "unit.h" // struct unit_data +#include "../common/cbasetypes.h" +#include "../common/mmo.h" // NAME_LENGTH, struct s_pet + +#define MAX_PET_DB 300 +#define MAX_PETLOOT_SIZE 30 struct s_pet_db { short class_; @@ -30,7 +37,6 @@ struct s_pet_db { struct script_code *equip_script; struct script_code *pet_script; }; -extern struct s_pet_db pet_db[MAX_PET_DB]; enum { PET_CLASS,PET_CATCH,PET_EGG,PET_EQUIP,PET_FOOD }; @@ -86,7 +92,7 @@ struct pet_data { unsigned skillbonus : 1; } state; int move_fail_count; - unsigned int next_walktime,last_thinktime; + int64 next_walktime, last_thinktime; short rate_fix; //Support rate as modified by intimacy (1000 = 100%) [Skotlex] struct pet_recovery* recovery; @@ -98,39 +104,58 @@ struct pet_data { struct map_session_data *msd; }; +#define pet_stop_walking(pd, type) (unit->stop_walking(&(pd)->bl, (type))) +#define pet_stop_attack(pd) (unit->stop_attack(&(pd)->bl)) + +struct pet_interface { + struct s_pet_db db[MAX_PET_DB]; + struct eri *item_drop_ers; //For loot drops delay structures. + struct eri *item_drop_list_ers; + /* */ + int (*init) (bool minimal); + int (*final) (void); + /* */ + int (*hungry_val) (struct pet_data *pd); + void (*set_intimate) (struct pet_data *pd, int value); + int (*create_egg) (struct map_session_data *sd, int item_id); + int (*unlocktarget) (struct pet_data *pd); + int (*attackskill) (struct pet_data *pd, int target_id); + int (*target_check) (struct map_session_data *sd, struct block_list *bl, int type); + int (*sc_check) (struct map_session_data *sd, int type); + int (*hungry) (int tid, int64 tick, int id, intptr_t data); + int (*search_petDB_index) (int key, int type); + int (*hungry_timer_delete) (struct pet_data *pd); + int (*performance) (struct map_session_data *sd, struct pet_data *pd); + int (*return_egg) (struct map_session_data *sd, struct pet_data *pd); + int (*data_init) (struct map_session_data *sd, struct s_pet *petinfo); + int (*birth_process) (struct map_session_data *sd, struct s_pet *petinfo); + int (*recv_petdata) (int account_id, struct s_pet *p, int flag); + int (*select_egg) (struct map_session_data *sd, short egg_index); + int (*catch_process1) (struct map_session_data *sd, int target_class); + int (*catch_process2) (struct map_session_data *sd, int target_id); + bool (*get_egg) (int account_id, short pet_class, int pet_id ); + int (*unequipitem) (struct map_session_data *sd, struct pet_data *pd); + int (*food) (struct map_session_data *sd, struct pet_data *pd); + int (*ai_sub_hard_lootsearch) (struct block_list *bl, va_list ap); + int (*menu) (struct map_session_data *sd, int menunum); + int (*change_name) (struct map_session_data *sd, char *name); + int (*change_name_ack) (struct map_session_data *sd, char *name, int flag); + int (*equipitem) (struct map_session_data *sd, int index); + int (*randomwalk) (struct pet_data *pd, int64 tick); + int (*ai_sub_hard) (struct pet_data *pd, struct map_session_data *sd, int64 tick); + int (*ai_sub_foreachclient) (struct map_session_data *sd, va_list ap); + int (*ai_hard) (int tid, int64 tick, int id, intptr_t data); + int (*delay_item_drop) (int tid, int64 tick, int id, intptr_t data); + int (*lootitem_drop) (struct pet_data *pd, struct map_session_data *sd); + int (*skill_bonus_timer) (int tid, int64 tick, int id, intptr_t data); + int (*recovery_timer) (int tid, int64 tick, int id, intptr_t data); + int (*heal_timer) (int tid, int64 tick, int id, intptr_t data); + int (*skill_support_timer) (int tid, int64 tick, int id, intptr_t data); + int (*read_db) (); +}; + +struct pet_interface *pet; +void pet_defaults(void); -int pet_create_egg(struct map_session_data *sd, int item_id); -int pet_hungry_val(struct pet_data *pd); -void pet_set_intimate(struct pet_data *pd, int value); -int pet_target_check(struct map_session_data *sd,struct block_list *bl,int type); -int pet_unlocktarget(struct pet_data *pd); -int pet_sc_check(struct map_session_data *sd, int type); //Skotlex -int search_petDB_index(int key,int type); -int pet_hungry_timer_delete(struct pet_data *pd); -int pet_data_init(struct map_session_data *sd, struct s_pet *pet); -int pet_birth_process(struct map_session_data *sd, struct s_pet *pet); -int pet_recv_petdata(int account_id,struct s_pet *p,int flag); -int pet_select_egg(struct map_session_data *sd,short egg_index); -int pet_catch_process1(struct map_session_data *sd,int target_class); -int pet_catch_process2(struct map_session_data *sd,int target_id); -int pet_get_egg(int account_id,int pet_id,int flag); -int pet_menu(struct map_session_data *sd,int menunum); -int pet_change_name(struct map_session_data *sd,char *name); -int pet_change_name_ack(struct map_session_data *sd, char* name, int flag); -int pet_equipitem(struct map_session_data *sd,int index); -int pet_lootitem_drop(struct pet_data *pd,struct map_session_data *sd); -int pet_attackskill(struct pet_data *pd, int target_id); -int pet_skill_support_timer(int tid, unsigned int tick, int id, intptr_t data); // [Skotlex] -int pet_skill_bonus_timer(int tid, unsigned int tick, int id, intptr_t data); // [Valaris] -int pet_recovery_timer(int tid, unsigned int tick, int id, intptr_t data); // [Valaris] -int pet_heal_timer(int tid, unsigned int tick, int id, intptr_t data); // [Valaris] - -#define pet_stop_walking(pd, type) unit_stop_walking(&(pd)->bl, type) -#define pet_stop_attack(pd) unit_stop_attack(&(pd)->bl) - -int read_petdb(void); -int do_init_pet(void); -int do_final_pet(void); - -#endif /* _PET_H_ */ +#endif /* MAP_PET_H */ diff --git a/src/map/quest.c b/src/map/quest.c index b56088886..b76d6bc82 100644 --- a/src/map/quest.c +++ b/src/map/quest.c @@ -1,246 +1,305 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder +// Copyright (c) Hercules Dev Team, licensed under GNU GPL. +// See the LICENSE file +// Portions Copyright (c) Athena Dev Teams -#include "../common/cbasetypes.h" -#include "../common/socket.h" -#include "../common/timer.h" -#include "../common/malloc.h" -#include "../common/nullpo.h" -#include "../common/showmsg.h" -#include "../common/strlib.h" -#include "../common/utils.h" +#define HERCULES_CORE -#include "map.h" -#include "pc.h" -#include "npc.h" -#include "itemdb.h" -#include "script.h" -#include "intif.h" -#include "battle.h" -#include "mob.h" -#include "party.h" -#include "unit.h" -#include "log.h" -#include "clif.h" #include "quest.h" -#include "intif.h" -#include "chrif.h" +#include <stdarg.h> #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <stdarg.h> #include <time.h> +#include "battle.h" +#include "chrif.h" +#include "clif.h" +#include "intif.h" +#include "itemdb.h" +#include "log.h" +#include "map.h" +#include "mob.h" +#include "npc.h" +#include "party.h" +#include "pc.h" +#include "script.h" +#include "unit.h" +#include "../common/cbasetypes.h" +#include "../common/malloc.h" +#include "../common/nullpo.h" +#include "../common/showmsg.h" +#include "../common/socket.h" +#include "../common/strlib.h" +#include "../common/timer.h" +#include "../common/utils.h" -struct s_quest_db quest_db[MAX_QUEST_DB]; - +struct quest_interface quest_s; + +/** + * Searches a quest by ID. + * + * @param quest_id ID to lookup + * @return Quest entry (equals to &quest->dummy if the ID is invalid) + */ +struct quest_db *quest_db(int quest_id) { + if (quest_id < 0 || quest_id > MAX_QUEST_DB || quest->db_data[quest_id] == NULL) + return &quest->dummy; + return quest->db_data[quest_id]; +} -int quest_search_db(int quest_id) -{ +/** + * Sends quest info to the player on login. + * + * @param sd Player's data + * @return 0 in case of success, nonzero otherwise (i.e. the player has no quests) + */ +int quest_pc_login(TBL_PC *sd) { int i; - ARR_FIND(0, MAX_QUEST_DB,i,quest_id == quest_db[i].id); - if( i == MAX_QUEST_DB ) - return -1; - - return i; -} - -//Send quest info on login -int quest_pc_login(TBL_PC * sd) -{ if(sd->avail_quests == 0) return 1; clif->quest_send_list(sd); clif->quest_send_mission(sd); + for( i = 0; i < sd->avail_quests; i++ ) { + // TODO[Haru]: is this necessary? Does quest_send_mission not take care of this? + clif->quest_update_objective(sd, &sd->quest_log[i]); + } return 0; } -int quest_add(TBL_PC * sd, int quest_id) -{ - - int i, j; - - if( sd->num_quests >= MAX_QUEST_DB ) - { - ShowError("quest_add: Character %d has got all the quests.(max quests: %d)\n", sd->status.char_id, MAX_QUEST_DB); - return 1; +/** + * Adds a quest to the player's list. + * + * New quest will be added as Q_ACTIVE. + * + * @param sd Player's data + * @param quest_id ID of the quest to add. + * @return 0 in case of success, nonzero otherwise + */ +int quest_add(TBL_PC *sd, int quest_id) { + int n; + struct quest_db *qi = quest->db(quest_id); + + if( qi == &quest->dummy ) { + ShowError("quest_add: quest %d not found in DB.\n", quest_id); + return -1; } - if( quest_check(sd, quest_id, HAVEQUEST) >= 0 ) - { + if( quest->check(sd, quest_id, HAVEQUEST) >= 0 ) { ShowError("quest_add: Character %d already has quest %d.\n", sd->status.char_id, quest_id); return -1; } - if( (j = quest_search_db(quest_id)) < 0 ) - { - ShowError("quest_add: quest %d not found in DB.\n", quest_id); - return -1; + n = sd->avail_quests; // Insertion point + + sd->num_quests++; + sd->avail_quests++; + RECREATE(sd->quest_log, struct quest, sd->num_quests); + + if( sd->avail_quests != sd->num_quests ) { + // The character has some completed quests, make room before them so that they will stay at the end of the array + memmove(&sd->quest_log[n+1], &sd->quest_log[n], sizeof(struct quest)*(sd->num_quests-sd->avail_quests)); } - i = sd->avail_quests; - memmove(&sd->quest_log[i+1], &sd->quest_log[i], sizeof(struct quest)*(sd->num_quests-sd->avail_quests)); - memmove(sd->quest_index+i+1, sd->quest_index+i, sizeof(int)*(sd->num_quests-sd->avail_quests)); + memset(&sd->quest_log[n], 0, sizeof(struct quest)); - memset(&sd->quest_log[i], 0, sizeof(struct quest)); - sd->quest_log[i].quest_id = quest_db[j].id; - if( quest_db[j].time ) - sd->quest_log[i].time = (unsigned int)(time(NULL) + quest_db[j].time); - sd->quest_log[i].state = Q_ACTIVE; + sd->quest_log[n].quest_id = qi->id; + if( qi->time ) + sd->quest_log[n].time = (unsigned int)(time(NULL) + qi->time); + sd->quest_log[n].state = Q_ACTIVE; - sd->quest_index[i] = j; - sd->num_quests++; - sd->avail_quests++; sd->save_quest = true; - clif->quest_add(sd, &sd->quest_log[i], sd->quest_index[i]); + clif->quest_add(sd, &sd->quest_log[n]); + clif->quest_update_objective(sd, &sd->quest_log[n]); - if( iMap->save_settings&64 ) - chrif_save(sd,0); + if( map->save_settings&64 ) + chrif->save(sd,0); return 0; } -int quest_change(TBL_PC * sd, int qid1, int qid2) -{ - - int i, j; +/** + * Replaces a quest in a player's list with another one. + * + * @param sd Player's data + * @param qid1 Current quest to replace + * @param qid2 New quest to add + * @return 0 in case of success, nonzero otherwise + */ +int quest_change(TBL_PC *sd, int qid1, int qid2) { + int i; + struct quest_db *qi = quest->db(qid2); - if( quest_check(sd, qid2, HAVEQUEST) >= 0 ) - { - ShowError("quest_change: Character %d already has quest %d.\n", sd->status.char_id, qid2); + if( qi == &quest->dummy ) { + ShowError("quest_change: quest %d not found in DB.\n", qid2); return -1; } - if( quest_check(sd, qid1, HAVEQUEST) < 0 ) - { - ShowError("quest_change: Character %d doesn't have quest %d.\n", sd->status.char_id, qid1); + if( quest->check(sd, qid2, HAVEQUEST) >= 0 ) { + ShowError("quest_change: Character %d already has quest %d.\n", sd->status.char_id, qid2); return -1; } - if( (j = quest_search_db(qid2)) < 0 ) - { - ShowError("quest_change: quest %d not found in DB.\n",qid2); + if( quest->check(sd, qid1, HAVEQUEST) < 0 ) { + ShowError("quest_change: Character %d doesn't have quest %d.\n", sd->status.char_id, qid1); return -1; } ARR_FIND(0, sd->avail_quests, i, sd->quest_log[i].quest_id == qid1); - if(i == sd->avail_quests) - { - ShowError("quest_change: Character %d has completed quests %d.\n", sd->status.char_id, qid1); + if( i == sd->avail_quests ) { + ShowError("quest_change: Character %d has completed quest %d.\n", sd->status.char_id, qid1); return -1; } memset(&sd->quest_log[i], 0, sizeof(struct quest)); - sd->quest_log[i].quest_id = quest_db[j].id; - if( quest_db[j].time ) - sd->quest_log[i].time = (unsigned int)(time(NULL) + quest_db[j].time); + sd->quest_log[i].quest_id = qi->id; + if( qi->time ) + sd->quest_log[i].time = (unsigned int)(time(NULL) + qi->time); sd->quest_log[i].state = Q_ACTIVE; - sd->quest_index[i] = j; sd->save_quest = true; clif->quest_delete(sd, qid1); - clif->quest_add(sd, &sd->quest_log[i], sd->quest_index[i]); + clif->quest_add(sd, &sd->quest_log[i]); + clif->quest_update_objective(sd, &sd->quest_log[i]); - if( iMap->save_settings&64 ) - chrif_save(sd,0); + if( map->save_settings&64 ) + chrif->save(sd,0); return 0; } -int quest_delete(TBL_PC * sd, int quest_id) -{ +/** + * Removes a quest from a player's list + * + * @param sd Player's data + * @param quest_id ID of the quest to remove + * @return 0 in case of success, nonzero otherwise + */ +int quest_delete(TBL_PC *sd, int quest_id) { int i; //Search for quest ARR_FIND(0, sd->num_quests, i, sd->quest_log[i].quest_id == quest_id); - if(i == sd->num_quests) - { + + if(i == sd->num_quests) { ShowError("quest_delete: Character %d doesn't have quest %d.\n", sd->status.char_id, quest_id); return -1; } if( sd->quest_log[i].state != Q_COMPLETE ) sd->avail_quests--; - if( sd->num_quests-- < MAX_QUEST_DB && sd->quest_log[i+1].quest_id ) - { + + if( i < --sd->num_quests ) { + // Compact the array memmove(&sd->quest_log[i], &sd->quest_log[i+1], sizeof(struct quest)*(sd->num_quests-i)); - memmove(sd->quest_index+i, sd->quest_index+i+1, sizeof(int)*(sd->num_quests-i)); } - memset(&sd->quest_log[sd->num_quests], 0, sizeof(struct quest)); - sd->quest_index[sd->num_quests] = 0; + if( sd->num_quests == 0 ) { + aFree(sd->quest_log); + sd->quest_log = NULL; + } else { + RECREATE(sd->quest_log, struct quest, sd->num_quests); + } sd->save_quest = true; clif->quest_delete(sd, quest_id); - if( iMap->save_settings&64 ) - chrif_save(sd,0); + if( map->save_settings&64 ) + chrif->save(sd,0); return 0; } -int quest_update_objective_sub(struct block_list *bl, va_list ap) -{ - struct map_session_data * sd; - int mob, party; +/** + * Map iterator subroutine to update quest objectives for a party after killing a monster. + * + * @see map_foreachinrange + * @param ap Argument list, expecting: + * int Party ID + * int Mob ID + */ +int quest_update_objective_sub(struct block_list *bl, va_list ap) { + struct map_session_data *sd; + int mob_id, party_id; nullpo_ret(bl); nullpo_ret(sd = (struct map_session_data *)bl); - party = va_arg(ap,int); - mob = va_arg(ap,int); + party_id = va_arg(ap,int); + mob_id = va_arg(ap,int); if( !sd->avail_quests ) return 0; - if( sd->status.party_id != party ) + if( sd->status.party_id != party_id ) return 0; - quest_update_objective(sd, mob); + quest->update_objective(sd, mob_id); return 1; } -void quest_update_objective(TBL_PC * sd, int mob) { +/** + * Updates the quest objectives for a character after killing a monster. + * + * @param sd Character's data + * @param mob_id Monster ID + */ +void quest_update_objective(TBL_PC *sd, int mob_id) { int i,j; for( i = 0; i < sd->avail_quests; i++ ) { - if( sd->quest_log[i].state != Q_ACTIVE ) + struct quest_db *qi = NULL; + + if( sd->quest_log[i].state != Q_ACTIVE ) // Skip inactive quests continue; - for( j = 0; j < MAX_QUEST_OBJECTIVES; j++ ) - if( quest_db[sd->quest_index[i]].mob[j] == mob && sd->quest_log[i].count[j] < quest_db[sd->quest_index[i]].count[j] ) { + qi = quest->db(sd->quest_log[i].quest_id); + + for( j = 0; j < qi->num_objectives; j++ ) { + if( qi->mob[j] == mob_id && sd->quest_log[i].count[j] < qi->count[j] ) { sd->quest_log[i].count[j]++; sd->save_quest = true; - clif->quest_update_objective(sd,&sd->quest_log[i],sd->quest_index[i]); + clif->quest_update_objective(sd, &sd->quest_log[i]); } + } } } -int quest_update_status(TBL_PC * sd, int quest_id, quest_state status) { +/** + * Updates a quest's state. + * + * Only status of active and inactive quests can be updated. Completed quests can't (for now). [Inkfish] + * + * @param sd Character's data + * @param quest_id Quest ID to update + * @param qs New quest state + * @return 0 in case of success, nonzero otherwise + */ +int quest_update_status(TBL_PC *sd, int quest_id, enum quest_state qs) { int i; - //Only status of active and inactive quests can be updated. Completed quests can't (for now). [Inkfish] ARR_FIND(0, sd->avail_quests, i, sd->quest_log[i].quest_id == quest_id); - if(i == sd->avail_quests) { + if( i == sd->avail_quests ) { ShowError("quest_update_status: Character %d doesn't have quest %d.\n", sd->status.char_id, quest_id); return -1; } - sd->quest_log[i].state = status; + sd->quest_log[i].state = qs; sd->save_quest = true; - if( status < Q_COMPLETE ) { - clif->quest_update_status(sd, quest_id, (bool)status); + if( qs < Q_COMPLETE ) { + clif->quest_update_status(sd, quest_id, qs == Q_ACTIVE ? true : false); return 0; } - if( i != (--sd->avail_quests) ) { + // The quest is complete, so it needs to be moved to the completed quests block at the end of the array. + + if( i < (--sd->avail_quests) ) { struct quest tmp_quest; memcpy(&tmp_quest, &sd->quest_log[i],sizeof(struct quest)); memcpy(&sd->quest_log[i], &sd->quest_log[sd->avail_quests],sizeof(struct quest)); @@ -249,13 +308,28 @@ int quest_update_status(TBL_PC * sd, int quest_id, quest_state status) { clif->quest_delete(sd, quest_id); - if( iMap->save_settings&64 ) - chrif_save(sd,0); + if( map->save_settings&64 ) + chrif->save(sd,0); return 0; } -int quest_check(TBL_PC * sd, int quest_id, quest_check_type type) { +/** + * Queries quest information for a character. + * + * @param sd Character's data + * @param quest_id Quest ID + * @param type Check type + * @return -1 if the quest was not found, otherwise it depends on the type: + * HAVEQUEST: The quest's state + * PLAYTIME: 2 if the quest's timeout has expired + * 1 if the quest was completed + * 0 otherwise + * HUNTING: 2 if the quest has not been marked as completed yet, and its objectives have been fulfilled + * 1 if the quest's timeout has expired + * 0 otherwise + */ +int quest_check(TBL_PC *sd, int quest_id, enum quest_check_type type) { int i; ARR_FIND(0, sd->num_quests, i, sd->quest_log[i].quest_id == quest_id); @@ -267,18 +341,17 @@ int quest_check(TBL_PC * sd, int quest_id, quest_check_type type) { return sd->quest_log[i].state; case PLAYTIME: return (sd->quest_log[i].time < (unsigned int)time(NULL) ? 2 : sd->quest_log[i].state == Q_COMPLETE ? 1 : 0); - case HUNTING: { - if( sd->quest_log[i].state == 0 || sd->quest_log[i].state == 1 ) { - int j; - ARR_FIND(0, MAX_QUEST_OBJECTIVES, j, sd->quest_log[i].count[j] < quest_db[sd->quest_index[i]].count[j]); - if( j == MAX_QUEST_OBJECTIVES ) - return 2; - if( sd->quest_log[i].time < (unsigned int)time(NULL) ) - return 1; - return 0; - } else - return 0; + case HUNTING: + if( sd->quest_log[i].state == Q_INACTIVE || sd->quest_log[i].state == Q_ACTIVE ) { + int j; + struct quest_db *qi = quest->db(sd->quest_log[i].quest_id); + ARR_FIND(0, MAX_QUEST_OBJECTIVES, j, sd->quest_log[i].count[j] < qi->count[j]); + if( j == MAX_QUEST_OBJECTIVES ) + return 2; + if( sd->quest_log[i].time < (unsigned int)time(NULL) ) + return 1; } + return 0; default: ShowError("quest_check_quest: Unknown parameter %d",type); break; @@ -287,72 +360,181 @@ int quest_check(TBL_PC * sd, int quest_id, quest_check_type type) { return -1; } +/** + * Loads quests from the quest db. + * + * @return Number of loaded quests, or -1 if the file couldn't be read. + */ int quest_read_db(void) { + // TODO[Haru] This duplicates some sv_readdb functionalities, and it would be + // nice if it could be replaced by it. The reason why it wasn't is probably + // because we need to accept commas (which is also used as delimiter) in the + // last field (quest name), and sv_readdb isn't capable of doing so. FILE *fp; char line[1024]; - int i,j,k = 0; - char *str[20],*p,*np; + int i, count = 0; + char *str[20], *p, *np; + struct quest_db entry; - sprintf(line, "%s/quest_db.txt", iMap->db_path); - if( (fp=fopen(line,"r"))==NULL ){ + sprintf(line, "%s/quest_db.txt", map->db_path); + if ((fp=fopen(line,"r"))==NULL) { ShowError("can't read %s\n", line); return -1; } - - while(fgets(line, sizeof(line), fp)) { - - if (k == MAX_QUEST_DB) { - ShowError("quest_read_db: Too many entries specified in %s/quest_db.txt!\n", iMap->db_path); - break; - } - - if(line[0]=='/' && line[1]=='/') + + while (fgets(line, sizeof(line), fp)) { + if (line[0]=='/' && line[1]=='/') continue; memset(str,0,sizeof(str)); - for( j = 0, p = line; j < 8; j++ ) { - if( ( np = strchr(p,',') ) != NULL ) { - str[j] = p; + for (i = 0, p = line; i < 8; i++) { + if (( np = strchr(p,',') ) != NULL) { + str[i] = p; *np = 0; p = np + 1; - } - else if (str[0] == NULL) - continue; - else { + } else if (str[0] == NULL) { + break; + } else { ShowError("quest_read_db: insufficient columns in line %s\n", line); continue; } } - if(str[0]==NULL) + if (str[0] == NULL) + continue; + + memset(&entry, 0, sizeof(entry)); + + entry.id = atoi(str[0]); + + if (entry.id < 0 || entry.id >= MAX_QUEST_DB) { + ShowError("quest_read_db: Invalid quest ID '%d' in line '%s' (min: 0, max: %d.)\n", entry.id, line, MAX_QUEST_DB); continue; + } - memset(&quest_db[k], 0, sizeof(quest_db[0])); + entry.time = atoi(str[1]); - quest_db[k].id = atoi(str[0]); - quest_db[k].time = atoi(str[1]); - - for( i = 0; i < MAX_QUEST_OBJECTIVES; i++ ) { - quest_db[k].mob[i] = atoi(str[2*i+2]); - quest_db[k].count[i] = atoi(str[2*i+3]); + for (i = 0; i < MAX_QUEST_OBJECTIVES; i++) { + entry.mob[i] = atoi(str[2*i+2]); + entry.count[i] = atoi(str[2*i+3]); - if( !quest_db[k].mob[i] || !quest_db[k].count[i] ) + if (!entry.mob[i] || !entry.count[i]) break; } - - quest_db[k].num_objectives = i; - k++; + entry.num_objectives = i; + + if (quest->db_data[entry.id] == NULL) + quest->db_data[entry.id] = aMalloc(sizeof(struct quest_db)); + + memcpy(quest->db_data[entry.id], &entry, sizeof(struct quest_db)); + count++; } fclose(fp); - ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", k, "quest_db.txt"); + ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", count, "quest_db.txt"); return 0; } -void do_init_quest(void) { - quest_read_db(); +/** + * Map iterator to ensures a player has no invalid quest log entries. + * + * Any entries that are no longer in the db are removed. + * + * @see map->foreachpc + * @param ap Ignored + */ +int quest_reload_check_sub(struct map_session_data *sd, va_list ap) { + int i, j; + + nullpo_ret(sd); + + j = 0; + for (i = 0; i < sd->num_quests; i++) { + struct quest_db *qi = quest->db(sd->quest_log[i].quest_id); + if (qi == &quest->dummy) { // Remove no longer existing entries + if (sd->quest_log[i].state != Q_COMPLETE) // And inform the client if necessary + clif->quest_delete(sd, sd->quest_log[i].quest_id); + continue; + } + if (i != j) { + // Move entries if there's a gap to fill + memcpy(&sd->quest_log[j], &sd->quest_log[i], sizeof(struct quest)); + } + j++; + } + sd->num_quests = j; + ARR_FIND(0, sd->num_quests, i, sd->quest_log[i].state == Q_COMPLETE); + sd->avail_quests = i; + + return 1; +} + +/** + * Clears the quest database for shutdown or reload. + */ +void quest_clear_db(void) { + int i; + + for (i = 0; i < MAX_QUEST_DB; i++) { + if (quest->db_data[i]) { + aFree(quest->db_data[i]); + quest->db_data[i] = NULL; + } + } } +/** + * Initializes the quest interface. + * + * @param minimal Run in minimal mode (skips most of the loading) + */ +void do_init_quest(bool minimal) { + if (minimal) + return; + + quest->read_db(); +} + +/** + * Finalizes the quest interface before shutdown. + */ +void do_final_quest(void) { + quest->clear(); +} + +/** + * Reloads the quest database. + */ void do_reload_quest(void) { - memset(&quest_db, 0, sizeof(quest_db)); - quest_read_db(); + quest->clear(); + + quest->read_db(); + + // Update quest data for players, to ensure no entries about removed quests are left over. + map->foreachpc(&quest_reload_check_sub); +} + +/** + * Initializes default values for the quest interface. + */ +void quest_defaults(void) { + quest = &quest_s; + + memset(&quest->db, 0, sizeof(quest->db)); + memset(&quest->dummy, 0, sizeof(quest->dummy)); + /* */ + quest->init = do_init_quest; + quest->final = do_final_quest; + quest->reload = do_reload_quest; + /* */ + quest->db = quest_db; + quest->pc_login = quest_pc_login; + quest->add = quest_add; + quest->change = quest_change; + quest->delete = quest_delete; + quest->update_objective_sub = quest_update_objective_sub; + quest->update_objective = quest_update_objective; + quest->update_status = quest_update_status; + quest->check = quest_check; + quest->clear = quest_clear_db; + quest->read_db = quest_read_db; } diff --git a/src/map/quest.h b/src/map/quest.h index 7f638a54c..9d617e369 100644 --- a/src/map/quest.h +++ b/src/map/quest.h @@ -1,10 +1,17 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder +// Copyright (c) Hercules Dev Team, licensed under GNU GPL. +// See the LICENSE file +// Portions Copyright (c) Athena Dev Teams -#ifndef _QUEST_H_ -#define _QUEST_H_ +#ifndef MAP_QUEST_H +#define MAP_QUEST_H -struct s_quest_db { +#include "map.h" // TBL_PC +#include "../common/cbasetypes.h" +#include "../common/mmo.h" // MAX_QUEST_OBJECTIVES + +#define MAX_QUEST_DB (60355+1) // Highest quest ID + 1 + +struct quest_db { int id; unsigned int time; int mob[MAX_QUEST_OBJECTIVES]; @@ -12,23 +19,37 @@ struct s_quest_db { int num_objectives; //char name[NAME_LENGTH]; }; -extern struct s_quest_db quest_db[MAX_QUEST_DB]; - -typedef enum quest_check_type { HAVEQUEST, PLAYTIME, HUNTING } quest_check_type; -int quest_pc_login(TBL_PC * sd); +// Questlog check types +enum quest_check_type { + HAVEQUEST, ///< Query the state of the given quest + PLAYTIME, ///< Check if the given quest has been completed or has yet to expire + HUNTING, ///< Check if the given hunting quest's requirements have been met +}; -int quest_add(TBL_PC * sd, int quest_id); -int quest_delete(TBL_PC * sd, int quest_id); -int quest_change(TBL_PC * sd, int qid1, int qid2); -int quest_update_objective_sub(struct block_list *bl, va_list ap); -void quest_update_objective(TBL_PC * sd, int mob); -int quest_update_status(TBL_PC * sd, int quest_id, quest_state status); -int quest_check(TBL_PC * sd, int quest_id, quest_check_type type); +struct quest_interface { + struct quest_db *db_data[MAX_QUEST_DB]; ///< Quest database + struct quest_db dummy; ///< Dummy entry for invalid quest lookups + /* */ + void (*init) (bool minimal); + void (*final) (void); + void (*reload) (void); + /* */ + struct quest_db *(*db) (int quest_id); + int (*pc_login) (TBL_PC *sd); + int (*add) (TBL_PC *sd, int quest_id); + int (*change) (TBL_PC *sd, int qid1, int qid2); + int (*delete) (TBL_PC *sd, int quest_id); + int (*update_objective_sub) (struct block_list *bl, va_list ap); + void (*update_objective) (TBL_PC *sd, int mob_id); + int (*update_status) (TBL_PC *sd, int quest_id, enum quest_state qs); + int (*check) (TBL_PC *sd, int quest_id, enum quest_check_type type); + void (*clear) (void); + int (*read_db) (void); +}; -int quest_search_db(int quest_id); +struct quest_interface *quest; -void do_init_quest(); -void do_reload_quest(void); +void quest_defaults(void); -#endif +#endif /* MAP_QUEST_H */ diff --git a/src/map/script.c b/src/map/script.c index 682faa42b..ecd12a3c1 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -2,250 +2,78 @@ // See the LICENSE file // Portions Copyright (c) Athena Dev Teams -//#define DEBUG_DISP -//#define DEBUG_DISASM -//#define DEBUG_RUN -//#define DEBUG_HASH -//#define DEBUG_DUMP_STACK +#define HERCULES_CORE -#include "../common/cbasetypes.h" -#include "../common/malloc.h" -#include "../common/md5calc.h" -#include "../common/nullpo.h" -#include "../common/random.h" -#include "../common/showmsg.h" -#include "../common/socket.h" // usage: getcharip -#include "../common/strlib.h" -#include "../common/timer.h" -#include "../common/utils.h" +#include "../config/core.h" // RENEWAL, RENEWAL_ASPD, RENEWAL_CAST, RENEWAL_DROP, RENEWAL_EDP, RENEWAL_EXP, RENEWAL_LVDMG, SCRIPT_CALLFUNC_CHECK, SECURE_NPCTIMEOUT, SECURE_NPCTIMEOUT_INTERVAL +#include "script.h" -#include "map.h" -#include "path.h" -#include "clif.h" +#include <math.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#include "atcommand.h" +#include "battle.h" +#include "battleground.h" +#include "chat.h" #include "chrif.h" +#include "clif.h" +#include "elemental.h" +#include "guild.h" +#include "homunculus.h" +#include "instance.h" +#include "intif.h" #include "itemdb.h" -#include "pc.h" -#include "status.h" -#include "storage.h" +#include "log.h" +#include "mail.h" +#include "map.h" +#include "mapreg.h" +#include "mercenary.h" #include "mob.h" #include "npc.h" +#include "party.h" +#include "path.h" +#include "pc.h" #include "pet.h" -#include "mapreg.h" -#include "homunculus.h" -#include "instance.h" -#include "mercenary.h" -#include "intif.h" +#include "pet.h" +#include "quest.h" #include "skill.h" #include "status.h" -#include "chat.h" -#include "battle.h" -#include "battleground.h" -#include "party.h" -#include "guild.h" -#include "atcommand.h" -#include "log.h" +#include "status.h" +#include "storage.h" #include "unit.h" -#include "pet.h" -#include "mail.h" -#include "script.h" -#include "quest.h" -#include "elemental.h" -#include "../config/core.h" +#include "../common/cbasetypes.h" +#include "../common/malloc.h" +#include "../common/md5calc.h" +#include "../common/mmo.h" // NEW_CARTS +#include "../common/nullpo.h" +#include "../common/random.h" +#include "../common/showmsg.h" +#include "../common/socket.h" // usage: getcharip +#include "../common/strlib.h" +#include "../common/sysinfo.h" +#include "../common/timer.h" +#include "../common/utils.h" -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <math.h> #ifndef WIN32 #include <sys/time.h> #endif -#include <time.h> -#include <setjmp.h> -#include <errno.h> - -#define FETCH(n, t) \ - if( script_hasdata(st,n) ) \ - (t)=script_getnum(st,n); - -/// Maximum amount of elements in script arrays -#define SCRIPT_MAX_ARRAYSIZE 128 -#define SCRIPT_BLOCK_SIZE 512 -enum { LABEL_NEXTLINE=1,LABEL_START }; - -/// temporary buffer for passing around compiled bytecode -/// @see add_scriptb, set_label, parse_script -static unsigned char* script_buf = NULL; -static int script_pos = 0, script_size = 0; - -static inline int GETVALUE(const unsigned char* buf, int i) -{ +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) -{ +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); } -// Using a prime number for SCRIPT_HASH_SIZE should give better distributions -#define SCRIPT_HASH_SIZE 1021 -int str_hash[SCRIPT_HASH_SIZE]; -// Specifies which string hashing method to use -//#define SCRIPT_HASH_DJB2 -//#define SCRIPT_HASH_SDBM -#define SCRIPT_HASH_ELF - -static DBMap* scriptlabel_db=NULL; // const char* label_name -> int script_pos -static DBMap* userfunc_db=NULL; // const char* func_name -> struct script_code* -static int parse_options=0; -DBMap* script_get_label_db(void){ return scriptlabel_db; } -DBMap* script_get_userfunc_db(void){ return userfunc_db; } - -// important buildin function references for usage in scripts -static int buildin_set_ref = 0; -static int buildin_callsub_ref = 0; -static int buildin_callfunc_ref = 0; -static int buildin_getelementofarray_ref = 0; - -// Caches compiled autoscript item code. -// Note: This is not cleared when reloading itemdb. -static DBMap* autobonus_db=NULL; // char* script -> char* bytecode - -struct Script_Config script_config = { - 1, // warn_func_mismatch_argtypes - 1, 65535, 2048, //warn_func_mismatch_paramnum/check_cmdcount/check_gotocount - 0, INT_MAX, // input_min_value/input_max_value - "OnPCDieEvent", //die_event_name - "OnPCKillEvent", //kill_pc_event_name - "OnNPCKillEvent", //kill_mob_event_name - "OnPCLoginEvent", //login_event_name - "OnPCLogoutEvent", //logout_event_name - "OnPCLoadMapEvent", //loadmap_event_name - "OnPCBaseLvUpEvent", //baselvup_event_name - "OnPCJobLvUpEvent", //joblvup_event_name - "OnTouch_", //ontouch_name (runs on first visible char to enter area, picks another char if the first char leaves) - "OnTouch", //ontouch2_name (run whenever a char walks into the OnTouch area) -}; - -static jmp_buf error_jump; -static char* error_msg; -static const char* error_pos; -static int error_report; // if the error should produce output - -// for advanced scripting support ( nested if, switch, while, for, do-while, function, etc ) -// [Eoe / jA 1080, 1081, 1094, 1164] -enum curly_type { - TYPE_NULL = 0, - TYPE_IF, - TYPE_SWITCH, - TYPE_WHILE, - TYPE_FOR, - TYPE_DO, - TYPE_USERFUNC, - TYPE_ARGLIST // function argument list -}; - -enum e_arglist -{ - ARGLIST_UNDEFINED = 0, - ARGLIST_NO_PAREN = 1, - ARGLIST_PAREN = 2, -}; - -static struct { - struct { - enum curly_type type; - int index; - int count; - int flag; - struct linkdb_node *case_label; - } curly[256]; // Information right parenthesis - int curly_count; // The number of right brackets - int index; // Number of the syntax used in the script -} syntax; +struct script_interface script_s; -const char* parse_curly_close(const char* p); -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); -static int parse_syntax_for_flag = 0; - -extern int current_equip_item_index; //for New CARDS Scripts. It contains Inventory Index of the EQUIP_SCRIPT caller item. [Lupus] -int potion_flag=0; //For use on Alchemist improved potions/Potion Pitcher. [Skotlex] -int potion_hp=0, potion_per_hp=0, potion_sp=0, potion_per_sp=0; -int potion_target=0; - - -c_op get_com(unsigned char *script,int *pos); -int get_num(unsigned char *script,int *pos); - -/*========================================== - * (Only those needed) local declaration prototype - *------------------------------------------*/ -const char* parse_subexpr(const char* p,int limit); -int run_func(struct script_state *st); - -enum { - MF_NOMEMO, //0 - MF_NOTELEPORT, - MF_NOSAVE, - MF_NOBRANCH, - MF_NOPENALTY, - MF_NOZENYPENALTY, - MF_PVP, - MF_PVP_NOPARTY, - MF_PVP_NOGUILD, - MF_GVG, - MF_GVG_NOPARTY, //10 - MF_NOTRADE, - MF_NOSKILL, - MF_NOWARP, - MF_PARTYLOCK, - MF_NOICEWALL, - MF_SNOW, - MF_FOG, - MF_SAKURA, - MF_LEAVES, - /* 21 - 22 free */ - MF_CLOUDS = 23, - MF_CLOUDS2, - MF_FIREWORKS, - MF_GVG_CASTLE, - MF_GVG_DUNGEON, - MF_NIGHTENABLED, - MF_NOBASEEXP, - MF_NOJOBEXP, //30 - MF_NOMOBLOOT, - MF_NOMVPLOOT, - MF_NORETURN, - MF_NOWARPTO, - MF_NIGHTMAREDROP, - MF_ZONE, - MF_NOCOMMAND, - MF_NODROP, - MF_JEXP, - MF_BEXP, //40 - MF_NOVENDING, - MF_LOADEVENT, - MF_NOCHAT, - MF_NOEXPPENALTY, - MF_GUILDLOCK, - MF_TOWN, - MF_AUTOTRADE, - MF_ALLOWKS, - MF_MONSTER_NOTELEPORT, - MF_PVP_NOCALCRANK, //50 - MF_BATTLEGROUND, - MF_RESET -}; - -const char* script_op2name(int op) -{ +const char* script_op2name(int op) { #define RETURN_OP_NAME(type) case type: return #type - switch( op ) - { + switch( op ) { RETURN_OP_NAME(C_NOP); RETURN_OP_NAME(C_POS); RETURN_OP_NAME(C_INT); @@ -260,6 +88,8 @@ const char* script_op2name(int op) RETURN_OP_NAME(C_USERFUNC); RETURN_OP_NAME(C_USERFUNC_POS); + RETURN_OP_NAME(C_REF); + // operators RETURN_OP_NAME(C_OP3); RETURN_OP_NAME(C_LOR); @@ -283,6 +113,14 @@ const char* script_op2name(int op) RETURN_OP_NAME(C_NOT); RETURN_OP_NAME(C_R_SHIFT); RETURN_OP_NAME(C_L_SHIFT); + RETURN_OP_NAME(C_ADD_POST); + RETURN_OP_NAME(C_SUB_POST); + RETURN_OP_NAME(C_ADD_PRE); + RETURN_OP_NAME(C_SUB_PRE); +#ifdef PCRE_SUPPORT + RETURN_OP_NAME(C_RE_EQ); + RETURN_OP_NAME(C_RE_NE); +#endif // PCRE_SUPPORT default: ShowDebug("script_op2name: unexpected op=%d\n", op); @@ -291,7 +129,7 @@ const char* script_op2name(int op) #undef RETURN_OP_NAME } -#ifdef DEBUG_DUMP_STACK +#ifdef SCRIPT_DEBUG_DUMP_STACK static void script_dump_stack(struct script_state* st) { int i; @@ -322,7 +160,7 @@ static void script_dump_stack(struct script_state* st) case C_RETINFO: { struct script_retinfo* ri = data->u.ri; - ShowMessage(" %p {var_function=%p, script=%p, pos=%d, nargs=%d, defsp=%d}\n", ri, ri->var_function, ri->script, ri->pos, ri->nargs, ri->defsp); + ShowMessage(" %p {scope.vars=%p, scope.arrays=%p, script=%p, pos=%d, nargs=%d, defsp=%d}\n", ri, ri->scope.vars, ri->scope.arrays, ri->script, ri->pos, ri->nargs, ri->defsp); } break; default: @@ -334,35 +172,34 @@ static void script_dump_stack(struct script_state* st) #endif /// Reports on the console the src of a script error. -static void script_reportsrc(struct script_state *st) -{ +void script_reportsrc(struct script_state *st) { struct block_list* bl; if( st->oid == 0 ) return; //Can't report source. - bl = iMap->id2bl(st->oid); + bl = map->id2bl(st->oid); if( bl == NULL ) return; switch( bl->type ) { case BL_NPC: if( bl->m >= 0 ) - ShowDebug("Source (NPC): %s at %s (%d,%d)\n", ((struct npc_data *)bl)->name, map[bl->m].name, bl->x, bl->y); + ShowDebug("Source (NPC): %s at %s (%d,%d)\n", ((struct npc_data *)bl)->name, map->list[bl->m].name, bl->x, bl->y); else ShowDebug("Source (NPC): %s (invisible/not on a map)\n", ((struct npc_data *)bl)->name); break; default: if( bl->m >= 0 ) - ShowDebug("Source (Non-NPC type %d): name %s at %s (%d,%d)\n", bl->type, status_get_name(bl), map[bl->m].name, bl->x, bl->y); + ShowDebug("Source (Non-NPC type %d): name %s at %s (%d,%d)\n", bl->type, status->get_name(bl), map->list[bl->m].name, bl->x, bl->y); else - ShowDebug("Source (Non-NPC type %d): name %s (invisible/not on a map)\n", bl->type, status_get_name(bl)); + ShowDebug("Source (Non-NPC type %d): name %s (invisible/not on a map)\n", bl->type, status->get_name(bl)); break; } } /// Reports on the console information about the script data. -static void script_reportdata(struct script_data* data) +void script_reportdata(struct script_data* data) { if( data == NULL ) return; @@ -371,7 +208,7 @@ static void script_reportdata(struct script_data* data) ShowDebug("Data: nothing (nil)\n"); break; case C_INT:// number - ShowDebug("Data: number value=%d\n", data->u.num); + ShowDebug("Data: number value=%"PRId64"\n", data->u.num); break; case C_STR: case C_CONSTSTR:// string @@ -384,31 +221,28 @@ static void script_reportdata(struct script_data* data) case C_NAME:// reference if( reference_tovariable(data) ) {// variable const char* name = reference_getname(data); - if( not_array_variable(*name) ) - ShowDebug("Data: variable name='%s'\n", name); - else - ShowDebug("Data: variable name='%s' index=%d\n", name, reference_getindex(data)); + ShowDebug("Data: variable name='%s' index=%d\n", name, reference_getindex(data)); } else if( reference_toconstant(data) ) {// constant ShowDebug("Data: constant name='%s' value=%d\n", reference_getname(data), reference_getconstant(data)); } else if( reference_toparam(data) ) {// param ShowDebug("Data: param name='%s' type=%d\n", reference_getname(data), reference_getparamtype(data)); } else {// ??? - ShowDebug("Data: reference name='%s' type=%s\n", reference_getname(data), script_op2name(data->type)); - ShowDebug("Please report this!!! - script->str_data.type=%s\n", script_op2name(script->str_data[reference_getid(data)].type)); + ShowDebug("Data: reference name='%s' type=%s\n", reference_getname(data), script->op2name(data->type)); + ShowDebug("Please report this!!! - script->str_data.type=%s\n", script->op2name(script->str_data[reference_getid(data)].type)); } break; case C_POS:// label - ShowDebug("Data: label pos=%d\n", data->u.num); + ShowDebug("Data: label pos=%"PRId64"\n", data->u.num); break; default: - ShowDebug("Data: %s\n", script_op2name(data->type)); + ShowDebug("Data: %s\n", script->op2name(data->type)); break; } } /// Reports on the console information about the current built-in function. -static void script_reportfunc(struct script_state* st) +void script_reportfunc(struct script_state* st) { int i, params, id; struct script_data* data; @@ -430,16 +264,16 @@ static void script_reportfunc(struct script_state* st) if( params > 0 ) { - ShowDebug("Function: %s (%d parameter%s):\n", get_str(id), params, ( params == 1 ) ? "" : "s"); + ShowDebug("Function: %s (%d parameter%s):\n", script->get_str(id), params, ( params == 1 ) ? "" : "s"); for( i = 2; i <= script_lastdata(st); i++ ) { - script_reportdata(script_getdata(st,i)); + script->reportdata(script_getdata(st,i)); } } else { - ShowDebug("Function: %s (no parameters)\n", get_str(id)); + ShowDebug("Function: %s (no parameters)\n", script->get_str(id)); } } @@ -447,35 +281,73 @@ static void script_reportfunc(struct script_state* st) /*========================================== * Output error message *------------------------------------------*/ -static void disp_error_message2(const char *mes,const char *pos,int report) -{ - error_msg = aStrdup(mes); - error_pos = pos; - error_report = report; - longjmp( error_jump, 1 ); +static void disp_error_message2(const char *mes,const char *pos,int report) analyzer_noreturn; +static void disp_error_message2(const char *mes,const char *pos,int report) { + script->error_msg = aStrdup(mes); + script->error_pos = pos; + script->error_report = report; + longjmp( script->error_jump, 1 ); +} +#define disp_error_message(mes,pos) (disp_error_message2((mes),(pos),1)) + +void disp_warning_message(const char *mes, const char *pos) { + script->warning(script->parser_current_src,script->parser_current_file,script->parser_current_line,mes,pos); } -#define disp_error_message(mes,pos) disp_error_message2(mes,pos,1) /// Checks event parameter validity -static void check_event(struct script_state *st, const char *evt) +void check_event(struct script_state *st, const char *evt) { if( evt && evt[0] && !stristr(evt, "::On") ) { ShowWarning("NPC event parameter deprecated! Please use 'NPCNAME::OnEVENT' instead of '%s'.\n", evt); - script_reportsrc(st); + script->reportsrc(st); } } /*========================================== * Hashes the input string *------------------------------------------*/ -static unsigned int calc_hash(const char* p) -{ +unsigned int calc_hash(const char* p) { unsigned int h; #if defined(SCRIPT_HASH_DJB2) h = 5381; while( *p ) // hash*33 + c + h = ( h << 5 ) + h + ((unsigned char)(*p++)); +#elif defined(SCRIPT_HASH_SDBM) + h = 0; + while( *p ) // hash*65599 + c + h = ( h << 6 ) + ( h << 16 ) - h + ((unsigned char)(*p++)); +#elif defined(SCRIPT_HASH_ELF) // UNIX ELF hash + h = 0; + while( *p ) { + unsigned int g; + h = ( h << 4 ) + ((unsigned char)(*p++)); + g = h & 0xF0000000; + if( g ) { + h ^= g >> 24; + h &= ~g; + } + } +#else // athena hash + h = 0; + while( *p ) + h = ( h << 1 ) + ( h >> 3 ) + ( h >> 5 ) + ( h >> 8 ) + (unsigned char)(*p++); +#endif + + return h % SCRIPT_HASH_SIZE; +} + +/*========================================== + * Hashes the input string in a case insensitive way + *------------------------------------------*/ +unsigned int calc_hash_ci(const char* p) { + unsigned int h = 0; +#ifdef ENABLE_CASE_CHECK + +#if defined(SCRIPT_HASH_DJB2) + h = 5381; + while( *p ) // hash*33 + c h = ( h << 5 ) + h + ((unsigned char)TOLOWER(*p++)); #elif defined(SCRIPT_HASH_SDBM) h = 0; @@ -483,12 +355,11 @@ static unsigned int calc_hash(const char* p) h = ( h << 6 ) + ( h << 16 ) - h + ((unsigned char)TOLOWER(*p++)); #elif defined(SCRIPT_HASH_ELF) // UNIX ELF hash h = 0; - while( *p ){ + while( *p ) { unsigned int g; h = ( h << 4 ) + ((unsigned char)TOLOWER(*p++)); g = h & 0xF0000000; - if( g ) - { + if( g ) { h ^= g >> 24; h &= ~g; } @@ -499,6 +370,7 @@ static unsigned int calc_hash(const char* p) h = ( h << 1 ) + ( h >> 3 ) + ( h >> 5 ) + ( h >> 8 ) + (unsigned char)TOLOWER(*p++); #endif +#endif // ENABLE_CASE_CHECK return h % SCRIPT_HASH_SIZE; } @@ -508,39 +380,129 @@ static unsigned int calc_hash(const char* p) *------------------------------------------*/ /// Looks up string using the provided id. -const char* get_str(int id) +const char* script_get_str(int id) { Assert( id >= LABEL_START && id < script->str_size ); return script->str_buf+script->str_data[id].str; } /// Returns the uid of the string, or -1. -static int search_str(const char* p) +int script_search_str(const char* p) { int i; - for( i = str_hash[calc_hash(p)]; i != 0; i = script->str_data[i].next ) - if( strcasecmp(get_str(i),p) == 0 ) + for( i = script->str_hash[script->calc_hash(p)]; i != 0; i = script->str_data[i].next ) { + if( strcmp(script->get_str(i),p) == 0 ) { return i; + } + } return -1; } +void script_casecheck_clear_sub(struct casecheck_data *ccd) { +#ifdef ENABLE_CASE_CHECK + if (ccd->str_data) { + aFree(ccd->str_data); + ccd->str_data = NULL; + } + ccd->str_data_size = 0; + ccd->str_num = 1; + if (ccd->str_buf) { + aFree(ccd->str_buf); + ccd->str_buf = NULL; + } + ccd->str_pos = 0; + ccd->str_size = 0; + memset(ccd->str_hash, 0, sizeof(ccd->str_hash)); +#endif // ENABLE_CASE_CHECK +} + +void script_global_casecheck_clear(void) { + script_casecheck_clear_sub(&script->global_casecheck); +} + +void script_local_casecheck_clear(void) { + script_casecheck_clear_sub(&script->local_casecheck); +} + +const char *script_casecheck_add_str_sub(struct casecheck_data *ccd, const char *p) { +#ifdef ENABLE_CASE_CHECK + int len, i; + int h = script->calc_hash_ci(p); + if( ccd->str_hash[h] == 0 ) { //empty bucket, add new node here + ccd->str_hash[h] = ccd->str_num; + } else { + const char *s = NULL; + for( i = ccd->str_hash[h]; ; i = ccd->str_data[i].next ) { + Assert( i >= 0 && i < ccd->str_size ); + s = ccd->str_buf+ccd->str_data[i].str; + if( strcasecmp(s,p) == 0 ) { + return s; // string already in list + } + if( ccd->str_data[i].next == 0 ) + break; // reached the end + } + + // append node to end of list + ccd->str_data[i].next = ccd->str_num; + } + + // grow list if neccessary + if( ccd->str_num >= ccd->str_data_size ) { + ccd->str_data_size += 1280; + RECREATE(ccd->str_data,struct str_data_struct,ccd->str_data_size); + memset(ccd->str_data + (ccd->str_data_size - 1280), '\0', 1280); + } + + len=(int)strlen(p); + + // grow string buffer if neccessary + while( ccd->str_pos+len+1 >= ccd->str_size ) { + ccd->str_size += 10240; + RECREATE(ccd->str_buf,char,ccd->str_size); + memset(ccd->str_buf + (ccd->str_size - 10240), '\0', 10240); + } + + safestrncpy(ccd->str_buf+ccd->str_pos, p, len+1); + ccd->str_data[ccd->str_num].type = C_NOP; + ccd->str_data[ccd->str_num].str = ccd->str_pos; + ccd->str_data[ccd->str_num].val = 0; + ccd->str_data[ccd->str_num].next = 0; + ccd->str_data[ccd->str_num].func = NULL; + ccd->str_data[ccd->str_num].backpatch = -1; + ccd->str_data[ccd->str_num].label = -1; + ccd->str_pos += len+1; + + ccd->str_num++; +#endif // ENABLE_CASE_CHECK + return NULL; +} + +const char *script_global_casecheck_add_str(const char *p) { + return script_casecheck_add_str_sub(&script->global_casecheck, p); +} + +const char *script_local_casecheck_add_str(const char *p) { + return script_casecheck_add_str_sub(&script->local_casecheck, p); +} + /// Stores a copy of the string and returns its id. /// If an identical string is already present, returns its id instead. -int add_str(const char* p) +int script_add_str(const char* p) { - int i, h; - int len; + int i, len, h = script->calc_hash(p); +#ifdef ENABLE_CASE_CHECK + const char *existingentry = NULL; +#endif // ENABLE_CASE_CHECK - h = calc_hash(p); - - if( str_hash[h] == 0 ) {// empty bucket, add new node here - str_hash[h] = script->str_num; + if( script->str_hash[h] == 0 ) {// empty bucket, add new node here + script->str_hash[h] = script->str_num; } else {// scan for end of list, or occurence of identical string - for( i = str_hash[h]; ; i = script->str_data[i].next ) { - if( strcasecmp(get_str(i),p) == 0 ) + for( i = script->str_hash[h]; ; i = script->str_data[i].next ) { + if( strcmp(script->get_str(i),p) == 0 ) { return i; // string already in list + } if( script->str_data[i].next == 0 ) break; // reached the end } @@ -549,6 +511,25 @@ int add_str(const char* p) script->str_data[i].next = script->str_num; } +#ifdef ENABLE_CASE_CHECK + if( (strncmp(p, ".@", 2) == 0) ) // Local scope vars are checked separately to decrease false positives + existingentry = script->local_casecheck.add_str(p); + else { + existingentry = script->global_casecheck.add_str(p); + if( existingentry ) { + if( strcasecmp(p, "disguise") == 0 || strcasecmp(p, "Poison_Spore") == 0 + || strcasecmp(p, "PecoPeco_Egg") == 0 || strcasecmp(p, "Soccer_Ball") == 0 + || strcasecmp(p, "Horn") == 0 || strcasecmp(p, "Treasure_Box_") == 0 + || strcasecmp(p, "Lord_of_Death") == 0 + ) // Known duplicates, don't bother warning the user + existingentry = NULL; + } + } + if( existingentry ) { + DeprecationWarning2("script_add_str", p, existingentry, script->parser_current_file); // TODO + } +#endif // ENABLE_CASE_CHECK + // grow list if neccessary if( script->str_num >= script->str_data_size ) { script->str_data_size += 1280; @@ -568,6 +549,7 @@ int add_str(const char* p) safestrncpy(script->str_buf+script->str_pos, p, len+1); script->str_data[script->str_num].type = C_NOP; script->str_data[script->str_num].str = script->str_pos; + script->str_data[script->str_num].val = 0; script->str_data[script->str_num].next = 0; script->str_data[script->str_num].func = NULL; script->str_data[script->str_num].backpatch = -1; @@ -579,43 +561,43 @@ int add_str(const char* p) /// Appends 1 byte to the script buffer. -static void add_scriptb(int a) +void add_scriptb(int a) { - if( script_pos+1 >= script_size ) + if( script->pos+1 >= script->size ) { - script_size += SCRIPT_BLOCK_SIZE; - RECREATE(script_buf,unsigned char,script_size); + script->size += SCRIPT_BLOCK_SIZE; + RECREATE(script->buf,unsigned char,script->size); } - script_buf[script_pos++] = (uint8)(a); + script->buf[script->pos++] = (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). -static void add_scriptc(int a) +void add_scriptc(int a) { while( a >= 0x40 ) { - add_scriptb((a&0x3f)|0x40); + script->addb((a&0x3f)|0x40); a = (a - 0x40) >> 6; } - add_scriptb(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). -static void add_scripti(int a) +void add_scripti(int a) { while( a >= 0x40 ) { - add_scriptb((a&0x3f)|0xc0); + script->addb((a&0x3f)|0xc0); a = (a - 0x40) >> 6; } - add_scriptb(a|0x80); + script->addb(a|0x80); } /// Appends a script->str_data object (label/function/variable/integer) to the script buffer. @@ -623,37 +605,37 @@ static void add_scripti(int a) /// /// @param l The id of the script->str_data entry // Maximum up to 16M -static void add_scriptl(int l) +void add_scriptl(int l) { int backpatch = script->str_data[l].backpatch; - switch(script->str_data[l].type){ + switch(script->str_data[l].type) { case C_POS: case C_USERFUNC_POS: - add_scriptc(C_POS); - add_scriptb(script->str_data[l].label); - add_scriptb(script->str_data[l].label>>8); - add_scriptb(script->str_data[l].label>>16); + script->addc(C_POS); + script->addb(script->str_data[l].label); + script->addb(script->str_data[l].label>>8); + script->addb(script->str_data[l].label>>16); break; case C_NOP: case C_USERFUNC: // Embedded data backpatch there is a possibility of label - add_scriptc(C_NAME); - script->str_data[l].backpatch = script_pos; - add_scriptb(backpatch); - add_scriptb(backpatch>>8); - add_scriptb(backpatch>>16); + script->addc(C_NAME); + script->str_data[l].backpatch = script->pos; + script->addb(backpatch); + script->addb(backpatch>>8); + script->addb(backpatch>>16); break; case C_INT: - add_scripti(abs(script->str_data[l].val)); + script->addi(abs(script->str_data[l].val)); if( script->str_data[l].val < 0 ) //Notice that this is negative, from jA (Rayce) - add_scriptc(C_NEG); + script->addc(C_NEG); break; default: // assume C_NAME - add_scriptc(C_NAME); - add_scriptb(l); - add_scriptb(l>>8); - add_scriptb(l>>16); + script->addc(C_NAME); + script->addb(l); + script->addb(l>>8); + script->addb(l>>16); break; } } @@ -665,27 +647,27 @@ void set_label(int l,int pos, const char* script_pos) { int i,next; - if(script->str_data[l].type==C_INT || script->str_data[l].type==C_PARAM || script->str_data[l].type==C_FUNC) - { //Prevent overwriting constants values, parameters and built-in functions [Skotlex] + if(script->str_data[l].type==C_INT || script->str_data[l].type==C_PARAM || script->str_data[l].type==C_FUNC) { + //Prevent overwriting constants values, parameters and built-in functions [Skotlex] disp_error_message("set_label: invalid label name",script_pos); return; } - if(script->str_data[l].label!=-1){ + if(script->str_data[l].label!=-1) { disp_error_message("set_label: dup label ",script_pos); return; } 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;){ - 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); + for(i=script->str_data[l].backpatch;i>=0 && i!=0x00ffffff;) { + 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); i=next; } } /// Skips spaces and/or comments. -const char* skip_space(const char* p) +const char* script_skip_space(const char* p) { if( p == NULL ) return NULL; @@ -703,8 +685,10 @@ const char* skip_space(const char* p) p += 2; for(;;) { - if( *p == '\0' ) - return p;//disp_error_message("script:skip_space: end of file while parsing block comment. expected "CL_BOLD"*/"CL_NORM, p); + if( *p == '\0' ) { + script->disp_warning_message("script:script->skip_space: end of file while parsing block comment. expected "CL_BOLD"*/"CL_NORM, p); + return p; + } if( *p == '*' && p[1] == '/' ) {// end of block comment p += 2; @@ -722,7 +706,7 @@ const char* skip_space(const char* p) /// Skips a word. /// A word consists of undercores and/or alphanumeric characters, /// and valid variable prefixes/postfixes. -static const char* skip_word(const char* p) { +const char* skip_word(const char* p) { // prefix switch( *p ) { case '@':// temporary char variable @@ -737,7 +721,7 @@ static const char* skip_word(const char* p) { p += ( p[1] == '@' ? 2 : 1 ); break; } - while( ISALNUM(*p) || *p == '_' ) + while( ISALNUM(*p) || *p == '_' || *p == '\'' ) ++p; // postfix @@ -748,26 +732,26 @@ static const char* skip_word(const char* p) { } /// Adds a word to script->str_data. /// @see skip_word -/// @see add_str -static int add_word(const char* p) { - int len; +/// @see script->add_str +int add_word(const char* p) { + size_t len; int i; // Check for a word - len = skip_word(p) - p; + len = script->skip_word(p) - p; if( len == 0 ) disp_error_message("script:add_word: invalid word. A word consists of undercores and/or alphanumeric characters, and valid variable prefixes/postfixes.", p); // Duplicate the word if( len+1 > script->word_size ) RECREATE(script->word_buf, char, (script->word_size = (len+1))); - + memcpy(script->word_buf, p, len); script->word_buf[len] = 0; // add the word - i = add_str(script->word_buf); - + i = script->add_str(script->word_buf); + return i; } @@ -779,109 +763,109 @@ const char* parse_callfunc(const char* p, int require_paren, int is_custom) { const char *p2; char *arg = NULL; + char null_arg = '\0'; int func; - func = add_word(p); - if( script->str_data[func].type == C_FUNC ){ - char argT = 0; + func = script->add_word(p); + if( script->str_data[func].type == C_FUNC ) { // buildin function - add_scriptl(func); - add_scriptc(C_ARG); + script->addl(func); + script->addc(C_ARG); arg = script->buildin[script->str_data[func].val]; - if( !arg ) arg = &argT; - } else if( script->str_data[func].type == C_USERFUNC || script->str_data[func].type == C_USERFUNC_POS ){ + if( !arg ) arg = &null_arg; // Use a dummy, null string + } else if( script->str_data[func].type == C_USERFUNC || script->str_data[func].type == C_USERFUNC_POS ) { // script defined function - add_scriptl(buildin_callsub_ref); - add_scriptc(C_ARG); - add_scriptl(func); - arg = script->buildin[script->str_data[buildin_callsub_ref].val]; + script->addl(script->buildin_callsub_ref); + script->addc(C_ARG); + script->addl(func); + arg = script->buildin[script->str_data[script->buildin_callsub_ref].val]; if( *arg == 0 ) disp_error_message("parse_callfunc: callsub has no arguments, please review its definition",p); if( *arg != '*' ) ++arg; // count func as argument } else { #ifdef SCRIPT_CALLFUNC_CHECK - const char* name = get_str(func); - if( !is_custom && strdb_get(userfunc_db, name) == NULL ) { + const char* name = script->get_str(func); + if( !is_custom && strdb_get(script->userfunc_db, name) == NULL ) { #endif disp_error_message("parse_line: expect command, missing function name or calling undeclared function",p); #ifdef SCRIPT_CALLFUNC_CHECK } else {; - add_scriptl(buildin_callfunc_ref); - add_scriptc(C_ARG); - add_scriptc(C_STR); - while( *name ) add_scriptb(*name ++); - add_scriptb(0); - arg = script->buildin[script->str_data[buildin_callfunc_ref].val]; + script->addl(script->buildin_callfunc_ref); + script->addc(C_ARG); + script->addc(C_STR); + while( *name ) script->addb(*name ++); + script->addb(0); + arg = script->buildin[script->str_data[script->buildin_callfunc_ref].val]; if( *arg != '*' ) ++ arg; } #endif } - p = skip_word(p); - p = skip_space(p); - syntax.curly[syntax.curly_count].type = TYPE_ARGLIST; - syntax.curly[syntax.curly_count].count = 0; + p = script->skip_word(p); + p = script->skip_space(p); + script->syntax.curly[script->syntax.curly_count].type = TYPE_ARGLIST; + script->syntax.curly[script->syntax.curly_count].count = 0; if( *p == ';' ) {// <func name> ';' - syntax.curly[syntax.curly_count].flag = ARGLIST_NO_PAREN; - } else if( *p == '(' && *(p2=skip_space(p+1)) == ')' ) + script->syntax.curly[script->syntax.curly_count].flag = ARGLIST_NO_PAREN; + } else if( *p == '(' && *(p2=script->skip_space(p+1)) == ')' ) {// <func name> '(' ')' - syntax.curly[syntax.curly_count].flag = ARGLIST_PAREN; + script->syntax.curly[script->syntax.curly_count].flag = ARGLIST_PAREN; p = p2; /* } else if( 0 && require_paren && *p != '(' ) {// <func name> - syntax.curly[syntax.curly_count].flag = ARGLIST_NO_PAREN; + script->syntax.curly[script->syntax.curly_count].flag = ARGLIST_NO_PAREN; */ } else {// <func name> <arg list> - if( require_paren ){ + if( require_paren ) { if( *p != '(' ) disp_error_message("need '('",p); ++p; // skip '(' - syntax.curly[syntax.curly_count].flag = ARGLIST_PAREN; - } else if( *p == '(' ){ - syntax.curly[syntax.curly_count].flag = ARGLIST_UNDEFINED; + script->syntax.curly[script->syntax.curly_count].flag = ARGLIST_PAREN; + } else if( *p == '(' ) { + script->syntax.curly[script->syntax.curly_count].flag = ARGLIST_UNDEFINED; } else { - syntax.curly[syntax.curly_count].flag = ARGLIST_NO_PAREN; + script->syntax.curly[script->syntax.curly_count].flag = ARGLIST_NO_PAREN; } - ++syntax.curly_count; + ++script->syntax.curly_count; while( *arg ) { - p2=parse_subexpr(p,-1); + p2=script->parse_subexpr(p,-1); if( p == p2 ) break; // not an argument if( *arg != '*' ) ++arg; // next argument - p=skip_space(p2); + p=script->skip_space(p2); if( *arg == 0 || *p != ',' ) break; // no more arguments ++p; // skip comma } - --syntax.curly_count; + --script->syntax.curly_count; } if( arg && *arg && *arg != '?' && *arg != '*' ) - disp_error_message2("parse_callfunc: not enough arguments, expected ','", p, script_config.warn_func_mismatch_paramnum); - if( syntax.curly[syntax.curly_count].type != TYPE_ARGLIST ) + disp_error_message2("parse_callfunc: not enough arguments, expected ','", p, script->config.warn_func_mismatch_paramnum); + if( script->syntax.curly[script->syntax.curly_count].type != TYPE_ARGLIST ) disp_error_message("parse_callfunc: DEBUG last curly is not an argument list",p); - if( syntax.curly[syntax.curly_count].flag == ARGLIST_PAREN ){ + if( script->syntax.curly[script->syntax.curly_count].flag == ARGLIST_PAREN ) { if( *p != ')' ) disp_error_message("parse_callfunc: expected ')' to close argument list",p); ++p; } - add_scriptc(C_FUNC); + script->addc(C_FUNC); return p; } /// Processes end of logical script line. /// @param first When true, only fix up scheduling data is initialized /// @param p Script position for error reporting in set_label -static void parse_nextline(bool first, const char* p) +void parse_nextline(bool first, const char* p) { if( !first ) { - add_scriptc(C_EOL); // mark end of line for stack cleanup - set_label(LABEL_NEXTLINE, script_pos, p); // fix up '-' labels + script->addc(C_EOL); // mark end of line for stack cleanup + script->set_label(LABEL_NEXTLINE, script->pos, p); // fix up '-' labels } // initialize data for new '-' label fix up scheduling @@ -890,6 +874,38 @@ static void parse_nextline(bool first, const char* p) script->str_data[LABEL_NEXTLINE].label = -1; } +/** + * Pushes a variable into stack, processing its array index if needed. + * @see parse_variable + */ +void parse_variable_sub_push(int word, const char *p2) { + const char* p3 = NULL; + + if( p2 ) { + // process the variable index + + // push the getelementofarray method into the stack + script->addl(script->buildin_getelementofarray_ref); + script->addc(C_ARG); + script->addl(word); + + // process the sub-expression for this assignment + p3 = script->parse_subexpr(p2 + 1, 1); + p3 = script->skip_space(p3); + + if( *p3 != ']' ) {// closing parenthesis is required for this script + disp_error_message("Missing closing ']' parenthesis for the variable assignment.", p3); + } + + // push the closing function stack operator onto the stack + script->addc(C_FUNC); + p3++; + } else { + // No array index, simply push the variable or value onto the stack + script->addl(word); + } +} + /// Parse a variable assignment using the direct equals operator /// @param p script position where the function should run from /// @return NULL if not a variable assignment, the new position otherwise @@ -899,21 +915,30 @@ const char* parse_variable(const char* p) { const char *p2 = NULL; const char *var = p; + if( ( p[0] == '+' && p[1] == '+' && (type = C_ADD_PRE) ) // pre ++ + || ( p[0] == '-' && p[1] == '-' && (type = C_SUB_PRE) ) // pre -- + ) { + var = p = script->skip_space(&p[2]); + } + // skip the variable where applicable - p = skip_word(p); - p = skip_space(p); + p = script->skip_word(p); + p = script->skip_space(p); - if( p == NULL ) {// end of the line or invalid buffer + if( p == NULL ) { + // end of the line or invalid buffer return NULL; } - if( *p == '[' ) {// array variable so process the array as appropriate + if( *p == '[' ) { + // array variable so process the array as appropriate for( p2 = p, i = 0, j = 1; p; ++ i ) { if( *p ++ == ']' && --(j) == 0 ) break; if( *p == '[' ) ++ j; } - if( !(p = skip_space(p)) ) {// end of line or invalid characters remaining + if( !(p = script->skip_space(p)) ) { + // end of line or invalid characters remaining disp_error_message("Missing right expression or closing bracket for variable.", p); } } @@ -928,9 +953,8 @@ const char* parse_variable(const char* p) { || ( p[0] == '*' && p[1] == '=' && (type = C_MUL) ) // *= || ( p[0] == '/' && p[1] == '=' && (type = C_DIV) ) // /= || ( p[0] == '%' && p[1] == '=' && (type = C_MOD) ) // %= - || ( p[0] == '~' && p[1] == '=' && (type = C_NOT) ) // ~= - || ( p[0] == '+' && p[1] == '+' && (type = C_ADD_PP) ) // ++ - || ( p[0] == '-' && p[1] == '-' && (type = C_SUB_PP) ) // -- + || ( p[0] == '+' && p[1] == '+' && (type = C_ADD_POST) ) // post ++ + || ( p[0] == '-' && p[1] == '-' && (type = C_SUB_POST) ) // post -- || ( p[0] == '<' && p[1] == '<' && p[2] == '=' && (type = C_L_SHIFT) ) // <<= || ( p[0] == '>' && p[1] == '>' && p[2] == '=' && (type = C_R_SHIFT) ) // >>= ) ) @@ -939,188 +963,229 @@ const char* parse_variable(const char* p) { } switch( type ) { - case C_EQ: {// incremental modifier - p = skip_space( &p[1] ); - } - break; + case C_ADD_PRE: // pre ++ + case C_SUB_PRE: // pre -- + // (nothing more to skip) + break; - case C_L_SHIFT: - case C_R_SHIFT: {// left or right shift modifier - p = skip_space( &p[3] ); - } - break; + case C_EQ: // = + p = script->skip_space( &p[1] ); + break; - default: {// normal incremental command - p = skip_space( &p[2] ); - } + case C_L_SHIFT: // <<= + case C_R_SHIFT: // >>= + p = script->skip_space( &p[3] ); + break; + + default: // everything else + p = script->skip_space( &p[2] ); } - if( p == NULL ) {// end of line or invalid buffer + if( p == NULL ) { + // end of line or invalid buffer return NULL; } // push the set function onto the stack - add_scriptl(buildin_set_ref); - add_scriptc(C_ARG); + script->addl(script->buildin_set_ref); + script->addc(C_ARG); // always append parenthesis to avoid errors - syntax.curly[syntax.curly_count].type = TYPE_ARGLIST; - syntax.curly[syntax.curly_count].count = 0; - syntax.curly[syntax.curly_count].flag = ARGLIST_PAREN; + script->syntax.curly[script->syntax.curly_count].type = TYPE_ARGLIST; + script->syntax.curly[script->syntax.curly_count].count = 0; + script->syntax.curly[script->syntax.curly_count].flag = ARGLIST_PAREN; // increment the total curly count for the position in the script - ++ syntax.curly_count; + ++script->syntax.curly_count; // parse the variable currently being modified - word = add_word(var); + word = script->add_word(var); - if( script->str_data[word].type == C_FUNC || script->str_data[word].type == C_USERFUNC || script->str_data[word].type == C_USERFUNC_POS ) - {// cannot assign a variable which exists as a function or label + if( script->str_data[word].type == C_FUNC + || script->str_data[word].type == C_USERFUNC + || script->str_data[word].type == C_USERFUNC_POS + ) { + // cannot assign a variable which exists as a function or label disp_error_message("Cannot modify a variable which has the same name as a function or label.", p); } - if( p2 ) {// process the variable index - const char* p3 = NULL; - - // push the getelementofarray method into the stack - add_scriptl(buildin_getelementofarray_ref); - add_scriptc(C_ARG); - add_scriptl(word); - - // process the sub-expression for this assignment - p3 = parse_subexpr(p2 + 1, 1); - p3 = skip_space(p3); + parse_variable_sub_push(word, p2); // Push variable onto the stack - if( *p3 != ']' ) {// closing parenthesis is required for this script - disp_error_message("Missing closing ']' parenthesis for the variable assignment.", p3); - } - - // push the closing function stack operator onto the stack - add_scriptc(C_FUNC); - p3 ++; - } else {// simply push the variable or value onto the stack - add_scriptl(word); + if( type != C_EQ ) { + parse_variable_sub_push(word, p2); // Push variable onto the stack once again (first argument of setr) } - if( type != C_EQ ) - add_scriptc(C_REF); + if( type == C_ADD_POST || type == C_SUB_POST ) { // post ++ / -- + script->addi(1); + script->addc(type == C_ADD_POST ? C_ADD : C_SUB); - if( type == C_ADD_PP || type == C_SUB_PP ) {// incremental operator for the method - add_scripti(1); - add_scriptc(type == C_ADD_PP ? C_ADD : C_SUB); - } else {// process the value as an expression - p = parse_subexpr(p, -1); + parse_variable_sub_push(word, p2); // Push variable onto the stack (third argument of setr) + } else if( type == C_ADD_PRE || type == C_SUB_PRE ) { // pre ++ / -- + script->addi(1); + script->addc(type == C_ADD_PRE ? C_ADD : C_SUB); + } else { + // process the value as an expression + p = script->parse_subexpr(p, -1); - if( type != C_EQ ) - {// push the type of modifier onto the stack - add_scriptc(type); + if( type != C_EQ ) { + // push the type of modifier onto the stack + script->addc(type); } } // decrement the curly count for the position within the script - -- syntax.curly_count; + --script->syntax.curly_count; // close the script by appending the function operator - add_scriptc(C_FUNC); + script->addc(C_FUNC); // push the buffer from the method return p; } +/* + * Checks whether the gives string is a number literal + * + * Mainly necessary to differentiate between number literals and NPC name + * constants, since several of those start with a digit. + * + * All this does is to check if the string begins with an optional + or - sign, + * followed by a hexadecimal or decimal number literal literal and is NOT + * followed by a underscore or letter. + * + * @param p Pointer to the string to check + * @return Whether the string is a number literal + */ +bool is_number(const char *p) { + const char *np; + if (!p) + return false; + if (*p == '-' || *p == '+') + p++; + np = p; + if (*p == '0' && p[1] == 'x') { + p+=2; + np = p; + // Hexadecimal + while (ISXDIGIT(*np)) + np++; + } else { + // Decimal + while (ISDIGIT(*np)) + np++; + } + if (p != np && *np != '_' && !ISALPHA(*np)) // At least one digit, and next isn't a letter or _ + return true; + return false; +} + /*========================================== * Analysis section *------------------------------------------*/ -const char* parse_simpleexpr(const char *p) -{ +const char* parse_simpleexpr(const char *p) { int i; - p=skip_space(p); + p=script->skip_space(p); if(*p==';' || *p==',') disp_error_message("parse_simpleexpr: unexpected end of expression",p); - if(*p=='('){ - if( (i=syntax.curly_count-1) >= 0 && syntax.curly[i].type == TYPE_ARGLIST ) - ++syntax.curly[i].count; - p=parse_subexpr(p+1,-1); - p=skip_space(p); - if( (i=syntax.curly_count-1) >= 0 && syntax.curly[i].type == TYPE_ARGLIST && - syntax.curly[i].flag == ARGLIST_UNDEFINED && --syntax.curly[i].count == 0 - ){ - if( *p == ',' ){ - syntax.curly[i].flag = ARGLIST_PAREN; + if(*p=='(') { + if( (i=script->syntax.curly_count-1) >= 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 - syntax.curly[i].flag = ARGLIST_NO_PAREN; + } else { + script->syntax.curly[i].flag = ARGLIST_NO_PAREN; + } } if( *p != ')' ) disp_error_message("parse_simpleexpr: unmatched ')'",p); ++p; - } else if(ISDIGIT(*p) || ((*p=='-' || *p=='+') && ISDIGIT(p[1]))){ + } else if(is_number(p)) { char *np; - while(*p == '0' && ISDIGIT(p[1])) p++; - i=strtoul(p,&np,0); - add_scripti(i); + 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=='"'){ - add_scriptc(C_STR); - 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; - add_scriptb(*buf); - continue; - } else if( *p == '\n' ) - disp_error_message("parse_simpleexpr: unexpected newline @ string",p); - add_scriptb(*p++); - } - if(!*p) - disp_error_message("parse_simpleexpr: unexpected end of file @ string",p); - add_scriptb(0); - p++; //'"' + } else if(*p=='"') { + script->addc(C_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->addb(*buf); + continue; + } else if( *p == '\n' ) { + disp_error_message("parse_simpleexpr: unexpected newline @ string",p); + } + script->addb(*p++); + } + if(!*p) + disp_error_message("parse_simpleexpr: unexpected end of file @ string",p); + p++; //'"' + p = script->skip_space(p); + } while( *p && *p == '"' ); + script->addb(0); } else { int l; const char* pv; // label , register , function etc - if(skip_word(p)==p) + if(script->skip_word(p)==p) disp_error_message("parse_simpleexpr: unexpected character",p); - l=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 parse_callfunc(p,1,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 = get_str(l); - if( strdb_get(userfunc_db,name) != NULL ) { - return parse_callfunc(p,1,1); + } else { + const char* name = script->get_str(l); + if( strdb_get(script->userfunc_db,name) != NULL ) { + return script->parse_callfunc(p,1,1); } - } #endif + } - if( (pv = parse_variable(p)) ) - {// successfully processed a variable assignment + if( (pv = script->parse_variable(p)) ) { + // successfully processed a variable assignment return pv; } - p=skip_word(p); - if( *p == '[' ){ + p=script->skip_word(p); + if( *p == '[' ) { // array(name[i] => getelementofarray(name,i) ) - add_scriptl(buildin_getelementofarray_ref); - add_scriptc(C_ARG); - add_scriptl(l); + script->addl(script->buildin_getelementofarray_ref); + script->addc(C_ARG); + script->addl(l); - p=parse_subexpr(p+1,-1); - p=skip_space(p); + p=script->parse_subexpr(p+1,-1); + p=script->skip_space(p); if( *p != ']' ) disp_error_message("parse_simpleexpr: unmatched ']'",p); ++p; - add_scriptc(C_FUNC); - }else - add_scriptl(l); + script->addc(C_FUNC); + } else { + script->addl(l); + } } @@ -1130,60 +1195,67 @@ const char* parse_simpleexpr(const char *p) /*========================================== * Analysis of the expression *------------------------------------------*/ -const char* parse_subexpr(const char* p,int limit) -{ +const char* script_parse_subexpr(const char* p,int limit) { int op,opl,len; const char* tmpp; - p=skip_space(p); + p=script->skip_space(p); - if( *p == '-' ){ - tmpp = skip_space(p+1); - if( *tmpp == ';' || *tmpp == ',' ){ - add_scriptl(LABEL_NEXTLINE); + if( *p == '-' ) { + tmpp = script->skip_space(p+1); + if( *tmpp == ';' || *tmpp == ',' ) { + script->addl(LABEL_NEXTLINE); p++; return p; } } - if((op=C_NEG,*p=='-') || (op=C_LNOT,*p=='!') || (op=C_NOT,*p=='~')){ - p=parse_subexpr(p+1,10); - add_scriptc(op); - } else - p=parse_simpleexpr(p); - p=skip_space(p); + if( (p[0]=='+' && p[1]=='+') /* C_ADD_PRE */ || (p[0]=='-'&&p[1]=='-') /* C_SUB_PRE */ ) { // Pre ++ -- operators + p=script->parse_variable(p); + } else if( (op=C_NEG,*p=='-') || (op=C_LNOT,*p=='!') || (op=C_NOT,*p=='~') ) { // Unary - ! ~ operators + p=script->parse_subexpr(p+1,11); + script->addc(op); + } else { + p=script->parse_simpleexpr(p); + } + p=script->skip_space(p); while(( - (op=C_OP3,opl=0,len=1,*p=='?') || - (op=C_ADD,opl=8,len=1,*p=='+') || - (op=C_SUB,opl=8,len=1,*p=='-') || - (op=C_MUL,opl=9,len=1,*p=='*') || - (op=C_DIV,opl=9,len=1,*p=='/') || - (op=C_MOD,opl=9,len=1,*p=='%') || - (op=C_LAND,opl=2,len=2,*p=='&' && p[1]=='&') || - (op=C_AND,opl=6,len=1,*p=='&') || - (op=C_LOR,opl=1,len=2,*p=='|' && p[1]=='|') || - (op=C_OR,opl=5,len=1,*p=='|') || - (op=C_XOR,opl=4,len=1,*p=='^') || - (op=C_EQ,opl=3,len=2,*p=='=' && p[1]=='=') || - (op=C_NE,opl=3,len=2,*p=='!' && p[1]=='=') || - (op=C_R_SHIFT,opl=7,len=2,*p=='>' && p[1]=='>') || - (op=C_GE,opl=3,len=2,*p=='>' && p[1]=='=') || - (op=C_GT,opl=3,len=1,*p=='>') || - (op=C_L_SHIFT,opl=7,len=2,*p=='<' && p[1]=='<') || - (op=C_LE,opl=3,len=2,*p=='<' && p[1]=='=') || - (op=C_LT,opl=3,len=1,*p=='<')) && opl>limit){ + (op=C_OP3, opl=0, len=1,*p=='?') // ?: + || (op=C_ADD, opl=9, len=1,*p=='+') // + + || (op=C_SUB, opl=9, len=1,*p=='-') // - + || (op=C_MUL, opl=10,len=1,*p=='*') // * + || (op=C_DIV, opl=10,len=1,*p=='/') // / + || (op=C_MOD, opl=10,len=1,*p=='%') // % + || (op=C_LAND, opl=2, len=2,*p=='&' && p[1]=='&') // && + || (op=C_AND, opl=5, len=1,*p=='&') // & + || (op=C_LOR, opl=1, len=2,*p=='|' && p[1]=='|') // || + || (op=C_OR, opl=3, len=1,*p=='|') // | + || (op=C_XOR, opl=4, len=1,*p=='^') // ^ + || (op=C_EQ, opl=6, len=2,*p=='=' && p[1]=='=') // == + || (op=C_NE, opl=6, len=2,*p=='!' && p[1]=='=') // != +#ifdef PCRE_SUPPORT + || (op=C_RE_EQ, opl=6, len=2,*p=='~' && p[1]=='=') // ~= + || (op=C_RE_NE, opl=6, len=2,*p=='~' && p[1]=='!') // ~! +#endif // PCRE_SUPPORT + || (op=C_R_SHIFT,opl=8, len=2,*p=='>' && p[1]=='>') // >> + || (op=C_GE, opl=7, len=2,*p=='>' && p[1]=='=') // >= + || (op=C_GT, opl=7, len=1,*p=='>') // > + || (op=C_L_SHIFT,opl=8, len=2,*p=='<' && p[1]=='<') // << + || (op=C_LE, opl=7, len=2,*p=='<' && p[1]=='=') // <= + || (op=C_LT, opl=7, len=1,*p=='<') // < + ) && opl>limit) { p+=len; if(op == C_OP3) { - p=parse_subexpr(p,-1); - p=skip_space(p); + p=script->parse_subexpr(p,-1); + p=script->skip_space(p); if( *(p++) != ':') disp_error_message("parse_subexpr: need ':'", p-1); - p=parse_subexpr(p,-1); + p=script->parse_subexpr(p,-1); } else { - p=parse_subexpr(p,opl); + p=script->parse_subexpr(p,opl); } - add_scriptc(op); - p=skip_space(p); + script->addc(op); + p=script->skip_space(p); } return p; /* return first untreated operator */ @@ -1194,12 +1266,12 @@ const char* parse_subexpr(const char* p,int limit) *------------------------------------------*/ const char* parse_expr(const char *p) { - switch(*p){ + switch(*p) { case ')': case ';': case ':': case '[': case ']': case '}': disp_error_message("parse_expr: unexpected char",p); } - p=parse_subexpr(p,-1); + p=script->parse_subexpr(p,-1); return p; } @@ -1210,43 +1282,43 @@ const char* parse_line(const char* p) { const char* p2; - p=skip_space(p); + p=script->skip_space(p); if(*p==';') { //Close decision for if(); for(); while(); - p = parse_syntax_close(p + 1); + p = script->parse_syntax_close(p + 1); return p; } - if(*p==')' && parse_syntax_for_flag) + if(*p==')' && script->parse_syntax_for_flag) return p+1; - p = skip_space(p); + p = script->skip_space(p); if(p[0] == '{') { - syntax.curly[syntax.curly_count].type = TYPE_NULL; - syntax.curly[syntax.curly_count].count = -1; - syntax.curly[syntax.curly_count].index = -1; - syntax.curly_count++; + script->syntax.curly[script->syntax.curly_count].type = TYPE_NULL; + script->syntax.curly[script->syntax.curly_count].count = -1; + script->syntax.curly[script->syntax.curly_count].index = -1; + script->syntax.curly_count++; return p + 1; } else if(p[0] == '}') { - return parse_curly_close(p); + return script->parse_curly_close(p); } // Syntax-related processing - p2 = parse_syntax(p); + p2 = script->parse_syntax(p); if(p2 != NULL) return p2; // attempt to process a variable assignment - p2 = parse_variable(p); + p2 = script->parse_variable(p); if( p2 != NULL ) {// variable assignment processed so leave the method - return parse_syntax_close(p2 + 1); + return script->parse_syntax_close(p2 + 1); } - p = parse_callfunc(p,0,0); - p = skip_space(p); + p = script->parse_callfunc(p,0,0); + p = script->skip_space(p); - if(parse_syntax_for_flag) { + if(script->parse_syntax_for_flag) { if( *p != ')' ) disp_error_message("parse_line: need ')'",p); } else { @@ -1255,7 +1327,7 @@ const char* parse_line(const char* p) } //Binding decision for if(), for(), while() - p = parse_syntax_close(p+1); + p = script->parse_syntax_close(p+1); return p; } @@ -1263,52 +1335,52 @@ const char* parse_line(const char* p) // { ... } Closing process const char* parse_curly_close(const char* p) { - if(syntax.curly_count <= 0) { + if(script->syntax.curly_count <= 0) { disp_error_message("parse_curly_close: unexpected string",p); return p + 1; - } else if(syntax.curly[syntax.curly_count-1].type == TYPE_NULL) { - syntax.curly_count--; + } else if(script->syntax.curly[script->syntax.curly_count-1].type == TYPE_NULL) { + script->syntax.curly_count--; //Close decision if, for , while - p = parse_syntax_close(p + 1); + p = script->parse_syntax_close(p + 1); return p; - } else if(syntax.curly[syntax.curly_count-1].type == TYPE_SWITCH) { + } else if(script->syntax.curly[script->syntax.curly_count-1].type == TYPE_SWITCH) { //Closing switch() - int pos = syntax.curly_count-1; + int pos = script->syntax.curly_count-1; char label[256]; int l; // Remove temporary variables - sprintf(label,"set $@__SW%x_VAL,0;",syntax.curly[pos].index); - syntax.curly[syntax.curly_count++].type = TYPE_NULL; - parse_line(label); - syntax.curly_count--; + sprintf(label,"set $@__SW%x_VAL,0;",script->syntax.curly[pos].index); + script->syntax.curly[script->syntax.curly_count++].type = TYPE_NULL; + script->parse_line(label); + script->syntax.curly_count--; // Go to the end pointer unconditionally - sprintf(label,"goto __SW%x_FIN;",syntax.curly[pos].index); - syntax.curly[syntax.curly_count++].type = TYPE_NULL; - parse_line(label); - syntax.curly_count--; + sprintf(label,"goto __SW%x_FIN;",script->syntax.curly[pos].index); + script->syntax.curly[script->syntax.curly_count++].type = TYPE_NULL; + script->parse_line(label); + script->syntax.curly_count--; // You are here labeled - sprintf(label,"__SW%x_%x",syntax.curly[pos].index,syntax.curly[pos].count); - l=add_str(label); - set_label(l,script_pos, p); + sprintf(label,"__SW%x_%x",script->syntax.curly[pos].index,script->syntax.curly[pos].count); + l=script->add_str(label); + script->set_label(l,script->pos, p); - if(syntax.curly[pos].flag) { + if(script->syntax.curly[pos].flag) { //Exists default - sprintf(label,"goto __SW%x_DEF;",syntax.curly[pos].index); - syntax.curly[syntax.curly_count++].type = TYPE_NULL; - parse_line(label); - syntax.curly_count--; + sprintf(label,"goto __SW%x_DEF;",script->syntax.curly[pos].index); + script->syntax.curly[script->syntax.curly_count++].type = TYPE_NULL; + script->parse_line(label); + script->syntax.curly_count--; } // Label end - sprintf(label,"__SW%x_FIN",syntax.curly[pos].index); - l=add_str(label); - set_label(l,script_pos, p); - linkdb_final(&syntax.curly[pos].case_label); // free the list of case label - syntax.curly_count--; + sprintf(label,"__SW%x_FIN",script->syntax.curly[pos].index); + l=script->add_str(label); + script->set_label(l,script->pos, p); + linkdb_final(&script->syntax.curly[pos].case_label); // free the list of case label + script->syntax.curly_count--; //Closing decision if, for , while - p = parse_syntax_close(p + 1); + p = script->parse_syntax_close(p + 1); return p; } else { disp_error_message("parse_curly_close: unexpected string",p); @@ -1321,27 +1393,27 @@ const char* parse_curly_close(const char* p) // if, switch, while ? will handle this internally. const char* parse_syntax(const char* p) { - const char *p2 = skip_word(p); + const char *p2 = script->skip_word(p); switch(*p) { case 'B': case 'b': - if(p2 - p == 5 && !strncasecmp(p,"break",5)) { + if( p2 - p == 5 && strncmp(p,"break",5) == 0 ) { // break Processing char label[256]; - int pos = syntax.curly_count - 1; + int pos = script->syntax.curly_count - 1; while(pos >= 0) { - if(syntax.curly[pos].type == TYPE_DO) { - sprintf(label,"goto __DO%x_FIN;",syntax.curly[pos].index); + if(script->syntax.curly[pos].type == TYPE_DO) { + sprintf(label,"goto __DO%x_FIN;",script->syntax.curly[pos].index); break; - } else if(syntax.curly[pos].type == TYPE_FOR) { - sprintf(label,"goto __FR%x_FIN;",syntax.curly[pos].index); + } else if(script->syntax.curly[pos].type == TYPE_FOR) { + sprintf(label,"goto __FR%x_FIN;",script->syntax.curly[pos].index); break; - } else if(syntax.curly[pos].type == TYPE_WHILE) { - sprintf(label,"goto __WL%x_FIN;",syntax.curly[pos].index); + } else if(script->syntax.curly[pos].type == TYPE_WHILE) { + sprintf(label,"goto __WL%x_FIN;",script->syntax.curly[pos].index); break; - } else if(syntax.curly[pos].type == TYPE_SWITCH) { - sprintf(label,"goto __SW%x_FIN;",syntax.curly[pos].index); + } else if(script->syntax.curly[pos].type == TYPE_SWITCH) { + sprintf(label,"goto __SW%x_FIN;",script->syntax.curly[pos].index); break; } pos--; @@ -1349,107 +1421,113 @@ const char* parse_syntax(const char* p) if(pos < 0) { disp_error_message("parse_syntax: unexpected 'break'",p); } else { - syntax.curly[syntax.curly_count++].type = TYPE_NULL; - parse_line(label); - syntax.curly_count--; + script->syntax.curly[script->syntax.curly_count++].type = TYPE_NULL; + script->parse_line(label); + script->syntax.curly_count--; } - p = skip_space(p2); + p = script->skip_space(p2); if(*p != ';') disp_error_message("parse_syntax: need ';'",p); // Closing decision if, for , while - p = parse_syntax_close(p + 1); + p = script->parse_syntax_close(p + 1); return p; +#ifdef ENABLE_CASE_CHECK + } else if( p2 - p == 5 && strncasecmp(p, "break", 5) == 0 ) { + disp_deprecation_message("parse_syntax", "break", p); // TODO +#endif // ENABLE_CASE_CHECK } break; case 'c': case 'C': - if(p2 - p == 4 && !strncasecmp(p,"case",4)) { + if( p2 - p == 4 && strncmp(p, "case", 4) == 0 ) { //Processing case - int pos = syntax.curly_count-1; - if(pos < 0 || syntax.curly[pos].type != TYPE_SWITCH) { + int pos = script->syntax.curly_count-1; + if(pos < 0 || script->syntax.curly[pos].type != TYPE_SWITCH) { disp_error_message("parse_syntax: unexpected 'case' ",p); return p+1; } else { char label[256]; int l,v; char *np; - if(syntax.curly[pos].count != 1) { + if(script->syntax.curly[pos].count != 1) { //Jump for FALLTHRU - sprintf(label,"goto __SW%x_%xJ;",syntax.curly[pos].index,syntax.curly[pos].count); - syntax.curly[syntax.curly_count++].type = TYPE_NULL; - parse_line(label); - syntax.curly_count--; + sprintf(label,"goto __SW%x_%xJ;",script->syntax.curly[pos].index,script->syntax.curly[pos].count); + script->syntax.curly[script->syntax.curly_count++].type = TYPE_NULL; + script->parse_line(label); + script->syntax.curly_count--; // You are here labeled - sprintf(label,"__SW%x_%x",syntax.curly[pos].index,syntax.curly[pos].count); - l=add_str(label); - set_label(l,script_pos, p); + sprintf(label,"__SW%x_%x",script->syntax.curly[pos].index,script->syntax.curly[pos].count); + l=script->add_str(label); + script->set_label(l,script->pos, p); } //Decision statement switch - p = skip_space(p2); + p = script->skip_space(p2); if(p == p2) { disp_error_message("parse_syntax: expect space ' '",p); } // check whether case label is integer or not - v = strtol(p,&np,0); - if(np == p) { //Check for constants - p2 = skip_word(p); - v = p2-p; // length of word at p2 - memcpy(label,p,v); - label[v]='\0'; - if( !script_get_constant(label, &v) ) - disp_error_message("parse_syntax: 'case' label is not an integer",p); - p = skip_word(p); - } else { //Numeric value - if((*p == '-' || *p == '+') && ISDIGIT(p[1])) // pre-skip because '-' can not skip_word + if(is_number(p)) { + //Numeric value + v = (int)strtol(p,&np,0); + if((*p == '-' || *p == '+') && ISDIGIT(p[1])) // pre-skip because '-' can not skip_word p++; - p = skip_word(p); + p = script->skip_word(p); if(np != p) disp_error_message("parse_syntax: 'case' label is not an integer",np); + } else { + //Check for constants + p2 = script->skip_word(p); + v = (int)(size_t) (p2-p); // length of word at p2 + memcpy(label,p,v); + label[v]='\0'; + if( !script->get_constant(label, &v) ) + disp_error_message("parse_syntax: 'case' label is not an integer",p); + p = script->skip_word(p); } - p = skip_space(p); + p = script->skip_space(p); if(*p != ':') disp_error_message("parse_syntax: expect ':'",p); sprintf(label,"if(%d != $@__SW%x_VAL) goto __SW%x_%x;", - v,syntax.curly[pos].index,syntax.curly[pos].index,syntax.curly[pos].count+1); - syntax.curly[syntax.curly_count++].type = TYPE_NULL; + v,script->syntax.curly[pos].index,script->syntax.curly[pos].index,script->syntax.curly[pos].count+1); + script->syntax.curly[script->syntax.curly_count++].type = TYPE_NULL; // Bad I do not parse twice - p2 = parse_line(label); - parse_line(p2); - syntax.curly_count--; - if(syntax.curly[pos].count != 1) { + p2 = script->parse_line(label); + script->parse_line(p2); + script->syntax.curly_count--; + if(script->syntax.curly[pos].count != 1) { // Label after the completion of FALLTHRU - sprintf(label,"__SW%x_%xJ",syntax.curly[pos].index,syntax.curly[pos].count); - l=add_str(label); - set_label(l,script_pos,p); + sprintf(label,"__SW%x_%xJ",script->syntax.curly[pos].index,script->syntax.curly[pos].count); + l=script->add_str(label); + script->set_label(l,script->pos,p); } // check duplication of case label [Rayce] - if(linkdb_search(&syntax.curly[pos].case_label, (void*)__64BPTRSIZE(v)) != NULL) + if(linkdb_search(&script->syntax.curly[pos].case_label, (void*)h64BPTRSIZE(v)) != NULL) disp_error_message("parse_syntax: dup 'case'",p); - linkdb_insert(&syntax.curly[pos].case_label, (void*)__64BPTRSIZE(v), (void*)1); + linkdb_insert(&script->syntax.curly[pos].case_label, (void*)h64BPTRSIZE(v), (void*)1); - sprintf(label,"set $@__SW%x_VAL,0;",syntax.curly[pos].index); - syntax.curly[syntax.curly_count++].type = TYPE_NULL; + sprintf(label,"set $@__SW%x_VAL,0;",script->syntax.curly[pos].index); + script->syntax.curly[script->syntax.curly_count++].type = TYPE_NULL; - parse_line(label); - syntax.curly_count--; - syntax.curly[pos].count++; + script->parse_line(label); + script->syntax.curly_count--; + script->syntax.curly[pos].count++; } return p + 1; - } else if(p2 - p == 8 && !strncasecmp(p,"continue",8)) { + } else if( p2 - p == 8 && strncmp(p, "continue", 8) == 0 ) { // Processing continue char label[256]; - int pos = syntax.curly_count - 1; + int pos = script->syntax.curly_count - 1; while(pos >= 0) { - if(syntax.curly[pos].type == TYPE_DO) { - sprintf(label,"goto __DO%x_NXT;",syntax.curly[pos].index); - syntax.curly[pos].flag = 1; //Flag put the link for continue + if(script->syntax.curly[pos].type == TYPE_DO) { + sprintf(label,"goto __DO%x_NXT;",script->syntax.curly[pos].index); + script->syntax.curly[pos].flag = 1; //Flag put the link for continue break; - } else if(syntax.curly[pos].type == TYPE_FOR) { - sprintf(label,"goto __FR%x_NXT;",syntax.curly[pos].index); + } else if(script->syntax.curly[pos].type == TYPE_FOR) { + sprintf(label,"goto __FR%x_NXT;",script->syntax.curly[pos].index); break; - } else if(syntax.curly[pos].type == TYPE_WHILE) { - sprintf(label,"goto __WL%x_NXT;",syntax.curly[pos].index); + } else if(script->syntax.curly[pos].type == TYPE_WHILE) { + sprintf(label,"goto __WL%x_NXT;",script->syntax.curly[pos].index); break; } pos--; @@ -1457,162 +1535,173 @@ const char* parse_syntax(const char* p) if(pos < 0) { disp_error_message("parse_syntax: unexpected 'continue'",p); } else { - syntax.curly[syntax.curly_count++].type = TYPE_NULL; - parse_line(label); - syntax.curly_count--; + script->syntax.curly[script->syntax.curly_count++].type = TYPE_NULL; + script->parse_line(label); + script->syntax.curly_count--; } - p = skip_space(p2); + p = script->skip_space(p2); if(*p != ';') disp_error_message("parse_syntax: need ';'",p); //Closing decision if, for , while - p = parse_syntax_close(p + 1); + p = script->parse_syntax_close(p + 1); return p; +#ifdef ENABLE_CASE_CHECK + } else if( p2 - p == 4 && strncasecmp(p, "case", 4) == 0 ) { + disp_deprecation_message("parse_syntax", "case", p); // TODO + } else if( p2 - p == 8 && strncasecmp(p, "continue", 8) == 0 ) { + disp_deprecation_message("parse_syntax", "continue", p); // TODO +#endif // ENABLE_CASE_CHECK } break; case 'd': case 'D': - if(p2 - p == 7 && !strncasecmp(p,"default",7)) { + if( p2 - p == 7 && strncmp(p, "default", 7) == 0 ) { // Switch - default processing - int pos = syntax.curly_count-1; - if(pos < 0 || syntax.curly[pos].type != TYPE_SWITCH) { + int pos = script->syntax.curly_count-1; + if(pos < 0 || script->syntax.curly[pos].type != TYPE_SWITCH) { disp_error_message("parse_syntax: unexpected 'default'",p); - } else if(syntax.curly[pos].flag) { + } else if(script->syntax.curly[pos].flag) { disp_error_message("parse_syntax: dup 'default'",p); } else { char label[256]; int l; // Put the label location - p = skip_space(p2); + p = script->skip_space(p2); if(*p != ':') { disp_error_message("parse_syntax: need ':'",p); } - sprintf(label,"__SW%x_%x",syntax.curly[pos].index,syntax.curly[pos].count); - l=add_str(label); - set_label(l,script_pos,p); + sprintf(label,"__SW%x_%x",script->syntax.curly[pos].index,script->syntax.curly[pos].count); + l=script->add_str(label); + script->set_label(l,script->pos,p); // Skip to the next link w/o condition - sprintf(label,"goto __SW%x_%x;",syntax.curly[pos].index,syntax.curly[pos].count+1); - syntax.curly[syntax.curly_count++].type = TYPE_NULL; - parse_line(label); - syntax.curly_count--; + sprintf(label,"goto __SW%x_%x;",script->syntax.curly[pos].index,script->syntax.curly[pos].count+1); + script->syntax.curly[script->syntax.curly_count++].type = TYPE_NULL; + script->parse_line(label); + script->syntax.curly_count--; // The default label - sprintf(label,"__SW%x_DEF",syntax.curly[pos].index); - l=add_str(label); - set_label(l,script_pos,p); + sprintf(label,"__SW%x_DEF",script->syntax.curly[pos].index); + l=script->add_str(label); + script->set_label(l,script->pos,p); - syntax.curly[syntax.curly_count - 1].flag = 1; - syntax.curly[pos].count++; + script->syntax.curly[script->syntax.curly_count - 1].flag = 1; + script->syntax.curly[pos].count++; } return p + 1; - } else if(p2 - p == 2 && !strncasecmp(p,"do",2)) { + } else if( p2 - p == 2 && strncmp(p, "do", 2) == 0 ) { int l; char label[256]; - p=skip_space(p2); + p=script->skip_space(p2); - syntax.curly[syntax.curly_count].type = TYPE_DO; - syntax.curly[syntax.curly_count].count = 1; - syntax.curly[syntax.curly_count].index = syntax.index++; - syntax.curly[syntax.curly_count].flag = 0; + script->syntax.curly[script->syntax.curly_count].type = TYPE_DO; + script->syntax.curly[script->syntax.curly_count].count = 1; + script->syntax.curly[script->syntax.curly_count].index = script->syntax.index++; + script->syntax.curly[script->syntax.curly_count].flag = 0; // Label of the (do) form here - sprintf(label,"__DO%x_BGN",syntax.curly[syntax.curly_count].index); - l=add_str(label); - set_label(l,script_pos,p); - syntax.curly_count++; + sprintf(label,"__DO%x_BGN",script->syntax.curly[script->syntax.curly_count].index); + l=script->add_str(label); + script->set_label(l,script->pos,p); + script->syntax.curly_count++; return p; +#ifdef ENABLE_CASE_CHECK + } else if( p2 - p == 7 && strncasecmp(p, "default", 7) == 0 ) { + disp_deprecation_message("parse_syntax", "default", p); // TODO + } else if( p2 - p == 2 && strncasecmp(p, "do", 2) == 0 ) { + disp_deprecation_message("parse_syntax", "do", p); // TODO +#endif // ENABLE_CASE_CHECK } break; case 'f': case 'F': - if(p2 - p == 3 && !strncasecmp(p,"for",3)) { + if( p2 - p == 3 && strncmp(p, "for", 3) == 0 ) { int l; char label[256]; - int pos = syntax.curly_count; - syntax.curly[syntax.curly_count].type = TYPE_FOR; - syntax.curly[syntax.curly_count].count = 1; - syntax.curly[syntax.curly_count].index = syntax.index++; - syntax.curly[syntax.curly_count].flag = 0; - syntax.curly_count++; + int pos = script->syntax.curly_count; + script->syntax.curly[script->syntax.curly_count].type = TYPE_FOR; + script->syntax.curly[script->syntax.curly_count].count = 1; + script->syntax.curly[script->syntax.curly_count].index = script->syntax.index++; + script->syntax.curly[script->syntax.curly_count].flag = 0; + script->syntax.curly_count++; - p=skip_space(p2); + p=script->skip_space(p2); if(*p != '(') disp_error_message("parse_syntax: need '('",p); p++; // Execute the initialization statement - syntax.curly[syntax.curly_count++].type = TYPE_NULL; - p=parse_line(p); - syntax.curly_count--; + script->syntax.curly[script->syntax.curly_count++].type = TYPE_NULL; + p=script->parse_line(p); + script->syntax.curly_count--; // Form the start of label decision - sprintf(label,"__FR%x_J",syntax.curly[pos].index); - l=add_str(label); - set_label(l,script_pos,p); + sprintf(label,"__FR%x_J",script->syntax.curly[pos].index); + l=script->add_str(label); + script->set_label(l,script->pos,p); - p=skip_space(p); + p=script->skip_space(p); if(*p == ';') { // For (; Because the pattern of always true ;) ; } else { // Skip to the end point if the condition is false - sprintf(label,"__FR%x_FIN",syntax.curly[pos].index); - add_scriptl(add_str("jump_zero")); - add_scriptc(C_ARG); - p=parse_expr(p); - p=skip_space(p); - add_scriptl(add_str(label)); - add_scriptc(C_FUNC); + sprintf(label,"__FR%x_FIN",script->syntax.curly[pos].index); + script->addl(script->add_str("jump_zero")); + script->addc(C_ARG); + p=script->parse_expr(p); + p=script->skip_space(p); + script->addl(script->add_str(label)); + script->addc(C_FUNC); } if(*p != ';') disp_error_message("parse_syntax: need ';'",p); p++; // Skip to the beginning of the loop - sprintf(label,"goto __FR%x_BGN;",syntax.curly[pos].index); - syntax.curly[syntax.curly_count++].type = TYPE_NULL; - parse_line(label); - syntax.curly_count--; + sprintf(label,"goto __FR%x_BGN;",script->syntax.curly[pos].index); + script->syntax.curly[script->syntax.curly_count++].type = TYPE_NULL; + script->parse_line(label); + script->syntax.curly_count--; // Labels to form the next loop - sprintf(label,"__FR%x_NXT",syntax.curly[pos].index); - l=add_str(label); - set_label(l,script_pos,p); + sprintf(label,"__FR%x_NXT",script->syntax.curly[pos].index); + l=script->add_str(label); + script->set_label(l,script->pos,p); // Process the next time you enter the loop // A ')' last for; flag to be treated as' - parse_syntax_for_flag = 1; - syntax.curly[syntax.curly_count++].type = TYPE_NULL; - p=parse_line(p); - syntax.curly_count--; - parse_syntax_for_flag = 0; + script->parse_syntax_for_flag = 1; + script->syntax.curly[script->syntax.curly_count++].type = TYPE_NULL; + p=script->parse_line(p); + script->syntax.curly_count--; + script->parse_syntax_for_flag = 0; // Skip to the determination process conditions - sprintf(label,"goto __FR%x_J;",syntax.curly[pos].index); - syntax.curly[syntax.curly_count++].type = TYPE_NULL; - parse_line(label); - syntax.curly_count--; + sprintf(label,"goto __FR%x_J;",script->syntax.curly[pos].index); + script->syntax.curly[script->syntax.curly_count++].type = TYPE_NULL; + script->parse_line(label); + script->syntax.curly_count--; // Loop start labeling - sprintf(label,"__FR%x_BGN",syntax.curly[pos].index); - l=add_str(label); - set_label(l,script_pos,p); + sprintf(label,"__FR%x_BGN",script->syntax.curly[pos].index); + l=script->add_str(label); + script->set_label(l,script->pos,p); return p; - } - else if( p2 - p == 8 && strncasecmp(p,"function",8) == 0 ) - {// internal script function + } else if( p2 - p == 8 && strncmp(p, "function", 8) == 0 ) { + // internal script function const char *func_name; - func_name = skip_space(p2); - p = skip_word(func_name); + func_name = script->skip_space(p2); + p = script->skip_word(func_name); if( p == func_name ) disp_error_message("parse_syntax:function: function name is missing or invalid", p); - p2 = skip_space(p); + p2 = script->skip_space(p); if( *p2 == ';' ) {// function <name> ; // function declaration - just register the name int l; - l = add_word(func_name); + l = script->add_word(func_name); if( script->str_data[l].type == C_NOP )// register only, if the name was not used by something else script->str_data[l].type = C_USERFUNC; else if( script->str_data[l].type == C_USERFUNC ) @@ -1621,7 +1710,7 @@ const char* parse_syntax(const char* p) disp_error_message("parse_syntax:function: function name is invalid", func_name); // Close condition of if, for, while - p = parse_syntax_close(p2 + 1); + p = script->parse_syntax_close(p2 + 1); return p; } else if(*p2 == '{') @@ -1629,118 +1718,136 @@ const char* parse_syntax(const char* p) char label[256]; int l; - syntax.curly[syntax.curly_count].type = TYPE_USERFUNC; - syntax.curly[syntax.curly_count].count = 1; - syntax.curly[syntax.curly_count].index = syntax.index++; - syntax.curly[syntax.curly_count].flag = 0; - ++syntax.curly_count; + script->syntax.curly[script->syntax.curly_count].type = TYPE_USERFUNC; + script->syntax.curly[script->syntax.curly_count].count = 1; + script->syntax.curly[script->syntax.curly_count].index = script->syntax.index++; + script->syntax.curly[script->syntax.curly_count].flag = 0; + ++script->syntax.curly_count; // Jump over the function code - sprintf(label, "goto __FN%x_FIN;", syntax.curly[syntax.curly_count-1].index); - syntax.curly[syntax.curly_count].type = TYPE_NULL; - ++syntax.curly_count; - parse_line(label); - --syntax.curly_count; + sprintf(label, "goto __FN%x_FIN;", script->syntax.curly[script->syntax.curly_count-1].index); + script->syntax.curly[script->syntax.curly_count].type = TYPE_NULL; + ++script->syntax.curly_count; + script->parse_line(label); + --script->syntax.curly_count; // Set the position of the function (label) - l=add_word(func_name); + l=script->add_word(func_name); 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; - set_label(l, script_pos, p); - if( parse_options&SCRIPT_USE_LABEL_DB ) - strdb_iput(scriptlabel_db, get_str(l), script_pos); + script->set_label(l, script->pos, p); + if( script->parse_options&SCRIPT_USE_LABEL_DB ) + script->label_add(l,script->pos); } else disp_error_message("parse_syntax:function: function name is invalid", func_name); - return skip_space(p); + return script->skip_space(p); } else { disp_error_message("expect ';' or '{' at function syntax",p); } +#ifdef ENABLE_CASE_CHECK + } else if( p2 - p == 3 && strncasecmp(p, "for", 3) == 0 ) { + disp_deprecation_message("parse_syntax", "for", p); // TODO + } else if( p2 - p == 8 && strncasecmp(p, "function", 8) == 0 ) { + disp_deprecation_message("parse_syntax", "function", p); // TODO +#endif // ENABLE_CASE_CHECK } break; case 'i': case 'I': - if(p2 - p == 2 && !strncasecmp(p,"if",2)) { + if( p2 - p == 2 && strncmp(p, "if", 2) == 0 ) { // If process char label[256]; - p=skip_space(p2); - if(*p != '(') { //Prevent if this {} non-c syntax. from Rayce (jA) + p=script->skip_space(p2); + if(*p != '(') { //Prevent if this {} non-c script->syntax. from Rayce (jA) disp_error_message("need '('",p); } - syntax.curly[syntax.curly_count].type = TYPE_IF; - syntax.curly[syntax.curly_count].count = 1; - syntax.curly[syntax.curly_count].index = syntax.index++; - syntax.curly[syntax.curly_count].flag = 0; - sprintf(label,"__IF%x_%x",syntax.curly[syntax.curly_count].index,syntax.curly[syntax.curly_count].count); - syntax.curly_count++; - add_scriptl(add_str("jump_zero")); - add_scriptc(C_ARG); - p=parse_expr(p); - p=skip_space(p); - add_scriptl(add_str(label)); - add_scriptc(C_FUNC); + script->syntax.curly[script->syntax.curly_count].type = TYPE_IF; + script->syntax.curly[script->syntax.curly_count].count = 1; + script->syntax.curly[script->syntax.curly_count].index = script->syntax.index++; + script->syntax.curly[script->syntax.curly_count].flag = 0; + sprintf(label,"__IF%x_%x",script->syntax.curly[script->syntax.curly_count].index,script->syntax.curly[script->syntax.curly_count].count); + script->syntax.curly_count++; + script->addl(script->add_str("jump_zero")); + script->addc(C_ARG); + p=script->parse_expr(p); + p=script->skip_space(p); + script->addl(script->add_str(label)); + script->addc(C_FUNC); return p; +#ifdef ENABLE_CASE_CHECK + } else if( p2 - p == 2 && strncasecmp(p, "if", 2) == 0 ) { + disp_deprecation_message("parse_syntax", "if", p); // TODO +#endif // ENABLE_CASE_CHECK } break; case 's': case 'S': - if(p2 - p == 6 && !strncasecmp(p,"switch",6)) { + if( p2 - p == 6 && strncmp(p, "switch", 6) == 0 ) { // Processing of switch () char label[256]; - p=skip_space(p2); + p=script->skip_space(p2); if(*p != '(') { disp_error_message("need '('",p); } - syntax.curly[syntax.curly_count].type = TYPE_SWITCH; - syntax.curly[syntax.curly_count].count = 1; - syntax.curly[syntax.curly_count].index = syntax.index++; - syntax.curly[syntax.curly_count].flag = 0; - sprintf(label,"$@__SW%x_VAL",syntax.curly[syntax.curly_count].index); - syntax.curly_count++; - add_scriptl(add_str("set")); - add_scriptc(C_ARG); - add_scriptl(add_str(label)); - p=parse_expr(p); - p=skip_space(p); + script->syntax.curly[script->syntax.curly_count].type = TYPE_SWITCH; + script->syntax.curly[script->syntax.curly_count].count = 1; + script->syntax.curly[script->syntax.curly_count].index = script->syntax.index++; + script->syntax.curly[script->syntax.curly_count].flag = 0; + sprintf(label,"$@__SW%x_VAL",script->syntax.curly[script->syntax.curly_count].index); + script->syntax.curly_count++; + script->addl(script->add_str("set")); + script->addc(C_ARG); + script->addl(script->add_str(label)); + p=script->parse_expr(p); + p=script->skip_space(p); if(*p != '{') { disp_error_message("parse_syntax: need '{'",p); } - add_scriptc(C_FUNC); + script->addc(C_FUNC); return p + 1; +#ifdef ENABLE_CASE_CHECK + } else if( p2 - p == 6 && strncasecmp(p, "switch", 6) == 0 ) { + disp_deprecation_message("parse_syntax", "switch", p); // TODO +#endif // ENABLE_CASE_CHECK } break; case 'w': case 'W': - if(p2 - p == 5 && !strncasecmp(p,"while",5)) { + if( p2 - p == 5 && strncmp(p, "while", 5) == 0 ) { int l; char label[256]; - p=skip_space(p2); + p=script->skip_space(p2); if(*p != '(') { disp_error_message("need '('",p); } - syntax.curly[syntax.curly_count].type = TYPE_WHILE; - syntax.curly[syntax.curly_count].count = 1; - syntax.curly[syntax.curly_count].index = syntax.index++; - syntax.curly[syntax.curly_count].flag = 0; + script->syntax.curly[script->syntax.curly_count].type = TYPE_WHILE; + script->syntax.curly[script->syntax.curly_count].count = 1; + script->syntax.curly[script->syntax.curly_count].index = script->syntax.index++; + script->syntax.curly[script->syntax.curly_count].flag = 0; // Form the start of label decision - sprintf(label,"__WL%x_NXT",syntax.curly[syntax.curly_count].index); - l=add_str(label); - set_label(l,script_pos,p); + sprintf(label,"__WL%x_NXT",script->syntax.curly[script->syntax.curly_count].index); + l=script->add_str(label); + script->set_label(l,script->pos,p); // Skip to the end point if the condition is false - sprintf(label,"__WL%x_FIN",syntax.curly[syntax.curly_count].index); - syntax.curly_count++; - add_scriptl(add_str("jump_zero")); - add_scriptc(C_ARG); - p=parse_expr(p); - p=skip_space(p); - add_scriptl(add_str(label)); - add_scriptc(C_FUNC); + sprintf(label,"__WL%x_FIN",script->syntax.curly[script->syntax.curly_count].index); + script->syntax.curly_count++; + script->addl(script->add_str("jump_zero")); + script->addc(C_ARG); + p=script->parse_expr(p); + p=script->skip_space(p); + script->addl(script->add_str(label)); + script->addc(C_FUNC); return p; +#ifdef ENABLE_CASE_CHECK + } else if( p2 - p == 5 && strncasecmp(p, "while", 5) == 0 ) { + disp_deprecation_message("parse_syntax", "while", p); // TODO +#endif // ENABLE_CASE_CHECK } break; } @@ -1752,183 +1859,190 @@ const char* parse_syntax_close(const char *p) { int flag; do { - p = parse_syntax_close_sub(p,&flag); + p = script->parse_syntax_close_sub(p,&flag); } while(flag); return p; } // Close judgment if, for, while, of do -// flag == 1 : closed -// flag == 0 : not closed +// flag == 1 : closed +// flag == 0 : not closed const char* parse_syntax_close_sub(const char* p,int* flag) { char label[256]; - int pos = syntax.curly_count - 1; + int pos = script->syntax.curly_count - 1; int l; *flag = 1; - if(syntax.curly_count <= 0) { + if(script->syntax.curly_count <= 0) { *flag = 0; return p; - } else if(syntax.curly[pos].type == TYPE_IF) { + } else if(script->syntax.curly[pos].type == TYPE_IF) { const char *bp = p; const char *p2; // if-block and else-block end is a new line - parse_nextline(false, p); + script->parse_nextline(false, p); // Skip to the last location if - sprintf(label,"goto __IF%x_FIN;",syntax.curly[pos].index); - syntax.curly[syntax.curly_count++].type = TYPE_NULL; - parse_line(label); - syntax.curly_count--; + sprintf(label,"goto __IF%x_FIN;",script->syntax.curly[pos].index); + script->syntax.curly[script->syntax.curly_count++].type = TYPE_NULL; + script->parse_line(label); + script->syntax.curly_count--; // Put the label of the location - sprintf(label,"__IF%x_%x",syntax.curly[pos].index,syntax.curly[pos].count); - l=add_str(label); - set_label(l,script_pos,p); - - syntax.curly[pos].count++; - p = skip_space(p); - p2 = skip_word(p); - if(!syntax.curly[pos].flag && p2 - p == 4 && !strncasecmp(p,"else",4)) { + sprintf(label,"__IF%x_%x",script->syntax.curly[pos].index,script->syntax.curly[pos].count); + l=script->add_str(label); + script->set_label(l,script->pos,p); + + script->syntax.curly[pos].count++; + p = script->skip_space(p); + p2 = script->skip_word(p); + if( !script->syntax.curly[pos].flag && p2 - p == 4 && strncmp(p, "else", 4) == 0 ) { // else or else - if - p = skip_space(p2); - p2 = skip_word(p); - if(p2 - p == 2 && !strncasecmp(p,"if",2)) { + p = script->skip_space(p2); + p2 = script->skip_word(p); + if( p2 - p == 2 && strncmp(p, "if", 2) == 0 ) { // else - if - p=skip_space(p2); + p=script->skip_space(p2); if(*p != '(') { disp_error_message("need '('",p); } - sprintf(label,"__IF%x_%x",syntax.curly[pos].index,syntax.curly[pos].count); - add_scriptl(add_str("jump_zero")); - add_scriptc(C_ARG); - p=parse_expr(p); - p=skip_space(p); - add_scriptl(add_str(label)); - add_scriptc(C_FUNC); + sprintf(label,"__IF%x_%x",script->syntax.curly[pos].index,script->syntax.curly[pos].count); + script->addl(script->add_str("jump_zero")); + script->addc(C_ARG); + p=script->parse_expr(p); + p=script->skip_space(p); + script->addl(script->add_str(label)); + script->addc(C_FUNC); *flag = 0; return p; +#ifdef ENABLE_CASE_CHECK + } else if( p2 - p == 2 && strncasecmp(p, "if", 2) == 0 ) { + disp_deprecation_message("parse_syntax", "if", p); // TODO +#endif // ENABLE_CASE_CHECK } else { // else - if(!syntax.curly[pos].flag) { - syntax.curly[pos].flag = 1; + if(!script->syntax.curly[pos].flag) { + script->syntax.curly[pos].flag = 1; *flag = 0; return p; } } +#ifdef ENABLE_CASE_CHECK + } else if( !script->syntax.curly[pos].flag && p2 - p == 4 && strncasecmp(p, "else", 4) == 0 ) { + disp_deprecation_message("parse_syntax", "else", p); // TODO +#endif // ENABLE_CASE_CHECK } // Close if - syntax.curly_count--; + script->syntax.curly_count--; // Put the label of the final location - sprintf(label,"__IF%x_FIN",syntax.curly[pos].index); - l=add_str(label); - set_label(l,script_pos,p); - if(syntax.curly[pos].flag == 1) { + sprintf(label,"__IF%x_FIN",script->syntax.curly[pos].index); + l=script->add_str(label); + script->set_label(l,script->pos,p); + if(script->syntax.curly[pos].flag == 1) { // Because the position of the pointer is the same if not else for this return bp; } return p; - } else if(syntax.curly[pos].type == TYPE_DO) { - int l; - char label[256]; + } else if(script->syntax.curly[pos].type == TYPE_DO) { const char *p2; - if(syntax.curly[pos].flag) { + if(script->syntax.curly[pos].flag) { // (Come here continue) to form the label here - sprintf(label,"__DO%x_NXT",syntax.curly[pos].index); - l=add_str(label); - set_label(l,script_pos,p); + sprintf(label,"__DO%x_NXT",script->syntax.curly[pos].index); + l=script->add_str(label); + script->set_label(l,script->pos,p); } // Skip to the end point if the condition is false - p = skip_space(p); - p2 = skip_word(p); - if(p2 - p != 5 || strncasecmp(p,"while",5)) + p = script->skip_space(p); + p2 = script->skip_word(p); + if( p2 - p != 5 || strncmp(p, "while", 5) != 0 ) { +#ifdef ENABLE_CASE_CHECK + if( p2 - p == 5 && strncasecmp(p, "while", 5) == 0 ) disp_deprecation_message("parse_syntax", "while", p); // TODO +#endif // ENABLE_CASE_CHECK disp_error_message("parse_syntax: need 'while'",p); + } - p = skip_space(p2); + p = script->skip_space(p2); if(*p != '(') { disp_error_message("need '('",p); } // do-block end is a new line - parse_nextline(false, p); + script->parse_nextline(false, p); - sprintf(label,"__DO%x_FIN",syntax.curly[pos].index); - add_scriptl(add_str("jump_zero")); - add_scriptc(C_ARG); - p=parse_expr(p); - p=skip_space(p); - add_scriptl(add_str(label)); - add_scriptc(C_FUNC); + sprintf(label,"__DO%x_FIN",script->syntax.curly[pos].index); + script->addl(script->add_str("jump_zero")); + script->addc(C_ARG); + p=script->parse_expr(p); + p=script->skip_space(p); + script->addl(script->add_str(label)); + script->addc(C_FUNC); // Skip to the starting point - sprintf(label,"goto __DO%x_BGN;",syntax.curly[pos].index); - syntax.curly[syntax.curly_count++].type = TYPE_NULL; - parse_line(label); - syntax.curly_count--; + sprintf(label,"goto __DO%x_BGN;",script->syntax.curly[pos].index); + script->syntax.curly[script->syntax.curly_count++].type = TYPE_NULL; + script->parse_line(label); + script->syntax.curly_count--; // Form label of the end point conditions - sprintf(label,"__DO%x_FIN",syntax.curly[pos].index); - l=add_str(label); - set_label(l,script_pos,p); - p = skip_space(p); + sprintf(label,"__DO%x_FIN",script->syntax.curly[pos].index); + l=script->add_str(label); + script->set_label(l,script->pos,p); + p = script->skip_space(p); if(*p != ';') { disp_error_message("parse_syntax: need ';'",p); return p+1; } p++; - syntax.curly_count--; + script->syntax.curly_count--; return p; - } else if(syntax.curly[pos].type == TYPE_FOR) { + } else if(script->syntax.curly[pos].type == TYPE_FOR) { // for-block end is a new line - parse_nextline(false, p); + script->parse_nextline(false, p); // Skip to the next loop - sprintf(label,"goto __FR%x_NXT;",syntax.curly[pos].index); - syntax.curly[syntax.curly_count++].type = TYPE_NULL; - parse_line(label); - syntax.curly_count--; + sprintf(label,"goto __FR%x_NXT;",script->syntax.curly[pos].index); + script->syntax.curly[script->syntax.curly_count++].type = TYPE_NULL; + script->parse_line(label); + script->syntax.curly_count--; // End for labeling - sprintf(label,"__FR%x_FIN",syntax.curly[pos].index); - l=add_str(label); - set_label(l,script_pos,p); - syntax.curly_count--; + sprintf(label,"__FR%x_FIN",script->syntax.curly[pos].index); + l=script->add_str(label); + script->set_label(l,script->pos,p); + script->syntax.curly_count--; return p; - } else if(syntax.curly[pos].type == TYPE_WHILE) { + } else if(script->syntax.curly[pos].type == TYPE_WHILE) { // while-block end is a new line - parse_nextline(false, p); + script->parse_nextline(false, p); // Skip to the decision while - sprintf(label,"goto __WL%x_NXT;",syntax.curly[pos].index); - syntax.curly[syntax.curly_count++].type = TYPE_NULL; - parse_line(label); - syntax.curly_count--; + sprintf(label,"goto __WL%x_NXT;",script->syntax.curly[pos].index); + script->syntax.curly[script->syntax.curly_count++].type = TYPE_NULL; + script->parse_line(label); + script->syntax.curly_count--; // End while labeling - sprintf(label,"__WL%x_FIN",syntax.curly[pos].index); - l=add_str(label); - set_label(l,script_pos,p); - syntax.curly_count--; + sprintf(label,"__WL%x_FIN",script->syntax.curly[pos].index); + l=script->add_str(label); + script->set_label(l,script->pos,p); + script->syntax.curly_count--; return p; - } else if(syntax.curly[syntax.curly_count-1].type == TYPE_USERFUNC) { - int pos = syntax.curly_count-1; - char label[256]; - int l; + } else if(script->syntax.curly[pos].type == TYPE_USERFUNC) { // Back sprintf(label,"return;"); - syntax.curly[syntax.curly_count++].type = TYPE_NULL; - parse_line(label); - syntax.curly_count--; + script->syntax.curly[script->syntax.curly_count++].type = TYPE_NULL; + script->parse_line(label); + script->syntax.curly_count--; // Put the label of the location - sprintf(label,"__FN%x_FIN",syntax.curly[pos].index); - l=add_str(label); - set_label(l,script_pos,p); - syntax.curly_count--; + sprintf(label,"__FN%x_FIN",script->syntax.curly[pos].index); + l=script->add_str(label); + script->set_label(l,script->pos,p); + script->syntax.curly_count--; return p; } else { *flag = 0; @@ -1939,7 +2053,7 @@ const char* parse_syntax_close_sub(const char* p,int* flag) /// Retrieves the value of a constant. bool script_get_constant(const char* name, int* value) { - int n = search_str(name); + int n = script->search_str(name); if( n == -1 || script->str_data[n].type != C_INT ) {// not found or not a constant @@ -1951,287 +2065,380 @@ bool script_get_constant(const char* name, int* value) } /// Creates new constant or parameter with given value. -void script_set_constant(const char* name, int value, bool isparameter) -{ - int n = add_str(name); +void script_set_constant(const char* name, int value, bool isparameter) { + int n = script->add_str(name); - if( script->str_data[n].type == C_NOP ) - {// new + if( script->str_data[n].type == C_NOP ) {// new script->str_data[n].type = isparameter ? C_PARAM : C_INT; script->str_data[n].val = value; - } - else if( script->str_data[n].type == C_PARAM || script->str_data[n].type == C_INT ) - {// existing parameter or constant + } else if( script->str_data[n].type == C_PARAM || script->str_data[n].type == C_INT ) {// existing parameter or constant ShowError("script_set_constant: Attempted to overwrite existing %s '%s' (old value=%d, new value=%d).\n", ( script->str_data[n].type == C_PARAM ) ? "parameter" : "constant", name, script->str_data[n].val, value); - } - else - {// existing name - ShowError("script_set_constant: Invalid name for %s '%s' (already defined as %s).\n", isparameter ? "parameter" : "constant", name, script_op2name(script->str_data[n].type)); + } else {// existing name + ShowError("script_set_constant: Invalid name for %s '%s' (already defined as %s).\n", isparameter ? "parameter" : "constant", name, script->op2name(script->str_data[n].type)); } } +/* adds data to a existent constant in the database, inserted normally via parse */ +void script_set_constant2(const char *name, int value, bool isparameter) { + int n = script->add_str(name); + if( script->str_data[n].type == C_PARAM ) { + ShowError("script_set_constant2: Attempted to overwrite existing parameter '%s' with a constant (value=%d).\n", name, value); + return; + } + + if( script->str_data[n].type == C_NAME && script->str_data[n].val ) { + ShowWarning("script_set_constant2: Attempted to overwrite existing variable '%s' with a constant (value=%d).\n", name, value); + return; + } + + if( script->str_data[n].type == C_INT && value && value != script->str_data[n].val ) { // existing constant + ShowWarning("script_set_constant2: Attempted to overwrite existing constant '%s' (old value=%d, new value=%d).\n", name, script->str_data[n].val, value); + return; + } + + if( script->str_data[n].type != C_NOP ) { + script->str_data[n].func = NULL; + script->str_data[n].backpatch = -1; + script->str_data[n].label = -1; + } + + script->str_data[n].type = isparameter ? C_PARAM : C_INT; + script->str_data[n].val = value; + +} /*========================================== * Reading constant databases * const.txt *------------------------------------------*/ -static void read_constdb(void) -{ +void read_constdb(void) { FILE *fp; char line[1024],name[1024],val[1024]; int type; - sprintf(line, "%s/const.txt", iMap->db_path); + sprintf(line, "%s/const.txt", map->db_path); fp=fopen(line, "r"); - if(fp==NULL){ + if(fp==NULL) { ShowError("can't read %s\n", line); return ; } - while(fgets(line, sizeof(line), fp)) - { - if(line[0]=='/' && line[1]=='/') + while (fgets(line, sizeof(line), fp)) { + if (line[0] == '/' && line[1] == '/') continue; - type=0; - if(sscanf(line,"%[A-Za-z0-9_],%[-0-9xXA-Fa-f],%d",name,val,&type)>=2 || - sscanf(line,"%[A-Za-z0-9_] %[-0-9xXA-Fa-f] %d",name,val,&type)>=2){ - script_set_constant(name, (int)strtol(val, NULL, 0), (bool)type); + type = 0; + if (sscanf(line, "%1023[A-Za-z0-9_],%1023[-0-9xXA-Fa-f],%d", name, val, &type) >=2 + || sscanf(line, "%1023[A-Za-z0-9_] %1023[-0-9xXA-Fa-f] %d", name, val, &type) >=2 + ) { + script->set_constant(name, (int)strtol(val, NULL, 0), (bool)type); } } fclose(fp); } +// Standard UNIX tab size is 8 +#define TAB_SIZE 8 +#define update_tabstop(tabstop,chars) \ + do { \ + (tabstop) -= (chars); \ + while ((tabstop) <= 0) (tabstop) += TAB_SIZE; \ + } while (false) + /*========================================== * Display emplacement line of script *------------------------------------------*/ -static const char* script_print_line(StringBuf* buf, const char* p, const char* mark, int line) +const char* script_print_line(StringBuf* buf, const char* p, const char* mark, int line) { - int i; + int i, mark_pos = 0, tabstop = TAB_SIZE; if( p == NULL || !p[0] ) return NULL; if( line < 0 ) - StrBuf->Printf(buf, "*% 5d : ", -line); + StrBuf->Printf(buf, "*%5d: ", -line); // len = 8 else - StrBuf->Printf(buf, " % 5d : ", line); - for(i=0;p[i] && p[i] != '\n';i++){ - if(p + i != mark) - StrBuf->Printf(buf, "%c", p[i]); + StrBuf->Printf(buf, " %5d: ", line); // len = 8 + update_tabstop(tabstop,8); // len = 8 + for( i=0; p[i] && p[i] != '\n'; i++ ) { + char c = p[i]; + int w = 1; + // Like Clang does, let's print the code with tabs expanded to spaces to ensure that the marker will be under the right character + if( c == '\t' ) { + c = ' '; + w = tabstop; + } + update_tabstop(tabstop, w); + if( p + i < mark) + mark_pos += w; + if( p + i != mark) + StrBuf->Printf(buf, "%*c", w, c); else - StrBuf->Printf(buf, "\'%c\'", p[i]); + StrBuf->Printf(buf, CL_BT_RED"%*c"CL_RESET, w, c); } StrBuf->AppendStr(buf, "\n"); + if( mark ) { + StrBuf->AppendStr(buf, " "CL_BT_CYAN); // len = 8 + for( ; mark_pos > 0; mark_pos-- ) { + StrBuf->AppendStr(buf, "~"); + } + StrBuf->AppendStr(buf, CL_RESET CL_BT_GREEN"^"CL_RESET"\n"); + } return p+i+(p[i] == '\n' ? 1 : 0); } +#undef TAB_SIZE +#undef update_tabstop -void script_error(const char* src, const char* file, int start_line, const char* error_msg, const char* error_pos) -{ +#define CONTEXTLINES 3 +void script_errorwarning_sub(StringBuf *buf, const char* src, const char* file, int start_line, const char* error_msg, const char* error_pos) { // Find the line where the error occurred int j; int line = start_line; - const char *p; - const char *linestart[5] = { NULL, NULL, NULL, NULL, NULL }; - StringBuf buf; + const char *p, *error_linepos; + const char *linestart[CONTEXTLINES] = { NULL }; - for(p=src;p && *p;line++){ + for(p=src;p && *p;line++) { const char *lineend=strchr(p,'\n'); - if(lineend==NULL || error_pos<lineend){ + if(lineend==NULL || error_pos<lineend) { break; } - for( j = 0; j < 4; j++ ) { + for( j = 0; j < CONTEXTLINES-1; j++ ) { linestart[j] = linestart[j+1]; } - linestart[4] = p; - p=lineend+1; + linestart[CONTEXTLINES-1] = p; + p = lineend+1; } + error_linepos = p; - StrBuf->Init(&buf); - StrBuf->AppendStr(&buf, "\a\n"); if( line >= 0 ) - StrBuf->Printf(&buf, "script error on %s line %d\n", file, line); + StrBuf->Printf(buf, "script error in file '%s' line %d column %"PRIdPTR"\n", file, line, error_pos-error_linepos+1); else - StrBuf->Printf(&buf, "script error on %s item ID %d\n", file, -line); + StrBuf->Printf(buf, "script error in file '%s' item ID %d\n", file, -line); - StrBuf->Printf(&buf, " %s\n", error_msg); - for(j = 0; j < 5; j++ ) { - script_print_line(&buf, linestart[j], NULL, line + j - 5); + StrBuf->Printf(buf, " %s\n", error_msg); + for(j = 0; j < CONTEXTLINES; j++ ) { + script->print_line(buf, linestart[j], NULL, line + j - CONTEXTLINES); } - p = script_print_line(&buf, p, error_pos, -line); - for(j = 0; j < 5; j++) { - p = script_print_line(&buf, p, NULL, line + j + 1 ); + p = script->print_line(buf, p, error_pos, -line); + for(j = 0; j < CONTEXTLINES; j++) { + p = script->print_line(buf, p, NULL, line + j + 1 ); } +} +#undef CONTEXTLINES + +void script_error(const char* src, const char* file, int start_line, const char* error_msg, const char* error_pos) { + StringBuf buf; + + StrBuf->Init(&buf); + StrBuf->AppendStr(&buf, "\a"); + + script->errorwarning_sub(&buf, src, file, start_line, error_msg, error_pos); + ShowError("%s", StrBuf->Value(&buf)); StrBuf->Destroy(&buf); } +void script_warning(const char* src, const char* file, int start_line, const char* error_msg, const char* error_pos) { + StringBuf buf; + + StrBuf->Init(&buf); + + script->errorwarning_sub(&buf, src, file, start_line, error_msg, error_pos); + + ShowWarning("%s", StrBuf->Value(&buf)); + StrBuf->Destroy(&buf); +} + /*========================================== * Analysis of the script *------------------------------------------*/ -struct script_code* parse_script(const char *src,const char *file,int line,int options) -{ +struct script_code* parse_script(const char *src,const char *file,int line,int options, int *retval) { const char *p,*tmpp; int i; struct script_code* code = NULL; char end; bool unresolved_names = false; + script->parser_current_src = src; + script->parser_current_file = file; + script->parser_current_line = line; + if( src == NULL ) return NULL;// empty script - memset(&syntax,0,sizeof(syntax)); + memset(&script->syntax,0,sizeof(script->syntax)); - script_buf=(unsigned char *)aMalloc(SCRIPT_BLOCK_SIZE*sizeof(unsigned char)); - script_pos=0; - script_size=SCRIPT_BLOCK_SIZE; - parse_nextline(true, NULL); + script->buf=(unsigned char *)aMalloc(SCRIPT_BLOCK_SIZE*sizeof(unsigned char)); + script->pos=0; + script->size=SCRIPT_BLOCK_SIZE; + 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 if( options&SCRIPT_USE_LABEL_DB ) - db_clear(scriptlabel_db); - parse_options = options; + script->label_count = 0; + script->parse_options = options; - if( setjmp( error_jump ) != 0 ) { + if( setjmp( script->error_jump ) != 0 ) { //Restore program state when script has problems. [from jA] - int i; - const int size = ARRAYLENGTH(syntax.curly); - if( error_report ) - script_error(src,file,line,error_msg,error_pos); - aFree( error_msg ); - aFree( script_buf ); - script_pos = 0; - script_size = 0; - script_buf = NULL; + const int size = ARRAYLENGTH(script->syntax.curly); + if( script->error_report ) + script->error(src,file,line,script->error_msg,script->error_pos); + aFree( script->error_msg ); + aFree( script->buf ); + script->pos = 0; + script->size = 0; + script->buf = NULL; 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++) - linkdb_final(&syntax.curly[i].case_label); + linkdb_final(&script->syntax.curly[i].case_label); +#ifdef ENABLE_CASE_CHECK + script->local_casecheck.clear(); + script->parser_current_src = NULL; + script->parser_current_file = NULL; + script->parser_current_line = 0; +#endif // ENABLE_CASE_CHECK + if (retval) *retval = EXIT_FAILURE; return NULL; } - parse_syntax_for_flag=0; + script->parse_syntax_for_flag=0; p=src; - p=skip_space(p); + 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 - aFree( script_buf ); - script_pos = 0; - script_size = 0; - script_buf = NULL; + aFree( script->buf ); + script->pos = 0; + script->size = 0; + script->buf = NULL; +#ifdef ENABLE_CASE_CHECK + script->local_casecheck.clear(); + script->parser_current_src = NULL; + script->parser_current_file = NULL; + script->parser_current_line = 0; +#endif // ENABLE_CASE_CHECK return NULL; } end = '\0'; } else {// requires brackets around the script - if( *p != '{' ) + if( *p != '{' ) { disp_error_message("not found '{'",p); - p = skip_space(p+1); + if (retval) *retval = EXIT_FAILURE; + } + p = script->skip_space(p+1); if( *p == '}' && !(options&SCRIPT_RETURN_EMPTY_SCRIPT) ) {// empty script and can return NULL - aFree( script_buf ); - script_pos = 0; - script_size = 0; - script_buf = NULL; + aFree( script->buf ); + script->pos = 0; + script->size = 0; + script->buf = NULL; +#ifdef ENABLE_CASE_CHECK + script->local_casecheck.clear(); + script->parser_current_src = NULL; + script->parser_current_file = NULL; + script->parser_current_line = 0; +#endif // ENABLE_CASE_CHECK return NULL; } end = '}'; } // clear references of labels, variables and internal functions - for(i=LABEL_START;i<script->str_num;i++){ + for(i=LABEL_START;i<script->str_num;i++) { if( script->str_data[i].type==C_POS || script->str_data[i].type==C_NAME || script->str_data[i].type==C_USERFUNC || script->str_data[i].type == C_USERFUNC_POS - ){ + ) { script->str_data[i].type=C_NOP; script->str_data[i].backpatch=-1; script->str_data[i].label=-1; } } - while( syntax.curly_count != 0 || *p != end ) + while( script->syntax.curly_count != 0 || *p != end ) { if( *p == '\0' ) disp_error_message("unexpected end of script",p); // Special handling only label - tmpp=skip_space(skip_word(p)); - if(*tmpp==':' && !(!strncasecmp(p,"default:",8) && p + 7 == tmpp)){ - i=add_word(p); - set_label(i,script_pos,p); - if( parse_options&SCRIPT_USE_LABEL_DB ) - strdb_iput(scriptlabel_db, get_str(i), script_pos); + 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); + if( script->parse_options&SCRIPT_USE_LABEL_DB ) + script->label_add(i,script->pos); p=tmpp+1; - p=skip_space(p); + p=script->skip_space(p); continue; } // All other lumped - p=parse_line(p); - p=skip_space(p); + p=script->parse_line(p); + p=script->skip_space(p); - parse_nextline(false, p); + script->parse_nextline(false, p); } - add_scriptc(C_NOP); + script->addc(C_NOP); // trim code to size - script_size = script_pos; - RECREATE(script_buf,unsigned char,script_pos); + script->size = script->pos; + RECREATE(script->buf,unsigned char,script->pos); // default unknown references to variables - for(i=LABEL_START;i<script->str_num;i++){ - if(script->str_data[i].type==C_NOP){ + for(i=LABEL_START;i<script->str_num;i++) { + if(script->str_data[i].type==C_NOP) { int j,next; script->str_data[i].type=C_NAME; script->str_data[i].label=i; - for(j=script->str_data[i].backpatch;j>=0 && j!=0x00ffffff;){ - next=GETVALUE(script_buf,j); - SETVALUE(script_buf,j,i); + for(j=script->str_data[i].backpatch;j>=0 && j!=0x00ffffff;) { + next=GETVALUE(script->buf,j); + SETVALUE(script->buf,j,i); j=next; } } else if( script->str_data[i].type == C_USERFUNC ) {// 'function name;' without follow-up code ShowError("parse_script: function '%s' declared but not defined.\n", script->str_buf+script->str_data[i].str); + if (retval) *retval = EXIT_FAILURE; unresolved_names = true; } } - if( unresolved_names ) - { + if( unresolved_names ) { disp_error_message("parse_script: unresolved function references", p); + if (retval) *retval = EXIT_FAILURE; } -#ifdef DEBUG_DISP - for(i=0;i<script_pos;i++){ +#ifdef SCRIPT_DEBUG_DISP + for(i=0;i<script->pos;i++) { if((i&15)==0) ShowMessage("%04x : ",i); - ShowMessage("%02x ",script_buf[i]); + ShowMessage("%02x ",script->buf[i]); if((i&15)==15) ShowMessage("\n"); } ShowMessage("\n"); #endif -#ifdef DEBUG_DISASM +#ifdef SCRIPT_DEBUG_DISASM { int i = 0,j; - while(i < script_pos) { - c_op op = get_com(script_buf,&i); + while(i < script->pos) { + c_op op = script->get_com(script->buf,&i); - ShowMessage("%06x %s", i, script_op2name(op)); + ShowMessage("%06x %s", i, script->op2name(op)); j = i; switch(op) { case C_INT: - ShowMessage(" %d", 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*)(script->buf+i)&0xffffff); i += 3; break; case C_NAME: - j = (*(int*)(script_buf+i)&0xffffff); - ShowMessage(" %s", ( j == 0xffffff ) ? "?? unknown ??" : get_str(j)); + j = (*(int*)(script->buf+i)&0xffffff); + ShowMessage(" %s", ( j == 0xffffff ) ? "?? unknown ??" : script->get_str(j)); i += 3; break; case C_STR: - j = strlen(script_buf + i); - ShowMessage(" %s", script_buf + i); + j = strlen((char*)script->buf + i); + ShowMessage(" %s", script->buf + i); i += j+1; break; } @@ -2241,9 +2448,16 @@ 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 = script_buf; - code->script_size = script_size; - code->script_vars = NULL; + code->script_buf = script->buf; + code->script_size = script->size; + code->local.vars = NULL; + code->local.arrays = NULL; +#ifdef ENABLE_CASE_CHECK + script->local_casecheck.clear(); + script->parser_current_src = NULL; + script->parser_current_file = NULL; + script->parser_current_line = 0; +#endif // ENABLE_CASE_CHECK return code; } @@ -2251,28 +2465,30 @@ struct script_code* parse_script(const char *src,const char *file,int line,int o /// If there is no player attached, the script is terminated. TBL_PC *script_rid2sd(struct script_state *st) { TBL_PC *sd; - if( !( sd = iMap->id2sd(st->rid) ) ){ + if( !( sd = map->id2sd(st->rid) ) ) { ShowError("script_rid2sd: fatal error ! player not attached!\n"); - script_reportfunc(st); - script_reportsrc(st); + script->reportfunc(st); + script->reportsrc(st); st->state = END; } return sd; } -/// Dereferences a variable/constant, replacing it with a copy of the value. -/// -/// @param st Script state -/// @param data Variable/constant -void get_val(struct script_state* st, struct script_data* data) -{ +/** + * Dereferences a variable/constant, replacing it with a copy of the value. + * + * @param st[in] script state. + * @param data[in,out] variable/constant. + * @return pointer to data, for convenience. + */ +struct script_data *get_val(struct script_state* st, struct script_data* data) { const char* name; char prefix; char postfix; TBL_PC* sd = NULL; if( !data_isreference(data) ) - return;// not a variable/constant + return data;// not a variable/constant name = reference_getname(data); prefix = name[0]; @@ -2280,18 +2496,18 @@ void get_val(struct script_state* st, struct script_data* data) //##TODO use reference_tovariable(data) when it's confirmed that it works [FlavioJS] if( !reference_toconstant(data) && not_server_variable(prefix) ) { - sd = script_rid2sd(st); + sd = script->rid2sd(st); if( sd == NULL ) {// needs player attached if( postfix == '$' ) {// string variable - ShowWarning("script:script->get_val: cannot access player variable '%s', defaulting to \"\"\n", name); + ShowWarning("script_get_val: cannot access player variable '%s', defaulting to \"\"\n", name); data->type = C_CONSTSTR; data->u.str = ""; } else {// integer variable - ShowWarning("script:script->get_val: cannot access player variable '%s', defaulting to 0\n", name); + ShowWarning("script_get_val: cannot access player variable '%s', defaulting to 0\n", name); data->type = C_INT; data->u.num = 0; } - return; + return data; } } @@ -2302,36 +2518,36 @@ void get_val(struct script_state* st, struct script_data* data) data->u.str = pc->readregstr(sd, data->u.num); break; case '$': - data->u.str = mapreg_readregstr(data->u.num); + data->u.str = mapreg->readregstr(data->u.num); break; case '#': if( name[1] == '#' ) - data->u.str = pc_readaccountreg2str(sd, name);// global + data->u.str = pc_readaccountreg2str(sd, data->u.num);// global else - data->u.str = pc_readaccountregstr(sd, name);// local + data->u.str = pc_readaccountregstr(sd, data->u.num);// local break; case '.': { - struct DBMap* n = - data->ref ? *data->ref: - name[1] == '@' ? st->stack->var_function:// instance/scope variable - st->script->script_vars;// npc variable + struct DBMap* n = data->ref ? + data->ref->vars : name[1] == '@' ? + st->stack->scope.vars : // instance/scope variable + st->script->local.vars; // npc variable if( n ) - data->u.str = (char*)idb_get(n,reference_getuid(data)); + data->u.str = (char*)i64db_get(n,reference_getuid(data)); else data->u.str = NULL; } break; case '\'': if ( st->instance_id >= 0 ) { - data->u.str = (char*)idb_get(instances[st->instance_id].vars,reference_getuid(data)); + data->u.str = (char*)i64db_get(instance->list[st->instance_id].regs.vars, reference_getuid(data)); } else { - ShowWarning("script:script->get_val: cannot access instance variable '%s', defaulting to \"\"\n", name); + ShowWarning("script_get_val: cannot access instance variable '%s', defaulting to \"\"\n", name); data->u.str = NULL; } break; default: - data->u.str = pc_readglobalreg_str(sd, name); + data->u.str = pc_readglobalreg_str(sd, data->u.num); break; } @@ -2357,106 +2573,362 @@ void get_val(struct script_state* st, struct script_data* data) data->u.num = pc->readreg(sd, data->u.num); break; case '$': - data->u.num = mapreg_readreg(data->u.num); + data->u.num = mapreg->readreg(data->u.num); break; case '#': if( name[1] == '#' ) - data->u.num = pc_readaccountreg2(sd, name);// global + data->u.num = pc_readaccountreg2(sd, data->u.num);// global else - data->u.num = pc_readaccountreg(sd, name);// local + data->u.num = pc_readaccountreg(sd, data->u.num);// local break; case '.': { - struct DBMap* n = - data->ref ? *data->ref: - name[1] == '@' ? st->stack->var_function:// instance/scope variable - st->script->script_vars;// npc variable + struct DBMap* n = data->ref ? + data->ref->vars : name[1] == '@' ? + st->stack->scope.vars : // instance/scope variable + st->script->local.vars; // npc variable if( n ) - data->u.num = (int)idb_iget(n,reference_getuid(data)); + data->u.num = (int)i64db_iget(n,reference_getuid(data)); else data->u.num = 0; } break; case '\'': if( st->instance_id >= 0 ) - data->u.num = (int)idb_iget(instances[st->instance_id].vars,reference_getuid(data)); + data->u.num = (int)i64db_iget(instance->list[st->instance_id].regs.vars, reference_getuid(data)); else { - ShowWarning("script:script->get_val: cannot access instance variable '%s', defaulting to 0\n", name); + ShowWarning("script_get_val: cannot access instance variable '%s', defaulting to 0\n", name); data->u.num = 0; } break; default: - data->u.num = pc_readglobalreg(sd, name); + data->u.num = pc_readglobalreg(sd, data->u.num); break; } } + data->ref = NULL; - return; + return data; } -/// Retrieves the value of a reference identified by uid (variable, constant, param) -/// The value is left in the top of the stack and needs to be removed manually. -void* get_val2(struct script_state* st, int uid, struct DBMap** ref) { +/** + * Retrieves the value of a reference identified by uid (variable, constant, param) + * + * The value is left in the top of the stack and needs to be removed manually. + * + * @param st[in] script state. + * @param uid[in] reference identifier. + * @param ref[in] the container to look up the reference into. + * @return the retrieved value of the reference. + */ +void* get_val2(struct script_state* st, int64 uid, struct reg_db *ref) { struct script_data* data; script->push_val(st->stack, C_NAME, uid, ref); data = script_getdatatop(st, -1); script->get_val(st, data); - return (data->type == C_INT ? (void*)__64BPTRSIZE(data->u.num) : (void*)__64BPTRSIZE(data->u.str)); + return (data->type == C_INT ? (void*)h64BPTRSIZE((int32)data->u.num) : (void*)h64BPTRSIZE(data->u.str)); // u.num is int32 because it comes from script->get_val +} +/** + * Because, currently, array members with key 0 are indifferenciable from normal variables, we should ensure its actually in + * Will be gone as soon as undefined var feature is implemented + **/ +void script_array_ensure_zero(struct script_state *st, struct map_session_data *sd, int64 uid, struct reg_db *ref) { + const char *name = script->get_str(script_getvarid(uid)); + struct reg_db *src = script->array_src(st, sd ? sd : st->rid ? map->id2sd(st->rid) : NULL, name, ref); + struct script_array *sa = NULL; + bool insert = false; + + if( sd && !st ) /* when sd comes, st isn't available */ + insert = true; + else { + if( is_string_variable(name) ) { + char* str = (char*)script->get_val2(st, uid, ref); + if( str && *str ) + insert = true; + script_removetop(st, -1, 0); + } else { + int32 num = (int32)h64BPTRSIZE(script->get_val2(st, uid, ref)); + if( num ) + insert = true; + script_removetop(st, -1, 0); + } + } + + if( src && src->arrays ) { + if( (sa = idb_get(src->arrays, script_getvarid(uid)) ) ) { + unsigned int i; + + ARR_FIND(0, sa->size, i, sa->members[i] == 0); + if( i != sa->size ) { + if( !insert ) + script->array_remove_member(src,sa,i); + return; + } + + script->array_add_member(sa,0); + } else if( insert ) { + script->array_update(src,reference_uid(script_getvarid(uid), 0),false); + } + } +} +/** + * Returns array size by ID + **/ +unsigned int script_array_size(struct script_state *st, struct map_session_data *sd, const char *name, struct reg_db *ref) { + struct script_array *sa = NULL; + struct reg_db *src = script->array_src(st, sd, name, ref); + + if( src && src->arrays ) + sa = idb_get(src->arrays, script->search_str(name)); + + return sa ? sa->size : 0; +} +/** + * Returns array's highest key (for that awful getarraysize implementation that doesn't really gets the array size) + **/ +unsigned int script_array_highest_key(struct script_state *st, struct map_session_data *sd, const char *name, struct reg_db *ref) { + struct script_array *sa = NULL; + struct reg_db *src = script->array_src(st, sd, name, ref); + + + if( src && src->arrays ) { + int key = script->add_word(name); + + script->array_ensure_zero(st,sd,reference_uid(key, 0),ref); + + if( ( sa = idb_get(src->arrays, key) ) ) { + unsigned int i, highest_key = 0; + + for(i = 0; i < sa->size; i++) { + if( sa->members[i] > highest_key ) + highest_key = sa->members[i]; + } + + return sa->size ? highest_key + 1 : 0; + } + } + + return 0; +} +int script_free_array_db(DBKey key, DBData *data, va_list ap) { + struct script_array *sa = DB->data2ptr(data); + aFree(sa->members); + ers_free(script->array_ers, sa); + return 0; +} +/** + * Clears script_array and removes it from script->array_db + **/ +void script_array_delete(struct reg_db *src, struct script_array *sa) { + aFree(sa->members); + idb_remove(src->arrays, sa->id); + ers_free(script->array_ers, sa); +} +/** + * Removes a member from a script_array list + * + * @param idx the index of the member in script_array struct list, not of the actual array member + **/ +void script_array_remove_member(struct reg_db *src, struct script_array *sa, unsigned int idx) { + unsigned int i, cursor; + + /* its the only member left, no need to do anything other than delete the array data */ + if( sa->size == 1 ) { + script->array_delete(src,sa); + return; + } + + sa->members[idx] = UINT_MAX; + + for(i = 0, cursor = 0; i < sa->size; i++) { + if( sa->members[i] == UINT_MAX ) + continue; + if( i != cursor ) + sa->members[cursor] = sa->members[i]; + cursor++; + } + + sa->size = cursor; } +/** + * Appends a new array index to the list in script_array + * + * @param idx the index of the array member being inserted + **/ +void script_array_add_member(struct script_array *sa, unsigned int idx) { + + RECREATE(sa->members, unsigned int, ++sa->size); + + sa->members[sa->size - 1] = idx; -/*========================================== +} +/** + * Obtains the source of the array database for this type and scenario + * Initializes such database when not yet initialized. + **/ +struct reg_db *script_array_src(struct script_state *st, struct map_session_data *sd, const char *name, struct reg_db *ref) { + struct reg_db *src = NULL; + + switch( name[0] ) { + /* from player */ + default: /* char reg */ + case '@':/* temp char reg */ + case '#':/* account reg */ + src = &sd->regs; + break; + case '$':/* map reg */ + src = &mapreg->regs; + break; + case '.':/* npc/script */ + if( ref ) + src = ref; + else + src = (name[1] == '@') ? &st->stack->scope : &st->script->local; + break; + case '\'':/* instance */ + if( st->instance_id >= 0 ) { + src = &instance->list[st->instance_id].regs; + } + break; + } + + if( src ) { + if( !src->arrays ) + src->arrays = idb_alloc(DB_OPT_BASE); + return src; + } + + return NULL; +} + +/** + * Processes a array member modification, and update data accordingly + * + * @param src[in,out] Variable source database. If the array database doesn't exist, it is created. + * @param num[in] Variable ID + * @param empty[in] Whether the modified member is empty (needs to be removed) + **/ +void script_array_update(struct reg_db *src, int64 num, bool empty) { + struct script_array *sa = NULL; + int id = script_getvarid(num); + unsigned int index = script_getvaridx(num); + + if (!src->arrays) { + src->arrays = idb_alloc(DB_OPT_BASE); + } else { + sa = idb_get(src->arrays, id); + } + + if( sa ) { + unsigned int i; + + /* search */ + for(i = 0; i < sa->size; i++) { + if( sa->members[i] == index ) + break; + } + + /* if existent */ + if( i != sa->size ) { + /* if empty, we gotta remove it */ + if( empty ) { + script->array_remove_member(src, sa, i); + } + } else if( !empty ) { /* new entry */ + script->array_add_member(sa,index); + /* we do nothing if its empty, no point in modifying array data for a new empty member */ + } + } else if ( !empty ) {/* we only move to create if not empty */ + sa = ers_alloc(script->array_ers, struct script_array); + sa->id = id; + sa->members = NULL; + sa->size = 0; + script->array_add_member(sa,index); + idb_put(src->arrays, id, sa); + } +} + +/** * Stores the value of a script variable - * Return value is 0 on fail, 1 on success. + * + * @param st current script state. + * @param sd current character data. + * @param num variable identifier. + * @param name variable name. + * @param value new value. + * @param ref variable container, in case of a npc/scope variable reference outside the current scope. + * @retval 0 failure. + * @retval 1 success. + * + * TODO: return values are screwed up, have been for some time (reaad: years), e.g. some functions return 1 failure and success. *------------------------------------------*/ -static int set_reg(struct script_state* st, TBL_PC* sd, int num, const char* name, const void* value, struct DBMap** ref) -{ +int set_reg(struct script_state* st, TBL_PC* sd, int64 num, const char* name, const void* value, struct reg_db *ref) { char prefix = name[0]; + + if( is_string_variable(name) ) {// string variable + const char *str = (const char*)value; - if( is_string_variable(name) ) - {// string variable - const char* str = (const char*)value; switch (prefix) { - case '@': - return pc->setregstr(sd, num, str); - case '$': - return mapreg_setregstr(num, str); - case '#': - return (name[1] == '#') ? - pc_setaccountreg2str(sd, name, str) : - pc_setaccountregstr(sd, name, str); - case '.': - { - struct DBMap* n; - n = (ref) ? *ref : (name[1] == '@') ? st->stack->var_function : st->script->script_vars; - if( n ) { - idb_remove(n, num); - if (str[0]) idb_put(n, num, aStrdup(str)); + case '@': + pc->setregstr(sd, num, str); + return 1; + case '$': + return mapreg->setregstr(num, str); + case '#': + return (name[1] == '#') ? + pc_setaccountreg2str(sd, num, str) : + pc_setaccountregstr(sd, num, str); + case '.': + { + struct reg_db *n = (ref) ? ref : (name[1] == '@') ? &st->stack->scope : &st->script->local; + if( n ) { + if (str[0]) { + i64db_put(n->vars, num, aStrdup(str)); + if( script_getvaridx(num) ) + script->array_update(n, num, false); + } else { + i64db_remove(n->vars, num); + if( script_getvaridx(num) ) + script->array_update(n, num, true); + } + } } - } - return 1; - case '\'': - if( st->instance_id >= 0 ) { - idb_remove(instances[st->instance_id].vars, num); - if( str[0] ) idb_put(instances[st->instance_id].vars, num, aStrdup(str)); - } - return 1; - default: - return pc_setglobalreg_str(sd, name, str); + return 1; + case '\'': + if( st->instance_id >= 0 ) { + if( str[0] ) { + i64db_put(instance->list[st->instance_id].regs.vars, num, aStrdup(str)); + if( script_getvaridx(num) ) + script->array_update(&instance->list[st->instance_id].regs, num, false); + } else { + i64db_remove(instance->list[st->instance_id].regs.vars, num); + if( script_getvaridx(num) ) + script->array_update(&instance->list[st->instance_id].regs, num, true); + } + } else { + ShowError("script_set_reg: cannot write instance variable '%s', NPC not in a instance!\n", name); + script_reportsrc(st); + } + return 1; + default: + return pc_setglobalreg_str(sd, num, str); } - } - else - {// integer variable - int val = (int)__64BPTRSIZE(value); - if(script->str_data[num&0x00ffffff].type == C_PARAM) - { - if( pc->setparam(sd, script->str_data[num&0x00ffffff].val, val) == 0 ) - { - if( st != NULL ) - { + } else {// integer variable + // FIXME: This isn't safe, in 32bits systems we're converting a 64bit pointer + // to a 32bit int, this will lead to overflows! [Panikon] + int val = (int)h64BPTRSIZE(value); + + if(script->str_data[script_getvarid(num)].type == C_PARAM) { + if( pc->setparam(sd, script->str_data[script_getvarid(num)].val, val) == 0 ) { + if( st != NULL ) { ShowError("script:set_reg: failed to set param '%s' to %d.\n", name, val); - script_reportsrc(st); - st->state = END; + script->reportsrc(st); + // Instead of just stop the script execution we let the character close + // the window if it was open. + st->state = (sd->state.dialog) ? CLOSE : END; + if( st->state == CLOSE ) + clif->scriptclose(sd, st->oid); } return 0; } @@ -2464,46 +2936,59 @@ static int set_reg(struct script_state* st, TBL_PC* sd, int num, const char* nam } switch (prefix) { - case '@': - return pc->setreg(sd, num, val); - case '$': - return mapreg_setreg(num, val); - case '#': - return (name[1] == '#') ? - pc_setaccountreg2(sd, name, val) : - pc_setaccountreg(sd, name, val); - case '.': - { - struct DBMap* n; - n = (ref) ? *ref : (name[1] == '@') ? st->stack->var_function : st->script->script_vars; - if( n ) { - idb_remove(n, num); - if( val != 0 ) - idb_iput(n, num, val); + case '@': + pc->setreg(sd, num, val); + return 1; + case '$': + return mapreg->setreg(num, val); + case '#': + return (name[1] == '#') ? + pc_setaccountreg2(sd, num, val) : + pc_setaccountreg(sd, num, val); + case '.': + { + struct reg_db *n = (ref) ? ref : (name[1] == '@') ? &st->stack->scope : &st->script->local; + if( n ) { + if( val != 0 ) { + i64db_iput(n->vars, num, val); + if( script_getvaridx(num) ) + script->array_update(n, num, false); + } else { + i64db_remove(n->vars, num); + if( script_getvaridx(num) ) + script->array_update(n, num, true); + } + } } - } - return 1; - case '\'': - if( st->instance_id >= 0 ) { - idb_remove(instances[st->instance_id].vars, num); - if( val != 0 ) - idb_iput(instances[st->instance_id].vars, num, val); - } - return 1; - default: - return pc_setglobalreg(sd, name, val); + return 1; + case '\'': + if( st->instance_id >= 0 ) { + if( val != 0 ) { + i64db_iput(instance->list[st->instance_id].regs.vars, num, val); + if( script_getvaridx(num) ) + script->array_update(&instance->list[st->instance_id].regs, num, false); + } else { + i64db_remove(instance->list[st->instance_id].regs.vars, num); + if( script_getvaridx(num) ) + script->array_update(&instance->list[st->instance_id].regs, num, true); + } + } else { + ShowError("script_set_reg: cannot write instance variable '%s', NPC not in a instance!\n", name); + script_reportsrc(st); + } + return 1; + default: + return pc_setglobalreg(sd, num, val); } } } -int set_var(TBL_PC* sd, char* name, void* val) -{ - return set_reg(NULL, sd, reference_uid(add_str(name),0), name, val, NULL); +int set_var(TBL_PC* sd, char* name, void* val) { + return script->set_reg(NULL, sd, reference_uid(script->add_str(name),0), name, val, NULL); } -void setd_sub(struct script_state *st, TBL_PC *sd, const char *varname, int elem, void *value, struct DBMap **ref) -{ - set_reg(st, sd, reference_uid(add_str(varname),elem), varname, value, ref); +void setd_sub(struct script_state *st, TBL_PC *sd, const char *varname, int elem, void *value, struct reg_db *ref) { + script->set_reg(st, sd, reference_uid(script->add_str(varname),elem), varname, value, ref); } /// Converts the data to a string @@ -2518,7 +3003,7 @@ const char* conv_str(struct script_state* st, struct script_data* data) else if( data_isint(data) ) {// int -> string CREATE(p, char, ITEM_NAME_LENGTH); - snprintf(p, ITEM_NAME_LENGTH, "%d", data->u.num); + snprintf(p, ITEM_NAME_LENGTH, "%"PRId64"", data->u.num); p[ITEM_NAME_LENGTH-1] = '\0'; data->type = C_STR; data->u.str = p; @@ -2532,8 +3017,8 @@ const char* conv_str(struct script_state* st, struct script_data* data) else {// unsupported data type ShowError("script:conv_str: cannot convert to string, defaulting to \"\"\n"); - script_reportdata(data); - script_reportsrc(st); + script->reportdata(data); + script->reportsrc(st); data->type = C_CONSTSTR; data->u.str = ""; } @@ -2572,8 +3057,8 @@ int conv_num(struct script_state* st, struct script_data* data) { num = INT_MAX; ShowError("script:conv_num: overflow detected, capping to %ld\n", num); } - script_reportdata(data); - script_reportsrc(st); + script->reportdata(data); + script->reportsrc(st); } if( data->type == C_STR ) aFree(p); @@ -2586,13 +3071,13 @@ int conv_num(struct script_state* st, struct script_data* data) { else {// unsupported data type ShowError("script:conv_num: cannot convert to number, defaulting to 0\n"); - script_reportdata(data); - script_reportsrc(st); + script->reportdata(data); + script->reportsrc(st); data->type = C_INT; data->u.num = 0; } #endif - return data->u.num; + return (int)data->u.num; } // @@ -2609,9 +3094,9 @@ void stack_expand(struct script_stack* stack) { } /// Pushes a value into the stack (with reference) -struct script_data* push_val(struct script_stack* stack, enum c_op type, int val, struct DBMap** ref) { +struct script_data* push_val(struct script_stack* stack, enum c_op type, int64 val, struct reg_db *ref) { if( stack->sp >= stack->sp_max ) - stack_expand(stack); + script->stack_expand(stack); stack->stack_data[stack->sp].type = type; stack->stack_data[stack->sp].u.num = val; stack->stack_data[stack->sp].ref = ref; @@ -2623,7 +3108,7 @@ struct script_data* push_val(struct script_stack* stack, enum c_op type, int val struct script_data* push_str(struct script_stack* stack, enum c_op type, char* str) { if( stack->sp >= stack->sp_max ) - stack_expand(stack); + script->stack_expand(stack); stack->stack_data[stack->sp].type = type; stack->stack_data[stack->sp].u.str = str; stack->stack_data[stack->sp].ref = NULL; @@ -2632,10 +3117,9 @@ struct script_data* push_str(struct script_stack* stack, enum c_op type, char* s } /// Pushes a retinfo into the stack -struct script_data* push_retinfo(struct script_stack* stack, struct script_retinfo* ri, DBMap **ref) -{ +struct script_data* push_retinfo(struct script_stack* stack, struct script_retinfo* ri, struct reg_db *ref) { if( stack->sp >= stack->sp_max ) - stack_expand(stack); + script->stack_expand(stack); stack->stack_data[stack->sp].type = C_RETINFO; stack->stack_data[stack->sp].u.ri = ri; stack->stack_data[stack->sp].ref = ref; @@ -2668,8 +3152,7 @@ struct script_data* push_copy(struct script_stack* stack, int pos) { /// Removes the values in indexes [start,end[ from the stack. /// Adjusts all stack pointers. -void pop_stack(struct script_state* st, int start, int end) -{ +void pop_stack(struct script_state* st, int start, int end) { struct script_stack* stack = st->stack; struct script_data* data; int i; @@ -2690,8 +3173,18 @@ void pop_stack(struct script_state* st, int start, int end) if( data->type == C_RETINFO ) { struct script_retinfo* ri = data->u.ri; - if( ri->var_function ) - script_free_vars(ri->var_function); + if( ri->scope.vars ) { + // Note: This is necessary evern if we're also doing it in run_func + // (in the RETFUNC block) because not all functions return. If a + // function (or a sub) has an 'end' or a 'close', it'll reach this + // block with its scope vars still to be freed. + script->free_vars(ri->scope.vars); + ri->scope.vars = NULL; + } + if( ri->scope.arrays ) { + ri->scope.arrays->destroy(ri->scope.arrays,script->array_free_db); + ri->scope.arrays = NULL; + } if( data->ref ) aFree(data->ref); aFree(ri); @@ -2706,12 +3199,18 @@ void pop_stack(struct script_state* st, int start, int end) stack->stack_data[i].type = C_NOP; } // adjust stack pointers - if( st->start > end ) st->start -= end - start; - else if( st->start > start ) st->start = start; - if( st->end > end ) st->end -= end - start; - else if( st->end > start ) st->end = start; - if( stack->defsp > end ) stack->defsp -= end - start; - else if( stack->defsp > start ) stack->defsp = start; + if( st->start > end ) + st->start -= end - start; + else if( st->start > start ) + st->start = start; + if( st->end > end ) + st->end -= end - start; + else if( st->end > start ) + st->end = start; + if( stack->defsp > end ) + stack->defsp -= end - start; + else if( stack->defsp > start ) + stack->defsp = start; stack->sp -= end - start; } @@ -2722,17 +3221,24 @@ void pop_stack(struct script_state* st, int start, int end) /*========================================== * Release script dependent variable, dependent variable of function *------------------------------------------*/ -void script_free_vars(struct DBMap* storage) -{ - if( storage ) - {// destroy the storage construct containing the variables - db_destroy(storage); +void script_free_vars(struct DBMap* var_storage) { + if( var_storage ) { + // destroy the storage construct containing the variables + db_destroy(var_storage); } } void script_free_code(struct script_code* code) { - script_free_vars( code->script_vars ); + nullpo_retv(code); + + if( code->instances ) + script->stop_instances(code); + else { + 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 ); aFree( code ); } @@ -2746,14 +3252,17 @@ void script_free_code(struct script_code* code) /// @return Script state struct script_state* script_alloc_state(struct script_code* rootscript, int pos, int rid, int oid) { struct script_state* st; - + st = ers_alloc(script->st_ers, struct script_state); st->stack = ers_alloc(script->stack_ers, struct script_stack); + st->pending_refs = NULL; + st->pending_ref_count = 0; st->stack->sp = 0; st->stack->sp_max = 64; CREATE(st->stack->stack_data, struct script_data, st->stack->sp_max); st->stack->defsp = st->stack->sp; - st->stack->var_function = idb_alloc(DB_OPT_RELEASE_DATA); + st->stack->scope.vars = i64db_alloc(DB_OPT_RELEASE_DATA); + st->stack->scope.arrays = NULL; st->state = RUN; st->script = rootscript; st->pos = pos; @@ -2762,91 +3271,125 @@ struct script_state* script_alloc_state(struct script_code* rootscript, int pos, st->sleep.timer = INVALID_TIMER; st->npc_item_flag = battle_config.item_enabled_npc; - if( !st->script->script_vars ) - st->script->script_vars = idb_alloc(DB_OPT_RELEASE_DATA); - + if( st->script->instances != USHRT_MAX ) + st->script->instances++; + else { + struct npc_data *nd = map->id2nd(oid); + ShowError("over 65k instances of '%s' script are being run\n",nd ? nd->name : "unknown"); + } + + if( !st->script->local.vars ) + st->script->local.vars = i64db_alloc(DB_OPT_RELEASE_DATA); + st->id = script->next_id++; script->active_scripts++; idb_put(script->st_db, st->id, st); - + return st; } /// Frees a script state. /// /// @param st Script state -void script_free_state(struct script_state* st) -{ - if(st->bk_st) {// backup was not restored - ShowDebug("script_free_state: Previous script state lost (rid=%d, oid=%d, state=%d, bk_npcid=%d).\n", st->bk_st->rid, st->bk_st->oid, st->bk_st->state, st->bk_npcid); - } +void script_free_state(struct script_state* st) { + if( idb_exists(script->st_db,st->id) ) { + struct map_session_data *sd = st->rid ? map->id2sd(st->rid) : NULL; + + if(st->bk_st) {// backup was not restored + ShowDebug("script_free_state: Previous script state lost (rid=%d, oid=%d, state=%d, bk_npcid=%d).\n", st->bk_st->rid, st->bk_st->oid, st->bk_st->state, st->bk_npcid); + } + + if(sd && sd->st == st) { //Current script is aborted. + if(sd->state.using_fake_npc){ + clif->clearunit_single(sd->npc_id, CLR_OUTSIGHT, sd->fd); + sd->state.using_fake_npc = 0; + } + sd->st = NULL; + sd->npc_id = 0; + } - if( st->sleep.timer != INVALID_TIMER ) - iTimer->delete_timer(st->sleep.timer, run_script_timer); - script_free_vars(st->stack->var_function); - script->pop_stack(st, 0, st->stack->sp); - aFree(st->stack->stack_data); - ers_free(script->stack_ers, st->stack); - if( st->script && st->script->script_vars && !db_size(st->script->script_vars) ) { - script_free_vars(st->script->script_vars); - st->script->script_vars = NULL; - } - st->stack = NULL; - st->pos = -1; - idb_remove(script->st_db, st->id); - ers_free(script->st_ers, st); - if( --script->active_scripts == 0 ) { - script->next_id = 0; + if( st->sleep.timer != INVALID_TIMER ) + timer->delete(st->sleep.timer, script->run_timer); + if( st->stack ) { + script->free_vars(st->stack->scope.vars); + if( st->stack->scope.arrays ) + st->stack->scope.arrays->destroy(st->stack->scope.arrays,script->array_free_db); + script->pop_stack(st, 0, st->stack->sp); + aFree(st->stack->stack_data); + ers_free(script->stack_ers, st->stack); + st->stack = NULL; + } + if( st->script && st->script->instances != USHRT_MAX && --st->script->instances == 0 ) { + if( st->script->local.vars && !db_size(st->script->local.vars) ) { + script->free_vars(st->script->local.vars); + st->script->local.vars = NULL; + } + if( st->script->local.arrays && !db_size(st->script->local.arrays) ) { + st->script->local.arrays->destroy(st->script->local.arrays,script->array_free_db); + st->script->local.arrays = NULL; + } + } + st->pos = -1; + if (st->pending_ref_count > 0) { + while (st->pending_ref_count > 0) + aFree(st->pending_refs[--st->pending_ref_count]); + aFree(st->pending_refs); + st->pending_refs = NULL; + } + idb_remove(script->st_db, st->id); + ers_free(script->st_ers, st); + if( --script->active_scripts == 0 ) { + script->next_id = 0; + } } } +/** + * Adds a pending reference entry to the current script. + * + * @see struct script_state::pending_refs + * + * @param st[in] Script state. + * @param ref[in] Reference to be added. + */ +void script_add_pending_ref(struct script_state *st, struct reg_db *ref) { + RECREATE(st->pending_refs, struct reg_db*, ++st->pending_ref_count); + st->pending_refs[st->pending_ref_count-1] = ref; +} + // // Main execution unit // /*========================================== * Read command *------------------------------------------*/ -c_op get_com(unsigned char *script,int *pos) +c_op get_com(unsigned char *scriptbuf,int *pos) { int i = 0, j = 0; - if(script[*pos]>=0x80){ + if(scriptbuf[*pos]>=0x80) { return C_INT; } - while(script[*pos]>=0x40){ - i=script[(*pos)++]<<j; + while(scriptbuf[*pos]>=0x40) { + i=scriptbuf[(*pos)++]<<j; j+=6; } - return (c_op)(i+(script[(*pos)++]<<j)); + return (c_op)(i+(scriptbuf[(*pos)++]<<j)); } /*========================================== * Income figures *------------------------------------------*/ -int get_num(unsigned char *script,int *pos) +int get_num(unsigned char *scriptbuf,int *pos) { int i,j; i=0; j=0; - while(script[*pos]>=0xc0){ - i+=(script[(*pos)++]&0x7f)<<j; + while(scriptbuf[*pos]>=0xc0) { + i+=(scriptbuf[(*pos)++]&0x7f)<<j; j+=6; } - return i+((script[(*pos)++]&0x7f)<<j); -} - -/*========================================== - * Remove the value from the stack - *------------------------------------------*/ -int pop_val(struct script_state* st) -{ - if(st->stack->sp<=0) - return 0; - st->stack->sp--; - script->get_val(st,&(st->stack->stack_data[st->stack->sp])); - if(st->stack->stack_data[st->stack->sp].type==C_INT) - return st->stack->stack_data[st->stack->sp].u.num; - return 0; + return i+((scriptbuf[(*pos)++]&0x7f)<<j); } /// Ternary operators @@ -2862,12 +3405,12 @@ void op_3(struct script_state* st, int op) if( data_isstring(data) ) flag = data->u.str[0];// "" -> false else if( data_isint(data) ) - flag = data->u.num;// 0 -> false + flag = data->u.num == 0 ? 0 : 1;// 0 -> false else { ShowError("script:op_3: invalid data for the ternary operator test\n"); - script_reportdata(data); - script_reportsrc(st); + script->reportdata(data); + script->reportsrc(st); script_removetop(st, -3, 0); script_pushnil(st); return; @@ -2886,18 +3429,86 @@ void op_3(struct script_state* st, int op) /// s1 GE s2 -> i /// s1 LT s2 -> i /// s1 LE s2 -> i +/// s1 RE_EQ s2 -> i +/// s1 RE_NE s2 -> i /// s1 ADD s2 -> s void op_2str(struct script_state* st, int op, const char* s1, const char* s2) { int a = 0; - switch(op){ + switch(op) { case C_EQ: a = (strcmp(s1,s2) == 0); break; case C_NE: a = (strcmp(s1,s2) != 0); break; case C_GT: a = (strcmp(s1,s2) > 0); break; case C_GE: a = (strcmp(s1,s2) >= 0); break; case C_LT: a = (strcmp(s1,s2) < 0); break; case C_LE: a = (strcmp(s1,s2) <= 0); break; +#ifdef PCRE_SUPPORT + case C_RE_EQ: + case C_RE_NE: + { + int inputlen = (int)strlen(s1); + pcre *compiled_regex; + pcre_extra *extra_regex; + const char *pcre_error, *pcre_match; + int pcre_erroroffset, offsetcount, i; + int offsets[256*3]; // (max_capturing_groups+1)*3 + + compiled_regex = libpcre->compile(s2, 0, &pcre_error, &pcre_erroroffset, NULL); + + if( compiled_regex == NULL ) { + ShowError("script:op2_str: Invalid regex '%s'.\n", s2); + script->reportsrc(st); + script_pushnil(st); + st->state = END; + return; + } + + extra_regex = libpcre->study(compiled_regex, 0, &pcre_error); + + if( pcre_error != NULL ) { + libpcre->free(compiled_regex); + ShowError("script:op2_str: Unable to optimize the regex '%s': %s\n", s2, pcre_error); + script->reportsrc(st); + script_pushnil(st); + st->state = END; + return; + } + + offsetcount = libpcre->exec(compiled_regex, extra_regex, s1, inputlen, 0, 0, offsets, 256*3); + + if( offsetcount == 0 ) { + offsetcount = 256; + } else if( offsetcount == PCRE_ERROR_NOMATCH ) { + offsetcount = 0; + } else if( offsetcount < 0 ) { + libpcre->free(compiled_regex); + if( extra_regex != NULL ) + libpcre->free(extra_regex); + ShowWarning("script:op2_str: Unable to process the regex '%s'.\n", s2); + script->reportsrc(st); + script_pushnil(st); + st->state = END; + return; + } + + if( op == C_RE_EQ ) { + 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); + } + mapreg->setreg(script->add_str("$@regexmatchcount"), i); + a = offsetcount; + } else { // C_RE_NE + a = (offsetcount == 0); + } + libpcre->free(compiled_regex); + if( extra_regex != NULL ) + libpcre->free(extra_regex); + } + break; +#endif // PCRE_SUPPORT case C_ADD: { char* buf = (char *)aMalloc((strlen(s1)+strlen(s2)+1)*sizeof(char)); @@ -2907,8 +3518,8 @@ void op_2str(struct script_state* st, int op, const char* s1, const char* s2) return; } default: - ShowError("script:op2_str: unexpected string operator %s\n", script_op2name(op)); - script_reportsrc(st); + ShowError("script:op2_str: unexpected string operator %s\n", script->op2name(op)); + script->reportsrc(st); script_pushnil(st); st->state = END; return; @@ -2924,27 +3535,26 @@ void op_2num(struct script_state* st, int op, int i1, int i2) int ret; double ret_double; - switch( op ) - { - case C_AND: ret = i1 & i2; break; - case C_OR: ret = i1 | i2; break; - case C_XOR: ret = i1 ^ i2; break; - case C_LAND: ret = (i1 && i2); break; - case C_LOR: ret = (i1 || i2); break; - case C_EQ: ret = (i1 == i2); break; - case C_NE: ret = (i1 != i2); break; - case C_GT: ret = (i1 > i2); break; - case C_GE: ret = (i1 >= i2); break; - case C_LT: ret = (i1 < i2); break; - case C_LE: ret = (i1 <= i2); break; - case C_R_SHIFT: ret = i1>>i2; break; - case C_L_SHIFT: ret = i1<<i2; break; + switch( op ) { + case C_AND: ret = i1 & i2; break; + case C_OR: ret = i1 | i2; break; + case C_XOR: ret = i1 ^ i2; break; + case C_LAND: ret = (i1 && i2); break; + case C_LOR: ret = (i1 || i2); break; + case C_EQ: ret = (i1 == i2); break; + case C_NE: ret = (i1 != i2); break; + case C_GT: ret = (i1 > i2); break; + case C_GE: ret = (i1 >= i2); break; + case C_LT: ret = (i1 < i2); break; + case C_LE: ret = (i1 <= i2); break; + case C_R_SHIFT: ret = i1>>i2; break; + case C_L_SHIFT: ret = i1<<i2; break; case C_DIV: case C_MOD: if( i2 == 0 ) { - ShowError("script:op_2num: division by zero detected op=%s i1=%d i2=%d\n", script_op2name(op), i1, i2); - script_reportsrc(st); + ShowError("script:op_2num: division by zero detected op=%s i1=%d i2=%d\n", script->op2name(op), i1, i2); + script->reportsrc(st); script_pushnil(st); st->state = END; return; @@ -2961,21 +3571,21 @@ void op_2num(struct script_state* st, int op, int i1, int i2) case C_SUB: ret = i1 - i2; ret_double = (double)i1 - (double)i2; break; case C_MUL: ret = i1 * i2; ret_double = (double)i1 * (double)i2; break; default: - ShowError("script:op_2num: unexpected number operator %s i1=%d i2=%d\n", script_op2name(op), i1, i2); - script_reportsrc(st); + ShowError("script:op_2num: unexpected number operator %s i1=%d i2=%d\n", script->op2name(op), i1, i2); + script->reportsrc(st); script_pushnil(st); return; } if( ret_double < (double)INT_MIN ) { - ShowWarning("script:op_2num: underflow detected op=%s i1=%d i2=%d\n", script_op2name(op), i1, i2); - script_reportsrc(st); + ShowWarning("script:op_2num: underflow detected op=%s i1=%d i2=%d\n", script->op2name(op), i1, i2); + script->reportsrc(st); ret = INT_MIN; } else if( ret_double > (double)INT_MAX ) { - ShowWarning("script:op_2num: overflow detected op=%s i1=%d i2=%d\n", script_op2name(op), i1, i2); - script_reportsrc(st); + ShowWarning("script:op_2num: overflow detected op=%s i1=%d i2=%d\n", script->op2name(op), i1, i2); + script->reportsrc(st); ret = INT_MAX; } } @@ -3021,32 +3631,33 @@ void op_2(struct script_state *st, int op) if( data_isstring(left) && data_isstring(right) ) {// ss => op_2str - op_2str(st, op, left->u.str, right->u.str); + script->op_2str(st, op, left->u.str, right->u.str); script_removetop(st, leftref.type == C_NOP ? -3 : -2, -1);// pop the two values before the top one if (leftref.type != C_NOP) { - aFree(left->u.str); + if (left->type == C_STR) // don't free C_CONSTSTR + aFree(left->u.str); *left = leftref; } } else if( data_isint(left) && data_isint(right) ) {// ii => op_2num - int i1 = left->u.num; - int i2 = right->u.num; + int i1 = (int)left->u.num; + int i2 = (int)right->u.num; script_removetop(st, leftref.type == C_NOP ? -2 : -1, 0); - op_2num(st, op, i1, i2); + script->op_2num(st, op, i1, i2); if (leftref.type != C_NOP) *left = leftref; } else {// invalid argument - ShowError("script:op_2: invalid data for operator %s\n", script_op2name(op)); - script_reportdata(left); - script_reportdata(right); - script_reportsrc(st); + ShowError("script:op_2: invalid data for operator %s\n", script->op2name(op)); + script->reportdata(left); + script->reportdata(right); + script->reportsrc(st); script_removetop(st, -2, 0); script_pushnil(st); st->state = END; @@ -3067,27 +3678,26 @@ void op_1(struct script_state* st, int op) if( !data_isint(data) ) {// not a number - ShowError("script:op_1: argument is not a number (op=%s)\n", script_op2name(op)); - script_reportdata(data); - script_reportsrc(st); + ShowError("script:op_1: argument is not a number (op=%s)\n", script->op2name(op)); + script->reportdata(data); + script->reportsrc(st); script_pushnil(st); st->state = END; return; } - i1 = data->u.num; + i1 = (int)data->u.num; script_removetop(st, -1, 0); - switch( op ) - { - case C_NEG: i1 = -i1; break; - case C_NOT: i1 = ~i1; break; - case C_LNOT: i1 = !i1; break; - default: - ShowError("script:op_1: unexpected operator %s i1=%d\n", script_op2name(op), i1); - script_reportsrc(st); - script_pushnil(st); - st->state = END; - return; + switch( op ) { + case C_NEG: i1 = -i1; break; + case C_NOT: i1 = ~i1; break; + case C_LNOT: i1 = !i1; break; + default: + ShowError("script:op_1: unexpected operator %s i1=%d\n", script->op2name(op), i1); + script->reportsrc(st); + script_pushnil(st); + st->state = END; + return; } script_pushint(st, i1); } @@ -3097,7 +3707,7 @@ 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. -static void script_check_buildin_argtype(struct script_state* st, int func) +void script_check_buildin_argtype(struct script_state* st, int func) { char type; int idx, invalid = 0; @@ -3107,11 +3717,11 @@ static void script_check_buildin_argtype(struct script_state* st, int func) struct script_data* data = script_getdata(st, idx); type = sf[idx-2]; - + if( type == '?' || type == '*' ) {// optional argument or unknown number of optional parameters ( no types are after this ) break; } else if( type == 0 ) {// more arguments than necessary ( should not happen, as it is checked before ) - ShowWarning("Found more arguments than necessary. unexpected arg type %s\n",script_op2name(data->type)); + ShowWarning("Found more arguments than necessary. unexpected arg type %s\n",script->op2name(data->type)); invalid++; break; } else { @@ -3127,7 +3737,7 @@ static void script_check_buildin_argtype(struct script_state* st, int func) if( !data_isstring(data) && !data_isint(data) && !data_isreference(data) ) {// variant ShowWarning("Unexpected type for argument %d. Expected string, number or variable.\n", idx-1); - script_reportdata(data); + script->reportdata(data); invalid++; } break; @@ -3135,7 +3745,7 @@ static void script_check_buildin_argtype(struct script_state* st, int func) if( !data_isstring(data) && !( data_isreference(data) && is_string_variable(name) ) ) {// string ShowWarning("Unexpected type for argument %d. Expected string.\n", idx-1); - script_reportdata(data); + script->reportdata(data); invalid++; } break; @@ -3143,23 +3753,23 @@ static void script_check_buildin_argtype(struct script_state* st, int func) if( !data_isint(data) && !( data_isreference(data) && ( reference_toparam(data) || reference_toconstant(data) || !is_string_variable(name) ) ) ) {// int ( params and constants are always int ) ShowWarning("Unexpected type for argument %d. Expected number.\n", idx-1); - script_reportdata(data); + script->reportdata(data); invalid++; } break; case 'r': - if( !data_isreference(data) ) + if( !data_isreference(data) || reference_toconstant(data) ) {// variables - ShowWarning("Unexpected type for argument %d. Expected variable, got %s.\n", idx-1,script_op2name(data->type)); - script_reportdata(data); + ShowWarning("Unexpected type for argument %d. Expected variable, got %s.\n", idx-1,script->op2name(data->type)); + script->reportdata(data); invalid++; } break; case 'l': if( !data_islabel(data) && !data_isfunclabel(data) ) {// label - ShowWarning("Unexpected type for argument %d. Expected label, got %s\n", idx-1,script_op2name(data->type)); - script_reportdata(data); + ShowWarning("Unexpected type for argument %d. Expected label, got %s\n", idx-1,script->op2name(data->type)); + script->reportdata(data); invalid++; } break; @@ -3168,8 +3778,8 @@ static void script_check_buildin_argtype(struct script_state* st, int func) } if(invalid) { - ShowDebug("Function: %s\n", get_str(func)); - script_reportsrc(st); + ShowDebug("Function: %s\n", script->get_str(func)); + script->reportsrc(st); } } @@ -3189,7 +3799,7 @@ int run_func(struct script_state *st) { ShowError("script:run_func: C_ARG not found. please report this!!!\n"); st->state = END; - script_reportsrc(st); + script->reportsrc(st); return 1; } start_sp = i-1;// C_NAME of the command @@ -3198,27 +3808,27 @@ int run_func(struct script_state *st) data = &st->stack->stack_data[st->start]; if( data->type == C_NAME && script->str_data[data->u.num].type == C_FUNC ) - func = data->u.num; + func = (int)data->u.num; else { ShowError("script:run_func: not a buildin command.\n"); - script_reportdata(data); - script_reportsrc(st); + script->reportdata(data); + script->reportsrc(st); st->state = END; return 1; } - if( script_config.warn_func_mismatch_argtypes ) - { - script_check_buildin_argtype(st, func); + if( script->config.warn_func_mismatch_argtypes ) { + script->check_buildin_argtype(st, func); } - if(script->str_data[func].func){ + if(script->str_data[func].func) { if (!(script->str_data[func].func(st))) //Report error - script_reportsrc(st); + script->reportsrc(st); } else { - ShowError("script:run_func: '%s' (id=%d type=%s) has no C function. please report this!!!\n", get_str(func), func, script_op2name(script->str_data[func].type)); - script_reportsrc(st); + ShowError("script:run_func: '%s' (id=%d type=%s) has no C function. please report this!!!\n", + script->get_str(func), func, script->op2name(script->str_data[func].type)); + script->reportsrc(st); st->state = END; } @@ -3237,17 +3847,19 @@ int run_func(struct script_state *st) if( st->stack->defsp < 1 || st->stack->stack_data[st->stack->defsp-1].type != C_RETINFO ) { ShowWarning("script:run_func: return without callfunc or callsub!\n"); - script_reportsrc(st); + script->reportsrc(st); st->state = END; return 1; } - script_free_vars( st->stack->var_function ); + script->free_vars(st->stack->scope.vars); + st->stack->scope.arrays->destroy(st->stack->scope.arrays,script->array_free_db); ri = st->stack->stack_data[st->stack->defsp-1].u.ri; nargs = ri->nargs; st->pos = ri->pos; st->script = ri->script; - st->stack->var_function = ri->var_function; + st->stack->scope.vars = ri->scope.vars; + st->stack->scope.arrays = ri->scope.arrays; st->stack->defsp = ri->defsp; memset(ri, 0, sizeof(struct script_retinfo)); @@ -3267,48 +3879,50 @@ void run_script(struct script_code *rootscript,int pos,int rid,int oid) { if( rootscript == NULL || pos < 0 ) return; - + // TODO In jAthena, this function can take over the pending script in the player. [FlavioJS] // It is unclear how that can be triggered, so it needs the be traced/checked in more detail. // NOTE At the time of this change, this function wasn't capable of taking over the script state because st->scriptroot was never set. - st = script_alloc_state(rootscript, pos, rid, oid); - - run_script_main(st); + st = script->alloc_state(rootscript, pos, rid, oid); + + script->run_main(st); } -void script_stop_instances(int id) { +void script_stop_instances(struct script_code *code) { DBIterator *iter; struct script_state* st; - + if( !script->active_scripts ) return;//dont even bother. - + iter = db_iterator(script->st_db); - + for( st = dbi_first(iter); dbi_exists(iter); st = dbi_next(iter) ) { - if( st->oid == id ) { - script_free_state(st); + if( st->script == code ) { + script->free_state(st); } } - + dbi_destroy(iter); } /*========================================== * Timer function for sleep *------------------------------------------*/ -int run_script_timer(int tid, unsigned int tick, int id, intptr_t data) { - struct script_state *st = (struct script_state *)data; - TBL_PC *sd = iMap->id2sd(st->rid); +int run_script_timer(int tid, int64 tick, int id, intptr_t data) { + struct script_state *st = idb_get(script->st_db,(int)data); + if( st ) { + TBL_PC *sd = map->id2sd(st->rid); - if((sd && sd->status.char_id != id) || (st->rid && !sd)) { //Character mismatch. Cancel execution. - st->rid = 0; - st->state = END; + if((sd && sd->status.char_id != id) || (st->rid && !sd)) { //Character mismatch. Cancel execution. + st->rid = 0; + st->state = END; + } + st->sleep.timer = INVALID_TIMER; + if(st->state != RERUNLINE) + st->sleep.tick = 0; + script->run_main(st); } - st->sleep.timer = INVALID_TIMER; - if(st->state != RERUNLINE) - st->sleep.tick = 0; - run_script_main(st); return 0; } @@ -3316,11 +3930,10 @@ int run_script_timer(int tid, unsigned int tick, int id, intptr_t data) { /// /// @param st Script state to detach. /// @param dequeue_event Whether to schedule any queued events, when there was no previous script. -static void script_detach_state(struct script_state* st, bool dequeue_event) -{ +void script_detach_state(struct script_state* st, bool dequeue_event) { struct map_session_data* sd; - if(st->rid && (sd = iMap->id2sd(st->rid))!=NULL) { + if(st->rid && (sd = map->id2sd(st->rid))!=NULL) { sd->st = st->bk_st; sd->npc_id = st->bk_npcid; sd->state.dialog = 0; @@ -3329,25 +3942,21 @@ static void script_detach_state(struct script_state* st, bool dequeue_event) st->bk_st = NULL; st->bk_npcid = 0; } else if(dequeue_event) { - /** - * For the Secure NPC Timeout option (check config/Secure.h) [RR] - **/ + // For the Secure NPC Timeout option (check config/Secure.h) [RR] #ifdef SECURE_NPCTIMEOUT - /** - * We're done with this NPC session, so we cancel the timer (if existent) and move on - **/ + // We're done with this NPC session, so we cancel the timer (if existent) and move on if( sd->npc_idle_timer != INVALID_TIMER ) { - iTimer->delete_timer(sd->npc_idle_timer,npc_rr_secure_timeout_timer); + timer->delete(sd->npc_idle_timer,npc->secure_timeout_timer); sd->npc_idle_timer = INVALID_TIMER; } #endif - npc_event_dequeue(sd); + npc->event_dequeue(sd); } } else if(st->bk_st) { // rid was set to 0, before detaching the script state ShowError("script_detach_state: Found previous script state without attached player (rid=%d, oid=%d, state=%d, bk_npcid=%d)\n", st->bk_st->rid, st->bk_st->oid, st->bk_st->state, st->bk_npcid); - script_reportsrc(st->bk_st); + script->reportsrc(st->bk_st); - script_free_state(st->bk_st); + script->free_state(st->bk_st); st->bk_st = NULL; } } @@ -3355,11 +3964,10 @@ static void script_detach_state(struct script_state* st, bool dequeue_event) /// Attaches script state to possibly attached character and backups it's previous script, if any. /// /// @param st Script state to attach. -static void script_attach_state(struct script_state* st) -{ +void script_attach_state(struct script_state* st) { struct map_session_data* sd; - if(st->rid && (sd = iMap->id2sd(st->rid))!=NULL) + if(st->rid && (sd = map->id2sd(st->rid))!=NULL) { if(st!=sd->st) { @@ -3378,8 +3986,8 @@ static void script_attach_state(struct script_state* st) **/ #ifdef SECURE_NPCTIMEOUT if( sd->npc_idle_timer == INVALID_TIMER ) - sd->npc_idle_timer = iTimer->add_timer(iTimer->gettick() + (SECURE_NPCTIMEOUT_INTERVAL*1000),npc_rr_secure_timeout_timer,sd->bl.id,0); - sd->npc_idle_tick = iTimer->gettick(); + sd->npc_idle_timer = timer->add(timer->gettick() + (SECURE_NPCTIMEOUT_INTERVAL*1000),npc->secure_timeout_timer,sd->bl.id,0); + sd->npc_idle_tick = timer->gettick(); #endif } } @@ -3387,32 +3995,31 @@ static void script_attach_state(struct script_state* st) /*========================================== * The main part of the script execution *------------------------------------------*/ -void run_script_main(struct script_state *st) -{ - int cmdcount = script_config.check_cmdcount; - int gotocount = script_config.check_gotocount; +void run_script_main(struct script_state *st) { + int cmdcount = script->config.check_cmdcount; + int gotocount = script->config.check_gotocount; TBL_PC *sd; struct script_stack *stack = st->stack; struct npc_data *nd; - script_attach_state(st); + script->attach_state(st); - nd = iMap->id2nd(st->oid); + nd = map->id2nd(st->oid); if( nd && nd->bl.m >= 0 ) - st->instance_id = map[nd->bl.m].instance_id; + st->instance_id = map->list[nd->bl.m].instance_id; else st->instance_id = -1; if(st->state == RERUNLINE) { - run_func(st); + script->run_func(st); if(st->state == GOTO) st->state = RUN; } else if(st->state != END) st->state = RUN; - while( st->state == RUN ){ - enum c_op c = get_com(st->script->script_buf,&st->pos); - switch(c){ + while( st->state == RUN ) { + enum c_op c = script->get_com(st->script->script_buf,&st->pos); + switch(c) { case C_EOL: if( stack->defsp > stack->sp ) ShowError("script:run_script_main: unexpected stack position (defsp=%d sp=%d). please report this!!!\n", stack->defsp, stack->sp); @@ -3420,7 +4027,7 @@ 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,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: @@ -3435,12 +4042,12 @@ void run_script_main(struct script_state *st) while(st->script->script_buf[st->pos++]); break; case C_FUNC: - run_func(st); - if(st->state==GOTO){ + script->run_func(st); + if(st->state==GOTO) { st->state = RUN; - if( !st->freeloop && gotocount>0 && (--gotocount)<=0 ){ + if( !st->freeloop && gotocount>0 && (--gotocount)<=0 ) { ShowError("run_script: infinity loop !\n"); - script_reportsrc(st); + script->reportsrc(st); st->state=END; } } @@ -3453,7 +4060,7 @@ void run_script_main(struct script_state *st) case C_NEG: case C_NOT: case C_LNOT: - op_1(st ,c); + script->op_1(st ,c); break; case C_ADD: @@ -3474,11 +4081,15 @@ void run_script_main(struct script_state *st) case C_LOR: case C_R_SHIFT: case C_L_SHIFT: - op_2(st, c); +#ifdef PCRE_SUPPORT + case C_RE_EQ: + case C_RE_NE: +#endif // PCRE_SUPPORT + script->op_2(st, c); break; case C_OP3: - op_3(st, c); + script->op_3(st, c); break; case C_NOP: @@ -3490,93 +4101,88 @@ void run_script_main(struct script_state *st) st->state=END; break; } - if( !st->freeloop && cmdcount>0 && (--cmdcount)<=0 ){ - ShowError("run_script: infinity loop !\n"); - script_reportsrc(st); + if( !st->freeloop && cmdcount>0 && (--cmdcount)<=0 ) { + ShowError("run_script: too many opeartions being processed non-stop !\n"); + script->reportsrc(st); st->state=END; } } if(st->sleep.tick > 0) { //Restore previous script - script_detach_state(st, false); + script->detach_state(st, false); //Delay execution - sd = iMap->id2sd(st->rid); // Get sd since script might have attached someone while running. [Inkfish] + sd = map->id2sd(st->rid); // Get sd since script might have attached someone while running. [Inkfish] st->sleep.charid = sd?sd->status.char_id:0; - st->sleep.timer = iTimer->add_timer(iTimer->gettick()+st->sleep.tick, - run_script_timer, st->sleep.charid, (intptr_t)st); - } else if(st->state != END && st->rid){ + st->sleep.timer = timer->add(timer->gettick()+st->sleep.tick, + script->run_timer, st->sleep.charid, (intptr_t)st->id); + } else if(st->state != END && st->rid) { //Resume later (st is already attached to player). if(st->bk_st) { ShowWarning("Unable to restore stack! Double continuation!\n"); //Report BOTH scripts to see if that can help somehow. ShowDebug("Previous script (lost):\n"); - script_reportsrc(st->bk_st); + script->reportsrc(st->bk_st); ShowDebug("Current script:\n"); - script_reportsrc(st); + script->reportsrc(st); - script_free_state(st->bk_st); + script->free_state(st->bk_st); st->bk_st = NULL; } } else { //Dispose of script. - if ((sd = iMap->id2sd(st->rid))!=NULL) { //Restore previous stack and save char. - if(sd->state.using_fake_npc){ + if ((sd = map->id2sd(st->rid))!=NULL) { //Restore previous stack and save char. + if(sd->state.using_fake_npc) { clif->clearunit_single(sd->npc_id, CLR_OUTSIGHT, sd->fd); sd->state.using_fake_npc = 0; } //Restore previous script if any. - script_detach_state(st, true); - if (sd->state.reg_dirty&2) - intif_saveregistry(sd,2); - if (sd->state.reg_dirty&1) - intif_saveregistry(sd,1); + script->detach_state(st, true); + if (sd->vars_dirty) + intif->saveregistry(sd); } - script_free_state(st); + script->free_state(st); st = NULL; } } -int script_config_read(char *cfgName) -{ +int script_config_read(char *cfgName) { int i; char line[1024],w1[1024],w2[1024]; FILE *fp; - fp=fopen(cfgName,"r"); - if(fp==NULL){ + if( !( fp = fopen(cfgName,"r") ) ) { ShowError("File not found: %s\n", cfgName); return 1; } - while(fgets(line, sizeof(line), fp)) - { - if(line[0] == '/' && line[1] == '/') + while (fgets(line, sizeof(line), fp)) { + if (line[0] == '/' && line[1] == '/') continue; - i=sscanf(line,"%[^:]: %[^\r\n]",w1,w2); + i = sscanf(line,"%1023[^:]: %1023[^\r\n]", w1, w2); if(i!=2) continue; if(strcmpi(w1,"warn_func_mismatch_paramnum")==0) { - script_config.warn_func_mismatch_paramnum = config_switch(w2); + script->config.warn_func_mismatch_paramnum = config_switch(w2); } else if(strcmpi(w1,"check_cmdcount")==0) { - script_config.check_cmdcount = config_switch(w2); + script->config.check_cmdcount = config_switch(w2); } else if(strcmpi(w1,"check_gotocount")==0) { - script_config.check_gotocount = config_switch(w2); + script->config.check_gotocount = config_switch(w2); } else if(strcmpi(w1,"input_min_value")==0) { - script_config.input_min_value = config_switch(w2); + script->config.input_min_value = config_switch(w2); } else if(strcmpi(w1,"input_max_value")==0) { - script_config.input_max_value = config_switch(w2); + script->config.input_max_value = config_switch(w2); } else if(strcmpi(w1,"warn_func_mismatch_argtypes")==0) { - script_config.warn_func_mismatch_argtypes = config_switch(w2); + script->config.warn_func_mismatch_argtypes = config_switch(w2); } - else if(strcmpi(w1,"import")==0){ - script_config_read(w2); + else if(strcmpi(w1,"import")==0) { + script->config_read(w2); } else { ShowWarning("Unknown setting '%s' in file %s\n", w1, cfgName); @@ -3590,102 +4196,132 @@ int script_config_read(char *cfgName) /** * @see DBApply */ -static int db_script_free_code_sub(DBKey key, DBData *data, va_list ap) +int db_script_free_code_sub(DBKey key, DBData *data, va_list ap) { struct script_code *code = DB->data2ptr(data); if (code) - script_free_code(code); + script->free_code(code); return 0; } void script_run_autobonus(const char *autobonus, int id, int pos) { - struct script_code *script = (struct script_code *)strdb_get(autobonus_db, autobonus); + struct script_code *scriptroot = (struct script_code *)strdb_get(script->autobonus_db, autobonus); - if( script ) - { - current_equip_item_index = pos; - run_script(script,0,id,0); + if( scriptroot ) { + status->current_equip_item_index = pos; + script->run(scriptroot,0,id,0); } } void script_add_autobonus(const char *autobonus) { - if( strdb_get(autobonus_db, autobonus) == NULL ) - { - struct script_code *script = parse_script(autobonus, "autobonus", 0, 0); + if( strdb_get(script->autobonus_db, autobonus) == NULL ) { + struct script_code *scriptroot = script->parse(autobonus, "autobonus", 0, 0, NULL); - if( script ) - strdb_put(autobonus_db, autobonus, script); + if( scriptroot ) + strdb_put(script->autobonus_db, autobonus, scriptroot); } } /// resets a temporary character array variable to given value -void script_cleararray_pc(struct map_session_data* sd, const char* varname, void* value) -{ +void script_cleararray_pc(struct map_session_data* sd, const char* varname, void* value) { + struct script_array *sa = NULL; + struct reg_db *src = NULL; + unsigned int i, *list = NULL, size = 0; int key; - uint8 idx; - if( not_array_variable(varname[0]) || !not_server_variable(varname[0]) ) - { - ShowError("script_cleararray_pc: Variable '%s' has invalid scope (char_id=%d).\n", varname, sd->status.char_id); + key = script->add_str(varname); + + if( !(src = script->array_src(NULL,sd,varname,NULL) ) ) return; - } - - key = add_str(varname); - - if( is_string_variable(varname) ) - { - for( idx = 0; idx < SCRIPT_MAX_ARRAYSIZE; idx++ ) - { - pc->setregstr(sd, reference_uid(key, idx), (const char*)value); - } - } - else - { - for( idx = 0; idx < SCRIPT_MAX_ARRAYSIZE; idx++ ) - { - pc->setreg(sd, reference_uid(key, idx), (int)__64BPTRSIZE(value)); - } + + if( value ) + script->array_ensure_zero(NULL,sd,reference_uid(key,0),NULL); + + if( !(sa = idb_get(src->arrays, key)) ) /* non-existent array, nothing to empty */ + return; + + size = sa->size; + list = script->array_cpy_list(sa); + + for(i = 0; i < size; i++) { + script->set_reg(NULL,sd,reference_uid(key, list[i]),varname,value,NULL); } } /// sets a temporary character array variable element idx to given value /// @param refcache Pointer to an int variable, which keeps a copy of the reference to varname and must be initialized to 0. Can be NULL if only one element is set. -void script_setarray_pc(struct map_session_data* sd, const char* varname, uint8 idx, void* value, int* refcache) -{ +void script_setarray_pc(struct map_session_data* sd, const char* varname, uint32 idx, void* value, int* refcache) { int key; - - if( not_array_variable(varname[0]) || !not_server_variable(varname[0]) ) - { - ShowError("script_setarray_pc: Variable '%s' has invalid scope (char_id=%d).\n", varname, sd->status.char_id); - return; - } - - if( idx >= SCRIPT_MAX_ARRAYSIZE ) - { - ShowError("script_setarray_pc: Variable '%s' has invalid index '%d' (char_id=%d).\n", varname, (int)idx, sd->status.char_id); + + if( idx >= SCRIPT_MAX_ARRAYSIZE ) { + ShowError("script_setarray_pc: Variable '%s' has invalid index '%u' (char_id=%d).\n", varname, idx, sd->status.char_id); return; } - key = ( refcache && refcache[0] ) ? refcache[0] : add_str(varname); - - if( is_string_variable(varname) ) - { - pc->setregstr(sd, reference_uid(key, idx), (const char*)value); + key = ( refcache && refcache[0] ) ? refcache[0] : script->add_str(varname); + + script->set_reg(NULL,sd,reference_uid(key, idx),varname,value,NULL); + + if( refcache ) + {// save to avoid repeated script->add_str calls + refcache[0] = key; } - else - { - pc->setreg(sd, reference_uid(key, idx), (int)__64BPTRSIZE(value)); +} +/** + * Clears persistent variables from memory + **/ +int script_reg_destroy(DBKey key, DBData *data, va_list ap) { + struct script_reg_state *src; + + if( data->type != DB_DATA_PTR )/* got no need for those! */ + return 0; + + src = DB->data2ptr(data); + + if( src->type ) { + struct script_reg_str *p = (struct script_reg_str *)src; + + if( p->value ) + aFree(p->value); + + ers_free(pc->str_reg_ers,p); + } else { + ers_free(pc->num_reg_ers,(struct script_reg_num*)src); } + + return 0; +} +/** + * Clears a single persistent variable + **/ +void script_reg_destroy_single(struct map_session_data *sd, int64 reg, struct script_reg_state *data) { + i64db_remove(sd->regs.vars, reg); - if( refcache ) - {// save to avoid repeated add_str calls - refcache[0] = key; + if( data->type ) { + struct script_reg_str *p = (struct script_reg_str*)data; + + if( p->value ) + aFree(p->value); + + ers_free(pc->str_reg_ers,p); + } else { + ers_free(pc->num_reg_ers,(struct script_reg_num*)data); } } +unsigned int *script_array_cpy_list(struct script_array *sa) { + if( sa->size > script->generic_ui_array_size ) + script->generic_ui_array_expand(sa->size); + memcpy(script->generic_ui_array, sa->members, sizeof(unsigned int)*sa->size); + return script->generic_ui_array; +} +void script_generic_ui_array_expand (unsigned int plus) { + script->generic_ui_array_size += plus + 100; + RECREATE(script->generic_ui_array, unsigned int, script->generic_ui_array_size); +} /*========================================== * Destructor *------------------------------------------*/ @@ -3693,8 +4329,8 @@ void do_final_script(void) { int i; DBIterator *iter; struct script_state *st; - -#ifdef DEBUG_HASH + +#ifdef SCRIPT_DEBUG_HASH if (battle_config.etc_log) { FILE *fp = fopen("hash_dump.txt","wt"); @@ -3711,8 +4347,8 @@ void do_final_script(void) { fprintf(fp,"num : hash : data_name\n"); fprintf(fp,"---------------------------------------------------------------\n"); for(i=LABEL_START; i<script->str_num; i++) { - unsigned int h = calc_hash(get_str(i)); - fprintf(fp,"%04d : %4u : %s\n",i,h, get_str(i)); + unsigned int h = script->calc_hash(script->get_str(i)); + fprintf(fp,"%04d : %4u : %s\n",i,h, script->get_str(i)); ++count[h]; } fprintf(fp,"--------------------\n\n"); @@ -3720,19 +4356,19 @@ void do_final_script(void) { for(i=0; i<SCRIPT_HASH_SIZE; i++) { fprintf(fp," hash %3d = %d\n",i,count[i]); if(min > count[i]) - min = count[i]; // minimun count of collision + min = count[i]; // minimun count of collision if(max < count[i]) - max = count[i]; // maximun count of collision + max = count[i]; // maximun count of collision if(count[i] == 0) zero++; ++count2[count[i]]; } fprintf(fp,"\n--------------------\n items : buckets\n--------------------\n"); - for( i=min; i <= max; ++i ){ + for( i=min; i <= max; ++i ) { fprintf(fp," %5d : %7d\n",i,count2[i]); mean += 1.0f*i*count2[i]/SCRIPT_HASH_SIZE; // Note: this will always result in <nr labels>/<nr buckets> } - for( i=min; i <= max; ++i ){ + for( i=min; i <= max; ++i ) { n += count2[i]; if( n*2 >= SCRIPT_HASH_SIZE ) { @@ -3749,20 +4385,19 @@ void do_final_script(void) { } #endif - mapreg_final(); - - db_destroy(scriptlabel_db); - userfunc_db->destroy(userfunc_db, db_script_free_code_sub); - autobonus_db->destroy(autobonus_db, db_script_free_code_sub); - iter = db_iterator(script->st_db); - + for( st = dbi_first(iter); dbi_exists(iter); st = dbi_next(iter) ) { - script_free_state(st); + script->free_state(st); } - + dbi_destroy(iter); - + + mapreg->final(); + + script->userfunc_db->destroy(script->userfunc_db, script->db_free_code_sub); + script->autobonus_db->destroy(script->autobonus_db, script->db_free_code_sub); + if (script->str_data) aFree(script->str_data); if (script->str_buf) @@ -3774,7 +4409,7 @@ void do_final_script(void) { if( atcommand->binding_count != 0 ) aFree(atcommand->binding); - + for( i = 0; i < script->buildin_count; i++) { if( script->buildin[i] ) { aFree(script->buildin[i]); @@ -3783,7 +4418,7 @@ void do_final_script(void) { } aFree(script->buildin); - + if( script->hqs ) { for( i = 0; i < script->hqs; i++ ) { if( script->hq[i].item != NULL ) @@ -3802,39 +4437,69 @@ void do_final_script(void) { aFree(script->hqi); if( script->word_buf != NULL ) aFree(script->word_buf); - + +#ifdef ENABLE_CASE_CHECK + script->global_casecheck.clear(); + script->local_casecheck.clear(); +#endif // ENABLE_CASE_CHECK + ers_destroy(script->st_ers); ers_destroy(script->stack_ers); - + db_destroy(script->st_db); + + if( script->labels != NULL ) + aFree(script->labels); + + ers_destroy(script->array_ers); + + if( script->generic_ui_array ) + aFree(script->generic_ui_array); } /*========================================== * Initialization *------------------------------------------*/ -void do_init_script(void) { +void do_init_script(bool minimal) { script->st_db = idb_alloc(DB_OPT_BASE); - userfunc_db = strdb_alloc(DB_OPT_DUP_KEY,0); - scriptlabel_db = strdb_alloc(DB_OPT_DUP_KEY,50); - autobonus_db = strdb_alloc(DB_OPT_DUP_KEY,0); + script->userfunc_db = strdb_alloc(DB_OPT_DUP_KEY,0); + script->autobonus_db = strdb_alloc(DB_OPT_DUP_KEY,0); - script->st_ers = ers_new(sizeof(struct script_state), "script.c::st_ers", ERS_OPT_NONE); - script->stack_ers = ers_new(sizeof(struct script_stack), "script.c::script_stack", ERS_OPT_NONE); + script->st_ers = ers_new(sizeof(struct script_state), "script.c::st_ers", ERS_OPT_CLEAN|ERS_OPT_FLEX_CHUNK); + script->stack_ers = ers_new(sizeof(struct script_stack), "script.c::script_stack", ERS_OPT_NONE|ERS_OPT_FLEX_CHUNK); + script->array_ers = ers_new(sizeof(struct script_array), "script.c::array_ers", ERS_OPT_CLEAN|ERS_OPT_CLEAR); ers_chunk_size(script->st_ers, 10); ers_chunk_size(script->stack_ers, 10); - + script->parse_builtin(); - read_constdb(); - mapreg_init(); + script->read_constdb(); + script->hardcoded_constants(); + + if (minimal) + return; + + mapreg->init(); } -int script_reload() { +int script_reload(void) { int i; DBIterator *iter; struct script_state *st; - userfunc_db->clear(userfunc_db, db_script_free_code_sub); - db_clear(scriptlabel_db); +#ifdef ENABLE_CASE_CHECK + script->global_casecheck.clear(); +#endif // ENABLE_CASE_CHECK + + iter = db_iterator(script->st_db); + + for( st = dbi_first(iter); dbi_exists(iter); st = dbi_next(iter) ) { + script->free_state(st); + } + + dbi_destroy(iter); + + script->userfunc_db->clear(script->userfunc_db, script->db_free_code_sub); + script->label_count = 0; for( i = 0; i < atcommand->binding_count; i++ ) { aFree(atcommand->binding[i]); @@ -3845,27 +4510,32 @@ int script_reload() { atcommand->binding_count = 0; - iter = db_iterator(script->st_db); - - for( st = dbi_first(iter); dbi_exists(iter); st = dbi_next(iter) ) { - script_free_state(st); - } - - dbi_destroy(iter); - db_clear(script->st_db); - - mapreg_reload(); + + mapreg->reload(); + + itemdb->name_constants(); + + sysinfo->vcsrevision_reload(); + return 0; } +/* returns name of current function being run, from within the stack [Ind/Hercules] */ +const char *script_getfuncname(struct script_state *st) { + struct script_data *data; + + data = &st->stack->stack_data[st->start]; + + if( data->type == C_NAME && script->str_data[data->u.num].type == C_FUNC ) + return script->get_str(script_getvarid(data->u.num)); + + return NULL; +} //----------------------------------------------------------------------------- // buildin functions // -#define BUILDIN_DEF(x,args) { buildin_ ## x , #x , args } -#define BUILDIN_DEF2(x,x2,args) { buildin_ ## x , x2 , args } - ///////////////////////////////////////////////////////////////////// // NPC interaction // @@ -3875,21 +4545,21 @@ int script_reload() { /// /// mes "<message>"; BUILDIN(mes) { - TBL_PC* sd = script_rid2sd(st); + TBL_PC* sd = script->rid2sd(st); 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; - + 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; } @@ -3900,8 +4570,8 @@ BUILDIN(mes) { BUILDIN(next) { TBL_PC* sd; - - sd = script_rid2sd(st); + + sd = script->rid2sd(st); if( sd == NULL ) return true; #ifdef SECURE_NPCTIMEOUT @@ -3918,11 +4588,11 @@ BUILDIN(next) /// close; BUILDIN(close) { TBL_PC* sd; - - sd = script_rid2sd(st); + + sd = script->rid2sd(st); if( sd == NULL ) return true; - + st->state = sd->state.dialog == 1 ? CLOSE : END; clif->scriptclose(sd, st->oid); return true; @@ -3934,12 +4604,18 @@ BUILDIN(close) { /// close2; BUILDIN(close2) { TBL_PC* sd; - - sd = script_rid2sd(st); + + sd = script->rid2sd(st); if( sd == NULL ) return true; - - st->state = STOP; + + if( sd->state.dialog == 1 ) + st->state = STOP; + else { + ShowWarning("misuse of 'close2'! trying to use it without prior dialog! skipping...\n"); + script->reportsrc(st); + } + clif->scriptclose(sd, st->oid); return true; } @@ -3947,15 +4623,15 @@ BUILDIN(close2) { /// Counts the number of valid and total number of options in 'str' /// If max_count > 0 the counting stops when that valid option is reached /// total is incremented for each option (NULL is supported) -static int menu_countoptions(const char* str, int max_count, int* total) +int menu_countoptions(const char* str, int max_count, int* total) { int count = 0; int bogus_total; - + if( total == NULL ) total = &bogus_total; ++(*total); - + // initial empty options while( *str == ':' ) { @@ -4001,62 +4677,60 @@ BUILDIN(menu) int i; const char* text; TBL_PC* sd; - - sd = script_rid2sd(st); + + sd = script->rid2sd(st); if( sd == NULL ) return true; - + #ifdef SECURE_NPCTIMEOUT sd->npc_idle_type = NPCT_MENU; #endif - + // TODO detect multiple scripts waiting for input at the same time, and what to do when that happens if( sd->state.menu_or_input == 0 ) { struct StringBuf buf; struct script_data* data; - + if( script_lastdata(st) % 2 == 0 ) {// argument count is not even (1st argument is at index 2) ShowError("script:menu: illegal number of arguments (%d).\n", (script_lastdata(st) - 1)); st->state = END; return false; } - + StrBuf->Init(&buf); sd->npc_menu = 0; for( i = 2; i < script_lastdata(st); i += 2 ) { // menu options text = script_getstr(st, i); - + // target label data = script_getdata(st, i+1); if( !data_islabel(data) ) {// not a label StrBuf->Destroy(&buf); ShowError("script:menu: argument #%d (from 1) is not a label or label not found.\n", i); - script_reportdata(data); + script->reportdata(data); st->state = END; return false; } - + // append option(s) if( text[0] == '\0' ) continue;// empty string, ignore if( sd->npc_menu > 0 ) StrBuf->AppendStr(&buf, ":"); StrBuf->AppendStr(&buf, text); - sd->npc_menu += menu_countoptions(text, 0, NULL); + sd->npc_menu += script->menu_countoptions(text, 0, NULL); } st->state = RERUNLINE; sd->state.menu_or_input = 1; - - /** - * menus beyond this length crash the client (see bugreport:6402) - **/ + + /* menus beyond this length crash the client (see bugreport:6402) */ if( StrBuf->Length(&buf) >= 2047 ) { - struct npc_data * nd = iMap->id2nd(st->oid); + struct npc_data * nd = map->id2nd(st->oid); char* menu; CREATE(menu, char, 2048); safestrncpy(menu, StrBuf->Value(&buf), 2047); @@ -4065,13 +4739,13 @@ BUILDIN(menu) aFree(menu); } else clif->scriptmenu(sd, st->oid, StrBuf->Value(&buf)); - + StrBuf->Destroy(&buf); - + if( sd->npc_menu >= 0xff ) {// client supports only up to 254 entries; 0 is not used and 255 is reserved for cancel; excess entries are displayed but cause 'uint8' overflow ShowWarning("buildin_menu: Too many options specified (current=%d, max=254).\n", sd->npc_menu); - script_reportsrc(st); + script->reportsrc(st); } } else if( sd->npc_menu == 0xff ) @@ -4082,7 +4756,7 @@ BUILDIN(menu) else {// goto target label int menu = 0; - + sd->state.menu_or_input = 0; if( sd->npc_menu <= 0 ) { @@ -4090,12 +4764,12 @@ BUILDIN(menu) st->state = END; return false; } - + // get target label for( i = 2; i < script_lastdata(st); i += 2 ) { text = script_getstr(st, i); - sd->npc_menu -= menu_countoptions(text, sd->npc_menu, &menu); + sd->npc_menu -= script->menu_countoptions(text, sd->npc_menu, &menu); if( sd->npc_menu <= 0 ) break;// entry found } @@ -4108,11 +4782,11 @@ BUILDIN(menu) if( !data_islabel(script_getdata(st, i + 1)) ) {// TODO remove this temporary crash-prevention code (fallback for multiple scripts requesting user input) ShowError("script:menu: unexpected data in label argument\n"); - script_reportdata(script_getdata(st, i + 1)); + script->reportdata(script_getdata(st, i + 1)); st->state = END; return false; } - pc->setreg(sd, add_str("@menu"), menu); + pc->setreg(sd, script->add_str("@menu"), menu); st->pos = script_getnum(st, i + 1); st->state = GOTO; } @@ -4130,38 +4804,36 @@ BUILDIN(select) int i; const char* text; TBL_PC* sd; - - sd = script_rid2sd(st); + + sd = script->rid2sd(st); if( sd == NULL ) return true; - + #ifdef SECURE_NPCTIMEOUT sd->npc_idle_type = NPCT_MENU; #endif - + if( sd->state.menu_or_input == 0 ) { struct StringBuf buf; - + StrBuf->Init(&buf); sd->npc_menu = 0; for( i = 2; i <= script_lastdata(st); ++i ) { text = script_getstr(st, i); - + if( sd->npc_menu > 0 ) StrBuf->AppendStr(&buf, ":"); - + StrBuf->AppendStr(&buf, text); - sd->npc_menu += menu_countoptions(text, 0, NULL); + sd->npc_menu += script->menu_countoptions(text, 0, NULL); } - + st->state = RERUNLINE; sd->state.menu_or_input = 1; - - /** - * menus beyond this length crash the client (see bugreport:6402) - **/ + + /* menus beyond this length crash the client (see bugreport:6402) */ if( StrBuf->Length(&buf) >= 2047 ) { - struct npc_data * nd = iMap->id2nd(st->oid); + struct npc_data * nd = map->id2nd(st->oid); char* menu; CREATE(menu, char, 2048); safestrncpy(menu, StrBuf->Value(&buf), 2047); @@ -4171,25 +4843,25 @@ BUILDIN(select) } else clif->scriptmenu(sd, st->oid, StrBuf->Value(&buf)); StrBuf->Destroy(&buf); - + if( sd->npc_menu >= 0xff ) { ShowWarning("buildin_select: Too many options specified (current=%d, max=254).\n", sd->npc_menu); - script_reportsrc(st); + script->reportsrc(st); } } else if( sd->npc_menu == 0xff ) {// Cancel was pressed sd->state.menu_or_input = 0; st->state = END; } else {// return selected option int menu = 0; - + sd->state.menu_or_input = 0; for( i = 2; i <= script_lastdata(st); ++i ) { text = script_getstr(st, i); - sd->npc_menu -= menu_countoptions(text, sd->npc_menu, &menu); + sd->npc_menu -= script->menu_countoptions(text, sd->npc_menu, &menu); if( sd->npc_menu <= 0 ) break;// entry found } - pc->setreg(sd, add_str("@menu"), menu); + pc->setreg(sd, script->add_str("@menu"), menu); script_pushint(st, menu); st->state = RUN; } @@ -4209,19 +4881,19 @@ BUILDIN(prompt) int i; const char *text; TBL_PC* sd; - - sd = script_rid2sd(st); + + sd = script->rid2sd(st); if( sd == NULL ) return true; - + #ifdef SECURE_NPCTIMEOUT sd->npc_idle_type = NPCT_MENU; #endif - + if( sd->state.menu_or_input == 0 ) { struct StringBuf buf; - + StrBuf->Init(&buf); sd->npc_menu = 0; for( i = 2; i <= script_lastdata(st); ++i ) @@ -4230,17 +4902,15 @@ BUILDIN(prompt) if( sd->npc_menu > 0 ) StrBuf->AppendStr(&buf, ":"); StrBuf->AppendStr(&buf, text); - sd->npc_menu += menu_countoptions(text, 0, NULL); + sd->npc_menu += script->menu_countoptions(text, 0, NULL); } - + st->state = RERUNLINE; sd->state.menu_or_input = 1; - - /** - * menus beyond this length crash the client (see bugreport:6402) - **/ + + /* menus beyond this length crash the client (see bugreport:6402) */ if( StrBuf->Length(&buf) >= 2047 ) { - struct npc_data * nd = iMap->id2nd(st->oid); + struct npc_data * nd = map->id2nd(st->oid); char* menu; CREATE(menu, char, 2048); safestrncpy(menu, StrBuf->Value(&buf), 2047); @@ -4250,33 +4920,33 @@ BUILDIN(prompt) } else clif->scriptmenu(sd, st->oid, StrBuf->Value(&buf)); StrBuf->Destroy(&buf); - + if( sd->npc_menu >= 0xff ) { ShowWarning("buildin_prompt: Too many options specified (current=%d, max=254).\n", sd->npc_menu); - script_reportsrc(st); + script->reportsrc(st); } } else if( sd->npc_menu == 0xff ) {// Cancel was pressed sd->state.menu_or_input = 0; - pc->setreg(sd, add_str("@menu"), 0xff); + pc->setreg(sd, script->add_str("@menu"), 0xff); script_pushint(st, 0xff); st->state = RUN; } else {// return selected option int menu = 0; - + sd->state.menu_or_input = 0; for( i = 2; i <= script_lastdata(st); ++i ) { text = script_getstr(st, i); - sd->npc_menu -= menu_countoptions(text, sd->npc_menu, &menu); + sd->npc_menu -= script->menu_countoptions(text, sd->npc_menu, &menu); if( sd->npc_menu <= 0 ) break;// entry found } - pc->setreg(sd, add_str("@menu"), menu); + pc->setreg(sd, script->add_str("@menu"), menu); script_pushint(st, menu); st->state = RUN; } @@ -4295,11 +4965,11 @@ BUILDIN(goto) if( !data_islabel(script_getdata(st,2)) ) { ShowError("script:goto: not a label\n"); - script_reportdata(script_getdata(st,2)); + script->reportdata(script_getdata(st,2)); st->state = END; return false; } - + st->pos = script_getnum(st,2); st->state = GOTO; return true; @@ -4314,44 +4984,55 @@ BUILDIN(callfunc) struct script_retinfo* ri; struct script_code* scr; const char* str = script_getstr(st,2); - DBMap **ref = NULL; - - scr = (struct script_code*)strdb_get(userfunc_db, str); + struct reg_db *ref = NULL; + + scr = (struct script_code*)strdb_get(script->userfunc_db, str); if( !scr ) { ShowError("script:callfunc: function not found! [%s]\n", str); st->state = END; return false; } - - for( i = st->start+3, j = 0; i < st->end; i++, j++ ) - { + + ref = (struct reg_db *)aCalloc(sizeof(struct reg_db), 2); + ref[0].vars = st->stack->scope.vars; + if (!st->stack->scope.arrays) + st->stack->scope.arrays = idb_alloc(DB_OPT_BASE); // TODO: Can this happen? when? + ref[0].arrays = st->stack->scope.arrays; + ref[1].vars = st->script->local.vars; + if (!st->script->local.arrays) + st->script->local.arrays = idb_alloc(DB_OPT_BASE); // TODO: Can this happen? when? + ref[1].arrays = st->script->local.arrays; + + for( i = st->start+3, j = 0; i < st->end; i++, j++ ) { struct script_data* data = script->push_copy(st->stack,i); - if( data_isreference(data) && !data->ref ) - { + if( data_isreference(data) && !data->ref ) { const char* name = reference_getname(data); if( name[0] == '.' ) { - ref = (struct DBMap**)aCalloc(sizeof(struct DBMap*), 1); - ref[0] = (name[1] == '@' ? st->stack->var_function : st->script->script_vars); - data->ref = ref; + data->ref = (name[1] == '@' ? &ref[0] : &ref[1]); } } } - + CREATE(ri, struct script_retinfo, 1); - ri->script = st->script;// script code - ri->var_function = st->stack->var_function;// scope variables - ri->pos = st->pos;// script location - ri->nargs = j;// argument count - ri->defsp = st->stack->defsp;// default stack pointer - push_retinfo(st->stack, ri, ref); - + ri->script = st->script; // script code + ri->scope.vars = st->stack->scope.vars; // scope variables + ri->scope.arrays = st->stack->scope.arrays; // scope arrays + ri->pos = st->pos; // script location + ri->nargs = j; // argument count + ri->defsp = st->stack->defsp; // default stack pointer + script->push_retinfo(st->stack, ri, ref); + st->pos = 0; st->script = scr; st->stack->defsp = st->stack->sp; st->state = GOTO; - st->stack->var_function = idb_alloc(DB_OPT_RELEASE_DATA); - + st->stack->scope.vars = i64db_alloc(DB_OPT_RELEASE_DATA); + st->stack->scope.arrays = idb_alloc(DB_OPT_BASE); + + if( !st->script->local.vars ) + st->script->local.vars = i64db_alloc(DB_OPT_RELEASE_DATA); + return true; } /*========================================== @@ -4362,45 +5043,47 @@ BUILDIN(callsub) int i,j; struct script_retinfo* ri; int pos = script_getnum(st,2); - DBMap **ref = NULL; - + struct reg_db *ref = NULL; + if( !data_islabel(script_getdata(st,2)) && !data_isfunclabel(script_getdata(st,2)) ) { ShowError("script:callsub: argument is not a label\n"); - script_reportdata(script_getdata(st,2)); + script->reportdata(script_getdata(st,2)); st->state = END; return false; } - - for( i = st->start+3, j = 0; i < st->end; i++, j++ ) - { + + ref = (struct reg_db *)aCalloc(sizeof(struct reg_db), 1); + ref[0].vars = st->stack->scope.vars; + if (!st->stack->scope.arrays) + st->stack->scope.arrays = idb_alloc(DB_OPT_BASE); // TODO: Can this happen? when? + ref[0].arrays = st->stack->scope.arrays; + + for( i = st->start+3, j = 0; i < st->end; i++, j++ ) { struct script_data* data = script->push_copy(st->stack,i); - if( data_isreference(data) && !data->ref ) - { + if( data_isreference(data) && !data->ref ) { const char* name = reference_getname(data); if( name[0] == '.' && name[1] == '@' ) { - if ( !ref ) { - ref = (struct DBMap**)aCalloc(sizeof(struct DBMap*), 1); - ref[0] = st->stack->var_function; - } - data->ref = ref; + data->ref = &ref[0]; } } } - + CREATE(ri, struct script_retinfo, 1); - ri->script = st->script;// script code - ri->var_function = st->stack->var_function;// scope variables - ri->pos = st->pos;// script location - ri->nargs = j;// argument count - ri->defsp = st->stack->defsp;// default stack pointer - push_retinfo(st->stack, ri, ref); - + ri->script = st->script; // script code + ri->scope.vars = st->stack->scope.vars; // scope variables + ri->scope.arrays = st->stack->scope.arrays; // scope arrays + ri->pos = st->pos; // script location + ri->nargs = j; // argument count + ri->defsp = st->stack->defsp; // default stack pointer + script->push_retinfo(st->stack, ri, ref); + st->pos = pos; st->stack->defsp = st->stack->sp; st->state = GOTO; - st->stack->var_function = idb_alloc(DB_OPT_RELEASE_DATA); - + st->stack->scope.vars = i64db_alloc(DB_OPT_RELEASE_DATA); + st->stack->scope.arrays = idb_alloc(DB_OPT_BASE); + return true; } @@ -4412,7 +5095,7 @@ BUILDIN(getarg) { struct script_retinfo* ri; int idx; - + if( st->stack->defsp < 1 || st->stack->stack_data[st->stack->defsp - 1].type != C_RETINFO ) { ShowError("script:getarg: no callfunc or callsub!\n"); @@ -4420,9 +5103,9 @@ BUILDIN(getarg) return false; } ri = st->stack->stack_data[st->stack->defsp - 1].u.ri; - + idx = script_getnum(st,2); - + if( idx >= 0 && idx < ri->nargs ) script->push_copy(st->stack, st->stack->defsp - 1 - ri->nargs + idx); else if( script_hasdata(st,3) ) @@ -4433,7 +5116,7 @@ BUILDIN(getarg) st->state = END; return false; } - + return true; } @@ -4442,24 +5125,30 @@ BUILDIN(getarg) /// /// return; /// return <value>; -BUILDIN(return) -{ +BUILDIN(return) { if( script_hasdata(st,2) ) {// return value struct script_data* data; script_pushcopy(st, 2); data = script_getdatatop(st, -1); - if( data_isreference(data) ) - { + if( data_isreference(data) ) { const char* name = reference_getname(data); - if( name[0] == '.' && name[1] == '@' ) - {// scope variable - if( !data->ref || data->ref == (DBMap**)&st->stack->var_function ) + if( name[0] == '.' && name[1] == '@' ) { + // scope variable + if( !data->ref || data->ref->vars == st->stack->scope.vars ) script->get_val(st, data);// current scope, convert to value - } - else if( name[0] == '.' && !data->ref ) - {// script variable, link to current script - data->ref = &st->script->script_vars; + if( data->ref && data->ref->vars == st->stack->stack_data[st->stack->defsp-1].u.ri->scope.vars ) + data->ref = NULL; // Reference to the parent scope, remove reference pointer + } else if( name[0] == '.' && !data->ref ) { + // script variable without a reference set, link to current script + data->ref = (struct reg_db *)aCalloc(sizeof(struct reg_db), 1); + script->add_pending_ref(st, data->ref); + data->ref->vars = st->script->local.vars; + if( !st->script->local.arrays ) + st->script->local.arrays = idb_alloc(DB_OPT_BASE); + data->ref->arrays = st->script->local.arrays; + } else if ( name[0] == '.' /* && data->ref != NULL */ ) { + data->ref = NULL; // Reference to the parent scope's script, remove reference pointer. } } } @@ -4481,7 +5170,7 @@ BUILDIN(rand) int range; int min; int max; - + if( script_hasdata(st,3) ) {// min,max min = script_getnum(st,2); @@ -4499,7 +5188,7 @@ BUILDIN(rand) script_pushint(st, min); else script_pushint(st, rnd()%range + min); - + return true; } @@ -4512,59 +5201,59 @@ BUILDIN(warp) int x,y; const char* str; TBL_PC* sd; - - sd = script_rid2sd(st); + + sd = script->rid2sd(st); if( sd == NULL ) return true; - + str = script_getstr(st,2); x = script_getnum(st,3); y = script_getnum(st,4); - + if(strcmp(str,"Random")==0) ret = pc->randomwarp(sd,CLR_TELEPORT); else if(strcmp(str,"SavePoint")==0 || strcmp(str,"Save")==0) ret = pc->setpos(sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,CLR_TELEPORT); else - ret = pc->setpos(sd,mapindex_name2id(str),x,y,CLR_OUTSIGHT); - + ret = pc->setpos(sd,script->mapindexname2id(st,str),x,y,CLR_OUTSIGHT); + if( ret ) { ShowError("buildin_warp: moving player '%s' to \"%s\",%d,%d failed.\n", sd->status.name, str, x, y); - script_reportsrc(st); + script->reportsrc(st); } - + return true; } /*========================================== * Warp a specified area *------------------------------------------*/ -static int buildin_areawarp_sub(struct block_list *bl,va_list ap) +int buildin_areawarp_sub(struct block_list *bl,va_list ap) { int x2,y2,x3,y3; unsigned int index; - + index = va_arg(ap,unsigned int); x2 = va_arg(ap,int); y2 = va_arg(ap,int); x3 = va_arg(ap,int); y3 = va_arg(ap,int); - + if(index == 0) pc->randomwarp((TBL_PC *)bl,CLR_TELEPORT); else if(x3 && y3) { int max, tx, ty, j = 0; - + // choose a suitable max number of attempts if( (max = (y3-y2+1)*(x3-x2+1)*3) > 1000 ) max = 1000; - + // find a suitable map cell do { tx = rnd()%(x3-x2+1)+x2; ty = rnd()%(y3-y2+1)+y2; j++; - } while( iMap->getcell(index,tx,ty,CELL_CHKNOPASS) && j < max ); - + } while( map->getcell(index,tx,ty,CELL_CHKNOPASS) && j < max ); + pc->setpos((TBL_PC *)bl,index,tx,ty,CLR_OUTSIGHT); } else @@ -4577,7 +5266,7 @@ BUILDIN(areawarp) unsigned int index; const char *str; const char *mapname; - + mapname = script_getstr(st,2); x0 = script_getnum(st,3); y0 = script_getnum(st,4); @@ -4586,9 +5275,9 @@ BUILDIN(areawarp) str = script_getstr(st,7); x2 = script_getnum(st,8); y2 = script_getnum(st,9); - + if( script_hasdata(st,10) && script_hasdata(st,11) ) { // Warp area to area - if( (x3 = script_getnum(st,10)) < 0 || (y3 = script_getnum(st,11)) < 0 ){ + if( (x3 = script_getnum(st,10)) < 0 || (y3 = script_getnum(st,11)) < 0 ) { x3 = 0; y3 = 0; } else if( x3 && y3 ) { @@ -4597,23 +5286,23 @@ BUILDIN(areawarp) if( y3 < y2 ) swap(y3,y2); } } - - if( (m = iMap->mapname2mapid(mapname)) < 0 ) + + if( (m = map->mapname2mapid(mapname)) < 0 ) return true; - + if( strcmp(str,"Random") == 0 ) index = 0; - else if( !(index=mapindex_name2id(str)) ) + else if( !(index=script->mapindexname2id(st,str)) ) return true; - - iMap->foreachinarea(buildin_areawarp_sub, m,x0,y0,x1,y1, BL_PC, index,x2,y2,x3,y3); + + map->foreachinarea(script->buildin_areawarp_sub, m,x0,y0,x1,y1, BL_PC, index,x2,y2,x3,y3); return true; } /*========================================== * areapercentheal <map>,<x1>,<y1>,<x2>,<y2>,<hp>,<sp> *------------------------------------------*/ -static int buildin_areapercentheal_sub(struct block_list *bl,va_list ap) +int buildin_areapercentheal_sub(struct block_list *bl,va_list ap) { int hp, sp; hp = va_arg(ap, int); @@ -4621,12 +5310,11 @@ static int buildin_areapercentheal_sub(struct block_list *bl,va_list ap) pc->percentheal((TBL_PC *)bl,hp,sp); return 0; } -BUILDIN(areapercentheal) -{ +BUILDIN(areapercentheal) { int hp,sp,m; const char *mapname; int x0,y0,x1,y1; - + mapname=script_getstr(st,2); x0=script_getnum(st,3); y0=script_getnum(st,4); @@ -4634,11 +5322,11 @@ BUILDIN(areapercentheal) y1=script_getnum(st,6); hp=script_getnum(st,7); sp=script_getnum(st,8); - - if( (m=iMap->mapname2mapid(mapname))< 0) + + if( (m=map->mapname2mapid(mapname))< 0) return true; - - iMap->foreachinarea(buildin_areapercentheal_sub,m,x0,y0,x1,y1,BL_PC,hp,sp); + + map->foreachinarea(script->buildin_areapercentheal_sub,m,x0,y0,x1,y1,BL_PC,hp,sp); return true; } @@ -4648,29 +5336,28 @@ BUILDIN(areapercentheal) * another player npc-session. * Using: warpchar "mapname",x,y,Char_ID; *------------------------------------------*/ -BUILDIN(warpchar) -{ +BUILDIN(warpchar) { int x,y,a; const char *str; TBL_PC *sd; - + str=script_getstr(st,2); x=script_getnum(st,3); y=script_getnum(st,4); a=script_getnum(st,5); - - sd = iMap->charid2sd(a); + + sd = map->charid2sd(a); if( sd == NULL ) return true; - + if(strcmp(str, "Random") == 0) pc->randomwarp(sd, CLR_TELEPORT); else if(strcmp(str, "SavePoint") == 0) pc->setpos(sd, sd->status.save_point.map,sd->status.save_point.x, sd->status.save_point.y, CLR_TELEPORT); else - pc->setpos(sd, mapindex_name2id(str), x, y, CLR_TELEPORT); - + pc->setpos(sd, script->mapindexname2id(st,str), x, y, CLR_TELEPORT); + return true; } /*========================================== @@ -4684,9 +5371,9 @@ BUILDIN(warpparty) TBL_PC *pl_sd; struct party_data* p; int type; - int mapindex; + int map_index; int i; - + const char* str = script_getstr(st,2); int x = script_getnum(st,3); int y = script_getnum(st,4); @@ -4694,17 +5381,17 @@ BUILDIN(warpparty) const char* str2 = NULL; if ( script_hasdata(st,6) ) str2 = script_getstr(st,6); - + p = party->search(p_id); if(!p) return true; - + type = ( strcmp(str,"Random")==0 ) ? 0 : ( strcmp(str,"SavePointAll")==0 ) ? 1 : ( strcmp(str,"SavePoint")==0 ) ? 2 : ( strcmp(str,"Leader")==0 ) ? 3 : 4; - + switch (type) { case 3: @@ -4712,55 +5399,54 @@ BUILDIN(warpparty) if (i == MAX_PARTY || !p->data[i].sd) //Leader not found / not online return true; pl_sd = p->data[i].sd; - mapindex = pl_sd->mapindex; + map_index = pl_sd->mapindex; x = pl_sd->bl.x; y = pl_sd->bl.y; break; case 4: - mapindex = mapindex_name2id(str); + map_index = script->mapindexname2id(st,str); break; case 2: //"SavePoint" uses save point of the currently attached player - if (( sd = script_rid2sd(st) ) == NULL ) + if (( sd = script->rid2sd(st) ) == NULL ) return true; default: - mapindex = 0; + map_index = 0; break; } - - for (i = 0; i < MAX_PARTY; i++) - { + + for (i = 0; i < MAX_PARTY; i++) { if( !(pl_sd = p->data[i].sd) || pl_sd->status.party_id != p_id ) continue; - - if( str2 && strcmp(str2, map[pl_sd->bl.m].name) != 0 ) + + if( str2 && strcmp(str2, map->list[pl_sd->bl.m].name) != 0 ) continue; - + if( pc_isdead(pl_sd) ) continue; - + switch( type ) { case 0: // Random - if(!map[pl_sd->bl.m].flag.nowarp) + if(!map->list[pl_sd->bl.m].flag.nowarp) pc->randomwarp(pl_sd,CLR_TELEPORT); break; case 1: // SavePointAll - if(!map[pl_sd->bl.m].flag.noreturn) + if(!map->list[pl_sd->bl.m].flag.noreturn) pc->setpos(pl_sd,pl_sd->status.save_point.map,pl_sd->status.save_point.x,pl_sd->status.save_point.y,CLR_TELEPORT); break; case 2: // SavePoint - if(!map[pl_sd->bl.m].flag.noreturn) + if(!map->list[pl_sd->bl.m].flag.noreturn) pc->setpos(pl_sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,CLR_TELEPORT); break; case 3: // Leader case 4: // m,x,y - if(!map[pl_sd->bl.m].flag.noreturn && !map[pl_sd->bl.m].flag.nowarp) - pc->setpos(pl_sd,mapindex,x,y,CLR_TELEPORT); + if(!map->list[pl_sd->bl.m].flag.noreturn && !map->list[pl_sd->bl.m].flag.nowarp) + pc->setpos(pl_sd,map_index,x,y,CLR_TELEPORT); break; } } - + return true; } /*========================================== @@ -4774,70 +5460,69 @@ BUILDIN(warpguild) struct guild* g; struct s_mapiterator* iter; int type; - + const char* str = script_getstr(st,2); int x = script_getnum(st,3); int y = script_getnum(st,4); int gid = script_getnum(st,5); - + g = guild->search(gid); if( g == NULL ) return true; - + type = ( strcmp(str,"Random")==0 ) ? 0 : ( strcmp(str,"SavePointAll")==0 ) ? 1 : ( strcmp(str,"SavePoint")==0 ) ? 2 : 3; - - if( type == 2 && ( sd = script_rid2sd(st) ) == NULL ) + + if( type == 2 && ( sd = script->rid2sd(st) ) == NULL ) {// "SavePoint" uses save point of the currently attached player return true; } - + iter = mapit_getallusers(); for( pl_sd = (TBL_PC*)mapit->first(iter); mapit->exists(iter); pl_sd = (TBL_PC*)mapit->next(iter) ) { if( pl_sd->status.guild_id != gid ) continue; - + switch( type ) { case 0: // Random - if(!map[pl_sd->bl.m].flag.nowarp) + if(!map->list[pl_sd->bl.m].flag.nowarp) pc->randomwarp(pl_sd,CLR_TELEPORT); break; case 1: // SavePointAll - if(!map[pl_sd->bl.m].flag.noreturn) + if(!map->list[pl_sd->bl.m].flag.noreturn) pc->setpos(pl_sd,pl_sd->status.save_point.map,pl_sd->status.save_point.x,pl_sd->status.save_point.y,CLR_TELEPORT); break; case 2: // SavePoint - if(!map[pl_sd->bl.m].flag.noreturn) + if(!map->list[pl_sd->bl.m].flag.noreturn) pc->setpos(pl_sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,CLR_TELEPORT); break; case 3: // m,x,y - if(!map[pl_sd->bl.m].flag.noreturn && !map[pl_sd->bl.m].flag.nowarp) - pc->setpos(pl_sd,mapindex_name2id(str),x,y,CLR_TELEPORT); + if(!map->list[pl_sd->bl.m].flag.noreturn && !map->list[pl_sd->bl.m].flag.nowarp) + pc->setpos(pl_sd,script->mapindexname2id(st,str),x,y,CLR_TELEPORT); break; } } mapit->free(iter); - + return true; } /*========================================== * Force Heal a player (hp and sp) *------------------------------------------*/ -BUILDIN(heal) -{ +BUILDIN(heal) { TBL_PC *sd; int hp,sp; - - sd = script_rid2sd(st); + + sd = script->rid2sd(st); if (!sd) return true; - + hp=script_getnum(st,2); sp=script_getnum(st,3); - status_heal(&sd->bl, hp, sp, 1); + status->heal(&sd->bl, hp, sp, 1); return true; } /*========================================== @@ -4847,17 +5532,17 @@ BUILDIN(itemheal) { TBL_PC *sd; int hp,sp; - + hp=script_getnum(st,2); sp=script_getnum(st,3); - - if(potion_flag==1) { - potion_hp = hp; - potion_sp = sp; + + if(script->potion_flag==1) { + script->potion_hp = hp; + script->potion_sp = sp; return true; } - - sd = script_rid2sd(st); + + sd = script->rid2sd(st); if (!sd) return true; pc->itemheal(sd,sd->itemid,hp,sp); return true; @@ -4869,17 +5554,17 @@ BUILDIN(percentheal) { int hp,sp; TBL_PC* sd; - + hp=script_getnum(st,2); sp=script_getnum(st,3); - - if(potion_flag==1) { - potion_per_hp = hp; - potion_per_sp = sp; + + if(script->potion_flag==1) { + script->potion_per_hp = hp; + script->potion_per_sp = sp; return true; } - - sd = script_rid2sd(st); + + sd = script->rid2sd(st); if( sd == NULL ) return true; #ifdef RENEWAL @@ -4896,22 +5581,22 @@ BUILDIN(percentheal) BUILDIN(jobchange) { int job, upper=-1; - + job=script_getnum(st,2); if( script_hasdata(st,3) ) upper=script_getnum(st,3); - + if (pcdb_checkid(job)) { TBL_PC* sd; - - sd = script_rid2sd(st); + + sd = script->rid2sd(st); if( sd == NULL ) return true; - + pc->jobchange(sd, job, upper); } - + return true; } @@ -4936,53 +5621,52 @@ BUILDIN(input) { TBL_PC* sd; struct script_data* data; - int uid; + int64 uid; const char* name; int min; int max; - - sd = script_rid2sd(st); + + sd = script->rid2sd(st); if( sd == NULL ) return true; - + data = script_getdata(st,2); - if( !data_isreference(data) ){ + if( !data_isreference(data) ) { ShowError("script:input: not a variable\n"); - script_reportdata(data); + script->reportdata(data); st->state = END; return false; } uid = reference_getuid(data); name = reference_getname(data); - min = (script_hasdata(st,3) ? script_getnum(st,3) : script_config.input_min_value); - max = (script_hasdata(st,4) ? script_getnum(st,4) : script_config.input_max_value); - + min = (script_hasdata(st,3) ? script_getnum(st,3) : script->config.input_min_value); + max = (script_hasdata(st,4) ? script_getnum(st,4) : script->config.input_max_value); + #ifdef SECURE_NPCTIMEOUT sd->npc_idle_type = NPCT_WAIT; #endif - - if( !sd->state.menu_or_input ) - { // first invocation, display npc input box + + if( !sd->state.menu_or_input ) { + // first invocation, display npc input box sd->state.menu_or_input = 1; st->state = RERUNLINE; if( is_string_variable(name) ) clif->scriptinputstr(sd,st->oid); else clif->scriptinput(sd,st->oid); - } - else - { // take received text/value and store it in the designated variable + } else { + // take received text/value and store it in the designated variable sd->state.menu_or_input = 0; if( is_string_variable(name) ) { int len = (int)strlen(sd->npc_str); - set_reg(st, sd, uid, name, (void*)sd->npc_str, script_getref(st,2)); + script->set_reg(st, sd, uid, name, (void*)sd->npc_str, script_getref(st,2)); script_pushint(st, (len > max ? 1 : len < min ? -1 : 0)); } else { int amount = sd->npc_amount; - set_reg(st, sd, uid, name, (void*)__64BPTRSIZE(cap_value(amount,min,max)), script_getref(st,2)); + script->set_reg(st, sd, uid, name, (void*)h64BPTRSIZE(cap_value(amount,min,max)), script_getref(st,2)); script_pushint(st, (amount > max ? 1 : amount < min ? -1 : 0)); } st->state = RUN; @@ -4997,75 +5681,81 @@ BUILDIN(copyarray); /// The value is converted to the type of the variable. /// /// set(<variable>,<value>) -> <variable> -BUILDIN(set) -{ +BUILDIN(setr) { TBL_PC* sd = NULL; struct script_data* data; //struct script_data* datavalue; - int num; + int64 num; const char* name; char prefix; - + data = script_getdata(st,2); //datavalue = script_getdata(st,3); - if( !data_isreference(data) ) - { + if( !data_isreference(data) || reference_toconstant(data) ) { ShowError("script:set: not a variable\n"); - script_reportdata(script_getdata(st,2)); + script->reportdata(script_getdata(st,2)); st->state = END; return false; } - + num = reference_getuid(data); name = reference_getname(data); prefix = *name; - - if( not_server_variable(prefix) ) - { - sd = script_rid2sd(st); - if( sd == NULL ) - { + + if( not_server_variable(prefix) ) { + sd = script->rid2sd(st); + if( sd == NULL ) { ShowError("script:set: no player attached for player variable '%s'\n", name); return true; } } - + #if 0 - if( data_isreference(datavalue) ) - {// the value being referenced is a variable + // TODO: see de43fa0f73be01080bd11c08adbfb7c158324c81 + if( data_isreference(datavalue) ) { + // the value being referenced is a variable const char* namevalue = reference_getname(datavalue); - - if( !not_array_variable(*namevalue) ) - {// array variable being copied into another array variable - if( sd == NULL && not_server_variable(*namevalue) && !(sd = script_rid2sd(st)) ) - {// player must be attached in order to copy a player variable + + if( !not_array_variable(*namevalue) ) { + // array variable being copied into another array variable + if( sd == NULL && not_server_variable(*namevalue) && !(sd = script->rid2sd(st)) ) { + // player must be attached in order to copy a player variable ShowError("script:set: no player attached for player variable '%s'\n", namevalue); return true; } - - if( is_string_variable(namevalue) != is_string_variable(name) ) - {// non-matching array value types + + if( is_string_variable(namevalue) != is_string_variable(name) ) { + // non-matching array value types ShowWarning("script:set: two array variables do not match in type.\n"); return true; } - + // push the maximum number of array values to the stack script->push_val(st->stack, C_INT, SCRIPT_MAX_ARRAYSIZE,NULL); - + // call the copy array method directly return buildin_copyarray(st); } } #endif - + + if( script_hasdata(st, 4) ) { + // Optional argument used by post-increment/post-decrement constructs to return the previous value + if( is_string_variable(name) ) { + script_pushstrcopy(st, script_getstr(st, 4)); + } else { + script_pushint(st, script_getnum(st, 4)); + } + } else { + // return a copy of the variable reference + script_pushcopy(st,2); + } + if( is_string_variable(name) ) - set_reg(st,sd,num,name,(void*)script_getstr(st,3),script_getref(st,2)); + script->set_reg(st,sd,num,name,(void*)script_getstr(st,3),script_getref(st,2)); else - set_reg(st,sd,num,name,(void*)__64BPTRSIZE(script_getnum(st,3)),script_getref(st,2)); - - // return a copy of the variable reference - script_pushcopy(st,2); - + script->set_reg(st,sd,num,name,(void*)h64BPTRSIZE(script_getnum(st,3)),script_getref(st,2)); + return true; } @@ -5073,34 +5763,6 @@ BUILDIN(set) /// Array variables /// -/// Returns the size of the specified array -static int32 getarraysize(struct script_state* st, int32 id, int32 idx, int isstring, struct DBMap** ref) -{ - int32 ret = idx; - - if( isstring ) - { - for( ; idx < SCRIPT_MAX_ARRAYSIZE; ++idx ) - { - char* str = (char*)script->get_val2(st, reference_uid(id, idx), ref); - if( str && *str ) - ret = idx + 1; - script_removetop(st, -1, 0); - } - } - else - { - for( ; idx < SCRIPT_MAX_ARRAYSIZE; ++idx ) - { - int32 num = (int32)__64BPTRSIZE(script->get_val2(st, reference_uid(id, idx), ref)); - if( num ) - ret = idx + 1; - script_removetop(st, -1, 0); - } - } - return ret; -} - /// Sets values of an array, from the starting index. /// ex: setarray arr[1],1,2,3; /// @@ -5109,52 +5771,45 @@ BUILDIN(setarray) { struct script_data* data; const char* name; - int32 start; - int32 end; + uint32 start; + uint32 end; int32 id; int32 i; TBL_PC* sd = NULL; - + data = script_getdata(st, 2); - if( !data_isreference(data) ) + if( !data_isreference(data) || reference_toconstant(data) ) { ShowError("script:setarray: not a variable\n"); - script_reportdata(data); + script->reportdata(data); st->state = END; return false;// not a variable } - + id = reference_getid(data); start = reference_getindex(data); name = reference_getname(data); - if( not_array_variable(*name) ) - { - ShowError("script:setarray: illegal scope\n"); - script_reportdata(data); - st->state = END; - return false;// not supported - } - + if( not_server_variable(*name) ) { - sd = script_rid2sd(st); + sd = script->rid2sd(st); if( sd == NULL ) return true;// no player attached } - + end = start + script_lastdata(st) - 2; if( end > SCRIPT_MAX_ARRAYSIZE ) end = SCRIPT_MAX_ARRAYSIZE; - + if( is_string_variable(name) ) {// string array for( i = 3; start < end; ++start, ++i ) - set_reg(st, sd, reference_uid(id, start), name, (void*)script_getstr(st,i), reference_getref(data)); + script->set_reg(st, sd, reference_uid(id, start), name, (void*)script_getstr(st,i), reference_getref(data)); } else {// int array for( i = 3; start < end; ++start, ++i ) - set_reg(st, sd, reference_uid(id, start), name, (void*)__64BPTRSIZE(script_getnum(st,i)), reference_getref(data)); + script->set_reg(st, sd, reference_uid(id, start), name, (void*)h64BPTRSIZE(script_getnum(st,i)), reference_getref(data)); } return true; } @@ -5167,50 +5822,43 @@ BUILDIN(cleararray) { struct script_data* data; const char* name; - int32 start; - int32 end; + uint32 start; + uint32 end; int32 id; void* v; TBL_PC* sd = NULL; - + data = script_getdata(st, 2); if( !data_isreference(data) ) { ShowError("script:cleararray: not a variable\n"); - script_reportdata(data); + script->reportdata(data); st->state = END; return false;// not a variable } - + id = reference_getid(data); start = reference_getindex(data); name = reference_getname(data); - if( not_array_variable(*name) ) - { - ShowError("script:cleararray: illegal scope\n"); - script_reportdata(data); - st->state = END; - return false;// not supported - } - + if( not_server_variable(*name) ) { - sd = script_rid2sd(st); + sd = script->rid2sd(st); if( sd == NULL ) return true;// no player attached } - + if( is_string_variable(name) ) v = (void*)script_getstr(st, 3); else - v = (void*)__64BPTRSIZE(script_getnum(st, 3)); - + v = (void*)h64BPTRSIZE(script_getnum(st, 3)); + end = start + script_getnum(st, 4); if( end > SCRIPT_MAX_ARRAYSIZE ) end = SCRIPT_MAX_ARRAYSIZE; - + for( ; start < end; ++start ) - set_reg(st, sd, reference_uid(id, start), name, v, script_getref(st,2)); + script->set_reg(st, sd, reference_uid(id, start), name, v, script_getref(st,2)); return true; } @@ -5230,78 +5878,67 @@ BUILDIN(copyarray) int32 id2; void* v; int32 i; - int32 count; + uint32 count; TBL_PC* sd = NULL; - + data1 = script_getdata(st, 2); data2 = script_getdata(st, 3); if( !data_isreference(data1) || !data_isreference(data2) ) { ShowError("script:copyarray: not a variable\n"); - script_reportdata(data1); - script_reportdata(data2); + script->reportdata(data1); + script->reportdata(data2); st->state = END; return false;// not a variable } - + id1 = reference_getid(data1); id2 = reference_getid(data2); idx1 = reference_getindex(data1); idx2 = reference_getindex(data2); name1 = reference_getname(data1); name2 = reference_getname(data2); - if( not_array_variable(*name1) || not_array_variable(*name2) ) - { - ShowError("script:copyarray: illegal scope\n"); - script_reportdata(data1); - script_reportdata(data2); - st->state = END; - return false;// not supported - } - + if( is_string_variable(name1) != is_string_variable(name2) ) { ShowError("script:copyarray: type mismatch\n"); - script_reportdata(data1); - script_reportdata(data2); + script->reportdata(data1); + script->reportdata(data2); st->state = END; return false;// data type mismatch } - + if( not_server_variable(*name1) || not_server_variable(*name2) ) { - sd = script_rid2sd(st); + sd = script->rid2sd(st); if( sd == NULL ) return true;// no player attached } - + count = script_getnum(st, 4); if( count > SCRIPT_MAX_ARRAYSIZE - idx1 ) count = SCRIPT_MAX_ARRAYSIZE - idx1; - if( count <= 0 || (id1 == id2 && idx1 == idx2) ) + if( count <= 0 || (idx1 == idx2 && is_same_reference(data1, data2)) ) return true;// nothing to copy - - if( id1 == id2 && idx1 > idx2 ) - {// destination might be overlapping the source - copy in reverse order - for( i = count - 1; i >= 0; --i ) - { + + if( is_same_reference(data1, data2) && idx1 > idx2 ) { + // destination might be overlapping the source - copy in reverse order + for( i = count - 1; i >= 0; --i ) { v = script->get_val2(st, reference_uid(id2, idx2 + i), reference_getref(data2)); - set_reg(st, sd, reference_uid(id1, idx1 + i), name1, v, reference_getref(data1)); + script->set_reg(st, sd, reference_uid(id1, idx1 + i), name1, v, reference_getref(data1)); script_removetop(st, -1, 0); } - } - else - {// normal copy - for( i = 0; i < count; ++i ) - { - if( idx2 + i < SCRIPT_MAX_ARRAYSIZE ) - { + } else { + // normal copy + for( i = 0; i < count; ++i ) { + if( idx2 + i < SCRIPT_MAX_ARRAYSIZE ) { v = script->get_val2(st, reference_uid(id2, idx2 + i), reference_getref(data2)); - set_reg(st, sd, reference_uid(id1, idx1 + i), name1, v, reference_getref(data1)); + script->set_reg(st, sd, reference_uid(id1, idx1 + i), name1, v, reference_getref(data1)); script_removetop(st, -1, 0); + } else { + // out of range - assume ""/0 + script->set_reg(st, sd, reference_uid(id1, idx1 + i), name1, (is_string_variable(name1)?(void*)"":(void*)0), reference_getref(data1)); } - else// out of range - assume ""/0 - set_reg(st, sd, reference_uid(id1, idx1 + i), name1, (is_string_variable(name1)?(void*)"":(void*)0), reference_getref(data1)); } } return true; @@ -5315,31 +5952,23 @@ BUILDIN(copyarray) BUILDIN(getarraysize) { struct script_data* data; - const char* name; - + data = script_getdata(st, 2); if( !data_isreference(data) ) { ShowError("script:getarraysize: not a variable\n"); - script_reportdata(data); + script->reportdata(data); script_pushnil(st); st->state = END; return false;// not a variable } - - name = reference_getname(data); - if( not_array_variable(*name) ) - { - ShowError("script:getarraysize: illegal scope\n"); - script_reportdata(data); - script_pushnil(st); - st->state = END; - return false;// not supported - } - - script_pushint(st, getarraysize(st, reference_getid(data), reference_getindex(data), is_string_variable(name), reference_getref(data))); + + script_pushint(st, script->array_highest_key(st,st->rid ? script->rid2sd(st) : NULL,reference_getname(data),reference_getref(data))); return true; } +int script_array_index_cmp(const void *a, const void *b) { + return ( *(unsigned int*)a - *(unsigned int*)b ); +} /// Deletes count or all the elements in an array, from the starting index. /// ex: deletearray arr[4],2; @@ -5350,71 +5979,109 @@ BUILDIN(deletearray) { struct script_data* data; const char* name; - int start; - int end; + unsigned int start, end, i; int id; TBL_PC *sd = NULL; - + struct script_array *sa = NULL; + struct reg_db *src = NULL; + void *value; + data = script_getdata(st, 2); if( !data_isreference(data) ) { ShowError("script:deletearray: not a variable\n"); - script_reportdata(data); + script->reportdata(data); st->state = END; return false;// not a variable } - + id = reference_getid(data); start = reference_getindex(data); name = reference_getname(data); - if( not_array_variable(*name) ) - { - ShowError("script:deletearray: illegal scope\n"); - script_reportdata(data); - st->state = END; - return false;// not supported - } - + if( not_server_variable(*name) ) { - sd = script_rid2sd(st); + sd = script->rid2sd(st); if( sd == NULL ) return true;// no player attached } + + if( !(src = script->array_src(st,sd,name, reference_getref(data)) ) ) { + ShowError("script:deletearray: not a array\n"); + script->reportdata(data); + st->state = END; + return false;// not a variable + } - end = SCRIPT_MAX_ARRAYSIZE; + script->array_ensure_zero(st,NULL,data->u.num,reference_getref(data)); + + if ( !(sa = idb_get(src->arrays, id)) ) { /* non-existent array, nothing to empty */ + return true;// not a variable + } + + end = script->array_highest_key(st,sd,name,reference_getref(data)); if( start >= end ) return true;// nothing to free + + if( is_string_variable(name) ) + value = (void *)""; + else + value = (void *)0; - if( script_hasdata(st,3) ) - { - int count = script_getnum(st, 3); + if( script_hasdata(st,3) ) { + unsigned int count = script_getnum(st, 3); if( count > end - start ) count = end - start; if( count <= 0 ) return true;// nothing to free + + if( end - start < sa->size ) { + // Better to iterate directly on the array, no speed-up from using sa + for( ; start + count < end; ++start ) { + // Compact and overwrite + void* v = script->get_val2(st, reference_uid(id, start + count), reference_getref(data)); + script->set_reg(st, sd, reference_uid(id, start), name, v, reference_getref(data)); + script_removetop(st, -1, 0); + } + for( ; start < end; start++ ) { + // Clean up any leftovers that weren't overwritten + script->set_reg(st, sd, reference_uid(id, start), name, value, reference_getref(data)); + } + } else { + // using sa to speed up + unsigned int *list = NULL, size = 0; + list = script->array_cpy_list(sa); + size = sa->size; + qsort(list, size, sizeof(unsigned int), script_array_index_cmp); + + ARR_FIND(0, size, i, list[i] >= start); + + for( ; i < size && list[i] < start + count; i++ ) { + // Clear any entries between start and start+count, if they exist + script->set_reg(st, sd, reference_uid(id, list[i]), name, value, reference_getref(data)); + } + + for( ; i < size && list[i] < end; i++ ) { + // Move back count positions any entries between start+count to fill the gaps + void* v = script->get_val2(st, reference_uid(id, list[i]), reference_getref(data)); + script->set_reg(st, sd, reference_uid(id, list[i]-count), name, v, reference_getref(data)); + script_removetop(st, -1, 0); + // Clear their originals + script->set_reg(st, sd, reference_uid(id, list[i]), name, value, reference_getref(data)); + } + } + } else { + unsigned int *list = NULL, size = 0; + list = script->array_cpy_list(sa); + size = sa->size; - // move rest of the elements backward - for( ; start + count < end; ++start ) - { - void* v = script->get_val2(st, reference_uid(id, start + count), reference_getref(data)); - set_reg(st, sd, reference_uid(id, start), name, v, reference_getref(data)); - script_removetop(st, -1, 0); + for(i = 0; i < size; i++) { + if( list[i] >= start ) // Less expensive than sorting it, most likely + script->set_reg(st, sd, reference_uid(id, list[i]), name, value, reference_getref(data)); } } - - // clear the rest of the array - if( is_string_variable(name) ) - { - for( ; start < end; ++start ) - set_reg(st, sd, reference_uid(id, start), name, (void *)"", reference_getref(data)); - } - else - { - for( ; start < end; ++start ) - set_reg(st, sd, reference_uid(id, start), name, (void*)0, reference_getref(data)); - } + return true; } @@ -5425,42 +6092,31 @@ BUILDIN(deletearray) BUILDIN(getelementofarray) { struct script_data* data; - const char* name; int32 id; - int i; - + int64 i; + data = script_getdata(st, 2); if( !data_isreference(data) ) { ShowError("script:getelementofarray: not a variable\n"); - script_reportdata(data); + script->reportdata(data); script_pushnil(st); st->state = END; return false;// not a variable } - + id = reference_getid(data); - name = reference_getname(data); - if( not_array_variable(*name) ) - { - ShowError("script:getelementofarray: illegal scope\n"); - script_reportdata(data); - script_pushnil(st); - st->state = END; - return false;// not supported - } - + i = script_getnum(st, 3); - if( i < 0 || i >= SCRIPT_MAX_ARRAYSIZE ) - { - ShowWarning("script:getelementofarray: index out of range (%d)\n", i); - script_reportdata(data); + if (i < 0 || i >= SCRIPT_MAX_ARRAYSIZE) { + ShowWarning("script:getelementofarray: index out of range (%"PRId64")\n", i); + script->reportdata(data); script_pushnil(st); st->state = END; return false;// out of range } - - script->push_val(st->stack, C_NAME, reference_uid(id, i), reference_getref(data)); + + script->push_val(st->stack, C_NAME, reference_uid(id, (unsigned int)i), reference_getref(data)); return true; } @@ -5475,16 +6131,16 @@ BUILDIN(setlook) { int type,val; TBL_PC* sd; - + type=script_getnum(st,2); val=script_getnum(st,3); - - sd = script_rid2sd(st); + + sd = script->rid2sd(st); if( sd == NULL ) return true; - + pc->changelook(sd,type,val); - + return true; } @@ -5492,16 +6148,16 @@ BUILDIN(changelook) { // As setlook but only client side int type,val; TBL_PC* sd; - + type=script_getnum(st,2); val=script_getnum(st,3); - - sd = script_rid2sd(st); + + sd = script->rid2sd(st); if( sd == NULL ) return true; - + clif->changelook(&sd->bl,type,val); - + return true; } @@ -5511,11 +6167,11 @@ BUILDIN(changelook) BUILDIN(cutin) { TBL_PC* sd; - - sd = script_rid2sd(st); + + sd = script->rid2sd(st); if( sd == NULL ) return true; - + clif->cutin(sd,script_getstr(st,2),script_getnum(st,3)); return true; } @@ -5527,104 +6183,86 @@ BUILDIN(viewpoint) { int type,x,y,id,color; TBL_PC* sd; - + type=script_getnum(st,2); x=script_getnum(st,3); y=script_getnum(st,4); id=script_getnum(st,5); color=script_getnum(st,6); - - sd = script_rid2sd(st); + + sd = script->rid2sd(st); if( sd == NULL ) return true; - + clif->viewpoint(sd,st->oid,type,x,y,id,color); - + return true; } /*========================================== * *------------------------------------------*/ -BUILDIN(countitem) -{ +BUILDIN(countitem) { int nameid, i; int count = 0; struct item_data* id = NULL; - struct script_data* data; - - TBL_PC* sd = script_rid2sd(st); - if (!sd) { - script_pushint(st,0); + + TBL_PC* sd = script->rid2sd(st); + if( !sd ) return true; + + if( script_isstringtype(st, 2) ) { + // item name + id = itemdb->search_name(script_getstr(st, 2)); + } else { + // item id + id = itemdb->exists(script_getnum(st, 2)); } - - data = script_getdata(st,2); - script->get_val(st, data); // convert into value in case of a variable - - if( data_isstring(data) ) - {// item name - id = itemdb_searchname(script->conv_str(st, data)); - } - else - {// item id - id = itemdb_exists(script->conv_num(st, data)); - } - - if( id == NULL ) - { + + if( id == NULL ) { ShowError("buildin_countitem: Invalid item '%s'.\n", script_getstr(st,2)); // returns string, regardless of what it was script_pushint(st,0); return false; } - + nameid = id->nameid; - + for(i = 0; i < MAX_INVENTORY; i++) if(sd->status.inventory[i].nameid == nameid) count += sd->status.inventory[i].amount; - + script_pushint(st,count); return true; } /*========================================== - * countitem2(nameID,Identified,Refine,Attribute,Card0,Card1,Card2,Card3) [Lupus] - * returns number of items that meet the conditions + * countitem2(nameID,Identified,Refine,Attribute,Card0,Card1,Card2,Card3) [Lupus] + * returns number of items that meet the conditions *------------------------------------------*/ -BUILDIN(countitem2) -{ +BUILDIN(countitem2) { int nameid, iden, ref, attr, c1, c2, c3, c4; int count = 0; int i; struct item_data* id = NULL; - struct script_data* data; - - TBL_PC* sd = script_rid2sd(st); - if (!sd) { - script_pushint(st,0); + + TBL_PC* sd = script->rid2sd(st); + if( !sd ) return true; + + if( script_isstringtype(st, 2) ) { + // item name + id = itemdb->search_name(script_getstr(st, 2)); + } else { + // item id + id = itemdb->exists(script_getnum(st, 2)); } - - data = script_getdata(st,2); - script->get_val(st, data); // convert into value in case of a variable - - if( data_isstring(data) ) - {// item name - id = itemdb_searchname(script->conv_str(st, data)); - } - else - {// item id - id = itemdb_exists(script->conv_num(st, data)); - } - - if( id == NULL ) - { + + if( id == NULL ) { ShowError("buildin_countitem2: Invalid item '%s'.\n", script_getstr(st,2)); // returns string, regardless of what it was script_pushint(st,0); return false; } - + nameid = id->nameid; iden = script_getnum(st,3); ref = script_getnum(st,4); @@ -5633,7 +6271,7 @@ BUILDIN(countitem2) c2 = (short)script_getnum(st,7); c3 = (short)script_getnum(st,8); c4 = (short)script_getnum(st,9); - + for(i = 0; i < MAX_INVENTORY; i++) if (sd->status.inventory[i].nameid > 0 && sd->inventory_data[i] != NULL && sd->status.inventory[i].amount > 0 && sd->status.inventory[i].nameid == nameid && @@ -5643,7 +6281,7 @@ BUILDIN(countitem2) sd->status.inventory[i].card[3] == c4 ) count += sd->status.inventory[i].amount; - + script_pushint(st,count); return true; } @@ -5652,8 +6290,8 @@ BUILDIN(countitem2) * Check if item with this amount can fit in inventory * Checking : weight, stack amount >32k, slots amount >(MAX_INVENTORY) * Return - * 0 : fail - * 1 : success (npc side only) + * 0 : fail + * 1 : success (npc side only) *------------------------------------------*/ BUILDIN(checkweight) { @@ -5661,73 +6299,76 @@ BUILDIN(checkweight) unsigned int weight=0, i, nbargs; struct item_data* id = NULL; struct map_session_data* sd; - struct script_data* data; - - if( ( sd = script_rid2sd(st) ) == NULL ){ + + if( ( sd = script->rid2sd(st) ) == NULL ) { return true; } nbargs = script_lastdata(st)+1; - if(nbargs%2){ - ShowError("buildin_checkweight: Invalid nb of args should be a multiple of 2.\n"); - script_pushint(st,0); - return false; + if(nbargs%2) { + ShowError("buildin_checkweight: Invalid nb of args should be a multiple of 2.\n"); + script_pushint(st,0); + return false; } slots = pc->inventoryblank(sd); //nb of empty slot - - for(i=2; i<nbargs; i=i+2){ - data = script_getdata(st,i); - script->get_val(st, data); // convert into value in case of a variable - if( data_isstring(data) ){// item name - id = itemdb_searchname(script->conv_str(st, data)); - } else {// item id - id = itemdb_exists(script->conv_num(st, data)); - } - if( id == NULL ) { - ShowError("buildin_checkweight: Invalid item '%s'.\n", script_getstr(st,i)); // returns string, regardless of what it was - script_pushint(st,0); - return false; - } - nameid = id->nameid; - - amount = script_getnum(st,i+1); - if( amount < 1 ) { - ShowError("buildin_checkweight: Invalid amount '%d'.\n", amount); - script_pushint(st,0); - return false; - } - - weight += itemdb_weight(nameid)*amount; //total weight for all chk - if( weight + sd->weight > sd->max_weight ) - {// too heavy - script_pushint(st,0); - return true; - } - - switch( pc->checkadditem(sd, nameid, amount) ) - { - case ADDITEM_EXIST: - // item is already in inventory, but there is still space for the requested amount - break; - case ADDITEM_NEW: - if( itemdb_isstackable(nameid) ) {// stackable - amount2++; - if( slots < amount2 ) { - script_pushint(st,0); - return true; - } - } - else {// non-stackable - amount2 += amount; - if( slots < amount2){ - script_pushint(st,0); - return true; - } - } - break; - case ADDITEM_OVERAMOUNT: - script_pushint(st,0); - return true; - } + + for( i = 2; i < nbargs; i += 2 ) { + if( script_isstringtype(st, i) ) { + // item name + id = itemdb->search_name(script_getstr(st, i)); + } else if ( script_isinttype(st, i) ) { + // item id + id = itemdb->exists(script_getnum(st, i)); + } else { + ShowError("buildin_checkweight: invalid type for argument '%d'.\n", i); + script_pushint(st,0); + return false; + } + if( id == NULL ) { + ShowError("buildin_checkweight: Invalid item '%s'.\n", script_getstr(st,i)); // returns string, regardless of what it was + script_pushint(st,0); + return false; + } + nameid = id->nameid; + + amount = script_getnum(st,i+1); + if( amount < 1 ) { + ShowError("buildin_checkweight: Invalid amount '%d'.\n", amount); + script_pushint(st,0); + return false; + } + + weight += itemdb_weight(nameid)*amount; //total weight for all chk + if( weight + sd->weight > sd->max_weight ) + {// too heavy + script_pushint(st,0); + return true; + } + + switch( pc->checkadditem(sd, nameid, amount) ) { + case ADDITEM_EXIST: + // item is already in inventory, but there is still space for the requested amount + break; + case ADDITEM_NEW: + if( itemdb->isstackable(nameid) ) { + // stackable + amount2++; + if( slots < amount2 ) { + script_pushint(st,0); + return true; + } + } else { + // non-stackable + amount2 += amount; + if( slots < amount2) { + script_pushint(st,0); + return true; + } + } + break; + case ADDITEM_OVERAMOUNT: + script_pushint(st,0); + return true; + } } script_pushint(st,1); return true; @@ -5739,7 +6380,7 @@ BUILDIN(checkweight2) int32 nameid=-1, amount=-1; int i=0, amount2=0, slots=0, weight=0; short fail=0; - + //variable for array parsing struct script_data* data_it; struct script_data* data_nb; @@ -5748,13 +6389,15 @@ BUILDIN(checkweight2) int32 id_it, id_nb; int32 idx_it, idx_nb; int nb_it, nb_nb; //array size - - TBL_PC *sd = script_rid2sd(st); - nullpo_retr(1,sd); - + + TBL_PC *sd = script->rid2sd(st); + + if( sd == NULL ) + return false; + data_it = script_getdata(st, 2); data_nb = script_getdata(st, 3); - + if( !data_isreference(data_it) || !data_isreference(data_nb)) { ShowError("script:checkweight2: parameter not a variable\n"); @@ -5767,70 +6410,64 @@ BUILDIN(checkweight2) idx_nb = reference_getindex(data_nb); name_it = reference_getname(data_it); name_nb = reference_getname(data_nb); - - if( not_array_variable(*name_it) || not_array_variable(*name_nb)) - { - ShowError("script:checkweight2: illegal scope\n"); - script_pushint(st,0); - return false;// not supported - } - if(is_string_variable(name_it) || is_string_variable(name_nb)){ + + if(is_string_variable(name_it) || is_string_variable(name_nb)) { ShowError("script:checkweight2: illegal type, need int\n"); script_pushint(st,0); return false;// not supported } - nb_it = getarraysize(st, id_it, idx_it, 0, reference_getref(data_it)); - nb_nb = getarraysize(st, id_nb, idx_nb, 0, reference_getref(data_nb)); - if(nb_it != nb_nb){ + nb_it = script->array_highest_key(st,sd,reference_getname(data_it),reference_getref(data_it)); + nb_nb = script->array_highest_key(st,sd,reference_getname(data_nb),reference_getref(data_nb)); + if(nb_it != nb_nb) { ShowError("Size mistmatch: nb_it=%d, nb_nb=%d\n",nb_it,nb_nb); fail = 1; } - + slots = pc->inventoryblank(sd); - for(i=0; i<nb_it; i++){ - nameid = (int32)__64BPTRSIZE(script->get_val2(st,reference_uid(id_it,idx_it+i),reference_getref(data_it))); - script_removetop(st, -1, 0); - amount = (int32)__64BPTRSIZE(script->get_val2(st,reference_uid(id_nb,idx_nb+i),reference_getref(data_nb))); - script_removetop(st, -1, 0); - if(fail) continue; //cpntonie to depop rest - - if(itemdb_exists(nameid) == NULL ){ + for(i=0; i<nb_it; i++) { + nameid = (int32)h64BPTRSIZE(script->get_val2(st,reference_uid(id_it,idx_it+i),reference_getref(data_it))); + script_removetop(st, -1, 0); + amount = (int32)h64BPTRSIZE(script->get_val2(st,reference_uid(id_nb,idx_nb+i),reference_getref(data_nb))); + script_removetop(st, -1, 0); + if(fail) continue; //cpntonie to depop rest + + if(itemdb->exists(nameid) == NULL ) { ShowError("buildin_checkweight2: Invalid item '%d'.\n", nameid); fail=1; continue; } - if(amount < 0 ){ + if(amount < 0 ) { ShowError("buildin_checkweight2: Invalid amount '%d'.\n", amount); fail = 1; continue; } - weight += itemdb_weight(nameid)*amount; - if( weight + sd->weight > sd->max_weight ){ + weight += itemdb_weight(nameid)*amount; + if( weight + sd->weight > sd->max_weight ) { fail = 1; continue; - } - switch( pc->checkadditem(sd, nameid, amount) ) { - case ADDITEM_EXIST: + } + switch( pc->checkadditem(sd, nameid, amount) ) { + case ADDITEM_EXIST: // item is already in inventory, but there is still space for the requested amount - break; - case ADDITEM_NEW: - if( itemdb_isstackable(nameid) ){// stackable - amount2++; - if( slots < amount2 ) - fail = 1; - } - else {// non-stackable - amount2 += amount; - if( slots < amount2 ){ - fail = 1; - } - } - break; - case ADDITEM_OVERAMOUNT: - fail = 1; - } //end switch + break; + case ADDITEM_NEW: + if( itemdb->isstackable(nameid) ) {// stackable + amount2++; + if( slots < amount2 ) + fail = 1; + } + else {// non-stackable + amount2 += amount; + if( slots < amount2 ) { + fail = 1; + } + } + break; + case ADDITEM_OVERAMOUNT: + fail = 1; + } //end switch } //end loop DO NOT break it prematurly we need to depop all stack - + fail?script_pushint(st,0):script_pushint(st,1); return true; } @@ -5838,115 +6475,128 @@ BUILDIN(checkweight2) /*========================================== * getitem <item id>,<amount>{,<account ID>}; * getitem "<item name>",<amount>{,<account ID>}; + * + * getitembound <item id>,<amount>,<type>{,<account ID>}; + * getitembound "<item id>",<amount>,<type>{,<account ID>}; *------------------------------------------*/ -BUILDIN(getitem) -{ - int nameid,amount,get_count,i,flag = 0; +BUILDIN(getitem) { + int nameid,amount,get_count,i,flag = 0, offset = 0; struct item it; TBL_PC *sd; - struct script_data *data; struct item_data *item_data; - - data=script_getdata(st,2); - script->get_val(st,data); - if( data_isstring(data) ) - {// "<item name>" - const char *name=script->conv_str(st,data); - if( (item_data = itemdb_searchname(name)) == NULL ){ - ShowError("buildin_getitem: Nonexistant item %s requested.\n", name); + + if( script_isstringtype(st, 2) ) { + // "<item name>" + const char *name = script_getstr(st, 2); + if( (item_data = itemdb->search_name(name)) == NULL ) { + ShowError("buildin_%s: Nonexistant item %s requested.\n", script->getfuncname(st), name); return false; //No item created. } nameid=item_data->nameid; - } else if( data_isint(data) ) {// <item id> - nameid=script->conv_num(st,data); + } else { + // <item id> + nameid = script_getnum(st, 2); //Violet Box, Blue Box, etc - random item pick if( nameid < 0 ) { nameid = -nameid; flag = 1; } - if( nameid <= 0 || !(item_data = itemdb_exists(nameid)) ){ - ShowError("buildin_getitem: Nonexistant item %d requested.\n", nameid); + if( nameid <= 0 || !(item_data = itemdb->exists(nameid)) ) { + ShowError("buildin_%s: Nonexistant item %d requested.\n", script->getfuncname(st), nameid); return false; //No item created. } - } else { - ShowError("buildin_getitem: invalid data type for argument #1 (%d).", data->type); - return false; } - + // <amount> if( (amount=script_getnum(st,3)) <= 0) return true; //return if amount <=0, skip the useles iteration - + memset(&it,0,sizeof(it)); it.nameid=nameid; + if(!flag) it.identify=1; else - it.identify=itemdb_isidentified2(item_data); - - if( script_hasdata(st,4) ) - sd=iMap->id2sd(script_getnum(st,4)); // <Account ID> + it.identify=itemdb->isidentified2(item_data); + + if( !strcmp(script->getfuncname(st),"getitembound") ) { + int bound = script_getnum(st,4); + if( bound < IBT_MIN || bound > IBT_MAX ) { //Not a correct bound type + ShowError("script_getitembound: Not a correct bound type! Type=%d\n",bound); + return false; + } + if( item_data->type == IT_PETEGG || item_data->type == IT_PETARMOR ) { + ShowError("script_getitembound: can't bind a pet egg/armor! Type=%d\n",bound); + return false; + } + it.bound = (unsigned char)bound; + offset += 1; + } + + if( script_hasdata(st,4+offset) ) + sd=map->id2sd(script_getnum(st,4+offset)); // <Account ID> else - sd=script_rid2sd(st); // Attached player - + sd=script->rid2sd(st); // Attached player + if( sd == NULL ) // no target return true; - + //Check if it's stackable. - if (!itemdb_isstackable(nameid)) + if (!itemdb->isstackable(nameid)) get_count = 1; else get_count = amount; - - for (i = 0; i < amount; i += get_count) - { + + for (i = 0; i < amount; i += get_count) { // if not pet egg - if (!pet_create_egg(sd, nameid)) - { - if ((flag = pc->additem(sd, &it, get_count, LOG_TYPE_SCRIPT))) - { + if (!pet->create_egg(sd, nameid)) { + if ((flag = pc->additem(sd, &it, get_count, LOG_TYPE_SCRIPT))) { clif->additem(sd, 0, 0, flag); if( pc->candrop(sd,&it) ) - iMap->addflooritem(&it,get_count,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0); + map->addflooritem(&it,get_count,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0); } } } - + return true; } /*========================================== * *------------------------------------------*/ -BUILDIN(getitem2) -{ - int nameid,amount,get_count,i,flag = 0; - int iden,ref,attr,c1,c2,c3,c4; - struct item_data *item_data; - struct item item_tmp; +BUILDIN(getitem2) { + int nameid,amount,i,flag = 0, offset = 0; + int iden,ref,attr,c1,c2,c3,c4, bound = 0; TBL_PC *sd; - struct script_data *data; - - if( script_hasdata(st,11) ) - sd=iMap->id2sd(script_getnum(st,11)); // <Account ID> + + if( !strcmp(script->getfuncname(st),"getitembound2") ) { + bound = script_getnum(st,11); + if( bound < IBT_MIN || bound > IBT_MAX ) { //Not a correct bound type + ShowError("script_getitembound2: Not a correct bound type! Type=%d\n",bound); + return false; + } + offset += 1; + } + + if( script_hasdata(st,11+offset) ) + sd=map->id2sd(script_getnum(st,11+offset)); // <Account ID> else - sd=script_rid2sd(st); // Attached player - + sd=script->rid2sd(st); // Attached player + if( sd == NULL ) // no target return true; - - data=script_getdata(st,2); - script->get_val(st,data); - if( data_isstring(data) ){ - const char *name=script->conv_str(st,data); - struct item_data *item_data = itemdb_searchname(name); + + if( script_isstringtype(st, 2) ) { + const char *name = script_getstr(st, 2); + struct item_data *item_data = itemdb->search_name(name); if( item_data ) nameid=item_data->nameid; else nameid=UNKNOWN_ITEM_ID; - }else - nameid=script->conv_num(st,data); - + } else { + nameid = script_getnum(st, 2); + } + amount=script_getnum(st,3); iden=script_getnum(st,4); ref=script_getnum(st,5); @@ -5955,18 +6605,25 @@ BUILDIN(getitem2) c2=(short)script_getnum(st,8); c3=(short)script_getnum(st,9); c4=(short)script_getnum(st,10); - + + if (bound && (itemdb_type(nameid) == IT_PETEGG || itemdb_type(nameid) == IT_PETARMOR)) { + ShowError("script_getitembound2: can't bind a pet egg/armor! Type=%d\n",bound); + return false; + } + if(nameid<0) { // Invalide nameid nameid = -nameid; flag = 1; } - + if(nameid > 0) { + struct item item_tmp; + struct item_data *item_data = itemdb->exists(nameid); + int get_count; memset(&item_tmp,0,sizeof(item_tmp)); - item_data=itemdb_exists(nameid); if (item_data == NULL) return -1; - if(item_data->type==IT_WEAPON || item_data->type==IT_ARMOR){ + if(item_data->type==IT_WEAPON || item_data->type==IT_ARMOR) { if(ref > MAX_REFINE) ref = MAX_REFINE; } else if(item_data->type==IT_PETEGG) { @@ -5977,7 +6634,7 @@ BUILDIN(getitem2) iden = 1; ref = attr = 0; } - + item_tmp.nameid=nameid; if(!flag) item_tmp.identify=iden; @@ -5985,32 +6642,30 @@ BUILDIN(getitem2) item_tmp.identify=0; item_tmp.refine=ref; item_tmp.attribute=attr; + item_tmp.bound=(unsigned char)bound; item_tmp.card[0]=(short)c1; item_tmp.card[1]=(short)c2; item_tmp.card[2]=(short)c3; item_tmp.card[3]=(short)c4; - + //Check if it's stackable. - if (!itemdb_isstackable(nameid)) + if (!itemdb->isstackable(nameid)) get_count = 1; else get_count = amount; - - for (i = 0; i < amount; i += get_count) - { + + for (i = 0; i < amount; i += get_count) { // if not pet egg - if (!pet_create_egg(sd, nameid)) - { - if ((flag = pc->additem(sd, &item_tmp, get_count, LOG_TYPE_SCRIPT))) - { + if (!pet->create_egg(sd, nameid)) { + if ((flag = pc->additem(sd, &item_tmp, get_count, LOG_TYPE_SCRIPT))) { clif->additem(sd, 0, 0, flag); if( pc->candrop(sd,&item_tmp) ) - iMap->addflooritem(&item_tmp,get_count,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0); + map->addflooritem(&item_tmp,get_count,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0); } } } } - + return true; } @@ -6018,58 +6673,45 @@ BUILDIN(getitem2) * rentitem <item id>,<seconds> * rentitem "<item name>",<seconds> *------------------------------------------*/ -BUILDIN(rentitem) -{ +BUILDIN(rentitem) { struct map_session_data *sd; - struct script_data *data; struct item it; int seconds; int nameid = 0, flag; - - data = script_getdata(st,2); - script->get_val(st,data); - - if( (sd = script_rid2sd(st)) == NULL ) + + if( (sd = script->rid2sd(st)) == NULL ) return true; - - if( data_isstring(data) ) - { - const char *name = script->conv_str(st,data); - struct item_data *itd = itemdb_searchname(name); + + if( script_isstringtype(st, 2) ) { + const char *name = script_getstr(st, 2); + struct item_data *itd = itemdb->search_name(name); if( itd == NULL ) { ShowError("buildin_rentitem: Nonexistant item %s requested.\n", name); return false; } nameid = itd->nameid; - } - else if( data_isint(data) ) - { - nameid = script->conv_num(st,data); - if( nameid <= 0 || !itemdb_exists(nameid) ) - { + } else { + nameid = script_getnum(st, 2); + if( nameid <= 0 || !itemdb->exists(nameid) ) { ShowError("buildin_rentitem: Nonexistant item %d requested.\n", nameid); return false; } } - else - { - ShowError("buildin_rentitem: invalid data type for argument #1 (%d).\n", data->type); - return false; - } - + seconds = script_getnum(st,3); memset(&it, 0, sizeof(it)); it.nameid = nameid; it.identify = 1; it.expire_time = (unsigned int)(time(NULL) + seconds); - + it.bound = 0; + if( (flag = pc->additem(sd, &it, 1, LOG_TYPE_SCRIPT)) ) { clif->additem(sd, 0, 0, flag); return false; } - + return true; } @@ -6079,53 +6721,45 @@ BUILDIN(rentitem) * Returned Qty is always 1, only works on equip-able * equipment *------------------------------------------*/ -BUILDIN(getnameditem) -{ +BUILDIN(getnameditem) { int nameid; struct item item_tmp; TBL_PC *sd, *tsd; - struct script_data *data; - - sd = script_rid2sd(st); - if (sd == NULL) - { //Player not attached! - script_pushint(st,0); + + sd = script->rid2sd(st); + if (sd == NULL) // Player not attached! return true; - } - - data=script_getdata(st,2); - script->get_val(st,data); - if( data_isstring(data) ){ - const char *name=script->conv_str(st,data); - struct item_data *item_data = itemdb_searchname(name); - if( item_data == NULL) - { //Failed + + if( script_isstringtype(st, 2) ) { + const char *name = script_getstr(st, 2); + struct item_data *item_data = itemdb->search_name(name); + if( item_data == NULL) { + //Failed script_pushint(st,0); return true; } nameid = item_data->nameid; - }else - nameid = script->conv_num(st,data); - - if(!itemdb_exists(nameid)/* || itemdb_isstackable(nameid)*/) - { //Even though named stackable items "could" be risky, they are required for certain quests. + } else { + nameid = script_getnum(st, 2); + } + + if(!itemdb->exists(nameid)/* || itemdb->isstackable(nameid)*/) { + //Even though named stackable items "could" be risky, they are required for certain quests. script_pushint(st,0); return true; } - - data=script_getdata(st,3); - script->get_val(st,data); - if( data_isstring(data) ) //Char Name - tsd=iMap->nick2sd(script->conv_str(st,data)); - else //Char Id was given - tsd=iMap->charid2sd(script->conv_num(st,data)); - - if( tsd == NULL ) - { //Failed + + if( script_isstringtype(st, 3) ) //Char Name + tsd=map->nick2sd(script_getstr(st, 3)); + else //Char Id was given + tsd=map->charid2sd(script_getnum(st, 3)); + + if( tsd == NULL ) { + //Failed script_pushint(st,0); return true; } - + memset(&item_tmp,0,sizeof(item_tmp)); item_tmp.nameid=nameid; item_tmp.amount=1; @@ -6135,9 +6769,9 @@ BUILDIN(getnameditem) item_tmp.card[3]=tsd->status.char_id >> 16; if(pc->additem(sd,&item_tmp,1,LOG_TYPE_SCRIPT)) { script_pushint(st,0); - return true; //Failed to add item, we will not drop if they don't fit + return true; //Failed to add item, we will not drop if they don't fit } - + script_pushint(st,1); return true; } @@ -6146,12 +6780,30 @@ BUILDIN(getnameditem) * gets a random item ID from an item group [Skotlex] * groupranditem group_num *------------------------------------------*/ -BUILDIN(grouprandomitem) -{ - int group; - - group = script_getnum(st,2); - script_pushint(st,itemdb_searchrandomid(group)); +BUILDIN(grouprandomitem) { + struct item_data *data; + int nameid; + + if( script_hasdata(st, 2) ) + nameid = script_getnum(st, 2); + else if ( script->current_item_id ) + nameid = script->current_item_id; + else { + ShowWarning("buildin_grouprandomitem: no item id provided and no item attached\n"); + script_pushint(st, 0); + return true; + } + + if( !(data = itemdb->exists(nameid)) ) { + ShowWarning("buildin_grouprandomitem: unknown item id %d\n",nameid); + script_pushint(st, 0); + } else if ( !data->group ) { + ShowWarning("buildin_grouprandomitem: item '%s' (%d) isn't a group!\n",data->name,nameid); + script_pushint(st, 0); + } else { + script_pushint(st, itemdb->group_item(data->group)); + } + return true; } @@ -6164,47 +6816,49 @@ BUILDIN(makeitem) int x,y,m; const char *mapname; struct item item_tmp; - struct script_data *data; struct item_data *item_data; - data=script_getdata(st,2); - script->get_val(st,data); - if( data_isstring(data) ){ - const char *name=script->conv_str(st,data); - if( (item_data = itemdb_searchname(name)) ) + if( script_isstringtype(st, 2) ) { + const char *name = script_getstr(st, 2); + if( (item_data = itemdb->search_name(name)) ) nameid=item_data->nameid; else nameid=UNKNOWN_ITEM_ID; } else { - nameid=script->conv_num(st,data); - if( nameid <= 0 || !(item_data = itemdb_exists(nameid)) ){ + nameid = script_getnum(st, 2); + if( nameid <= 0 || !(item_data = itemdb->exists(nameid)) ) { ShowError("makeitem: Nonexistant item %d requested.\n", nameid); return false; //No item created. } } - amount=script_getnum(st,3); - mapname =script_getstr(st,4); - x =script_getnum(st,5); - y =script_getnum(st,6); - - if(strcmp(mapname,"this")==0) - { + amount = script_getnum(st,3); + mapname = script_getstr(st,4); + x = script_getnum(st,5); + y = script_getnum(st,6); + + if(strcmp(mapname,"this")==0) { TBL_PC *sd; - sd = script_rid2sd(st); + sd = script->rid2sd(st); if (!sd) return true; //Failed... m=sd->bl.m; } else - m=iMap->mapname2mapid(mapname); - + m=map->mapname2mapid(mapname); + + if( m == -1 ) { + ShowError("makeitem: creating map on unexistent map '%s'!\n", mapname); + return false; + } + + memset(&item_tmp,0,sizeof(item_tmp)); item_tmp.nameid=nameid; if(!flag) item_tmp.identify=1; else - item_tmp.identify=itemdb_isidentified2(item_data); - - iMap->addflooritem(&item_tmp,amount,m,x,y,0,0,0,0); - + item_tmp.identify=itemdb->isidentified2(item_data); + + map->addflooritem(&item_tmp,amount,m,x,y,0,0,0,0); + return true; } @@ -6212,22 +6866,22 @@ BUILDIN(makeitem) /// Counts / deletes the current item given by idx. /// Used by buildin_delitem_search /// Relies on all input data being already fully valid. -static void buildin_delitem_delete(struct map_session_data* sd, int idx, int* amount, bool delete_items) +void buildin_delitem_delete(struct map_session_data* sd, int idx, int* amount, bool delete_items) { int delamount; struct item* inv = &sd->status.inventory[idx]; - + delamount = ( amount[0] < inv->amount ) ? amount[0] : inv->amount; - + if( delete_items ) { if( sd->inventory_data[idx]->type == IT_PETEGG && inv->card[0] == CARD0_PET ) {// delete associated pet - intif_delete_petdata(MakeDWord(inv->card[1], inv->card[2])); + intif->delete_petdata(MakeDWord(inv->card[1], inv->card[2])); } pc->delitem(sd, idx, delamount, 0, 0, LOG_TYPE_SCRIPT); } - + amount[0]-= delamount; } @@ -6237,15 +6891,15 @@ static void buildin_delitem_delete(struct map_session_data* sd, int idx, int* am /// Relies on all input data being already fully valid. /// @param exact_match will also match item attributes and cards, not just name id /// @return true when all items could be deleted, false when there were not enough items to delete -static bool buildin_delitem_search(struct map_session_data* sd, struct item* it, bool exact_match) +bool buildin_delitem_search(struct map_session_data* sd, struct item* it, bool exact_match) { bool delete_items = false; int i, amount, important; struct item* inv; - + // prefer always non-equipped items it->equip = 0; - + // when searching for nameid only, prefer additionally if( !exact_match ) { @@ -6254,28 +6908,28 @@ static bool buildin_delitem_search(struct map_session_data* sd, struct item* it, // card-less items memset(it->card, 0, sizeof(it->card)); } - + for(;;) { amount = it->amount; important = 0; - + // 1st pass -- less important items / exact match for( i = 0; amount && i < ARRAYLENGTH(sd->status.inventory); i++ ) { inv = &sd->status.inventory[i]; - + if( !inv->nameid || !sd->inventory_data[i] || inv->nameid != it->nameid ) {// wrong/invalid item continue; } - + if( inv->equip != it->equip || inv->refine != it->refine ) {// not matching attributes important++; continue; } - + if( exact_match ) { if( inv->identify != it->identify || inv->attribute != it->attribute || memcmp(inv->card, it->card, sizeof(inv->card)) ) @@ -6287,7 +6941,7 @@ static bool buildin_delitem_search(struct map_session_data* sd, struct item* it, { if( sd->inventory_data[i]->type == IT_PETEGG ) { - if( inv->card[0] == CARD0_PET && CheckForCharServer() ) + if( inv->card[0] == CARD0_PET && intif->CheckForCharServer() ) {// pet which cannot be deleted continue; } @@ -6298,11 +6952,11 @@ static bool buildin_delitem_search(struct map_session_data* sd, struct item* it, continue; } } - + // count / delete item - buildin_delitem_delete(sd, i, &amount, delete_items); + script->buildin_delitem_delete(sd, i, &amount, delete_items); } - + // 2nd pass -- any matching item if( amount == 0 || important == 0 ) {// either everything was already consumed or no items were skipped @@ -6311,17 +6965,17 @@ static bool buildin_delitem_search(struct map_session_data* sd, struct item* it, else for( i = 0; amount && i < ARRAYLENGTH(sd->status.inventory); i++ ) { inv = &sd->status.inventory[i]; - + if( !inv->nameid || !sd->inventory_data[i] || inv->nameid != it->nameid ) {// wrong/invalid item continue; } - - if( sd->inventory_data[i]->type == IT_PETEGG && inv->card[0] == CARD0_PET && CheckForCharServer() ) + + if( sd->inventory_data[i]->type == IT_PETEGG && inv->card[0] == CARD0_PET && intif->CheckForCharServer() ) {// pet which cannot be deleted continue; } - + if( exact_match ) { if( inv->refine != it->refine || inv->identify != it->identify || inv->attribute != it->attribute || memcmp(inv->card, it->card, sizeof(inv->card)) ) @@ -6329,11 +6983,11 @@ static bool buildin_delitem_search(struct map_session_data* sd, struct item* it, continue; } } - + // count / delete item - buildin_delitem_delete(sd, i, &amount, delete_items); + script->buildin_delitem_delete(sd, i, &amount, delete_items); } - + if( amount ) {// not enough items return false; @@ -6355,16 +7009,14 @@ static bool buildin_delitem_search(struct map_session_data* sd, struct item* it, /// /// delitem <item id>,<amount>{,<account id>} /// delitem "<item name>",<amount>{,<account id>} -BUILDIN(delitem) -{ +BUILDIN(delitem) { TBL_PC *sd; struct item it; - struct script_data *data; - + if( script_hasdata(st,4) ) { int account_id = script_getnum(st,4); - sd = iMap->id2sd(account_id); // <account id> + sd = map->id2sd(account_id); // <account id> if( sd == NULL ) { ShowError("script:delitem: player not found (AID=%d).\n", account_id); @@ -6374,46 +7026,40 @@ BUILDIN(delitem) } else { - sd = script_rid2sd(st);// attached player + sd = script->rid2sd(st);// attached player if( sd == NULL ) return true; } - - data = script_getdata(st,2); - script->get_val(st,data); - if( data_isstring(data) ) - { - const char* item_name = script->conv_str(st,data); - struct item_data* id = itemdb_searchname(item_name); - if( id == NULL ) - { + + if( script_isstringtype(st, 2) ) { + const char* item_name = script_getstr(st, 2); + struct item_data* id = itemdb->search_name(item_name); + if( id == NULL ) { ShowError("script:delitem: unknown item \"%s\".\n", item_name); st->state = END; return false; } it.nameid = id->nameid;// "<item name>" - } - else - { - it.nameid = script->conv_num(st,data);// <item id> - if( !itemdb_exists( it.nameid ) ) + } else { + it.nameid = script_getnum(st, 2);// <item id> + if( !itemdb->exists( it.nameid ) ) { ShowError("script:delitem: unknown item \"%d\".\n", it.nameid); st->state = END; return false; } } - + it.amount=script_getnum(st,3); - + if( it.amount <= 0 ) return true;// nothing to do - - if( buildin_delitem_search(sd, &it, false) ) + + if( script->buildin_delitem_search(sd, &it, false) ) {// success return true; } - + ShowError("script:delitem: failed to delete %d items (AID=%d item_id=%d).\n", it.amount, sd->status.account_id, it.nameid); st->state = END; clif->scriptclose(sd, st->oid); @@ -6424,18 +7070,14 @@ BUILDIN(delitem) /// /// delitem2 <item id>,<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>{,<account ID>} /// delitem2 "<Item name>",<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>{,<account ID>} -BUILDIN(delitem2) -{ +BUILDIN(delitem2) { TBL_PC *sd; struct item it; - struct script_data *data; - - if( script_hasdata(st,11) ) - { + + if( script_hasdata(st,11) ) { int account_id = script_getnum(st,11); - sd = iMap->id2sd(account_id); // <account id> - if( sd == NULL ) - { + sd = map->id2sd(account_id); // <account id> + if( sd == NULL ) { ShowError("script:delitem2: player not found (AID=%d).\n", account_id); st->state = END; return false; @@ -6443,36 +7085,29 @@ BUILDIN(delitem2) } else { - sd = script_rid2sd(st);// attached player + sd = script->rid2sd(st);// attached player if( sd == NULL ) return true; } - - data = script_getdata(st,2); - script->get_val(st,data); - if( data_isstring(data) ) - { - const char* item_name = script->conv_str(st,data); - struct item_data* id = itemdb_searchname(item_name); - if( id == NULL ) - { + + if( script_isstringtype(st, 2) ) { + const char* item_name = script_getstr(st, 2); + struct item_data* id = itemdb->search_name(item_name); + if( id == NULL ) { ShowError("script:delitem2: unknown item \"%s\".\n", item_name); st->state = END; return false; } it.nameid = id->nameid;// "<item name>" - } - else - { - it.nameid = script->conv_num(st,data);// <item id> - if( !itemdb_exists( it.nameid ) ) - { + } else { + it.nameid = script_getnum(st, 2);// <item id> + if( !itemdb->exists( it.nameid ) ) { ShowError("script:delitem: unknown item \"%d\".\n", it.nameid); st->state = END; return false; } } - + it.amount=script_getnum(st,3); it.identify=script_getnum(st,4); it.refine=script_getnum(st,5); @@ -6481,15 +7116,15 @@ BUILDIN(delitem2) it.card[1]=(short)script_getnum(st,8); it.card[2]=(short)script_getnum(st,9); it.card[3]=(short)script_getnum(st,10); - + if( it.amount <= 0 ) return true;// nothing to do - - if( buildin_delitem_search(sd, &it, true) ) + + if( script->buildin_delitem_search(sd, &it, true) ) {// success return true; } - + ShowError("script:delitem2: failed to delete %d items (AID=%d item_id=%d).\n", it.amount, sd->status.account_id, it.nameid); st->state = END; clif->scriptclose(sd, st->oid); @@ -6502,7 +7137,7 @@ BUILDIN(delitem2) BUILDIN(enableitemuse) { TBL_PC *sd; - sd=script_rid2sd(st); + sd=script->rid2sd(st); if (sd) st->npc_item_flag = sd->npc_item_flag = 1; return true; @@ -6511,7 +7146,7 @@ BUILDIN(enableitemuse) BUILDIN(disableitemuse) { TBL_PC *sd; - sd=script_rid2sd(st); + sd=script->rid2sd(st); if (sd) st->npc_item_flag = sd->npc_item_flag = 0; return true; @@ -6521,52 +7156,50 @@ BUILDIN(disableitemuse) * return the basic stats of sd * chk pc->readparam for available type *------------------------------------------*/ -BUILDIN(readparam) -{ +BUILDIN(readparam) { int type; TBL_PC *sd; - + type=script_getnum(st,2); if( script_hasdata(st,3) ) - sd=iMap->nick2sd(script_getstr(st,3)); + sd=map->nick2sd(script_getstr(st,3)); else - sd=script_rid2sd(st); - - if(sd==NULL){ + sd=script->rid2sd(st); + + if(sd==NULL) { script_pushint(st,-1); return true; } - + script_pushint(st,pc->readparam(sd,type)); - + return true; } /*========================================== * Return charid identification * return by @num : - * 0 : char_id - * 1 : party_id - * 2 : guild_id - * 3 : account_id - * 4 : bg_id + * 0 : char_id + * 1 : party_id + * 2 : guild_id + * 3 : account_id + * 4 : bg_id *------------------------------------------*/ -BUILDIN(getcharid) -{ +BUILDIN(getcharid) { int num; TBL_PC *sd; - + num = script_getnum(st,2); if( script_hasdata(st,3) ) - sd=iMap->nick2sd(script_getstr(st,3)); + sd=map->nick2sd(script_getstr(st,3)); else - sd=script_rid2sd(st); - - if(sd==NULL){ - script_pushint(st,0); //return 0, according docs + sd=script->rid2sd(st); + + if(sd==NULL) { + script_pushint(st,0); //return 0, according docs return true; } - + switch( num ) { case 0: script_pushint(st,sd->status.char_id); break; case 1: script_pushint(st,sd->status.party_id); break; @@ -6578,7 +7211,7 @@ BUILDIN(getcharid) script_pushint(st,0); break; } - + return true; } /*========================================== @@ -6588,17 +7221,17 @@ BUILDIN(getnpcid) { int num = script_getnum(st,2); struct npc_data* nd = NULL; - + if( script_hasdata(st,3) ) {// unique npc name - if( ( nd = npc_name2id(script_getstr(st,3)) ) == NULL ) + if( ( nd = npc->name2id(script_getstr(st,3)) ) == NULL ) { ShowError("buildin_getnpcid: No such NPC '%s'.\n", script_getstr(st,3)); script_pushint(st,0); return false; } } - + switch (num) { case 0: script_pushint(st,nd ? nd->bl.id : st->oid); @@ -6608,7 +7241,7 @@ BUILDIN(getnpcid) script_pushint(st,0); return false; } - + return true; } @@ -6620,9 +7253,9 @@ BUILDIN(getpartyname) { int party_id; struct party_data* p; - + party_id = script_getnum(st,2); - + if( ( p = party->search(party_id) ) != NULL ) { script_pushstrcopy(st,p->party.name); @@ -6638,39 +7271,39 @@ BUILDIN(getpartyname) * Get the information of the members of a party by type * @party_id, @type * return by @type : - * - : nom des membres - * 1 : char_id des membres - * 2 : account_id des membres + * - : nom des membres + * 1 : char_id des membres + * 2 : account_id des membres *------------------------------------------*/ BUILDIN(getpartymember) { struct party_data *p; int i,j=0,type=0; - + p=party->search(script_getnum(st,2)); - + if( script_hasdata(st,3) ) - type=script_getnum(st,3); - - if(p!=NULL){ - for(i=0;i<MAX_PARTY;i++){ - if(p->party.member[i].account_id){ + type=script_getnum(st,3); + + if(p!=NULL) { + for(i=0;i<MAX_PARTY;i++) { + if(p->party.member[i].account_id) { switch (type) { case 2: - mapreg_setreg(reference_uid(add_str("$@partymemberaid"), j),p->party.member[i].account_id); + mapreg->setreg(reference_uid(script->add_str("$@partymemberaid"), j),p->party.member[i].account_id); break; case 1: - mapreg_setreg(reference_uid(add_str("$@partymembercid"), j),p->party.member[i].char_id); + mapreg->setreg(reference_uid(script->add_str("$@partymembercid"), j),p->party.member[i].char_id); break; default: - mapreg_setregstr(reference_uid(add_str("$@partymembername$"), j),p->party.member[i].name); + mapreg->setregstr(reference_uid(script->add_str("$@partymembername$"), j),p->party.member[i].name); } j++; } } } - mapreg_setreg(add_str("$@partymembercount"),j); - + mapreg->setreg(script->add_str("$@partymembercount"),j); + return true; } @@ -6682,16 +7315,16 @@ BUILDIN(getpartyleader) { int party_id, type = 0, i=0; struct party_data *p; - + party_id=script_getnum(st,2); if( script_hasdata(st,3) ) - type=script_getnum(st,3); - + type=script_getnum(st,3); + p=party->search(party_id); - + if (p) //Search leader for(i = 0; i < MAX_PARTY && !p->party.member[i].leader; i++); - + if (!p || i == MAX_PARTY) { //leader not found if (type) script_pushint(st,-1); @@ -6699,7 +7332,7 @@ BUILDIN(getpartyleader) script_pushconststr(st,"null"); return true; } - + switch (type) { case 1: script_pushint(st,p->party.member[i].account_id); break; case 2: script_pushint(st,p->party.member[i].char_id); break; @@ -6719,9 +7352,9 @@ BUILDIN(getguildname) { int guild_id; struct guild* g; - + guild_id = script_getnum(st,2); - + if( ( g = guild->search(guild_id) ) != NULL ) { script_pushstrcopy(st,g->name); @@ -6741,9 +7374,9 @@ BUILDIN(getguildmaster) { int guild_id; struct guild* g; - + guild_id = script_getnum(st,2); - + if( ( g = guild->search(guild_id) ) != NULL ) { script_pushstrcopy(st,g->member[0].name); @@ -6759,9 +7392,9 @@ BUILDIN(getguildmasterid) { int guild_id; struct guild* g; - + guild_id = script_getnum(st,2); - + if( ( g = guild->search(guild_id) ) != NULL ) { script_pushint(st,g->member[0].char_id); @@ -6776,11 +7409,11 @@ BUILDIN(getguildmasterid) /*========================================== * Get char string information by type : * Return by @type : - * 0 : char_name - * 1 : party_name or "" - * 2 : guild_name or "" - * 3 : map_name - * - : "" + * 0 : char_name + * 1 : party_name or "" + * 2 : guild_name or "" + * 3 : map_name + * - : "" *------------------------------------------*/ BUILDIN(strcharinfo) { @@ -6788,14 +7421,13 @@ BUILDIN(strcharinfo) int num; struct guild* g; struct party_data* p; - - sd=script_rid2sd(st); - if (!sd) { //Avoid crashing.... - script_pushconststr(st,""); + + sd=script->rid2sd(st); + if (!sd) //Avoid crashing.... return true; - } + num=script_getnum(st,2); - switch(num){ + switch(num) { case 0: script_pushstrcopy(st,sd->status.name); break; @@ -6814,40 +7446,39 @@ BUILDIN(strcharinfo) } break; case 3: - script_pushconststr(st,map[sd->bl.m].name); + script_pushconststr(st,map->list[sd->bl.m].name); break; default: ShowWarning("buildin_strcharinfo: unknown parameter.\n"); script_pushconststr(st,""); break; } - + return true; } /*========================================== * Get npc string information by type * return by @type: - * 0 : name - * 1 : str# - * 2 : #str - * 3 : ::str - * 4 : map name + * 0 : name + * 1 : str# + * 2 : #str + * 3 : ::str + * 4 : map name *------------------------------------------*/ -BUILDIN(strnpcinfo) -{ +BUILDIN(strnpcinfo) { TBL_NPC* nd; int num; char *buf,*name=NULL; - - nd = iMap->id2nd(st->oid); + + nd = map->id2nd(st->oid); if (!nd) { script_pushconststr(st, ""); return true; } - + num = script_getnum(st,2); - switch(num){ + switch(num) { case 0: // display name name = aStrdup(nd->name); break; @@ -6867,56 +7498,53 @@ BUILDIN(strnpcinfo) name = aStrdup(nd->exname); break; case 4: // map name - name = aStrdup(map[nd->bl.m].name); + if( nd->bl.m >= 0 ) // Only valid map indexes allowed (issue:8034) + name = aStrdup(map->list[nd->bl.m].name); break; } - + if(name) script_pushstr(st, name); else script_pushconststr(st, ""); - + return true; } - -// aegis->athena slot position conversion table -static unsigned int equip[] = {EQP_HEAD_TOP,EQP_ARMOR,EQP_HAND_L,EQP_HAND_R,EQP_GARMENT,EQP_SHOES,EQP_ACC_L,EQP_ACC_R,EQP_HEAD_MID,EQP_HEAD_LOW,EQP_COSTUME_HEAD_LOW,EQP_COSTUME_HEAD_MID,EQP_COSTUME_HEAD_TOP,EQP_COSTUME_GARMENT}; - /*========================================== - * GetEquipID(Pos); Pos: 1-10 + * GetEquipID(Pos); Pos: 1-SCRIPT_EQUIP_TABLE_SIZE *------------------------------------------*/ BUILDIN(getequipid) { int i, num; TBL_PC* sd; struct item_data* item; - - sd = script_rid2sd(st); + + sd = script->rid2sd(st); if( sd == NULL ) return true; - + num = script_getnum(st,2) - 1; - if( num < 0 || num >= ARRAYLENGTH(equip) ) + if( num < 0 || num >= ARRAYLENGTH(script->equip) ) { script_pushint(st,-1); return true; } - + // get inventory position of item - i = pc->checkequip(sd,equip[num]); + i = pc->checkequip(sd,script->equip[num]); if( i < 0 ) { script_pushint(st,-1); return true; } - + item = sd->inventory_data[i]; if( item != 0 ) script_pushint(st,item->nameid); else script_pushint(st,0); - + return true; } @@ -6929,32 +7557,32 @@ BUILDIN(getequipname) int i, num; TBL_PC* sd; struct item_data* item; - - sd = script_rid2sd(st); + + sd = script->rid2sd(st); if( sd == NULL ) return true; - + num = script_getnum(st,2) - 1; - if( num < 0 || num >= ARRAYLENGTH(equip) ) + if( num < 0 || num >= ARRAYLENGTH(script->equip) ) { script_pushconststr(st,""); return true; } - + // get inventory position of item - i = pc->checkequip(sd,equip[num]); + i = pc->checkequip(sd,script->equip[num]); if( i < 0 ) { script_pushconststr(st,""); return true; } - + item = sd->inventory_data[i]; if( item != 0 ) script_pushstrcopy(st,item->jname); else script_pushconststr(st,""); - + return true; } @@ -6965,24 +7593,24 @@ BUILDIN(getbrokenid) { int i,num,id=0,brokencounter=0; TBL_PC *sd; - - sd = script_rid2sd(st); + + sd = script->rid2sd(st); if( sd == NULL ) return true; - + num=script_getnum(st,2); for(i=0; i<MAX_INVENTORY; i++) { - if(sd->status.inventory[i].attribute){ + if(sd->status.inventory[i].attribute) { brokencounter++; - if(num==brokencounter){ + if(num==brokencounter) { id=sd->status.inventory[i].nameid; break; } } } - + script_pushint(st,id); - + return true; } @@ -6994,16 +7622,16 @@ BUILDIN(repair) int i,num; int repaircounter=0; TBL_PC *sd; - - sd = script_rid2sd(st); + + sd = script->rid2sd(st); if( sd == NULL ) return true; - + num=script_getnum(st,2); for(i=0; i<MAX_INVENTORY; i++) { - if(sd->status.inventory[i].attribute){ + if(sd->status.inventory[i].attribute) { repaircounter++; - if(num==repaircounter){ + if(num==repaircounter) { sd->status.inventory[i].attribute=0; clif->equiplist(sd); clif->produce_effect(sd, 0, sd->status.inventory[i].nameid); @@ -7012,7 +7640,7 @@ BUILDIN(repair) } } } - + return true; } @@ -7023,11 +7651,11 @@ BUILDIN(repairall) { int i, repaircounter = 0; TBL_PC *sd; - - sd = script_rid2sd(st); + + sd = script->rid2sd(st); if(sd == NULL) return true; - + for(i = 0; i < MAX_INVENTORY; i++) { if(sd->status.inventory[i].nameid && sd->status.inventory[i].attribute) @@ -7037,13 +7665,13 @@ BUILDIN(repairall) repaircounter++; } } - + if(repaircounter) { clif->misceffect(&sd->bl, 3); clif->equiplist(sd); } - + return true; } @@ -7054,15 +7682,15 @@ BUILDIN(getequipisequiped) { int i = -1,num; TBL_PC *sd; - + num = script_getnum(st,2); - sd = script_rid2sd(st); + sd = script->rid2sd(st); if( sd == NULL ) return true; - - if (num > 0 && num <= ARRAYLENGTH(equip)) - i=pc->checkequip(sd,equip[num-1]); - + + if (num > 0 && num <= ARRAYLENGTH(script->equip)) + i=pc->checkequip(sd,script->equip[num-1]); + if(i >= 0) script_pushint(st,1); else @@ -7074,78 +7702,78 @@ BUILDIN(getequipisequiped) * Chk if the player have something equiped at pos * if so chk if this item ain't marked not refinable or rental * return (npc) - * 1 : true - * 0 : false + * 1 : true + * 0 : false *------------------------------------------*/ BUILDIN(getequipisenableref) { int i = -1,num; TBL_PC *sd; - + num = script_getnum(st,2); - sd = script_rid2sd(st); + sd = script->rid2sd(st); if( sd == NULL ) return true; - - if( num > 0 && num <= ARRAYLENGTH(equip) ) - i = pc->checkequip(sd,equip[num-1]); + + if( num > 0 && num <= ARRAYLENGTH(script->equip) ) + i = pc->checkequip(sd,script->equip[num-1]); if( i >= 0 && sd->inventory_data[i] && !sd->inventory_data[i]->flag.no_refine && !sd->status.inventory[i].expire_time ) script_pushint(st,1); else script_pushint(st,0); - + return true; } /*========================================== * Chk if the item equiped at pos is identify (huh ?) * return (npc) - * 1 : true - * 0 : false + * 1 : true + * 0 : false *------------------------------------------*/ BUILDIN(getequipisidentify) { int i = -1,num; TBL_PC *sd; - + num = script_getnum(st,2); - sd = script_rid2sd(st); + sd = script->rid2sd(st); if( sd == NULL ) return true; - - if (num > 0 && num <= ARRAYLENGTH(equip)) - i=pc->checkequip(sd,equip[num-1]); + + if (num > 0 && num <= ARRAYLENGTH(script->equip)) + i=pc->checkequip(sd,script->equip[num-1]); if(i >= 0) script_pushint(st,sd->status.inventory[i].identify); else script_pushint(st,0); - + return true; } /*========================================== * Get the item refined value at pos * return (npc) - * x : refine amount - * 0 : false (not refined) + * x : refine amount + * 0 : false (not refined) *------------------------------------------*/ BUILDIN(getequiprefinerycnt) { int i = -1,num; TBL_PC *sd; - + num = script_getnum(st,2); - sd = script_rid2sd(st); + sd = script->rid2sd(st); if( sd == NULL ) return true; - - if (num > 0 && num <= ARRAYLENGTH(equip)) - i=pc->checkequip(sd,equip[num-1]); + + if (num > 0 && num <= ARRAYLENGTH(script->equip)) + i=pc->checkequip(sd,script->equip[num-1]); if(i >= 0) script_pushint(st,sd->status.inventory[i].refine); else script_pushint(st,0); - + return true; } @@ -7153,96 +7781,98 @@ BUILDIN(getequiprefinerycnt) * Get the weapon level value at pos * (pos should normally only be EQI_HAND_L or EQI_HAND_R) * return (npc) - * x : weapon level - * 0 : false + * x : weapon level + * 0 : false *------------------------------------------*/ BUILDIN(getequipweaponlv) { int i = -1,num; TBL_PC *sd; - + num = script_getnum(st,2); - sd = script_rid2sd(st); + sd = script->rid2sd(st); if( sd == NULL ) return true; - - if (num > 0 && num <= ARRAYLENGTH(equip)) - i=pc->checkequip(sd,equip[num-1]); + + if (num > 0 && num <= ARRAYLENGTH(script->equip)) + i=pc->checkequip(sd,script->equip[num-1]); if(i >= 0 && sd->inventory_data[i]) script_pushint(st,sd->inventory_data[i]->wlv); else script_pushint(st,0); - + return true; } /*========================================== * Get the item refine chance (from refine.txt) for item at pos * return (npc) - * x : refine chance - * 0 : false (max refine level or unequip..) + * x : refine chance + * 0 : false (max refine level or unequip..) *------------------------------------------*/ -BUILDIN(getequippercentrefinery) -{ +BUILDIN(getequippercentrefinery) { int i = -1,num; TBL_PC *sd; - + num = script_getnum(st,2); - sd = script_rid2sd(st); + sd = script->rid2sd(st); if( sd == NULL ) return true; - - if (num > 0 && num <= ARRAYLENGTH(equip)) - i=pc->checkequip(sd,equip[num-1]); + + if (num > 0 && num <= ARRAYLENGTH(script->equip)) + i=pc->checkequip(sd,script->equip[num-1]); if(i >= 0 && sd->status.inventory[i].nameid && sd->status.inventory[i].refine < MAX_REFINE) - script_pushint(st,status_get_refine_chance(itemdb_wlv(sd->status.inventory[i].nameid), (int)sd->status.inventory[i].refine)); + script_pushint(st,status->get_refine_chance(itemdb_wlv(sd->status.inventory[i].nameid), (int)sd->status.inventory[i].refine)); else script_pushint(st,0); - + return true; } /*========================================== * Refine +1 item at pos and log and display refine *------------------------------------------*/ -BUILDIN(successrefitem) -{ - int i=-1,num,ep; +BUILDIN(successrefitem) { + int i = -1 , num, ep, up = 1; TBL_PC *sd; - + num = script_getnum(st,2); - sd = script_rid2sd(st); + sd = script->rid2sd(st); if( sd == NULL ) return true; + + if( script_hasdata(st, 3) ) + up = script_getnum(st, 3); - if (num > 0 && num <= ARRAYLENGTH(equip)) - i=pc->checkequip(sd,equip[num-1]); + if (num > 0 && num <= ARRAYLENGTH(script->equip)) + i=pc->checkequip(sd,script->equip[num-1]); if(i >= 0) { ep=sd->status.inventory[i].equip; - + //Logs items, got from (N)PC scripts [Lupus] logs->pick_pc(sd, LOG_TYPE_SCRIPT, -1, &sd->status.inventory[i],sd->inventory_data[i]); - + if (sd->status.inventory[i].refine >= MAX_REFINE) return true; - - sd->status.inventory[i].refine++; + + sd->status.inventory[i].refine += up; + sd->status.inventory[i].refine = cap_value( sd->status.inventory[i].refine, 0, MAX_REFINE); pc->unequipitem(sd,i,2); // status calc will happen in pc->equipitem() below - + clif->refine(sd->fd,0,i,sd->status.inventory[i].refine); clif->delitem(sd,i,1,3); - + //Logs items, got from (N)PC scripts [Lupus] logs->pick_pc(sd, LOG_TYPE_SCRIPT, 1, &sd->status.inventory[i],sd->inventory_data[i]); - + clif->additem(sd,i,1,0); pc->equipitem(sd,i,ep); clif->misceffect(&sd->bl,3); if(sd->status.inventory[i].refine == 10 && sd->status.inventory[i].card[0] == CARD0_FORGE && sd->status.char_id == (int)MakeDWord(sd->status.inventory[i].card[2],sd->status.inventory[i].card[3]) - ){ // Fame point system [DracoRPG] - switch (sd->inventory_data[i]->wlv){ + ) { // Fame point system [DracoRPG] + switch (sd->inventory_data[i]->wlv) { case 1: pc->addfame(sd,1); // Success to refine to +10 a lv1 weapon you forged = +1 fame point break; @@ -7255,7 +7885,7 @@ BUILDIN(successrefitem) } } } - + return true; } @@ -7266,24 +7896,24 @@ BUILDIN(failedrefitem) { int i=-1,num; TBL_PC *sd; - + num = script_getnum(st,2); - sd = script_rid2sd(st); + sd = script->rid2sd(st); if( sd == NULL ) return true; - - if (num > 0 && num <= ARRAYLENGTH(equip)) - i=pc->checkequip(sd,equip[num-1]); + + if (num > 0 && num <= ARRAYLENGTH(script->equip)) + i=pc->checkequip(sd,script->equip[num-1]); if(i >= 0) { sd->status.inventory[i].refine = 0; pc->unequipitem(sd,i,3); //recalculate bonus clif->refine(sd->fd,1,i,sd->status.inventory[i].refine); //notify client of failure - + pc->delitem(sd,i,1,0,2,LOG_TYPE_SCRIPT); - - clif->misceffect(&sd->bl,2); // display failure effect + + clif->misceffect(&sd->bl,2); // display failure effect } - + return true; } @@ -7292,36 +7922,39 @@ BUILDIN(failedrefitem) *------------------------------------------*/ BUILDIN(downrefitem) { - int i = -1,num,ep; + int i = -1,num,ep, down = 1; TBL_PC *sd; - - num = script_getnum(st,2); - sd = script_rid2sd(st); + + sd = script->rid2sd(st); if( sd == NULL ) return true; - - if (num > 0 && num <= ARRAYLENGTH(equip)) - i = pc->checkequip(sd,equip[num-1]); + num = script_getnum(st,2); + if( script_hasdata(st, 3) ) + down = script_getnum(st, 3); + + if (num > 0 && num <= ARRAYLENGTH(script->equip)) + i = pc->checkequip(sd,script->equip[num-1]); if(i >= 0) { ep = sd->status.inventory[i].equip; - + //Logs items, got from (N)PC scripts [Lupus] logs->pick_pc(sd, LOG_TYPE_SCRIPT, -1, &sd->status.inventory[i],sd->inventory_data[i]); - - sd->status.inventory[i].refine++; + pc->unequipitem(sd,i,2); // status calc will happen in pc->equipitem() below - - clif->refine(sd->fd,2,i,sd->status.inventory[i].refine = sd->status.inventory[i].refine - 2); + sd->status.inventory[i].refine -= down; + sd->status.inventory[i].refine = cap_value( sd->status.inventory[i].refine, 0, MAX_REFINE); + + clif->refine(sd->fd,2,i,sd->status.inventory[i].refine); clif->delitem(sd,i,1,3); - + //Logs items, got from (N)PC scripts [Lupus] logs->pick_pc(sd, LOG_TYPE_SCRIPT, 1, &sd->status.inventory[i],sd->inventory_data[i]); - + clif->additem(sd,i,1,0); pc->equipitem(sd,i,ep); clif->misceffect(&sd->bl,2); } - + return true; } @@ -7332,37 +7965,39 @@ BUILDIN(delequip) { int i=-1,num; TBL_PC *sd; - + num = script_getnum(st,2); - sd = script_rid2sd(st); + sd = script->rid2sd(st); if( sd == NULL ) return true; - - if (num > 0 && num <= ARRAYLENGTH(equip)) - i=pc->checkequip(sd,equip[num-1]); + + if (num > 0 && num <= ARRAYLENGTH(script->equip)) + i=pc->checkequip(sd,script->equip[num-1]); if(i >= 0) { pc->unequipitem(sd,i,3); //recalculate bonus pc->delitem(sd,i,1,0,2,LOG_TYPE_SCRIPT); + script_pushint(st,1); + } else { + script_pushint(st,0); } - + return true; } /*========================================== * *------------------------------------------*/ -BUILDIN(statusup) -{ +BUILDIN(statusup) { int type; TBL_PC *sd; - + type=script_getnum(st,2); - sd = script_rid2sd(st); + sd = script->rid2sd(st); if( sd == NULL ) return true; - - pc->statusup(sd,type); - + + pc->statusup(sd, type, 1); + return true; } /*========================================== @@ -7372,15 +8007,15 @@ BUILDIN(statusup2) { int type,val; TBL_PC *sd; - + type=script_getnum(st,2); val=script_getnum(st,3); - sd = script_rid2sd(st); + sd = script->rid2sd(st); if( sd == NULL ) return true; - + pc->statusup2(sd,type,val); - + return true; } @@ -7391,8 +8026,7 @@ BUILDIN(statusup2) /// bonus3 <bonus type>,<val1>,<val2>,<val3>; /// bonus4 <bonus type>,<val1>,<val2>,<val3>,<val4>; /// bonus5 <bonus type>,<val1>,<val2>,<val3>,<val4>,<val5>; -BUILDIN(bonus) -{ +BUILDIN(bonus) { int type; int val1; int val2 = 0; @@ -7400,11 +8034,11 @@ BUILDIN(bonus) int val4 = 0; int val5 = 0; TBL_PC* sd; - - sd = script_rid2sd(st); + + sd = script->rid2sd(st); if( sd == NULL ) return true; // no player attached - + type = script_getnum(st,2); switch( type ) { case SP_AUTOSPELL: @@ -7424,13 +8058,16 @@ BUILDIN(bonus) case SP_FIXCASTRATE: case SP_SKILL_USE_SP: // these bonuses support skill names - val1 = ( script_isstring(st,3) ? skill->name2id(script_getstr(st,3)) : script_getnum(st,3) ); - break; + if (script_isstringtype(st, 3)) { + val1 = skill->name2id(script_getstr(st, 3)); + break; + } + // else fall through default: val1 = script_getnum(st,3); break; } - + switch( script_lastdata(st)-2 ) { case 1: pc->bonus(sd, type, val1); @@ -7445,21 +8082,21 @@ BUILDIN(bonus) pc->bonus3(sd, type, val1, val2, val3); break; case 4: - if( type == SP_AUTOSPELL_ONSKILL && script_isstring(st,4) ) + if( type == SP_AUTOSPELL_ONSKILL && script_isstringtype(st,4) ) val2 = skill->name2id(script_getstr(st,4)); // 2nd value can be skill name else val2 = script_getnum(st,4); - + val3 = script_getnum(st,5); val4 = script_getnum(st,6); pc->bonus4(sd, type, val1, val2, val3, val4); break; case 5: - if( type == SP_AUTOSPELL_ONSKILL && script_isstring(st,4) ) + if( type == SP_AUTOSPELL_ONSKILL && script_isstringtype(st,4) ) val2 = skill->name2id(script_getstr(st,4)); // 2nd value can be skill name else val2 = script_getnum(st,4); - + val3 = script_getnum(st,5); val4 = script_getnum(st,6); val5 = script_getnum(st,7); @@ -7469,116 +8106,113 @@ BUILDIN(bonus) ShowDebug("buildin_bonus: unexpected number of arguments (%d)\n", (script_lastdata(st) - 1)); break; } - + return true; } -BUILDIN(autobonus) -{ +BUILDIN(autobonus) { unsigned int dur; short rate; short atk_type = 0; TBL_PC* sd; const char *bonus_script, *other_script = NULL; - - sd = script_rid2sd(st); + + sd = script->rid2sd(st); if( sd == NULL ) return true; // no player attached - - if( sd->state.autobonus&sd->status.inventory[current_equip_item_index].equip ) + + if( sd->state.autobonus&sd->status.inventory[status->current_equip_item_index].equip ) return true; - + rate = script_getnum(st,3); dur = script_getnum(st,4); bonus_script = script_getstr(st,2); if( !rate || !dur || !bonus_script ) return true; - + if( script_hasdata(st,5) ) atk_type = script_getnum(st,5); if( script_hasdata(st,6) ) other_script = script_getstr(st,6); - - if( pc->addautobonus(sd->autobonus,ARRAYLENGTH(sd->autobonus), - bonus_script,rate,dur,atk_type,other_script,sd->status.inventory[current_equip_item_index].equip,false) ) - { - script_add_autobonus(bonus_script); + + if( pc->addautobonus(sd->autobonus,ARRAYLENGTH(sd->autobonus),bonus_script,rate,dur,atk_type,other_script, + sd->status.inventory[status->current_equip_item_index].equip,false) + ) { + script->add_autobonus(bonus_script); if( other_script ) - script_add_autobonus(other_script); + script->add_autobonus(other_script); } - + return true; } -BUILDIN(autobonus2) -{ +BUILDIN(autobonus2) { unsigned int dur; short rate; short atk_type = 0; TBL_PC* sd; const char *bonus_script, *other_script = NULL; - - sd = script_rid2sd(st); + + sd = script->rid2sd(st); if( sd == NULL ) return true; // no player attached - - if( sd->state.autobonus&sd->status.inventory[current_equip_item_index].equip ) + + if( sd->state.autobonus&sd->status.inventory[status->current_equip_item_index].equip ) return true; - + rate = script_getnum(st,3); dur = script_getnum(st,4); bonus_script = script_getstr(st,2); if( !rate || !dur || !bonus_script ) return true; - + if( script_hasdata(st,5) ) atk_type = script_getnum(st,5); if( script_hasdata(st,6) ) other_script = script_getstr(st,6); - - if( pc->addautobonus(sd->autobonus2,ARRAYLENGTH(sd->autobonus2), - bonus_script,rate,dur,atk_type,other_script,sd->status.inventory[current_equip_item_index].equip,false) ) - { - script_add_autobonus(bonus_script); + + if( pc->addautobonus(sd->autobonus2,ARRAYLENGTH(sd->autobonus2),bonus_script,rate,dur,atk_type,other_script, + sd->status.inventory[status->current_equip_item_index].equip,false) + ) { + script->add_autobonus(bonus_script); if( other_script ) - script_add_autobonus(other_script); + script->add_autobonus(other_script); } - + return true; } -BUILDIN(autobonus3) -{ +BUILDIN(autobonus3) { unsigned int dur; short rate,atk_type; TBL_PC* sd; const char *bonus_script, *other_script = NULL; - - sd = script_rid2sd(st); + + sd = script->rid2sd(st); if( sd == NULL ) return true; // no player attached - - if( sd->state.autobonus&sd->status.inventory[current_equip_item_index].equip ) + + if( sd->state.autobonus&sd->status.inventory[status->current_equip_item_index].equip ) return true; - + rate = script_getnum(st,3); dur = script_getnum(st,4); - atk_type = ( script_isstring(st,5) ? skill->name2id(script_getstr(st,5)) : script_getnum(st,5) ); + atk_type = ( script_isstringtype(st,5) ? skill->name2id(script_getstr(st,5)) : script_getnum(st,5) ); bonus_script = script_getstr(st,2); if( !rate || !dur || !atk_type || !bonus_script ) return true; - + if( script_hasdata(st,6) ) other_script = script_getstr(st,6); - - if( pc->addautobonus(sd->autobonus3,ARRAYLENGTH(sd->autobonus3), - bonus_script,rate,dur,atk_type,other_script,sd->status.inventory[current_equip_item_index].equip,true) ) - { - script_add_autobonus(bonus_script); + + if( pc->addautobonus(sd->autobonus3,ARRAYLENGTH(sd->autobonus3),bonus_script,rate,dur,atk_type,other_script, + sd->status.inventory[status->current_equip_item_index].equip,true) + ) { + script->add_autobonus(bonus_script); if( other_script ) - script_add_autobonus(other_script); + script->add_autobonus(other_script); } - + return true; } @@ -7592,23 +8226,22 @@ BUILDIN(autobonus3) /// skill <skill id>,<level> /// skill "<skill name>",<level>,<flag> /// skill "<skill name>",<level> -BUILDIN(skill) -{ +BUILDIN(skill) { int id; int level; int flag = 1; TBL_PC* sd; - - sd = script_rid2sd(st); + + sd = script->rid2sd(st); if( sd == NULL ) return true;// no player attached, report source - - id = ( script_isstring(st,2) ? skill->name2id(script_getstr(st,2)) : script_getnum(st,2) ); + + id = ( script_isstringtype(st,2) ? skill->name2id(script_getstr(st,2)) : script_getnum(st,2) ); level = script_getnum(st,3); if( script_hasdata(st,4) ) flag = script_getnum(st,4); pc->skill(sd, id, level, flag); - + return true; } @@ -7621,23 +8254,22 @@ BUILDIN(skill) /// addtoskill "<skill name>",<amount> /// /// @see skill -BUILDIN(addtoskill) -{ +BUILDIN(addtoskill) { int id; int level; int flag = 2; TBL_PC* sd; - - sd = script_rid2sd(st); + + sd = script->rid2sd(st); if( sd == NULL ) return true;// no player attached, report source - - id = ( script_isstring(st,2) ? skill->name2id(script_getstr(st,2)) : script_getnum(st,2) ); + + id = ( script_isstringtype(st,2) ? skill->name2id(script_getstr(st,2)) : script_getnum(st,2) ); level = script_getnum(st,3); if( script_hasdata(st,4) ) flag = script_getnum(st,4); pc->skill(sd, id, level, flag); - + return true; } @@ -7645,22 +8277,37 @@ BUILDIN(addtoskill) /// /// guildskill <skill id>,<amount>; /// guildskill "<skill name>",<amount>; -BUILDIN(guildskill) -{ - int id; +BUILDIN(guildskill) { + int skill_id, id, max_points; int level; + TBL_PC* sd; - int i; - - sd = script_rid2sd(st); + struct guild *gd; + struct guild_skill gd_skill; + + sd = script->rid2sd(st); if( sd == NULL ) - return true;// no player attached, report source - - id = ( script_isstring(st,2) ? skill->name2id(script_getstr(st,2)) : script_getnum(st,2) ); + return false; // no player attached, report source + + if( (gd = sd->guild) == NULL ) + return true; + + skill_id = ( script_isstringtype(st,2) ? skill->name2id(script_getstr(st,2)) : script_getnum(st,2) ); level = script_getnum(st,3); - for( i=0; i < level; i++ ) - guild->skillup(sd, id); - + + id = skill_id - GD_SKILLBASE; + max_points = guild->skill_get_max(skill_id); + + if( (gd->skill[id].lv + level) > max_points ) + level = max_points - gd->skill[id].lv; + + if( level <= 0 ) + return true; + + memcpy(&gd_skill, &(gd->skill[id]), sizeof(gd->skill[id])); + gd_skill.lv += level; + + intif->guild_change_basicinfo( gd->guild_id, GBI_SKILLLV, &(gd_skill), sizeof(gd_skill) ); return true; } @@ -7668,18 +8315,17 @@ BUILDIN(guildskill) /// /// getskilllv(<skill id>) -> <level> /// getskilllv("<skill name>") -> <level> -BUILDIN(getskilllv) -{ +BUILDIN(getskilllv) { int id; TBL_PC* sd; - - sd = script_rid2sd(st); + + sd = script->rid2sd(st); if( sd == NULL ) return true;// no player attached, report source - - id = ( script_isstring(st,2) ? skill->name2id(script_getstr(st,2)) : script_getnum(st,2) ); + + id = ( script_isstringtype(st,2) ? skill->name2id(script_getstr(st,2)) : script_getnum(st,2) ); script_pushint(st, pc->checkskill(sd,id)); - + return true; } @@ -7687,20 +8333,19 @@ BUILDIN(getskilllv) /// /// getgdskilllv(<guild id>,<skill id>) -> <level> /// getgdskilllv(<guild id>,"<skill name>") -> <level> -BUILDIN(getgdskilllv) -{ +BUILDIN(getgdskilllv) { int guild_id; uint16 skill_id; struct guild* g; - + guild_id = script_getnum(st,2); - skill_id = ( script_isstring(st,3) ? skill->name2id(script_getstr(st,3)) : script_getnum(st,3) ); + skill_id = ( script_isstringtype(st,3) ? skill->name2id(script_getstr(st,3)) : script_getnum(st,3) ); g = guild->search(guild_id); if( g == NULL ) script_pushint(st, -1); else script_pushint(st, guild->checkskill(g,skill_id)); - + return true; } @@ -7721,13 +8366,13 @@ BUILDIN(basicskillcheck) BUILDIN(getgmlevel) { TBL_PC* sd; - - sd = script_rid2sd(st); + + sd = script->rid2sd(st); if( sd == NULL ) return true;// no player attached, report source - - script_pushint(st, pc->get_group_level(sd)); - + + script_pushint(st, pc_get_group_level(sd)); + return true; } @@ -7737,12 +8382,12 @@ BUILDIN(getgmlevel) BUILDIN(getgroupid) { TBL_PC* sd; - - sd = script_rid2sd(st); + + sd = script->rid2sd(st); if (sd == NULL) return false; // no player attached, report source script_pushint(st, pc_get_group_id(sd)); - + return true; } @@ -7751,6 +8396,18 @@ BUILDIN(getgroupid) /// end BUILDIN(end) { st->state = END; + + /* are we stopping inside a function? */ + if( st->stack->defsp >= 1 && st->stack->stack_data[st->stack->defsp-1].type == C_RETINFO ) { + int i; + for(i = 0; i < st->stack->sp; i++) { + if( st->stack->stack_data[i].type == C_RETINFO ) {/* grab the first, aka the original */ + struct script_retinfo *ri = st->stack->stack_data[i].u.ri; + st->script = ri->script; + break; + } + } + } return true; } @@ -7761,17 +8418,17 @@ BUILDIN(checkoption) { int option; TBL_PC* sd; - - sd = script_rid2sd(st); + + sd = script->rid2sd(st); if( sd == NULL ) return true;// no player attached, report source - + option = script_getnum(st,2); if( sd->sc.option&option ) script_pushint(st, 1); else script_pushint(st, 0); - + return true; } @@ -7782,17 +8439,17 @@ BUILDIN(checkoption1) { int opt1; TBL_PC* sd; - - sd = script_rid2sd(st); + + sd = script->rid2sd(st); if( sd == NULL ) return true;// no player attached, report source - + opt1 = script_getnum(st,2); if( sd->sc.opt1 == opt1 ) script_pushint(st, 1); else script_pushint(st, 0); - + return true; } @@ -7803,17 +8460,17 @@ BUILDIN(checkoption2) { int opt2; TBL_PC* sd; - - sd = script_rid2sd(st); + + sd = script->rid2sd(st); if( sd == NULL ) return true;// no player attached, report source - + opt2 = script_getnum(st,2); if( sd->sc.opt2&opt2 ) script_pushint(st, 1); else script_pushint(st, 0); - + return true; } @@ -7829,28 +8486,28 @@ BUILDIN(setoption) int option; int flag = 1; TBL_PC* sd; - - sd = script_rid2sd(st); + + sd = script->rid2sd(st); if( sd == NULL ) return true;// no player attached, report source - + option = script_getnum(st,2); if( script_hasdata(st,3) ) flag = script_getnum(st,3); - else if( !option ){// Request to remove everything. + else if( !option ) {// Request to remove everything. flag = 0; option = OPTION_FALCON|OPTION_RIDING; #ifndef NEW_CARTS option |= OPTION_CART; #endif } - if( flag ){// Add option + if( flag ) {// Add option if( option&OPTION_WEDDING && !battle_config.wedding_modifydisplay ) option &= ~OPTION_WEDDING;// Do not show the wedding sprites pc->setoption(sd, sd->sc.option|option); } else// Remove option pc->setoption(sd, sd->sc.option&~option); - + return true; } @@ -7862,16 +8519,16 @@ BUILDIN(setoption) BUILDIN(checkcart) { TBL_PC* sd; - - sd = script_rid2sd(st); + + sd = script->rid2sd(st); if( sd == NULL ) return true;// no player attached, report source - + if( pc_iscarton(sd) ) script_pushint(st, 1); else script_pushint(st, 0); - + return true; } @@ -7890,15 +8547,15 @@ BUILDIN(setcart) { int type = 1; TBL_PC* sd; - - sd = script_rid2sd(st); + + sd = script->rid2sd(st); if( sd == NULL ) return true;// no player attached, report source - + if( script_hasdata(st,2) ) type = script_getnum(st,2); pc->setcart(sd, type); - + return true; } @@ -7910,16 +8567,16 @@ BUILDIN(setcart) BUILDIN(checkfalcon) { TBL_PC* sd; - - sd = script_rid2sd(st); + + sd = script->rid2sd(st); if( sd == NULL ) return true;// no player attached, report source - + if( pc_isfalcon(sd) ) script_pushint(st, 1); else script_pushint(st, 0); - + return true; } @@ -7932,16 +8589,16 @@ BUILDIN(setfalcon) { int flag = 1; TBL_PC* sd; - - sd = script_rid2sd(st); + + sd = script->rid2sd(st); if( sd == NULL ) return true;// no player attached, report source - + if( script_hasdata(st,2) ) flag = script_getnum(st,2); - + pc->setfalcon(sd, flag); - + return true; } @@ -7953,16 +8610,16 @@ BUILDIN(setfalcon) BUILDIN(checkriding) { TBL_PC* sd; - - sd = script_rid2sd(st); + + sd = script->rid2sd(st); if( sd == NULL ) return true;// no player attached, report source - + if( pc_isriding(sd) || pc_isridingwug(sd) || pc_isridingdragon(sd) ) script_pushint(st, 1); else script_pushint(st, 0); - + return true; } @@ -7975,15 +8632,15 @@ BUILDIN(setriding) { int flag = 1; TBL_PC* sd; - - sd = script_rid2sd(st); + + sd = script->rid2sd(st); if( sd == NULL ) return true;// no player attached, report source - + if( script_hasdata(st,2) ) flag = script_getnum(st,2); pc->setriding(sd, flag); - + return true; } @@ -7994,16 +8651,16 @@ BUILDIN(setriding) BUILDIN(checkwug) { TBL_PC* sd; - - sd = script_rid2sd(st); + + sd = script->rid2sd(st); if( sd == NULL ) return true;// no player attached, report source - + if( pc_iswug(sd) || pc_isridingwug(sd) ) script_pushint(st, 1); else script_pushint(st, 0); - + return true; } @@ -8014,16 +8671,16 @@ BUILDIN(checkwug) BUILDIN(checkmadogear) { TBL_PC* sd; - - sd = script_rid2sd(st); + + sd = script->rid2sd(st); if( sd == NULL ) return true;// no player attached, report source - + if( pc_ismadogear(sd) ) script_pushint(st, 1); else script_pushint(st, 0); - + return true; } @@ -8036,15 +8693,15 @@ BUILDIN(setmadogear) { int flag = 1; TBL_PC* sd; - - sd = script_rid2sd(st); + + sd = script->rid2sd(st); if( sd == NULL ) return true;// no player attached, report source - + if( script_hasdata(st,2) ) flag = script_getnum(st,2); pc->setmadogear(sd, flag); - + return true; } @@ -8052,40 +8709,38 @@ BUILDIN(setmadogear) /// /// save "<map name>",<x>,<y> /// savepoint "<map name>",<x>,<y> -BUILDIN(savepoint) -{ +BUILDIN(savepoint) { int x; int y; - short map; + short mapid; const char* str; TBL_PC* sd; - - sd = script_rid2sd(st); + + sd = script->rid2sd(st); if( sd == NULL ) - return true;// no player attached, report source - - str = script_getstr(st, 2); - x = script_getnum(st,3); - y = script_getnum(st,4); - map = mapindex_name2id(str); - if( map ) - pc->setsavepoint(sd, map, x, y); - + return false;// no player attached, report source + + str = script_getstr(st,2); + x = script_getnum(st,3); + y = script_getnum(st,4); + mapid = script->mapindexname2id(st,str); + if( mapid ) + pc->setsavepoint(sd, mapid, x, y); + return true; } /*========================================== * GetTimeTick(0: System Tick, 1: Time Second Tick) *------------------------------------------*/ -BUILDIN(gettimetick) /* Asgard Version */ -{ +BUILDIN(gettimetick) { /* Asgard Version */ int type; - time_t timer; + time_t clock; struct tm *t; - + type=script_getnum(st,2); - - switch(type){ + + switch(type) { case 2: //type 2:(Get the number of seconds elapsed since 00:00 hours, Jan 1, 1970 UTC // from the system clock.) @@ -8093,37 +8748,35 @@ BUILDIN(gettimetick) /* Asgard Version */ break; case 1: //type 1:(Second Ticks: 0-86399, 00:00:00-23:59:59) - time(&timer); - t=localtime(&timer); + time(&clock); + t=localtime(&clock); script_pushint(st,((t->tm_hour)*3600+(t->tm_min)*60+t->tm_sec)); break; case 0: default: //type 0:(System Ticks) - script_pushint(st,iTimer->gettick()); + script_pushint(st,(int)timer->gettick()); // TODO: change this to int64 when we'll support 64 bit script values break; } return true; } - /*========================================== * GetTime(Type); * 1: Sec 2: Min 3: Hour * 4: WeekDay 5: MonthDay 6: Month * 7: Year *------------------------------------------*/ -BUILDIN(gettime) /* Asgard Version */ -{ +BUILDIN(gettime) { /* Asgard Version */ int type; - time_t timer; + time_t clock; struct tm *t; - + type=script_getnum(st,2); - - time(&timer); - t=localtime(&timer); - - switch(type){ + + time(&clock); + t=localtime(&clock); + + switch(type) { case 1://Sec(0~59) script_pushint(st,t->tm_sec); break; @@ -8164,14 +8817,14 @@ BUILDIN(gettimestr) const char *fmtstr; int maxlen; time_t now = time(NULL); - + fmtstr=script_getstr(st,2); maxlen=script_getnum(st,3); - + tmpstr=(char *)aMalloc((maxlen+1)*sizeof(char)); strftime(tmpstr,maxlen,fmtstr,localtime(&now)); tmpstr[maxlen]='\0'; - + script_pushstr(st,tmpstr); return true; } @@ -8179,28 +8832,26 @@ BUILDIN(gettimestr) /*========================================== * Open player storage *------------------------------------------*/ -BUILDIN(openstorage) -{ +BUILDIN(openstorage) { TBL_PC* sd; - - sd = script_rid2sd(st); + + sd = script->rid2sd(st); if( sd == NULL ) return true; - - storage_storageopen(sd); + + storage->open(sd); return true; } -BUILDIN(guildopenstorage) -{ +BUILDIN(guildopenstorage) { TBL_PC* sd; int ret; - - sd = script_rid2sd(st); + + sd = script->rid2sd(st); if( sd == NULL ) return true; - - ret = storage_guild_storageopen(sd); + + ret = gstorage->open(sd); script_pushint(st,ret); return true; } @@ -8214,12 +8865,12 @@ BUILDIN(itemskill) { int id; int lv; TBL_PC* sd; - - sd = script_rid2sd(st); + + sd = script->rid2sd(st); if( sd == NULL || sd->ud.skilltimer != INVALID_TIMER ) return true; - - id = ( script_isstring(st,2) ? skill->name2id(script_getstr(st,2)) : script_getnum(st,2) ); + + id = ( script_isstringtype(st,2) ? skill->name2id(script_getstr(st,2)) : script_getnum(st,2) ); lv = script_getnum(st,3); /* temporarily disabled, awaiting for kenpachi to detail this so we can make it work properly */ #if 0 @@ -8240,11 +8891,11 @@ BUILDIN(produce) { int trigger; TBL_PC* sd; - - sd = script_rid2sd(st); + + sd = script->rid2sd(st); if( sd == NULL ) return true; - + trigger=script_getnum(st,2); clif->skill_produce_mix_list(sd, -1, trigger); return true; @@ -8256,11 +8907,11 @@ BUILDIN(cooking) { int trigger; TBL_PC* sd; - - sd = script_rid2sd(st); + + sd = script->rid2sd(st); if( sd == NULL ) return true; - + trigger=script_getnum(st,2); clif->cooking_list(sd, trigger, AM_PHARMACY, 1, 1); return true; @@ -8272,25 +8923,24 @@ BUILDIN(makepet) { TBL_PC* sd; int id,pet_id; - + id=script_getnum(st,2); - sd = script_rid2sd(st); + sd = script->rid2sd(st); if( sd == NULL ) return true; - - pet_id = search_petDB_index(id, PET_CLASS); - + + pet_id = pet->search_petDB_index(id, PET_CLASS); + if (pet_id < 0) - pet_id = search_petDB_index(id, PET_EGG); + pet_id = pet->search_petDB_index(id, PET_EGG); if (pet_id >= 0 && sd) { - sd->catch_target_class = pet_db[pet_id].class_; - intif_create_pet( - sd->status.account_id, sd->status.char_id, - (short)pet_db[pet_id].class_, (short)mob_db(pet_db[pet_id].class_)->lv, - (short)pet_db[pet_id].EggID, 0, (short)pet_db[pet_id].intimate, - 100, 0, 1, pet_db[pet_id].jname); + sd->catch_target_class = pet->db[pet_id].class_; + intif->create_pet(sd->status.account_id, sd->status.char_id, + (short)pet->db[pet_id].class_, (short)mob->db(pet->db[pet_id].class_)->lv, + (short)pet->db[pet_id].EggID, 0, (short)pet->db[pet_id].intimate, + 100, 0, 1, pet->db[pet_id].jname); } - + return true; } /*========================================== @@ -8301,23 +8951,23 @@ BUILDIN(getexp) TBL_PC* sd; int base=0,job=0; double bonus; - - sd = script_rid2sd(st); + + sd = script->rid2sd(st); if( sd == NULL ) return true; - + base=script_getnum(st,2); job =script_getnum(st,3); if(base<0 || job<0) return true; - + // bonus for npc-given exp bonus = battle_config.quest_exp_rate / 100.; base = (int) cap_value(base * bonus, 0, INT_MAX); job = (int) cap_value(job * bonus, 0, INT_MAX); - - pc->gainexp(sd, NULL, base, job, true); - + + pc->gainexp(sd, &sd->bl, base, job, true); + return true; } @@ -8328,71 +8978,70 @@ BUILDIN(guildgetexp) { TBL_PC* sd; int exp; - - sd = script_rid2sd(st); + + sd = script->rid2sd(st); if( sd == NULL ) return true; - + exp = script_getnum(st,2); if(exp < 0) return true; if(sd && sd->status.guild_id > 0) guild->getexp (sd, exp); - + return true; } /*========================================== * Changes the guild master of a guild [Skotlex] *------------------------------------------*/ -BUILDIN(guildchangegm) -{ +BUILDIN(guildchangegm) { TBL_PC *sd; int guild_id; const char *name; - + guild_id = script_getnum(st,2); name = script_getstr(st,3); - sd=iMap->nick2sd(name); - + sd=map->nick2sd(name); + if (!sd) script_pushint(st,0); else script_pushint(st,guild->gm_change(guild_id, sd)); - + return true; } /*========================================== * Spawn a monster : - @mapn,x,y : location - @str : monster name - @class_ : mob_id - @amount : nb to spawn - @event : event to attach to mob + * @mapn,x,y : location + * @str : monster name + * @class_ : mob_id + * @amount : nb to spawn + * @event : event to attach to mob *------------------------------------------*/ BUILDIN(monster) { - const char* mapn = script_getstr(st,2); - int x = script_getnum(st,3); - int y = script_getnum(st,4); - const char* str = script_getstr(st,5); - int class_ = script_getnum(st,6); - int amount = script_getnum(st,7); - const char* event = ""; - unsigned int size = SZ_SMALL; - unsigned int ai = AI_NONE; + const char *mapn = script_getstr(st,2); + int x = script_getnum(st,3); + int y = script_getnum(st,4); + const char *str = script_getstr(st,5); + int class_ = script_getnum(st,6); + int amount = script_getnum(st,7); + const char *event = ""; + unsigned int size = SZ_MEDIUM; + unsigned int ai = AI_NONE; int mob_id; - + struct map_session_data* sd; int16 m; - + if (script_hasdata(st, 8)) { event = script_getstr(st, 8); - check_event(st, event); + script->check_event(st, event); } - + if (script_hasdata(st, 9)) { size = script_getnum(st, 9); @@ -8402,7 +9051,7 @@ BUILDIN(monster) return false; } } - + if (script_hasdata(st, 10)) { ai = script_getnum(st, 10); @@ -8412,28 +9061,32 @@ BUILDIN(monster) return false; } } - - if (class_ >= 0 && !mobdb_checkid(class_)) + + if (class_ >= 0 && !mob->db_checkid(class_)) { ShowWarning("buildin_monster: Attempted to spawn non-existing monster class %d\n", class_); return false; } - - sd = iMap->id2sd(st->rid); - + + sd = map->id2sd(st->rid); + if (sd && strcmp(mapn, "this") == 0) m = sd->bl.m; else { - m = iMap->mapname2mapid(mapn); - if (map[m].flag.src4instance && st->instance_id >= 0) { // Try to redirect to the instance map, not the src map + if ( ( m = map->mapname2mapid(mapn) ) == -1 ) { + ShowWarning("buildin_monster: Attempted to spawn monster class %d on non-existing map '%s'\n",class_, mapn); + return false; + } + + if (map->list[m].flag.src4instance && st->instance_id >= 0) { // Try to redirect to the instance map, not the src map if ((m = instance->mapid2imapid(m, st->instance_id)) < 0) { ShowError("buildin_monster: Trying to spawn monster (%d) on instance map (%s) without instance attached.\n", class_, mapn); return false; } } } - - mob_id = mob_once_spawn(sd, m, x, y, str, class_, amount, event, size, ai); + + mob_id = mob->once_spawn(sd, m, x, y, str, class_, amount, event, size, ai); script_pushint(st, mob_id); return true; } @@ -8444,60 +9097,59 @@ BUILDIN(getmobdrops) { int class_ = script_getnum(st,2); int i, j = 0; - struct mob_db *mob; - - if( !mobdb_checkid(class_) ) + struct mob_db *monster; + + if( !mob->db_checkid(class_) ) { script_pushint(st, 0); return true; } - - mob = mob_db(class_); - + + monster = mob->db(class_); + for( i = 0; i < MAX_MOB_DROP; i++ ) { - if( mob->dropitem[i].nameid < 1 ) + if( monster->dropitem[i].nameid < 1 ) continue; - if( itemdb_exists(mob->dropitem[i].nameid) == NULL ) + if( itemdb->exists(monster->dropitem[i].nameid) == NULL ) continue; - - mapreg_setreg(reference_uid(add_str("$@MobDrop_item"), j), mob->dropitem[i].nameid); - mapreg_setreg(reference_uid(add_str("$@MobDrop_rate"), j), mob->dropitem[i].p); - + + mapreg->setreg(reference_uid(script->add_str("$@MobDrop_item"), j), monster->dropitem[i].nameid); + mapreg->setreg(reference_uid(script->add_str("$@MobDrop_rate"), j), monster->dropitem[i].p); + j++; } - - mapreg_setreg(add_str("$@MobDrop_count"), j); + + mapreg->setreg(script->add_str("$@MobDrop_count"), j); script_pushint(st, 1); - + return true; } /*========================================== * Same as monster but randomize location in x0,x1,y0,y1 area *------------------------------------------*/ -BUILDIN(areamonster) -{ - const char* mapn = script_getstr(st,2); - int x0 = script_getnum(st,3); - int y0 = script_getnum(st,4); - int x1 = script_getnum(st,5); - int y1 = script_getnum(st,6); - const char* str = script_getstr(st,7); - int class_ = script_getnum(st,8); - int amount = script_getnum(st,9); - const char* event = ""; - unsigned int size = SZ_SMALL; - unsigned int ai = AI_NONE; +BUILDIN(areamonster) { + const char *mapn = script_getstr(st,2); + int x0 = script_getnum(st,3); + int y0 = script_getnum(st,4); + int x1 = script_getnum(st,5); + int y1 = script_getnum(st,6); + const char *str = script_getstr(st,7); + int class_ = script_getnum(st,8); + int amount = script_getnum(st,9); + const char *event = ""; + unsigned int size = SZ_MEDIUM; + unsigned int ai = AI_NONE; int mob_id; - + struct map_session_data* sd; int16 m; - + if (script_hasdata(st,10)) { event = script_getstr(st, 10); - check_event(st, event); + script->check_event(st, event); } - + if (script_hasdata(st, 11)) { size = script_getnum(st, 11); if (size > 3) { @@ -8505,7 +9157,7 @@ BUILDIN(areamonster) return false; } } - + if (script_hasdata(st, 12)) { ai = script_getnum(st, 12); if (ai > 4) { @@ -8513,64 +9165,66 @@ BUILDIN(areamonster) return false; } } - - sd = iMap->id2sd(st->rid); - + + sd = map->id2sd(st->rid); + if (sd && strcmp(mapn, "this") == 0) m = sd->bl.m; else { - m = iMap->mapname2mapid(mapn); - if (map[m].flag.src4instance && st->instance_id >= 0) { // Try to redirect to the instance map, not the src map + if ( ( m = map->mapname2mapid(mapn) ) == -1 ) { + ShowWarning("buildin_areamonster: Attempted to spawn monster class %d on non-existing map '%s'\n",class_, mapn); + return false; + } + if (map->list[m].flag.src4instance && st->instance_id >= 0) { // Try to redirect to the instance map, not the src map if ((m = instance->mapid2imapid(m, st->instance_id)) < 0) { ShowError("buildin_areamonster: Trying to spawn monster (%d) on instance map (%s) without instance attached.\n", class_, mapn); return false; } } } - - mob_id = mob_once_spawn_area(sd, m, x0, y0, x1, y1, str, class_, amount, event, size, ai); + + mob_id = mob->once_spawn_area(sd, m, x0, y0, x1, y1, str, class_, amount, event, size, ai); script_pushint(st, mob_id); - + return true; } /*========================================== * KillMonster subcheck, verify if mob to kill ain't got an even to handle, could be force kill by allflag *------------------------------------------*/ -static int buildin_killmonster_sub_strip(struct block_list *bl,va_list ap) +int buildin_killmonster_sub_strip(struct block_list *bl,va_list ap) { //same fix but with killmonster instead - stripping events from mobs. TBL_MOB* md = (TBL_MOB*)bl; char *event=va_arg(ap,char *); int allflag=va_arg(ap,int); - + md->state.npc_killmonster = 1; - - if(!allflag){ + + if(!allflag) { if(strcmp(event,md->npc_event)==0) status_kill(bl); - }else{ + } else { if(!md->spawn) status_kill(bl); } md->state.npc_killmonster = 0; return 0; } -static int buildin_killmonster_sub(struct block_list *bl,va_list ap) +int buildin_killmonster_sub(struct block_list *bl,va_list ap) { TBL_MOB* md = (TBL_MOB*)bl; char *event=va_arg(ap,char *); int allflag=va_arg(ap,int); - - if(!allflag){ + + if(!allflag) { if(strcmp(event,md->npc_event)==0) status_kill(bl); - }else{ + } else { if(!md->spawn) status_kill(bl); } return 0; } -BUILDIN(killmonster) -{ +BUILDIN(killmonster) { const char *mapname,*event; int16 m,allflag=0; mapname=script_getstr(st,2); @@ -8578,63 +9232,62 @@ BUILDIN(killmonster) if(strcmp(event,"All")==0) allflag = 1; else - check_event(st, event); - - if( (m=iMap->mapname2mapid(mapname))<0 ) + script->check_event(st, event); + + if( (m=map->mapname2mapid(mapname))<0 ) return true; - - if( map[m].flag.src4instance && st->instance_id >= 0 && (m = instance->mapid2imapid(m, st->instance_id)) < 0 ) + + if( map->list[m].flag.src4instance && st->instance_id >= 0 && (m = instance->mapid2imapid(m, st->instance_id)) < 0 ) return true; - + if( script_hasdata(st,4) ) { if ( script_getnum(st,4) == 1 ) { - iMap->foreachinmap(buildin_killmonster_sub, m, BL_MOB, event ,allflag); + map->foreachinmap(script->buildin_killmonster_sub, m, BL_MOB, event ,allflag); return true; } } - - iMap->freeblock_lock(); - iMap->foreachinmap(buildin_killmonster_sub_strip, m, BL_MOB, event ,allflag); - iMap->freeblock_unlock(); + + map->freeblock_lock(); + map->foreachinmap(script->buildin_killmonster_sub_strip, m, BL_MOB, event ,allflag); + map->freeblock_unlock(); return true; } -static int buildin_killmonsterall_sub_strip(struct block_list *bl,va_list ap) +int buildin_killmonsterall_sub_strip(struct block_list *bl,va_list ap) { //Strips the event from the mob if it's killed the old method. struct mob_data *md; - + md = BL_CAST(BL_MOB, bl); if (md->npc_event[0]) md->npc_event[0] = 0; - + status_kill(bl); return 0; } -static int buildin_killmonsterall_sub(struct block_list *bl,va_list ap) +int buildin_killmonsterall_sub(struct block_list *bl,va_list ap) { status_kill(bl); return 0; } -BUILDIN(killmonsterall) -{ +BUILDIN(killmonsterall) { const char *mapname; int16 m; mapname=script_getstr(st,2); - - if( (m = iMap->mapname2mapid(mapname))<0 ) + + if( (m = map->mapname2mapid(mapname))<0 ) return true; - - if( map[m].flag.src4instance && st->instance_id >= 0 && (m = instance->mapid2imapid(m, st->instance_id)) < 0 ) + + if( map->list[m].flag.src4instance && st->instance_id >= 0 && (m = instance->mapid2imapid(m, st->instance_id)) < 0 ) return true; - + if( script_hasdata(st,3) ) { if ( script_getnum(st,3) == 1 ) { - iMap->foreachinmap(buildin_killmonsterall_sub,m,BL_MOB); + map->foreachinmap(script->buildin_killmonsterall_sub,m,BL_MOB); return true; } } - - iMap->foreachinmap(buildin_killmonsterall_sub_strip,m,BL_MOB); + + map->foreachinmap(script->buildin_killmonsterall_sub_strip,m,BL_MOB); return true; } @@ -8642,50 +9295,49 @@ BUILDIN(killmonsterall) * Creates a clone of a player. * clone map, x, y, event, char_id, master_id, mode, flag, duration *------------------------------------------*/ -BUILDIN(clone) -{ +BUILDIN(clone) { TBL_PC *sd, *msd=NULL; int char_id,master_id=0,x,y, mode = 0, flag = 0, m; unsigned int duration = 0; - const char *map,*event=""; - - map=script_getstr(st,2); + const char *mapname, *event=""; + + mapname=script_getstr(st,2); x=script_getnum(st,3); y=script_getnum(st,4); event=script_getstr(st,5); char_id=script_getnum(st,6); - + if( script_hasdata(st,7) ) master_id=script_getnum(st,7); - + if( script_hasdata(st,8) ) mode=script_getnum(st,8); - + if( script_hasdata(st,9) ) flag=script_getnum(st,9); - + if( script_hasdata(st,10) ) duration=script_getnum(st,10); - - check_event(st, event); - - m = iMap->mapname2mapid(map); + + script->check_event(st, event); + + m = map->mapname2mapid(mapname); if (m < 0) return true; - - sd = iMap->charid2sd(char_id); - + + sd = map->charid2sd(char_id); + if (master_id) { - msd = iMap->charid2sd(master_id); + msd = map->charid2sd(master_id); if (msd) master_id = msd->bl.id; else master_id = 0; } if (sd) //Return ID of newly crafted clone. - script_pushint(st,mob_clone_spawn(sd, m, x, y, event, master_id, mode, flag, 1000*duration)); + script_pushint(st,mob->clone_spawn(sd, m, x, y, event, master_id, mode, flag, 1000*duration)); else //Failed to create clone. script_pushint(st,0); - + return true; } /*========================================== @@ -8694,14 +9346,14 @@ BUILDIN(doevent) { const char* event = script_getstr(st,2); struct map_session_data* sd; - - if( ( sd = script_rid2sd(st) ) == NULL ) + + if( ( sd = script->rid2sd(st) ) == NULL ) { return true; } - - check_event(st, event); - npc_event(sd, event, 0); + + script->check_event(st, event); + npc->event(sd, event, 0); return true; } /*========================================== @@ -8709,9 +9361,9 @@ BUILDIN(doevent) BUILDIN(donpcevent) { const char* event = script_getstr(st,2); - check_event(st, event); - if( !npc_event_do(event) ) { - struct npc_data * nd = iMap->id2nd(st->oid); + script->check_event(st, event); + if( !npc->event_do(event) ) { + struct npc_data * nd = map->id2nd(st->oid); ShowDebug("NPCEvent '%s' not found! (source: %s)\n",event,nd?nd->name:"Unknown"); script_pushint(st, 0); } else @@ -8720,15 +9372,14 @@ BUILDIN(donpcevent) } /// for Aegis compatibility -/// basically a specialized 'donpcevent', with the event specified as two arguments instead of one -BUILDIN(cmdothernpc) // Added by RoVeRT -{ - const char* npc = script_getstr(st,2); +/// basically a specialized 'donpcevent', with the event specified as two arguments instead of one [RoVeRT] +BUILDIN(cmdothernpc) { + const char* npc_name = script_getstr(st,2); const char* command = script_getstr(st,3); char event[EVENT_NAME_LENGTH]; - snprintf(event, sizeof(event), "%s::OnCommand%s", npc, command); - check_event(st, event); - npc_event_do(event); + snprintf(event, sizeof(event), "%s::OnCommand%s", npc_name, command); + script->check_event(st, event); + npc->event_do(event); return true; } @@ -8739,13 +9390,16 @@ BUILDIN(addtimer) int tick = script_getnum(st,2); const char* event = script_getstr(st, 3); TBL_PC* sd; - - check_event(st, event); - sd = script_rid2sd(st); + + script->check_event(st, event); + sd = script->rid2sd(st); if( sd == NULL ) return true; - - pc->addeventtimer(sd,tick,event); + + if (!pc->addeventtimer(sd,tick,event)) { + ShowWarning("buildin_addtimer: Event timer is full, can't add new event timer. (cid:%d timer:%s)\n",sd->status.char_id,event); + return false; + } return true; } /*========================================== @@ -8754,13 +9408,13 @@ BUILDIN(deltimer) { const char *event; TBL_PC* sd; - + event=script_getstr(st, 2); - sd = script_rid2sd(st); + sd = script->rid2sd(st); if( sd == NULL ) return true; - - check_event(st, event); + + script->check_event(st, event); pc->deleventtimer(sd,event); return true; } @@ -8771,14 +9425,14 @@ BUILDIN(addtimercount) const char *event; int tick; TBL_PC* sd; - + event=script_getstr(st, 2); tick=script_getnum(st,3); - sd = script_rid2sd(st); + sd = script->rid2sd(st); if( sd == NULL ) return true; - - check_event(st, event); + + script->check_event(st, event); pc->addeventtimercount(sd,event,tick); return true; } @@ -8789,46 +9443,42 @@ BUILDIN(initnpctimer) { struct npc_data *nd; int flag = 0; - - if( script_hasdata(st,3) ) - { //Two arguments: NPC name and attach flag. - nd = npc_name2id(script_getstr(st, 2)); + + if( script_hasdata(st,3) ) { + //Two arguments: NPC name and attach flag. + nd = npc->name2id(script_getstr(st, 2)); flag = script_getnum(st,3); - } - else if( script_hasdata(st,2) ) - { //Check if argument is numeric (flag) or string (npc name) + } else if( script_hasdata(st,2) ) { + //Check if argument is numeric (flag) or string (npc name) struct script_data *data; data = script_getdata(st,2); - script->get_val(st,data); + script->get_val(st,data); // dereference if it's a variable if( data_isstring(data) ) //NPC name - nd = npc_name2id(script->conv_str(st, data)); - else if( data_isint(data) ) //Flag - { - nd = (struct npc_data *)iMap->id2bl(st->oid); + nd = npc->name2id(script->conv_str(st, data)); + else if( data_isint(data) ) { + //Flag + nd = (struct npc_data *)map->id2bl(st->oid); flag = script->conv_num(st,data); - } - else - { + } else { ShowError("initnpctimer: invalid argument type #1 (needs be int or string)).\n"); return false; } - } - else - nd = (struct npc_data *)iMap->id2bl(st->oid); - + } else + nd = (struct npc_data *)map->id2bl(st->oid); + if( !nd ) return true; if( flag ) //Attach { - TBL_PC* sd = script_rid2sd(st); + TBL_PC* sd = script->rid2sd(st); if( sd == NULL ) return true; nd->u.scr.rid = sd->bl.id; } - + nd->u.scr.timertick = 0; - npc_settimerevent_tick(nd,0); - npc_timerevent_start(nd, st->rid); + npc->settimerevent_tick(nd,0); + npc->timerevent_start(nd, st->rid); return true; } /*========================================== @@ -8837,117 +9487,104 @@ BUILDIN(startnpctimer) { struct npc_data *nd; int flag = 0; - - if( script_hasdata(st,3) ) - { //Two arguments: NPC name and attach flag. - nd = npc_name2id(script_getstr(st, 2)); + + if( script_hasdata(st,3) ) { + //Two arguments: NPC name and attach flag. + nd = npc->name2id(script_getstr(st, 2)); flag = script_getnum(st,3); - } - else if( script_hasdata(st,2) ) - { //Check if argument is numeric (flag) or string (npc name) + } else if( script_hasdata(st,2) ) { + //Check if argument is numeric (flag) or string (npc name) struct script_data *data; data = script_getdata(st,2); - script->get_val(st,data); + script->get_val(st,data); // dereference if it's a variable if( data_isstring(data) ) //NPC name - nd = npc_name2id(script->conv_str(st, data)); - else if( data_isint(data) ) //Flag - { - nd = (struct npc_data *)iMap->id2bl(st->oid); + nd = npc->name2id(script->conv_str(st, data)); + else if( data_isint(data) ) { + //Flag + nd = (struct npc_data *)map->id2bl(st->oid); flag = script->conv_num(st,data); - } - else - { + } else { ShowError("initnpctimer: invalid argument type #1 (needs be int or string)).\n"); return false; } - } - else - nd=(struct npc_data *)iMap->id2bl(st->oid); - + } else + nd=(struct npc_data *)map->id2bl(st->oid); + if( !nd ) return true; if( flag ) //Attach { - TBL_PC* sd = script_rid2sd(st); + TBL_PC* sd = script->rid2sd(st); if( sd == NULL ) return true; nd->u.scr.rid = sd->bl.id; } - - npc_timerevent_start(nd, st->rid); + + npc->timerevent_start(nd, st->rid); return true; } /*========================================== *------------------------------------------*/ -BUILDIN(stopnpctimer) -{ +BUILDIN(stopnpctimer) { struct npc_data *nd; int flag = 0; - - if( script_hasdata(st,3) ) - { //Two arguments: NPC name and attach flag. - nd = npc_name2id(script_getstr(st, 2)); + + if( script_hasdata(st,3) ) { + //Two arguments: NPC name and attach flag. + nd = npc->name2id(script_getstr(st, 2)); flag = script_getnum(st,3); - } - else if( script_hasdata(st,2) ) - { //Check if argument is numeric (flag) or string (npc name) + } else if( script_hasdata(st,2) ) { + //Check if argument is numeric (flag) or string (npc name) struct script_data *data; data = script_getdata(st,2); - script->get_val(st,data); + script->get_val(st,data); // Dereference if it's a variable if( data_isstring(data) ) //NPC name - nd = npc_name2id(script->conv_str(st, data)); - else if( data_isint(data) ) //Flag - { - nd = (struct npc_data *)iMap->id2bl(st->oid); + nd = npc->name2id(script->conv_str(st, data)); + else if( data_isint(data) ) { + //Flag + nd = (struct npc_data *)map->id2bl(st->oid); flag = script->conv_num(st,data); - } - else - { + } else { ShowError("initnpctimer: invalid argument type #1 (needs be int or string)).\n"); return false; } - } - else - nd=(struct npc_data *)iMap->id2bl(st->oid); - + } else + nd=(struct npc_data *)map->id2bl(st->oid); + if( !nd ) return true; if( flag ) //Detach nd->u.scr.rid = 0; - - npc_timerevent_stop(nd); + + npc->timerevent_stop(nd); return true; } /*========================================== *------------------------------------------*/ -BUILDIN(getnpctimer) -{ +BUILDIN(getnpctimer) { struct npc_data *nd; TBL_PC *sd; int type = script_getnum(st,2); int val = 0; - + if( script_hasdata(st,3) ) - nd = npc_name2id(script_getstr(st,3)); + nd = npc->name2id(script_getstr(st,3)); else - nd = (struct npc_data *)iMap->id2bl(st->oid); - + nd = (struct npc_data *)map->id2bl(st->oid); + if( !nd || nd->bl.type != BL_NPC ) { script_pushint(st,0); ShowError("getnpctimer: Invalid NPC.\n"); return false; } - - switch( type ) - { - case 0: val = npc_gettimerevent_tick(nd); break; + + switch( type ) { + case 0: val = (int)npc->gettimerevent_tick(nd); break; // FIXME: change this to int64 when we'll support 64 bit script values case 1: - if( nd->u.scr.rid ) - { - sd = iMap->id2sd(nd->u.scr.rid); - if( !sd ) - { + if( nd->u.scr.rid ) { + sd = map->id2sd(nd->u.scr.rid); + if( !sd ) { ShowError("buildin_getnpctimer: Attached player not found!\n"); break; } @@ -8958,7 +9595,7 @@ BUILDIN(getnpctimer) break; case 2: val = nd->u.scr.timeramount; break; } - + script_pushint(st,val); return true; } @@ -8968,21 +9605,20 @@ BUILDIN(setnpctimer) { int tick; struct npc_data *nd; - + tick = script_getnum(st,2); if( script_hasdata(st,3) ) - nd = npc_name2id(script_getstr(st,3)); + nd = npc->name2id(script_getstr(st,3)); else - nd = (struct npc_data *)iMap->id2bl(st->oid); - - if( !nd || nd->bl.type != BL_NPC ) - { + nd = (struct npc_data *)map->id2bl(st->oid); + + if( !nd || nd->bl.type != BL_NPC ) { script_pushint(st,1); ShowError("setnpctimer: Invalid NPC.\n"); return false; } - - npc_settimerevent_tick(nd,tick); + + npc->settimerevent_tick(nd,tick); script_pushint(st,0); return true; } @@ -8990,30 +9626,29 @@ BUILDIN(setnpctimer) /*========================================== * attaches the player rid to the timer [Celest] *------------------------------------------*/ -BUILDIN(attachnpctimer) -{ +BUILDIN(attachnpctimer) { TBL_PC *sd; - struct npc_data *nd = (struct npc_data *)iMap->id2bl(st->oid); - + struct npc_data *nd = (struct npc_data *)map->id2bl(st->oid); + if( !nd || nd->bl.type != BL_NPC ) { script_pushint(st,1); ShowError("setnpctimer: Invalid NPC.\n"); return false; } - + if( script_hasdata(st,2) ) - sd = iMap->nick2sd(script_getstr(st,2)); + sd = map->nick2sd(script_getstr(st,2)); else - sd = script_rid2sd(st); - + sd = script->rid2sd(st); + if( !sd ) { script_pushint(st,1); ShowWarning("attachnpctimer: Invalid player.\n"); return false; } - + nd->u.scr.rid = sd->bl.id; script_pushint(st,0); return true; @@ -9022,22 +9657,21 @@ BUILDIN(attachnpctimer) /*========================================== * detaches a player rid from the timer [Celest] *------------------------------------------*/ -BUILDIN(detachnpctimer) -{ +BUILDIN(detachnpctimer) { struct npc_data *nd; - + if( script_hasdata(st,2) ) - nd = npc_name2id(script_getstr(st,2)); + nd = npc->name2id(script_getstr(st,2)); else - nd = (struct npc_data *)iMap->id2bl(st->oid); - + nd = (struct npc_data *)map->id2bl(st->oid); + if( !nd || nd->bl.type != BL_NPC ) { script_pushint(st,1); ShowError("detachnpctimer: Invalid NPC.\n"); return false; } - + nd->u.scr.rid = 0; script_pushint(st,0); return true; @@ -9048,9 +9682,8 @@ BUILDIN(detachnpctimer) * it checks if there is a player attached to the current script. [Skotlex] * If no, returns 0, if yes, returns the account_id of the attached player. *------------------------------------------*/ -BUILDIN(playerattached) -{ - if(st->rid == 0 || iMap->id2sd(st->rid) == NULL) +BUILDIN(playerattached) { + if(st->rid == 0 || map->id2sd(st->rid) == NULL) script_pushint(st,0); else script_pushint(st,st->rid); @@ -9059,8 +9692,7 @@ 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; @@ -9068,36 +9700,36 @@ 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 - - if (flag&0x0f) // Broadcast source or broadcast region defined - { + + if( flag&(BC_TARGET_MASK|BC_SOURCE_MASK) ) { + // Broadcast source or broadcast region defined send_target target; - struct block_list *bl = (flag&0x08) ? iMap->id2bl(st->oid) : (struct block_list *)script_rid2sd(st); // If bc_npc flag is set, use NPC as broadcast source + struct block_list *bl = (flag&BC_NPC) ? map->id2bl(st->oid) : (struct block_list *)script->rid2sd(st); // If bc_npc flag is set, use NPC as broadcast source if (bl == NULL) return true; - - flag &= 0x07; - target = (flag == 1) ? ALL_SAMEMAP : - (flag == 2) ? AREA : - (flag == 3) ? SELF : - ALL_CLIENT; + + switch( flag&BC_TARGET_MASK ) { + case BC_MAP: target = ALL_SAMEMAP; break; + case BC_AREA: target = AREA; break; + case BC_SELF: target = SELF; break; + default: target = ALL_CLIENT; break; // BC_ALL + } + if (fontColor) - clif->broadcast2(bl, mes, (int)strlen(mes)+1, strtol(fontColor, (char **)NULL, 0), fontType, fontSize, fontAlign, fontY, target); + clif->broadcast2(bl, mes, (int)strlen(mes)+1, (unsigned int)strtoul(fontColor, (char **)NULL, 0), fontType, fontSize, fontAlign, fontY, target); else - clif->broadcast(bl, mes, (int)strlen(mes)+1, flag&0xf0, target); - } - else - { + clif->broadcast(bl, mes, (int)strlen(mes)+1, flag&BC_COLOR_MASK, target); + } else { if (fontColor) - intif_broadcast2(mes, (int)strlen(mes)+1, strtol(fontColor, (char **)NULL, 0), fontType, fontSize, fontAlign, fontY); + intif->broadcast2(mes, (int)strlen(mes)+1, (unsigned int)strtoul(fontColor, (char **)NULL, 0), fontType, fontSize, fontAlign, fontY); else - intif_broadcast(mes, (int)strlen(mes)+1, flag&0xf0); + intif->broadcast(mes, (int)strlen(mes)+1, flag&BC_COLOR_MASK); } return true; } /*========================================== *------------------------------------------*/ -static int buildin_announce_sub(struct block_list *bl, va_list ap) +int buildin_announce_sub(struct block_list *bl, va_list ap) { char *mes = va_arg(ap, char *); int len = va_arg(ap, int); @@ -9108,7 +9740,7 @@ static int buildin_announce_sub(struct block_list *bl, va_list ap) short fontAlign = (short)va_arg(ap, int); short fontY = (short)va_arg(ap, int); if (fontColor) - clif->broadcast2(bl, mes, len, strtol(fontColor, (char **)NULL, 0), fontType, fontSize, fontAlign, fontY, SELF); + clif->broadcast2(bl, mes, len, (unsigned int)strtoul(fontColor, (char **)NULL, 0), fontType, fontSize, fontAlign, fontY, SELF); else clif->broadcast(bl, mes, len, type, SELF); return 0; @@ -9119,41 +9751,38 @@ static int buildin_announce_sub(struct block_list *bl, va_list ap) BUILDIN(itemeffect) { TBL_NPC *nd; TBL_PC *sd; - struct script_data *data; struct item_data *item_data; - - nullpo_retr( 1, ( sd = script_rid2sd( st ) ) ); - nullpo_retr( 1, ( nd = (TBL_NPC *)iMap->id2bl( sd->npc_id ) ) ); - - data = script_getdata( st, 2 ); - script->get_val( st, data ); - - if( data_isstring( data ) ){ - const char *name = script->conv_str( st, data ); - - if( ( item_data = itemdb_searchname( name ) ) == NULL ){ + + sd = script->rid2sd(st); + if( sd == NULL ) + return false; + + nd = (TBL_NPC *)map->id2bl(sd->npc_id); + if( nd == NULL ) + return false; + + if( script_isstringtype(st, 2) ) { + const char *name = script_getstr(st, 2); + + if( ( item_data = itemdb->search_name( name ) ) == NULL ) { ShowError( "buildin_itemeffect: Nonexistant item %s requested.\n", name ); return false; } - } else if( data_isint( data ) ){ - int nameid = script->conv_num( st, data ); - - if( ( item_data = itemdb_exists( nameid ) ) == NULL ){ + } else { + int nameid = script_getnum(st, 2); + + if( ( item_data = itemdb->exists( nameid ) ) == NULL ) { ShowError("buildin_itemeffect: Nonexistant item %d requested.\n", nameid ); return false; } - } else { - ShowError("buildin_itemeffect: invalid data type for argument #1 (%d).", data->type ); - return false; } - - run_script( item_data->script, 0, sd->bl.id, nd->bl.id ); - + + script->run( item_data->script, 0, sd->bl.id, nd->bl.id ); + 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); @@ -9163,18 +9792,17 @@ 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; - - if ((m = iMap->mapname2mapid(mapname)) < 0) + + if ((m = map->mapname2mapid(mapname)) < 0) return true; - - iMap->foreachinmap(buildin_announce_sub, m, BL_PC, - mes, strlen(mes)+1, flag&0xf0, fontColor, fontType, fontSize, fontAlign, fontY); + + map->foreachinmap(script->buildin_announce_sub, m, BL_PC, + mes, strlen(mes)+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); @@ -9188,51 +9816,47 @@ 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; - - if ((m = iMap->mapname2mapid(mapname)) < 0) + + if ((m = map->mapname2mapid(mapname)) < 0) return true; - - iMap->foreachinarea(buildin_announce_sub, m, x0, y0, x1, y1, BL_PC, - mes, strlen(mes)+1, flag&0xf0, fontColor, fontType, fontSize, fontAlign, fontY); + + 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); return true; } /*========================================== *------------------------------------------*/ -BUILDIN(getusers) -{ +BUILDIN(getusers) { int flag, val = 0; struct map_session_data* sd; struct block_list* bl = NULL; - + flag = script_getnum(st,2); - - switch(flag&0x07) - { + + switch(flag&0x07) { case 0: - if(flag&0x8) - {// npc - bl = iMap->id2bl(st->oid); - } - else if((sd = script_rid2sd(st))!=NULL) - {// pc + if(flag&0x8) { + // npc + bl = map->id2bl(st->oid); + } else if((sd = script->rid2sd(st))!=NULL) { + // pc bl = &sd->bl; } - - if(bl) - { - val = map[bl->m].users; + + if(bl) { + val = map->list[bl->m].users; } break; case 1: - val = iMap->getusers(); + val = map->getusers(); break; default: ShowWarning("buildin_getusers: Unknown type %d.\n", flag); script_pushint(st,0); return false; } - + script_pushint(st,val); return true; } @@ -9244,17 +9868,17 @@ BUILDIN(getusersname) TBL_PC *sd, *pl_sd; int /*disp_num=1,*/ group_level = 0; struct s_mapiterator* iter; - - sd = script_rid2sd(st); + + sd = script->rid2sd(st); if (!sd) return true; - - group_level = pc->get_group_level(sd); + + group_level = pc_get_group_level(sd); iter = mapit_getallusers(); for( pl_sd = (TBL_PC*)mapit->first(iter); mapit->exists(iter); pl_sd = (TBL_PC*)mapit->next(iter) ) { - if (pc_has_permission(pl_sd, PC_PERM_HIDE_SESSION) && pc->get_group_level(pl_sd) > group_level) + if (pc_has_permission(pl_sd, PC_PERM_HIDE_SESSION) && pc_get_group_level(pl_sd) > group_level) continue; // skip hidden sessions - + /* Temporary fix for bugreport:1023. * Do not uncomment unless you want thousands of 'next' buttons. if((disp_num++)%10==0) @@ -9262,7 +9886,7 @@ BUILDIN(getusersname) clif->scriptmes(sd,st->oid,pl_sd->status.name); } mapit->free(iter); - + return true; } /*========================================== @@ -9277,40 +9901,39 @@ BUILDIN(getmapguildusers) struct guild *g = NULL; str=script_getstr(st,2); gid=script_getnum(st,3); - if ((m = iMap->mapname2mapid(str)) < 0) { // map id on this server (m == -1 if not in actual map-server) + if ((m = map->mapname2mapid(str)) < 0) { // map id on this server (m == -1 if not in actual map-server) script_pushint(st,-1); return true; } g = guild->search(gid); - - if (g){ + + if (g) { for(i = 0; i < g->max_member; i++) { if (g->member[i].sd && g->member[i].sd->bl.m == m) c++; } } - + script_pushint(st,c); return true; } /*========================================== *------------------------------------------*/ -BUILDIN(getmapusers) -{ +BUILDIN(getmapusers) { const char *str; int16 m; str=script_getstr(st,2); - if( (m=iMap->mapname2mapid(str))< 0){ + if( (m=map->mapname2mapid(str))< 0) { script_pushint(st,-1); return true; } - script_pushint(st,map[m].users); + script_pushint(st,map->list[m].users); return true; } /*========================================== *------------------------------------------*/ -static int buildin_getareausers_sub(struct block_list *bl,va_list ap) +int buildin_getareausers_sub(struct block_list *bl,va_list ap) { int *users=va_arg(ap,int *); (*users)++; @@ -9325,59 +9948,56 @@ BUILDIN(getareausers) y0=script_getnum(st,4); x1=script_getnum(st,5); y1=script_getnum(st,6); - if( (m=iMap->mapname2mapid(str))< 0){ + if( (m=map->mapname2mapid(str))< 0) { script_pushint(st,-1); return true; } - iMap->foreachinarea(buildin_getareausers_sub, - m,x0,y0,x1,y1,BL_PC,&users); + map->foreachinarea(script->buildin_getareausers_sub, + m,x0,y0,x1,y1,BL_PC,&users); script_pushint(st,users); return true; } /*========================================== *------------------------------------------*/ -static int buildin_getareadropitem_sub(struct block_list *bl,va_list ap) +int buildin_getareadropitem_sub(struct block_list *bl,va_list ap) { int item=va_arg(ap,int); int *amount=va_arg(ap,int *); struct flooritem_data *drop=(struct flooritem_data *)bl; - + if(drop->item_data.nameid==item) (*amount)+=drop->item_data.amount; - + return 0; } -BUILDIN(getareadropitem) -{ +BUILDIN(getareadropitem) { const char *str; int16 m,x0,y0,x1,y1; int item,amount=0; - struct script_data *data; - + str=script_getstr(st,2); x0=script_getnum(st,3); y0=script_getnum(st,4); x1=script_getnum(st,5); y1=script_getnum(st,6); - - data=script_getdata(st,7); - script->get_val(st,data); - if( data_isstring(data) ){ - const char *name=script->conv_str(st,data); - struct item_data *item_data = itemdb_searchname(name); + + if( script_isstringtype(st, 7) ) { + const char *name = script_getstr(st, 7); + struct item_data *item_data = itemdb->search_name(name); item=UNKNOWN_ITEM_ID; if( item_data ) item=item_data->nameid; - }else - item=script->conv_num(st,data); - - if( (m=iMap->mapname2mapid(str))< 0){ + } else { + item=script_getnum(st, 7); + } + + if( (m=map->mapname2mapid(str))< 0) { script_pushint(st,-1); return true; } - iMap->foreachinarea(buildin_getareadropitem_sub, - m,x0,y0,x1,y1,BL_ITEM,item,&amount); + map->foreachinarea(script->buildin_getareadropitem_sub, + m,x0,y0,x1,y1,BL_ITEM,item,&amount); script_pushint(st,amount); return true; } @@ -9387,7 +10007,7 @@ BUILDIN(enablenpc) { const char *str; str=script_getstr(st,2); - npc_enable(str,1); + npc->enable(str,1); return true; } /*========================================== @@ -9396,7 +10016,7 @@ BUILDIN(disablenpc) { const char *str; str=script_getstr(st,2); - npc_enable(str,0); + npc->enable(str,0); return true; } @@ -9406,7 +10026,7 @@ BUILDIN(hideoffnpc) { const char *str; str=script_getstr(st,2); - npc_enable(str,2); + npc->enable(str,2); return true; } /*========================================== @@ -9415,91 +10035,88 @@ BUILDIN(hideonnpc) { const char *str; str=script_getstr(st,2); - npc_enable(str,4); + npc->enable(str,4); return true; } /// Starts a status effect on the target unit or on the attached player. /// /// sc_start <effect_id>,<duration>,<val1>{,<unit_id>}; -BUILDIN(sc_start) -{ +BUILDIN(sc_start) { struct block_list* bl; enum sc_type type; int tick; int val1; int val4 = 0; - + type = (sc_type)script_getnum(st,2); tick = script_getnum(st,3); val1 = script_getnum(st,4); if( script_hasdata(st,5) ) - bl = iMap->id2bl(script_getnum(st,5)); + bl = map->id2bl(script_getnum(st,5)); else - bl = iMap->id2bl(st->rid); - - if( tick == 0 && val1 > 0 && type > SC_NONE && type < SC_MAX && status_sc2skill(type) != 0 ) - {// When there isn't a duration specified, try to get it from the skill_db - tick = skill->get_time(status_sc2skill(type), val1); + bl = map->id2bl(st->rid); + + if( tick == 0 && val1 > 0 && type > SC_NONE && type < SC_MAX && status->sc2skill(type) != 0 ) { + // When there isn't a duration specified, try to get it from the skill_db + tick = skill->get_time(status->sc2skill(type), val1); } - - if( potion_flag == 1 && potion_target ) - { //skill.c set the flags before running the script, this must be a potion-pitched effect. - bl = iMap->id2bl(potion_target); + + if( script->potion_flag == 1 && script->potion_target ) { + //skill.c set the flags before running the script, this must be a potion-pitched effect. + bl = map->id2bl(script->potion_target); tick /= 2;// Thrown potions only last half. val4 = 1;// Mark that this was a thrown sc_effect } - + if( bl ) - status_change_start(bl, type, 10000, val1, 0, 0, val4, tick, 2); - + status->change_start(NULL, bl, type, 10000, val1, 0, 0, val4, tick, 2); + return true; } /// Starts a status effect on the target unit or on the attached player. /// /// sc_start2 <effect_id>,<duration>,<val1>,<percent chance>{,<unit_id>}; -BUILDIN(sc_start2) -{ +BUILDIN(sc_start2) { struct block_list* bl; enum sc_type type; int tick; int val1; int val4 = 0; int rate; - + type = (sc_type)script_getnum(st,2); tick = script_getnum(st,3); val1 = script_getnum(st,4); rate = script_getnum(st,5); if( script_hasdata(st,6) ) - bl = iMap->id2bl(script_getnum(st,6)); + bl = map->id2bl(script_getnum(st,6)); else - bl = iMap->id2bl(st->rid); - - if( tick == 0 && val1 > 0 && type > SC_NONE && type < SC_MAX && status_sc2skill(type) != 0 ) - {// When there isn't a duration specified, try to get it from the skill_db - tick = skill->get_time(status_sc2skill(type), val1); + bl = map->id2bl(st->rid); + + if( tick == 0 && val1 > 0 && type > SC_NONE && type < SC_MAX && status->sc2skill(type) != 0 ) { + // When there isn't a duration specified, try to get it from the skill_db + tick = skill->get_time(status->sc2skill(type), val1); } - - if( potion_flag == 1 && potion_target ) - { //skill.c set the flags before running the script, this must be a potion-pitched effect. - bl = iMap->id2bl(potion_target); + + if( script->potion_flag == 1 && script->potion_target ) { + //skill.c set the flags before running the script, this must be a potion-pitched effect. + bl = map->id2bl(script->potion_target); tick /= 2;// Thrown potions only last half. val4 = 1;// Mark that this was a thrown sc_effect } - + if( bl ) - status_change_start(bl, type, rate, val1, 0, 0, val4, tick, 2); - + status->change_start(NULL, bl, type, rate, val1, 0, 0, val4, tick, 2); + return true; } /// Starts a status effect on the target unit or on the attached player. /// /// sc_start4 <effect_id>,<duration>,<val1>,<val2>,<val3>,<val4>{,<unit_id>}; -BUILDIN(sc_start4) -{ +BUILDIN(sc_start4) { struct block_list* bl; enum sc_type type; int tick; @@ -9507,7 +10124,7 @@ BUILDIN(sc_start4) int val2; int val3; int val4; - + type = (sc_type)script_getnum(st,2); tick = script_getnum(st,3); val1 = script_getnum(st,4); @@ -9515,96 +10132,91 @@ BUILDIN(sc_start4) val3 = script_getnum(st,6); val4 = script_getnum(st,7); if( script_hasdata(st,8) ) - bl = iMap->id2bl(script_getnum(st,8)); + bl = map->id2bl(script_getnum(st,8)); else - bl = iMap->id2bl(st->rid); - - if( tick == 0 && val1 > 0 && type > SC_NONE && type < SC_MAX && status_sc2skill(type) != 0 ) - {// When there isn't a duration specified, try to get it from the skill_db - tick = skill->get_time(status_sc2skill(type), val1); + bl = map->id2bl(st->rid); + + if( tick == 0 && val1 > 0 && type > SC_NONE && type < SC_MAX && status->sc2skill(type) != 0 ) { + // When there isn't a duration specified, try to get it from the skill_db + tick = skill->get_time(status->sc2skill(type), val1); } - - if( potion_flag == 1 && potion_target ) - { //skill.c set the flags before running the script, this must be a potion-pitched effect. - bl = iMap->id2bl(potion_target); + + if( script->potion_flag == 1 && script->potion_target ) { + //skill.c set the flags before running the script, this must be a potion-pitched effect. + bl = map->id2bl(script->potion_target); tick /= 2;// Thrown potions only last half. } - + if( bl ) - status_change_start(bl, type, 10000, val1, val2, val3, val4, tick, 2); - + status->change_start(NULL, bl, type, 10000, val1, val2, val3, val4, tick, 2); + return true; } /// Ends one or all status effects on the target unit or on the attached player. /// /// sc_end <effect_id>{,<unit_id>}; -BUILDIN(sc_end) -{ +BUILDIN(sc_end) { struct block_list* bl; int type; - + type = script_getnum(st, 2); if (script_hasdata(st, 3)) - bl = iMap->id2bl(script_getnum(st, 3)); + bl = map->id2bl(script_getnum(st, 3)); else - bl = iMap->id2bl(st->rid); - - if (potion_flag == 1 && potion_target) //##TODO how does this work [FlavioJS] - bl = iMap->id2bl(potion_target); - + bl = map->id2bl(st->rid); + + if (script->potion_flag == 1 && script->potion_target) //##TODO how does this work [FlavioJS] + bl = map->id2bl(script->potion_target); + if (!bl) return true; - - if (type >= 0 && type < SC_MAX) - { - struct status_change *sc = status_get_sc(bl); + + if (type >= 0 && type < SC_MAX) { + struct status_change *sc = status->get_sc(bl); struct status_change_entry *sce = sc ? sc->data[type] : NULL; - + if (!sce) return true; - - - switch (type) - { + + /* status that can't be individually removed (TODO sc_config option?) */ + switch (type) { case SC_WEIGHTOVER50: case SC_WEIGHTOVER90: case SC_NOCHAT: case SC_PUSH_CART: return true; - default: break; } - + //This should help status_change_end force disabling the SC in case it has no limit. sce->val1 = sce->val2 = sce->val3 = sce->val4 = 0; status_change_end(bl, (sc_type)type, INVALID_TIMER); } else - status_change_clear(bl, 3); // remove all effects - + status->change_clear(bl, 3); // remove all effects + return true; } /*========================================== * @FIXME atm will return reduced tick, 0 immune, 1 no tick *------------------------------------------*/ -BUILDIN(getscrate) -{ +BUILDIN(getscrate) { struct block_list *bl; int type,rate; - + type=script_getnum(st,2); rate=script_getnum(st,3); if( script_hasdata(st,4) ) //get for the bl assigned - bl = iMap->id2bl(script_getnum(st,4)); + bl = map->id2bl(script_getnum(st,4)); else - bl = iMap->id2bl(st->rid); - + bl = map->id2bl(st->rid); + if (bl) - rate = status_get_sc_def(bl, (sc_type)type, 10000, 10000, 0); - + rate = status->get_sc_def(bl, bl, (sc_type)type, 10000, 10000, 0); + script_pushint(st,rate); return true; } @@ -9615,47 +10227,46 @@ BUILDIN(getscrate) BUILDIN(getstatus) { int id, type; - struct map_session_data* sd = script_rid2sd(st); - + struct map_session_data* sd = script->rid2sd(st); + if( sd == NULL ) {// no player attached return true; } - + id = script_getnum(st, 2); type = script_hasdata(st, 3) ? script_getnum(st, 3) : 0; - + if( id <= SC_NONE || id >= SC_MAX ) {// invalid status type given ShowWarning("script.c:getstatus: Invalid status type given (%d).\n", id); return true; } - + if( sd->sc.count == 0 || !sd->sc.data[id] ) {// no status is active script_pushint(st, 0); return true; } - - switch( type ) - { - case 1: script_pushint(st, sd->sc.data[id]->val1); break; - case 2: script_pushint(st, sd->sc.data[id]->val2); break; - case 3: script_pushint(st, sd->sc.data[id]->val3); break; - case 4: script_pushint(st, sd->sc.data[id]->val4); break; + + switch( type ) { + case 1: script_pushint(st, sd->sc.data[id]->val1); break; + case 2: script_pushint(st, sd->sc.data[id]->val2); break; + case 3: script_pushint(st, sd->sc.data[id]->val3); break; + case 4: script_pushint(st, sd->sc.data[id]->val4); break; case 5: { - struct TimerData* timer = (struct TimerData*)iTimer->get_timer(sd->sc.data[id]->timer); - - if( timer ) - {// return the amount of time remaining - script_pushint(st, timer->tick - iTimer->gettick()); + struct TimerData* td = (struct TimerData*)timer->get(sd->sc.data[id]->timer); + + if( td ) { + // return the amount of time remaining + script_pushint(st, (int)(td->tick - timer->gettick())); // TODO: change this to int64 when we'll support 64 bit script values } } break; default: script_pushint(st, 1); break; } - + return true; } @@ -9676,13 +10287,13 @@ BUILDIN(catchpet) { int pet_id; TBL_PC *sd; - + pet_id= script_getnum(st,2); - sd=script_rid2sd(st); + sd=script->rid2sd(st); if( sd == NULL ) return true; - - pet_catch_process1(sd,pet_id); + + pet->catch_process1(sd,pet_id); return true; } @@ -9692,11 +10303,11 @@ BUILDIN(catchpet) BUILDIN(homunculus_evolution) { TBL_PC *sd; - - sd=script_rid2sd(st); + + sd=script->rid2sd(st); if( sd == NULL ) return true; - + if(homun_alive(sd->hd)) { if (sd->hd->homunculus.intimacy > 91000) homun->evolve(sd->hd); @@ -9708,44 +10319,82 @@ BUILDIN(homunculus_evolution) /*========================================== * [Xantara] + * Checks for vaporized morph state + * and deletes ITEMID_STRANGE_EMBRYO. *------------------------------------------*/ BUILDIN(homunculus_mutate) { int homun_id; enum homun_type m_class, m_id; TBL_PC *sd; - - sd = script_rid2sd(st); + bool success = false; + + sd = script->rid2sd(st); if( sd == NULL || sd->hd == NULL ) return true; - - if(script_hasdata(st,2)) - homun_id = script_getnum(st,2); - else - homun_id = 6048 + (rnd() % 4); - - if(homun_alive(sd->hd)) { + + if( sd->hd->homunculus.vaporize == HOM_ST_MORPH ) { + int i = pc->search_inventory(sd, ITEMID_STRANGE_EMBRYO); + if( script_hasdata(st,2) ) + homun_id = script_getnum(st,2); + else + homun_id = 6048 + (rnd() % 4); + m_class = homun->class2type(sd->hd->homunculus.class_); m_id = homun->class2type(homun_id); - - if ( m_class != -1 && m_id != -1 && m_class == HT_EVO && m_id == HT_S && sd->hd->homunculus.level >= 99 ) + + if( m_class == HT_EVO && m_id == HT_S && + sd->hd->homunculus.level >= 99 && i != INDEX_NOT_FOUND && + !pc->delitem(sd, i, 1, 0, 0, LOG_TYPE_SCRIPT) ) { + sd->hd->homunculus.vaporize = HOM_ST_REST; // Remove morph state. + homun->call(sd); // Respawn homunculus. homun->mutate(sd->hd, homun_id); - else + success = true; + } else clif->emotion(&sd->hd->bl, E_SWT); - } + } else + clif->emotion(&sd->hd->bl, E_SWT); + + script_pushint(st,success?1:0); return true; } -// [Zephyrus] -BUILDIN(homunculus_shuffle) { +/*========================================== + * Puts homunculus into morph state + * and gives ITEMID_STRANGE_EMBRYO. + *------------------------------------------*/ +BUILDIN(homunculus_morphembryo) { + enum homun_type m_class; + int i = 0; TBL_PC *sd; - - sd=script_rid2sd(st); - if( sd == NULL ) + bool success = false; + + sd = script->rid2sd(st); + if( sd == NULL || sd->hd == NULL ) return true; - - if(homun_alive(sd->hd)) - homun->shuffle(sd->hd); - + + if( homun_alive(sd->hd) ) { + m_class = homun->class2type(sd->hd->homunculus.class_); + + if ( m_class == HT_EVO && sd->hd->homunculus.level >= 99 ) { + struct item item_tmp; + + memset(&item_tmp, 0, sizeof(item_tmp)); + item_tmp.nameid = ITEMID_STRANGE_EMBRYO; + item_tmp.identify = 1; + + if( (i = pc->additem(sd, &item_tmp, 1, LOG_TYPE_SCRIPT)) ) { + clif->additem(sd, 0, 0, i); + clif->emotion(&sd->hd->bl, E_SWT); + } else { + homun->vaporize(sd, HOM_ST_MORPH); + success = true; + } + } else + clif->emotion(&sd->hd->bl, E_SWT); + } else + clif->emotion(&sd->hd->bl, E_SWT); + + script_pushint(st, success?1:0); return true; } @@ -9756,20 +10405,28 @@ BUILDIN(homunculus_shuffle) { * 1 = Homunculus is vaporized (rest) * 2 = Homunculus is in morph state *------------------------------------------*/ -BUILDIN(checkhomcall) -{ - TBL_PC *sd = script_rid2sd(st); - TBL_HOM *hd; +BUILDIN(homunculus_checkcall) { + TBL_PC *sd = script->rid2sd(st); - if( sd == NULL ) - return false; - - hd = sd->hd; - - if( !hd ) + if( sd == NULL || !sd->hd ) script_pushint(st, -1); else - script_pushint(st, hd->homunculus.vaporize); + script_pushint(st, sd->hd->homunculus.vaporize); + + return true; +} + + +// [Zephyrus] +BUILDIN(homunculus_shuffle) { + TBL_PC *sd; + + sd=script->rid2sd(st); + if( sd == NULL ) + return true; + + if(homun_alive(sd->hd)) + homun->shuffle(sd->hd); return true; } @@ -9782,11 +10439,9 @@ BUILDIN(eaclass) class_ = script_getnum(st,2); else { TBL_PC *sd; - sd=script_rid2sd(st); - if (!sd) { - script_pushint(st,-1); + sd=script->rid2sd(st); + if( !sd ) return true; - } class_ = sd->status.class_; } script_pushint(st,pc->jobid2mapid(class_)); @@ -9801,7 +10456,7 @@ BUILDIN(roclass) sex = script_getnum(st,3); else { TBL_PC *sd; - if (st->rid && (sd=script_rid2sd(st))) + if (st->rid && (sd=script->rid2sd(st))) sex = sd->status.sex; else sex = 1; //Just use male when not found. @@ -9816,15 +10471,15 @@ BUILDIN(roclass) BUILDIN(birthpet) { TBL_PC *sd; - sd=script_rid2sd(st); + sd=script->rid2sd(st); if( sd == NULL ) return true; - + if( sd->status.pet_id ) {// do not send egg list, when you already have a pet return true; } - + clif->sendegg(sd); return true; } @@ -9832,21 +10487,21 @@ BUILDIN(birthpet) /*========================================== * Added - AppleGirl For Advanced Classes, (Updated for Cleaner Script Purposes) * @type - * 1 : make like after rebirth - * 2 : blvl,jlvl=1, skillpoint=0 - * 3 : don't reset skill, blvl=1 - * 4 : jlvl=0 + * 1 : make like after rebirth + * 2 : blvl,jlvl=1, skillpoint=0 + * 3 : don't reset skill, blvl=1 + * 4 : jlvl=0 *------------------------------------------*/ BUILDIN(resetlvl) { TBL_PC *sd; - + int type=script_getnum(st,2); - - sd=script_rid2sd(st); + + sd=script->rid2sd(st); if( sd == NULL ) return true; - + pc->resetlvl(sd,type); return true; } @@ -9856,7 +10511,9 @@ BUILDIN(resetlvl) BUILDIN(resetstatus) { TBL_PC *sd; - sd=script_rid2sd(st); + sd=script->rid2sd(st); + if( sd == NULL ) + return false; pc->resetstate(sd); return true; } @@ -9867,7 +10524,9 @@ BUILDIN(resetstatus) BUILDIN(resetskill) { TBL_PC *sd; - sd=script_rid2sd(st); + sd=script->rid2sd(st); + if( sd == NULL ) + return false; pc->resetskill(sd,1); return true; } @@ -9878,7 +10537,9 @@ BUILDIN(resetskill) BUILDIN(skillpointcount) { TBL_PC *sd; - sd=script_rid2sd(st); + sd=script->rid2sd(st); + if( sd == NULL ) + return false; script_pushint(st,sd->status.skill_point + pc->resetskill(sd,2)); return true; } @@ -9886,19 +10547,18 @@ BUILDIN(skillpointcount) /*========================================== * *------------------------------------------*/ -BUILDIN(changebase) -{ +BUILDIN(changebase) { TBL_PC *sd=NULL; int vclass; - + if( script_hasdata(st,3) ) - sd=iMap->id2sd(script_getnum(st,3)); + sd=map->id2sd(script_getnum(st,3)); else - sd=script_rid2sd(st); - + sd=script->rid2sd(st); + if(sd == NULL) return true; - + vclass = script_getnum(st,2); if(vclass == JOB_WEDDING) { @@ -9907,9 +10567,9 @@ BUILDIN(changebase) ) return true; } - + if(sd->disguise == -1 && vclass != sd->vd.class_) { - status_set_viewdata(&sd->bl, vclass); + status->set_viewdata(&sd->bl, vclass); //Updated client view. Base, Weapon and Cloth Colors. clif->changelook(&sd->bl,LOOK_BASE,sd->vd.class_); clif->changelook(&sd->bl,LOOK_WEAPON,sd->status.weapon); @@ -9917,7 +10577,7 @@ BUILDIN(changebase) clif->changelook(&sd->bl,LOOK_CLOTHES_COLOR,sd->vd.cloth_color); clif->skillinfoblock(sd); } - + return true; } @@ -9928,36 +10588,39 @@ BUILDIN(changesex) { int i; TBL_PC *sd = NULL; - sd = script_rid2sd(st); - + sd = script->rid2sd(st); + + if( sd == NULL ) + return false; + pc->resetskill(sd,4); // to avoid any problem with equipment and invalid sex, equipment is unequiped. for( i=0; i<EQI_MAX; i++ ) if( sd->equip_index[i] >= 0 ) pc->unequipitem(sd, sd->equip_index[i], 3); - chrif_changesex(sd); + chrif->changesex(sd); return true; } /*========================================== * Works like 'announce' but outputs in the common chat window *------------------------------------------*/ -BUILDIN(globalmes) -{ - struct block_list *bl = iMap->id2bl(st->oid); +BUILDIN(globalmes) { + struct block_list *bl = map->id2bl(st->oid); struct npc_data *nd = (struct npc_data *)bl; const char *name=NULL,*mes; - + mes=script_getstr(st,2); if(mes==NULL) return true; - - if(script_hasdata(st,3)){ // npc name to display + + if(script_hasdata(st,3)) { + // npc name to display name=script_getstr(st,3); } else { name=nd->name; //use current npc name } - - npc_globalmessage(name,mes); // broadcast to all players connected - + + npc->globalmessage(name,mes); // broadcast to all players connected + return true; } @@ -9968,8 +10631,7 @@ BUILDIN(globalmes) /// Creates a waiting room (chat room) for this npc. /// /// waitingroom "<title>",<limit>{,"<event>"{,<trigger>{,<zeny>{,<minlvl>{,<maxlvl>}}}}}; -BUILDIN(waitingroom) -{ +BUILDIN(waitingroom) { struct npc_data* nd; int pub = 1; const char* title = script_getstr(st, 2); @@ -9979,11 +10641,11 @@ BUILDIN(waitingroom) int zeny = script_hasdata(st,6) ? script_getnum(st,6) : 0; int minLvl = script_hasdata(st,7) ? script_getnum(st,7) : 1; int maxLvl = script_hasdata(st,8) ? script_getnum(st,8) : MAX_LEVEL; - - nd = (struct npc_data *)iMap->id2bl(st->oid); + + nd = (struct npc_data *)map->id2bl(st->oid); if( nd != NULL ) - chat_createnpcchat(nd, title, limit, pub, trigger, ev, zeny, minLvl, maxLvl); - + chat->create_npc_chat(nd, title, limit, pub, trigger, ev, zeny, minLvl, maxLvl); + return true; } @@ -9991,15 +10653,14 @@ BUILDIN(waitingroom) /// /// delwaitingroom "<npc_name>"; /// delwaitingroom; -BUILDIN(delwaitingroom) -{ +BUILDIN(delwaitingroom) { struct npc_data* nd; if( script_hasdata(st,2) ) - nd = npc_name2id(script_getstr(st, 2)); + nd = npc->name2id(script_getstr(st, 2)); else - nd = (struct npc_data *)iMap->id2bl(st->oid); + nd = (struct npc_data *)map->id2bl(st->oid); if( nd != NULL ) - chat_deletenpcchat(nd); + chat->delete_npc_chat(nd); return true; } @@ -10007,18 +10668,17 @@ BUILDIN(delwaitingroom) /// /// kickwaitingroomall "<npc_name>"; /// kickwaitingroomall; -BUILDIN(waitingroomkickall) -{ +BUILDIN(waitingroomkickall) { struct npc_data* nd; struct chat_data* cd; - + if( script_hasdata(st,2) ) - nd = npc_name2id(script_getstr(st,2)); + nd = npc->name2id(script_getstr(st,2)); else - nd = (struct npc_data *)iMap->id2bl(st->oid); - - if( nd != NULL && (cd=(struct chat_data *)iMap->id2bl(nd->chat_id)) != NULL ) - chat_npckickall(cd); + nd = (struct npc_data *)map->id2bl(st->oid); + + if( nd != NULL && (cd=(struct chat_data *)map->id2bl(nd->chat_id)) != NULL ) + chat->npc_kick_all(cd); return true; } @@ -10026,18 +10686,17 @@ BUILDIN(waitingroomkickall) /// /// enablewaitingroomevent "<npc_name>"; /// enablewaitingroomevent; -BUILDIN(enablewaitingroomevent) -{ +BUILDIN(enablewaitingroomevent) { struct npc_data* nd; struct chat_data* cd; - + if( script_hasdata(st,2) ) - nd = npc_name2id(script_getstr(st, 2)); + nd = npc->name2id(script_getstr(st, 2)); else - nd = (struct npc_data *)iMap->id2bl(st->oid); - - if( nd != NULL && (cd=(struct chat_data *)iMap->id2bl(nd->chat_id)) != NULL ) - chat_enableevent(cd); + nd = (struct npc_data *)map->id2bl(st->oid); + + if( nd != NULL && (cd=(struct chat_data *)map->id2bl(nd->chat_id)) != NULL ) + chat->enable_event(cd); return true; } @@ -10045,18 +10704,17 @@ BUILDIN(enablewaitingroomevent) /// /// disablewaitingroomevent "<npc_name>"; /// disablewaitingroomevent; -BUILDIN(disablewaitingroomevent) -{ +BUILDIN(disablewaitingroomevent) { struct npc_data *nd; struct chat_data *cd; - + if( script_hasdata(st,2) ) - nd = npc_name2id(script_getstr(st, 2)); + nd = npc->name2id(script_getstr(st, 2)); else - nd = (struct npc_data *)iMap->id2bl(st->oid); - - if( nd != NULL && (cd=(struct chat_data *)iMap->id2bl(nd->chat_id)) != NULL ) - chat_disableevent(cd); + nd = (struct npc_data *)map->id2bl(st->oid); + + if( nd != NULL && (cd=(struct chat_data *)map->id2bl(nd->chat_id)) != NULL ) + chat->disable_event(cd); return true; } @@ -10074,26 +10732,23 @@ BUILDIN(disablewaitingroomevent) /// /// getwaitingroomstate(<type>,"<npc_name>") -> <info> /// getwaitingroomstate(<type>) -> <info> -BUILDIN(getwaitingroomstate) -{ +BUILDIN(getwaitingroomstate) { struct npc_data *nd; struct chat_data *cd; int type; - + type = script_getnum(st,2); if( script_hasdata(st,3) ) - nd = npc_name2id(script_getstr(st, 3)); + nd = npc->name2id(script_getstr(st, 3)); else - nd = (struct npc_data *)iMap->id2bl(st->oid); - - if( nd == NULL || (cd=(struct chat_data *)iMap->id2bl(nd->chat_id)) == NULL ) - { + nd = (struct npc_data *)map->id2bl(st->oid); + + if( nd == NULL || (cd=(struct chat_data *)map->id2bl(nd->chat_id)) == NULL ) { script_pushint(st, -1); return true; } - - switch(type) - { + + switch(type) { case 0: script_pushint(st, cd->users); break; case 1: script_pushint(st, cd->limit); break; case 2: script_pushint(st, cd->trigger&0x7f); break; @@ -10120,8 +10775,7 @@ BUILDIN(getwaitingroomstate) /// /// warpwaitingpc "<map name>",<x>,<y>,<number of players>; /// warpwaitingpc "<map name>",<x>,<y>; -BUILDIN(warpwaitingpc) -{ +BUILDIN(warpwaitingpc) { int x; int y; int i; @@ -10130,47 +10784,46 @@ BUILDIN(warpwaitingpc) struct npc_data* nd; struct chat_data* cd; TBL_PC* sd; - - nd = (struct npc_data *)iMap->id2bl(st->oid); - if( nd == NULL || (cd=(struct chat_data *)iMap->id2bl(nd->chat_id)) == NULL ) + + nd = (struct npc_data *)map->id2bl(st->oid); + if( nd == NULL || (cd=(struct chat_data *)map->id2bl(nd->chat_id)) == NULL ) return true; - + map_name = script_getstr(st,2); x = script_getnum(st,3); y = script_getnum(st,4); n = cd->trigger&0x7f; - + if( script_hasdata(st,5) ) n = script_getnum(st,5); - - for( i = 0; i < n && cd->users > 0; i++ ) - { + + for( i = 0; i < n && cd->users > 0; i++ ) { sd = cd->usersd[0]; - - if( strcmp(map_name,"SavePoint") == 0 && map[sd->bl.m].flag.noteleport ) - {// can't teleport on this map + + if( strcmp(map_name,"SavePoint") == 0 && map->list[sd->bl.m].flag.noteleport ) { + // can't teleport on this map break; } - - if( cd->zeny ) - {// fee set - if( (uint32)sd->status.zeny < cd->zeny ) - {// no zeny to cover set fee + + if( cd->zeny ) { + // fee set + if( (uint32)sd->status.zeny < cd->zeny ) { + // no zeny to cover set fee break; } pc->payzeny(sd, cd->zeny, LOG_TYPE_NPC, NULL); } - - mapreg_setreg(reference_uid(add_str("$@warpwaitingpc"), i), sd->bl.id); - + + mapreg->setreg(reference_uid(script->add_str("$@warpwaitingpc"), i), sd->bl.id); + if( strcmp(map_name,"Random") == 0 ) pc->randomwarp(sd,CLR_TELEPORT); else if( strcmp(map_name,"SavePoint") == 0 ) pc->setpos(sd, sd->status.save_point.map, sd->status.save_point.x, sd->status.save_point.y, CLR_TELEPORT); else - pc->setpos(sd, mapindex_name2id(map_name), x, y, CLR_OUTSIGHT); + pc->setpos(sd, script->mapindexname2id(st,map_name), x, y, CLR_OUTSIGHT); } - mapreg_setreg(add_str("$@warpwaitingpcnum"), i); + mapreg->setreg(script->add_str("$@warpwaitingpcnum"), i); return true; } @@ -10183,7 +10836,7 @@ BUILDIN(warpwaitingpc) /// @param st Script state to detach the character from. void script_detach_rid(struct script_state* st) { if(st->rid) { - script_detach_state(st, false); + script->detach_state(st, false); st->rid = 0; } } @@ -10191,15 +10844,14 @@ void script_detach_rid(struct script_state* st) { /*========================================== * Attach sd char id to script and detach current one if any *------------------------------------------*/ -BUILDIN(attachrid) -{ +BUILDIN(attachrid) { int rid = script_getnum(st,2); - - if (iMap->id2sd(rid) != NULL) { - script_detach_rid(st); - + + if (map->id2sd(rid) != NULL) { + script->detach_rid(st); + st->rid = rid; - script_attach_state(st); + script->attach_state(st); script_pushint(st,1); } else script_pushint(st,0); @@ -10210,15 +10862,14 @@ BUILDIN(attachrid) *------------------------------------------*/ BUILDIN(detachrid) { - script_detach_rid(st); + script->detach_rid(st); return true; } /*========================================== * Chk if account connected, (and charid from account if specified) *------------------------------------------*/ -BUILDIN(isloggedin) -{ - TBL_PC* sd = iMap->id2sd(script_getnum(st,2)); +BUILDIN(isloggedin) { + TBL_PC* sd = map->id2sd(script_getnum(st,2)); if (script_hasdata(st,3) && sd && sd->status.char_id != script_getnum(st,3)) sd = NULL; @@ -10230,26 +10881,25 @@ BUILDIN(isloggedin) /*========================================== * *------------------------------------------*/ -BUILDIN(setmapflagnosave) -{ +BUILDIN(setmapflagnosave) { int16 m,x,y; - unsigned short mapindex; + unsigned short map_index; const char *str,*str2; - + str=script_getstr(st,2); str2=script_getstr(st,3); x=script_getnum(st,4); y=script_getnum(st,5); - m = iMap->mapname2mapid(str); - mapindex = mapindex_name2id(str2); - - if(m >= 0 && mapindex) { - map[m].flag.nosave=1; - map[m].save.map=mapindex; - map[m].save.x=x; - map[m].save.y=y; + m = map->mapname2mapid(str); + map_index = script->mapindexname2id(st,str2); + + if(m >= 0 && map_index) { + map->list[m].flag.nosave=1; + map->list[m].save.map=map_index; + map->list[m].save.x=x; + map->list[m].save.y=y; } - + return true; } @@ -10257,72 +10907,74 @@ BUILDIN(getmapflag) { int16 m,i; const char *str; - + str=script_getstr(st,2); i=script_getnum(st,3); - - m = iMap->mapname2mapid(str); + + m = map->mapname2mapid(str); if(m >= 0) { switch(i) { - case MF_NOMEMO: script_pushint(st,map[m].flag.nomemo); break; - case MF_NOTELEPORT: script_pushint(st,map[m].flag.noteleport); break; - case MF_NOSAVE: script_pushint(st,map[m].flag.nosave); break; - case MF_NOBRANCH: script_pushint(st,map[m].flag.nobranch); break; - case MF_NOPENALTY: script_pushint(st,map[m].flag.noexppenalty); break; - case MF_NOZENYPENALTY: script_pushint(st,map[m].flag.nozenypenalty); break; - case MF_PVP: script_pushint(st,map[m].flag.pvp); break; - case MF_PVP_NOPARTY: script_pushint(st,map[m].flag.pvp_noparty); break; - case MF_PVP_NOGUILD: script_pushint(st,map[m].flag.pvp_noguild); break; - case MF_GVG: script_pushint(st,map[m].flag.gvg); break; - case MF_GVG_NOPARTY: script_pushint(st,map[m].flag.gvg_noparty); break; - case MF_NOTRADE: script_pushint(st,map[m].flag.notrade); break; - case MF_NOSKILL: script_pushint(st,map[m].flag.noskill); break; - case MF_NOWARP: script_pushint(st,map[m].flag.nowarp); break; - case MF_PARTYLOCK: script_pushint(st,map[m].flag.partylock); break; - case MF_NOICEWALL: script_pushint(st,map[m].flag.noicewall); break; - case MF_SNOW: script_pushint(st,map[m].flag.snow); break; - case MF_FOG: script_pushint(st,map[m].flag.fog); break; - case MF_SAKURA: script_pushint(st,map[m].flag.sakura); break; - case MF_LEAVES: script_pushint(st,map[m].flag.leaves); break; - case MF_CLOUDS: script_pushint(st,map[m].flag.clouds); break; - case MF_CLOUDS2: script_pushint(st,map[m].flag.clouds2); break; - case MF_FIREWORKS: script_pushint(st,map[m].flag.fireworks); break; - case MF_GVG_CASTLE: script_pushint(st,map[m].flag.gvg_castle); break; - case MF_GVG_DUNGEON: script_pushint(st,map[m].flag.gvg_dungeon); break; - case MF_NIGHTENABLED: script_pushint(st,map[m].flag.nightenabled); break; - case MF_NOBASEEXP: script_pushint(st,map[m].flag.nobaseexp); break; - case MF_NOJOBEXP: script_pushint(st,map[m].flag.nojobexp); break; - case MF_NOMOBLOOT: script_pushint(st,map[m].flag.nomobloot); break; - case MF_NOMVPLOOT: script_pushint(st,map[m].flag.nomvploot); break; - case MF_NORETURN: script_pushint(st,map[m].flag.noreturn); break; - case MF_NOWARPTO: script_pushint(st,map[m].flag.nowarpto); break; - case MF_NIGHTMAREDROP: script_pushint(st,map[m].flag.pvp_nightmaredrop); break; - case MF_NOCOMMAND: script_pushint(st,map[m].nocommand); break; - case MF_NODROP: script_pushint(st,map[m].flag.nodrop); break; - case MF_JEXP: script_pushint(st,map[m].jexp); break; - case MF_BEXP: script_pushint(st,map[m].bexp); break; - case MF_NOVENDING: script_pushint(st,map[m].flag.novending); break; - case MF_LOADEVENT: script_pushint(st,map[m].flag.loadevent); break; - case MF_NOCHAT: script_pushint(st,map[m].flag.nochat); break; - case MF_NOEXPPENALTY: script_pushint(st,map[m].flag.noexppenalty ); break; - case MF_GUILDLOCK: script_pushint(st,map[m].flag.guildlock); break; - case MF_TOWN: script_pushint(st,map[m].flag.town); break; - case MF_AUTOTRADE: script_pushint(st,map[m].flag.autotrade); break; - case MF_ALLOWKS: script_pushint(st,map[m].flag.allowks); break; - case MF_MONSTER_NOTELEPORT: script_pushint(st,map[m].flag.monster_noteleport); break; - case MF_PVP_NOCALCRANK: script_pushint(st,map[m].flag.pvp_nocalcrank); break; - case MF_BATTLEGROUND: script_pushint(st,map[m].flag.battleground); break; - case MF_RESET: script_pushint(st,map[m].flag.reset); break; + case MF_NOMEMO: script_pushint(st,map->list[m].flag.nomemo); break; + case MF_NOTELEPORT: script_pushint(st,map->list[m].flag.noteleport); break; + case MF_NOSAVE: script_pushint(st,map->list[m].flag.nosave); break; + case MF_NOBRANCH: script_pushint(st,map->list[m].flag.nobranch); break; + case MF_NOPENALTY: script_pushint(st,map->list[m].flag.noexppenalty); break; + case MF_NOZENYPENALTY: script_pushint(st,map->list[m].flag.nozenypenalty); break; + case MF_PVP: script_pushint(st,map->list[m].flag.pvp); break; + case MF_PVP_NOPARTY: script_pushint(st,map->list[m].flag.pvp_noparty); break; + case MF_PVP_NOGUILD: script_pushint(st,map->list[m].flag.pvp_noguild); break; + case MF_GVG: script_pushint(st,map->list[m].flag.gvg); break; + case MF_GVG_NOPARTY: script_pushint(st,map->list[m].flag.gvg_noparty); break; + case MF_NOTRADE: script_pushint(st,map->list[m].flag.notrade); break; + case MF_NOSKILL: script_pushint(st,map->list[m].flag.noskill); break; + case MF_NOWARP: script_pushint(st,map->list[m].flag.nowarp); break; + case MF_PARTYLOCK: script_pushint(st,map->list[m].flag.partylock); break; + case MF_NOICEWALL: script_pushint(st,map->list[m].flag.noicewall); break; + case MF_SNOW: script_pushint(st,map->list[m].flag.snow); break; + case MF_FOG: script_pushint(st,map->list[m].flag.fog); break; + case MF_SAKURA: script_pushint(st,map->list[m].flag.sakura); break; + case MF_LEAVES: script_pushint(st,map->list[m].flag.leaves); break; + case MF_CLOUDS: script_pushint(st,map->list[m].flag.clouds); break; + case MF_CLOUDS2: script_pushint(st,map->list[m].flag.clouds2); break; + case MF_FIREWORKS: script_pushint(st,map->list[m].flag.fireworks); break; + case MF_GVG_CASTLE: script_pushint(st,map->list[m].flag.gvg_castle); break; + case MF_GVG_DUNGEON: script_pushint(st,map->list[m].flag.gvg_dungeon); break; + case MF_NIGHTENABLED: script_pushint(st,map->list[m].flag.nightenabled); break; + case MF_NOBASEEXP: script_pushint(st,map->list[m].flag.nobaseexp); break; + case MF_NOJOBEXP: script_pushint(st,map->list[m].flag.nojobexp); break; + case MF_NOMOBLOOT: script_pushint(st,map->list[m].flag.nomobloot); break; + case MF_NOMVPLOOT: script_pushint(st,map->list[m].flag.nomvploot); break; + case MF_NORETURN: script_pushint(st,map->list[m].flag.noreturn); break; + case MF_NOWARPTO: script_pushint(st,map->list[m].flag.nowarpto); break; + case MF_NIGHTMAREDROP: script_pushint(st,map->list[m].flag.pvp_nightmaredrop); break; + case MF_NOCOMMAND: script_pushint(st,map->list[m].nocommand); break; + case MF_NODROP: script_pushint(st,map->list[m].flag.nodrop); break; + case MF_JEXP: script_pushint(st,map->list[m].jexp); break; + case MF_BEXP: script_pushint(st,map->list[m].bexp); break; + case MF_NOVENDING: script_pushint(st,map->list[m].flag.novending); break; + case MF_LOADEVENT: script_pushint(st,map->list[m].flag.loadevent); break; + case MF_NOCHAT: script_pushint(st,map->list[m].flag.nochat); break; + case MF_NOEXPPENALTY: script_pushint(st,map->list[m].flag.noexppenalty ); break; + case MF_GUILDLOCK: script_pushint(st,map->list[m].flag.guildlock); break; + case MF_TOWN: script_pushint(st,map->list[m].flag.town); break; + case MF_AUTOTRADE: script_pushint(st,map->list[m].flag.autotrade); break; + case MF_ALLOWKS: script_pushint(st,map->list[m].flag.allowks); break; + case MF_MONSTER_NOTELEPORT: script_pushint(st,map->list[m].flag.monster_noteleport); break; + case MF_PVP_NOCALCRANK: script_pushint(st,map->list[m].flag.pvp_nocalcrank); break; + case MF_BATTLEGROUND: script_pushint(st,map->list[m].flag.battleground); break; + case MF_RESET: script_pushint(st,map->list[m].flag.reset); break; + case MF_NOTOMB: script_pushint(st,map->list[m].flag.notomb); break; + case MF_NOCASHSHOP: script_pushint(st,map->list[m].flag.nocashshop); break; } } - + return true; } /* pvp timer handling */ -static int script_mapflag_pvp_sub(struct block_list *bl,va_list ap) { +int script_mapflag_pvp_sub(struct block_list *bl,va_list ap) { TBL_PC* sd = (TBL_PC*)bl; if (sd->pvp_timer == INVALID_TIMER) { - sd->pvp_timer = iTimer->add_timer(iTimer->gettick() + 200, pc->calc_pvprank_timer, sd->bl.id, 0); + sd->pvp_timer = timer->add(timer->gettick() + 200, pc->calc_pvprank_timer, sd->bl.id, 0); sd->pvp_rank = 0; sd->pvp_lastusers = 0; sd->pvp_point = 5; @@ -10333,227 +10985,229 @@ static int script_mapflag_pvp_sub(struct block_list *bl,va_list ap) { clif->maptypeproperty2(&sd->bl,SELF); return 0; } -BUILDIN(setmapflag) -{ +BUILDIN(setmapflag) { int16 m,i; const char *str, *val2 = NULL; - struct script_data* data; int val=0; - + str=script_getstr(st,2); - + i = script_getnum(st, 3); - - if(script_hasdata(st,4)){ - data = script_getdata(st,4); - script->get_val(st, data); - - - if( data_isstring(data) ) + + if (script_hasdata(st,4)) { + if (script_isstringtype(st, 4)) { val2 = script_getstr(st, 4); - else + } else if (script_isinttype(st, 4)) { val = script_getnum(st, 4); - + } else { + ShowError("buildin_setmapflag: invalid data type for argument 3.\n"); + return false; + } } - m = iMap->mapname2mapid(str); - + m = map->mapname2mapid(str); + if(m >= 0) { switch(i) { - case MF_NOMEMO: map[m].flag.nomemo = 1; break; - case MF_NOTELEPORT: map[m].flag.noteleport = 1; break; - case MF_NOSAVE: map[m].flag.nosave = 1; break; - case MF_NOBRANCH: map[m].flag.nobranch = 1; break; - case MF_NOPENALTY: map[m].flag.noexppenalty = 1; map[m].flag.nozenypenalty = 1; break; - case MF_NOZENYPENALTY: map[m].flag.nozenypenalty = 1; break; + case MF_NOMEMO: map->list[m].flag.nomemo = 1; break; + case MF_NOTELEPORT: map->list[m].flag.noteleport = 1; break; + case MF_NOSAVE: map->list[m].flag.nosave = 1; break; + case MF_NOBRANCH: map->list[m].flag.nobranch = 1; break; + case MF_NOPENALTY: map->list[m].flag.noexppenalty = 1; map->list[m].flag.nozenypenalty = 1; break; + case MF_NOZENYPENALTY: map->list[m].flag.nozenypenalty = 1; break; case MF_PVP: - map[m].flag.pvp = 1; + map->list[m].flag.pvp = 1; if( !battle_config.pk_mode ) { - iMap->foreachinmap(script_mapflag_pvp_sub,m,BL_PC); + map->foreachinmap(script->mapflag_pvp_sub,m,BL_PC); } break; - case MF_PVP_NOPARTY: map[m].flag.pvp_noparty = 1; break; - case MF_PVP_NOGUILD: map[m].flag.pvp_noguild = 1; break; + case MF_PVP_NOPARTY: map->list[m].flag.pvp_noparty = 1; break; + case MF_PVP_NOGUILD: map->list[m].flag.pvp_noguild = 1; break; case MF_GVG: { struct block_list bl; - map[m].flag.gvg = 1; + map->list[m].flag.gvg = 1; clif->map_property_mapall(m, MAPPROPERTY_AGITZONE); bl.type = BL_NUL; bl.m = m; clif->maptypeproperty2(&bl,ALL_SAMEMAP); } break; - case MF_GVG_NOPARTY: map[m].flag.gvg_noparty = 1; break; - case MF_NOTRADE: map[m].flag.notrade = 1; break; - case MF_NOSKILL: map[m].flag.noskill = 1; break; - case MF_NOWARP: map[m].flag.nowarp = 1; break; - case MF_PARTYLOCK: map[m].flag.partylock = 1; break; - case MF_NOICEWALL: map[m].flag.noicewall = 1; break; - case MF_SNOW: map[m].flag.snow = 1; break; - case MF_FOG: map[m].flag.fog = 1; break; - case MF_SAKURA: map[m].flag.sakura = 1; break; - case MF_LEAVES: map[m].flag.leaves = 1; break; - case MF_CLOUDS: map[m].flag.clouds = 1; break; - case MF_CLOUDS2: map[m].flag.clouds2 = 1; break; - case MF_FIREWORKS: map[m].flag.fireworks = 1; break; - case MF_GVG_CASTLE: map[m].flag.gvg_castle = 1; break; - case MF_GVG_DUNGEON: map[m].flag.gvg_dungeon = 1; break; - case MF_NIGHTENABLED: map[m].flag.nightenabled = 1; break; - case MF_NOBASEEXP: map[m].flag.nobaseexp = 1; break; - case MF_NOJOBEXP: map[m].flag.nojobexp = 1; break; - case MF_NOMOBLOOT: map[m].flag.nomobloot = 1; break; - case MF_NOMVPLOOT: map[m].flag.nomvploot = 1; break; - case MF_NORETURN: map[m].flag.noreturn = 1; break; - case MF_NOWARPTO: map[m].flag.nowarpto = 1; break; - case MF_NIGHTMAREDROP: map[m].flag.pvp_nightmaredrop = 1; break; - case MF_ZONE: { - char zone[6] = "zone\0"; - char empty[1] = "\0"; - char params[MAP_ZONE_MAPFLAG_LENGTH]; - memcpy(params, val2, MAP_ZONE_MAPFLAG_LENGTH); - npc_parse_mapflag(map[m].name, empty, zone, params, empty, empty, empty); - } + case MF_GVG_NOPARTY: map->list[m].flag.gvg_noparty = 1; break; + case MF_NOTRADE: map->list[m].flag.notrade = 1; break; + case MF_NOSKILL: map->list[m].flag.noskill = 1; break; + case MF_NOWARP: map->list[m].flag.nowarp = 1; break; + case MF_PARTYLOCK: map->list[m].flag.partylock = 1; break; + case MF_NOICEWALL: map->list[m].flag.noicewall = 1; break; + case MF_SNOW: map->list[m].flag.snow = 1; break; + case MF_FOG: map->list[m].flag.fog = 1; break; + case MF_SAKURA: map->list[m].flag.sakura = 1; break; + case MF_LEAVES: map->list[m].flag.leaves = 1; break; + case MF_CLOUDS: map->list[m].flag.clouds = 1; break; + case MF_CLOUDS2: map->list[m].flag.clouds2 = 1; break; + case MF_FIREWORKS: map->list[m].flag.fireworks = 1; break; + case MF_GVG_CASTLE: map->list[m].flag.gvg_castle = 1; break; + case MF_GVG_DUNGEON: map->list[m].flag.gvg_dungeon = 1; break; + case MF_NIGHTENABLED: map->list[m].flag.nightenabled = 1; break; + case MF_NOBASEEXP: map->list[m].flag.nobaseexp = 1; break; + case MF_NOJOBEXP: map->list[m].flag.nojobexp = 1; break; + case MF_NOMOBLOOT: map->list[m].flag.nomobloot = 1; break; + case MF_NOMVPLOOT: map->list[m].flag.nomvploot = 1; break; + case MF_NORETURN: map->list[m].flag.noreturn = 1; break; + case MF_NOWARPTO: map->list[m].flag.nowarpto = 1; break; + case MF_NIGHTMAREDROP: map->list[m].flag.pvp_nightmaredrop = 1; break; + case MF_ZONE: + if( val2 ) { + char zone[6] = "zone\0"; + char empty[1] = "\0"; + char params[MAP_ZONE_MAPFLAG_LENGTH]; + memcpy(params, val2, MAP_ZONE_MAPFLAG_LENGTH); + npc->parse_mapflag(map->list[m].name, empty, zone, params, empty, empty, empty, NULL); + } break; - case MF_NOCOMMAND: map[m].nocommand = (val <= 0) ? 100 : val; break; - case MF_NODROP: map[m].flag.nodrop = 1; break; - case MF_JEXP: map[m].jexp = (val <= 0) ? 100 : val; break; - case MF_BEXP: map[m].bexp = (val <= 0) ? 100 : val; break; - case MF_NOVENDING: map[m].flag.novending = 1; break; - case MF_LOADEVENT: map[m].flag.loadevent = 1; break; - case MF_NOCHAT: map[m].flag.nochat = 1; break; - case MF_NOEXPPENALTY: map[m].flag.noexppenalty = 1; break; - case MF_GUILDLOCK: map[m].flag.guildlock = 1; break; - case MF_TOWN: map[m].flag.town = 1; break; - case MF_AUTOTRADE: map[m].flag.autotrade = 1; break; - case MF_ALLOWKS: map[m].flag.allowks = 1; break; - case MF_MONSTER_NOTELEPORT: map[m].flag.monster_noteleport = 1; break; - case MF_PVP_NOCALCRANK: map[m].flag.pvp_nocalcrank = 1; break; - case MF_BATTLEGROUND: map[m].flag.battleground = (val <= 0 || val > 2) ? 1 : val; break; - case MF_RESET: map[m].flag.reset = 1; break; + case MF_NOCOMMAND: map->list[m].nocommand = (val <= 0) ? 100 : val; break; + case MF_NODROP: map->list[m].flag.nodrop = 1; break; + case MF_JEXP: map->list[m].jexp = (val <= 0) ? 100 : val; break; + case MF_BEXP: map->list[m].bexp = (val <= 0) ? 100 : val; break; + case MF_NOVENDING: map->list[m].flag.novending = 1; break; + case MF_LOADEVENT: map->list[m].flag.loadevent = 1; break; + case MF_NOCHAT: map->list[m].flag.nochat = 1; break; + case MF_NOEXPPENALTY: map->list[m].flag.noexppenalty = 1; break; + case MF_GUILDLOCK: map->list[m].flag.guildlock = 1; break; + case MF_TOWN: map->list[m].flag.town = 1; break; + case MF_AUTOTRADE: map->list[m].flag.autotrade = 1; break; + case MF_ALLOWKS: map->list[m].flag.allowks = 1; break; + case MF_MONSTER_NOTELEPORT: map->list[m].flag.monster_noteleport = 1; break; + case MF_PVP_NOCALCRANK: map->list[m].flag.pvp_nocalcrank = 1; break; + case MF_BATTLEGROUND: map->list[m].flag.battleground = (val <= 0 || val > 2) ? 1 : val; break; + case MF_RESET: map->list[m].flag.reset = 1; break; + case MF_NOTOMB: map->list[m].flag.notomb = 1; break; + case MF_NOCASHSHOP: map->list[m].flag.nocashshop = 1; break; } } - + return true; } -BUILDIN(removemapflag) -{ +BUILDIN(removemapflag) { int16 m,i; const char *str; - int val=0; - + str=script_getstr(st,2); i=script_getnum(st,3); - if(script_hasdata(st,4)){ - val=script_getnum(st,4); - } - m = iMap->mapname2mapid(str); + + m = map->mapname2mapid(str); if(m >= 0) { switch(i) { - case MF_NOMEMO: map[m].flag.nomemo = 0; break; - case MF_NOTELEPORT: map[m].flag.noteleport = 0; break; - case MF_NOSAVE: map[m].flag.nosave = 0; break; - case MF_NOBRANCH: map[m].flag.nobranch = 0; break; - case MF_NOPENALTY: map[m].flag.noexppenalty = 0; map[m].flag.nozenypenalty = 0; break; - case MF_NOZENYPENALTY: map[m].flag.nozenypenalty = 0; break; + case MF_NOMEMO: map->list[m].flag.nomemo = 0; break; + case MF_NOTELEPORT: map->list[m].flag.noteleport = 0; break; + case MF_NOSAVE: map->list[m].flag.nosave = 0; break; + case MF_NOBRANCH: map->list[m].flag.nobranch = 0; break; + case MF_NOPENALTY: map->list[m].flag.noexppenalty = 0; map->list[m].flag.nozenypenalty = 0; break; + case MF_NOZENYPENALTY: map->list[m].flag.nozenypenalty = 0; break; case MF_PVP: { struct block_list bl; bl.type = BL_NUL; bl.m = m; - map[m].flag.pvp = 0; + map->list[m].flag.pvp = 0; clif->map_property_mapall(m, MAPPROPERTY_NOTHING); clif->maptypeproperty2(&bl,ALL_SAMEMAP); } break; - case MF_PVP_NOPARTY: map[m].flag.pvp_noparty = 0; break; - case MF_PVP_NOGUILD: map[m].flag.pvp_noguild = 0; break; + case MF_PVP_NOPARTY: map->list[m].flag.pvp_noparty = 0; break; + case MF_PVP_NOGUILD: map->list[m].flag.pvp_noguild = 0; break; case MF_GVG: { struct block_list bl; bl.type = BL_NUL; bl.m = m; - map[m].flag.gvg = 0; + map->list[m].flag.gvg = 0; clif->map_property_mapall(m, MAPPROPERTY_NOTHING); clif->maptypeproperty2(&bl,ALL_SAMEMAP); } break; - case MF_GVG_NOPARTY: map[m].flag.gvg_noparty = 0; break; - case MF_NOTRADE: map[m].flag.notrade = 0; break; - case MF_NOSKILL: map[m].flag.noskill = 0; break; - case MF_NOWARP: map[m].flag.nowarp = 0; break; - case MF_PARTYLOCK: map[m].flag.partylock = 0; break; - case MF_NOICEWALL: map[m].flag.noicewall = 0; break; - case MF_SNOW: map[m].flag.snow = 0; break; - case MF_FOG: map[m].flag.fog = 0; break; - case MF_SAKURA: map[m].flag.sakura = 0; break; - case MF_LEAVES: map[m].flag.leaves = 0; break; - case MF_CLOUDS: map[m].flag.clouds = 0; break; - case MF_CLOUDS2: map[m].flag.clouds2 = 0; break; - case MF_FIREWORKS: map[m].flag.fireworks = 0; break; - case MF_GVG_CASTLE: map[m].flag.gvg_castle = 0; break; - case MF_GVG_DUNGEON: map[m].flag.gvg_dungeon = 0; break; - case MF_NIGHTENABLED: map[m].flag.nightenabled = 0; break; - case MF_NOBASEEXP: map[m].flag.nobaseexp = 0; break; - case MF_NOJOBEXP: map[m].flag.nojobexp = 0; break; - case MF_NOMOBLOOT: map[m].flag.nomobloot = 0; break; - case MF_NOMVPLOOT: map[m].flag.nomvploot = 0; break; - case MF_NORETURN: map[m].flag.noreturn = 0; break; - case MF_NOWARPTO: map[m].flag.nowarpto = 0; break; - case MF_NIGHTMAREDROP: map[m].flag.pvp_nightmaredrop = 0; break; + case MF_GVG_NOPARTY: map->list[m].flag.gvg_noparty = 0; break; + case MF_NOTRADE: map->list[m].flag.notrade = 0; break; + case MF_NOSKILL: map->list[m].flag.noskill = 0; break; + case MF_NOWARP: map->list[m].flag.nowarp = 0; break; + case MF_PARTYLOCK: map->list[m].flag.partylock = 0; break; + case MF_NOICEWALL: map->list[m].flag.noicewall = 0; break; + case MF_SNOW: map->list[m].flag.snow = 0; break; + case MF_FOG: map->list[m].flag.fog = 0; break; + case MF_SAKURA: map->list[m].flag.sakura = 0; break; + case MF_LEAVES: map->list[m].flag.leaves = 0; break; + case MF_CLOUDS: map->list[m].flag.clouds = 0; break; + case MF_CLOUDS2: map->list[m].flag.clouds2 = 0; break; + case MF_FIREWORKS: map->list[m].flag.fireworks = 0; break; + case MF_GVG_CASTLE: map->list[m].flag.gvg_castle = 0; break; + case MF_GVG_DUNGEON: map->list[m].flag.gvg_dungeon = 0; break; + case MF_NIGHTENABLED: map->list[m].flag.nightenabled = 0; break; + case MF_NOBASEEXP: map->list[m].flag.nobaseexp = 0; break; + case MF_NOJOBEXP: map->list[m].flag.nojobexp = 0; break; + case MF_NOMOBLOOT: map->list[m].flag.nomobloot = 0; break; + case MF_NOMVPLOOT: map->list[m].flag.nomvploot = 0; break; + case MF_NORETURN: map->list[m].flag.noreturn = 0; break; + case MF_NOWARPTO: map->list[m].flag.nowarpto = 0; break; + case MF_NIGHTMAREDROP: map->list[m].flag.pvp_nightmaredrop = 0; break; case MF_ZONE: - iMap->zone_change2(m, map[m].prev_zone); + map->zone_change2(m, map->list[m].prev_zone); break; - case MF_NOCOMMAND: map[m].nocommand = 0; break; - case MF_NODROP: map[m].flag.nodrop = 0; break; - case MF_JEXP: map[m].jexp = 0; break; - case MF_BEXP: map[m].bexp = 0; break; - case MF_NOVENDING: map[m].flag.novending = 0; break; - case MF_LOADEVENT: map[m].flag.loadevent = 0; break; - case MF_NOCHAT: map[m].flag.nochat = 0; break; - case MF_NOEXPPENALTY: map[m].flag.noexppenalty = 0; break; - case MF_GUILDLOCK: map[m].flag.guildlock = 0; break; - case MF_TOWN: map[m].flag.town = 0; break; - case MF_AUTOTRADE: map[m].flag.autotrade = 0; break; - case MF_ALLOWKS: map[m].flag.allowks = 0; break; - case MF_MONSTER_NOTELEPORT: map[m].flag.monster_noteleport = 0; break; - case MF_PVP_NOCALCRANK: map[m].flag.pvp_nocalcrank = 0; break; - case MF_BATTLEGROUND: map[m].flag.battleground = 0; break; - case MF_RESET: map[m].flag.reset = 0; break; + case MF_NOCOMMAND: map->list[m].nocommand = 0; break; + case MF_NODROP: map->list[m].flag.nodrop = 0; break; + case MF_JEXP: map->list[m].jexp = 0; break; + case MF_BEXP: map->list[m].bexp = 0; break; + case MF_NOVENDING: map->list[m].flag.novending = 0; break; + case MF_LOADEVENT: map->list[m].flag.loadevent = 0; break; + case MF_NOCHAT: map->list[m].flag.nochat = 0; break; + case MF_NOEXPPENALTY: map->list[m].flag.noexppenalty = 0; break; + case MF_GUILDLOCK: map->list[m].flag.guildlock = 0; break; + case MF_TOWN: map->list[m].flag.town = 0; break; + case MF_AUTOTRADE: map->list[m].flag.autotrade = 0; break; + case MF_ALLOWKS: map->list[m].flag.allowks = 0; break; + case MF_MONSTER_NOTELEPORT: map->list[m].flag.monster_noteleport = 0; break; + case MF_PVP_NOCALCRANK: map->list[m].flag.pvp_nocalcrank = 0; break; + case MF_BATTLEGROUND: map->list[m].flag.battleground = 0; break; + case MF_RESET: map->list[m].flag.reset = 0; break; + case MF_NOTOMB: map->list[m].flag.notomb = 0; break; + case MF_NOCASHSHOP: map->list[m].flag.nocashshop = 0; break; } } - + return true; } -BUILDIN(pvpon) -{ +BUILDIN(pvpon) { int16 m; const char *str; TBL_PC* sd = NULL; struct s_mapiterator* iter; struct block_list bl; - + str = script_getstr(st,2); - m = iMap->mapname2mapid(str); - if( m < 0 || map[m].flag.pvp ) + m = map->mapname2mapid(str); + if( m < 0 || map->list[m].flag.pvp ) return true; // nothing to do - - iMap->zone_change2(m, strdb_get(zone_db, MAP_ZONE_PVP_NAME)); - map[m].flag.pvp = 1; + + if( !strdb_exists(map->zone_db,MAP_ZONE_PVP_NAME) ) { + ShowError("buildin_pvpon: zone_db missing '%s'\n",MAP_ZONE_PVP_NAME); + return true; + } + + map->zone_change2(m, strdb_get(map->zone_db, MAP_ZONE_PVP_NAME)); + map->list[m].flag.pvp = 1; clif->map_property_mapall(m, MAPPROPERTY_FREEPVPZONE); bl.type = BL_NUL; bl.m = m; clif->maptypeproperty2(&bl,ALL_SAMEMAP); - - + + if(battle_config.pk_mode) // disable ranking functions if pk_mode is on [Valaris] return true; - + iter = mapit_getallusers(); for( sd = (TBL_PC*)mapit->first(iter); mapit->exists(iter); sd = (TBL_PC*)mapit->next(iter) ) { if( sd->bl.m != m || sd->pvp_timer != INVALID_TIMER ) continue; // not applicable - - sd->pvp_timer = iTimer->add_timer(iTimer->gettick()+200,pc->calc_pvprank_timer,sd->bl.id,0); + + sd->pvp_timer = timer->add(timer->gettick()+200,pc->calc_pvprank_timer,sd->bl.id,0); sd->pvp_rank = 0; sd->pvp_lastusers = 0; sd->pvp_point = 5; @@ -10561,227 +11215,218 @@ BUILDIN(pvpon) sd->pvp_lost = 0; } mapit->free(iter); - + return true; } -static int buildin_pvpoff_sub(struct block_list *bl,va_list ap) +int buildin_pvpoff_sub(struct block_list *bl,va_list ap) { TBL_PC* sd = (TBL_PC*)bl; clif->pvpset(sd, 0, 0, 2); if (sd->pvp_timer != INVALID_TIMER) { - iTimer->delete_timer(sd->pvp_timer, pc->calc_pvprank_timer); + timer->delete(sd->pvp_timer, pc->calc_pvprank_timer); sd->pvp_timer = INVALID_TIMER; } return 0; } -BUILDIN(pvpoff) -{ +BUILDIN(pvpoff) { int16 m; const char *str; struct block_list bl; - + str=script_getstr(st,2); - m = iMap->mapname2mapid(str); - if(m < 0 || !map[m].flag.pvp) + m = map->mapname2mapid(str); + if(m < 0 || !map->list[m].flag.pvp) return true; //fixed Lupus - - iMap->zone_change2(m, map[m].prev_zone); - map[m].flag.pvp = 0; + + map->zone_change2(m, map->list[m].prev_zone); + map->list[m].flag.pvp = 0; clif->map_property_mapall(m, MAPPROPERTY_NOTHING); bl.type = BL_NUL; bl.m = m; clif->maptypeproperty2(&bl,ALL_SAMEMAP); - + if(battle_config.pk_mode) // disable ranking options if pk_mode is on [Valaris] return true; - - iMap->foreachinmap(buildin_pvpoff_sub, m, BL_PC); + + map->foreachinmap(script->buildin_pvpoff_sub, m, BL_PC); return true; } -BUILDIN(gvgon) -{ +BUILDIN(gvgon) { int16 m; const char *str; - + str=script_getstr(st,2); - m = iMap->mapname2mapid(str); - if(m >= 0 && !map[m].flag.gvg) { + m = map->mapname2mapid(str); + if(m >= 0 && !map->list[m].flag.gvg) { struct block_list bl; - iMap->zone_change2(m, strdb_get(zone_db, MAP_ZONE_GVG_NAME)); - map[m].flag.gvg = 1; + + if( !strdb_exists(map->zone_db,MAP_ZONE_GVG_NAME) ) { + ShowError("buildin_gvgon: zone_db missing '%s'\n",MAP_ZONE_GVG_NAME); + return true; + } + + map->zone_change2(m, strdb_get(map->zone_db, MAP_ZONE_GVG_NAME)); + map->list[m].flag.gvg = 1; clif->map_property_mapall(m, MAPPROPERTY_AGITZONE); bl.type = BL_NUL; bl.m = m; clif->maptypeproperty2(&bl,ALL_SAMEMAP); } - + return true; } -BUILDIN(gvgoff) -{ +BUILDIN(gvgoff) { int16 m; const char *str; - + str=script_getstr(st,2); - m = iMap->mapname2mapid(str); - if(m >= 0 && map[m].flag.gvg) { + m = map->mapname2mapid(str); + if(m >= 0 && map->list[m].flag.gvg) { struct block_list bl; - iMap->zone_change2(m, map[m].prev_zone); - map[m].flag.gvg = 0; + map->zone_change2(m, map->list[m].prev_zone); + map->list[m].flag.gvg = 0; clif->map_property_mapall(m, MAPPROPERTY_NOTHING); bl.type = BL_NUL; bl.m = m; clif->maptypeproperty2(&bl,ALL_SAMEMAP); } - + return true; } /*========================================== - * Shows an emoticon on top of the player/npc - * emotion emotion#, <target: 0 - NPC, 1 - PC>, <NPC/PC name> + * Shows an emoticon on top of the player/npc + * emotion emotion#, <target: 0 - NPC, 1 - PC>, <NPC/PC name> *------------------------------------------*/ //Optional second parameter added by [Skotlex] -BUILDIN(emotion) -{ +BUILDIN(emotion) { int type; int player=0; - + type=script_getnum(st,2); if(type < 0 || type > 100) return true; - + if( script_hasdata(st,3) ) player=script_getnum(st,3); - + if (player) { TBL_PC *sd = NULL; if( script_hasdata(st,4) ) - sd = iMap->nick2sd(script_getstr(st,4)); + sd = map->nick2sd(script_getstr(st,4)); else - sd = script_rid2sd(st); + sd = script->rid2sd(st); if (sd) clif->emotion(&sd->bl,type); + } else if( script_hasdata(st,4) ) { + TBL_NPC *nd = npc->name2id(script_getstr(st,4)); + if(nd) + clif->emotion(&nd->bl,type); } else - if( script_hasdata(st,4) ) - { - TBL_NPC *nd = npc_name2id(script_getstr(st,4)); - if(nd) - clif->emotion(&nd->bl,type); - } - else - clif->emotion(iMap->id2bl(st->oid),type); + clif->emotion(map->id2bl(st->oid),type); return true; } -static int buildin_maprespawnguildid_sub_pc(struct map_session_data* sd, va_list ap) +int buildin_maprespawnguildid_sub_pc(struct map_session_data* sd, va_list ap) { int16 m=va_arg(ap,int); int g_id=va_arg(ap,int); int flag=va_arg(ap,int); - + if(!sd || sd->bl.m != m) return 0; if( - (sd->status.guild_id == g_id && flag&1) || //Warp out owners - (sd->status.guild_id != g_id && flag&2) || //Warp out outsiders - (sd->status.guild_id == 0) // Warp out players not in guild [Valaris] - ) + (sd->status.guild_id == g_id && flag&1) //Warp out owners + || (sd->status.guild_id != g_id && flag&2) //Warp out outsiders + || (sd->status.guild_id == 0) // Warp out players not in guild [Valaris] + ) pc->setpos(sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,CLR_TELEPORT); return 1; } -static int buildin_maprespawnguildid_sub_mob(struct block_list *bl,va_list ap) +int buildin_maprespawnguildid_sub_mob(struct block_list *bl,va_list ap) { struct mob_data *md=(struct mob_data *)bl; - + if(!md->guardian_data && md->class_ != MOBID_EMPERIUM) status_kill(bl); - + return 0; } -BUILDIN(maprespawnguildid) -{ +BUILDIN(maprespawnguildid) { const char *mapname=script_getstr(st,2); int g_id=script_getnum(st,3); int flag=script_getnum(st,4); - - int16 m=iMap->mapname2mapid(mapname); - + + int16 m=map->mapname2mapid(mapname); + if(m == -1) return true; - + //Catch ALL players (in case some are 'between maps' on execution time) - iMap->map_foreachpc(buildin_maprespawnguildid_sub_pc,m,g_id,flag); + map->foreachpc(script->buildin_maprespawnguildid_sub_pc,m,g_id,flag); if (flag&4) //Remove script mobs. - iMap->foreachinmap(buildin_maprespawnguildid_sub_mob,m,BL_MOB); + map->foreachinmap(script->buildin_maprespawnguildid_sub_mob,m,BL_MOB); return true; } -BUILDIN(agitstart) -{ - if(iMap->agit_flag==1) return true; // Agit already Start. - iMap->agit_flag=1; +BUILDIN(agitstart) { + if(map->agit_flag==1) return true; // Agit already Start. + map->agit_flag=1; guild->agit_start(); return true; } -BUILDIN(agitend) -{ - if(iMap->agit_flag==0) return true; // Agit already End. - iMap->agit_flag=0; +BUILDIN(agitend) { + if(map->agit_flag==0) return true; // Agit already End. + map->agit_flag=0; guild->agit_end(); return true; } -BUILDIN(agitstart2) -{ - if(iMap->agit2_flag==1) return true; // Agit2 already Start. - iMap->agit2_flag=1; +BUILDIN(agitstart2) { + if(map->agit2_flag==1) return true; // Agit2 already Start. + map->agit2_flag=1; guild->agit2_start(); return true; } -BUILDIN(agitend2) -{ - if(iMap->agit2_flag==0) return true; // Agit2 already End. - iMap->agit2_flag=0; +BUILDIN(agitend2) { + if(map->agit2_flag==0) return true; // Agit2 already End. + map->agit2_flag=0; guild->agit2_end(); return true; } /*========================================== - * Returns whether woe is on or off. // choice script + * Returns whether woe is on or off. *------------------------------------------*/ -BUILDIN(agitcheck) -{ - script_pushint(st,iMap->agit_flag); +BUILDIN(agitcheck) { + script_pushint(st,map->agit_flag); return true; } /*========================================== - * Returns whether woese is on or off. // choice script + * Returns whether woese is on or off. *------------------------------------------*/ -BUILDIN(agitcheck2) -{ - script_pushint(st,iMap->agit2_flag); +BUILDIN(agitcheck2) { + script_pushint(st,map->agit2_flag); return true; } /// Sets the guild_id of this npc. /// /// flagemblem <guild_id>; -BUILDIN(flagemblem) -{ +BUILDIN(flagemblem) { TBL_NPC* nd; int g_id = script_getnum(st,2); - + if(g_id < 0) return true; - - nd = (TBL_NPC*)iMap->id2nd(st->oid); + + nd = (TBL_NPC*)map->id2nd(st->oid); if( nd == NULL ) { ShowError("script:flagemblem: npc %d not found\n", st->oid); } else if( nd->subtype != SCRIPT ) { @@ -10801,7 +11446,7 @@ BUILDIN(flagemblem) BUILDIN(getcastlename) { - const char* mapname = mapindex_getmapname(script_getstr(st,2),NULL); + const char* mapname = mapindex->getmapname(script_getstr(st,2),NULL); struct guild_castle* gc = guild->mapname2gc(mapname); const char* name = (gc) ? gc->castle_name : ""; script_pushstrcopy(st,name); @@ -10810,16 +11455,16 @@ BUILDIN(getcastlename) BUILDIN(getcastledata) { - const char *mapname = mapindex_getmapname(script_getstr(st,2),NULL); + const char *mapname = mapindex->getmapname(script_getstr(st,2),NULL); int index = script_getnum(st,3); struct guild_castle *gc = guild->mapname2gc(mapname); - + if (gc == NULL) { script_pushint(st,0); ShowWarning("buildin_setcastledata: guild castle for map '%s' not found\n", mapname); return false; } - + switch (index) { case 1: script_pushint(st,gc->guild_id); break; @@ -10853,21 +11498,21 @@ BUILDIN(getcastledata) BUILDIN(setcastledata) { - const char *mapname = mapindex_getmapname(script_getstr(st,2),NULL); + const char *mapname = mapindex->getmapname(script_getstr(st,2),NULL); int index = script_getnum(st,3); int value = script_getnum(st,4); struct guild_castle *gc = guild->mapname2gc(mapname); - + if (gc == NULL) { ShowWarning("buildin_setcastledata: guild castle for map '%s' not found\n", mapname); return false; } - + if (index <= 0 || index > 9+MAX_GUARDIANS) { ShowWarning("buildin_setcastledata: index = '%d' is out of allowed range\n", index); return false; } - + guild->castledatasave(gc->castle_id, index, value); return true; } @@ -10878,12 +11523,12 @@ BUILDIN(requestguildinfo) { int guild_id=script_getnum(st,2); const char *event=NULL; - - if( script_hasdata(st,3) ){ + + if( script_hasdata(st,3) ) { event=script_getstr(st,3); - check_event(st, event); + script->check_event(st, event); } - + if(guild_id>0) guild->npc_request_info(guild_id,event); return true; @@ -10896,28 +11541,32 @@ BUILDIN(getequipcardcnt) int i=-1,j,num; TBL_PC *sd; int count; - + num=script_getnum(st,2); - sd=script_rid2sd(st); - if (num > 0 && num <= ARRAYLENGTH(equip)) - i=pc->checkequip(sd,equip[num-1]); - + sd=script->rid2sd(st); + + if( sd == NULL ) + return false; + + if (num > 0 && num <= ARRAYLENGTH(script->equip)) + i=pc->checkequip(sd,script->equip[num-1]); + if (i < 0 || !sd->inventory_data[i]) { script_pushint(st,0); return true; } - + if(itemdb_isspecial(sd->status.inventory[i].card[0])) { script_pushint(st,0); return true; } - + count = 0; for( j = 0; j < sd->inventory_data[i]->slot; j++ ) if( sd->status.inventory[i].card[j] && itemdb_type(sd->status.inventory[i].card[j]) == IT_CARD ) count++; - + script_pushint(st,count); return true; } @@ -10927,20 +11576,23 @@ BUILDIN(getequipcardcnt) /// successremovecards <slot>; BUILDIN(successremovecards) { int i=-1,j,c,cardflag=0; - - TBL_PC* sd = script_rid2sd(st); + + TBL_PC* sd = script->rid2sd(st); int num = script_getnum(st,2); - - if (num > 0 && num <= ARRAYLENGTH(equip)) - i=pc->checkequip(sd,equip[num-1]); - + + if( sd == NULL ) + return false; + + if (num > 0 && num <= ARRAYLENGTH(script->equip)) + i=pc->checkequip(sd,script->equip[num-1]); + if (i < 0 || !sd->inventory_data[i]) { return true; } - + if(itemdb_isspecial(sd->status.inventory[i].card[0])) return true; - + for( c = sd->inventory_data[i]->slot - 1; c >= 0; --c ) { if( sd->status.inventory[i].card[c] && itemdb_type(sd->status.inventory[i].card[c]) == IT_CARD ) {// extract this card from the item int flag; @@ -10949,34 +11601,37 @@ BUILDIN(successremovecards) { cardflag = 1; item_tmp.nameid = sd->status.inventory[i].card[c]; item_tmp.identify = 1; - - if((flag=pc->additem(sd,&item_tmp,1,LOG_TYPE_SCRIPT))){ // get back the cart in inventory + + if((flag=pc->additem(sd,&item_tmp,1,LOG_TYPE_SCRIPT))) { + // get back the cart in inventory clif->additem(sd,0,0,flag); - iMap->addflooritem(&item_tmp,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0); + map->addflooritem(&item_tmp,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0); } } } - + if(cardflag == 1) {//if card was remove remplace item with no card int flag; struct item item_tmp; memset(&item_tmp,0,sizeof(item_tmp)); - + item_tmp.nameid = sd->status.inventory[i].nameid; item_tmp.identify = 1; item_tmp.refine = sd->status.inventory[i].refine; item_tmp.attribute = sd->status.inventory[i].attribute; item_tmp.expire_time = sd->status.inventory[i].expire_time; - + item_tmp.bound = sd->status.inventory[i].bound; + for (j = sd->inventory_data[i]->slot; j < MAX_SLOTS; j++) item_tmp.card[j]=sd->status.inventory[i].card[j]; - + pc->delitem(sd,i,1,0,3,LOG_TYPE_SCRIPT); - if((flag=pc->additem(sd,&item_tmp,1,LOG_TYPE_SCRIPT))){ //chk if can be spawn in inventory otherwise put on floor + if((flag=pc->additem(sd,&item_tmp,1,LOG_TYPE_SCRIPT))) { + //chk if can be spawn in inventory otherwise put on floor clif->additem(sd,0,0,flag); - iMap->addflooritem(&item_tmp,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0); + map->addflooritem(&item_tmp,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0); } - + clif->misceffect(&sd->bl,3); } return true; @@ -10990,80 +11645,86 @@ BUILDIN(successremovecards) { /// <type>=? : will just display the failure effect. BUILDIN(failedremovecards) { int i=-1,j,c,cardflag=0; - - TBL_PC* sd = script_rid2sd(st); + + TBL_PC* sd = script->rid2sd(st); int num = script_getnum(st,2); int typefail = script_getnum(st,3); - - if (num > 0 && num <= ARRAYLENGTH(equip)) - i=pc->checkequip(sd,equip[num-1]); - + + if( sd == NULL ) + return false; + + if (num > 0 && num <= ARRAYLENGTH(script->equip)) + i=pc->checkequip(sd,script->equip[num-1]); + if (i < 0 || !sd->inventory_data[i]) return true; - + if(itemdb_isspecial(sd->status.inventory[i].card[0])) return true; - + for( c = sd->inventory_data[i]->slot - 1; c >= 0; --c ) { if( sd->status.inventory[i].card[c] && itemdb_type(sd->status.inventory[i].card[c]) == IT_CARD ) { cardflag = 1; - + if(typefail == 2) {// add cards to inventory, clear int flag; struct item item_tmp; - + memset(&item_tmp,0,sizeof(item_tmp)); - + item_tmp.nameid = sd->status.inventory[i].card[c]; item_tmp.identify = 1; - - if((flag=pc->additem(sd,&item_tmp,1,LOG_TYPE_SCRIPT))){ + + if((flag=pc->additem(sd,&item_tmp,1,LOG_TYPE_SCRIPT))) { clif->additem(sd,0,0,flag); - iMap->addflooritem(&item_tmp,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0); + map->addflooritem(&item_tmp,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0); } } } } - + if(cardflag == 1) { - if(typefail == 0 || typefail == 2){ // destroy the item + if(typefail == 0 || typefail == 2) { + // destroy the item pc->delitem(sd,i,1,0,2,LOG_TYPE_SCRIPT); } - if(typefail == 1){ // destroy the card + if(typefail == 1) { + // destroy the card int flag; struct item item_tmp; - + memset(&item_tmp,0,sizeof(item_tmp)); - + item_tmp.nameid = sd->status.inventory[i].nameid; item_tmp.identify = 1; item_tmp.refine = sd->status.inventory[i].refine; item_tmp.attribute = sd->status.inventory[i].attribute; item_tmp.expire_time = sd->status.inventory[i].expire_time; - + item_tmp.bound = sd->status.inventory[i].bound; + for (j = sd->inventory_data[i]->slot; j < MAX_SLOTS; j++) item_tmp.card[j]=sd->status.inventory[i].card[j]; - + pc->delitem(sd,i,1,0,2,LOG_TYPE_SCRIPT); - - if((flag=pc->additem(sd,&item_tmp,1,LOG_TYPE_SCRIPT))){ + + if((flag=pc->additem(sd,&item_tmp,1,LOG_TYPE_SCRIPT))) { clif->additem(sd,0,0,flag); - iMap->addflooritem(&item_tmp,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0); + map->addflooritem(&item_tmp,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0); } } clif->misceffect(&sd->bl,2); } - + return true; } /* ================================================================ * mapwarp "<from map>","<to map>",<x>,<y>,<type>,<ID for Type>; - * type: 0=everyone, 1=guild, 2=party; [Reddozen] + * type: 0=everyone, 1=guild, 2=party; [Reddozen] * improved by [Lance] * ================================================================*/ -BUILDIN(mapwarp) // Added by RoVeRT -{ +// Added by RoVeRT +BUILDIN(mapwarp) { int x,y,m,check_val=0,check_ID=0,i=0; struct guild *g = NULL; struct party_data *p = NULL; @@ -11074,24 +11735,24 @@ BUILDIN(mapwarp) // Added by RoVeRT str=script_getstr(st,3); x=script_getnum(st,4); y=script_getnum(st,5); - if(script_hasdata(st,7)){ + if(script_hasdata(st,7)) { check_val=script_getnum(st,6); check_ID=script_getnum(st,7); } - - if((m=iMap->mapname2mapid(mapname))< 0) + + if((m=map->mapname2mapid(mapname))< 0) return true; - - if(!(index=mapindex_name2id(str))) + + if(!(index=script->mapindexname2id(st,str))) return true; - - switch(check_val){ + + switch(check_val) { case 1: g = guild->search(check_ID); - if (g){ + if (g) { for( i=0; i < g->max_member; i++) { - if(g->member[i].sd && g->member[i].sd->bl.m==m){ + if(g->member[i].sd && g->member[i].sd->bl.m==m) { pc->setpos(g->member[i].sd,index,x,y,CLR_TELEPORT); } } @@ -11099,24 +11760,24 @@ BUILDIN(mapwarp) // Added by RoVeRT break; case 2: p = party->search(check_ID); - if(p){ - for(i=0;i<MAX_PARTY; i++){ - if(p->data[i].sd && p->data[i].sd->bl.m == m){ + if(p) { + for(i=0;i<MAX_PARTY; i++) { + if(p->data[i].sd && p->data[i].sd->bl.m == m) { pc->setpos(p->data[i].sd,index,x,y,CLR_TELEPORT); } } } break; default: - iMap->foreachinmap(buildin_areawarp_sub,m,BL_PC,index,x,y,0,0); + map->foreachinmap(script->buildin_areawarp_sub,m,BL_PC,index,x,y,0,0); break; } - + return true; } -static int buildin_mobcount_sub(struct block_list *bl,va_list ap) // Added by RoVeRT -{ +// Added by RoVeRT +int buildin_mobcount_sub(struct block_list *bl,va_list ap) { char *event=va_arg(ap,char *); struct mob_data *md = ((struct mob_data *)bl); if( md->status.hp > 0 && (!event || strcmp(event,md->npc_event) == 0) ) @@ -11124,70 +11785,67 @@ static int buildin_mobcount_sub(struct block_list *bl,va_list ap) // Added by Ro return 0; } -BUILDIN(mobcount) // Added by RoVeRT -{ +// Added by RoVeRT +BUILDIN(mobcount) { const char *mapname,*event; int16 m; mapname=script_getstr(st,2); event=script_getstr(st,3); - + if( strcmp(event, "all") == 0 ) event = NULL; else - check_event(st, event); + script->check_event(st, event); if( strcmp(mapname, "this") == 0 ) { - struct map_session_data *sd = script_rid2sd(st); - if( sd ) - m = sd->bl.m; - else { - script_pushint(st,-1); - return true; - } - } else if( (m = iMap->mapname2mapid(mapname)) < 0 ) { + struct map_session_data *sd = script->rid2sd(st); + + if( sd == NULL ) + return false; + + m = sd->bl.m; + } else if( (m = map->mapname2mapid(mapname)) < 0 ) { script_pushint(st,-1); return true; } - if( map[m].flag.src4instance && map[m].instance_id == -1 && st->instance_id >= 0 && (m = instance->mapid2imapid(m, st->instance_id)) < 0 ) { + if( map->list[m].flag.src4instance && map->list[m].instance_id == -1 && st->instance_id >= 0 && (m = instance->mapid2imapid(m, st->instance_id)) < 0 ) { script_pushint(st,-1); return true; } - script_pushint(st,iMap->foreachinmap(buildin_mobcount_sub, m, BL_MOB, event)); - + script_pushint(st,map->foreachinmap(script->buildin_mobcount_sub, m, BL_MOB, event)); + return true; } -BUILDIN(marriage) -{ +BUILDIN(marriage) { const char *partner=script_getstr(st,2); - TBL_PC *sd=script_rid2sd(st); - TBL_PC *p_sd=iMap->nick2sd(partner); - - if(sd==NULL || p_sd==NULL || pc->marriage(sd,p_sd) < 0){ + TBL_PC *sd=script->rid2sd(st); + TBL_PC *p_sd=map->nick2sd(partner); + + if(sd==NULL || p_sd==NULL || pc->marriage(sd,p_sd) < 0) { script_pushint(st,0); return true; } script_pushint(st,1); return true; } -BUILDIN(wedding_effect) -{ - TBL_PC *sd=script_rid2sd(st); +BUILDIN(wedding_effect) { + TBL_PC *sd=script->rid2sd(st); struct block_list *bl; - - if(sd==NULL) { - bl=iMap->id2bl(st->oid); - } else - bl=&sd->bl; + + if( sd == NULL ) + return false; //bl=map->id2bl(st->oid); + + bl=&sd->bl; clif->wedding_effect(bl); return true; } BUILDIN(divorce) { - TBL_PC *sd=script_rid2sd(st); - if(sd==NULL || pc->divorce(sd) < 0){ + TBL_PC *sd=script->rid2sd(st); + if(sd==NULL || pc->divorce(sd) < 0) { script_pushint(st,0); return true; } @@ -11195,89 +11853,76 @@ BUILDIN(divorce) return true; } -BUILDIN(ispartneron) -{ - TBL_PC *sd=script_rid2sd(st); - - if(sd==NULL || !pc->ismarried(sd) || - iMap->charid2sd(sd->status.partner_id) == NULL) { +BUILDIN(ispartneron) { + TBL_PC *sd=script->rid2sd(st); + + if (sd==NULL || !pc->ismarried(sd) + || map->charid2sd(sd->status.partner_id) == NULL) { script_pushint(st,0); return true; } - + script_pushint(st,1); return true; } -BUILDIN(getpartnerid) -{ - TBL_PC *sd=script_rid2sd(st); - if (sd == NULL) { - script_pushint(st,0); - return true; - } - - script_pushint(st,sd->status.partner_id); - return true; +BUILDIN(getpartnerid) { + TBL_PC *sd=script->rid2sd(st); + if( sd == NULL ) + return false; + + script_pushint(st,sd->status.partner_id); + return true; } -BUILDIN(getchildid) -{ - TBL_PC *sd=script_rid2sd(st); - if (sd == NULL) { - script_pushint(st,0); - return true; - } - - script_pushint(st,sd->status.child); - return true; +BUILDIN(getchildid) { + TBL_PC *sd=script->rid2sd(st); + if( sd == NULL ) + return false; + + script_pushint(st,sd->status.child); + return true; } -BUILDIN(getmotherid) -{ - TBL_PC *sd=script_rid2sd(st); - if (sd == NULL) { - script_pushint(st,0); - return true; - } - - script_pushint(st,sd->status.mother); - return true; +BUILDIN(getmotherid) { + TBL_PC *sd=script->rid2sd(st); + if( sd == NULL ) + return false; + + script_pushint(st,sd->status.mother); + return true; } -BUILDIN(getfatherid) -{ - TBL_PC *sd=script_rid2sd(st); - if (sd == NULL) { - script_pushint(st,0); - return true; - } - - script_pushint(st,sd->status.father); - return true; +BUILDIN(getfatherid) { + TBL_PC *sd=script->rid2sd(st); + if( sd == NULL ) + return false; + + script_pushint(st,sd->status.father); + return true; } BUILDIN(warppartner) { int x,y; - unsigned short mapindex; + unsigned short map_index; const char *str; - TBL_PC *sd=script_rid2sd(st); + TBL_PC *sd=script->rid2sd(st); TBL_PC *p_sd=NULL; - - if(sd==NULL || !pc->ismarried(sd) || - (p_sd=iMap->charid2sd(sd->status.partner_id)) == NULL) { + + if ( sd==NULL || !pc->ismarried(sd) + || (p_sd=map->charid2sd(sd->status.partner_id)) == NULL) { script_pushint(st,0); return true; } - + str=script_getstr(st,2); x=script_getnum(st,3); y=script_getnum(st,4); - - mapindex = mapindex_name2id(str); - if (mapindex) { - pc->setpos(p_sd,mapindex,x,y,CLR_OUTSIGHT); + + map_index = script->mapindexname2id(st,str); + if (map_index) { + pc->setpos(p_sd,map_index,x,y,CLR_OUTSIGHT); script_pushint(st,1); } else script_pushint(st,0); @@ -11289,11 +11934,11 @@ BUILDIN(warppartner) *------------------------------------------------*/ BUILDIN(strmobinfo) { - + int num=script_getnum(st,2); int class_=script_getnum(st,3); - - if(!mobdb_checkid(class_)) + + if(!mob->db_checkid(class_)) { if (num < 3) //requested a string script_pushconststr(st,""); @@ -11301,15 +11946,15 @@ BUILDIN(strmobinfo) script_pushint(st,0); return true; } - + switch (num) { - case 1: script_pushstrcopy(st,mob_db(class_)->name); break; - case 2: script_pushstrcopy(st,mob_db(class_)->jname); break; - case 3: script_pushint(st,mob_db(class_)->lv); break; - case 4: script_pushint(st,mob_db(class_)->status.max_hp); break; - case 5: script_pushint(st,mob_db(class_)->status.max_sp); break; - case 6: script_pushint(st,mob_db(class_)->base_exp); break; - case 7: script_pushint(st,mob_db(class_)->job_exp); break; + case 1: script_pushstrcopy(st,mob->db(class_)->name); break; + case 2: script_pushstrcopy(st,mob->db(class_)->jname); break; + case 3: script_pushint(st,mob->db(class_)->lv); break; + case 4: script_pushint(st,mob->db(class_)->status.max_hp); break; + case 5: script_pushint(st,mob->db(class_)->status.max_sp); break; + case 6: script_pushint(st,mob->db(class_)->base_exp); break; + case 7: script_pushint(st,mob->db(class_)->job_exp); break; default: script_pushint(st,0); break; @@ -11321,74 +11966,70 @@ BUILDIN(strmobinfo) * Summon guardians [Valaris] * guardian("<map name>",<x>,<y>,"<name to show>",<mob id>{,"<event label>"}{,<guardian index>}) -> <id> *------------------------------------------*/ -BUILDIN(guardian) -{ - int class_=0,x=0,y=0,guardian=0; - const char *str,*map,*evt=""; - struct script_data *data; +BUILDIN(guardian) { + int class_ = 0, x = 0, y = 0, guardian = 0; + const char *str, *mapname, *evt=""; bool has_index = false; - - map =script_getstr(st,2); - x =script_getnum(st,3); - y =script_getnum(st,4); - str =script_getstr(st,5); - class_=script_getnum(st,6); - + + mapname = script_getstr(st,2); + x = script_getnum(st,3); + y = script_getnum(st,4); + str = script_getstr(st,5); + class_ = script_getnum(st,6); + if( script_hasdata(st,8) ) {// "<event label>",<guardian index> evt=script_getstr(st,7); guardian=script_getnum(st,8); has_index = true; - } else if( script_hasdata(st,7) ){ - data=script_getdata(st,7); - script->get_val(st,data); - if( data_isstring(data) ) - {// "<event label>" + } else if( script_hasdata(st,7) ) { + struct script_data *data = script_getdata(st,7); + script->get_val(st,data); // Dereference if it's a variable + if( data_isstring(data) ) { + // "<event label>" evt=script_getstr(st,7); - } else if( data_isint(data) ) - {// <guardian index> + } else if( data_isint(data) ) { + // <guardian index> guardian=script_getnum(st,7); has_index = true; } else { ShowError("script:guardian: invalid data type for argument #6 (from 1)\n"); - script_reportdata(data); + script->reportdata(data); return false; } } - - check_event(st, evt); - script_pushint(st, mob_spawn_guardian(map,x,y,str,class_,evt,guardian,has_index)); - + + script->check_event(st, evt); + script_pushint(st, mob->spawn_guardian(mapname,x,y,str,class_,evt,guardian,has_index)); + return true; } /*========================================== * Invisible Walls [Zephyrus] *------------------------------------------*/ -BUILDIN(setwall) -{ - const char *map, *name; +BUILDIN(setwall) { + const char *mapname, *name; int x, y, m, size, dir; bool shootable; - - map = script_getstr(st,2); - x = script_getnum(st,3); - y = script_getnum(st,4); - size = script_getnum(st,5); - dir = script_getnum(st,6); + + mapname = script_getstr(st,2); + x = script_getnum(st,3); + y = script_getnum(st,4); + size = script_getnum(st,5); + dir = script_getnum(st,6); shootable = script_getnum(st,7); - name = script_getstr(st,8); - - if( (m = iMap->mapname2mapid(map)) < 0 ) + name = script_getstr(st,8); + + if( (m = map->mapname2mapid(mapname)) < 0 ) return true; // Invalid Map - - iMap->iwall_set(m, x, y, size, dir, shootable, name); + + map->iwall_set(m, x, y, size, dir, shootable, name); return true; } -BUILDIN(delwall) -{ +BUILDIN(delwall) { const char *name = script_getstr(st,2); - iMap->iwall_remove(name); - + map->iwall_remove(name); + return true; } @@ -11399,69 +12040,59 @@ BUILDIN(delwall) /// 1 - maximum hp /// 2 - current hp /// -BUILDIN(guardianinfo) -{ - const char* mapname = mapindex_getmapname(script_getstr(st,2),NULL); +BUILDIN(guardianinfo) { + const char* mapname = mapindex->getmapname(script_getstr(st,2),NULL); int id = script_getnum(st,3); int type = script_getnum(st,4); - + struct guild_castle* gc = guild->mapname2gc(mapname); struct mob_data* gd; - - if( gc == NULL || id < 0 || id >= MAX_GUARDIANS ) - { + + if( gc == NULL || id < 0 || id >= MAX_GUARDIANS ) { script_pushint(st,-1); return true; } - + if( type == 0 ) script_pushint(st, gc->guardian[id].visible); + else if( !gc->guardian[id].visible ) + script_pushint(st,-1); + else if( (gd = map->id2md(gc->guardian[id].id)) == NULL ) + script_pushint(st,-1); + else if( type == 1 ) + script_pushint(st,gd->status.max_hp); + else if( type == 2 ) + script_pushint(st,gd->status.hp); else - if( !gc->guardian[id].visible ) - script_pushint(st,-1); - else - if( (gd = iMap->id2md(gc->guardian[id].id)) == NULL ) - script_pushint(st,-1); - else - { - if ( type == 1 ) script_pushint(st,gd->status.max_hp); - else if( type == 2 ) script_pushint(st,gd->status.hp); - else - script_pushint(st,-1); - } - + script_pushint(st,-1); + return true; } /*========================================== * Get the item name by item_id or null *------------------------------------------*/ -BUILDIN(getitemname) -{ +BUILDIN(getitemname) { int item_id=0; struct item_data *i_data; char *item_name; - struct script_data *data; - - data=script_getdata(st,2); - script->get_val(st,data); - - if( data_isstring(data) ){ - const char *name=script->conv_str(st,data); - struct item_data *item_data = itemdb_searchname(name); + + if( script_isstringtype(st, 2) ) { + const char *name = script_getstr(st, 2); + struct item_data *item_data = itemdb->search_name(name); if( item_data ) item_id=item_data->nameid; - }else - item_id=script->conv_num(st,data); - - i_data = itemdb_exists(item_id); - if (i_data == NULL) - { + } else { + item_id = script_getnum(st, 2); + } + + i_data = itemdb->exists(item_id); + if (i_data == NULL) { script_pushconststr(st,"null"); return true; } item_name=(char *)aMalloc(ITEM_NAME_LENGTH*sizeof(char)); - + memcpy(item_name, i_data->jname, ITEM_NAME_LENGTH); script_pushstr(st,item_name); return true; @@ -11473,11 +12104,11 @@ BUILDIN(getitemslots) { int item_id; struct item_data *i_data; - + item_id=script_getnum(st,2); - - i_data = itemdb_exists(item_id); - + + i_data = itemdb->exists(item_id); + if (i_data) script_pushint(st,i_data->slot); else @@ -11490,35 +12121,35 @@ BUILDIN(getitemslots) /*========================================== * Returns some values of an item [Lupus] * Price, Weight, etc... - getiteminfo(itemID,n), where n - 0 value_buy; - 1 value_sell; - 2 type; - 3 maxchance = Max drop chance of this item e.g. 1 = 0.01% , etc.. - if = 0, then monsters don't drop it at all (rare or a quest item) - if = -1, then this item is sold in NPC shops only - 4 sex; - 5 equip; - 6 weight; - 7 atk; - 8 def; - 9 range; - 10 slot; - 11 look; - 12 elv; - 13 wlv; - 14 view id + * getiteminfo(itemID,n), where n + * 0 value_buy; + * 1 value_sell; + * 2 type; + * 3 maxchance = Max drop chance of this item e.g. 1 = 0.01% , etc.. + * if = 0, then monsters don't drop it at all (rare or a quest item) + * if = -1, then this item is sold in NPC shops only + * 4 sex; + * 5 equip; + * 6 weight; + * 7 atk; + * 8 def; + * 9 range; + * 10 slot; + * 11 look; + * 12 elv; + * 13 wlv; + * 14 view id *------------------------------------------*/ BUILDIN(getiteminfo) { int item_id,n; int *item_arr; struct item_data *i_data; - - item_id = script_getnum(st,2); - n = script_getnum(st,3); - i_data = itemdb_exists(item_id); - + + item_id = script_getnum(st,2); + n = script_getnum(st,3); + i_data = itemdb->exists(item_id); + if (i_data && n>=0 && n<=14) { item_arr = (int*)&i_data->value_buy; script_pushint(st,item_arr[n]); @@ -11530,24 +12161,24 @@ BUILDIN(getiteminfo) /*========================================== * Set some values of an item [Lupus] * Price, Weight, etc... - setiteminfo(itemID,n,Value), where n - 0 value_buy; - 1 value_sell; - 2 type; - 3 maxchance = Max drop chance of this item e.g. 1 = 0.01% , etc.. - if = 0, then monsters don't drop it at all (rare or a quest item) - if = -1, then this item is sold in NPC shops only - 4 sex; - 5 equip; - 6 weight; - 7 atk; - 8 def; - 9 range; - 10 slot; - 11 look; - 12 elv; - 13 wlv; - 14 view id + * setiteminfo(itemID,n,Value), where n + * 0 value_buy; + * 1 value_sell; + * 2 type; + * 3 maxchance = Max drop chance of this item e.g. 1 = 0.01% , etc.. + * if = 0, then monsters don't drop it at all (rare or a quest item) + * if = -1, then this item is sold in NPC shops only + * 4 sex; + * 5 equip; + * 6 weight; + * 7 atk; + * 8 def; + * 9 range; + * 10 slot; + * 11 look; + * 12 elv; + * 13 wlv; + * 14 view id * Returns Value or -1 if the wrong field's been set *------------------------------------------*/ BUILDIN(setiteminfo) @@ -11555,12 +12186,12 @@ BUILDIN(setiteminfo) int item_id,n,value; int *item_arr; struct item_data *i_data; - - item_id = script_getnum(st,2); - n = script_getnum(st,3); - value = script_getnum(st,4); - i_data = itemdb_exists(item_id); - + + item_id = script_getnum(st,2); + n = script_getnum(st,3); + value = script_getnum(st,4); + i_data = itemdb->exists(item_id); + if (i_data && n>=0 && n<=14) { item_arr = (int*)&i_data->value_buy; item_arr[n] = value; @@ -11572,31 +12203,35 @@ BUILDIN(setiteminfo) /*========================================== * Returns value from equipped item slot n [Lupus] - getequpcardid(num,slot) - where - num = eqip position slot - slot = 0,1,2,3 (Card Slot N) - - This func returns CARD ID, 255,254,-255 (for card 0, if the item is produced) - it's useful when you want to check item cards or if it's signed - Useful for such quests as "Sign this refined item with players name" etc - Hat[0] +4 -> Player's Hat[0] +4 + * getequpcardid(num,slot) + * where + * num = eqip position slot + * slot = 0,1,2,3 (Card Slot N) + * + * This func returns CARD ID, 255,254,-255 (for card 0, if the item is produced) + * it's useful when you want to check item cards or if it's signed + * Useful for such quests as "Sign this refined item with players name" etc + * Hat[0] +4 -> Player's Hat[0] +4 *------------------------------------------*/ BUILDIN(getequipcardid) { int i=-1,num,slot; TBL_PC *sd; - + num=script_getnum(st,2); slot=script_getnum(st,3); - sd=script_rid2sd(st); - if (num > 0 && num <= ARRAYLENGTH(equip)) - i=pc->checkequip(sd,equip[num-1]); + sd=script->rid2sd(st); + + if( sd == NULL ) + return false; + + if (num > 0 && num <= ARRAYLENGTH(script->equip)) + i=pc->checkequip(sd,script->equip[num-1]); if(i >= 0 && slot>=0 && slot<4) script_pushint(st,sd->status.inventory[i].card[slot]); else script_pushint(st,0); - + return true; } @@ -11606,34 +12241,34 @@ BUILDIN(getequipcardid) BUILDIN(petskillbonus) { struct pet_data *pd; - - TBL_PC *sd=script_rid2sd(st); - + + TBL_PC *sd=script->rid2sd(st); + if(sd==NULL || sd->pd==NULL) return true; - + pd=sd->pd; if (pd->bonus) { //Clear previous bonus if (pd->bonus->timer != INVALID_TIMER) - iTimer->delete_timer(pd->bonus->timer, pet_skill_bonus_timer); + timer->delete(pd->bonus->timer, pet->skill_bonus_timer); } else //init pd->bonus = (struct pet_bonus *) aMalloc(sizeof(struct pet_bonus)); - + pd->bonus->type=script_getnum(st,2); pd->bonus->val=script_getnum(st,3); pd->bonus->duration=script_getnum(st,4); pd->bonus->delay=script_getnum(st,5); - + if (pd->state.skillbonus == 1) - pd->state.skillbonus=0; // waiting state - + pd->state.skillbonus=0; // waiting state + // wait for timer to start if (battle_config.pet_equip_required && pd->pet.equip == 0) pd->bonus->timer = INVALID_TIMER; else - pd->bonus->timer = iTimer->add_timer(iTimer->gettick()+pd->bonus->delay*1000, pet_skill_bonus_timer, sd->bl.id, 0); - + pd->bonus->timer = timer->add(timer->gettick()+pd->bonus->delay*1000, pet->skill_bonus_timer, sd->bl.id, 0); + return true; } @@ -11644,33 +12279,33 @@ BUILDIN(petloot) { int max; struct pet_data *pd; - TBL_PC *sd=script_rid2sd(st); - + TBL_PC *sd=script->rid2sd(st); + if(sd==NULL || sd->pd==NULL) return true; - + max=script_getnum(st,2); - + if(max < 1) - max = 1; //Let'em loot at least 1 item. + max = 1; //Let'em loot at least 1 item. else if (max > MAX_PETLOOT_SIZE) max = MAX_PETLOOT_SIZE; - + pd = sd->pd; - if (pd->loot != NULL) - { //Release whatever was there already and reallocate memory - pet_lootitem_drop(pd, pd->msd); + if (pd->loot != NULL) { + //Release whatever was there already and reallocate memory + pet->lootitem_drop(pd, pd->msd); aFree(pd->loot->item); } else pd->loot = (struct pet_loot *)aMalloc(sizeof(struct pet_loot)); - + pd->loot->item = (struct item *)aCalloc(max,sizeof(struct item)); - + pd->loot->max=max; pd->loot->count = 0; pd->loot->weight = 0; - + return true; } /*========================================== @@ -11682,52 +12317,53 @@ BUILDIN(petloot) *------------------------------------------*/ BUILDIN(getinventorylist) { - TBL_PC *sd=script_rid2sd(st); + TBL_PC *sd=script->rid2sd(st); char card_var[NAME_LENGTH]; - + int i,j=0,k; if(!sd) return true; - for(i=0;i<MAX_INVENTORY;i++){ - if(sd->status.inventory[i].nameid > 0 && sd->status.inventory[i].amount > 0){ - pc->setreg(sd,reference_uid(add_str("@inventorylist_id"), j),sd->status.inventory[i].nameid); - pc->setreg(sd,reference_uid(add_str("@inventorylist_amount"), j),sd->status.inventory[i].amount); - pc->setreg(sd,reference_uid(add_str("@inventorylist_equip"), j),sd->status.inventory[i].equip); - pc->setreg(sd,reference_uid(add_str("@inventorylist_refine"), j),sd->status.inventory[i].refine); - pc->setreg(sd,reference_uid(add_str("@inventorylist_identify"), j),sd->status.inventory[i].identify); - pc->setreg(sd,reference_uid(add_str("@inventorylist_attribute"), j),sd->status.inventory[i].attribute); + for(i=0;i<MAX_INVENTORY;i++) { + if(sd->status.inventory[i].nameid > 0 && sd->status.inventory[i].amount > 0) { + pc->setreg(sd,reference_uid(script->add_str("@inventorylist_id"), j),sd->status.inventory[i].nameid); + pc->setreg(sd,reference_uid(script->add_str("@inventorylist_amount"), j),sd->status.inventory[i].amount); + pc->setreg(sd,reference_uid(script->add_str("@inventorylist_equip"), j),sd->status.inventory[i].equip); + pc->setreg(sd,reference_uid(script->add_str("@inventorylist_refine"), j),sd->status.inventory[i].refine); + pc->setreg(sd,reference_uid(script->add_str("@inventorylist_identify"), j),sd->status.inventory[i].identify); + pc->setreg(sd,reference_uid(script->add_str("@inventorylist_attribute"), j),sd->status.inventory[i].attribute); for (k = 0; k < MAX_SLOTS; k++) { sprintf(card_var, "@inventorylist_card%d",k+1); - pc->setreg(sd,reference_uid(add_str(card_var), j),sd->status.inventory[i].card[k]); + pc->setreg(sd,reference_uid(script->add_str(card_var), j),sd->status.inventory[i].card[k]); } - pc->setreg(sd,reference_uid(add_str("@inventorylist_expire"), j),sd->status.inventory[i].expire_time); + pc->setreg(sd,reference_uid(script->add_str("@inventorylist_expire"), j),sd->status.inventory[i].expire_time); + pc->setreg(sd,reference_uid(script->add_str("@inventorylist_bound"), j),sd->status.inventory[i].bound); j++; } } - pc->setreg(sd,add_str("@inventorylist_count"),j); + pc->setreg(sd,script->add_str("@inventorylist_count"),j); return true; } BUILDIN(getskilllist) { - TBL_PC *sd=script_rid2sd(st); + TBL_PC *sd=script->rid2sd(st); int i,j=0; if(!sd) return true; - for(i=0;i<MAX_SKILL;i++){ - if(sd->status.skill[i].id > 0 && sd->status.skill[i].lv > 0){ - pc->setreg(sd,reference_uid(add_str("@skilllist_id"), j),sd->status.skill[i].id); - pc->setreg(sd,reference_uid(add_str("@skilllist_lv"), j),sd->status.skill[i].lv); - pc->setreg(sd,reference_uid(add_str("@skilllist_flag"), j),sd->status.skill[i].flag); + for(i=0;i<MAX_SKILL;i++) { + if(sd->status.skill[i].id > 0 && sd->status.skill[i].lv > 0) { + pc->setreg(sd,reference_uid(script->add_str("@skilllist_id"), j),sd->status.skill[i].id); + pc->setreg(sd,reference_uid(script->add_str("@skilllist_lv"), j),sd->status.skill[i].lv); + pc->setreg(sd,reference_uid(script->add_str("@skilllist_flag"), j),sd->status.skill[i].flag); j++; } } - pc->setreg(sd,add_str("@skilllist_count"),j); + pc->setreg(sd,script->add_str("@skilllist_count"),j); return true; } BUILDIN(clearitem) { - TBL_PC *sd=script_rid2sd(st); + TBL_PC *sd=script->rid2sd(st); int i; if(sd==NULL) return true; for (i=0; i<MAX_INVENTORY; i++) { @@ -11744,17 +12380,17 @@ BUILDIN(clearitem) BUILDIN(disguise) { int id; - TBL_PC* sd = script_rid2sd(st); + TBL_PC* sd = script->rid2sd(st); if (sd == NULL) return true; - + id = script_getnum(st,2); - - if (mobdb_checkid(id) || npcdb_checkid(id)) { + + if (mob->db_checkid(id) || npcdb_checkid(id)) { pc->disguise(sd, id); script_pushint(st,id); } else script_pushint(st,0); - + return true; } @@ -11763,9 +12399,9 @@ BUILDIN(disguise) *------------------------------------------*/ BUILDIN(undisguise) { - TBL_PC* sd = script_rid2sd(st); + TBL_PC* sd = script->rid2sd(st); if (sd == NULL) return true; - + if (sd->disguise != -1) { pc->disguise(sd, -1); script_pushint(st,0); @@ -11776,19 +12412,18 @@ BUILDIN(undisguise) } /*========================================== - * Transform a bl to another _class, + * Transform a bl to another class, * @type unused *------------------------------------------*/ -BUILDIN(classchange) -{ - int _class,type; - struct block_list *bl=iMap->id2bl(st->oid); - +BUILDIN(classchange) { + int class_,type; + struct block_list *bl=map->id2bl(st->oid); + if(bl==NULL) return true; - - _class=script_getnum(st,2); + + class_=script_getnum(st,2); type=script_getnum(st,3); - clif->class_change(bl,_class,type); + clif->class_change(bl,class_,type); return true; } @@ -11798,14 +12433,14 @@ BUILDIN(classchange) BUILDIN(misceffect) { int type; - + type=script_getnum(st,2); - if(st->oid && st->oid != fake_nd->bl.id) { - struct block_list *bl = iMap->id2bl(st->oid); + if(st->oid && st->oid != npc->fake_nd->bl.id) { + struct block_list *bl = map->id2bl(st->oid); if (bl) clif->specialeffect(bl,type,AREA); - } else{ - TBL_PC *sd=script_rid2sd(st); + } else { + TBL_PC *sd=script->rid2sd(st); if(sd) clif->specialeffect(&sd->bl,type,AREA); } @@ -11814,34 +12449,34 @@ BUILDIN(misceffect) /*========================================== * Play a BGM on a single client [Rikter/Yommy] *------------------------------------------*/ -BUILDIN(playBGM) +BUILDIN(playbgm) { const char* name; struct map_session_data* sd; - - if( ( sd = script_rid2sd(st) ) != NULL ) + + if( ( sd = script->rid2sd(st) ) != NULL ) { name = script_getstr(st,2); - + clif->playBGM(sd, name); } - + return true; } -static int playBGM_sub(struct block_list* bl,va_list ap) +int playbgm_sub(struct block_list* bl,va_list ap) { const char* name = va_arg(ap,const char*); - + clif->playBGM(BL_CAST(BL_PC, bl), name); - + return 0; } -static int playBGM_foreachpc_sub(struct map_session_data* sd, va_list args) +int playbgm_foreachpc_sub(struct map_session_data* sd, va_list args) { const char* name = va_arg(args, const char*); - + clif->playBGM(sd, name); return 0; } @@ -11849,33 +12484,42 @@ static int playBGM_foreachpc_sub(struct map_session_data* sd, va_list args) /*========================================== * Play a BGM on multiple client [Rikter/Yommy] *------------------------------------------*/ -BUILDIN(playBGMall) -{ +BUILDIN(playbgmall) { const char* name; - + name = script_getstr(st,2); - - if( script_hasdata(st,7) ) - {// specified part of map - const char* map = script_getstr(st,3); + + if( script_hasdata(st,7) ) { + // specified part of map + const char *mapname = script_getstr(st,3); int x0 = script_getnum(st,4); int y0 = script_getnum(st,5); int x1 = script_getnum(st,6); int y1 = script_getnum(st,7); - - iMap->foreachinarea(playBGM_sub, iMap->mapname2mapid(map), x0, y0, x1, y1, BL_PC, name); - } - else if( script_hasdata(st,3) ) - {// entire map - const char* map = script_getstr(st,3); - - iMap->foreachinmap(playBGM_sub, iMap->mapname2mapid(map), BL_PC, name); - } - else - {// entire server - iMap->map_foreachpc(&playBGM_foreachpc_sub, name); + int m; + + if ( ( m = map->mapname2mapid(mapname) ) == -1 ) { + ShowWarning("playbgmall: Attempted to play song '%s' on non-existent map '%s'\n",name, mapname); + return true; + } + + map->foreachinarea(script->playbgm_sub, m, x0, y0, x1, y1, BL_PC, name); + } else if( script_hasdata(st,3) ) { + // entire map + const char* mapname = script_getstr(st,3); + int m; + + if ( ( m = map->mapname2mapid(mapname) ) == -1 ) { + ShowWarning("playbgmall: Attempted to play song '%s' on non-existent map '%s'\n",name, mapname); + return true; + } + + map->foreachinmap(script->playbgm_sub, m, BL_PC, name); + } else { + // entire server + map->foreachpc(script->playbgm_foreachpc_sub, name); } - + return true; } @@ -11884,10 +12528,10 @@ BUILDIN(playBGMall) *------------------------------------------*/ BUILDIN(soundeffect) { - TBL_PC* sd = script_rid2sd(st); + TBL_PC* sd = script->rid2sd(st); const char* name = script_getstr(st,2); int type = script_getnum(st,3); - + if(sd) { clif->soundeffect(sd,&sd->bl,name,type); @@ -11899,9 +12543,9 @@ int soundeffect_sub(struct block_list* bl,va_list ap) { char* name = va_arg(ap,char*); int type = va_arg(ap,int); - + clif->soundeffect((TBL_PC *)bl, bl, name, type); - + return true; } @@ -11909,46 +12553,52 @@ int soundeffect_sub(struct block_list* bl,va_list ap) * Play a sound effect (.wav) on multiple clients * soundeffectall "<filepath>",<type>{,"<map name>"}{,<x0>,<y0>,<x1>,<y1>}; *------------------------------------------*/ -BUILDIN(soundeffectall) -{ +BUILDIN(soundeffectall) { struct block_list* bl; const char* name; int type; - - bl = (st->rid) ? &(script_rid2sd(st)->bl) : iMap->id2bl(st->oid); + + bl = (st->rid) ? &(script->rid2sd(st)->bl) : map->id2bl(st->oid); if (!bl) return true; - + name = script_getstr(st,2); type = script_getnum(st,3); - - //FIXME: enumerating map squares (iMap->foreach) is slower than enumerating the list of online players (iMap->foreachpc?) [ultramage] - - if(!script_hasdata(st,4)) - { // area around + + //FIXME: enumerating map squares (map->foreach) is slower than enumerating the list of online players (map->foreachpc?) [ultramage] + + if(!script_hasdata(st,4)) { // area around clif->soundeffectall(bl, name, type, AREA); - } - else - if(!script_hasdata(st,5)) - { // entire map - const char* map = script_getstr(st,4); - iMap->foreachinmap(soundeffect_sub, iMap->mapname2mapid(map), BL_PC, name, type); - } - else - if(script_hasdata(st,8)) - { // specified part of map - const char* map = script_getstr(st,4); - int x0 = script_getnum(st,5); - int y0 = script_getnum(st,6); - int x1 = script_getnum(st,7); - int y1 = script_getnum(st,8); - iMap->foreachinarea(soundeffect_sub, iMap->mapname2mapid(map), x0, y0, x1, y1, BL_PC, name, type); + } else { + if(!script_hasdata(st,5)) { // entire map + const char *mapname = script_getstr(st,4); + int m; + + if ( ( m = map->mapname2mapid(mapname) ) == -1 ) { + ShowWarning("soundeffectall: Attempted to play song '%s' (type %d) on non-existent map '%s'\n",name,type, mapname); + return true; } - else - { - ShowError("buildin_soundeffectall: insufficient arguments for specific area broadcast.\n"); + + map->foreachinmap(script->soundeffect_sub, m, BL_PC, name, type); + } else if(script_hasdata(st,8)) { // specified part of map + const char *mapname = script_getstr(st,4); + int x0 = script_getnum(st,5); + int y0 = script_getnum(st,6); + int x1 = script_getnum(st,7); + int y1 = script_getnum(st,8); + int m; + + if ( ( m = map->mapname2mapid(mapname) ) == -1 ) { + ShowWarning("soundeffectall: Attempted to play song '%s' (type %d) on non-existent map '%s'\n",name,type, mapname); + return true; } - + + map->foreachinarea(script->soundeffect_sub, m, x0, y0, x1, y1, BL_PC, name, type); + } else { + ShowError("buildin_soundeffectall: insufficient arguments for specific area broadcast.\n"); + } + } + return true; } /*========================================== @@ -11957,24 +12607,24 @@ BUILDIN(soundeffectall) BUILDIN(petrecovery) { struct pet_data *pd; - TBL_PC *sd=script_rid2sd(st); - + TBL_PC *sd=script->rid2sd(st); + if(sd==NULL || sd->pd==NULL) return true; - + pd=sd->pd; - + if (pd->recovery) { //Halt previous bonus if (pd->recovery->timer != INVALID_TIMER) - iTimer->delete_timer(pd->recovery->timer, pet_recovery_timer); + timer->delete(pd->recovery->timer, pet->recovery_timer); } else //Init pd->recovery = (struct pet_recovery *)aMalloc(sizeof(struct pet_recovery)); - + pd->recovery->type = (sc_type)script_getnum(st,2); pd->recovery->delay = script_getnum(st,3); pd->recovery->timer = INVALID_TIMER; - + return true; } @@ -11984,37 +12634,37 @@ BUILDIN(petrecovery) BUILDIN(petheal) { struct pet_data *pd; - TBL_PC *sd=script_rid2sd(st); - + TBL_PC *sd=script->rid2sd(st); + if(sd==NULL || sd->pd==NULL) return true; - + pd=sd->pd; if (pd->s_skill) { //Clear previous skill if (pd->s_skill->timer != INVALID_TIMER) { if (pd->s_skill->id) - iTimer->delete_timer(pd->s_skill->timer, pet_skill_support_timer); + timer->delete(pd->s_skill->timer, pet->skill_support_timer); else - iTimer->delete_timer(pd->s_skill->timer, pet_heal_timer); + timer->delete(pd->s_skill->timer, pet->heal_timer); } } else //init memory pd->s_skill = (struct pet_skill_support *) aMalloc(sizeof(struct pet_skill_support)); - + pd->s_skill->id=0; //This id identifies that it IS petheal rather than pet_skillsupport //Use the lv as the amount to heal pd->s_skill->lv=script_getnum(st,2); pd->s_skill->delay=script_getnum(st,3); pd->s_skill->hp=script_getnum(st,4); pd->s_skill->sp=script_getnum(st,5); - + //Use delay as initial offset to avoid skill/heal exploits if (battle_config.pet_equip_required && pd->pet.equip == 0) pd->s_skill->timer = INVALID_TIMER; else - pd->s_skill->timer = iTimer->add_timer(iTimer->gettick()+pd->s_skill->delay*1000,pet_heal_timer,sd->bl.id,0); - + pd->s_skill->timer = timer->add(timer->gettick()+pd->s_skill->delay*1000,pet->heal_timer,sd->bl.id,0); + return true; } @@ -12023,24 +12673,23 @@ BUILDIN(petheal) *------------------------------------------*/ /// petskillattack <skill id>,<level>,<rate>,<bonusrate> /// petskillattack "<skill name>",<level>,<rate>,<bonusrate> -BUILDIN(petskillattack) -{ +BUILDIN(petskillattack) { struct pet_data *pd; - TBL_PC *sd=script_rid2sd(st); - + TBL_PC *sd=script->rid2sd(st); + if(sd==NULL || sd->pd==NULL) return true; - + pd=sd->pd; if (pd->a_skill == NULL) pd->a_skill = (struct pet_skill_attack *)aMalloc(sizeof(struct pet_skill_attack)); - - pd->a_skill->id=( script_isstring(st,2) ? skill->name2id(script_getstr(st,2)) : script_getnum(st,2) ); + + pd->a_skill->id=( script_isstringtype(st,2) ? skill->name2id(script_getstr(st,2)) : script_getnum(st,2) ); pd->a_skill->lv=script_getnum(st,3); pd->a_skill->div_ = 0; pd->a_skill->rate=script_getnum(st,4); pd->a_skill->bonusrate=script_getnum(st,5); - + return true; } @@ -12049,24 +12698,23 @@ BUILDIN(petskillattack) *------------------------------------------*/ /// petskillattack2 <skill id>,<level>,<div>,<rate>,<bonusrate> /// petskillattack2 "<skill name>",<level>,<div>,<rate>,<bonusrate> -BUILDIN(petskillattack2) -{ +BUILDIN(petskillattack2) { struct pet_data *pd; - TBL_PC *sd=script_rid2sd(st); - + TBL_PC *sd=script->rid2sd(st); + if(sd==NULL || sd->pd==NULL) return true; - + pd=sd->pd; if (pd->a_skill == NULL) pd->a_skill = (struct pet_skill_attack *)aMalloc(sizeof(struct pet_skill_attack)); - - pd->a_skill->id=( script_isstring(st,2) ? skill->name2id(script_getstr(st,2)) : script_getnum(st,2) ); + + pd->a_skill->id=( script_isstringtype(st,2) ? skill->name2id(script_getstr(st,2)) : script_getnum(st,2) ); pd->a_skill->lv=script_getnum(st,3); pd->a_skill->div_ = script_getnum(st,4); pd->a_skill->rate=script_getnum(st,5); pd->a_skill->bonusrate=script_getnum(st,6); - + return true; } @@ -12075,39 +12723,38 @@ BUILDIN(petskillattack2) *------------------------------------------*/ /// petskillsupport <skill id>,<level>,<delay>,<hp>,<sp> /// petskillsupport "<skill name>",<level>,<delay>,<hp>,<sp> -BUILDIN(petskillsupport) -{ +BUILDIN(petskillsupport) { struct pet_data *pd; - TBL_PC *sd=script_rid2sd(st); - + TBL_PC *sd=script->rid2sd(st); + if(sd==NULL || sd->pd==NULL) return true; - + pd=sd->pd; if (pd->s_skill) { //Clear previous skill if (pd->s_skill->timer != INVALID_TIMER) { if (pd->s_skill->id) - iTimer->delete_timer(pd->s_skill->timer, pet_skill_support_timer); + timer->delete(pd->s_skill->timer, pet->skill_support_timer); else - iTimer->delete_timer(pd->s_skill->timer, pet_heal_timer); + timer->delete(pd->s_skill->timer, pet->heal_timer); } } else //init memory pd->s_skill = (struct pet_skill_support *) aMalloc(sizeof(struct pet_skill_support)); - - pd->s_skill->id=( script_isstring(st,2) ? skill->name2id(script_getstr(st,2)) : script_getnum(st,2) ); + + pd->s_skill->id=( script_isstringtype(st,2) ? skill->name2id(script_getstr(st,2)) : script_getnum(st,2) ); pd->s_skill->lv=script_getnum(st,3); pd->s_skill->delay=script_getnum(st,4); pd->s_skill->hp=script_getnum(st,5); pd->s_skill->sp=script_getnum(st,6); - + //Use delay as initial offset to avoid skill/heal exploits if (battle_config.pet_equip_required && pd->pet.equip == 0) pd->s_skill->timer = INVALID_TIMER; else - pd->s_skill->timer = iTimer->add_timer(iTimer->gettick()+pd->s_skill->delay*1000,pet_skill_support_timer,sd->bl.id,0); - + pd->s_skill->timer = timer->add(timer->gettick()+pd->s_skill->delay*1000,pet->skill_support_timer,sd->bl.id,0); + return true; } @@ -12116,16 +12763,25 @@ BUILDIN(petskillsupport) *------------------------------------------*/ /// skilleffect <skill id>,<level> /// skilleffect "<skill name>",<level> -BUILDIN(skilleffect) -{ +BUILDIN(skilleffect) { TBL_PC *sd; - - uint16 skill_id=( script_isstring(st,2) ? skill->name2id(script_getstr(st,2)) : script_getnum(st,2) ); + + uint16 skill_id=( script_isstringtype(st,2) ? skill->name2id(script_getstr(st,2)) : script_getnum(st,2) ); uint16 skill_lv=script_getnum(st,3); - sd=script_rid2sd(st); - + sd=script->rid2sd(st); + + if( sd == NULL ) + return false; + + /* ensure we're standing because the following packet causes the client to virtually set the char to stand, + * which leaves the server thinking it still is sitting. */ + if( pc_issit(sd) ) { + pc->setstand(sd); + skill->sit(sd,0); + clif->standing(&sd->bl); + } clif->skill_nodamage(&sd->bl,&sd->bl,skill_id,skill_lv,1); - + return true; } @@ -12134,65 +12790,64 @@ BUILDIN(skilleffect) *------------------------------------------*/ /// npcskilleffect <skill id>,<level>,<x>,<y> /// npcskilleffect "<skill name>",<level>,<x>,<y> -BUILDIN(npcskilleffect) -{ - struct block_list *bl= iMap->id2bl(st->oid); - - uint16 skill_id=( script_isstring(st,2) ? skill->name2id(script_getstr(st,2)) : script_getnum(st,2) ); +BUILDIN(npcskilleffect) { + struct block_list *bl= map->id2bl(st->oid); + + uint16 skill_id=( script_isstringtype(st,2) ? skill->name2id(script_getstr(st,2)) : script_getnum(st,2) ); uint16 skill_lv=script_getnum(st,3); int x=script_getnum(st,4); int y=script_getnum(st,5); - + if (bl) - clif->skill_poseffect(bl,skill_id,skill_lv,x,y,iTimer->gettick()); - + clif->skill_poseffect(bl,skill_id,skill_lv,x,y,timer->gettick()); + return true; } /*========================================== * Special effects [Valaris] *------------------------------------------*/ -BUILDIN(specialeffect) -{ - struct block_list *bl=iMap->id2bl(st->oid); +BUILDIN(specialeffect) { + struct block_list *bl=map->id2bl(st->oid); int type = script_getnum(st,2); enum send_target target = script_hasdata(st,3) ? (send_target)script_getnum(st,3) : AREA; - + if(bl==NULL) return true; - + if( script_hasdata(st,4) ) { - TBL_NPC *nd = npc_name2id(script_getstr(st,4)); + TBL_NPC *nd = npc->name2id(script_getstr(st,4)); if(nd) clif->specialeffect(&nd->bl, type, target); } else { if (target == SELF) { - TBL_PC *sd=script_rid2sd(st); + TBL_PC *sd=script->rid2sd(st); if (sd) clif->specialeffect_single(bl,type,sd->fd); } else { clif->specialeffect(bl, type, target); } } - + return true; } -BUILDIN(specialeffect2) -{ - TBL_PC *sd=script_rid2sd(st); +BUILDIN(specialeffect2) { + TBL_PC *sd; int type = script_getnum(st,2); enum send_target target = script_hasdata(st,3) ? (send_target)script_getnum(st,3) : AREA; - + if( script_hasdata(st,4) ) - sd = iMap->nick2sd(script_getstr(st,4)); - + sd = map->nick2sd(script_getstr(st,4)); + else + sd = script->rid2sd(st); + if (sd) clif->specialeffect(&sd->bl, type, target); - + return true; } @@ -12201,12 +12856,12 @@ BUILDIN(specialeffect2) *------------------------------------------*/ BUILDIN(nude) { - TBL_PC *sd = script_rid2sd(st); + TBL_PC *sd = script->rid2sd(st); int i, calcflag = 0; - + if( sd == NULL ) return true; - + for( i = 0 ; i < EQI_MAX; i++ ) { if( sd->equip_index[ i ] >= 0 ) { if( !calcflag ) @@ -12214,49 +12869,48 @@ BUILDIN(nude) pc->unequipitem( sd , sd->equip_index[ i ] , 2); } } - + if( calcflag ) - status_calc_pc(sd,0); - + status_calc_pc(sd,SCO_NONE); + return true; } /*========================================== * gmcommand [MouseJstr] *------------------------------------------*/ -BUILDIN(atcommand) -{ - TBL_PC dummy_sd; - TBL_PC* sd; +BUILDIN(atcommand) { + TBL_PC *sd, *dummy_sd = NULL; int fd; const char* cmd; - + bool ret = true; + cmd = script_getstr(st,2); - + if (st->rid) { - sd = script_rid2sd(st); + sd = script->rid2sd(st); + if( sd == NULL ) + return false; fd = sd->fd; } else { //Use a dummy character. - sd = &dummy_sd; + sd = dummy_sd = pc->get_dummy_sd(); fd = 0; - - memset(&dummy_sd, 0, sizeof(TBL_PC)); - if (st->oid) - { - struct block_list* bl = iMap->id2bl(st->oid); - memcpy(&dummy_sd.bl, bl, sizeof(struct block_list)); + + if (st->oid) { + struct block_list* bl = map->id2bl(st->oid); + memcpy(&sd->bl, bl, sizeof(struct block_list)); if (bl->type == BL_NPC) - safestrncpy(dummy_sd.status.name, ((TBL_NPC*)bl)->name, NAME_LENGTH); + safestrncpy(sd->status.name, ((TBL_NPC*)bl)->name, NAME_LENGTH); } } - - if (!atcommand->parse(fd, sd, cmd, 0)) { + + if (!atcommand->exec(fd, sd, cmd, false)) { ShowWarning("script: buildin_atcommand: failed to execute command '%s'\n", cmd); - script_reportsrc(st); - return false; + script->reportsrc(st); + ret = false; } - - return true; + if (dummy_sd) aFree(dummy_sd); + return ret; } /*========================================== @@ -12264,11 +12918,11 @@ BUILDIN(atcommand) *------------------------------------------*/ BUILDIN(dispbottom) { - TBL_PC *sd=script_rid2sd(st); + TBL_PC *sd=script->rid2sd(st); const char *message; message=script_getstr(st,2); if(sd) - clif->disp_onlyself(sd,message,(int)strlen(message)); + clif_disp_onlyself(sd,message,(int)strlen(message)); return true; } @@ -12280,15 +12934,15 @@ BUILDIN(recovery) { TBL_PC* sd; struct s_mapiterator* iter; - + iter = mapit_getallusers(); for( sd = (TBL_PC*)mapit->first(iter); mapit->exists(iter); sd = (TBL_PC*)mapit->next(iter) ) { if(pc_isdead(sd)) - status_revive(&sd->bl, 100, 100); + status->revive(&sd->bl, 100, 100); else status_percent_heal(&sd->bl, 100, 100); - clif->message(sd->fd,msg_txt(680)); + clif->message(sd->fd,msg_txt(880)); // "You have been recovered!" } mapit->free(iter); return true; @@ -12300,10 +12954,10 @@ BUILDIN(recovery) *------------------------------------------*/ BUILDIN(getpetinfo) { - TBL_PC *sd=script_rid2sd(st); + TBL_PC *sd=script->rid2sd(st); TBL_PET *pd; int type=script_getnum(st,2); - + if(!sd || !sd->pd) { if (type == 2) script_pushconststr(st,"null"); @@ -12312,7 +12966,7 @@ BUILDIN(getpetinfo) return true; } pd = sd->pd; - switch(type){ + switch(type) { case 0: script_pushint(st,pd->pet.pet_id); break; case 1: script_pushint(st,pd->pet.class_); break; case 2: script_pushstrcopy(st,pd->pet.name); break; @@ -12334,28 +12988,25 @@ BUILDIN(getpetinfo) *------------------------------------------*/ BUILDIN(gethominfo) { - TBL_PC *sd=script_rid2sd(st); - TBL_HOM *hd; - int type=script_getnum(st,2); - - hd = sd?sd->hd:NULL; - if(!homun_alive(hd)) - { + TBL_PC *sd=script->rid2sd(st); + int type = script_getnum(st,2); + + if(!sd || !sd->hd) { if (type == 2) script_pushconststr(st,"null"); else script_pushint(st,0); return true; } - - switch(type){ - case 0: script_pushint(st,hd->homunculus.hom_id); break; - case 1: script_pushint(st,hd->homunculus.class_); break; - case 2: script_pushstrcopy(st,hd->homunculus.name); break; - case 3: script_pushint(st,hd->homunculus.intimacy); break; - case 4: script_pushint(st,hd->homunculus.hunger); break; - case 5: script_pushint(st,hd->homunculus.rename_flag); break; - case 6: script_pushint(st,hd->homunculus.level); break; + + switch(type) { + case 0: script_pushint(st,sd->hd->homunculus.hom_id); break; + case 1: script_pushint(st,sd->hd->homunculus.class_); break; + case 2: script_pushstrcopy(st,sd->hd->homunculus.name); break; + case 3: script_pushint(st,sd->hd->homunculus.intimacy); break; + case 4: script_pushint(st,sd->hd->homunculus.hunger); break; + case 5: script_pushint(st,sd->hd->homunculus.rename_flag); break; + case 6: script_pushint(st,sd->hd->homunculus.level); break; default: script_pushint(st,0); break; @@ -12365,36 +13016,28 @@ BUILDIN(gethominfo) /// Retrieves information about character's mercenary /// getmercinfo <type>[,<char id>]; -BUILDIN(getmercinfo) -{ +BUILDIN(getmercinfo) { int type, char_id; struct map_session_data* sd; struct mercenary_data* md; - + type = script_getnum(st,2); - - if( script_hasdata(st,3) ) - { + + if( script_hasdata(st,3) ) { char_id = script_getnum(st,3); - - if( ( sd = iMap->charid2sd(char_id) ) == NULL ) - { + + if( ( sd = map->charid2sd(char_id) ) == NULL ) { ShowError("buildin_getmercinfo: No such character (char_id=%d).\n", char_id); script_pushnil(st); return false; } - } - else - { - if( ( sd = script_rid2sd(st) ) == NULL ) - { - script_pushnil(st); + } else { + if( ( sd = script->rid2sd(st) ) == NULL ) return true; - } } - + md = ( sd->status.mer_id && sd->md ) ? sd->md : NULL; - + switch( type ) { case 0: script_pushint(st,md ? md->mercenary.mercenary_id : 0); break; @@ -12405,46 +13048,48 @@ BUILDIN(getmercinfo) else script_pushconststr(st,""); break; - case 3: script_pushint(st,md ? mercenary_get_faith(md) : 0); break; - case 4: script_pushint(st,md ? mercenary_get_calls(md) : 0); break; + case 3: script_pushint(st,md ? mercenary->get_faith(md) : 0); break; + case 4: script_pushint(st,md ? mercenary->get_calls(md) : 0); break; case 5: script_pushint(st,md ? md->mercenary.kill_count : 0); break; - case 6: script_pushint(st,md ? mercenary_get_lifetime(md) : 0); break; + case 6: script_pushint(st,md ? mercenary->get_lifetime(md) : 0); break; case 7: script_pushint(st,md ? md->db->lv : 0); break; default: ShowError("buildin_getmercinfo: Invalid type %d (char_id=%d).\n", type, sd->status.char_id); script_pushnil(st); return false; } - + return true; } /*========================================== * Shows wether your inventory(and equips) contain - selected card or not. - checkequipedcard(4001); + * selected card or not. + * checkequipedcard(4001); *------------------------------------------*/ BUILDIN(checkequipedcard) { - TBL_PC *sd=script_rid2sd(st); - - if(sd){ - int n,i,c=0; - c=script_getnum(st,2); - - for(i=0;i<MAX_INVENTORY;i++){ - if(sd->status.inventory[i].nameid > 0 && sd->status.inventory[i].amount && sd->inventory_data[i]){ - if (itemdb_isspecial(sd->status.inventory[i].card[0])) - continue; - for(n=0;n<sd->inventory_data[i]->slot;n++){ - if(sd->status.inventory[i].card[n]==c){ - script_pushint(st,1); - return true; - } + int n,i,c=0; + TBL_PC *sd=script->rid2sd(st); + + if( sd == NULL ) + return false; + + c = script_getnum(st,2); + + for( i=0; i<MAX_INVENTORY; i++) { + if(sd->status.inventory[i].nameid > 0 && sd->status.inventory[i].amount && sd->inventory_data[i]) { + if (itemdb_isspecial(sd->status.inventory[i].card[0])) + continue; + for(n=0;n<sd->inventory_data[i]->slot;n++) { + if(sd->status.inventory[i].card[n]==c) { + script_pushint(st,1); + return true; } } } } + script_pushint(st,0); return true; } @@ -12455,12 +13100,12 @@ BUILDIN(jump_zero) sel=script_getnum(st,2); if(!sel) { int pos; - if( !data_islabel(script_getdata(st,3)) ){ + if( !data_islabel(script_getdata(st,3)) ) { ShowError("script: jump_zero: not label !\n"); st->state=END; return false; } - + pos=script_getnum(st,3); st->pos=pos; st->state=GOTO; @@ -12473,51 +13118,49 @@ BUILDIN(jump_zero) *------------------------------------------*/ BUILDIN(movenpc) { TBL_NPC *nd = NULL; - const char *npc; + const char *npc_name; int x,y; - - npc = script_getstr(st,2); + + npc_name = script_getstr(st,2); x = script_getnum(st,3); y = script_getnum(st,4); - - if ((nd = npc_name2id(npc)) == NULL) + + if ((nd = npc->name2id(npc_name)) == NULL) return -1; - + if (script_hasdata(st,5)) nd->dir = script_getnum(st,5) % 8; - npc_movenpc(nd, x, y); + npc->movenpc(nd, x, y); return true; } /*========================================== * message [MouseJstr] *------------------------------------------*/ -BUILDIN(message) -{ +BUILDIN(message) { const char *msg,*player; TBL_PC *pl_sd = NULL; - + player = script_getstr(st,2); msg = script_getstr(st,3); - - if((pl_sd=iMap->nick2sd((char *) player)) == NULL) + + if((pl_sd=map->nick2sd((char *) player)) == NULL) return true; clif->message(pl_sd->fd, msg); - + return true; } /*========================================== * npctalk (sends message to surrounding area) *------------------------------------------*/ -BUILDIN(npctalk) -{ +BUILDIN(npctalk) { const char* str; char name[NAME_LENGTH], message[256]; - - struct npc_data* nd = (struct npc_data *)iMap->id2bl(st->oid); + + struct npc_data* nd = (struct npc_data *)map->id2bl(st->oid); str = script_getstr(st,2); - + if(nd) { safestrncpy(name, nd->name, sizeof(name)); @@ -12525,65 +13168,55 @@ BUILDIN(npctalk) safesnprintf(message, sizeof(message), "%s : %s", name, str); clif->disp_overhead(&nd->bl, message); } - + return true; } // change npc walkspeed [Valaris] -BUILDIN(npcspeed) -{ +BUILDIN(npcspeed) { struct npc_data* nd; int speed; - + speed = script_getnum(st,2); - nd =(struct npc_data *)iMap->id2bl(st->oid); - + nd = (struct npc_data *)map->id2bl(st->oid); + if( nd ) { - if( nd->ud == &npc_base_ud ) { - nd->ud = NULL; - CREATE(nd->ud, struct unit_data, 1); - unit_dataset(&nd->bl); - } + unit->bl2ud2(&nd->bl); // ensure nd->ud is safe to edit nd->speed = speed; nd->ud->state.speed_changed = 1; } - + return true; } // make an npc walk to a position [Valaris] BUILDIN(npcwalkto) { - struct npc_data *nd=(struct npc_data *)iMap->id2bl(st->oid); + struct npc_data *nd=(struct npc_data *)map->id2bl(st->oid); int x=0,y=0; - + x=script_getnum(st,2); y=script_getnum(st,3); - - if(nd) { - if( nd->ud == &npc_base_ud ) { - nd->ud = NULL; - CREATE(nd->ud, struct unit_data, 1); - unit_dataset(&nd->bl); - } - + + if( nd ) { + unit->bl2ud2(&nd->bl); // ensure nd->ud is safe to edit if (!nd->status.hp) { - status_calc_npc(nd, true); + status_calc_npc(nd, SCO_FIRST); } else { - status_calc_npc(nd, false); + status_calc_npc(nd, SCO_NONE); } - unit_walktoxy(&nd->bl,x,y,0); + unit->walktoxy(&nd->bl,x,y,0); } - + return true; } // stop an npc's movement [Valaris] -BUILDIN(npcstop) -{ - struct npc_data *nd=(struct npc_data *)iMap->id2bl(st->oid); - - if(nd) { - unit_stop_walking(&nd->bl,1|4); +BUILDIN(npcstop) { + struct npc_data *nd = (struct npc_data *)map->id2bl(st->oid); + + if( nd ) { + unit->bl2ud2(&nd->bl); // ensure nd->ud is safe to edit + unit->stop_walking(&nd->bl,1|4); } - + return true; } @@ -12595,23 +13228,25 @@ BUILDIN(getlook) { int type,val; TBL_PC *sd; - sd=script_rid2sd(st); - + sd=script->rid2sd(st); + if( sd == NULL ) + return false; + type=script_getnum(st,2); - val=-1; + val = -1; switch(type) { - case LOOK_HAIR: val=sd->status.hair; break; //1 - case LOOK_WEAPON: val=sd->status.weapon; break; //2 - case LOOK_HEAD_BOTTOM: val=sd->status.head_bottom; break; //3 - case LOOK_HEAD_TOP: val=sd->status.head_top; break; //4 - case LOOK_HEAD_MID: val=sd->status.head_mid; break; //5 - case LOOK_HAIR_COLOR: val=sd->status.hair_color; break; //6 - case LOOK_CLOTHES_COLOR:val=sd->status.clothes_color; break; //7 - case LOOK_SHIELD: val=sd->status.shield; break; //8 - case LOOK_SHOES: break; //9 - case LOOK_ROBE: val=sd->status.robe; break; //12 + case LOOK_HAIR: val = sd->status.hair; break; //1 + case LOOK_WEAPON: val = sd->status.weapon; break; //2 + case LOOK_HEAD_BOTTOM: val = sd->status.head_bottom; break; //3 + case LOOK_HEAD_TOP: val = sd->status.head_top; break; //4 + case LOOK_HEAD_MID: val = sd->status.head_mid; break; //5 + case LOOK_HAIR_COLOR: val = sd->status.hair_color; break; //6 + case LOOK_CLOTHES_COLOR: val = sd->status.clothes_color; break; //7 + case LOOK_SHIELD: val = sd->status.shield; break; //8 + case LOOK_SHOES: break; //9 + case LOOK_ROBE: val = sd->status.robe; break; //12 } - + script_pushint(st,val); return true; } @@ -12623,15 +13258,13 @@ BUILDIN(getsavepoint) { TBL_PC* sd; int type; - - sd = script_rid2sd(st); - if (sd == NULL) { - script_pushint(st,0); - return true; - } - + + sd = script->rid2sd(st); + if( sd == NULL ) + return false; + type = script_getnum(st,2); - + switch(type) { case 0: script_pushstrcopy(st,mapindex_id2name(sd->status.save_point.map)); break; case 1: script_pushint(st,sd->status.save_point.x); break; @@ -12669,88 +13302,106 @@ BUILDIN(getmapxy) { struct block_list *bl = NULL; TBL_PC *sd=NULL; - - int num; + + int64 num; const char *name; char prefix; - + int x,y,type; char mapname[MAP_NAME_LENGTH]; - - if( !data_isreference(script_getdata(st,2)) ){ + + if( !data_isreference(script_getdata(st,2)) ) { ShowWarning("script: buildin_getmapxy: not mapname variable\n"); script_pushint(st,-1); return false; } - if( !data_isreference(script_getdata(st,3)) ){ + if( !data_isreference(script_getdata(st,3)) ) { ShowWarning("script: buildin_getmapxy: not mapx variable\n"); script_pushint(st,-1); return false; } - if( !data_isreference(script_getdata(st,4)) ){ + if( !data_isreference(script_getdata(st,4)) ) { ShowWarning("script: buildin_getmapxy: not mapy variable\n"); script_pushint(st,-1); return false; } + if( !is_string_variable(reference_getname(script_getdata(st, 2))) ) { + ShowWarning("script: buildin_getmapxy: %s is not a string variable\n",reference_getname(script_getdata(st, 2))); + script_pushint(st,-1); + return false; + } + + if( is_string_variable(reference_getname(script_getdata(st, 3))) ) { + ShowWarning("script: buildin_getmapxy: %s is a string variable, should be int\n",reference_getname(script_getdata(st, 3))); + script_pushint(st,-1); + return false; + } + + if( is_string_variable(reference_getname(script_getdata(st, 4))) ) { + ShowWarning("script: buildin_getmapxy: %s is a string variable, should be int\n",reference_getname(script_getdata(st, 4))); + script_pushint(st,-1); + return false; + } + // Possible needly check function parameters on C_STR,C_INT,C_INT type=script_getnum(st,5); - - switch (type){ - case 0: //Get Character Position + + switch (type) { + case 0: //Get Character Position if( script_hasdata(st,6) ) - sd=iMap->nick2sd(script_getstr(st,6)); + sd=map->nick2sd(script_getstr(st,6)); else - sd=script_rid2sd(st); - + sd=script->rid2sd(st); + if (sd) bl = &sd->bl; break; - case 1: //Get NPC Position + case 1: //Get NPC Position if( script_hasdata(st,6) ) { struct npc_data *nd; - nd=npc_name2id(script_getstr(st,6)); + nd=npc->name2id(script_getstr(st,6)); if (nd) bl = &nd->bl; } else //In case the origin is not an npc? - bl=iMap->id2bl(st->oid); + bl=map->id2bl(st->oid); break; - case 2: //Get Pet Position + case 2: //Get Pet Position if(script_hasdata(st,6)) - sd=iMap->nick2sd(script_getstr(st,6)); + sd=map->nick2sd(script_getstr(st,6)); else - sd=script_rid2sd(st); - + sd=script->rid2sd(st); + if (sd && sd->pd) bl = &sd->pd->bl; break; - case 3: //Get Mob Position + case 3: //Get Mob Position break; //Not supported? - case 4: //Get Homun Position + case 4: //Get Homun Position if(script_hasdata(st,6)) - sd=iMap->nick2sd(script_getstr(st,6)); + sd=map->nick2sd(script_getstr(st,6)); else - sd=script_rid2sd(st); - + sd=script->rid2sd(st); + if (sd && sd->hd) bl = &sd->hd->bl; break; case 5: //Get Mercenary Position if(script_hasdata(st,6)) - sd=iMap->nick2sd(script_getstr(st,6)); + sd=map->nick2sd(script_getstr(st,6)); else - sd=script_rid2sd(st); - + sd=script->rid2sd(st); + if (sd && sd->md) bl = &sd->md->bl; break; case 6: //Get Elemental Position if(script_hasdata(st,6)) - sd=iMap->nick2sd(script_getstr(st,6)); + sd=map->nick2sd(script_getstr(st,6)); else - sd=script_rid2sd(st); - + sd=script->rid2sd(st); + if (sd && sd->ed) bl = &sd->ed->bl; break; @@ -12763,44 +13414,44 @@ BUILDIN(getmapxy) script_pushint(st,-1); return true; } - + x= bl->x; y= bl->y; - safestrncpy(mapname, map[bl->m].name, MAP_NAME_LENGTH); - + safestrncpy(mapname, map->list[bl->m].name, MAP_NAME_LENGTH); + //Set MapName$ num=st->stack->stack_data[st->start+2].u.num; - name=get_str(num&0x00ffffff); + name=script->get_str(script_getvarid(num)); prefix=*name; if(not_server_variable(prefix)) - sd=script_rid2sd(st); + sd=script->rid2sd(st); else sd=NULL; - set_reg(st,sd,num,name,(void*)mapname,script_getref(st,2)); - + script->set_reg(st,sd,num,name,(void*)mapname,script_getref(st,2)); + //Set MapX num=st->stack->stack_data[st->start+3].u.num; - name=get_str(num&0x00ffffff); + name=script->get_str(script_getvarid(num)); prefix=*name; - + if(not_server_variable(prefix)) - sd=script_rid2sd(st); + sd=script->rid2sd(st); else sd=NULL; - set_reg(st,sd,num,name,(void*)__64BPTRSIZE(x),script_getref(st,3)); - + script->set_reg(st,sd,num,name,(void*)h64BPTRSIZE(x),script_getref(st,3)); + //Set MapY num=st->stack->stack_data[st->start+4].u.num; - name=get_str(num&0x00ffffff); + name=script->get_str(script_getvarid(num)); prefix=*name; - + if(not_server_variable(prefix)) - sd=script_rid2sd(st); + sd=script->rid2sd(st); else sd=NULL; - set_reg(st,sd,num,name,(void*)__64BPTRSIZE(y),script_getref(st,4)); - + script->set_reg(st,sd,num,name,(void*)h64BPTRSIZE(y),script_getref(st,4)); + //Return Success value script_pushint(st,0); return true; @@ -12813,11 +13464,11 @@ BUILDIN(logmes) { const char *str; TBL_PC* sd; - - sd = script_rid2sd(st); + + sd = script->rid2sd(st); if( sd == NULL ) return false; - + str = script_getstr(st,2); logs->npc(sd,str); return true; @@ -12825,36 +13476,36 @@ BUILDIN(logmes) BUILDIN(summon) { - int _class, timeout=0; + int class_, timeout=0; const char *str,*event=""; TBL_PC *sd; struct mob_data *md; - int tick = iTimer->gettick(); - - sd=script_rid2sd(st); + int64 tick = timer->gettick(); + + sd=script->rid2sd(st); if (!sd) return true; - - str =script_getstr(st,2); - _class=script_getnum(st,3); + + str = script_getstr(st,2); + class_ = script_getnum(st,3); if( script_hasdata(st,4) ) timeout=script_getnum(st,4); - if( script_hasdata(st,5) ){ + if( script_hasdata(st,5) ) { event=script_getstr(st,5); - check_event(st, event); + script->check_event(st, event); } - + clif->skill_poseffect(&sd->bl,AM_CALLHOMUN,1,sd->bl.x,sd->bl.y,tick); - - md = mob_once_spawn_sub(&sd->bl, sd->bl.m, sd->bl.x, sd->bl.y, str, _class, event, SZ_SMALL, AI_NONE); + + md = mob->once_spawn_sub(&sd->bl, sd->bl.m, sd->bl.x, sd->bl.y, str, class_, event, SZ_MEDIUM, AI_NONE); if (md) { md->master_id=sd->bl.id; md->special_state.ai = AI_ATTACK; if( md->deletetimer != INVALID_TIMER ) - iTimer->delete_timer(md->deletetimer, mob_timer_delete); - md->deletetimer = iTimer->add_timer(tick+(timeout>0?timeout*1000:60000),mob_timer_delete,md->bl.id,0); - mob_spawn (md); //Now it is ready for spawning. + timer->delete(md->deletetimer, mob->timer_delete); + md->deletetimer = timer->add(tick+(timeout>0?timeout*1000:60000),mob->timer_delete,md->bl.id,0); + mob->spawn (md); //Now it is ready for spawning. clif->specialeffect(&md->bl,344,AREA); - sc_start4(&md->bl, SC_MODECHANGE, 100, 1, 0, MD_AGGRESSIVE, 0, 60000); + sc_start4(NULL, &md->bl, SC_MODECHANGE, 100, 1, 0, MD_AGGRESSIVE, 0, 60000); } return true; } @@ -12862,15 +13513,13 @@ BUILDIN(summon) /*========================================== * Checks whether it is daytime/nighttime *------------------------------------------*/ -BUILDIN(isnight) -{ - script_pushint(st,(iMap->night_flag == 1)); +BUILDIN(isnight) { + script_pushint(st,(map->night_flag == 1)); return true; } -BUILDIN(isday) -{ - script_pushint(st,(iMap->night_flag == 0)); +BUILDIN(isday) { + script_pushint(st,(map->night_flag == 0)); return true; } @@ -12883,18 +13532,16 @@ BUILDIN(isequippedcnt) TBL_PC *sd; int i, j, k, id = 1; int ret = 0; - - sd = script_rid2sd(st); - if (!sd) { //If the player is not attached it is a script error anyway... but better prevent the map server from crashing... - script_pushint(st,0); - return true; - } - + + sd = script->rid2sd(st); + if( sd == NULL ) + return false; + for (i=0; id!=0; i++) { - FETCH (i+2, id) else id = 0; + script_fetch(st,i+2, id); if (id <= 0) continue; - + for (j=0; j<EQI_MAX; j++) { int index; index = sd->equip_index[j]; @@ -12902,10 +13549,10 @@ BUILDIN(isequippedcnt) if(j == EQI_HAND_R && sd->equip_index[EQI_HAND_L] == index) continue; if(j == EQI_HEAD_MID && sd->equip_index[EQI_HEAD_LOW] == index) continue; if(j == EQI_HEAD_TOP && (sd->equip_index[EQI_HEAD_MID] == index || sd->equip_index[EQI_HEAD_LOW] == index)) continue; - + if(!sd->inventory_data[index]) continue; - + if (itemdb_type(id) != IT_CARD) { //No card. Count amount in inventory. if (sd->inventory_data[index]->nameid == id) ret+= sd->status.inventory[index].amount; @@ -12919,7 +13566,7 @@ BUILDIN(isequippedcnt) } } } - + script_pushint(st,ret); return true; } @@ -12938,18 +13585,16 @@ BUILDIN(isequipped) int ret = -1; //Original hash to reverse it when full check fails. unsigned int setitem_hash = 0, setitem_hash2 = 0; - - sd = script_rid2sd(st); - - if (!sd) { //If the player is not attached it is a script error anyway... but better prevent the map server from crashing... - script_pushint(st,0); - return true; - } - + + sd = script->rid2sd(st); + + if( sd == NULL ) + return false; + setitem_hash = sd->bonus.setitem_hash; setitem_hash2 = sd->bonus.setitem_hash2; for (i=0; id!=0; i++) { - FETCH (i+2, id) else id = 0; + script_fetch(st,i+2, id); if (id <= 0) continue; flag = 0; @@ -12959,10 +13604,10 @@ BUILDIN(isequipped) if(j == EQI_HAND_R && sd->equip_index[EQI_HAND_L] == index) continue; if(j == EQI_HEAD_MID && sd->equip_index[EQI_HEAD_LOW] == index) continue; if(j == EQI_HEAD_TOP && (sd->equip_index[EQI_HEAD_MID] == index || sd->equip_index[EQI_HEAD_LOW] == index)) continue; - + if(!sd->inventory_data[index]) continue; - + if (itemdb_type(id) != IT_CARD) { if (sd->inventory_data[index]->nameid != id) continue; @@ -12972,18 +13617,18 @@ BUILDIN(isequipped) if (sd->inventory_data[index]->slot == 0 || itemdb_isspecial(sd->status.inventory[index].card[0])) continue; - - for (k = 0; k < sd->inventory_data[index]->slot; k++) - { //New hash system which should support up to 4 slots on any equipment. [Skotlex] + + for (k = 0; k < sd->inventory_data[index]->slot; k++) { + //New hash system which should support up to 4 slots on any equipment. [Skotlex] unsigned int hash = 0; if (sd->status.inventory[index].card[k] != id) continue; - + hash = 1<<((j<5?j:j-5)*4 + k); // check if card is already used by another set if ( ( j < 5 ? sd->bonus.setitem_hash : sd->bonus.setitem_hash2 ) & hash) continue; - + // We have found a match flag = 1; // Set hash so this card cannot be used by another @@ -13014,26 +13659,28 @@ BUILDIN(isequipped) * Check how many given inserted cards in the CURRENT * weapon - used for 2/15's cards patch [Lupus] *------------------------------------------------*/ -BUILDIN(cardscnt) -{ +BUILDIN(cardscnt) { TBL_PC *sd; int i, k, id = 1; int ret = 0; int index; - - sd = script_rid2sd(st); - + + sd = script->rid2sd(st); + + if( sd == NULL ) + return false; + for (i=0; id!=0; i++) { - FETCH (i+2, id) else id = 0; + script_fetch(st,i+2, id); if (id <= 0) continue; - - index = current_equip_item_index; //we get CURRENT WEAPON inventory index from status.c [Lupus] + + index = status->current_equip_item_index; //we get CURRENT WEAPON inventory index from status.c [Lupus] if(index < 0) continue; - + if(!sd->inventory_data[index]) continue; - + if(itemdb_type(id) != IT_CARD) { if (sd->inventory_data[index]->nameid == id) ret+= sd->status.inventory[index].amount; @@ -13047,7 +13694,7 @@ BUILDIN(cardscnt) } } script_pushint(st,ret); - // script_pushint(st,current_equip_item_index); + // script_pushint(st,status->current_equip_item_index); return true; } @@ -13055,27 +13702,26 @@ BUILDIN(cardscnt) * Returns the refined number of the current item, or an * item with inventory index specified *-------------------------------------------------------*/ -BUILDIN(getrefine) -{ +BUILDIN(getrefine) { TBL_PC *sd; - if ((sd = script_rid2sd(st))!= NULL) - script_pushint(st,sd->status.inventory[current_equip_item_index].refine); - else - script_pushint(st,0); + + sd = script->rid2sd(st); + if( sd == NULL ) + return false; + + script_pushint(st,sd->status.inventory[status->current_equip_item_index].refine); return true; } /*======================================================= * Day/Night controls *-------------------------------------------------------*/ -BUILDIN(night) -{ - if (iMap->night_flag != 1) pc->map_night_timer(pc->night_timer_tid, 0, 0, 1); +BUILDIN(night) { + if (map->night_flag != 1) pc->map_night_timer(pc->night_timer_tid, 0, 0, 1); return true; } -BUILDIN(day) -{ - if (iMap->night_flag != 0) pc->map_day_timer(pc->day_timer_tid, 0, 0, 1); +BUILDIN(day) { + if (map->night_flag != 0) pc->map_day_timer(pc->day_timer_tid, 0, 0, 1); return true; } @@ -13087,12 +13733,12 @@ BUILDIN(unequip) int i; size_t num; TBL_PC *sd; - + num = script_getnum(st,2); - sd = script_rid2sd(st); - if( sd != NULL && num >= 1 && num <= ARRAYLENGTH(equip) ) + sd = script->rid2sd(st); + if( sd != NULL && num >= 1 && num <= ARRAYLENGTH(script->equip) ) { - i = pc->checkequip(sd,equip[num-1]); + i = pc->checkequip(sd,script->equip[num-1]); if (i >= 0) pc->unequipitem(sd,i,1|2); } @@ -13104,19 +13750,21 @@ BUILDIN(equip) int nameid=0,i; TBL_PC *sd; struct item_data *item_data; - - sd = script_rid2sd(st); - + + sd = script->rid2sd(st); + if( sd == NULL ) + return false; + nameid=script_getnum(st,2); - if((item_data = itemdb_exists(nameid)) == NULL) + if((item_data = itemdb->exists(nameid)) == NULL) { ShowError("wrong item ID : equipitem(%i)\n",nameid); return false; } - ARR_FIND( 0, MAX_INVENTORY, i, sd->status.inventory[i].nameid == nameid ); + ARR_FIND( 0, MAX_INVENTORY, i, sd->status.inventory[i].nameid == nameid && sd->status.inventory[i].equip == 0 ); if( i < MAX_INVENTORY ) pc->equipitem(sd,i,item_data->equip); - + return true; } @@ -13126,19 +13774,19 @@ BUILDIN(autoequip) struct item_data *item_data; nameid=script_getnum(st,2); flag=script_getnum(st,3); - - if( ( item_data = itemdb_exists(nameid) ) == NULL ) + + if( ( item_data = itemdb->exists(nameid) ) == NULL ) { ShowError("buildin_autoequip: Invalid item '%d'.\n", nameid); return false; } - - if( !itemdb_isequip2(item_data) ) + + if( !itemdb->isequip2(item_data) ) { ShowError("buildin_autoequip: Item '%d' cannot be equipped.\n", nameid); return false; } - + item_data->flag.autoequip = flag>0?1:0; return true; } @@ -13146,15 +13794,15 @@ BUILDIN(autoequip) BUILDIN(setbattleflag) { const char *flag, *value; - + flag = script_getstr(st,2); value = script_getstr(st,3); // HACK: Retrieve number as string (auto-converted) for battle_set_value - + if (battle->config_set_value(flag, value) == 0) ShowWarning("buildin_setbattleflag: unknown battle_config flag '%s'\n",flag); else ShowInfo("buildin_setbattleflag: battle_config flag '%s' is now set to '%s'.\n",flag,value); - + return true; } @@ -13171,10 +13819,10 @@ BUILDIN(getbattleflag) //------------------------------------------------------- BUILDIN(getstrlen) { - + const char *str = script_getstr(st,2); int len = (str) ? (int)strlen(str) : 0; - + script_pushint(st,len); return true; } @@ -13186,9 +13834,9 @@ BUILDIN(charisalpha) { const char *str=script_getstr(st,2); int pos=script_getnum(st,3); - + int val = ( str && pos >= 0 && (unsigned int)pos < strlen(str) ) ? ISALPHA( str[pos] ) != 0 : 0; - + script_pushint(st,val); return true; } @@ -13200,9 +13848,9 @@ BUILDIN(charisupper) { const char *str = script_getstr(st,2); int pos = script_getnum(st,3); - + int val = ( str && pos >= 0 && (unsigned int)pos < strlen(str) ) ? ISUPPER( str[pos] ) : 0; - + script_pushint(st,val); return true; } @@ -13214,9 +13862,9 @@ BUILDIN(charislower) { const char *str = script_getstr(st,2); int pos = script_getnum(st,3); - + int val = ( str && pos >= 0 && (unsigned int)pos < strlen(str) ) ? ISLOWER( str[pos] ) : 0; - + script_pushint(st,val); return true; } @@ -13227,7 +13875,7 @@ BUILDIN(charislower) BUILDIN(charat) { const char *str = script_getstr(st,2); int pos = script_getnum(st,3); - + if( pos >= 0 && (unsigned int)pos < strlen(str) ) { char output[2]; output[0] = str[pos]; @@ -13247,10 +13895,10 @@ BUILDIN(setchar) const char *c = script_getstr(st,3); int index = script_getnum(st,4); char *output = aStrdup(str); - + if(index >= 0 && index < strlen(output)) output[index] = *c; - + script_pushstr(st, output); return true; } @@ -13265,19 +13913,19 @@ BUILDIN(insertchar) int index = script_getnum(st,4); char *output; size_t len = strlen(str); - + if(index < 0) index = 0; else if(index > len) - index = len; - + index = (int)len; + output = (char*)aMalloc(len + 2); - + memcpy(output, str, index); output[index] = c[0]; memcpy(&output[index+1], &str[index], len - index); output[len+1] = '\0'; - + script_pushstr(st, output); return true; } @@ -13291,19 +13939,19 @@ BUILDIN(delchar) int index = script_getnum(st,3); char *output; size_t len = strlen(str); - + if(index < 0 || index > len) { //return original output = aStrdup(str); script_pushstr(st, output); return true; } - + output = (char*)aMalloc(len); - + memcpy(output, str, index); memcpy(&output[index], &str[index+1], len - index); - + script_pushstr(st, output); return true; } @@ -13316,12 +13964,12 @@ BUILDIN(strtoupper) const char *str = script_getstr(st,2); char *output = aStrdup(str); char *cursor = output; - + while (*cursor != '\0') { *cursor = TOUPPER(*cursor); cursor++; } - + script_pushstr(st, output); return true; } @@ -13334,12 +13982,12 @@ BUILDIN(strtolower) const char *str = script_getstr(st,2); char *output = aStrdup(str); char *cursor = output; - + while (*cursor != '\0') { *cursor = TOLOWER(*cursor); cursor++; } - + script_pushstr(st, output); return true; } @@ -13353,18 +14001,18 @@ BUILDIN(substr) char *output; int start = script_getnum(st,3); int end = script_getnum(st,4); - + int len = 0; - + if(start >= 0 && end < strlen(str) && start <= end) { len = end - start + 1; output = (char*)aMalloc(len + 1); memcpy(output, &str[start], len); } else output = (char*)aMalloc(1); - + output[len] = '\0'; - + script_pushstr(st, output); return true; } @@ -13382,54 +14030,46 @@ BUILDIN(explode) size_t len = strlen(str); int i = 0, j = 0; int start; - - + + char *temp; const char* name; - + TBL_PC* sd = NULL; - + temp = (char*)aMalloc(len + 1); - + if( !data_isreference(data) ) { ShowError("script:explode: not a variable\n"); - script_reportdata(data); + script->reportdata(data); st->state = END; return false;// not a variable } - + id = reference_getid(data); start = reference_getindex(data); name = reference_getname(data); - - if( not_array_variable(*name) ) - { - ShowError("script:explode: illegal scope\n"); - script_reportdata(data); - st->state = END; - return false;// not supported - } - + if( !is_string_variable(name) ) { ShowError("script:explode: not string array\n"); - script_reportdata(data); + script->reportdata(data); st->state = END; return false;// data type mismatch } - + if( not_server_variable(*name) ) { - sd = script_rid2sd(st); + sd = script->rid2sd(st); if( sd == NULL ) return true;// no player attached } - + while(str[i] != '\0') { if(str[i] == delimiter && start < SCRIPT_MAX_ARRAYSIZE-1) { //break at delimiter but ignore after reaching last array index temp[j] = '\0'; - set_reg(st, sd, reference_uid(id, start++), name, (void*)temp, reference_getref(data)); + script->set_reg(st, sd, reference_uid(id, start++), name, (void*)temp, reference_getref(data)); j = 0; ++i; } else { @@ -13438,8 +14078,8 @@ BUILDIN(explode) } //set last string temp[j] = '\0'; - set_reg(st, sd, reference_uid(id, start), name, (void*)temp, reference_getref(data)); - + script->set_reg(st, sd, reference_uid(id, start), name, (void*)temp, reference_getref(data)); + aFree(temp); return true; } @@ -13452,63 +14092,55 @@ BUILDIN(implode) { struct script_data* data = script_getdata(st, 2); const char *glue = NULL, *name, *temp; - int32 glue_len = 0, array_size, id; - size_t len = 0; - int i, k = 0; - + uint32 array_size, id; + size_t len = 0, glue_len = 0, k = 0; + int i; + TBL_PC* sd = NULL; - + char *output; - + if( !data_isreference(data) ) { ShowError("script:implode: not a variable\n"); - script_reportdata(data); + script->reportdata(data); st->state = END; return false;// not a variable } - + id = reference_getid(data); name = reference_getname(data); - - if( not_array_variable(*name) ) - { - ShowError("script:implode: illegal scope\n"); - script_reportdata(data); - st->state = END; - return false;// not supported - } - + if( !is_string_variable(name) ) { ShowError("script:implode: not string array\n"); - script_reportdata(data); + script->reportdata(data); st->state = END; return false;// data type mismatch } - + if( not_server_variable(*name) ) { - sd = script_rid2sd(st); + sd = script->rid2sd(st); if( sd == NULL ) return true;// no player attached } - + //count chars - array_size = getarraysize(st, id, reference_getindex(data), is_string_variable(name), reference_getref(data)) - 1; - - if(array_size == -1) //empty array check (AmsTaff) - { - ShowWarning("script:implode: array length = 0\n"); - output = (char*)aMalloc(sizeof(char)*5); - sprintf(output,"%s","NULL"); + array_size = script->array_highest_key(st,sd,name,reference_getref(data)) - 1; + + if(array_size == -1) { + //empty array check (AmsTaff) + ShowWarning("script:implode: array length = 0\n"); + output = (char*)aMalloc(sizeof(char)*5); + sprintf(output,"%s","NULL"); } else { for(i = 0; i <= array_size; ++i) { temp = (char*) script->get_val2(st, reference_uid(id, i), reference_getref(data)); len += strlen(temp); script_removetop(st, -1, 0); } - + //allocate mem if( script_hasdata(st,3) ) { glue = script_getstr(st,3); @@ -13516,7 +14148,7 @@ BUILDIN(implode) len += glue_len * (array_size); } output = (char*)aMalloc(len + 1); - + //build output for(i = 0; i < array_size; ++i) { temp = (char*) script->get_val2(st, reference_uid(id, i), reference_getref(data)); @@ -13534,10 +14166,10 @@ BUILDIN(implode) memcpy(&output[k], temp, len); k += len; script_removetop(st, -1, 0); - + output[k] = '\0'; } - + script_pushstr(st, output); return true; } @@ -13547,232 +14179,242 @@ 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 len, argc = 0, arg = 0, buf2_len = 0; - const char* format; - char* p; - char* q; - char* buf = NULL; - char* buf2 = NULL; - struct script_data* data; - 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){ +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"); - if(buf) 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"); - if(buf) 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); - } - - // Passed more, than needed - if(arg<argc){ - ShowWarning("buildin_sprintf: Unused arguments passed.\n"); - script_reportsrc(st); - } - - script_pushstrcopy(st, StrBuf->Value(&final_buf)); - - if(buf) aFree(buf); - if(buf2) aFree(buf2); - StrBuf->Destroy(&final_buf); - - return true; + 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"); + if(buf) 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"); + if(buf) 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); + } + + // Passed more, than needed + if(arg<argc) { + ShowWarning("buildin_sprintf: Unused arguments passed.\n"); + script->reportsrc(st); + } + + script_pushstrcopy(st, StrBuf->Value(&final_buf)); + + if(buf) aFree(buf); + if(buf2) aFree(buf2); + StrBuf->Destroy(&final_buf); + + return true; } //======================================================= // sscanf(<str>, <format>, ...); // Implements C sscanf. //------------------------------------------------------- -BUILDIN(sscanf){ - unsigned int argc, arg = 0, len; - struct script_data* data; - struct map_session_data* sd = NULL; - const char* str; - const char* format; - const char* p; - const char* q; - char* buf = NULL; - char* buf_p; - char* ref_str = NULL; - int ref_int; - - // Get data - str = script_getstr(st, 2); - format = script_getstr(st, 3); - argc = script_lastdata(st)-3; - - len = strlen(format); - CREATE(buf, char, len*2+1); - - // Issue sscanf for each parameter - *buf = 0; - q = format; - while((p = strchr(q, '%'))){ - if(p!=q){ - strncat(buf, q, (size_t)(p-q)); - q = p; - } - p = q+1; - if(*p=='*' || *p=='%'){ // Skip - strncat(buf, q, 2); - q+=2; - continue; - } - if(arg>=argc){ - ShowError("buildin_sscanf: Not enough arguments passed!\n"); - script_pushint(st, -1); - if(buf) aFree(buf); - if(ref_str) aFree(ref_str); - return false; - } - if((p = strchr(q+1, '%'))==NULL){ - p = strchr(q, 0); // EOS - } - len = p-q; - strncat(buf, q, len); - q = p; - - // Validate output - data = script_getdata(st, arg+4); - if(!data_isreference(data) || !reference_tovariable(data)){ - ShowError("buildin_sscanf: Target argument is not a variable!\n"); - script_pushint(st, -1); - if(buf) aFree(buf); - if(ref_str) aFree(ref_str); - return false; - } - buf_p = reference_getname(data); - if(not_server_variable(*buf_p) && (sd = script_rid2sd(st))==NULL){ - script_pushint(st, -1); - if(buf) aFree(buf); - if(ref_str) aFree(ref_str); - return true; - } - - // Save value if any - if(buf_p[strlen(buf_p)-1]=='$'){ // String - if(ref_str==NULL){ - CREATE(ref_str, char, strlen(str)+1); - } - if(sscanf(str, buf, ref_str)==0){ - break; - } - set_reg(st, sd, reference_uid( reference_getid(data), reference_getindex(data) ), buf_p, (void *)(ref_str), reference_getref(data)); - } else { // Number - if(sscanf(str, buf, &ref_int)==0){ - break; - } - set_reg(st, sd, reference_uid( reference_getid(data), reference_getindex(data) ), buf_p, (void *)__64BPTRSIZE(ref_int), reference_getref(data)); - } - arg++; - - // Disable used format (%... -> %*...) - buf_p = strchr(buf, 0); - memmove(buf_p-len+2, buf_p-len+1, len); - *(buf_p-len+1) = '*'; - } - - script_pushint(st, arg); - if(buf) aFree(buf); - if(ref_str) aFree(ref_str); - - return true; +BUILDIN(sscanf) { + unsigned int argc, arg = 0; + struct script_data* data; + struct map_session_data* sd = NULL; + const char* str; + const char* format; + const char* p; + const char* q; + char* buf = NULL; + char* buf_p; + char* ref_str = NULL; + int ref_int; + size_t len; + + // Get data + str = script_getstr(st, 2); + format = script_getstr(st, 3); + argc = script_lastdata(st)-3; + + len = strlen(format); + + if (len != 0 && strlen(str) == 0) { + // If the source string is empty but the format string is not, we return -1 + // according to the C specs. (if the format string is also empty, we shall + // continue and return 0: 0 conversions took place out of the 0 attempted.) + script_pushint(st, -1); + return true; + } + + CREATE(buf, char, len*2+1); + + // Issue sscanf for each parameter + *buf = 0; + q = format; + while((p = strchr(q, '%'))) { + if(p!=q) { + strncat(buf, q, (size_t)(p-q)); + q = p; + } + p = q+1; + if(*p=='*' || *p=='%') { // Skip + strncat(buf, q, 2); + q+=2; + continue; + } + if(arg>=argc) { + ShowError("buildin_sscanf: Not enough arguments passed!\n"); + script_pushint(st, -1); + if(buf) aFree(buf); + if(ref_str) aFree(ref_str); + return false; + } + if((p = strchr(q+1, '%'))==NULL) { + p = strchr(q, 0); // EOS + } + len = p-q; + strncat(buf, q, len); + q = p; + + // Validate output + data = script_getdata(st, arg+4); + if(!data_isreference(data) || !reference_tovariable(data)) { + ShowError("buildin_sscanf: Target argument is not a variable!\n"); + script_pushint(st, -1); + if(buf) aFree(buf); + if(ref_str) aFree(ref_str); + return false; + } + buf_p = reference_getname(data); + if(not_server_variable(*buf_p) && (sd = script->rid2sd(st))==NULL) { + script_pushint(st, -1); + if(buf) aFree(buf); + if(ref_str) aFree(ref_str); + return true; + } + + // Save value if any + if(buf_p[strlen(buf_p)-1]=='$') { // String + if(ref_str==NULL) { + CREATE(ref_str, char, strlen(str)+1); + } + if(sscanf(str, buf, ref_str)==0) { + break; + } + script->set_reg(st, sd, reference_uid( reference_getid(data), reference_getindex(data) ), buf_p, (void *)(ref_str), reference_getref(data)); + } else { // Number + if(sscanf(str, buf, &ref_int)==0) { + break; + } + script->set_reg(st, sd, reference_uid( reference_getid(data), reference_getindex(data) ), buf_p, (void *)h64BPTRSIZE(ref_int), reference_getref(data)); + } + arg++; + + // Disable used format (%... -> %*...) + buf_p = strchr(buf, 0); + memmove(buf_p-len+2, buf_p-len+1, len); + *(buf_p-len+1) = '*'; + } + + script_pushint(st, arg); + if(buf) aFree(buf); + if(ref_str) aFree(ref_str); + + return true; } //======================================================= @@ -13787,17 +14429,17 @@ BUILDIN(strpos) { const char *needle = script_getstr(st,3); int i; size_t len; - + if( script_hasdata(st,4) ) i = script_getnum(st,4); else i = 0; - + if (needle[0] == '\0') { script_pushint(st, -1); return true; } - + len = strlen(haystack); for ( ; i < len; ++i ) { if ( haystack[i] == *needle ) { @@ -13835,48 +14477,47 @@ BUILDIN(replacestr) size_t findlen = strlen(find); struct StringBuf output; bool usecase = true; - + int count = 0; int numFinds = 0; int i = 0, f = 0; - + if(findlen == 0) { ShowError("script:replacestr: Invalid search length.\n"); st->state = END; return false; } - + if(script_hasdata(st, 5)) { - if( !script_isstring(st,5) ) + if( script_isinttype(st,5) ) { usecase = script_getnum(st, 5) != 0; - else { - ShowError("script:replacestr: Invalid usecase value. Expected int got string\n"); + } else { + ShowError("script:replacestr: Invalid usecase value. Expected int.\n"); st->state = END; return false; } } - + if(script_hasdata(st, 6)) { - count = script_getnum(st, 6); - if(count == 0) { - ShowError("script:replacestr: Invalid count value. Expected int got string\n"); + if (!script_isinttype(st, 5) || (count = script_getnum(st, 6) == 0)) { + ShowError("script:replacestr: Invalid count value. Expected int.\n"); st->state = END; return false; } } - + StrBuf->Init(&output); - + for(; i < inputlen; i++) { - if(count && count == numFinds) { //found enough, stop looking - break; + if(count && count == numFinds) { + break; //found enough, stop looking } - + for(f = 0; f <= findlen; f++) { if(f == findlen) { //complete match numFinds++; StrBuf->AppendStr(&output, replace); - + i += findlen - 1; break; } else { @@ -13894,11 +14535,11 @@ BUILDIN(replacestr) } } } - + //append excess after enough found if(i < inputlen) StrBuf->AppendStr(&output, &(input[i])); - + script_pushstrcopy(st, StrBuf->Value(&output)); StrBuf->Destroy(&output); return true; @@ -13917,26 +14558,26 @@ BUILDIN(countstr) size_t inputlen = strlen(input); size_t findlen = strlen(find); bool usecase = true; - + int numFinds = 0; int i = 0, f = 0; - + if(findlen == 0) { ShowError("script:countstr: Invalid search length.\n"); st->state = END; return false; } - + if(script_hasdata(st, 4)) { - if( !script_isstring(st,4) ) + if( script_isinttype(st,4) ) usecase = script_getnum(st, 4) != 0; else { - ShowError("script:countstr: Invalid usecase value. Expected int got string\n"); + ShowError("script:countstr: Invalid usecase value. Expected int.\n"); st->state = END; return false; } } - + for(; i < inputlen; i++) { for(f = 0; f <= findlen; f++) { if(f == findlen) { //complete match @@ -13968,70 +14609,80 @@ BUILDIN(countstr) /// setnpcdisplay("<npc name>", "<new display name>", <new class id>) -> <int> /// setnpcdisplay("<npc name>", "<new display name>") -> <int> /// setnpcdisplay("<npc name>", <new class id>) -> <int> -BUILDIN(setnpcdisplay) -{ +BUILDIN(setnpcdisplay) { const char* name; const char* newname = NULL; int class_ = -1, size = -1; - struct script_data* data; struct npc_data* nd; - + name = script_getstr(st,2); - data = script_getdata(st,3); - + if( script_hasdata(st,4) ) class_ = script_getnum(st,4); if( script_hasdata(st,5) ) size = script_getnum(st,5); - - script->get_val(st, data); - if( data_isstring(data) ) - newname = script->conv_str(st,data); - else if( data_isint(data) ) - class_ = script->conv_num(st,data); + + if( script_isstringtype(st, 3) ) + newname = script_getstr(st, 3); else - { - ShowError("script:setnpcdisplay: expected string or number\n"); - script_reportdata(data); - return false; - } - - nd = npc_name2id(name); + class_ = script_getnum(st, 3); + + nd = npc->name2id(name); if( nd == NULL ) {// not found script_pushint(st,1); return true; } - + // update npc if( newname ) - npc_setdisplayname(nd, newname); - + npc->setdisplayname(nd, newname); + if( size != -1 && size != (int)nd->size ) nd->size = size; else size = -1; - + if( class_ != -1 && nd->class_ != class_ ) - npc_setclass(nd, class_); + npc->setclass(nd, class_); else if( size != -1 ) { // Required to update the visual size clif->clearunit_area(&nd->bl, CLR_OUTSIGHT); clif->spawn(&nd->bl); } - + script_pushint(st,0); return true; } -BUILDIN(atoi) -{ +BUILDIN(atoi) { const char *value; value = script_getstr(st,2); script_pushint(st,atoi(value)); return true; } +BUILDIN(axtoi) { + const char *hex = script_getstr(st,2); + long value = strtol(hex, NULL, 16); +#if LONG_MAX > INT_MAX || LONG_MIN < INT_MIN + value = cap_value(value, INT_MIN, INT_MAX); +#endif + script_pushint(st, (int)value); + return true; +} + +BUILDIN(strtol) { + const char *string = script_getstr(st, 2); + int base = script_getnum(st, 3); + long value = strtol(string, NULL, base); +#if LONG_MAX > INT_MAX || LONG_MIN < INT_MIN + value = cap_value(value, INT_MIN, INT_MAX); +#endif + script_pushint(st, (int)value); + return true; +} + // case-insensitive substring search [lordalfa] BUILDIN(compare) { @@ -14066,12 +14717,12 @@ BUILDIN(pow) BUILDIN(distance) { int x0, y0, x1, y1; - + x0 = script_getnum(st,2); y0 = script_getnum(st,3); x1 = script_getnum(st,4); y1 = script_getnum(st,5); - + script_pushint(st,distance_xy(x0,y0,x1,y1)); return true; } @@ -14082,7 +14733,7 @@ BUILDIN(md5) { const char *tmpstr; char *md5str; - + tmpstr = script_getstr(st,2); md5str = (char *)aMalloc((32+1)*sizeof(char)); MD5_String(tmpstr, md5str); @@ -14099,26 +14750,26 @@ BUILDIN(setd) const char *buffer; int elem; buffer = script_getstr(st, 2); - + if(sscanf(buffer, "%99[^[][%d]", varname, &elem) < 2) elem = 0; - + if( not_server_variable(*varname) ) { - sd = script_rid2sd(st); + sd = script->rid2sd(st); if( sd == NULL ) { ShowError("script:setd: no player attached for player variable '%s'\n", buffer); return true; } } - + if( is_string_variable(varname) ) { - setd_sub(st, sd, varname, elem, (void *)script_getstr(st, 3), NULL); + script->setd_sub(st, sd, varname, elem, (void *)script_getstr(st, 3), NULL); } else { - setd_sub(st, sd, varname, elem, (void *)__64BPTRSIZE(script_getnum(st, 3)), NULL); + script->setd_sub(st, sd, varname, elem, (void *)h64BPTRSIZE(script_getnum(st, 3)), NULL); } - + return true; } @@ -14129,97 +14780,92 @@ int buildin_query_sql_sub(struct script_state* st, Sql* handle) const char* query; struct script_data* data; const char* name; - int max_rows = SCRIPT_MAX_ARRAYSIZE; // maximum number of rows + unsigned int max_rows = SCRIPT_MAX_ARRAYSIZE; // maximum number of rows int num_vars; int num_cols; - + // check target variables for( i = 3; script_hasdata(st,i); ++i ) { data = script_getdata(st, i); if( data_isreference(data) ) { // it's a variable name = reference_getname(data); if( not_server_variable(*name) && sd == NULL ) { // requires a player - sd = script_rid2sd(st); - if( sd == NULL ) { // no player attached - script_reportdata(data); - st->state = END; + sd = script->rid2sd(st); + if( sd == NULL )// no player attached return false; - } } - if( not_array_variable(*name) ) - max_rows = 1;// not an array, limit to one row } else { ShowError("script:query_sql: not a variable\n"); - script_reportdata(data); + script->reportdata(data); st->state = END; return false; } } num_vars = i - 3; - + // Execute the query query = script_getstr(st,2); - + if( SQL_ERROR == SQL->QueryStr(handle, query) ) { Sql_ShowDebug(handle); - script_pushint(st, 0); + st->state = END; return false; } - + if( SQL->NumRows(handle) == 0 ) { // No data received SQL->FreeResult(handle); script_pushint(st, 0); return true; } - + // Count the number of columns to store num_cols = SQL->NumColumns(handle); if( num_vars < num_cols ) { ShowWarning("script:query_sql: Too many columns, discarding last %u columns.\n", (unsigned int)(num_cols-num_vars)); - script_reportsrc(st); + script->reportsrc(st); } else if( num_vars > num_cols ) { ShowWarning("script:query_sql: Too many variables (%u extra).\n", (unsigned int)(num_vars-num_cols)); - script_reportsrc(st); + script->reportsrc(st); } - + // Store data for( i = 0; i < max_rows && SQL_SUCCESS == SQL->NextRow(handle); ++i ) { for( j = 0; j < num_vars; ++j ) { char* str = NULL; - + if( j < num_cols ) SQL->GetData(handle, j, &str, NULL); - + data = script_getdata(st, j+3); name = reference_getname(data); if( is_string_variable(name) ) - setd_sub(st, sd, name, i, (void *)(str?str:""), reference_getref(data)); + script->setd_sub(st, sd, name, i, (void *)(str?str:""), reference_getref(data)); else - setd_sub(st, sd, name, i, (void *)__64BPTRSIZE((str?atoi(str):0)), reference_getref(data)); + script->setd_sub(st, sd, name, i, (void *)h64BPTRSIZE((str?atoi(str):0)), reference_getref(data)); } } if( i == max_rows && max_rows < SQL->NumRows(handle) ) { ShowWarning("script:query_sql: Only %d/%u rows have been stored.\n", max_rows, (unsigned int)SQL->NumRows(handle)); - script_reportsrc(st); + script->reportsrc(st); } - + // Free data SQL->FreeResult(handle); script_pushint(st, i); - + return true; } BUILDIN(query_sql) { - return buildin_query_sql_sub(st, mmysql_handle); + return script->buildin_query_sql_sub(st, map->mysql_handle); } BUILDIN(query_logsql) { - if( !logs->config.sql_logs ) {// logmysql_handle == NULL + if( !logs->config.sql_logs ) {// logs->mysql_handle == NULL ShowWarning("buildin_query_logsql: SQL logs are disabled, query '%s' will not be executed.\n", script_getstr(st,2)); script_pushint(st,-1); return false; } - return buildin_query_sql_sub(st, logmysql_handle); + return script->buildin_query_sql_sub(st, logs->mysql_handle); } //Allows escaping of a given string. @@ -14228,29 +14874,28 @@ BUILDIN(escape_sql) const char *str; char *esc_str; size_t len; - + str = script_getstr(st,2); len = strlen(str); esc_str = (char*)aMalloc(len*2+1); - SQL->EscapeStringLen(mmysql_handle, esc_str, str, len); + SQL->EscapeStringLen(map->mysql_handle, esc_str, str, len); script_pushstr(st, esc_str); return true; } -BUILDIN(getd) -{ +BUILDIN(getd) { char varname[100]; const char *buffer; int elem; - + buffer = script_getstr(st, 2); - - if(sscanf(buffer, "%[^[][%d]", varname, &elem) < 2) + + if (sscanf(buffer, "%99[^[][%d]", varname, &elem) < 2) elem = 0; - + // Push the 'pointer' so it's more flexible [Lance] - script->push_val(st->stack, C_NAME, reference_uid(add_str(varname), elem),NULL); - + script->push_val(st->stack, C_NAME, reference_uid(script->add_str(varname), elem),NULL); + return true; } @@ -14261,8 +14906,8 @@ BUILDIN(petstat) TBL_PC *sd = NULL; struct pet_data *pd; int flag = script_getnum(st,2); - sd = script_rid2sd(st); - if(!sd || !sd->status.pet_id || !sd->pd){ + sd = script->rid2sd(st); + if(!sd || !sd->status.pet_id || !sd->pd) { if(flag == 2) script_pushconststr(st, ""); else @@ -14270,7 +14915,7 @@ BUILDIN(petstat) return true; } pd = sd->pd; - switch(flag){ + switch(flag) { case 1: script_pushint(st,(int)pd->pet.class_); break; case 2: script_pushstrcopy(st, pd->pet.name); break; case 3: script_pushint(st,(int)pd->pet.level); break; @@ -14289,37 +14934,35 @@ BUILDIN(callshop) struct npc_data *nd; const char *shopname; int flag = 0; - sd = script_rid2sd(st); - if (!sd) { - script_pushint(st,0); - return true; - } + sd = script->rid2sd(st); + if( sd == NULL ) + return false; shopname = script_getstr(st, 2); if( script_hasdata(st,3) ) flag = script_getnum(st,3); - nd = npc_name2id(shopname); + nd = npc->name2id(shopname); if( !nd || nd->bl.type != BL_NPC || (nd->subtype != SHOP && nd->subtype != CASHSHOP) ) { ShowError("buildin_callshop: Shop [%s] not found (or NPC is not shop type)\n", shopname); script_pushint(st,0); return false; } - + if( nd->subtype == SHOP ) { // flag the user as using a valid script call for opening the shop (for floating NPCs) sd->state.callshop = 1; - + switch( flag ) { - case 1: npc_buysellsel(sd,nd->bl.id,0); break; //Buy window - case 2: npc_buysellsel(sd,nd->bl.id,1); break; //Sell window + case 1: npc->buysellsel(sd,nd->bl.id,0); break; //Buy window + case 2: npc->buysellsel(sd,nd->bl.id,1); break; //Sell window default: clif->npcbuysell(sd,nd->bl.id); break; //Show menu } } else clif->cashshop_show(sd, nd); - + sd->npc_shopid = nd->bl.id; script_pushint(st,1); return true; @@ -14328,19 +14971,19 @@ BUILDIN(callshop) BUILDIN(npcshopitem) { const char* npcname = script_getstr(st, 2); - struct npc_data* nd = npc_name2id(npcname); + struct npc_data* nd = npc->name2id(npcname); int n, i; int amount; - - if( !nd || ( nd->subtype != SHOP && nd->subtype != CASHSHOP ) ) - { //Not found. + + if( !nd || ( nd->subtype != SHOP && nd->subtype != CASHSHOP ) ) { + //Not found. script_pushint(st,0); return true; } - + // get the count of new entries amount = (script_lastdata(st)-2)/2; - + // generate new shop item list RECREATE(nd->u.shop.shop_item, struct npc_item_list, amount); for( n = 0, i = 3; n < amount; n++, i+=2 ) @@ -14349,7 +14992,7 @@ BUILDIN(npcshopitem) nd->u.shop.shop_item[n].value = script_getnum(st,i+1); } nd->u.shop.count = n; - + script_pushint(st,1); return true; } @@ -14357,19 +15000,19 @@ BUILDIN(npcshopitem) BUILDIN(npcshopadditem) { const char* npcname = script_getstr(st,2); - struct npc_data* nd = npc_name2id(npcname); + struct npc_data* nd = npc->name2id(npcname); int n, i; int amount; - - if( !nd || ( nd->subtype != SHOP && nd->subtype != CASHSHOP ) ) - { //Not found. + + if( !nd || ( nd->subtype != SHOP && nd->subtype != CASHSHOP ) ) { + //Not found. script_pushint(st,0); return true; } - + // get the count of new entries amount = (script_lastdata(st)-2)/2; - + // append new items to existing shop item list RECREATE(nd->u.shop.shop_item, struct npc_item_list, nd->u.shop.count+amount); for( n = nd->u.shop.count, i = 3; n < nd->u.shop.count+amount; n++, i+=2 ) @@ -14378,7 +15021,7 @@ BUILDIN(npcshopadditem) nd->u.shop.shop_item[n].value = script_getnum(st,i+1); } nd->u.shop.count = n; - + script_pushint(st,1); return true; } @@ -14386,26 +15029,26 @@ BUILDIN(npcshopadditem) BUILDIN(npcshopdelitem) { const char* npcname = script_getstr(st,2); - struct npc_data* nd = npc_name2id(npcname); + struct npc_data* nd = npc->name2id(npcname); unsigned int nameid; int n, i; int amount; int size; - - if( !nd || ( nd->subtype != SHOP && nd->subtype != CASHSHOP ) ) - { //Not found. + + if( !nd || ( nd->subtype != SHOP && nd->subtype != CASHSHOP ) ) { + //Not found. script_pushint(st,0); return true; } - + amount = script_lastdata(st)-2; size = nd->u.shop.count; - + // remove specified items from the shop item list for( i = 3; i < 3 + amount; i++ ) { nameid = script_getnum(st,i); - + ARR_FIND( 0, size, n, nd->u.shop.shop_item[n].nameid == nameid ); if( n < size ) { @@ -14413,35 +15056,34 @@ BUILDIN(npcshopdelitem) size--; } } - + RECREATE(nd->u.shop.shop_item, struct npc_item_list, size); nd->u.shop.count = size; - + script_pushint(st,1); return true; } //Sets a script to attach to a shop npc. -BUILDIN(npcshopattach) -{ +BUILDIN(npcshopattach) { const char* npcname = script_getstr(st,2); - struct npc_data* nd = npc_name2id(npcname); + struct npc_data* nd = npc->name2id(npcname); int flag = 1; - + if( script_hasdata(st,3) ) flag = script_getnum(st,3); - - if( !nd || nd->subtype != SHOP ) - { //Not found. + + if( !nd || nd->subtype != SHOP ) { + //Not found. script_pushint(st,0); return true; } - + if (flag) - nd->master_nd = ((struct npc_data *)iMap->id2bl(st->oid)); + nd->master_nd = ((struct npc_data *)map->id2bl(st->oid)); else nd->master_nd = NULL; - + script_pushint(st,1); return true; } @@ -14449,11 +15091,11 @@ BUILDIN(npcshopattach) /*========================================== * Returns some values of an item [Lupus] * Price, Weight, etc... - setitemscript(itemID,"{new item bonus script}",[n]); - Where n: - 0 - script - 1 - Equip script - 2 - Unequip script + * setitemscript(itemID,"{new item bonus script}",[n]); + * Where n: + * 0 - script + * 1 - Equip script + * 2 - Unequip script *------------------------------------------*/ BUILDIN(setitemscript) { @@ -14461,13 +15103,13 @@ BUILDIN(setitemscript) const char *new_bonus_script; struct item_data *i_data; struct script_code **dstscript; - - item_id = script_getnum(st,2); + + item_id = script_getnum(st,2); new_bonus_script = script_getstr(st,3); if( script_hasdata(st,4) ) n=script_getnum(st,4); - i_data = itemdb_exists(item_id); - + i_data = itemdb->exists(item_id); + if (!i_data || new_bonus_script==NULL || ( new_bonus_script[0] && new_bonus_script[0]!='{' )) { script_pushint(st,0); return true; @@ -14484,52 +15126,132 @@ BUILDIN(setitemscript) break; } if(*dstscript) - script_free_code(*dstscript); - - *dstscript = new_bonus_script[0] ? parse_script(new_bonus_script, "script_setitemscript", 0, 0) : NULL; + script->free_code(*dstscript); + + *dstscript = new_bonus_script[0] ? script->parse(new_bonus_script, "script_setitemscript", 0, 0, NULL) : NULL; script_pushint(st,1); return true; } -/* Work In Progress [Lupus] - BUILDIN(addmonsterdrop) - { - int class_,item_id,chance; - class_=script_getnum(st,2); - item_id=script_getnum(st,3); - chance=script_getnum(st,4); - if(class_>1000 && item_id>500 && chance>0) { - script_pushint(st,1); - } else { - script_pushint(st,0); - } - } - - BUILDIN(delmonsterdrop) - { - int class_,item_id; - class_=script_getnum(st,2); - item_id=script_getnum(st,3); - if(class_>1000 && item_id>500) { - script_pushint(st,1); - } else { - script_pushint(st,0); - } - } - */ +/*======================================================= + * Temporarily add or update a mob drop + * Original Idea By: [Lupus], [Akinari] + * + * addmonsterdrop <mob_id or name>,<item_id>,<rate>; + * + * If given an item the mob already drops, the rate + * is updated to the new rate. Rate must be in the range [1:10000] + * Returns 1 if succeeded (added/updated a mob drop) + *-------------------------------------------------------*/ +BUILDIN(addmonsterdrop) { + struct mob_db *monster; + int item_id, rate, i, c = MAX_MOB_DROP; + + if( script_isstringtype(st,2) ) + monster = mob->db(mob->db_searchname(script_getstr(st,2))); + else + monster = mob->db(script_getnum(st,2)); + + if( monster == mob->dummy ) { + if( script_isstringtype(st,2) ) { + ShowError("buildin_addmonsterdrop: invalid mob name: '%s'.\n", script_getstr(st,2)); + } else { + ShowError("buildin_addmonsterdrop: invalid mob id: '%d'.\n", script_getnum(st,2)); + } + return false; + } + + item_id = script_getnum(st,3); + if( !itemdb->exists(item_id) ) { + ShowError("buildin_addmonsterdrop: Invalid item ID: '%d'.\n", item_id); + return false; + } + + rate = script_getnum(st,4); + if( rate < 1 || rate > 10000 ) { + ShowWarning("buildin_addmonsterdrop: Invalid drop rate '%d'. Capping to the [1:10000] range.\n", rate); + rate = cap_value(rate,1,10000); + } + + for( i = 0; i < MAX_MOB_DROP; i++ ) { + if( monster->dropitem[i].nameid == item_id ) // Item ID found + break; + if( c == MAX_MOB_DROP && monster->dropitem[i].nameid < 1 ) // First empty slot + c = i; + } + if( i < MAX_MOB_DROP ) // If the item ID was found, prefer it + c = i; + + if( c < MAX_MOB_DROP ) { + // Fill in the slot with the item and rate + monster->dropitem[c].nameid = item_id; + monster->dropitem[c].p = rate; + script_pushint(st,1); + } else { + //No place to put the new drop + script_pushint(st,0); + } + + return true; +} + +/*======================================================= + * Temporarily remove a mob drop + * Original Idea By: [Lupus], [Akinari] + * + * delmonsterdrop <mob_id or name>,<item_id>; + * + * Returns 1 if succeeded (deleted a mob drop) + *-------------------------------------------------------*/ +BUILDIN(delmonsterdrop) { + struct mob_db *monster; + int item_id, i; + + if( script_isstringtype(st, 2) ) + monster = mob->db(mob->db_searchname(script_getstr(st, 2))); + else + monster = mob->db(script_getnum(st, 2)); + + if( monster == mob->dummy ) { + if( script_isstringtype(st, 2) ) { + ShowError("buildin_delmonsterdrop: invalid mob name: '%s'.\n", script_getstr(st,2)); + } else { + ShowError("buildin_delmonsterdrop: invalid mob id: '%d'.\n", script_getnum(st,2)); + } + return false; + } + + item_id = script_getnum(st,3); + if( !itemdb->exists(item_id) ) { + ShowError("buildin_delmonsterdrop: Invalid item ID: '%d'.\n", item_id); + return false; + } + + for( i = 0; i < MAX_MOB_DROP; i++ ) { + if( monster->dropitem[i].nameid == item_id ) { + monster->dropitem[i].nameid = 0; + monster->dropitem[i].p = 0; + script_pushint(st,1); + return true; + } + } + // No drop on that monster + script_pushint(st,0); + return true; +} /*========================================== * Returns some values of a monster [Lupus] * Name, Level, race, size, etc... - getmonsterinfo(monsterID,queryIndex); + * getmonsterinfo(monsterID,queryIndex); *------------------------------------------*/ BUILDIN(getmonsterinfo) { - struct mob_db *mob; + struct mob_db *monster; int mob_id; - - mob_id = script_getnum(st,2); - if (!mobdb_checkid(mob_id)) { + + mob_id = script_getnum(st,2); + if (!mob->db_checkid(mob_id)) { ShowError("buildin_getmonsterinfo: Wrong Monster ID: %i\n", mob_id); if ( !script_getnum(st,3) ) //requested a string script_pushconststr(st,"null"); @@ -14537,31 +15259,31 @@ BUILDIN(getmonsterinfo) script_pushint(st,-1); return -1; } - mob = mob_db(mob_id); + monster = mob->db(mob_id); switch ( script_getnum(st,3) ) { - case 0: script_pushstrcopy(st,mob->jname); break; - case 1: script_pushint(st,mob->lv); break; - case 2: script_pushint(st,mob->status.max_hp); break; - case 3: script_pushint(st,mob->base_exp); break; - case 4: script_pushint(st,mob->job_exp); break; - case 5: script_pushint(st,mob->status.rhw.atk); break; - case 6: script_pushint(st,mob->status.rhw.atk2); break; - case 7: script_pushint(st,mob->status.def); break; - case 8: script_pushint(st,mob->status.mdef); break; - case 9: script_pushint(st,mob->status.str); break; - case 10: script_pushint(st,mob->status.agi); break; - case 11: script_pushint(st,mob->status.vit); break; - case 12: script_pushint(st,mob->status.int_); break; - case 13: script_pushint(st,mob->status.dex); break; - case 14: script_pushint(st,mob->status.luk); break; - case 15: script_pushint(st,mob->status.rhw.range); break; - case 16: script_pushint(st,mob->range2); break; - case 17: script_pushint(st,mob->range3); break; - case 18: script_pushint(st,mob->status.size); break; - case 19: script_pushint(st,mob->status.race); break; - case 20: script_pushint(st,mob->status.def_ele); break; - case 21: script_pushint(st,mob->status.mode); break; - case 22: script_pushint(st,mob->mexp); break; + case 0: script_pushstrcopy(st,monster->jname); break; + case 1: script_pushint(st,monster->lv); break; + case 2: script_pushint(st,monster->status.max_hp); break; + case 3: script_pushint(st,monster->base_exp); break; + case 4: script_pushint(st,monster->job_exp); break; + case 5: script_pushint(st,monster->status.rhw.atk); break; + case 6: script_pushint(st,monster->status.rhw.atk2); break; + case 7: script_pushint(st,monster->status.def); break; + case 8: script_pushint(st,monster->status.mdef); break; + case 9: script_pushint(st,monster->status.str); break; + case 10: script_pushint(st,monster->status.agi); break; + case 11: script_pushint(st,monster->status.vit); break; + case 12: script_pushint(st,monster->status.int_); break; + case 13: script_pushint(st,monster->status.dex); break; + case 14: script_pushint(st,monster->status.luk); break; + case 15: script_pushint(st,monster->status.rhw.range); break; + case 16: script_pushint(st,monster->range2); break; + case 17: script_pushint(st,monster->range3); break; + case 18: script_pushint(st,monster->status.size); break; + case 19: script_pushint(st,monster->status.race); break; + case 20: script_pushint(st,monster->status.def_ele); break; + case 21: script_pushint(st,monster->status.mode); break; + case 22: script_pushint(st,monster->mexp); break; default: script_pushint(st,-1); //wrong Index } return true; @@ -14570,52 +15292,51 @@ BUILDIN(getmonsterinfo) BUILDIN(checkvending) // check vending [Nab4] { TBL_PC *sd = NULL; - + if(script_hasdata(st,2)) - sd = iMap->nick2sd(script_getstr(st,2)); + sd = map->nick2sd(script_getstr(st,2)); else - sd = script_rid2sd(st); - + sd = script->rid2sd(st); + if(sd) script_pushint(st, sd->state.autotrade ? 2 : sd->state.vending); else script_pushint(st,0); - + return true; } -BUILDIN(checkchatting) // check chatting [Marka] -{ +// check chatting [Marka] +BUILDIN(checkchatting) { TBL_PC *sd = NULL; - + if(script_hasdata(st,2)) - sd = iMap->nick2sd(script_getstr(st,2)); + sd = map->nick2sd(script_getstr(st,2)); else - sd = script_rid2sd(st); - + sd = script->rid2sd(st); + if(sd) script_pushint(st,(sd->chatID != 0)); else script_pushint(st,0); - + return true; } -BUILDIN(checkidle) -{ +BUILDIN(checkidle) { TBL_PC *sd = NULL; - + if (script_hasdata(st, 2)) - sd = iMap->nick2sd(script_getstr(st, 2)); + sd = map->nick2sd(script_getstr(st, 2)); else - sd = script_rid2sd(st); - + sd = script->rid2sd(st); + if (sd) - script_pushint(st, DIFF_TICK(last_tick, sd->idletime)); + script_pushint(st, DIFF_TICK32(sockt->last_tick, sd->idletime)); // TODO: change this to int64 when we'll support 64 bit script values else script_pushint(st, 0); - + return true; } @@ -14625,117 +15346,67 @@ BUILDIN(searchitem) const char *itemname = script_getstr(st,3); struct item_data *items[MAX_SEARCH]; int count; - + char* name; int32 start; int32 id; int32 i; TBL_PC* sd = NULL; - - if ((items[0] = itemdb_exists(atoi(itemname)))) + + if ((items[0] = itemdb->exists(atoi(itemname)))) count = 1; else { - count = itemdb_searchname_array(items, ARRAYLENGTH(items), itemname); + count = itemdb->search_name_array(items, ARRAYLENGTH(items), itemname, 0); if (count > MAX_SEARCH) count = MAX_SEARCH; } - + if (!count) { script_pushint(st, 0); return true; } - + if( !data_isreference(data) ) { ShowError("script:searchitem: not a variable\n"); - script_reportdata(data); + script->reportdata(data); st->state = END; return false;// not a variable } - + id = reference_getid(data); start = reference_getindex(data); name = reference_getname(data); - if( not_array_variable(*name) ) - { - ShowError("script:searchitem: illegal scope\n"); - script_reportdata(data); - st->state = END; - return false;// not supported - } - + if( not_server_variable(*name) ) { - sd = script_rid2sd(st); + sd = script->rid2sd(st); if( sd == NULL ) return true;// no player attached } - + if( is_string_variable(name) ) {// string array ShowError("script:searchitem: not an integer array reference\n"); - script_reportdata(data); + script->reportdata(data); st->state = END; return false;// not supported } - + for( i = 0; i < count; ++start, ++i ) {// Set array - void* v = (void*)__64BPTRSIZE((int)items[i]->nameid); - set_reg(st, sd, reference_uid(id, start), name, v, reference_getref(data)); + void* v = (void*)h64BPTRSIZE((int)items[i]->nameid); + script->set_reg(st, sd, reference_uid(id, start), name, v, reference_getref(data)); } - - script_pushint(st, count); - return true; -} -int axtoi(const char *hexStg) -{ - int n = 0; // position in string - int16 m = 0; // position in digit[] to shift - int count; // loop index - int intValue = 0; // integer value of hex string - int digit[11]; // hold values to convert - while (n < 10) { - if (hexStg[n]=='\0') - break; - if (hexStg[n] > 0x29 && hexStg[n] < 0x40 ) //if 0 to 9 - digit[n] = hexStg[n] & 0x0f; //convert to int - else if (hexStg[n] >='a' && hexStg[n] <= 'f') //if a to f - digit[n] = (hexStg[n] & 0x0f) + 9; //convert to int - else if (hexStg[n] >='A' && hexStg[n] <= 'F') //if A to F - digit[n] = (hexStg[n] & 0x0f) + 9; //convert to int - else break; - n++; - } - count = n; - m = n - 1; - n = 0; - while(n < count) { - // digit[n] is value of hex digit at position n - // (m << 2) is the number of positions to shift - // OR the bits into return value - intValue = intValue | (digit[n] << (m << 2)); - m--; // adjust the position to set - n++; // next digit to process - } - return (intValue); -} - -// [Lance] Hex string to integer converter -BUILDIN(axtoi) -{ - const char *hex = script_getstr(st,2); - script_pushint(st,axtoi(hex)); + script_pushint(st, count); return true; } // [zBuffer] List of player cont commands ---> -BUILDIN(rid2name) -{ +BUILDIN(rid2name) { struct block_list *bl = NULL; int rid = script_getnum(st,2); - if((bl = iMap->id2bl(rid))) - { + if((bl = map->id2bl(rid))) { switch(bl->type) { case BL_MOB: script_pushstrcopy(st,((TBL_MOB*)bl)->name); break; case BL_PC: script_pushstrcopy(st,((TBL_PC*)bl)->status.name); break; @@ -14755,93 +15426,91 @@ BUILDIN(rid2name) return true; } -BUILDIN(pcblockmove) -{ +BUILDIN(pcblockmove) { int id, flag; TBL_PC *sd = NULL; - + id = script_getnum(st,2); flag = script_getnum(st,3); - + if(id) - sd = iMap->id2sd(id); + sd = map->id2sd(id); else - sd = script_rid2sd(st); - + sd = script->rid2sd(st); + if(sd) sd->state.blockedmove = flag > 0; - + return true; } -BUILDIN(pcfollow) -{ +BUILDIN(pcfollow) { int id, targetid; TBL_PC *sd = NULL; - - + + id = script_getnum(st,2); targetid = script_getnum(st,3); - + if(id) - sd = iMap->id2sd(id); + sd = map->id2sd(id); else - sd = script_rid2sd(st); - + sd = script->rid2sd(st); + if(sd) pc->follow(sd, targetid); - - return true; + + return true; } BUILDIN(pcstopfollow) { int id; TBL_PC *sd = NULL; - - + + id = script_getnum(st,2); - + if(id) - sd = iMap->id2sd(id); + sd = map->id2sd(id); else - sd = script_rid2sd(st); - + sd = script->rid2sd(st); + if(sd) pc->stop_following(sd); - + return true; } // <--- [zBuffer] List of player cont commands // [zBuffer] List of mob control commands ---> //## TODO always return if the request/whatever was successfull [FlavioJS] -/// Makes the unit walk to target position or map +/// Makes the unit walk to target position or target id /// Returns if it was successfull /// /// unitwalk(<unit_id>,<x>,<y>) -> <bool> -/// unitwalk(<unit_id>,<map_id>) -> <bool> -BUILDIN(unitwalk) -{ +/// unitwalk(<unit_id>,<target_id>) -> <bool> +BUILDIN(unitwalk) { struct block_list* bl; - - bl = iMap->id2bl(script_getnum(st,2)); - if( bl == NULL ) - { + + bl = map->id2bl(script_getnum(st,2)); + if( bl == NULL ) { script_pushint(st, 0); + return true; } - else if( script_hasdata(st,4) ) - { + + if( bl->type == BL_NPC ) { + unit->bl2ud2(bl); // ensure the ((TBL_NPC*)bl)->ud is safe to edit + } + if( script_hasdata(st,4) ) { int x = script_getnum(st,3); int y = script_getnum(st,4); - script_pushint(st, unit_walktoxy(bl,x,y,0));// We'll use harder calculations. - } - else - { - int map_id = script_getnum(st,3); - script_pushint(st, unit_walktobl(bl,iMap->id2bl(map_id),65025,1)); + script_pushint(st, unit->walktoxy(bl,x,y,0));// We'll use harder calculations. + } else { + int target_id = script_getnum(st,3); + script_pushint(st, unit->walktobl(bl,map->id2bl(target_id),1,1)); } - + return true; } @@ -14850,10 +15519,10 @@ BUILDIN(unitwalk) /// unitkill <unit_id>; BUILDIN(unitkill) { - struct block_list* bl = iMap->id2bl(script_getnum(st,2)); + struct block_list* bl = map->id2bl(script_getnum(st,2)); if( bl != NULL ) status_kill(bl); - + return true; } @@ -14861,35 +15530,36 @@ BUILDIN(unitkill) /// Returns if it was successfull /// /// unitwarp(<unit_id>,"<map name>",<x>,<y>) -> <bool> -BUILDIN(unitwarp) -{ +BUILDIN(unitwarp) { int unit_id; - int map; + int mapid; short x; short y; struct block_list* bl; const char *mapname; - + unit_id = script_getnum(st,2); mapname = script_getstr(st, 3); x = (short)script_getnum(st,4); y = (short)script_getnum(st,5); - + if (!unit_id) //Warp the script's runner - bl = iMap->id2bl(st->rid); + bl = map->id2bl(st->rid); else - bl = iMap->id2bl(unit_id); - + bl = map->id2bl(unit_id); + if( strcmp(mapname,"this") == 0 ) - map = bl?bl->m:-1; - else - map = iMap->mapname2mapid(mapname); - - if( map >= 0 && bl != NULL ) - script_pushint(st, unit_warp(bl,map,x,y,CLR_OUTSIGHT)); + mapid = bl?bl->m:-1; else + mapid = map->mapname2mapid(mapname); + + if( mapid >= 0 && bl != NULL ) { + unit->bl2ud2(bl); // ensure ((TBL_NPC*)bl)->ud is safe to edit + script_pushint(st, unit->warp(bl,mapid,x,y,CLR_OUTSIGHT)); + } else { script_pushint(st, 0); - + } + return true; } @@ -14900,44 +15570,39 @@ BUILDIN(unitwarp) /// /// unitattack(<unit_id>,"<target name>"{,<action type>}) -> <bool> /// unitattack(<unit_id>,<target_id>{,<action type>}) -> <bool> -BUILDIN(unitattack) -{ +BUILDIN(unitattack) { struct block_list* unit_bl; struct block_list* target_bl = NULL; - struct script_data* data; int actiontype = 0; - + // get unit - unit_bl = iMap->id2bl(script_getnum(st,2)); + unit_bl = map->id2bl(script_getnum(st,2)); if( unit_bl == NULL ) { script_pushint(st, 0); return true; } - - data = script_getdata(st, 3); - script->get_val(st, data); - if( data_isstring(data) ) - { - TBL_PC* sd = iMap->nick2sd(script->conv_str(st, data)); + + if( script_isstringtype(st, 3) ) { + TBL_PC* sd = map->nick2sd(script_getstr(st, 3)); if( sd != NULL ) target_bl = &sd->bl; } else - target_bl = iMap->id2bl(script->conv_num(st, data)); + target_bl = map->id2bl(script_getnum(st, 3)); // request the attack if( target_bl == NULL ) { script_pushint(st, 0); return true; } - + // get actiontype if( script_hasdata(st,4) ) actiontype = script_getnum(st,4); - + switch( unit_bl->type ) { case BL_PC: - clif->pActionRequest_sub(((TBL_PC *)unit_bl), actiontype > 0 ? 0x07 : 0x00, target_bl->id, iTimer->gettick()); + clif->pActionRequest_sub(((TBL_PC *)unit_bl), actiontype > 0 ? 0x07 : 0x00, target_bl->id, timer->gettick()); script_pushint(st, 1); return true; case BL_MOB: @@ -14951,56 +15616,53 @@ BUILDIN(unitattack) script_pushint(st, 0); return false; } - script_pushint(st, unit_walktobl(unit_bl, target_bl, 65025, 2)); + script_pushint(st, unit->walktobl(unit_bl, target_bl, 65025, 2)); return true; } /// Makes the unit stop attacking and moving /// /// unitstop <unit_id>; -BUILDIN(unitstop) -{ +BUILDIN(unitstop) { int unit_id; struct block_list* bl; - + unit_id = script_getnum(st,2); - - bl = iMap->id2bl(unit_id); - if( bl != NULL ) - { - unit_stop_attack(bl); - unit_stop_walking(bl,4); + + bl = map->id2bl(unit_id); + if( bl != NULL ) { + unit->bl2ud2(bl); // ensure ((TBL_NPC*)bl)->ud is safe to edit + unit->stop_attack(bl); + unit->stop_walking(bl,4); if( bl->type == BL_MOB ) ((TBL_MOB*)bl)->target_id = 0; } - + return true; } /// Makes the unit say the message /// /// unittalk <unit_id>,"<message>"; -BUILDIN(unittalk) -{ +BUILDIN(unittalk) { int unit_id; const char* message; struct block_list* bl; - + unit_id = script_getnum(st,2); message = script_getstr(st, 3); - - bl = iMap->id2bl(unit_id); - if( bl != NULL ) - { + + bl = map->id2bl(unit_id); + if( bl != NULL ) { struct StringBuf sbuf; StrBuf->Init(&sbuf); - StrBuf->Printf(&sbuf, "%s : %s", status_get_name(bl), message); + StrBuf->Printf(&sbuf, "%s : %s", status->get_name(bl), message); clif->disp_overhead(bl, StrBuf->Value(&sbuf)); if( bl->type == BL_PC ) clif->message(((TBL_PC*)bl)->fd, StrBuf->Value(&sbuf)); StrBuf->Destroy(&sbuf); } - + return true; } @@ -15009,18 +15671,17 @@ BUILDIN(unittalk) /// unitemote <unit_id>,<emotion>; /// /// @see e_* in const.txt -BUILDIN(unitemote) -{ +BUILDIN(unitemote) { int unit_id; int emotion; struct block_list* bl; - + unit_id = script_getnum(st,2); emotion = script_getnum(st,3); - bl = iMap->id2bl(unit_id); + bl = map->id2bl(unit_id); if( bl != NULL ) clif->emotion(bl, emotion); - + return true; } @@ -15028,23 +15689,31 @@ BUILDIN(unitemote) /// /// unitskilluseid <unit_id>,<skill_id>,<skill_lv>{,<target_id>}; /// unitskilluseid <unit_id>,"<skill name>",<skill_lv>{,<target_id>}; -BUILDIN(unitskilluseid) -{ +BUILDIN(unitskilluseid) { int unit_id; uint16 skill_id; uint16 skill_lv; int target_id; struct block_list* bl; - + unit_id = script_getnum(st,2); - skill_id = ( script_isstring(st,3) ? skill->name2id(script_getstr(st,3)) : script_getnum(st,3) ); + skill_id = ( script_isstringtype(st, 3) ? skill->name2id(script_getstr(st, 3)) : script_getnum(st, 3) ); skill_lv = script_getnum(st,4); target_id = ( script_hasdata(st,5) ? script_getnum(st,5) : unit_id ); - - bl = iMap->id2bl(unit_id); - if( bl != NULL ) - unit_skilluse_id(bl, target_id, skill_id, skill_lv); - + + bl = map->id2bl(unit_id); + + if( bl != NULL ) { + if( bl->type == BL_NPC ) { + if (!((TBL_NPC*)bl)->status.hp) { + status_calc_npc(((TBL_NPC*)bl), SCO_FIRST); + } else { + status_calc_npc(((TBL_NPC*)bl), SCO_NONE); + } + } + unit->skilluse_id(bl, target_id, skill_id, skill_lv); + } + return true; } @@ -15052,25 +15721,33 @@ BUILDIN(unitskilluseid) /// /// unitskillusepos <unit_id>,<skill_id>,<skill_lv>,<target_x>,<target_y>; /// unitskillusepos <unit_id>,"<skill name>",<skill_lv>,<target_x>,<target_y>; -BUILDIN(unitskillusepos) -{ +BUILDIN(unitskillusepos) { int unit_id; uint16 skill_id; uint16 skill_lv; int skill_x; int skill_y; struct block_list* bl; - + unit_id = script_getnum(st,2); - skill_id = ( script_isstring(st,3) ? skill->name2id(script_getstr(st,3)) : script_getnum(st,3) ); + skill_id = ( script_isstringtype(st, 3) ? skill->name2id(script_getstr(st, 3)) : script_getnum(st, 3) ); skill_lv = script_getnum(st,4); skill_x = script_getnum(st,5); skill_y = script_getnum(st,6); - - bl = iMap->id2bl(unit_id); - if( bl != NULL ) - unit_skilluse_pos(bl, skill_x, skill_y, skill_id, skill_lv); - + + bl = map->id2bl(unit_id); + + if( bl != NULL ) { + if( bl->type == BL_NPC ) { + if (!((TBL_NPC*)bl)->status.hp) { + status_calc_npc(((TBL_NPC*)bl), SCO_FIRST); + } else { + status_calc_npc(((TBL_NPC*)bl), SCO_NONE); + } + } + unit->skilluse_pos(bl, skill_x, skill_y, skill_id, skill_lv); + } + return true; } @@ -15082,12 +15759,12 @@ BUILDIN(unitskillusepos) BUILDIN(sleep) { int ticks; - + ticks = script_getnum(st,2); - + // detach the player - script_detach_rid(st); - + script->detach_rid(st); + if( ticks <= 0 ) {// do nothing } @@ -15108,26 +15785,23 @@ BUILDIN(sleep) /// Returns if a player is still attached /// /// sleep2(<mili secconds>) -> <bool> -BUILDIN(sleep2) -{ +BUILDIN(sleep2) { int ticks; - + ticks = script_getnum(st,2); - - if( ticks <= 0 ) - {// do nothing - script_pushint(st, (iMap->id2sd(st->rid)!=NULL)); - } - else if( !st->sleep.tick ) - {// sleep for the target amount of time + + if( ticks <= 0 ) { + // do nothing + script_pushint(st, (map->id2sd(st->rid)!=NULL)); + } else if( !st->sleep.tick ) { + // sleep for the target amount of time st->state = RERUNLINE; st->sleep.tick = ticks; - } - else - {// sleep time is over + } else { + // sleep time is over st->state = RUN; st->sleep.tick = 0; - script_pushint(st, (iMap->id2sd(st->rid)!=NULL)); + script_pushint(st, (map->id2sd(st->rid)!=NULL)); } return true; } @@ -15139,18 +15813,18 @@ BUILDIN(awake) { DBIterator *iter; struct script_state *tst; struct npc_data* nd; - - if( ( nd = npc_name2id(script_getstr(st, 2)) ) == NULL ) { + + if( ( nd = npc->name2id(script_getstr(st, 2)) ) == NULL ) { ShowError("awake: NPC \"%s\" not found\n", script_getstr(st, 2)); return false; } - + iter = db_iterator(script->st_db); - + for( tst = dbi_first(iter); dbi_exists(iter); tst = dbi_next(iter) ) { if( tst->oid == nd->bl.id ) { - TBL_PC* sd = iMap->id2sd(tst->rid); - + TBL_PC* sd = map->id2sd(tst->rid); + if( tst->sleep.timer == INVALID_TIMER ) {// already awake ??? continue; } @@ -15159,17 +15833,17 @@ BUILDIN(awake) { tst->state = END; tst->rid = 0; } - - iTimer->delete_timer(tst->sleep.timer, run_script_timer); + + timer->delete(tst->sleep.timer, script->run_timer); tst->sleep.timer = INVALID_TIMER; if(tst->state != RERUNLINE) tst->sleep.tick = 0; - run_script_main(tst); + script->run_main(tst); } } - + dbi_destroy(iter); - + return true; } @@ -15182,28 +15856,28 @@ BUILDIN(getvariableofnpc) struct script_data* data; const char* name; struct npc_data* nd; - + data = script_getdata(st,2); if( !data_isreference(data) ) {// Not a reference (aka varaible name) ShowError("script:getvariableofnpc: not a variable\n"); - script_reportdata(data); + script->reportdata(data); script_pushnil(st); st->state = END; return false; } - + name = reference_getname(data); if( *name != '.' || name[1] == '@' ) {// not a npc variable ShowError("script:getvariableofnpc: invalid scope (not npc variable)\n"); - script_reportdata(data); + script->reportdata(data); script_pushnil(st); st->state = END; return false; } - - nd = npc_name2id(script_getstr(st,3)); + + nd = npc->name2id(script_getstr(st,3)); if( nd == NULL || nd->subtype != SCRIPT || nd->u.scr.script == NULL ) {// NPC not found or has no script ShowError("script:getvariableofnpc: can't find npc %s\n", script_getstr(st,3)); @@ -15211,8 +15885,11 @@ BUILDIN(getvariableofnpc) st->state = END; return false; } + + if( !nd->u.scr.script->local.vars ) + nd->u.scr.script->local.vars = i64db_alloc(DB_OPT_RELEASE_DATA); - script->push_val(st->stack, C_NAME, reference_getuid(data), &nd->u.scr.script->script_vars ); + script->push_val(st->stack, C_NAME, reference_getuid(data), &nd->u.scr.script->local); return true; } @@ -15222,65 +15899,64 @@ BUILDIN(getvariableofnpc) /// warpportal <source x>,<source y>,"<target map>",<target x>,<target y>; /// /// @author blackhole89 -BUILDIN(warpportal) -{ +BUILDIN(warpportal) { int spx; int spy; - unsigned short mapindex; + unsigned short map_index; int tpx; int tpy; struct skill_unit_group* group; struct block_list* bl; - - bl = iMap->id2bl(st->oid); + + bl = map->id2bl(st->oid); if( bl == NULL ) { ShowError("script:warpportal: npc is needed\n"); return false; } - + spx = script_getnum(st,2); spy = script_getnum(st,3); - mapindex = mapindex_name2id(script_getstr(st, 4)); + map_index = script->mapindexname2id(st,script_getstr(st, 4)); tpx = script_getnum(st,5); tpy = script_getnum(st,6); - - if( mapindex == 0 ) + + if( map_index == 0 ) return true;// map not found - + group = skill->unitsetting(bl, AL_WARP, 4, spx, spy, 0); if( group == NULL ) return true;// failed group->val1 = (group->val1<<16)|(short)0; group->val2 = (tpx<<16) | tpy; - group->val3 = mapindex; - + group->val3 = map_index; + return true; } BUILDIN(openmail) { TBL_PC* sd; - - sd = script_rid2sd(st); + + sd = script->rid2sd(st); if( sd == NULL ) return true; - + mail->openmail(sd); - + return true; } BUILDIN(openauction) { TBL_PC* sd; - - sd = script_rid2sd(st); + + sd = script->rid2sd(st); if( sd == NULL ) return true; - + clif->auction_openwindow(sd); - + return true; } @@ -15289,15 +15965,19 @@ BUILDIN(openauction) /// checkcell("<map name>",<x>,<y>,<type>) -> <bool> /// /// @see cell_chk* constants in const.txt for the types -BUILDIN(checkcell) -{ - int16 m = iMap->mapname2mapid(script_getstr(st,2)); +BUILDIN(checkcell) { + int16 m = map->mapname2mapid(script_getstr(st,2)); int16 x = script_getnum(st,3); int16 y = script_getnum(st,4); cell_chk type = (cell_chk)script_getnum(st,5); - - script_pushint(st, iMap->getcell(m, x, y, type)); - + + if ( m == -1 ) { + ShowWarning("checkcell: Attempted to run on unexsitent map '%s', type %d, x/y %d,%d\n",script_getstr(st,2),type,x,y); + return true; + } + + script_pushint(st, map->getcell(m, x, y, type)); + return true; } @@ -15306,25 +15986,29 @@ BUILDIN(checkcell) /// setcell "<map name>",<x1>,<y1>,<x2>,<y2>,<type>,<flag>; /// /// @see cell_* constants in const.txt for the types -BUILDIN(setcell) -{ - int16 m = iMap->mapname2mapid(script_getstr(st,2)); +BUILDIN(setcell) { + int16 m = map->mapname2mapid(script_getstr(st,2)); int16 x1 = script_getnum(st,3); int16 y1 = script_getnum(st,4); int16 x2 = script_getnum(st,5); int16 y2 = script_getnum(st,6); cell_t type = (cell_t)script_getnum(st,7); bool flag = (bool)script_getnum(st,8); - + int x,y; - + + if ( m == -1 ) { + ShowWarning("setcell: Attempted to run on unexistent map '%s', type %d, x1/y1 - %d,%d | x2/y2 - %d,%d\n",script_getstr(st, 2),type,x1,y1,x2,y2); + return true; + } + if( x1 > x2 ) swap(x1,x2); if( y1 > y2 ) swap(y1,y2); - + for( y = y1; y <= y2; ++y ) for( x = x1; x <= x2; ++x ) - map[m].setcell(m, x, y, type, flag); - + map->list[m].setcell(m, x, y, type, flag); + return true; } @@ -15335,62 +16019,58 @@ BUILDIN(mercenary_create) { struct map_session_data *sd; int class_, contract_time; - - if( (sd = script_rid2sd(st)) == NULL || sd->md || sd->status.mer_id != 0 ) + + if( (sd = script->rid2sd(st)) == NULL || sd->md || sd->status.mer_id != 0 ) return true; - + class_ = script_getnum(st,2); - - if( !merc_class(class_) ) + + if( !mercenary->class(class_) ) return true; - + contract_time = script_getnum(st,3); - merc_create(sd, class_, contract_time); + mercenary->create(sd, class_, contract_time); return true; } -BUILDIN(mercenary_heal) -{ - struct map_session_data *sd = script_rid2sd(st); +BUILDIN(mercenary_heal) { + struct map_session_data *sd = script->rid2sd(st); int hp, sp; - + if( sd == NULL || sd->md == NULL ) return true; hp = script_getnum(st,2); sp = script_getnum(st,3); - - status_heal(&sd->md->bl, hp, sp, 0); + + status->heal(&sd->md->bl, hp, sp, 0); return true; } -BUILDIN(mercenary_sc_start) -{ - struct map_session_data *sd = script_rid2sd(st); +BUILDIN(mercenary_sc_start) { + struct map_session_data *sd = script->rid2sd(st); enum sc_type type; int tick, val1; - + if( sd == NULL || sd->md == NULL ) return true; - + type = (sc_type)script_getnum(st,2); tick = script_getnum(st,3); val1 = script_getnum(st,4); - - status_change_start(&sd->md->bl, type, 10000, val1, 0, 0, 0, tick, 2); + + status->change_start(NULL, &sd->md->bl, type, 10000, val1, 0, 0, 0, tick, 2); return true; } -BUILDIN(mercenary_get_calls) -{ - struct map_session_data *sd = script_rid2sd(st); - int guild; - +BUILDIN(mercenary_get_calls) { + struct map_session_data *sd = script->rid2sd(st); + int guild_id; + if( sd == NULL ) return true; - - guild = script_getnum(st,2); - switch( guild ) - { + + guild_id = script_getnum(st,2); + switch( guild_id ) { case ARCH_MERC_GUILD: script_pushint(st,sd->status.arch_calls); break; @@ -15404,23 +16084,21 @@ BUILDIN(mercenary_get_calls) script_pushint(st,0); break; } - + return true; } -BUILDIN(mercenary_set_calls) -{ - struct map_session_data *sd = script_rid2sd(st); - int guild, value, *calls; - +BUILDIN(mercenary_set_calls) { + struct map_session_data *sd = script->rid2sd(st); + int guild_id, value, *calls; + if( sd == NULL ) return true; - - guild = script_getnum(st,2); + + guild_id = script_getnum(st,2); value = script_getnum(st,3); - - switch( guild ) - { + + switch( guild_id ) { case ARCH_MERC_GUILD: calls = &sd->status.arch_calls; break; @@ -15433,24 +16111,22 @@ BUILDIN(mercenary_set_calls) default: return true; // Invalid Guild } - + *calls += value; *calls = cap_value(*calls, 0, INT_MAX); - + return true; } -BUILDIN(mercenary_get_faith) -{ - struct map_session_data *sd = script_rid2sd(st); - int guild; - +BUILDIN(mercenary_get_faith) { + struct map_session_data *sd = script->rid2sd(st); + int guild_id; + if( sd == NULL ) return true; - - guild = script_getnum(st,2); - switch( guild ) - { + + guild_id = script_getnum(st,2); + switch( guild_id ) { case ARCH_MERC_GUILD: script_pushint(st,sd->status.arch_faith); break; @@ -15464,23 +16140,21 @@ BUILDIN(mercenary_get_faith) script_pushint(st,0); break; } - + return true; } -BUILDIN(mercenary_set_faith) -{ - struct map_session_data *sd = script_rid2sd(st); - int guild, value, *calls; - +BUILDIN(mercenary_set_faith) { + struct map_session_data *sd = script->rid2sd(st); + int guild_id, value, *calls; + if( sd == NULL ) return true; - - guild = script_getnum(st,2); + + guild_id = script_getnum(st,2); value = script_getnum(st,3); - - switch( guild ) - { + + switch( guild_id ) { case ARCH_MERC_GUILD: calls = &sd->status.arch_faith; break; @@ -15493,12 +16167,12 @@ BUILDIN(mercenary_set_faith) default: return true; // Invalid Guild } - + *calls += value; *calls = cap_value(*calls, 0, INT_MAX); - if( mercenary_get_guild(sd->md) == guild ) + if( mercenary->get_guild(sd->md) == guild_id ) clif->mercenary_updatestatus(sd,SP_MERCFAITH); - + return true; } @@ -15509,337 +16183,419 @@ BUILDIN(readbook) { struct map_session_data *sd; int book_id, page; - - if( (sd = script_rid2sd(st)) == NULL ) + + if( (sd = script->rid2sd(st)) == NULL ) return true; - + book_id = script_getnum(st,2); page = script_getnum(st,3); - + clif->readbook(sd->fd, book_id, page); return true; } -/****************** - Questlog script commands - *******************/ +/**************************** + * Questlog script commands * + ****************************/ -BUILDIN(setquest) +BUILDIN(questinfo) { - struct map_session_data *sd = script_rid2sd(st); - nullpo_ret(sd); - - quest_add(sd, script_getnum(st, 2)); + struct npc_data *nd = map->id2nd(st->oid); + int quest_id, icon, job, color = 0; + struct questinfo qi; + + if( nd == NULL || nd->bl.m == -1 ) + return true; + + quest_id = script_getnum(st, 2); + icon = script_getnum(st, 3); + + #if PACKETVER >= 20120410 + if(icon < 0 || (icon > 8 && icon != 9999) || icon == 7) + icon = 9999; // Default to nothing if icon id is invalid. + #else + if(icon < 0 || icon > 7) + icon = 0; + else + icon = icon + 1; + #endif + + qi.quest_id = quest_id; + qi.icon = (unsigned char)icon; + qi.nd = nd; + + if( script_hasdata(st, 4) ) { + color = script_getnum(st, 4); + if( color < 0 || color > 3 ) { + ShowWarning("buildin_questinfo: invalid color '%d', changing to 0\n",color); + script->reportfunc(st); + color = 0; + } + qi.color = (unsigned char)color; + } + + qi.hasJob = false; + + if(script_hasdata(st, 5)) { + job = script_getnum(st, 5); + + if (!pcdb_checkid(job)) + ShowError("buildin_questinfo: Nonexistant Job Class.\n"); + else { + qi.hasJob = true; + qi.job = (unsigned short)job; + } + } + + map->add_questinfo(nd->bl.m,&qi); + return true; } -BUILDIN(erasequest) -{ - struct map_session_data *sd = script_rid2sd(st); - nullpo_ret(sd); - - quest_delete(sd, script_getnum(st, 2)); +BUILDIN(setquest) { + struct map_session_data *sd = script->rid2sd(st); + unsigned short i; + int quest_id; + + if( sd == NULL ) + return false; + + quest_id = script_getnum(st, 2); + + quest->add(sd, quest_id); + + // If questinfo is set, remove quest bubble once quest is set. + for(i = 0; i < map->list[sd->bl.m].qi_count; i++) { + struct questinfo *qi = &map->list[sd->bl.m].qi_data[i]; + if( qi->quest_id == quest_id ) { +#if PACKETVER >= 20120410 + clif->quest_show_event(sd, &qi->nd->bl, 9999, 0); +#else + clif->quest_show_event(sd, &qi->nd->bl, 0, 0); +#endif + } + } + return true; } -BUILDIN(completequest) -{ - struct map_session_data *sd = script_rid2sd(st); - nullpo_ret(sd); - - quest_update_status(sd, script_getnum(st, 2), Q_COMPLETE); +BUILDIN(erasequest) { + struct map_session_data *sd = script->rid2sd(st); + + if( sd == NULL ) + return false; + + quest->delete(sd, script_getnum(st, 2)); return true; } -BUILDIN(changequest) -{ - struct map_session_data *sd = script_rid2sd(st); - nullpo_ret(sd); - - quest_change(sd, script_getnum(st, 2),script_getnum(st, 3)); +BUILDIN(completequest) { + struct map_session_data *sd = script->rid2sd(st); + + if( sd == NULL ) + return false; + + quest->update_status(sd, script_getnum(st, 2), Q_COMPLETE); return true; } -BUILDIN(checkquest) -{ - struct map_session_data *sd = script_rid2sd(st); - quest_check_type type = HAVEQUEST; - - nullpo_ret(sd); - +BUILDIN(changequest) { + struct map_session_data *sd = script->rid2sd(st); + + if( sd == NULL ) + return false; + + quest->change(sd, script_getnum(st, 2),script_getnum(st, 3)); + return true; +} + +BUILDIN(checkquest) { + struct map_session_data *sd = script->rid2sd(st); + enum quest_check_type type = HAVEQUEST; + + if( sd == NULL ) + return false; + if( script_hasdata(st, 3) ) - type = (quest_check_type)script_getnum(st, 3); - - script_pushint(st, quest_check(sd, script_getnum(st, 2), type)); - + type = (enum quest_check_type)script_getnum(st, 3); + + script_pushint(st, quest->check(sd, script_getnum(st, 2), type)); + return true; } -BUILDIN(showevent) -{ - TBL_PC *sd = script_rid2sd(st); - struct npc_data *nd = iMap->id2nd(st->oid); - int state, color; - +BUILDIN(showevent) { + TBL_PC *sd = script->rid2sd(st); + struct npc_data *nd = map->id2nd(st->oid); + int icon, color = 0; + if( sd == NULL || nd == NULL ) return true; - state = script_getnum(st, 2); - color = script_getnum(st, 3); - - if( color < 0 || color > 3 ) - color = 0; // set default color - - clif->quest_show_event(sd, &nd->bl, state, color); + + icon = script_getnum(st, 2); + if( script_hasdata(st, 3) ) { + color = script_getnum(st, 3); + if( color < 0 || color > 3 ) { + ShowWarning("buildin_showevent: invalid color '%d', changing to 0\n",color); + script->reportfunc(st); + color = 0; + } + } + + #if PACKETVER >= 20120410 + if(icon < 0 || (icon > 8 && icon != 9999) || icon == 7) + icon = 9999; // Default to nothing if icon id is invalid. + #else + if(icon < 0 || icon > 7) + icon = 0; + else + icon = icon + 1; + #endif + + clif->quest_show_event(sd, &nd->bl, icon, color); return true; } /*========================================== * BattleGround System *------------------------------------------*/ -BUILDIN(waitingroom2bg) -{ +BUILDIN(waitingroom2bg) { struct npc_data *nd; struct chat_data *cd; const char *map_name, *ev = "", *dev = ""; - int x, y, i, mapindex = 0, bg_id, n; + int x, y, i, map_index = 0, bg_id, n; struct map_session_data *sd; - + if( script_hasdata(st,7) ) - nd = npc_name2id(script_getstr(st,7)); + nd = npc->name2id(script_getstr(st,7)); else - nd = (struct npc_data *)iMap->id2bl(st->oid); - - if( nd == NULL || (cd = (struct chat_data *)iMap->id2bl(nd->chat_id)) == NULL ) - { + nd = (struct npc_data *)map->id2bl(st->oid); + + if( nd == NULL || (cd = (struct chat_data *)map->id2bl(nd->chat_id)) == NULL ) { script_pushint(st,0); return true; } - + map_name = script_getstr(st,2); if( strcmp(map_name,"-") != 0 ) { - mapindex = mapindex_name2id(map_name); - if( mapindex == 0 ) + map_index = script->mapindexname2id(st,map_name); + if( map_index == 0 ) { // Invalid Map script_pushint(st,0); return true; } } - + x = script_getnum(st,3); y = script_getnum(st,4); ev = script_getstr(st,5); // Logout Event dev = script_getstr(st,6); // Die Event - - if( (bg_id = bg_create(mapindex, x, y, ev, dev)) == 0 ) + + if( (bg_id = bg->create(map_index, x, y, ev, dev)) == 0 ) { // Creation failed script_pushint(st,0); return true; } - + n = cd->users; for( i = 0; i < n && i < MAX_BG_MEMBERS; i++ ) { - if( (sd = cd->usersd[i]) != NULL && bg_team_join(bg_id, sd) ) - mapreg_setreg(reference_uid(add_str("$@arenamembers"), i), sd->bl.id); + if( (sd = cd->usersd[i]) != NULL && bg->team_join(bg_id, sd) ) + mapreg->setreg(reference_uid(script->add_str("$@arenamembers"), i), sd->bl.id); else - mapreg_setreg(reference_uid(add_str("$@arenamembers"), i), 0); + mapreg->setreg(reference_uid(script->add_str("$@arenamembers"), i), 0); } - - mapreg_setreg(add_str("$@arenamembersnum"), i); + + mapreg->setreg(script->add_str("$@arenamembersnum"), i); script_pushint(st,bg_id); return true; } -BUILDIN(waitingroom2bg_single) -{ +BUILDIN(waitingroom2bg_single) { const char* map_name; struct npc_data *nd; struct chat_data *cd; struct map_session_data *sd; - int x, y, mapindex, bg_id; - + int x, y, map_index, bg_id; + bg_id = script_getnum(st,2); map_name = script_getstr(st,3); - if( (mapindex = mapindex_name2id(map_name)) == 0 ) + if( (map_index = script->mapindexname2id(st,map_name)) == 0 ) return true; // Invalid Map - + x = script_getnum(st,4); y = script_getnum(st,5); - nd = npc_name2id(script_getstr(st,6)); - - if( nd == NULL || (cd = (struct chat_data *)iMap->id2bl(nd->chat_id)) == NULL || cd->users <= 0 ) + nd = npc->name2id(script_getstr(st,6)); + + if( nd == NULL || (cd = (struct chat_data *)map->id2bl(nd->chat_id)) == NULL || cd->users <= 0 ) return true; - + if( (sd = cd->usersd[0]) == NULL ) return true; - - if( bg_team_join(bg_id, sd) ) + + if( bg->team_join(bg_id, sd) ) { - pc->setpos(sd, mapindex, x, y, CLR_TELEPORT); + pc->setpos(sd, map_index, x, y, CLR_TELEPORT); script_pushint(st,1); } else script_pushint(st,0); - + return true; } BUILDIN(bg_team_setxy) { - struct battleground_data *bg; + struct battleground_data *bgd; int bg_id; - + bg_id = script_getnum(st,2); - if( (bg = bg_team_search(bg_id)) == NULL ) + if( (bgd = bg->team_search(bg_id)) == NULL ) return true; - - bg->x = script_getnum(st,3); - bg->y = script_getnum(st,4); + + bgd->x = script_getnum(st,3); + bgd->y = script_getnum(st,4); return true; } BUILDIN(bg_warp) { - int x, y, mapindex, bg_id; + int x, y, map_index, bg_id; const char* map_name; - + bg_id = script_getnum(st,2); map_name = script_getstr(st,3); - if( (mapindex = mapindex_name2id(map_name)) == 0 ) + if( (map_index = script->mapindexname2id(st,map_name)) == 0 ) return true; // Invalid Map x = script_getnum(st,4); y = script_getnum(st,5); - bg_team_warp(bg_id, mapindex, x, y); + bg->team_warp(bg_id, map_index, x, y); return true; } BUILDIN(bg_monster) { int class_ = 0, x = 0, y = 0, bg_id = 0; - const char *str,*map, *evt=""; - - bg_id = script_getnum(st,2); - map = script_getstr(st,3); - x = script_getnum(st,4); - y = script_getnum(st,5); - str = script_getstr(st,6); - class_ = script_getnum(st,7); + const char *str, *mapname, *evt=""; + + bg_id = script_getnum(st,2); + mapname = script_getstr(st,3); + x = script_getnum(st,4); + y = script_getnum(st,5); + str = script_getstr(st,6); + class_ = script_getnum(st,7); if( script_hasdata(st,8) ) evt = script_getstr(st,8); - check_event(st, evt); - script_pushint(st, mob_spawn_bg(map,x,y,str,class_,evt,bg_id)); + script->check_event(st, evt); + script_pushint(st, mob->spawn_bg(mapname,x,y,str,class_,evt,bg_id)); return true; } -BUILDIN(bg_monster_set_team) -{ +BUILDIN(bg_monster_set_team) { struct mob_data *md; struct block_list *mbl; int id = script_getnum(st,2), bg_id = script_getnum(st,3); - - if( (mbl = iMap->id2bl(id)) == NULL || mbl->type != BL_MOB ) + + if( (mbl = map->id2bl(id)) == NULL || mbl->type != BL_MOB ) return true; md = (TBL_MOB *)mbl; md->bg_id = bg_id; - + mob_stop_attack(md); mob_stop_walking(md, 0); md->target_id = md->attacked_id = 0; clif->charnameack(0, &md->bl); - + return true; } BUILDIN(bg_leave) { - struct map_session_data *sd = script_rid2sd(st); + struct map_session_data *sd = script->rid2sd(st); if( sd == NULL || !sd->bg_id ) return true; - - bg_team_leave(sd,0); + + bg->team_leave(sd,BGTL_LEFT); return true; } BUILDIN(bg_destroy) { int bg_id = script_getnum(st,2); - bg_team_delete(bg_id); + bg->team_delete(bg_id); return true; } -BUILDIN(bg_getareausers) -{ +BUILDIN(bg_getareausers) { const char *str; int16 m, x0, y0, x1, y1; int bg_id; int i = 0, c = 0; - struct battleground_data *bg = NULL; + struct battleground_data *bgd = NULL; struct map_session_data *sd; - + bg_id = script_getnum(st,2); str = script_getstr(st,3); - - if( (bg = bg_team_search(bg_id)) == NULL || (m = iMap->mapname2mapid(str)) < 0 ) - { + + if( (bgd = bg->team_search(bg_id)) == NULL || (m = map->mapname2mapid(str)) < 0 ) { script_pushint(st,0); return true; } - + x0 = script_getnum(st,4); y0 = script_getnum(st,5); x1 = script_getnum(st,6); y1 = script_getnum(st,7); - + for( i = 0; i < MAX_BG_MEMBERS; i++ ) { - if( (sd = bg->members[i].sd) == NULL ) + if( (sd = bgd->members[i].sd) == NULL ) continue; if( sd->bl.m != m || sd->bl.x < x0 || sd->bl.y < y0 || sd->bl.x > x1 || sd->bl.y > y1 ) continue; c++; } - + script_pushint(st,c); return true; } -BUILDIN(bg_updatescore) -{ +BUILDIN(bg_updatescore) { const char *str; int16 m; - + str = script_getstr(st,2); - if( (m = iMap->mapname2mapid(str)) < 0 ) + if( (m = map->mapname2mapid(str)) < 0 ) return true; - - map[m].bgscore_lion = script_getnum(st,3); - map[m].bgscore_eagle = script_getnum(st,4); - + + map->list[m].bgscore_lion = script_getnum(st,3); + map->list[m].bgscore_eagle = script_getnum(st,4); + clif->bg_updatescore(m); return true; } BUILDIN(bg_get_data) { - struct battleground_data *bg; + struct battleground_data *bgd; int bg_id = script_getnum(st,2), type = script_getnum(st,3); - - if( (bg = bg_team_search(bg_id)) == NULL ) + + if( (bgd = bg->team_search(bg_id)) == NULL ) { script_pushint(st,0); return true; } - + switch( type ) { - case 0: script_pushint(st, bg->count); break; + case 0: script_pushint(st, bgd->count); break; default: ShowError("script:bg_get_data: unknown data identifier %d\n", type); break; } - + return true; } @@ -15851,7 +16607,7 @@ BUILDIN(instance_create) { const char *name; int owner_id, res; int type = IOT_PARTY; - + name = script_getstr(st, 2); owner_id = script_getnum(st, 3); if( script_hasdata(st,4) ) { @@ -15861,9 +16617,9 @@ BUILDIN(instance_create) { return true; } } - + res = instance->create(owner_id, name, (enum instance_owner_type) type); - if( res == -4 ) { // Already exists + if( res == -4 ) { // Already exists script_pushint(st, -1); return true; } else if( res < 0 ) { @@ -15878,25 +16634,25 @@ BUILDIN(instance_create) { script_pushint(st, -2); return true; } - + script_pushint(st, res); return true; } BUILDIN(instance_destroy) { int instance_id = -1; - + if( script_hasdata(st, 2) ) instance_id = script_getnum(st, 2); else if( st->instance_id >= 0 ) instance_id = st->instance_id; else return true; - + if( !instance->valid(instance_id) ) { ShowError("buildin_instance_destroy: Trying to destroy invalid instance %d.\n", instance_id); return true; } - + instance->destroy(instance_id); return true; } @@ -15906,22 +16662,22 @@ BUILDIN(instance_attachmap) { int16 m; int instance_id = -1; bool usebasename = false; - + name = script_getstr(st,2); instance_id = script_getnum(st,3); if( script_hasdata(st,4) && script_getnum(st,4) > 0 ) usebasename = true; - + if( script_hasdata(st, 5) ) map_name = script_getstr(st, 5); - + if( (m = instance->add_map(name, instance_id, usebasename, map_name)) < 0 ) { // [Saithis] ShowError("buildin_instance_attachmap: instance creation failed (%s): %d\n", name, m); script_pushconststr(st, ""); return true; } - script_pushconststr(st, map[m].name); - + script_pushconststr(st, map->list[m].name); + return true; } @@ -15929,30 +16685,30 @@ BUILDIN(instance_detachmap) { const char *str; int16 m; int instance_id = -1; - + str = script_getstr(st, 2); if( script_hasdata(st, 3) ) instance_id = script_getnum(st, 3); else if( st->instance_id >= 0 ) instance_id = st->instance_id; else return true; - - if( (m = iMap->mapname2mapid(str)) < 0 || (m = instance->map2imap(m,instance_id)) < 0 ) { + + if( (m = map->mapname2mapid(str)) < 0 || (m = instance->map2imap(m,instance_id)) < 0 ) { ShowError("buildin_instance_detachmap: Trying to detach invalid map %s\n", str); return true; } - + instance->del_map(m); return true; } BUILDIN(instance_attach) { int instance_id = -1; - + instance_id = script_getnum(st, 2); if( !instance->valid(instance_id) ) return true; - + st->instance_id = instance_id; return true; } @@ -15966,35 +16722,35 @@ BUILDIN(instance_set_timeout) { int progress_timeout, idle_timeout; int instance_id = -1; - + progress_timeout = script_getnum(st, 2); idle_timeout = script_getnum(st, 3); - + if( script_hasdata(st, 4) ) instance_id = script_getnum(st, 4); else if( st->instance_id >= 0 ) instance_id = st->instance_id; else return true; - + if( instance_id >= 0 ) instance->set_timeout(instance_id, progress_timeout, idle_timeout); - + return true; } BUILDIN(instance_init) { int instance_id = script_getnum(st, 2); - + if( !instance->valid(instance_id) ) { ShowError("instance_init: invalid instance id %d.\n",instance_id); return true; } - - if( instances[instance_id].state != INSTANCE_IDLE ) { + + if( instance->list[instance_id].state != INSTANCE_IDLE ) { ShowError("instance_init: instance already initialized.\n"); return true; } - + instance->start(instance_id); return true; } @@ -16008,23 +16764,23 @@ 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; - + if( instance_id == -1 ) { if( st->instance_id >= 0 ) instance_id = st->instance_id; else return true; } - + if( !instance->valid(instance_id) ) return true; - - for( i = 0; i < instances[instance_id].num_map; i++ ) - iMap->foreachinmap(buildin_announce_sub, instances[instance_id].map[i], BL_PC, - mes, strlen(mes)+1, flag&0xf0, fontColor, fontType, fontSize, fontAlign, fontY); - + + 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); + return true; } @@ -16032,91 +16788,107 @@ BUILDIN(instance_npcname) { const char *str; int instance_id = -1; struct npc_data *nd; - + str = script_getstr(st, 2); if( script_hasdata(st, 3) ) instance_id = script_getnum(st, 3); else if( st->instance_id >= 0 ) instance_id = st->instance_id; - - if( instance_id >= 0 && (nd = npc_name2id(str)) != NULL ) { + + if( instance_id >= 0 && (nd = npc->name2id(str)) != NULL ) { static char npcname[NAME_LENGTH]; snprintf(npcname, sizeof(npcname), "dup_%d_%d", instance_id, nd->bl.id); - script_pushconststr(st,npcname); + script_pushconststr(st,npcname); } else { ShowError("script:instance_npcname: invalid instance NPC (instance_id: %d, NPC name: \"%s\".)\n", instance_id, str); st->state = END; return false; } - + return true; } BUILDIN(has_instance) { struct map_session_data *sd; - const char *str; + const char *str; int16 m; int instance_id = -1; + bool type = strcmp(script->getfuncname(st),"has_instance2") == 0 ? true : false; - str = script_getstr(st, 2); - - if( (m = iMap->mapname2mapid(str)) < 0 ) { - script_pushconststr(st, ""); + str = script_getstr(st, 2); + + if( (m = map->mapname2mapid(str)) < 0 ) { + if( type ) + script_pushint(st, -1); + else + script_pushconststr(st, ""); return true; } - + if( script_hasdata(st, 3) ) instance_id = script_getnum(st, 3); else if( st->instance_id >= 0 ) instance_id = st->instance_id; - else if( (sd = script_rid2sd(st)) != NULL ) { + else if( (sd = script->rid2sd(st)) != NULL ) { struct party_data *p; int i = 0, j = 0; if( sd->instances ) { for( i = 0; i < sd->instances; i++ ) { - ARR_FIND(0, instances[sd->instance[i]].num_map, j, map[instances[sd->instance[i]].map[j]].instance_src_map == m); - if( j != instances[sd->instance[i]].num_map ) - break; + if( sd->instance[i] >= 0 ) { + ARR_FIND(0, instance->list[sd->instance[i]].num_map, j, map->list[instance->list[sd->instance[i]].map[j]].instance_src_map == m); + if( j != instance->list[sd->instance[i]].num_map ) + break; + } } if( i != sd->instances ) instance_id = sd->instance[i]; } if( instance_id == -1 && sd->status.party_id && (p = party->search(sd->status.party_id)) && p->instances ) { for( i = 0; i < p->instances; i++ ) { - ARR_FIND(0, instances[p->instance[i]].num_map, j, map[instances[p->instance[i]].map[j]].instance_src_map == m); - if( j != instances[p->instance[i]].num_map ) - break; + if( p->instance[i] >= 0 ) { + ARR_FIND(0, instance->list[p->instance[i]].num_map, j, map->list[instance->list[p->instance[i]].map[j]].instance_src_map == m); + if( j != instance->list[p->instance[i]].num_map ) + break; + } } if( i != p->instances ) instance_id = p->instance[i]; } if( instance_id == -1 && sd->guild && sd->guild->instances ) { for( i = 0; i < sd->guild->instances; i++ ) { - ARR_FIND(0, instances[sd->guild->instance[i]].num_map, j, map[instances[sd->guild->instance[i]].map[j]].instance_src_map == m); - if( j != instances[sd->guild->instance[i]].num_map ) - break; + if( sd->guild->instance[i] >= 0 ) { + ARR_FIND(0, instance->list[sd->guild->instance[i]].num_map, j, map->list[instance->list[sd->guild->instance[i]].map[j]].instance_src_map == m); + if( j != instance->list[sd->guild->instance[i]].num_map ) + break; + } } if( i != sd->guild->instances ) instance_id = sd->guild->instance[i]; } } - + if( !instance->valid(instance_id) || (m = instance->map2imap(m, instance_id)) < 0 ) { - script_pushconststr(st, ""); + if( type ) + script_pushint(st, -1); + else + script_pushconststr(st, ""); return true; } - - script_pushconststr(st, map[m].name); + + if( type ) + script_pushint(st, instance_id); + else + script_pushconststr(st, map->list[m].name); return true; } -static int buildin_instance_warpall_sub(struct block_list *bl,va_list ap) { +int buildin_instance_warpall_sub(struct block_list *bl,va_list ap) { struct map_session_data *sd = ((TBL_PC*)bl); - int mapindex = va_arg(ap,int); + int map_index = va_arg(ap,int); int x = va_arg(ap,int); int y = va_arg(ap,int); - - pc->setpos(sd,mapindex,x,y,CLR_TELEPORT); - + + pc->setpos(sd,map_index,x,y,CLR_TELEPORT); + return 0; } BUILDIN(instance_warpall) { @@ -16124,25 +16896,25 @@ BUILDIN(instance_warpall) { int instance_id = -1; const char *mapn; int x, y; - int mapindex; - + int map_index; + mapn = script_getstr(st,2); x = script_getnum(st,3); y = script_getnum(st,4); - + if( script_hasdata(st,5) ) instance_id = script_getnum(st,5); else if( st->instance_id >= 0 ) instance_id = st->instance_id; else return true; - - if( (m = iMap->mapname2mapid(mapn)) < 0 || (map[m].flag.src4instance && (m = instance->mapid2imapid(m, instance_id)) < 0) ) + + if( (m = map->mapname2mapid(mapn)) < 0 || (map->list[m].flag.src4instance && (m = instance->mapid2imapid(m, instance_id)) < 0) ) return true; - - mapindex = map_id2index(m); - - iMap->foreachininstance(buildin_instance_warpall_sub, instance_id, BL_PC,mapindex,x,y); + + map_index = map_id2index(m); + + map->foreachininstance(script->buildin_instance_warpall_sub, instance_id, BL_PC,map_index,x,y); return true; } @@ -16161,46 +16933,46 @@ BUILDIN(instance_check_party) { struct map_session_data *pl_sd; int amount, min, max, i, party_id, c = 0; struct party_data *p = NULL; - + amount = script_hasdata(st,3) ? script_getnum(st,3) : 1; // Amount of needed Partymembers for the Instance. min = script_hasdata(st,4) ? script_getnum(st,4) : 1; // Minimum Level needed to join the Instance. max = script_hasdata(st,5) ? script_getnum(st,5) : MAX_LEVEL; // Maxium Level allowed to join the Instance. - - if( min < 1 || min > MAX_LEVEL){ + + if( min < 1 || min > MAX_LEVEL) { ShowError("instance_check_party: Invalid min level, %d\n", min); return true; - } else if( max < 1 || max > MAX_LEVEL){ + } else if( max < 1 || max > MAX_LEVEL) { ShowError("instance_check_party: Invalid max level, %d\n", max); return true; } - + if( script_hasdata(st,2) ) party_id = script_getnum(st,2); else return true; - - if( !(p = party->search(party_id)) ){ + + if( !(p = party->search(party_id)) ) { script_pushint(st, 0); // Returns false if party does not exist. return true; } - + for( i = 0; i < MAX_PARTY; i++ ) if( (pl_sd = p->data[i].sd) ) - if(iMap->id2bl(pl_sd->bl.id)){ - if(pl_sd->status.base_level < min){ + if(map->id2bl(pl_sd->bl.id)) { + if(pl_sd->status.base_level < min) { script_pushint(st, 0); return true; - }else if(pl_sd->status.base_level > max){ + } else if(pl_sd->status.base_level > max) { script_pushint(st, 0); return true; } c++; } - - if(c < amount){ + + if(c < amount) { script_pushint(st, 0); // Not enough Members in the Party to join Instance. - }else + } else script_pushint(st, 1); - + return true; } @@ -16209,113 +16981,112 @@ BUILDIN(instance_check_party) { *------------------------------------------*/ BUILDIN(setfont) { - struct map_session_data *sd = script_rid2sd(st); + struct map_session_data *sd = script->rid2sd(st); int font = script_getnum(st,2); if( sd == NULL ) return true; - - if( sd->user_font != font ) - sd->user_font = font; + + if( sd->status.font != font ) + sd->status.font = font; else - sd->user_font = 0; - + sd->status.font = 0; + clif->font(sd); return true; } -static int buildin_mobuseskill_sub(struct block_list *bl,va_list ap) +int buildin_mobuseskill_sub(struct block_list *bl,va_list ap) { - TBL_MOB* md = (TBL_MOB*)bl; + TBL_MOB* md = (TBL_MOB*)bl; struct block_list *tbl; - int mobid = va_arg(ap,int); - uint16 skill_id = va_arg(ap,int); - uint16 skill_lv = va_arg(ap,int); - int casttime = va_arg(ap,int); - int cancel = va_arg(ap,int); - int emotion = va_arg(ap,int); - int target = va_arg(ap,int); - + int mobid = va_arg(ap,int); + uint16 skill_id = va_arg(ap,int); + uint16 skill_lv = va_arg(ap,int); + int casttime = va_arg(ap,int); + int cancel = va_arg(ap,int); + int emotion = va_arg(ap,int); + int target = va_arg(ap,int); + if( md->class_ != mobid ) return 0; - + // 0:self, 1:target, 2:master, default:random switch( target ) { - case 0: tbl = iMap->id2bl(md->bl.id); break; - case 1: tbl = iMap->id2bl(md->target_id); break; - case 2: tbl = iMap->id2bl(md->master_id); break; - default:tbl = battle->get_enemy(&md->bl, DEFAULT_ENEMY_TYPE(md),skill->get_range2(&md->bl, skill_id, skill_lv)); break; + case 0: tbl = map->id2bl(md->bl.id); break; + case 1: tbl = map->id2bl(md->target_id); break; + case 2: tbl = map->id2bl(md->master_id); break; + default: tbl = battle->get_enemy(&md->bl, DEFAULT_ENEMY_TYPE(md),skill->get_range2(&md->bl, skill_id, skill_lv)); break; } - + if( !tbl ) return 0; - + if( md->ud.skilltimer != INVALID_TIMER ) // Cancel the casting skill. - unit_skillcastcancel(bl,0); - + unit->skillcastcancel(bl,0); + if( skill->get_casttype(skill_id) == CAST_GROUND ) - unit_skilluse_pos2(&md->bl, tbl->x, tbl->y, skill_id, skill_lv, casttime, cancel); + unit->skilluse_pos2(&md->bl, tbl->x, tbl->y, skill_id, skill_lv, casttime, cancel); else - unit_skilluse_id2(&md->bl, tbl->id, skill_id, skill_lv, casttime, cancel); - + unit->skilluse_id2(&md->bl, tbl->id, skill_id, skill_lv, casttime, cancel); + clif->emotion(&md->bl, emotion); - + return 0; } /*========================================== * areamobuseskill "Map Name",<x>,<y>,<range>,<Mob ID>,"Skill Name"/<Skill ID>,<Skill Lv>,<Cast Time>,<Cancelable>,<Emotion>,<Target Type>; *------------------------------------------*/ -BUILDIN(areamobuseskill) -{ +BUILDIN(areamobuseskill) { struct block_list center; int16 m; int range,mobid,skill_id,skill_lv,casttime,emotion,target,cancel; - - if( (m = iMap->mapname2mapid(script_getstr(st,2))) < 0 ) { + + if( (m = map->mapname2mapid(script_getstr(st,2))) < 0 ) { ShowError("areamobuseskill: invalid map name.\n"); return true; } - - if( map[m].flag.src4instance && st->instance_id >= 0 && (m = instance->mapid2imapid(m, st->instance_id)) < 0 ) + + if( map->list[m].flag.src4instance && st->instance_id >= 0 && (m = instance->mapid2imapid(m, st->instance_id)) < 0 ) return true; - + center.m = m; center.x = script_getnum(st,3); center.y = script_getnum(st,4); range = script_getnum(st,5); mobid = script_getnum(st,6); - skill_id = ( script_isstring(st,7) ? skill->name2id(script_getstr(st,7)) : script_getnum(st,7) ); + skill_id = ( script_isstringtype(st, 7) ? skill->name2id(script_getstr(st, 7)) : script_getnum(st, 7) ); skill_lv = script_getnum(st,8); casttime = script_getnum(st,9); cancel = script_getnum(st,10); emotion = script_getnum(st,11); target = script_getnum(st,12); - - iMap->foreachinrange(buildin_mobuseskill_sub, ¢er, range, BL_MOB, mobid, skill_id, skill_lv, casttime, cancel, emotion, target); + + map->foreachinrange(script->buildin_mobuseskill_sub, ¢er, range, BL_MOB, mobid, skill_id, skill_lv, casttime, cancel, emotion, target); return true; } BUILDIN(progressbar) { - struct map_session_data * sd = script_rid2sd(st); + struct map_session_data * sd = script->rid2sd(st); const char * color; unsigned int second; - + if( !st || !sd ) return true; - + st->state = STOP; - + color = script_getstr(st,2); second = script_getnum(st,3); - + sd->progressbar.npc_id = st->oid; - sd->progressbar.timeout = iTimer->gettick() + second*1000; + sd->progressbar.timeout = timer->gettick() + second*1000; sd->state.workinprogress = 3; - - clif->progressbar(sd, strtol(color, (char **)NULL, 0), second); - return true; + + clif->progressbar(sd, (unsigned int)strtoul(color, (char **)NULL, 0), second); + return true; } BUILDIN(pushpc) @@ -16323,23 +17094,23 @@ BUILDIN(pushpc) uint8 dir; int cells, dx, dy; struct map_session_data* sd; - - if((sd = script_rid2sd(st))==NULL) + + if((sd = script->rid2sd(st))==NULL) { return true; } - + dir = script_getnum(st,2); cells = script_getnum(st,3); - + if(dir>7) { ShowWarning("buildin_pushpc: Invalid direction %d specified.\n", dir); - script_reportsrc(st); - + script->reportsrc(st); + dir%= 8; // trim spin-over } - + if(!cells) {// zero distance return true; @@ -16349,11 +17120,11 @@ BUILDIN(pushpc) dir = (dir+4)%8; // turn around cells = -cells; } - + dx = dirx[dir]; dy = diry[dir]; - - unit_blown(&sd->bl, dx, dy, cells, 0); + + unit->blown(&sd->bl, dx, dy, cells, 0); return true; } @@ -16363,11 +17134,11 @@ BUILDIN(pushpc) BUILDIN(buyingstore) { struct map_session_data* sd; - - if( ( sd = script_rid2sd(st) ) == NULL ) { + + if( ( sd = script->rid2sd(st) ) == NULL ) { return true; } - + buyingstore->setup(sd, script_getnum(st,2)); return true; } @@ -16380,27 +17151,27 @@ BUILDIN(searchstores) unsigned short effect; unsigned int uses; struct map_session_data* sd; - - if( ( sd = script_rid2sd(st) ) == NULL ) + + if( ( sd = script->rid2sd(st) ) == NULL ) { return true; } - + uses = script_getnum(st,2); effect = script_getnum(st,3); - + if( !uses ) { ShowError("buildin_searchstores: Amount of uses cannot be zero.\n"); return false; } - + if( effect > 1 ) { ShowError("buildin_searchstores: Invalid effect id %hu, specified.\n", effect); return false; } - + searchstore->open(sd, uses, effect); return true; } @@ -16411,25 +17182,25 @@ BUILDIN(showdigit) unsigned int type = 0; int value; struct map_session_data* sd; - - if( ( sd = script_rid2sd(st) ) == NULL ) + + if( ( sd = script->rid2sd(st) ) == NULL ) { return true; } - + value = script_getnum(st,2); - + if( script_hasdata(st,3) ) { type = script_getnum(st,3); - + if( type > 3 ) { ShowError("buildin_showdigit: Invalid type %u.\n", type); return false; } } - + clif->showdigit(sd, (unsigned char)type, value); return true; } @@ -16438,7 +17209,7 @@ BUILDIN(showdigit) **/ BUILDIN(makerune) { TBL_PC* sd; - if( (sd = script_rid2sd(st)) == NULL ) + if( (sd = script->rid2sd(st)) == NULL ) return true; clif->skill_produce_mix_list(sd,RK_RUNEMASTERY,24); sd->itemid = script_getnum(st,2); @@ -16449,7 +17220,7 @@ BUILDIN(makerune) { **/ BUILDIN(checkdragon) { TBL_PC* sd; - if( (sd = script_rid2sd(st)) == NULL ) + if( (sd = script->rid2sd(st)) == NULL ) return true; if( pc_isridingdragon(sd) ) script_pushint(st,1); @@ -16470,8 +17241,8 @@ BUILDIN(checkdragon) { BUILDIN(setdragon) { TBL_PC* sd; int color = script_hasdata(st,2) ? script_getnum(st,2) : 0; - - if( (sd = script_rid2sd(st)) == NULL ) + + if( (sd = script->rid2sd(st)) == NULL ) return true; if( !pc->checkskill(sd,RK_DRAGONTRAINING) || (sd->class_&MAPID_THIRDMASK) != MAPID_RUNE_KNIGHT ) script_pushint(st,0);//Doesn't have the skill or it's not a Rune Knight @@ -16482,10 +17253,10 @@ BUILDIN(setdragon) { unsigned int option = OPTION_DRAGON1; if( color ) { option = ( color == 1 ? OPTION_DRAGON1 : - color == 2 ? OPTION_DRAGON2 : - color == 3 ? OPTION_DRAGON3 : - color == 4 ? OPTION_DRAGON4 : - color == 5 ? OPTION_DRAGON5 : 0); + color == 2 ? OPTION_DRAGON2 : + color == 3 ? OPTION_DRAGON3 : + color == 4 ? OPTION_DRAGON4 : + color == 5 ? OPTION_DRAGON5 : 0); if( !option ) { ShowWarning("script_setdragon: Unknown Color %d used; changing to green (1)\n",color); option = OPTION_DRAGON1; @@ -16502,7 +17273,7 @@ BUILDIN(setdragon) { **/ BUILDIN(ismounting) { TBL_PC* sd; - if( (sd = script_rid2sd(st)) == NULL ) + if( (sd = script->rid2sd(st)) == NULL ) return true; if( sd->sc.data[SC_ALL_RIDING] ) script_pushint(st,1); @@ -16519,16 +17290,16 @@ BUILDIN(ismounting) { **/ BUILDIN(setmounting) { TBL_PC* sd; - if( (sd = script_rid2sd(st)) == NULL ) + if( (sd = script->rid2sd(st)) == NULL ) return true; - if( sd->sc.option&(OPTION_WUGRIDER|OPTION_RIDING|OPTION_DRAGON|OPTION_MADOGEAR) ){ + if( sd->sc.option&(OPTION_WUGRIDER|OPTION_RIDING|OPTION_DRAGON|OPTION_MADOGEAR) ) { clif->msgtable(sd->fd, 0X78b); script_pushint(st,0);//can't mount with one of these - }else { + } else { if( sd->sc.data[SC_ALL_RIDING] ) status_change_end(&sd->bl, SC_ALL_RIDING, INVALID_TIMER); else - sc_start(&sd->bl, SC_ALL_RIDING, 100, 0, -1); + sc_start(NULL,&sd->bl, SC_ALL_RIDING, 100, 0, -1); script_pushint(st,1);//in both cases, return 1. } return true; @@ -16539,60 +17310,56 @@ BUILDIN(setmounting) { **/ BUILDIN(getargcount) { struct script_retinfo* ri; - + if( st->stack->defsp < 1 || st->stack->stack_data[st->stack->defsp - 1].type != C_RETINFO ) { ShowError("script:getargcount: used out of function or callsub label!\n"); st->state = END; return false; } ri = st->stack->stack_data[st->stack->defsp - 1].u.ri; - + script_pushint(st, ri->nargs); - + return true; } /** * getcharip(<account ID>/<character ID>/<character name>) **/ -BUILDIN(getcharip) -{ +BUILDIN(getcharip) { struct map_session_data* sd = NULL; - + /* check if a character name is specified */ - if( script_hasdata(st, 2) ) - { - if (script_isstring(st, 2)) - sd = iMap->nick2sd(script_getstr(st, 2)); - else if (script_isint(st, 2) || script_getnum(st, 2)) - { - int id; - id = script_getnum(st, 2); - sd = (iMap->id2sd(id) ? iMap->id2sd(id) : iMap->charid2sd(id)); + if( script_hasdata(st, 2) ) { + if (script_isstringtype(st, 2)) { + sd = map->nick2sd(script_getstr(st, 2)); + } else { + int id = script_getnum(st, 2); + sd = (map->id2sd(id) ? map->id2sd(id) : map->charid2sd(id)); } + } else { + sd = script->rid2sd(st); } - else - sd = script_rid2sd(st); - + /* check for sd and IP */ if (!sd || !session[sd->fd]->client_addr) { script_pushconststr(st, ""); return true; } - + /* return the client ip_addr converted for output */ if (sd && sd->fd && session[sd->fd]) { /* initiliaze */ const char *ip_addr = NULL; uint32 ip; - + /* set ip, ip_addr and convert to ip and push str */ ip = session[sd->fd]->client_addr; ip_addr = ip2str(ip, NULL); script_pushstrcopy(st, ip_addr); } - + return true; } /** @@ -16600,39 +17367,84 @@ BUILDIN(getcharip) **/ BUILDIN(is_function) { const char* str = script_getstr(st,2); - - if( strdb_exists(userfunc_db, str) ) + + if( strdb_exists(script->userfunc_db, str) ) script_pushint(st,1); else script_pushint(st,0); - - return true; -} -/** - * get_revision() -> retrieves the current svn revision (if available) - **/ -BUILDIN(get_revision) { - const char *svn = get_svn_revision(); - - if ( svn[0] != HERC_UNKNOWN_VER ) - script_pushint(st,atoi(svn)); - else - script_pushint(st,-1);//unknown - + return true; } /** * freeloop(<toggle>) -> toggles this script instance's looping-check ability **/ BUILDIN(freeloop) { - + if( script_getnum(st,2) ) st->freeloop = 1; else st->freeloop = 0; - + script_pushint(st, st->freeloop); - + + return true; +} + +BUILDIN(sit) { + struct map_session_data *sd = NULL; + + if( script_hasdata(st, 2) ) + sd = map->nick2sd(script_getstr(st, 2)); + else + sd = script->rid2sd(st); + + if( sd == NULL ) + return false; + + if (!pc_issit(sd)) + { + pc_setsit(sd); + skill->sit(sd,1); + clif->sitting(&sd->bl); + } + return true; +} + +BUILDIN(stand) { + struct map_session_data *sd = NULL; + + if( script_hasdata(st, 2) ) + sd = map->nick2sd(script_getstr(st, 2)); + else + sd = script->rid2sd(st); + + if( sd == NULL ) + return false; + + if (pc_issit(sd)) + { + pc->setstand(sd); + skill->sit(sd,0); + clif->standing(&sd->bl); + } + return true; +} + +BUILDIN(issit) { + struct map_session_data *sd = NULL; + + if( script_hasdata(st, 2) ) + sd = map->nick2sd(script_getstr(st, 2)); + else + sd = script->rid2sd(st); + + if( sd == NULL ) + return false; + + if (pc_issit(sd)) + script_pushint(st, 1); + else + script_pushint(st, 0); return true; } @@ -16645,21 +17457,21 @@ BUILDIN(bindatcmd) { int i, group_lv = 0, group_lv_char = 99; bool log = false; bool create = false; - + atcmd = script_getstr(st,2); eventName = script_getstr(st,3); - + if( *atcmd == atcommand->at_symbol || *atcmd == atcommand->char_symbol ) atcmd++; - + if( script_hasdata(st,4) ) group_lv = script_getnum(st,4); if( script_hasdata(st,5) ) group_lv_char = script_getnum(st,5); if( script_hasdata(st,6) ) log = script_getnum(st,6) ? true : false; - + if( atcommand->binding_count == 0 ) { CREATE(atcommand->binding,struct atcmd_binding_data*,1); - + create = true; } else { ARR_FIND(0, atcommand->binding_count, i, strcmp(atcommand->binding[i]->command,atcmd) == 0); @@ -16671,39 +17483,39 @@ BUILDIN(bindatcmd) { } else create = true; } - + if( create ) { i = atcommand->binding_count; - + if( atcommand->binding_count++ != 0 ) RECREATE(atcommand->binding,struct atcmd_binding_data*,atcommand->binding_count); - + CREATE(atcommand->binding[i],struct atcmd_binding_data,1); - + safestrncpy(atcommand->binding[i]->command, atcmd, 50); safestrncpy(atcommand->binding[i]->npc_event, eventName, 50); atcommand->binding[i]->group_lv = group_lv; atcommand->binding[i]->group_lv_char = group_lv_char; atcommand->binding[i]->log = log; } - + return true; } BUILDIN(unbindatcmd) { const char* atcmd; int i = 0; - + atcmd = script_getstr(st, 2); - + if( *atcmd == atcommand->at_symbol || *atcmd == atcommand->char_symbol ) atcmd++; - + if( atcommand->binding_count == 0 ) { script_pushint(st, 0); return true; } - + ARR_FIND(0, atcommand->binding_count, i, strcmp(atcommand->binding[i]->command, atcmd) == 0); if( i < atcommand->binding_count ) { int cursor = 0; @@ -16713,70 +17525,67 @@ BUILDIN(unbindatcmd) { for( i = 0, cursor = 0; i < atcommand->binding_count; i++ ) { if( atcommand->binding[i] == NULL ) continue; - + if( cursor != i ) { memmove(&atcommand->binding[cursor], &atcommand->binding[i], sizeof(struct atcmd_binding_data*)); } - + cursor++; } - + if( (atcommand->binding_count = cursor) == 0 ) aFree(atcommand->binding); - + script_pushint(st, 1); } else script_pushint(st, 0);/* not found */ - + return true; } -BUILDIN(useatcmd) -{ - TBL_PC dummy_sd; - TBL_PC* sd; +BUILDIN(useatcmd) { + TBL_PC *sd, *dummy_sd = NULL; int fd; const char* cmd; - + cmd = script_getstr(st,2); - - if( st->rid ) - { - sd = script_rid2sd(st); + + if( st->rid ) { + sd = script->rid2sd(st); + if( sd == NULL ) + return false; fd = sd->fd; - } - else - { // Use a dummy character. - sd = &dummy_sd; + } else { + // Use a dummy character. + sd = dummy_sd = pc->get_dummy_sd(); fd = 0; - - memset(&dummy_sd, 0, sizeof(TBL_PC)); - if( st->oid ) - { - struct block_list* bl = iMap->id2bl(st->oid); - memcpy(&dummy_sd.bl, bl, sizeof(struct block_list)); + + if( st->oid ) { + struct block_list* bl = map->id2bl(st->oid); + memcpy(&sd->bl, bl, sizeof(struct block_list)); if( bl->type == BL_NPC ) - safestrncpy(dummy_sd.status.name, ((TBL_NPC*)bl)->name, NAME_LENGTH); + safestrncpy(sd->status.name, ((TBL_NPC*)bl)->name, NAME_LENGTH); } } - + // compatibility with previous implementation (deprecated!) if( cmd[0] != atcommand->at_symbol ) { cmd += strlen(sd->status.name); while( *cmd != atcommand->at_symbol && *cmd != 0 ) cmd++; } - - atcommand->parse(fd, sd, cmd, 1); + + atcommand->exec(fd, sd, cmd, true); + if (dummy_sd) aFree(dummy_sd); return true; } BUILDIN(checkre) { int num; - + num=script_getnum(st,2); - switch(num){ + switch(num) { case 0: #ifdef RENEWAL script_pushint(st, 1); @@ -16833,112 +17642,112 @@ BUILDIN(checkre) return true; } -/* getrandgroupitem <group_id>,<quantity> */ +/* getrandgroupitem <container_item_id>,<quantity> */ BUILDIN(getrandgroupitem) { - TBL_PC* sd; - int i, get_count = 0, flag, nameid, group = script_getnum(st, 2), qty = script_getnum(st,3); - struct item item_tmp; - - if( !( sd = script_rid2sd(st) ) ) - return true; - - if( qty <= 0 ) { - ShowError("getrandgroupitem: qty is <= 0!\n"); - return false; - } - - if(group < 1 || group >= MAX_ITEMGROUP) { - ShowError("getrandgroupitem: Invalid group id %d\n", group); - return false; - } - if (!itemgroup_db[group].qty) { - ShowError("getrandgroupitem: group id %d is empty!\n", group); - return false; - } - - nameid = itemdb_searchrandomid(group); - memset(&item_tmp,0,sizeof(item_tmp)); - - item_tmp.nameid = nameid; - item_tmp.identify = itemdb_isidentified(nameid); - - //Check if it's stackable. - if (!itemdb_isstackable(nameid)) - get_count = 1; - else - get_count = qty; - - for (i = 0; i < qty; i += get_count) { - // if not pet egg - if (!pet_create_egg(sd, nameid)) { - if ((flag = pc->additem(sd, &item_tmp, get_count, LOG_TYPE_SCRIPT))) { - clif->additem(sd, 0, 0, flag); - if( pc->candrop(sd,&item_tmp) ) - iMap->addflooritem(&item_tmp,get_count,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0); + struct item_data *data = NULL; + struct map_session_data *sd = NULL; + int nameid = script_getnum(st, 2); + int count = script_getnum(st, 3); + + if( !(data = itemdb->exists(nameid)) ) { + ShowWarning("buildin_getrandgroupitem: unknown item id %d\n",nameid); + script_pushint(st, 1); + } else if ( count <= 0 ) { + ShowError("buildin_getrandgroupitem: qty is <= 0!\n"); + script_pushint(st, 1); + } else if ( !data->group ) { + ShowWarning("buildin_getrandgroupitem: item '%s' (%d) isn't a group!\n",data->name,nameid); + script_pushint(st, 1); + } else if( !( sd = script->rid2sd(st) ) ) { + ShowWarning("buildin_getrandgroupitem: no player attached!! (item %s (%d))\n",data->name,nameid); + script_pushint(st, 1); + } else { + int i, get_count, flag; + struct item it; + + memset(&it,0,sizeof(it)); + + nameid = itemdb->group_item(data->group); + + it.nameid = nameid; + it.identify = itemdb->isidentified(nameid); + + if (!itemdb->isstackable(nameid)) + get_count = 1; + else + get_count = count; + + for (i = 0; i < count; i += get_count) { + // if not pet egg + if (!pet->create_egg(sd, nameid)) { + if ((flag = pc->additem(sd, &it, get_count, LOG_TYPE_SCRIPT))) { + clif->additem(sd, 0, 0, flag); + if( pc->candrop(sd,&it) ) + map->addflooritem(&it,get_count,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0); + } } } + + script_pushint(st, 0); } - + return true; } /* cleanmap <map_name>; * cleanarea <map_name>, <x0>, <y0>, <x1>, <y1>; */ -static int atcommand_cleanfloor_sub(struct block_list *bl, va_list ap) -{ +int script_cleanfloor_sub(struct block_list *bl, va_list ap) { nullpo_ret(bl); - iMap->clearflooritem(bl); - + map->clearflooritem(bl); + return 0; } -BUILDIN(cleanmap) -{ - const char *map; - int16 m = -1; - int16 x0 = 0, y0 = 0, x1 = 0, y1 = 0; - - map = script_getstr(st, 2); - m = iMap->mapname2mapid(map); - if (!m) - return false; - +BUILDIN(cleanmap) { + const char *mapname; + int16 m = -1; + int16 x0 = 0, y0 = 0, x1 = 0, y1 = 0; + + mapname = script_getstr(st, 2); + m = map->mapname2mapid(mapname); + if ( m == -1 ) + return false; + if ((script_lastdata(st) - 2) < 4) { - iMap->foreachinmap(atcommand_cleanfloor_sub, m, BL_ITEM); + map->foreachinmap(script->cleanfloor_sub, m, BL_ITEM); } else { x0 = script_getnum(st, 3); y0 = script_getnum(st, 4); x1 = script_getnum(st, 5); y1 = script_getnum(st, 6); if (x0 > 0 && y0 > 0 && x1 > 0 && y1 > 0) { - iMap->foreachinarea(atcommand_cleanfloor_sub, m, x0, y0, x1, y1, BL_ITEM); + map->foreachinarea(script->cleanfloor_sub, m, x0, y0, x1, y1, BL_ITEM); } else { ShowError("cleanarea: invalid coordinate defined!\n"); return false; } } - + return true; } /* Cast a skill on the attached player. * npcskill <skill id>, <skill lvl>, <stat point>, <NPC level>; * npcskill "<skill name>", <skill lvl>, <stat point>, <NPC level>; */ -BUILDIN(npcskill) -{ +BUILDIN(npcskill) { uint16 skill_id; unsigned short skill_level; unsigned int stat_point; unsigned int npc_level; struct npc_data *nd; struct map_session_data *sd; - - skill_id = script_isstring(st, 2) ? skill->name2id(script_getstr(st, 2)) : script_getnum(st, 2); - skill_level = script_getnum(st, 3); - stat_point = script_getnum(st, 4); - npc_level = script_getnum(st, 5); - sd = script_rid2sd(st); - nd = (struct npc_data *)iMap->id2bl(sd->npc_id); - + + skill_id = script_isstringtype(st, 2) ? skill->name2id(script_getstr(st, 2)) : script_getnum(st, 2); + skill_level = script_getnum(st, 3); + stat_point = script_getnum(st, 4); + npc_level = script_getnum(st, 5); + sd = script->rid2sd(st); + nd = (struct npc_data *)map->id2bl(sd->npc_id); + if (stat_point > battle_config.max_third_parameter) { ShowError("npcskill: stat point exceeded maximum of %d.\n",battle_config.max_third_parameter ); return false; @@ -16947,112 +17756,190 @@ BUILDIN(npcskill) ShowError("npcskill: level exceeded maximum of %d.\n", MAX_LEVEL); return false; } - if (sd == NULL || nd == NULL) { //ain't possible, but I don't trust people. + if (sd == NULL || nd == NULL) { return false; } - + nd->level = npc_level; nd->stat_point = stat_point; - + if (!nd->status.hp) { - status_calc_npc(nd, true); + status_calc_npc(nd, SCO_FIRST); } else { - status_calc_npc(nd, false); + status_calc_npc(nd, SCO_NONE); } - + if (skill->get_inf(skill_id)&INF_GROUND_SKILL) { - unit_skilluse_pos(&nd->bl, sd->bl.x, sd->bl.y, skill_id, skill_level); + unit->skilluse_pos(&nd->bl, sd->bl.x, sd->bl.y, skill_id, skill_level); } else { - unit_skilluse_id(&nd->bl, sd->bl.id, skill_id, skill_level); + unit->skilluse_id(&nd->bl, sd->bl.id, skill_id, skill_level); + } + + return true; +} + +/* Turns a player into a monster and grants SC attribute effect. [malufett/Hercules] + * montransform <monster name/id>, <duration>, <sc type>, <val1>, <val2>, <val3>, <val4>; */ +BUILDIN(montransform) { + int tick; + enum sc_type type; + struct block_list* bl; + char msg[CHAT_SIZE_MAX]; + int mob_id, val1, val2, val3, val4; + + if( (bl = map->id2bl(st->rid)) == NULL ) + return true; + + if( script_isstringtype(st, 2) ) { + mob_id = mob->db_searchname(script_getstr(st, 2)); + } else { + mob_id = mob->db_checkid(script_getnum(st, 2)); + } + + if( mob_id == 0 ) { + if( script_isstringtype(st, 2) ) + ShowWarning("buildin_montransform: Attempted to use non-existing monster '%s'.\n", script_getstr(st, 2)); + else + ShowWarning("buildin_montransform: Attempted to use non-existing monster of ID '%d'.\n", script_getnum(st, 2)); + return false; + } + + tick = script_getnum(st, 3); + type = (sc_type)script_getnum(st, 4); + val1 = val2 = val3 = val4 = 0; + + if( !(type > SC_NONE && type < SC_MAX) ) { + ShowWarning("buildin_montransform: Unsupported status change id %d\n", type); + return false; + } + + if (script_hasdata(st, 5)) + val1 = script_getnum(st, 5); + + if (script_hasdata(st, 6)) + val2 = script_getnum(st, 6); + + if (script_hasdata(st, 7)) + val3 = script_getnum(st, 7); + + if (script_hasdata(st, 8)) + val4 = script_getnum(st, 8); + + if( tick != 0 ) { + struct map_session_data *sd = map->id2sd(bl->id); + struct mob_db *monster = mob->db(mob_id); + + if( !sd ) + return true; + + if( battle_config.mon_trans_disable_in_gvg && map_flag_gvg2(sd->bl.m) ) { + clif->message(sd->fd, msg_txt(1488)); // Transforming into monster is not allowed in Guild Wars. + return true; + } + + if( sd->disguise != -1 ) { + clif->message(sd->fd, msg_txt(1486)); // Cannot transform into monster while in disguise. + return true; + } + + sprintf(msg, msg_txt(1485), monster->name); // Traaaansformation-!! %s form!! + clif->ShowScript(&sd->bl, msg); + status_change_end(bl, SC_MONSTER_TRANSFORM, INVALID_TIMER); // Clear previous + sc_start2(NULL, bl, SC_MONSTER_TRANSFORM, 100, mob_id, type, tick); + sc_start4(NULL, bl, type, 100, val1, val2, val3, val4, tick); } - return true; } + struct hQueue *script_hqueue_get(int idx) { - if( idx < 0 || idx >= script->hqs || script->hq[idx].items == -1 ) + if( idx < 0 || idx >= script->hqs || script->hq[idx].size == -1 ) return NULL; return &script->hq[idx]; } -/* set .@id,queue(); */ -/* creates queue, returns created queue id */ -BUILDIN(queue) { +int script_hqueue_create(void) { int idx = script->hqs; int i; - + for(i = 0; i < script->hqs; i++) { - if( script->hq[i].items == -1 ) { + if( script->hq[i].size == -1 ) { break; } } - + if( i == script->hqs ) { RECREATE(script->hq, struct hQueue, ++script->hqs); script->hq[ idx ].item = NULL; } else idx = i; - + script->hq[ idx ].id = idx; + script->hq[ idx ].size = 0; script->hq[ idx ].items = 0; script->hq[ idx ].onDeath[0] = '\0'; script->hq[ idx ].onLogOut[0] = '\0'; script->hq[ idx ].onMapChange[0] = '\0'; - - script_pushint(st,idx); + return idx; +} +/* set .@id,queue(); */ +/* creates queue, returns created queue id */ +BUILDIN(queue) { + script_pushint(st,script->queue_create()); return true; } /* set .@length,queuesize(.@queue_id); */ /* returns queue length */ BUILDIN(queuesize) { int idx = script_getnum(st, 2); - - if( idx < 0 || idx >= script->hqs || script->hq[idx].items == -1 ) { + + if( idx < 0 || idx >= script->hqs || script->hq[idx].size == -1 ) { ShowWarning("buildin_queuesize: unknown queue id %d\n",idx); script_pushint(st, 0); - } else - script_pushint(st, script->hq[ idx ].items ); - + } else { + script_pushint(st, script->hq[ idx ].items); + } + return true; } bool script_hqueue_add(int idx, int var) { - if( idx < 0 || idx >= script->hqs || script->hq[idx].items == -1 ) { + if( idx < 0 || idx >= script->hqs || script->hq[idx].size == -1 ) { ShowWarning("script_hqueue_add: unknown queue id %d\n",idx); return true; } else { struct map_session_data *sd; int i; - - for(i = 0; i < script->hq[idx].items; i++) { + + for(i = 0; i < script->hq[idx].size; i++) { if( script->hq[idx].item[i] == var ) { return true; } } - - if( i == script->hq[idx].items ) { - - for(i = 0; i < script->hq[idx].items; i++) { + + if( i == script->hq[idx].size ) { + + for(i = 0; i < script->hq[idx].size; i++) { if( script->hq[idx].item[i] == 0 ) { break; } } - - if( i == script->hq[idx].items ) - RECREATE(script->hq[idx].item, int, ++script->hq[idx].items); - + + if( i == script->hq[idx].size ) + RECREATE(script->hq[idx].item, int, ++script->hq[idx].size); + script->hq[idx].item[i] = var; - - if( var >= START_ACCOUNT_NUM && (sd = iMap->id2sd(var)) ) { + script->hq[idx].items++; + if( var >= START_ACCOUNT_NUM && (sd = map->id2sd(var)) ) { for(i = 0; i < sd->queues_count; i++) { if( sd->queues[i] == -1 ) { break; } } - + if( i == sd->queues_count ) RECREATE(sd->queues, int, ++sd->queues_count); - + sd->queues[i] = idx; } - + } } return false; @@ -17062,39 +17949,41 @@ bool script_hqueue_add(int idx, int var) { BUILDIN(queueadd) { int idx = script_getnum(st, 2); int var = script_getnum(st, 3); - + script_pushint(st,script->queue_add(idx,var)?1:0); - + return true; } bool script_hqueue_remove(int idx, int var) { - if( idx < 0 || idx >= script->hqs || script->hq[idx].items == -1 ) { + if( idx < 0 || idx >= script->hqs || script->hq[idx].size == -1 ) { ShowWarning("script_hqueue_remove: unknown queue id %d (used with var %d)\n",idx,var); return true; } else { int i; - - for(i = 0; i < script->hq[idx].items; i++) { + + for(i = 0; i < script->hq[idx].size; i++) { if( script->hq[idx].item[i] == var ) { - return true; + break; } } - - if( i != script->hq[idx].items ) { + + if( i != script->hq[idx].size ) { struct map_session_data *sd; - script->hq[idx].item[i] = 0; - - if( var >= START_ACCOUNT_NUM && (sd = iMap->id2sd(var)) ) { + + script->hq[idx].item[i] = -1; + script->hq[idx].items--; + + if( var >= START_ACCOUNT_NUM && (sd = map->id2sd(var)) ) { for(i = 0; i < sd->queues_count; i++) { - if( sd->queues[i] == var ) { + if( sd->queues[i] == idx ) { break; } } - + if( i != sd->queues_count ) sd->queues[i] = -1; } - + } } return false; @@ -17106,7 +17995,7 @@ BUILDIN(queueremove) { int var = script_getnum(st, 3); script_pushint(st, script->queue_remove(idx,var)?1:0); - + return true; } @@ -17117,8 +18006,8 @@ BUILDIN(queueremove) { BUILDIN(queueopt) { int idx = script_getnum(st, 2); int var = script_getnum(st, 3); - - if( idx < 0 || idx >= script->hqs || script->hq[idx].items == -1 ) { + + if( idx < 0 || idx >= script->hqs || script->hq[idx].size == -1 ) { ShowWarning("buildin_queueopt: unknown queue id %d\n",idx); script_pushint(st, 1); } else if( var <= HQO_NONE || var >= HQO_MAX ) { @@ -17150,32 +18039,34 @@ BUILDIN(queueopt) { break; } } - + return true; } bool script_hqueue_del(int idx) { - if( idx < 0 || idx >= script->hqs || script->hq[idx].items == -1 ) { + if( idx < 0 || idx >= script->hqs || script->hq[idx].size == -1 ) { ShowWarning("script_queue_del: unknown queue id %d\n",idx); return true; } else { struct map_session_data *sd; int i; - - for(i = 0; i < script->hq[idx].items; i++) { - if( script->hq[idx].item[i] >= START_ACCOUNT_NUM && (sd = iMap->id2sd(script->hq[idx].item[i])) ) { + + for(i = 0; i < script->hq[idx].size; i++) { + if( script->hq[idx].item[i] >= START_ACCOUNT_NUM && (sd = map->id2sd(script->hq[idx].item[i])) ) { int j; for(j = 0; j < sd->queues_count; j++) { if( sd->queues[j] == script->hq[idx].item[i] ) { break; } } - + if( j != sd->queues_count ) sd->queues[j] = -1; } + script->hq[idx].item[i] = 0; } - - script->hq[idx].items = -1; + + script->hq[idx].size = -1; + script->hq[idx].items = 0; } return false; } @@ -17183,12 +18074,39 @@ bool script_hqueue_del(int idx) { /* deletes queue of id .@queue_id, returns 1 if id not found, 0 otherwise */ BUILDIN(queuedel) { int idx = script_getnum(st, 2); - + script_pushint(st,script->queue_del(idx)?1:0); - + return true; } +void script_hqueue_clear(int idx) { + if( idx < 0 || idx >= script->hqs || script->hq[idx].size == -1 ) { + ShowWarning("script_hqueue_clear: unknown queue id %d\n",idx); + return; + } else { + struct map_session_data *sd; + int i, j; + + for(i = 0; i < script->hq[idx].size; i++) { + if( script->hq[idx].item[i] > 0 ) { + + if( script->hq[idx].item[i] >= START_ACCOUNT_NUM && (sd = map->id2sd(script->hq[idx].item[i])) ) { + for(j = 0; j < sd->queues_count; j++) { + if( sd->queues[j] == idx ) { + break; + } + } + if( j != sd->queues_count ) + sd->queues[j] = -1; + } + script->hq[idx].item[i] = 0; + } + } + script->hq[idx].items = 0; + } + return; +} /* set .@id, queueiterator(.@queue_id); */ /* creates a new queue iterator, returns its id */ BUILDIN(queueiterator) { @@ -17196,30 +18114,37 @@ BUILDIN(queueiterator) { struct hQueue *queue = NULL; int idx = script->hqis; int i; - - if( qid < 0 || qid >= script->hqs || script->hq[idx].items == -1 || !(queue = script->queue(qid)) ) { + + if( qid < 0 || qid >= script->hqs || script->hq[qid].size == -1 || !(queue = script->queue(qid)) ) { ShowWarning("queueiterator: invalid queue id %d\n",qid); return true; } - + + /* what if queue->size is 0? (iterating a empty queue?) */ + if( queue->size <= 0 ) { + ShowWarning("queueiterator: attempting to iterate on on empty queue id %d!\n",qid); + return true; + } + for(i = 0; i < script->hqis; i++) { if( script->hqi[i].items == -1 ) { break; } } - - if( i == script->hqis ) + + if( i == script->hqis ) { RECREATE(script->hqi, struct hQueueIterator, ++script->hqis); - else + script->hqi[ idx ].item = NULL; + } else idx = i; - - RECREATE(script->hqi[ idx ].item, int, queue->items); - - memcpy(&script->hqi[idx].item, &queue->item, sizeof(int)*queue->items); - - script->hqi[ idx ].items = queue->items; + + RECREATE(script->hqi[ idx ].item, int, queue->size); + + memcpy(script->hqi[idx].item, queue->item, sizeof(int)*queue->size); + + script->hqi[ idx ].items = queue->size; script->hqi[ idx ].pos = 0; - + script_pushint(st,idx); return true; } @@ -17227,11 +18152,11 @@ BUILDIN(queueiterator) { /* returns next/first member in the iterator, 0 if none */ BUILDIN(qiget) { int idx = script_getnum(st, 2); - + if( idx < 0 || idx >= script->hqis ) { ShowWarning("buildin_qiget: unknown queue iterator id %d\n",idx); script_pushint(st, 0); - } else if ( script->hqi[idx].pos == script->hqi[idx].items ) { + } else if ( script->hqi[idx].pos -1 == script->hqi[idx].items ) { script_pushint(st, 0); } else { struct hQueueIterator *it = &script->hqi[idx]; @@ -17244,22 +18169,22 @@ BUILDIN(qiget) { /* returns 1:0 if there is a next member in the iterator */ BUILDIN(qicheck) { int idx = script_getnum(st, 2); - + if( idx < 0 || idx >= script->hqis ) { ShowWarning("buildin_qicheck: unknown queue iterator id %d\n",idx); script_pushint(st, 0); - } else if ( script->hqi[idx].pos == script->hqi[idx].items ) { + } else if ( script->hqi[idx].pos -1 == script->hqi[idx].items ) { script_pushint(st, 0); } else { script_pushint(st, 1); } - + return true; } /* Queue Iterator Check */ BUILDIN(qiclear) { int idx = script_getnum(st, 2); - + if( idx < 0 || idx >= script->hqis ) { ShowWarning("buildin_qiclear: unknown queue iterator id %d\n",idx); script_pushint(st, 1); @@ -17267,57 +18192,589 @@ BUILDIN(qiclear) { script->hqi[idx].items = -1; script_pushint(st, 0); } - + + return true; +} +/** + * packageitem({<optional container_item_id>}) + * when no item id is provided it tries to assume it comes from the current item id being processed (if any) + **/ +BUILDIN(packageitem) { + struct item_data *data = NULL; + struct map_session_data *sd = NULL; + int nameid; + + if( script_hasdata(st, 2) ) + nameid = script_getnum(st, 2); + else if ( script->current_item_id ) + nameid = script->current_item_id; + else { + ShowWarning("buildin_packageitem: no item id provided and no item attached\n"); + script_pushint(st, 1); + return true; + } + + if( !(data = itemdb->exists(nameid)) ) { + ShowWarning("buildin_packageitem: unknown item id %d\n",nameid); + script_pushint(st, 1); + } else if ( !data->package ) { + ShowWarning("buildin_packageitem: item '%s' (%d) isn't a package!\n",data->name,nameid); + script_pushint(st, 1); + } else if( !( sd = script->rid2sd(st) ) ) { + ShowWarning("buildin_packageitem: no player attached!! (item %s (%d))\n",data->name,nameid); + script_pushint(st, 1); + } else { + itemdb->package_item(sd,data->package); + script_pushint(st, 0); + } + + return true; +} +/* New Battlegrounds Stuff */ +/* bg_team_create(map_name,respawn_x,respawn_y) */ +/* returns created team id or -1 when fails */ +BUILDIN(bg_create_team) { + const char *map_name, *ev = "", *dev = "";//ev and dev will be dropped. + int x, y, map_index = 0, bg_id; + + map_name = script_getstr(st,2); + if( strcmp(map_name,"-") != 0 ) { + map_index = script->mapindexname2id(st,map_name); + if( map_index == 0 ) { // Invalid Map + script_pushint(st,0); + return true; + } + } + + x = script_getnum(st,3); + y = script_getnum(st,4); + + if( (bg_id = bg->create(map_index, x, y, ev, dev)) == 0 ) { // Creation failed + script_pushint(st,-1); + } else + script_pushint(st,bg_id); + + return true; + +} +/* bg_join_team(team_id{,optional account id}) */ +/* when account id is not present it tries to autodetect from the attached player (if any) */ +/* returns 0 when successful, 1 otherwise */ +BUILDIN(bg_join_team) { + struct map_session_data *sd; + int team_id = script_getnum(st, 2); + + if( script_hasdata(st, 3) ) + sd = map->id2sd(script_getnum(st, 3)); + else + sd = script->rid2sd(st); + + if( !sd ) + script_pushint(st, 1); + else + script_pushint(st,bg->team_join(team_id, sd)?0:1); + + return true; +} +/*==============[Mhalicot]================== + * countbound {<type>}; + * Creates an array of bounded item IDs + * Returns amount of items found + * Type: + * 1 - Account Bound + * 2 - Guild Bound + * 3 - Party Bound + * 4 - Character Bound + *------------------------------------------*/ +BUILDIN(countbound) +{ + int i, type, j=0, k=0; + TBL_PC *sd; + + if( (sd = script->rid2sd(st)) == NULL ) + return false; + + type = script_hasdata(st,2)?script_getnum(st,2):0; + + for(i=0;i<MAX_INVENTORY;i++) { + if(sd->status.inventory[i].nameid > 0 && ( + (!type && sd->status.inventory[i].bound > 0) || + (type && sd->status.inventory[i].bound == type) + )) { + pc->setreg(sd,reference_uid(script->add_str("@bound_items"), k),sd->status.inventory[i].nameid); + k++; + j += sd->status.inventory[i].amount; + } + } + + script_pushint(st,j); + return 0; +} + +/* bg_match_over( arena_name {, optional canceled } ) */ +/* returns 0 when successful, 1 otherwise */ +BUILDIN(bg_match_over) { + bool canceled = script_hasdata(st,3) ? true : false; + struct bg_arena *arena = bg->name2arena((char*)script_getstr(st, 2)); + + if( arena ) { + bg->match_over(arena,canceled); + script_pushint(st, 0); + } else + script_pushint(st, 1); + + return true; +} + +BUILDIN(instance_mapname) { + const char *map_name; + int m; + short instance_id = -1; + + map_name = script_getstr(st,2); + + if( script_hasdata(st,3) ) + instance_id = script_getnum(st,3); + else + instance_id = st->instance_id; + + // Check that instance mapname is a valid map + if( instance_id == -1 || (m = instance->mapname2imap(map_name,instance_id)) == -1 ) + script_pushconststr(st, ""); + else + script_pushconststr(st, map->list[m].name); + + return true; +} +/* modify an instances' reload-spawn point */ +/* instance_set_respawn <map_name>,<x>,<y>{,<instance_id>} */ +/* returns 1 when successful, 0 otherwise. */ +BUILDIN(instance_set_respawn) { + const char *map_name; + short instance_id = -1; + short mid; + short x,y; + + map_name = script_getstr(st,2); + x = script_getnum(st, 3); + y = script_getnum(st, 4); + + if( script_hasdata(st, 5) ) + instance_id = script_getnum(st, 5); + else + instance_id = st->instance_id; + + if( instance_id == -1 || !instance->valid(instance_id) ) + script_pushint(st, 0); + else if( (mid = map->mapname2mapid(map_name)) == -1 ) { + ShowError("buildin_instance_set_respawn: unknown map '%s'\n",map_name); + script_pushint(st, 0); + } else { + int i; + + for(i = 0; i < instance->list[instance_id].num_map; i++) { + if( map->list[instance->list[instance_id].map[i]].m == mid ) { + instance->list[instance_id].respawn.map = map_id2index(mid); + instance->list[instance_id].respawn.x = x; + instance->list[instance_id].respawn.y = y; + break; + } + } + + if( i != instance->list[instance_id].num_map ) + script_pushint(st, 1); + else { + ShowError("buildin_instance_set_respawn: map '%s' not part of instance '%s'\n",map_name,instance->list[instance_id].name); + script_pushint(st, 0); + } + } + + + return true; +} +/** + * @call openshop({NPC Name}); + * + * @return 1 on success, 0 otherwise. + **/ +BUILDIN(openshop) { + struct npc_data *nd; + struct map_session_data *sd; + const char *name = NULL; + + if( script_hasdata(st, 2) ) { + name = script_getstr(st, 2); + if( !(nd = npc->name2id(name)) || nd->subtype != SCRIPT ) { + ShowWarning("buildin_openshop(\"%s\"): trying to run without a proper NPC!\n",name); + return false; + } + } else if( !(nd = map->id2nd(st->oid)) ) { + ShowWarning("buildin_openshop: trying to run without a proper NPC!\n"); + return false; + } + if( !( sd = script->rid2sd(st) ) ) { + ShowWarning("buildin_openshop: trying to run without a player attached!\n"); + return false; + } else if ( !nd->u.scr.shop || !nd->u.scr.shop->items ) { + ShowWarning("buildin_openshop: trying to open without any items!\n"); + return false; + } + + if( !npc->trader_open(sd,nd) ) + script_pushint(st, 0); + else + script_pushint(st, 1); + + return true; +} +/** + * @call sellitem <Item_ID>,{,price{,qty}}; + * + * adds <Item_ID> (or modifies if present) to shop + * if price not provided (or -1) uses the item's value_sell + **/ +BUILDIN(sellitem) { + struct npc_data *nd; + struct item_data *it; + int i = 0, id = script_getnum(st,2); + int value = 0; + int qty = 0; + + if( !(nd = map->id2nd(st->oid)) ) { + ShowWarning("buildin_sellitem: trying to run without a proper NPC!\n"); + return false; + } else if ( !(it = itemdb->exists(id)) ) { + ShowWarning("buildin_sellitem: unknown item id '%d'!\n",id); + return false; + } + + value = script_hasdata(st,3) ? script_getnum(st, 3) : it->value_buy; + if( value == -1 ) + value = it->value_buy; + + if( !nd->u.scr.shop ) + npc->trader_update(nd->src_id?nd->src_id:nd->bl.id); + else {/* no need to run this if its empty */ + for( i = 0; i < nd->u.scr.shop->items; i++ ) { + if( nd->u.scr.shop->item[i].nameid == id ) + break; + } + } + + if( nd->u.scr.shop->type == NST_MARKET ) { + if( !script_hasdata(st,4) || ( qty = script_getnum(st, 4) ) <= 0 ) { + ShowError("buildin_sellitem: invalid 'qty' for market-type shop!\n"); + return false; + } + } + + if( ( nd->u.scr.shop->type == NST_ZENY || nd->u.scr.shop->type == NST_MARKET ) && value*0.75 < it->value_sell*1.24 ) { + ShowWarning("buildin_sellitem: Item %s [%d] discounted buying price (%d->%d) is less than overcharged selling price (%d->%d) in NPC %s (%s)\n", + it->name, id, value, (int)(value*0.75), it->value_sell, (int)(it->value_sell*1.24), nd->exname, nd->path); + } + + if( i != nd->u.scr.shop->items ) { + nd->u.scr.shop->item[i].value = value; + nd->u.scr.shop->item[i].qty = qty; + if( nd->u.scr.shop->type == NST_MARKET ) /* has been manually updated, make it reflect on sql */ + npc->market_tosql(nd,i); + } else { + for( i = 0; i < nd->u.scr.shop->items; i++ ) { + if( nd->u.scr.shop->item[i].nameid == 0 ) + break; + } + + if( i == nd->u.scr.shop->items ) { + if( nd->u.scr.shop->items == USHRT_MAX ) { + ShowWarning("buildin_sellitem: Can't add %s (%s/%s), shop list is full!\n", it->name, nd->exname, nd->path); + return false; + } + i = nd->u.scr.shop->items; + RECREATE(nd->u.scr.shop->item, struct npc_item_list, ++nd->u.scr.shop->items); + } + + nd->u.scr.shop->item[i].nameid = it->nameid; + nd->u.scr.shop->item[i].value = value; + nd->u.scr.shop->item[i].qty = qty; + } + + return true; +} +/** + * @call stopselling <Item_ID>; + * + * removes <Item_ID> from the current npc shop + * + * @return 1 on success, 0 otherwise + **/ +BUILDIN(stopselling) { + struct npc_data *nd; + int i, id = script_getnum(st,2); + + if( !(nd = map->id2nd(st->oid)) || !nd->u.scr.shop ) { + ShowWarning("buildin_stopselling: trying to run without a proper NPC!\n"); + return false; + } + + for( i = 0; i < nd->u.scr.shop->items; i++ ) { + if( nd->u.scr.shop->item[i].nameid == id ) + break; + } + + if( i != nd->u.scr.shop->items ) { + int cursor; + + if( nd->u.scr.shop->type == NST_MARKET ) + npc->market_delfromsql(nd,i); + + nd->u.scr.shop->item[i].nameid = 0; + nd->u.scr.shop->item[i].value = 0; + nd->u.scr.shop->item[i].qty = 0; + + for( i = 0, cursor = 0; i < nd->u.scr.shop->items; i++ ) { + if( nd->u.scr.shop->item[i].nameid == 0 ) + continue; + + if( cursor != i ) { + nd->u.scr.shop->item[cursor].nameid = nd->u.scr.shop->item[i].nameid; + nd->u.scr.shop->item[cursor].value = nd->u.scr.shop->item[i].value; + nd->u.scr.shop->item[cursor].qty = nd->u.scr.shop->item[i].qty; + } + + cursor++; + } + + script_pushint(st, 1); + } else + script_pushint(st, 0); + + return true; +} +/** + * @call setcurrency <Val1>{,<Val2>}; + * + * updates currently-attached player shop currency + **/ +/* setcurrency(<Val1>,{<Val2>}) */ +BUILDIN(setcurrency) { + int val1 = script_getnum(st,2), + val2 = script_hasdata(st, 3) ? script_getnum(st,3) : 0; + struct npc_data *nd; + + if( !(nd = map->id2nd(st->oid)) ) { + ShowWarning("buildin_setcurrency: trying to run without a proper NPC!\n"); + return false; + } + + npc->trader_funds[0] = val1; + npc->trader_funds[1] = val2; + + return true; +} +/** + * @call tradertype(<type>); + * + * defaults to 0, so no need to call when you're doing zeny + * check enum npc_shop_types for list + * cleans shop list on use + **/ +BUILDIN(tradertype) { + int type = script_getnum(st, 2); + struct npc_data *nd; + + if( !(nd = map->id2nd(st->oid)) ) { + ShowWarning("buildin_tradertype: trying to run without a proper NPC!\n"); + return false; + } else if ( type < 0 || type > NST_MAX ) { + ShowWarning("buildin_tradertype: invalid type param %d!\n",type); + return false; + } + + if( !nd->u.scr.shop ) + npc->trader_update(nd->src_id?nd->src_id:nd->bl.id); + else {/* clear list */ + int i; + for( i = 0; i < nd->u.scr.shop->items; i++ ) { + nd->u.scr.shop->item[i].nameid = 0; + nd->u.scr.shop->item[i].value = 0; + nd->u.scr.shop->item[i].qty = 0; + } + npc->market_delfromsql(nd,USHRT_MAX); + } + +#if PACKETVER < 20131223 + if( type == NST_MARKET ) { + ShowWarning("buildin_tradertype: NST_MARKET is only available with PACKETVER 20131223 or newer!\n"); + script->reportsrc(st); + } +#endif + + nd->u.scr.shop->type = type; + + return true; +} +/** + * @call purchaseok(); + * + * signs the transaction can proceed + **/ +BUILDIN(purchaseok) { + struct npc_data *nd; + + if( !(nd = map->id2nd(st->oid)) || !nd->u.scr.shop ) { + ShowWarning("buildin_purchaseok: trying to run without a proper NPC!\n"); + return false; + } + + npc->trader_ok = true; + + return true; +} +/** + * @call shopcount(<Item_ID>); + * + * @return number of available items in the script's attached shop + **/ +BUILDIN(shopcount) { + struct npc_data *nd; + int id = script_getnum(st, 2); + unsigned short i; + + if( !(nd = map->id2nd(st->oid)) ) { + ShowWarning("buildin_shopcount(%d): trying to run without a proper NPC!\n",id); + return false; + } else if ( !nd->u.scr.shop || !nd->u.scr.shop->items ) { + ShowWarning("buildin_shopcount(%d): trying to use without any items!\n",id); + return false; + } else if ( nd->u.scr.shop->type != NST_MARKET ) { + ShowWarning("buildin_shopcount(%d): trying to use on a non-NST_MARKET shop!\n",id); + return false; + } + + /* lookup */ + for(i = 0; i < nd->u.scr.shop->items; i++) { + if( nd->u.scr.shop->item[i].nameid == id ) { + script_pushint(st, nd->u.scr.shop->item[i].qty); + break; + } + } + + /* didn't find it */ + if( i == nd->u.scr.shop->items ) + script_pushint(st, 0); + return true; } // declarations that were supposed to be exported from npc_chat.c #ifdef PCRE_SUPPORT - BUILDIN(defpattern); - BUILDIN(activatepset); - BUILDIN(deactivatepset); - BUILDIN(deletepset); +BUILDIN(defpattern); +BUILDIN(activatepset); +BUILDIN(deactivatepset); +BUILDIN(deletepset); + +BUILDIN(pcre_match) { + const char *input = script_getstr(st, 2); + const char *regex = script_getstr(st, 3); + + script->op_2str(st, C_RE_EQ, input, regex); + return true; +} #endif -bool script_hp_add(char *name, char *args, bool (*func)(struct script_state *st)) { - int n = add_str(name), i = 0; - - if( script->str_data[n].type == C_FUNC ) { - script->str_data[n].func = func; - i = script->str_data[n].val; - if( args ) { - int slen = strlen(args); - if( script->buildin[i] ) { - aFree(script->buildin[i]); - } - CREATE(script->buildin[i], char, slen + 1); - safestrncpy(script->buildin[i], args, slen + 1); - } else { - if( script->buildin[i] ) - aFree(script->buildin[i]); - script->buildin[i] = NULL; +/** + * Adds a built-in script function. + * + * @param buildin Script function data + * @param force Whether to override an existing function with the same name + * (i.e. a plugin overriding a built-in function) + * @return Whether the function was successfully added. + */ +bool script_add_builtin(const struct script_function *buildin, bool override) { + int n = 0, offset = 0; + size_t slen; + if( !buildin ) { + return false; + } + if( buildin->arg ) { + // arg must follow the pattern: (v|s|i|r|l)*\?*\*? + // 'v' - value (either string or int or reference) + // 's' - string + // 'i' - int + // 'r' - reference (of a variable) + // 'l' - label + // '?' - one optional parameter + // '*' - unknown number of optional parameters + char *p = buildin->arg; + while( *p == 'v' || *p == 's' || *p == 'i' || *p == 'r' || *p == 'l' ) ++p; + while( *p == '?' ) ++p; + if( *p == '*' ) ++p; + if( *p != 0 ) { + ShowWarning("add_builtin: ignoring function \"%s\" with invalid arg \"%s\".\n", buildin->name, buildin->arg); + return false; } + } + if( !buildin->name || *script->skip_word(buildin->name) != 0 ) { + ShowWarning("add_builtin: ignoring function with invalid name \"%s\" (must be a word).\n", buildin->name); + return false; + } + if ( !buildin->func ) { + ShowWarning("add_builtin: ignoring function \"%s\" with invalid source function.\n", buildin->name); + return false; + } + slen = buildin->arg ? strlen(buildin->arg) : 0; + n = script->add_str(buildin->name); + if( !override && script->str_data[n].func && script->str_data[n].func != buildin->func ) { + return false; /* something replaced it, skip. */ + } + + if( override && script->str_data[n].type == C_FUNC ) { + // Overriding + offset = script->str_data[n].val; + if( script->buildin[offset] ) + aFree(script->buildin[offset]); + script->buildin[offset] = NULL; } else { - i = script->buildin_count; + // Adding new function + if( strcmp(buildin->name, "setr") == 0 ) script->buildin_set_ref = n; + else if( strcmp(buildin->name, "callsub") == 0 ) script->buildin_callsub_ref = n; + else if( strcmp(buildin->name, "callfunc") == 0 ) script->buildin_callfunc_ref = n; + else if( strcmp(buildin->name, "getelementofarray") == 0 ) script->buildin_getelementofarray_ref = n; + + offset = script->buildin_count; + script->str_data[n].type = C_FUNC; - script->str_data[n].val = i; - script->str_data[n].func = func; - + script->str_data[n].val = offset; + + // Note: This is a no-op if script->buildin is already large enough + // (it'll only have effect when a plugin adds a new command) RECREATE(script->buildin, char *, ++script->buildin_count); - - /* we only store the arguments, its the only thing used out of this */ - if( args != NULL ) { - int slen = strlen(args); - CREATE(script->buildin[i], char, slen + 1); - safestrncpy(script->buildin[i], args, slen + 1); - } else - script->buildin[i] = NULL; } - + + script->str_data[n].func = buildin->func; + + /* we only store the arguments, its the only thing used out of this */ + if( slen ) { + CREATE(script->buildin[offset], char, slen + 1); + safestrncpy(script->buildin[offset], buildin->arg, slen + 1); + } else { + script->buildin[offset] = NULL; + } + return true; } +bool script_hp_add(char *name, char *args, bool (*func)(struct script_state *st)) { + struct script_function buildin; + buildin.name = name; + buildin.arg = args; + buildin.func = func; + return script->add_builtin(&buildin, true); +} + +#define BUILDIN_DEF(x,args) { buildin_ ## x , #x , args } +#define BUILDIN_DEF2(x,x2,args) { buildin_ ## x , x2 , args } void script_parse_builtin(void) { struct script_function BUILDIN[] = { // NPC interaction @@ -17344,7 +18801,8 @@ void script_parse_builtin(void) { BUILDIN_DEF(warpguild,"siii"), // [Fredzilla] BUILDIN_DEF(setlook,"ii"), BUILDIN_DEF(changelook,"ii"), // Simulates but don't Store it - BUILDIN_DEF(set,"rv"), + BUILDIN_DEF2(setr,"set","rv"), + BUILDIN_DEF(setr,"rv?"), // Not meant to be used directly, required for var++/var-- BUILDIN_DEF(setarray,"rv*"), BUILDIN_DEF(cleararray,"rvi"), BUILDIN_DEF(copyarray,"rri"), @@ -17393,9 +18851,9 @@ void script_parse_builtin(void) { BUILDIN_DEF(getequiprefinerycnt,"i"), BUILDIN_DEF(getequipweaponlv,"i"), BUILDIN_DEF(getequippercentrefinery,"i"), - BUILDIN_DEF(successrefitem,"i"), + BUILDIN_DEF(successrefitem,"i?"), BUILDIN_DEF(failedrefitem,"i"), - BUILDIN_DEF(downrefitem,"i"), + BUILDIN_DEF(downrefitem,"i?"), BUILDIN_DEF(statusup,"i"), BUILDIN_DEF(statusup2,"ii"), BUILDIN_DEF(bonus,"iv"), @@ -17474,7 +18932,7 @@ void script_parse_builtin(void) { BUILDIN_DEF(sc_end,"i?"), BUILDIN_DEF(getstatus, "i?"), BUILDIN_DEF(getscrate,"ii?"), - BUILDIN_DEF(debugmes,"s"), + BUILDIN_DEF(debugmes,"v"), BUILDIN_DEF2(catchpet,"pet","i"), BUILDIN_DEF2(birthpet,"bpet",""), BUILDIN_DEF(resetlvl,"i"), @@ -17488,8 +18946,8 @@ void script_parse_builtin(void) { BUILDIN_DEF2(waitingroomkickall,"kickwaitingroomall","?"), BUILDIN_DEF(enablewaitingroomevent,"?"), BUILDIN_DEF(disablewaitingroomevent,"?"), - BUILDIN_DEF2(enablewaitingroomevent,"enablearena",""), // Added by RoVeRT - BUILDIN_DEF2(disablewaitingroomevent,"disablearena",""), // Added by RoVeRT + BUILDIN_DEF2(enablewaitingroomevent,"enablearena",""), // Added by RoVeRT + BUILDIN_DEF2(disablewaitingroomevent,"disablearena",""), // Added by RoVeRT BUILDIN_DEF(getwaitingroomstate,"i?"), BUILDIN_DEF(warpwaitingpc,"sii?"), BUILDIN_DEF(attachrid,"i"), @@ -17498,17 +18956,17 @@ void script_parse_builtin(void) { BUILDIN_DEF(setmapflagnosave,"ssii"), BUILDIN_DEF(getmapflag,"si"), BUILDIN_DEF(setmapflag,"si?"), - BUILDIN_DEF(removemapflag,"si?"), + BUILDIN_DEF(removemapflag,"si"), BUILDIN_DEF(pvpon,"s"), BUILDIN_DEF(pvpoff,"s"), BUILDIN_DEF(gvgon,"s"), BUILDIN_DEF(gvgoff,"s"), BUILDIN_DEF(emotion,"i??"), BUILDIN_DEF(maprespawnguildid,"sii"), - BUILDIN_DEF(agitstart,""), // <Agit> + BUILDIN_DEF(agitstart,""), // <Agit> BUILDIN_DEF(agitend,""), BUILDIN_DEF(agitcheck,""), // <Agitcheck> - BUILDIN_DEF(flagemblem,"i"), // Flag Emblem + BUILDIN_DEF(flagemblem,"i"), // Flag Emblem BUILDIN_DEF(getcastlename,"s"), BUILDIN_DEF(getcastledata,"si"), BUILDIN_DEF(setcastledata,"sii"), @@ -17534,13 +18992,13 @@ void script_parse_builtin(void) { BUILDIN_DEF(clearitem,""), BUILDIN_DEF(classchange,"ii"), BUILDIN_DEF(misceffect,"i"), - BUILDIN_DEF(playBGM,"s"), - BUILDIN_DEF(playBGMall,"s?????"), + BUILDIN_DEF(playbgm,"s"), + BUILDIN_DEF(playbgmall,"s?????"), BUILDIN_DEF(soundeffect,"si"), - BUILDIN_DEF(soundeffectall,"si?????"), // SoundEffectAll [Codemaster] - BUILDIN_DEF(strmobinfo,"ii"), // display mob data [Valaris] - BUILDIN_DEF(guardian,"siisi??"), // summon guardians - BUILDIN_DEF(guardianinfo,"sii"), // display guardian data [Valaris] + BUILDIN_DEF(soundeffectall,"si?????"), // SoundEffectAll [Codemaster] + BUILDIN_DEF(strmobinfo,"ii"), // display mob data [Valaris] + BUILDIN_DEF(guardian,"siisi??"), // summon guardians + BUILDIN_DEF(guardianinfo,"sii"), // display guardian data [Valaris] BUILDIN_DEF(petskillbonus,"iiii"), // [Valaris] BUILDIN_DEF(petrecovery,"ii"), // [Valaris] BUILDIN_DEF(petloot,"i"), // [Valaris] @@ -17553,7 +19011,7 @@ void script_parse_builtin(void) { BUILDIN_DEF(specialeffect,"i??"), // npc skill effect [Valaris] BUILDIN_DEF(specialeffect2,"i??"), // skill effect on players[Valaris] BUILDIN_DEF(nude,""), // nude command [Valaris] - BUILDIN_DEF(mapwarp,"ssii??"), // Added by RoVeRT + BUILDIN_DEF(mapwarp,"ssii??"), // Added by RoVeRT BUILDIN_DEF(atcommand,"s"), // [MouseJstr] BUILDIN_DEF2(atcommand,"charcommand","s"), // [MouseJstr] BUILDIN_DEF(movenpc,"sii?"), // [MouseJstr] @@ -17565,7 +19023,7 @@ void script_parse_builtin(void) { BUILDIN_DEF(npcspeed,"i"), // [Valaris] BUILDIN_DEF(npcwalkto,"ii"), // [Valaris] BUILDIN_DEF(npcstop,""), // [Valaris] - BUILDIN_DEF(getmapxy,"rrri?"), //by Lorky [Lupus] + BUILDIN_DEF(getmapxy,"rrri?"), //by Lorky [Lupus] BUILDIN_DEF(checkoption1,"i"), BUILDIN_DEF(checkoption2,"i"), BUILDIN_DEF(guildgetexp,"i"), @@ -17585,6 +19043,7 @@ void script_parse_builtin(void) { BUILDIN_DEF(activatepset,"i"), // Activate a pattern set [MouseJstr] BUILDIN_DEF(deactivatepset,"i"), // Deactive a pattern set [MouseJstr] BUILDIN_DEF(deletepset,"i"), // Delete a pattern set [MouseJstr] + BUILDIN_DEF(pcre_match,"ss"), #endif BUILDIN_DEF(dispbottom,"s"), //added from jA [Lupus] BUILDIN_DEF(getusersname,""), @@ -17643,11 +19102,14 @@ void script_parse_builtin(void) { BUILDIN_DEF(disguise,"i"), //disguise player. Lupus BUILDIN_DEF(undisguise,""), //undisguise player. Lupus BUILDIN_DEF(getmonsterinfo,"ii"), //Lupus + BUILDIN_DEF(addmonsterdrop,"vii"), + BUILDIN_DEF(delmonsterdrop,"vi"), BUILDIN_DEF(axtoi,"s"), BUILDIN_DEF(query_sql,"s*"), BUILDIN_DEF(query_logsql,"s*"), BUILDIN_DEF(escape_sql,"v"), BUILDIN_DEF(atoi,"s"), + BUILDIN_DEF(strtol,"si"), // [zBuffer] List of player cont commands ---> BUILDIN_DEF(rid2name,"i"), BUILDIN_DEF(pcfollow,"ii"), @@ -17670,12 +19132,13 @@ void script_parse_builtin(void) { BUILDIN_DEF(awake,"s"), BUILDIN_DEF(getvariableofnpc,"rs"), BUILDIN_DEF(warpportal,"iisii"), - BUILDIN_DEF2(homunculus_evolution,"homevolution",""), //[orn] + BUILDIN_DEF2(homunculus_evolution,"homevolution",""), //[orn] BUILDIN_DEF2(homunculus_mutate,"hommutate","?"), - BUILDIN_DEF2(homunculus_shuffle,"homshuffle",""), //[Zephyrus] - BUILDIN_DEF(checkhomcall,""), - BUILDIN_DEF(eaclass,"?"), //[Skotlex] - BUILDIN_DEF(roclass,"i?"), //[Skotlex] + BUILDIN_DEF2(homunculus_morphembryo,"morphembryo",""), + BUILDIN_DEF2(homunculus_checkcall,"checkhomcall",""), + BUILDIN_DEF2(homunculus_shuffle,"homshuffle",""), //[Zephyrus] + BUILDIN_DEF(eaclass,"?"), //[Skotlex] + BUILDIN_DEF(roclass,"i?"), //[Skotlex] BUILDIN_DEF(checkvending,"?"), BUILDIN_DEF(checkchatting,"?"), BUILDIN_DEF(checkidle,"?"), @@ -17718,7 +19181,7 @@ void script_parse_builtin(void) { BUILDIN_DEF(bg_get_data,"ii"), BUILDIN_DEF(bg_getareausers,"isiiii"), BUILDIN_DEF(bg_updatescore,"sii"), - + // Instancing BUILDIN_DEF(instance_create,"si?"), BUILDIN_DEF(instance_destroy,"?"), @@ -17733,6 +19196,10 @@ void script_parse_builtin(void) { BUILDIN_DEF(has_instance,"s?"), BUILDIN_DEF(instance_warpall,"sii?"), BUILDIN_DEF(instance_check_party,"i???"), + BUILDIN_DEF(instance_mapname,"s?"), + BUILDIN_DEF(instance_set_respawn,"sii?"), + BUILDIN_DEF2(has_instance,"has_instance2","s"), + /** * 3rd-related **/ @@ -17748,13 +19215,13 @@ void script_parse_builtin(void) { BUILDIN_DEF(getargcount,""), BUILDIN_DEF(getcharip,"?"), BUILDIN_DEF(is_function,"s"), - BUILDIN_DEF(get_revision,""), BUILDIN_DEF(freeloop,"i"), BUILDIN_DEF(getrandgroupitem,"ii"), BUILDIN_DEF(cleanmap,"s"), BUILDIN_DEF2(cleanmap,"cleanarea","siiii"), BUILDIN_DEF(npcskill,"viii"), BUILDIN_DEF(itemeffect,"v"), + BUILDIN_DEF2(itemeffect,"consumeitem","v"), /* alias of itemeffect */ BUILDIN_DEF(delequip,"i"), /** * @commands (script based) @@ -17762,15 +19229,23 @@ void script_parse_builtin(void) { BUILDIN_DEF(bindatcmd, "ss???"), BUILDIN_DEF(unbindatcmd, "s"), BUILDIN_DEF(useatcmd, "s"), - + + /** + * Item bound [Xantara] [Akinari] [Mhalicot/Hercules] + **/ + BUILDIN_DEF2(getitem,"getitembound","vii?"), + BUILDIN_DEF2(getitem2,"getitembound2","viiiiiiiii?"), + BUILDIN_DEF(countbound, "?"), + //Quest Log System [Inkfish] + BUILDIN_DEF(questinfo, "ii??"), BUILDIN_DEF(setquest, "i"), BUILDIN_DEF(erasequest, "i"), BUILDIN_DEF(completequest, "i"), BUILDIN_DEF(checkquest, "i?"), BUILDIN_DEF(changequest, "ii"), - BUILDIN_DEF(showevent, "ii"), - + BUILDIN_DEF(showevent, "i?"), + /** * hQueue [Ind/Hercules] **/ @@ -17784,87 +19259,231 @@ void script_parse_builtin(void) { BUILDIN_DEF(qicheck,"i"), BUILDIN_DEF(qiget,"i"), BUILDIN_DEF(qiclear,"i"), + + BUILDIN_DEF(packageitem,"?"), + + BUILDIN_DEF(sit, "?"), + BUILDIN_DEF(stand, "?"), + BUILDIN_DEF(issit, "?"), + + BUILDIN_DEF(montransform, "vii????"), // Monster Transform [malufett/Hercules] + + /* New BG Commands [Hercules] */ + BUILDIN_DEF(bg_create_team,"sii"), + BUILDIN_DEF(bg_join_team,"i?"), + BUILDIN_DEF(bg_match_over,"s?"), + + /* New Shop Support */ + BUILDIN_DEF(openshop,"?"), + BUILDIN_DEF(sellitem,"i??"), + BUILDIN_DEF(stopselling,"i"), + BUILDIN_DEF(setcurrency,"i?"), + BUILDIN_DEF(tradertype,"i"), + BUILDIN_DEF(purchaseok,""), + BUILDIN_DEF(shopcount, "i"), }; - int i,n, len = ARRAYLENGTH(BUILDIN), start = script->buildin_count; - char* p; - RECREATE(script->buildin, char *, start + len); + int i, len = ARRAYLENGTH(BUILDIN); + RECREATE(script->buildin, char *, script->buildin_count + len); // Pre-alloc to speed up + memset(script->buildin + script->buildin_count, '\0', sizeof(char *) * len); for( i = 0; i < len; i++ ) { - // arg must follow the pattern: (v|s|i|r|l)*\?*\*? - // 'v' - value (either string or int or reference) - // 's' - string - // 'i' - int - // 'r' - reference (of a variable) - // 'l' - label - // '?' - one optional parameter - // '*' - unknown number of optional parameters - p = BUILDIN[i].arg; - while( *p == 'v' || *p == 's' || *p == 'i' || *p == 'r' || *p == 'l' ) ++p; - while( *p == '?' ) ++p; - if( *p == '*' ) ++p; - if( *p != 0 ){ - ShowWarning("script_parse_builtin: ignoring function \"%s\" with invalid arg \"%s\".\n", BUILDIN[i].name, BUILDIN[i].arg); - } else if( *skip_word(BUILDIN[i].name) != 0 ){ - ShowWarning("script_parse_builtin: ignoring function with invalid name \"%s\" (must be a word).\n", BUILDIN[i].name); - } else { - int slen = strlen(BUILDIN[i].arg), offset = start + i; - n = add_str(BUILDIN[i].name); - - if (!strcmp(BUILDIN[i].name, "set")) buildin_set_ref = n; - else if (!strcmp(BUILDIN[i].name, "callsub")) buildin_callsub_ref = n; - else if (!strcmp(BUILDIN[i].name, "callfunc")) buildin_callfunc_ref = n; - else if (!strcmp(BUILDIN[i].name, "getelementofarray") ) buildin_getelementofarray_ref = n; - - if( script->str_data[n].func && script->str_data[n].func != BUILDIN[i].func ) - continue;/* something replaced it, skip. */ - - script->str_data[n].type = C_FUNC; - script->str_data[n].val = offset; - script->str_data[n].func = BUILDIN[i].func; - - /* we only store the arguments, its the only thing used out of this */ - if( slen ) { - CREATE(script->buildin[offset], char, slen + 1); - safestrncpy(script->buildin[offset], BUILDIN[i].arg, slen + 1); - } else - script->buildin[offset] = NULL; - - script->buildin_count++; + script->add_builtin(&BUILDIN[i], false); + } +} +#undef BUILDIN_DEF +#undef BUILDIN_DEF2 - } +void script_label_add(int key, int pos) { + int idx = script->label_count; + + if( script->labels_size == script->label_count ) { + script->labels_size += 1024; + RECREATE(script->labels, struct script_label_entry, script->labels_size); } + + script->labels[idx].key = key; + script->labels[idx].pos = pos; + script->label_count++; } +/** + * Sets source-end constants for scripts to play with + **/ +void script_hardcoded_constants(void) { + + /* server defines */ + script->set_constant("PACKETVER",PACKETVER,false); + script->set_constant("MAX_LEVEL",MAX_LEVEL,false); + script->set_constant("MAX_STORAGE",MAX_STORAGE,false); + script->set_constant("MAX_GUILD_STORAGE",MAX_GUILD_STORAGE,false); + script->set_constant("MAX_CART",MAX_INVENTORY,false); + script->set_constant("MAX_INVENTORY",MAX_INVENTORY,false); + script->set_constant("MAX_ZENY",MAX_ZENY,false); + script->set_constant("MAX_BG_MEMBERS",MAX_BG_MEMBERS,false); + script->set_constant("MAX_CHAT_USERS",MAX_CHAT_USERS,false); + + /* status options */ + script->set_constant("Option_Nothing",OPTION_NOTHING,false); + script->set_constant("Option_Sight",OPTION_SIGHT,false); + script->set_constant("Option_Hide",OPTION_HIDE,false); + script->set_constant("Option_Cloak",OPTION_CLOAK,false); + script->set_constant("Option_Falcon",OPTION_FALCON,false); + script->set_constant("Option_Riding",OPTION_RIDING,false); + script->set_constant("Option_Invisible",OPTION_INVISIBLE,false); + script->set_constant("Option_Orcish",OPTION_ORCISH,false); + script->set_constant("Option_Wedding",OPTION_WEDDING,false); + script->set_constant("Option_Chasewalk",OPTION_CHASEWALK,false); + script->set_constant("Option_Flying",OPTION_FLYING,false); + script->set_constant("Option_Xmas",OPTION_XMAS,false); + script->set_constant("Option_Transform",OPTION_TRANSFORM,false); + script->set_constant("Option_Summer",OPTION_SUMMER,false); + script->set_constant("Option_Dragon1",OPTION_DRAGON1,false); + script->set_constant("Option_Wug",OPTION_WUG,false); + script->set_constant("Option_Wugrider",OPTION_WUGRIDER,false); + script->set_constant("Option_Madogear",OPTION_MADOGEAR,false); + script->set_constant("Option_Dragon2",OPTION_DRAGON2,false); + script->set_constant("Option_Dragon3",OPTION_DRAGON3,false); + script->set_constant("Option_Dragon4",OPTION_DRAGON4,false); + script->set_constant("Option_Dragon5",OPTION_DRAGON5,false); + script->set_constant("Option_Hanbok",OPTION_HANBOK,false); + script->set_constant("Option_Oktoberfest",OPTION_OKTOBERFEST,false); + + /* status option compounds */ + script->set_constant("Option_Dragon",OPTION_DRAGON,false); + script->set_constant("Option_Costume",OPTION_COSTUME,false); + + /* send_target */ + script->set_constant("ALL_CLIENT",ALL_CLIENT,false); + script->set_constant("ALL_SAMEMAP",ALL_SAMEMAP,false); + script->set_constant("AREA",AREA,false); + script->set_constant("AREA_WOS",AREA_WOS,false); + script->set_constant("AREA_WOC",AREA_WOC,false); + script->set_constant("AREA_WOSC",AREA_WOSC,false); + script->set_constant("AREA_CHAT_WOC",AREA_CHAT_WOC,false); + script->set_constant("CHAT",CHAT,false); + script->set_constant("CHAT_WOS",CHAT_WOS,false); + script->set_constant("PARTY",PARTY,false); + script->set_constant("PARTY_WOS",PARTY_WOS,false); + script->set_constant("PARTY_SAMEMAP",PARTY_SAMEMAP,false); + script->set_constant("PARTY_SAMEMAP_WOS",PARTY_SAMEMAP_WOS,false); + script->set_constant("PARTY_AREA",PARTY_AREA,false); + script->set_constant("PARTY_AREA_WOS",PARTY_AREA_WOS,false); + script->set_constant("GUILD",GUILD,false); + script->set_constant("GUILD_WOS",GUILD_WOS,false); + script->set_constant("GUILD_SAMEMAP",GUILD_SAMEMAP,false); + script->set_constant("GUILD_SAMEMAP_WOS",GUILD_SAMEMAP_WOS,false); + script->set_constant("GUILD_AREA",GUILD_AREA,false); + script->set_constant("GUILD_AREA_WOS",GUILD_AREA_WOS,false); + script->set_constant("GUILD_NOBG",GUILD_NOBG,false); + script->set_constant("DUEL",DUEL,false); + script->set_constant("DUEL_WOS",DUEL_WOS,false); + script->set_constant("SELF",SELF,false); + script->set_constant("BG",BG,false); + script->set_constant("BG_WOS",BG_WOS,false); + script->set_constant("BG_SAMEMAP",BG_SAMEMAP,false); + script->set_constant("BG_SAMEMAP_WOS",BG_SAMEMAP_WOS,false); + script->set_constant("BG_AREA",BG_AREA,false); + script->set_constant("BG_AREA_WOS",BG_AREA_WOS,false); + script->set_constant("BG_QUEUE",BG_QUEUE,false); +} + +/** + * a mapindex_name2id wrapper meant to help with invalid name handling + **/ +unsigned short script_mapindexname2id (struct script_state *st, const char* name) { + unsigned short index; + + if( !(index=mapindex->name2id(name)) ) { + script->reportsrc(st); + return 0; + } + return index; +} + + void script_defaults(void) { + // aegis->athena slot position conversion table + unsigned int equip[SCRIPT_EQUIP_TABLE_SIZE] = {EQP_HEAD_TOP,EQP_ARMOR,EQP_HAND_L,EQP_HAND_R,EQP_GARMENT,EQP_SHOES,EQP_ACC_L,EQP_ACC_R,EQP_HEAD_MID,EQP_HEAD_LOW,EQP_COSTUME_HEAD_LOW,EQP_COSTUME_HEAD_MID,EQP_COSTUME_HEAD_TOP,EQP_COSTUME_GARMENT,EQP_SHADOW_ARMOR, EQP_SHADOW_WEAPON, EQP_SHADOW_SHIELD, EQP_SHADOW_SHOES, EQP_SHADOW_ACC_R, EQP_SHADOW_ACC_L}; + script = &script_s; - + script->st_db = NULL; script->active_scripts = 0; script->next_id = 0; script->st_ers = NULL; script->stack_ers = NULL; + script->array_ers = NULL; script->hq = NULL; script->hqi = NULL; script->hqs = script->hqis = 0; - memset(&script->hqe, 0, sizeof(script->hqe)); - - script->buildin_count = 0; + script->buildin = NULL; - + script->buildin_count = 0; + script->str_data = NULL; script->str_data_size = 0; script->str_num = LABEL_START; script->str_buf = NULL; script->str_size = 0; script->str_pos = 0; - + memset(script->str_hash, 0, sizeof(script->str_hash)); + script->word_buf = NULL; script->word_size = 0; - + + script->current_item_id = 0; + + script->labels = NULL; + script->label_count = 0; + script->labels_size = 0; + + script->buf = NULL; + script->pos = 0, script->size = 0; + + script->parse_options = 0; + script->buildin_set_ref = 0; + script->buildin_callsub_ref = 0; + script->buildin_callfunc_ref = 0; + script->buildin_getelementofarray_ref = 0; + + memset(script->error_jump,0,sizeof(script->error_jump)); + script->error_msg = NULL; + script->error_pos = NULL; + script->error_report = 0; + script->parser_current_src = NULL; + script->parser_current_file = NULL; + script->parser_current_line = 0; + + memset(&script->syntax,0,sizeof(script->syntax)); + + script->parse_syntax_for_flag = 0; + + memcpy(script->equip, &equip, sizeof(script->equip)); + + memset(&script->config, 0, sizeof(script->config)); + + script->autobonus_db = NULL; + script->userfunc_db = NULL; + + script->potion_flag = script->potion_hp = script->potion_per_hp = + script->potion_sp = script->potion_per_sp = script->potion_target = 0; + + script->generic_ui_array = NULL; + script->generic_ui_array_size = 0; + /* */ script->init = do_init_script; script->final = do_final_script; - + script->reload = script_reload; + + /* parse */ + script->parse = parse_script; + script->add_builtin = script_add_builtin; script->parse_builtin = script_parse_builtin; + script->skip_space = script_skip_space; + script->error = script_error; + script->warning = script_warning; + script->parse_subexpr = script_parse_subexpr; + script->addScript = script_hp_add; script->conv_num = conv_num; script->conv_str = conv_str; @@ -17876,9 +19495,165 @@ void script_defaults(void) { script->push_str = push_str; script->push_copy = push_copy; script->pop_stack = pop_stack; - + script->set_constant = script_set_constant; + script->set_constant2 = script_set_constant2; + script->get_constant = script_get_constant; + script->label_add = script_label_add; + script->run = run_script; + script->run_main = run_script_main; + script->run_timer = run_script_timer; + script->set_var = set_var; + script->stop_instances = script_stop_instances; + script->free_code = script_free_code; + script->free_vars = script_free_vars; + script->alloc_state = script_alloc_state; + script->free_state = script_free_state; + script->add_pending_ref = script_add_pending_ref; + script->run_autobonus = script_run_autobonus; + script->cleararray_pc = script_cleararray_pc; + script->setarray_pc = script_setarray_pc; + script->config_read = script_config_read; + script->add_str = script_add_str; + script->get_str = script_get_str; + script->search_str = script_search_str; + script->setd_sub = setd_sub; + script->attach_state = script_attach_state; + script->queue = script_hqueue_get; script->queue_add = script_hqueue_add; script->queue_del = script_hqueue_del; script->queue_remove = script_hqueue_remove; + script->queue_create = script_hqueue_create; + script->queue_clear = script_hqueue_clear; + + script->parse_curly_close = parse_curly_close; + script->parse_syntax_close = parse_syntax_close; + script->parse_syntax_close_sub = parse_syntax_close_sub; + script->parse_syntax = parse_syntax; + script->get_com = get_com; + script->get_num = get_num; + script->op2name = script_op2name; + script->reportsrc = script_reportsrc; + script->reportdata = script_reportdata; + script->reportfunc = script_reportfunc; + script->disp_warning_message = disp_warning_message; + script->check_event = check_event; + script->calc_hash = calc_hash; + script->addb = add_scriptb; + script->addc = add_scriptc; + script->addi = add_scripti; + script->addl = add_scriptl; + script->set_label = set_label; + script->skip_word = skip_word; + script->add_word = add_word; + script->parse_callfunc = parse_callfunc; + script->parse_nextline = parse_nextline; + script->parse_variable = parse_variable; + script->parse_simpleexpr = parse_simpleexpr; + script->parse_expr = parse_expr; + script->parse_line = parse_line; + script->read_constdb = read_constdb; + script->print_line = script_print_line; + script->errorwarning_sub = script_errorwarning_sub; + script->set_reg = set_reg; + script->stack_expand = stack_expand; + script->push_retinfo = push_retinfo; + script->op_3 = op_3; + script->op_2str = op_2str; + script->op_2num = op_2num; + script->op_2 = op_2; + script->op_1 = op_1; + script->check_buildin_argtype = script_check_buildin_argtype; + script->detach_state = script_detach_state; + script->db_free_code_sub = db_script_free_code_sub; + script->add_autobonus = script_add_autobonus; + script->menu_countoptions = menu_countoptions; + script->buildin_areawarp_sub = buildin_areawarp_sub; + script->buildin_areapercentheal_sub = buildin_areapercentheal_sub; + script->buildin_delitem_delete = buildin_delitem_delete; + script->buildin_delitem_search = buildin_delitem_search; + script->buildin_killmonster_sub_strip = buildin_killmonster_sub_strip; + script->buildin_killmonster_sub = buildin_killmonster_sub; + script->buildin_killmonsterall_sub_strip = buildin_killmonsterall_sub_strip; + script->buildin_killmonsterall_sub = buildin_killmonsterall_sub; + script->buildin_announce_sub = buildin_announce_sub; + script->buildin_getareausers_sub = buildin_getareausers_sub; + script->buildin_getareadropitem_sub = buildin_getareadropitem_sub; + script->mapflag_pvp_sub = script_mapflag_pvp_sub; + script->buildin_pvpoff_sub = buildin_pvpoff_sub; + script->buildin_maprespawnguildid_sub_pc = buildin_maprespawnguildid_sub_pc; + script->buildin_maprespawnguildid_sub_mob = buildin_maprespawnguildid_sub_mob; + script->buildin_mobcount_sub = buildin_mobcount_sub; + script->playbgm_sub = playbgm_sub; + script->playbgm_foreachpc_sub = playbgm_foreachpc_sub; + script->soundeffect_sub = soundeffect_sub; + script->buildin_query_sql_sub = buildin_query_sql_sub; + script->buildin_instance_warpall_sub = buildin_instance_warpall_sub; + script->buildin_mobuseskill_sub = buildin_mobuseskill_sub; + script->cleanfloor_sub = script_cleanfloor_sub; + script->run_func = run_func; + script->getfuncname = script_getfuncname; + + /* script_config base */ + script->config.warn_func_mismatch_argtypes = 1; + script->config.warn_func_mismatch_paramnum = 1; + script->config.check_cmdcount = 65535; + script->config.check_gotocount = 2048; + script->config.input_min_value = 0; + script->config.input_max_value = INT_MAX; + script->config.die_event_name = "OnPCDieEvent"; + script->config.kill_pc_event_name = "OnPCKillEvent"; + script->config.kill_mob_event_name = "OnNPCKillEvent"; + script->config.login_event_name = "OnPCLoginEvent"; + script->config.logout_event_name = "OnPCLogoutEvent"; + script->config.loadmap_event_name = "OnPCLoadMapEvent"; + script->config.baselvup_event_name = "OnPCBaseLvUpEvent"; + script->config.joblvup_event_name = "OnPCJobLvUpEvent"; + script->config.ontouch_name = "OnTouch_";//ontouch_name (runs on first visible char to enter area, picks another char if the first char leaves) + script->config.ontouch2_name = "OnTouch";//ontouch2_name (run whenever a char walks into the OnTouch area) + + // for ENABLE_CASE_CHECK + script->calc_hash_ci = calc_hash_ci; + script->local_casecheck.add_str = script_local_casecheck_add_str; + script->local_casecheck.clear = script_local_casecheck_clear; + script->local_casecheck.str_data = NULL; + script->local_casecheck.str_data_size = 0; + script->local_casecheck.str_num = 1; + script->local_casecheck.str_buf = NULL; + script->local_casecheck.str_size = 0; + script->local_casecheck.str_pos = 0; + memset(script->local_casecheck.str_hash, 0, sizeof(script->local_casecheck.str_hash)); + script->global_casecheck.add_str = script_global_casecheck_add_str; + script->global_casecheck.clear = script_global_casecheck_clear; + script->global_casecheck.str_data = NULL; + script->global_casecheck.str_data_size = 0; + script->global_casecheck.str_num = 1; + script->global_casecheck.str_buf = NULL; + script->global_casecheck.str_size = 0; + script->global_casecheck.str_pos = 0; + memset(script->global_casecheck.str_hash, 0, sizeof(script->global_casecheck.str_hash)); + // end ENABLE_CASE_CHECK + + /** + * Array Handling + **/ + script->array_src = script_array_src; + script->array_update = script_array_update; + script->array_add_member = script_array_add_member; + script->array_remove_member = script_array_remove_member; + script->array_delete = script_array_delete; + script->array_size = script_array_size; + script->array_free_db = script_free_array_db; + script->array_highest_key = script_array_highest_key; + script->array_ensure_zero = script_array_ensure_zero; + /* */ + script->reg_destroy_single = script_reg_destroy_single; + script->reg_destroy = script_reg_destroy; + /* */ + script->generic_ui_array_expand = script_generic_ui_array_expand; + script->array_cpy_list = script_array_cpy_list; + /* */ + script->hardcoded_constants = script_hardcoded_constants; + script->mapindexname2id = script_mapindexname2id; + } diff --git a/src/map/script.h b/src/map/script.h index 3cfcd9de4..48abf1487 100644 --- a/src/map/script.h +++ b/src/map/script.h @@ -1,41 +1,177 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder +// Copyright (c) Hercules Dev Team, licensed under GNU GPL. +// See the LICENSE file +// Portions Copyright (c) Athena Dev Teams -#ifndef _SCRIPT_H_ -#define _SCRIPT_H_ +#ifndef MAP_SCRIPT_H +#define MAP_SCRIPT_H + +#include <errno.h> +#include <setjmp.h> #include "map.h" //EVENT_NAME_LENGTH +#include "../common/cbasetypes.h" +#include "../common/db.h" +#include "../common/mmo.h" // struct item +#include "../common/sql.h" // Sql +#include "../common/strlib.h" //StringBuf + +/** + * Declarations + **/ +struct eri; + +/** + * Defines + **/ +// TODO: Remove temporary code +#define ENABLE_CASE_CHECK +#define get_script_source(source) ((source) ? (source) : "Unknown (Possibly source or variables stored in database") +#define DeprecationWarning(func, bad, good, file, line) ShowError("%s: use of deprecated keyword '%s' (use '%s' instead) in file '%s', line '%d'.\n", (func), (bad), (good), get_script_source(file), (line)); +#define DeprecationWarning2(func, bad, good, where) ShowError("%s: detected possible use of wrong case in a script. Found '%s', probably meant to be '%s' (in '%s').\n", (func), (bad), (good), get_script_source(where)); +#define disp_deprecation_message(func, good, p) disp_warning_message(func": use of deprecated keyword (use '"good"' instead).", (p)); #define NUM_WHISPER_VAR 10 -struct map_session_data; -struct eri; +/// Maximum amount of elements in script arrays +#define SCRIPT_MAX_ARRAYSIZE (UINT_MAX - 1) -extern int potion_flag; //For use on Alchemist improved potions/Potion Pitcher. [Skotlex] -extern int potion_hp, potion_per_hp, potion_sp, potion_per_sp; -extern int potion_target; +#define SCRIPT_BLOCK_SIZE 512 -extern struct Script_Config { - unsigned warn_func_mismatch_argtypes : 1; - unsigned warn_func_mismatch_paramnum : 1; - int check_cmdcount; - int check_gotocount; - int input_min_value; - int input_max_value; +// Using a prime number for SCRIPT_HASH_SIZE should give better distributions +#define SCRIPT_HASH_SIZE 1021 - const char *die_event_name; - const char *kill_pc_event_name; - const char *kill_mob_event_name; - const char *login_event_name; - const char *logout_event_name; - const char *loadmap_event_name; - const char *baselvup_event_name; - const char *joblvup_event_name; +// Specifies which string hashing method to use +//#define SCRIPT_HASH_DJB2 +//#define SCRIPT_HASH_SDBM +#define SCRIPT_HASH_ELF - const char* ontouch_name; - const char* ontouch2_name; -} script_config; +#define SCRIPT_EQUIP_TABLE_SIZE 20 + +//#define SCRIPT_DEBUG_DISP +//#define SCRIPT_DEBUG_DISASM +//#define SCRIPT_DEBUG_HASH +//#define SCRIPT_DEBUG_DUMP_STACK + +/////////////////////////////////////////////////////////////////////////////// +//## TODO possible enhancements: [FlavioJS] +// - 'callfunc' supporting labels in the current npc "::LabelName" +// - 'callfunc' supporting labels in other npcs "NpcName::LabelName" +// - 'function FuncName;' function declarations reverting to global functions +// if local label isn't found +// - join callfunc and callsub's functionality +// - remove dynamic allocation in add_word() +// - remove GETVALUE / SETVALUE +// - clean up the set_reg / set_val / setd_sub mess +// - detect invalid label references at parse-time + +// +// struct script_state* st; +// + +/// Returns the script_data at the target index +#define script_getdata(st,i) ( &((st)->stack->stack_data[(st)->start + (i)]) ) +/// Returns if the stack contains data at the target index +#define script_hasdata(st,i) ( (st)->end > (st)->start + (i) ) +/// Returns the index of the last data in the stack +#define script_lastdata(st) ( (st)->end - (st)->start - 1 ) +/// Pushes an int into the stack +#define script_pushint(st,val) (script->push_val((st)->stack, C_INT, (val),NULL)) +/// Pushes a string into the stack (script engine frees it automatically) +#define script_pushstr(st,val) (script->push_str((st)->stack, C_STR, (val))) +/// Pushes a copy of a string into the stack +#define script_pushstrcopy(st,val) (script->push_str((st)->stack, C_STR, aStrdup(val))) +/// Pushes a constant string into the stack (must never change or be freed) +#define script_pushconststr(st,val) (script->push_str((st)->stack, C_CONSTSTR, (val))) +/// Pushes a nil into the stack +#define script_pushnil(st) (script->push_val((st)->stack, C_NOP, 0,NULL)) +/// Pushes a copy of the data in the target index +#define script_pushcopy(st,i) (script->push_copy((st)->stack, (st)->start + (i))) + +#define script_isstring(st,i) data_isstring(script_getdata((st),(i))) +#define script_isint(st,i) data_isint(script_getdata((st),(i))) +#define script_isstringtype(st,i) data_isstring(script->get_val((st), script_getdata((st),(i)))) +#define script_isinttype(st,i) data_isint(script->get_val((st), script_getdata((st),(i)))) + +#define script_getnum(st,val) (script->conv_num((st), script_getdata((st),(val)))) +#define script_getstr(st,val) (script->conv_str((st), script_getdata((st),(val)))) +#define script_getref(st,val) ( script_getdata((st),(val))->ref ) + +// Note: "top" functions/defines use indexes relative to the top of the stack +// -1 is the index of the data at the top + +/// Returns the script_data at the target index relative to the top of the stack +#define script_getdatatop(st,i) ( &((st)->stack->stack_data[(st)->stack->sp + (i)]) ) +/// Pushes a copy of the data in the target index relative to the top of the stack +#define script_pushcopytop(st,i) script->push_copy((st)->stack, (st)->stack->sp + (i)) +/// Removes the range of values [start,end[ relative to the top of the stack +#define script_removetop(st,start,end) ( script->pop_stack((st), ((st)->stack->sp + (start)), (st)->stack->sp + (end)) ) + +// +// struct script_data* data; +// + +/// Returns if the script data is a string +#define data_isstring(data) ( (data)->type == C_STR || (data)->type == C_CONSTSTR ) +/// Returns if the script data is an int +#define data_isint(data) ( (data)->type == C_INT ) +/// Returns if the script data is a reference +#define data_isreference(data) ( (data)->type == C_NAME ) +/// Returns if the script data is a label +#define data_islabel(data) ( (data)->type == C_POS ) +/// Returns if the script data is an internal script function label +#define data_isfunclabel(data) ( (data)->type == C_USERFUNC_POS ) +/// Returns if this is a reference to a constant +#define reference_toconstant(data) ( script->str_data[reference_getid(data)].type == C_INT ) +/// Returns if this a reference to a param +#define reference_toparam(data) ( script->str_data[reference_getid(data)].type == C_PARAM ) +/// Returns if this a reference to a variable +//##TODO confirm it's C_NAME [FlavioJS] +#define reference_tovariable(data) ( script->str_data[reference_getid(data)].type == C_NAME ) +/// Returns the unique id of the reference (id and index) +#define reference_getuid(data) ( (data)->u.num ) +/// Returns the id of the reference +#define reference_getid(data) ( (int32)(int64)(reference_getuid(data) & 0xFFFFFFFF) ) +/// Returns the array index of the reference +#define reference_getindex(data) ( (uint32)(int64)((reference_getuid(data) >> 32) & 0xFFFFFFFF) ) +/// Returns the name of the reference +#define reference_getname(data) ( script->str_buf + script->str_data[reference_getid(data)].str ) +/// Returns the linked list of uid-value pairs of the reference (can be NULL) +#define reference_getref(data) ( (data)->ref ) +/// Returns the value of the constant +#define reference_getconstant(data) ( script->str_data[reference_getid(data)].val ) +/// Returns the type of param +#define reference_getparamtype(data) ( script->str_data[reference_getid(data)].val ) + +/// Composes the uid of a reference from the id and the index +#define reference_uid(id,idx) ( (int64) ((uint64)(id) & 0xFFFFFFFF) | ((uint64)(idx) << 32) ) + +/// Checks whether two references point to the same variable (or array) +#define is_same_reference(data1, data2) \ + ( reference_getid(data1) == reference_getid(data2) \ + && ( (data1->ref == data2->ref && data1->ref == NULL) \ + || (data1->ref != NULL && data2->ref != NULL && data1->ref->vars == data2->ref->vars \ + ) ) ) + +#define script_getvarid(var) ( (int32)(int64)(var & 0xFFFFFFFF) ) +#define script_getvaridx(var) ( (uint32)(int64)((var >> 32) & 0xFFFFFFFF) ) + +#define not_server_variable(prefix) ( (prefix) != '$' && (prefix) != '.' && (prefix) != '\'') +#define is_string_variable(name) ( (name)[strlen(name) - 1] == '$' ) + +#define BUILDIN(x) bool buildin_ ## x (struct script_state* st) + +#define script_fetch(st, n, t) do { \ + if( script_hasdata((st),(n)) ) \ + (t)=script_getnum((st),(n)); \ + else \ + (t) = 0; \ +} while(0) + + +/** + * Enumerations + **/ typedef enum c_op { C_NOP, // end of script/no value (nil) C_POS, @@ -51,7 +187,7 @@ typedef enum c_op { C_USERFUNC, // internal script function C_USERFUNC_POS, // internal script function label C_REF, // the next call to c_op2 should push back a ref to the left operand - + // operators C_OP3, // a ? b : c C_LOR, // a || b @@ -75,57 +211,189 @@ typedef enum c_op { C_NOT, // ~ a C_R_SHIFT, // a >> b C_L_SHIFT, // a << b - C_ADD_PP, // ++a - C_SUB_PP, // --a + C_ADD_POST, // a++ + C_SUB_POST, // a-- + C_ADD_PRE, // ++a + C_SUB_PRE, // --a +#ifdef PCRE_SUPPORT + C_RE_EQ, // ~= + C_RE_NE, // ~! +#endif // PCRE_SUPPORT } c_op; +enum hQueueOpt { + HQO_NONE, + HQO_onLogOut, + HQO_OnDeath, + HQO_OnMapChange, + HQO_MAX, +}; + +enum e_script_state { RUN,STOP,END,RERUNLINE,GOTO,RETFUNC,CLOSE }; + +enum script_parse_options { + SCRIPT_USE_LABEL_DB = 0x1,// records labels in scriptlabel_db + SCRIPT_IGNORE_EXTERNAL_BRACKETS = 0x2,// ignores the check for {} brackets around the script + SCRIPT_RETURN_EMPTY_SCRIPT = 0x4// returns the script object instead of NULL for empty scripts +}; + +enum { LABEL_NEXTLINE=1,LABEL_START }; + +// for advanced scripting support ( nested if, switch, while, for, do-while, function, etc ) +// [Eoe / jA 1080, 1081, 1094, 1164] +enum curly_type { + TYPE_NULL = 0, + TYPE_IF, + TYPE_SWITCH, + TYPE_WHILE, + TYPE_FOR, + TYPE_DO, + TYPE_USERFUNC, + TYPE_ARGLIST // function argument list +}; + +enum e_arglist { + ARGLIST_UNDEFINED = 0, + ARGLIST_NO_PAREN = 1, + ARGLIST_PAREN = 2, +}; + +/*========================================== + * (Only those needed) local declaration prototype + * - those could be used server-wide so that the scans are done once during processing and never again, + * - doing so would also improve map zone processing and storage [Ind] + *------------------------------------------*/ + +enum { + MF_NOMEMO, //0 + MF_NOTELEPORT, + MF_NOSAVE, + MF_NOBRANCH, + MF_NOPENALTY, + MF_NOZENYPENALTY, + MF_PVP, + MF_PVP_NOPARTY, + MF_PVP_NOGUILD, + MF_GVG, + MF_GVG_NOPARTY, //10 + MF_NOTRADE, + MF_NOSKILL, + MF_NOWARP, + MF_PARTYLOCK, + MF_NOICEWALL, + MF_SNOW, + MF_FOG, + MF_SAKURA, + MF_LEAVES, + /* 21 - 22 free */ + MF_CLOUDS = 23, + MF_CLOUDS2, + MF_FIREWORKS, + MF_GVG_CASTLE, + MF_GVG_DUNGEON, + MF_NIGHTENABLED, + MF_NOBASEEXP, + MF_NOJOBEXP, //30 + MF_NOMOBLOOT, + MF_NOMVPLOOT, + MF_NORETURN, + MF_NOWARPTO, + MF_NIGHTMAREDROP, + MF_ZONE, + MF_NOCOMMAND, + MF_NODROP, + MF_JEXP, + MF_BEXP, //40 + MF_NOVENDING, + MF_LOADEVENT, + MF_NOCHAT, + MF_NOEXPPENALTY, + MF_GUILDLOCK, + MF_TOWN, + MF_AUTOTRADE, + MF_ALLOWKS, + MF_MONSTER_NOTELEPORT, + MF_PVP_NOCALCRANK, //50 + MF_BATTLEGROUND, + MF_RESET, + MF_NOTOMB, + MF_NOCASHSHOP +}; + +/** + * Structures + **/ + +struct Script_Config { + unsigned warn_func_mismatch_argtypes : 1; + unsigned warn_func_mismatch_paramnum : 1; + int check_cmdcount; + int check_gotocount; + int input_min_value; + int input_max_value; + + const char *die_event_name; + const char *kill_pc_event_name; + const char *kill_mob_event_name; + const char *login_event_name; + const char *logout_event_name; + const char *loadmap_event_name; + const char *baselvup_event_name; + const char *joblvup_event_name; + + const char* ontouch_name; + const char* ontouch2_name; +}; + +/** + * Generic reg database abstraction to be used with various types of regs/script variables. + */ +struct reg_db { + struct DBMap *vars; + struct DBMap *arrays; +}; + struct script_retinfo { - struct DBMap* var_function;// scope variables - struct script_code* script;// script code - int pos;// script location - int nargs;// argument count - int defsp;// default stack pointer + struct reg_db scope; ///< scope variables + struct script_code* script; ///< script code + int pos; ///< script location + int nargs; ///< argument count + int defsp; ///< default stack pointer }; struct script_data { enum c_op type; union script_data_val { - int num; + int64 num; char *str; struct script_retinfo* ri; } u; - struct DBMap** ref; + struct reg_db *ref; }; // 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 DBMap* script_vars; + unsigned char *script_buf; + struct reg_db local; ///< Local (npc) vars + unsigned short instances; }; struct script_stack { - int sp;// number of entries in the stack - int sp_max;// capacity of the stack + int sp; ///< number of entries in the stack + int sp_max; ///< capacity of the stack int defsp; - struct script_data *stack_data;// stack - struct DBMap* var_function;// scope variables -}; - -enum hQueueOpt { - HQO_NONE, - HQO_onLogOut, - HQO_OnDeath, - HQO_OnMapChange, - HQO_MAX, + struct script_data *stack_data; ///< stack + struct reg_db scope; ///< scope variables }; /* [Ind/Hercules] */ struct hQueue { int id; int *item; - int items; + int items;/* how many actual items are in the array */ + int size;/* size of the *item array, not the current amount of items in it since it can have empty slots */ /* events */ char onLogOut[EVENT_NAME_LENGTH]; char onDeath[EVENT_NAME_LENGTH]; @@ -138,18 +406,15 @@ struct hQueueIterator { int pos; }; -// -// Script state -// -enum e_script_state { RUN,STOP,END,RERUNLINE,GOTO,RETFUNC,CLOSE }; - struct script_state { struct script_stack* stack; + struct reg_db **pending_refs; ///< References to .vars returned by sub-functions, pending deletion. + int pending_ref_count; ///< Amount of pending_refs currently stored. int start,end; int pos; enum e_script_state state; int rid,oid; - struct script_code *script, *scriptroot; + struct script_code *script; struct sleep_data { int tick,timer,charid; } sleep; @@ -164,58 +429,6 @@ struct script_state { unsigned int id; }; -struct script_reg { - int index; - int data; -}; - -struct script_regstr { - int index; - char* data; -}; - -enum script_parse_options { - SCRIPT_USE_LABEL_DB = 0x1,// records labels in scriptlabel_db - SCRIPT_IGNORE_EXTERNAL_BRACKETS = 0x2,// ignores the check for {} brackets around the script - SCRIPT_RETURN_EMPTY_SCRIPT = 0x4// returns the script object instead of NULL for empty scripts -}; - -const char* skip_space(const char* p); -void script_error(const char* src, const char* file, int start_line, const char* error_msg, const char* error_pos); - -struct script_code* parse_script(const char* src,const char* file,int line,int options); -void run_script_sub(struct script_code *rootscript,int pos,int rid,int oid, char* file, int lineno); -void run_script(struct script_code*,int,int,int); - -int set_var(struct map_session_data *sd, char *name, void *val); -int run_script_timer(int tid, unsigned int tick, int id, intptr_t data); -void run_script_main(struct script_state *st); - -void script_stop_instances(int id); -struct linkdb_node* script_erase_sleepdb(struct linkdb_node *n); -void script_free_code(struct script_code* code); -void script_free_vars(struct DBMap *storage); -struct script_state* script_alloc_state(struct script_code* rootscript, int pos, int rid, int oid); -void script_free_state(struct script_state* st); - -struct DBMap* script_get_label_db(void); -struct DBMap* script_get_userfunc_db(void); -void script_run_autobonus(const char *autobonus,int id, int pos); - -bool script_get_constant(const char* name, int* value); -void script_set_constant(const char* name, int value, bool isparameter); - -void script_cleararray_pc(struct map_session_data* sd, const char* varname, void* value); -void script_setarray_pc(struct map_session_data* sd, const char* varname, uint8 idx, void* value, int* refcache); - -int script_config_read(char *cfgName); -int add_str(const char* p); -const char* get_str(int id); -int script_reload(void); - -// @commands (script based) -void setd_sub(struct script_state *st, struct map_session_data *sd, const char *varname, int elem, void *value, struct DBMap **ref); - struct script_function { bool (*func)(struct script_state *st); char *name; @@ -234,106 +447,44 @@ struct str_data_struct { int next; }; -/////////////////////////////////////////////////////////////////////////////// -//## TODO possible enhancements: [FlavioJS] -// - 'callfunc' supporting labels in the current npc "::LabelName" -// - 'callfunc' supporting labels in other npcs "NpcName::LabelName" -// - 'function FuncName;' function declarations reverting to global functions -// if local label isn't found -// - join callfunc and callsub's functionality -// - remove dynamic allocation in add_word() -// - remove GETVALUE / SETVALUE -// - clean up the set_reg / set_val / setd_sub mess -// - detect invalid label references at parse-time - -// -// struct script_state* st; -// - -/// Returns the script_data at the target index -#define script_getdata(st,i) ( &((st)->stack->stack_data[(st)->start + (i)]) ) -/// Returns if the stack contains data at the target index -#define script_hasdata(st,i) ( (st)->end > (st)->start + (i) ) -/// Returns the index of the last data in the stack -#define script_lastdata(st) ( (st)->end - (st)->start - 1 ) -/// Pushes an int into the stack -#define script_pushint(st,val) script->push_val((st)->stack, C_INT, (val),NULL) -/// Pushes a string into the stack (script engine frees it automatically) -#define script_pushstr(st,val) script->push_str((st)->stack, C_STR, (val)) -/// Pushes a copy of a string into the stack -#define script_pushstrcopy(st,val) script->push_str((st)->stack, C_STR, aStrdup(val)) -/// Pushes a constant string into the stack (must never change or be freed) -#define script_pushconststr(st,val) script->push_str((st)->stack, C_CONSTSTR, (val)) -/// Pushes a nil into the stack -#define script_pushnil(st) script->push_val((st)->stack, C_NOP, 0,NULL) -/// Pushes a copy of the data in the target index -#define script_pushcopy(st,i) script->push_copy((st)->stack, (st)->start + (i)) - -#define script_isstring(st,i) data_isstring(script_getdata(st,i)) -#define script_isint(st,i) data_isint(script_getdata(st,i)) - -#define script_getnum(st,val) script->conv_num(st, script_getdata(st,val)) -#define script_getstr(st,val) script->conv_str(st, script_getdata(st,val)) -#define script_getref(st,val) ( script_getdata(st,val)->ref ) - -// Note: "top" functions/defines use indexes relative to the top of the stack -// -1 is the index of the data at the top - -/// Returns the script_data at the target index relative to the top of the stack -#define script_getdatatop(st,i) ( &((st)->stack->stack_data[(st)->stack->sp + (i)]) ) -/// Pushes a copy of the data in the target index relative to the top of the stack -#define script_pushcopytop(st,i) script->push_copy((st)->stack, (st)->stack->sp + (i)) -/// Removes the range of values [start,end[ relative to the top of the stack -#define script_removetop(st,start,end) ( script->pop_stack((st), ((st)->stack->sp + (start)), (st)->stack->sp + (end)) ) - -// -// struct script_data* data; -// - -/// Returns if the script data is a string -#define data_isstring(data) ( (data)->type == C_STR || (data)->type == C_CONSTSTR ) -/// Returns if the script data is an int -#define data_isint(data) ( (data)->type == C_INT ) -/// Returns if the script data is a reference -#define data_isreference(data) ( (data)->type == C_NAME ) -/// Returns if the script data is a label -#define data_islabel(data) ( (data)->type == C_POS ) -/// Returns if the script data is an internal script function label -#define data_isfunclabel(data) ( (data)->type == C_USERFUNC_POS ) - -/// Returns if this is a reference to a constant -#define reference_toconstant(data) ( script->str_data[reference_getid(data)].type == C_INT ) -/// Returns if this a reference to a param -#define reference_toparam(data) ( script->str_data[reference_getid(data)].type == C_PARAM ) -/// Returns if this a reference to a variable -//##TODO confirm it's C_NAME [FlavioJS] -#define reference_tovariable(data) ( script->str_data[reference_getid(data)].type == C_NAME ) -/// Returns the unique id of the reference (id and index) -#define reference_getuid(data) ( (data)->u.num ) -/// Returns the id of the reference -#define reference_getid(data) ( (int32)(reference_getuid(data) & 0x00ffffff) ) -/// Returns the array index of the reference -#define reference_getindex(data) ( (int32)(((uint32)(reference_getuid(data) & 0xff000000)) >> 24) ) -/// Returns the name of the reference -#define reference_getname(data) ( script->str_buf + script->str_data[reference_getid(data)].str ) -/// Returns the linked list of uid-value pairs of the reference (can be NULL) -#define reference_getref(data) ( (data)->ref ) -/// Returns the value of the constant -#define reference_getconstant(data) ( script->str_data[reference_getid(data)].val ) -/// Returns the type of param -#define reference_getparamtype(data) ( script->str_data[reference_getid(data)].val ) +struct script_label_entry { + int key,pos; +}; -/// Composes the uid of a reference from the id and the index -#define reference_uid(id,idx) ( (int32)((((uint32)(id)) & 0x00ffffff) | (((uint32)(idx)) << 24)) ) +struct script_syntax_data { + struct { + enum curly_type type; + int index; + int count; + int flag; + struct linkdb_node *case_label; + } curly[256]; // Information right parenthesis + int curly_count; // The number of right brackets + int index; // Number of the syntax used in the script +}; -#define not_server_variable(prefix) ( (prefix) != '$' && (prefix) != '.' && (prefix) != '\'') -#define not_array_variable(prefix) ( (prefix) != '$' && (prefix) != '@' && (prefix) != '.' && (prefix) != '\'' ) -#define is_string_variable(name) ( (name)[strlen(name) - 1] == '$' ) +struct casecheck_data { + struct str_data_struct *str_data; + int str_data_size; // size of the data + int str_num; // next id to be assigned + // str_buf holds the strings themselves + char *str_buf; + int str_size; // size of the buffer + int str_pos; // next position to be assigned + int str_hash[SCRIPT_HASH_SIZE]; + const char *(*add_str) (const char* p); + void (*clear) (void); +}; -#define BUILDIN(x) bool buildin_ ## x (struct script_state* st) -#define BUILDIN_A(x) buildin_ ## x +struct script_array { + unsigned int id;/* the first 32b of the 64b uid, aka the id */ + unsigned int size;/* how many members */ + unsigned int *members;/* member list */ +}; -/* script.c interface (incomplete) */ +/** + * Interface + **/ struct script_interface { /* */ DBMap *st_db; @@ -345,46 +496,223 @@ struct script_interface { struct hQueue *hq; struct hQueueIterator *hqi; int hqs, hqis; - int hqe[HQO_MAX]; /* */ char **buildin; unsigned int buildin_count; + /** + * used to generate quick script_array entries + **/ + struct eri *array_ers; /* */ struct str_data_struct *str_data; int str_data_size; // size of the data int str_num; // next id to be assigned // str_buf holds the strings themselves char *str_buf; - int str_size; // size of the buffer + size_t str_size; // size of the buffer int str_pos; // next position to be assigned - // + int str_hash[SCRIPT_HASH_SIZE]; + /* */ char *word_buf; - int word_size; + size_t word_size; /* */ - void (*init) (void); - void (*final) (void); + unsigned short current_item_id; + /* */ + struct script_label_entry *labels; + int label_count; + int labels_size; + /* */ + struct Script_Config config; + /* */ + /// temporary buffer for passing around compiled bytecode + /// @see add_scriptb, set_label, parse_script + unsigned char* buf; + int pos, size; + /* */ + struct script_syntax_data syntax; + /* */ + int parse_options; + // important buildin function references for usage in scripts + int buildin_set_ref; + int buildin_callsub_ref; + int buildin_callfunc_ref; + int buildin_getelementofarray_ref; + /* */ + jmp_buf error_jump; + char* error_msg; + const char* error_pos; + int error_report; // if the error should produce output + // Used by disp_warning_message + const char* parser_current_src; + const char* parser_current_file; + int parser_current_line; + int parse_syntax_for_flag; + // aegis->athena slot position conversion table + unsigned int equip[SCRIPT_EQUIP_TABLE_SIZE]; + /* */ + /* Caches compiled autoscript item code. */ + /* Note: This is not cleared when reloading itemdb. */ + DBMap* autobonus_db; // char* script -> char* bytecode + DBMap* userfunc_db; // const char* func_name -> struct script_code* + /* */ + int potion_flag; //For use on Alchemist improved potions/Potion Pitcher. [Skotlex] + int potion_hp, potion_per_hp, potion_sp, potion_per_sp; + int potion_target; + /* */ + unsigned int *generic_ui_array; + unsigned int generic_ui_array_size; /* */ + void (*init) (bool minimal); + void (*final) (void); + int (*reload) (void); + /* parse */ + struct script_code* (*parse) (const char* src,const char* file,int line,int options, int *retval); + bool (*add_builtin) (const struct script_function *buildin, bool override); void (*parse_builtin) (void); + const char* (*parse_subexpr) (const char* p,int limit); + const char* (*skip_space) (const char* p); + void (*error) (const char* src, const char* file, int start_line, const char* error_msg, const char* error_pos); + void (*warning) (const char* src, const char* file, int start_line, const char* error_msg, const char* error_pos); + /* */ bool (*addScript) (char *name, char *args, bool (*func)(struct script_state *st)); int (*conv_num) (struct script_state *st,struct script_data *data); const char* (*conv_str) (struct script_state *st,struct script_data *data); TBL_PC *(*rid2sd) (struct script_state *st); void (*detach_rid) (struct script_state* st); - struct script_data* (*push_val)(struct script_stack* stack, enum c_op type, int val, struct DBMap** ref); - void (*get_val) (struct script_state* st, struct script_data* data); - void* (*get_val2) (struct script_state* st, int uid, struct DBMap** ref); + struct script_data* (*push_val)(struct script_stack* stack, enum c_op type, int64 val, struct reg_db *ref); + struct script_data *(*get_val) (struct script_state* st, struct script_data* data); + void* (*get_val2) (struct script_state* st, int64 uid, struct reg_db *ref); struct script_data* (*push_str) (struct script_stack* stack, enum c_op type, char* str); struct script_data* (*push_copy) (struct script_stack* stack, int pos); void (*pop_stack) (struct script_state* st, int start, int end); + void (*set_constant) (const char* name, int value, bool isparameter); + void (*set_constant2) (const char *name, int value, bool isparameter); + bool (*get_constant) (const char* name, int* value); + void (*label_add)(int key, int pos); + void (*run) (struct script_code *rootscript,int pos,int rid,int oid); + void (*run_main) (struct script_state *st); + int (*run_timer) (int tid, int64 tick, int id, intptr_t data); + int (*set_var) (struct map_session_data *sd, char *name, void *val); + void (*stop_instances) (struct script_code *code); + void (*free_code) (struct script_code* code); + void (*free_vars) (struct DBMap *var_storage); + struct script_state* (*alloc_state) (struct script_code* rootscript, int pos, int rid, int oid); + void (*free_state) (struct script_state* st); + void (*add_pending_ref) (struct script_state *st, struct reg_db *ref); + void (*run_autobonus) (const char *autobonus,int id, int pos); + void (*cleararray_pc) (struct map_session_data* sd, const char* varname, void* value); + void (*setarray_pc) (struct map_session_data* sd, const char* varname, uint32 idx, void* value, int* refcache); + int (*config_read) (char *cfgName); + int (*add_str) (const char* p); + const char* (*get_str) (int id); + int (*search_str) (const char* p); + void (*setd_sub) (struct script_state *st, struct map_session_data *sd, const char *varname, int elem, void *value, struct reg_db *ref); + void (*attach_state) (struct script_state* st); /* */ struct hQueue *(*queue) (int idx); bool (*queue_add) (int idx, int var); bool (*queue_del) (int idx); bool (*queue_remove) (int idx, int var); -} script_s; + int (*queue_create) (void); + void (*queue_clear) (int idx); + /* */ + const char * (*parse_curly_close) (const char *p); + 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); + const char* (*op2name) (int op); + void (*reportsrc) (struct script_state *st); + void (*reportdata) (struct script_data *data); + void (*reportfunc) (struct script_state *st); + void (*disp_warning_message) (const char *mes, const char *pos); + void (*check_event) (struct script_state *st, const char *evt); + unsigned int (*calc_hash) (const char *p); + void (*addb) (int a); + void (*addc) (int a); + void (*addi) (int a); + void (*addl) (int l); + void (*set_label) (int l, int pos, const char *script_pos); + const char* (*skip_word) (const char *p); + 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); + void (*read_constdb) (void); + const char* (*print_line) (StringBuf *buf, const char *p, const char *mark, int line); + void (*errorwarning_sub) (StringBuf *buf, const char *src, const char *file, int start_line, const char *error_msg, const char *error_pos); + int (*set_reg) (struct script_state *st, TBL_PC *sd, int64 num, const char *name, const void *value, struct reg_db *ref); + void (*stack_expand) (struct script_stack *stack); + struct script_data* (*push_retinfo) (struct script_stack *stack, struct script_retinfo *ri, struct reg_db *ref); + void (*op_3) (struct script_state *st, int op); + void (*op_2str) (struct script_state *st, int op, const char *s1, const char *s2); + 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); + void (*detach_state) (struct script_state *st, bool dequeue_event); + int (*db_free_code_sub) (DBKey key, DBData *data, va_list ap); + void (*add_autobonus) (const char *autobonus); + int (*menu_countoptions) (const char *str, int max_count, int *total); + int (*buildin_areawarp_sub) (struct block_list *bl, va_list ap); + int (*buildin_areapercentheal_sub) (struct block_list *bl, va_list ap); + void (*buildin_delitem_delete) (struct map_session_data *sd, int idx, int *amount, bool delete_items); + bool (*buildin_delitem_search) (struct map_session_data *sd, struct item *it, bool exact_match); + int (*buildin_killmonster_sub_strip) (struct block_list *bl, va_list ap); + int (*buildin_killmonster_sub) (struct block_list *bl, va_list ap); + int (*buildin_killmonsterall_sub_strip) (struct block_list *bl, va_list ap); + int (*buildin_killmonsterall_sub) (struct block_list *bl, va_list ap); + int (*buildin_announce_sub) (struct block_list *bl, va_list ap); + int (*buildin_getareausers_sub) (struct block_list *bl, va_list ap); + int (*buildin_getareadropitem_sub) (struct block_list *bl, va_list ap); + int (*mapflag_pvp_sub) (struct block_list *bl, va_list ap); + int (*buildin_pvpoff_sub) (struct block_list *bl, va_list ap); + int (*buildin_maprespawnguildid_sub_pc) (struct map_session_data *sd, va_list ap); + int (*buildin_maprespawnguildid_sub_mob) (struct block_list *bl, va_list ap); + int (*buildin_mobcount_sub) (struct block_list *bl, va_list ap); + int (*playbgm_sub) (struct block_list *bl, va_list ap); + int (*playbgm_foreachpc_sub) (struct map_session_data *sd, va_list args); + int (*soundeffect_sub) (struct block_list *bl, va_list ap); + int (*buildin_query_sql_sub) (struct script_state *st, Sql *handle); + int (*buildin_instance_warpall_sub) (struct block_list *bl, va_list ap); + int (*buildin_mobuseskill_sub) (struct block_list *bl, va_list ap); + int (*cleanfloor_sub) (struct block_list *bl, va_list ap); + int (*run_func) (struct script_state *st); + const char *(*getfuncname) (struct script_state *st); + // for ENABLE_CASE_CHECK + unsigned int (*calc_hash_ci) (const char *p); + struct casecheck_data local_casecheck; + struct casecheck_data global_casecheck; + // end ENABLE_CASE_CHECK + /** + * Array Handling + **/ + struct reg_db *(*array_src) (struct script_state *st, struct map_session_data *sd, const char *name, struct reg_db *ref); + void (*array_update) (struct reg_db *src, int64 num, bool empty); + void (*array_delete) (struct reg_db *src, struct script_array *sa); + void (*array_remove_member) (struct reg_db *src, struct script_array *sa, unsigned int idx); + void (*array_add_member) (struct script_array *sa, unsigned int idx); + unsigned int (*array_size) (struct script_state *st, struct map_session_data *sd, const char *name, struct reg_db *ref); + unsigned int (*array_highest_key) (struct script_state *st, struct map_session_data *sd, const char *name, struct reg_db *ref); + int (*array_free_db) (DBKey key, DBData *data, va_list ap); + void (*array_ensure_zero) (struct script_state *st, struct map_session_data *sd, int64 uid, struct reg_db *ref); + /* */ + void (*reg_destroy_single) (struct map_session_data *sd, int64 reg, struct script_reg_state *data); + int (*reg_destroy) (DBKey key, DBData *data, va_list ap); + /* */ + void (*generic_ui_array_expand) (unsigned int plus); + unsigned int *(*array_cpy_list) (struct script_array *sa); + /* */ + void (*hardcoded_constants) (void); + unsigned short (*mapindexname2id) (struct script_state *st, const char* name); +}; struct script_interface *script; void script_defaults(void); -#endif /* _SCRIPT_H_ */ +#endif /* MAP_SCRIPT_H */ diff --git a/src/map/searchstore.c b/src/map/searchstore.c index 3cda77e4a..72b28aacd 100644 --- a/src/map/searchstore.c +++ b/src/map/searchstore.c @@ -2,43 +2,19 @@ // See the LICENSE file // Portions Copyright (c) Athena Dev Teams +#define HERCULES_CORE + +#include "searchstore.h" // struct s_search_store_info + +#include "battle.h" // battle_config.* +#include "clif.h" // clif->open_search_store_info, clif->search_store_info_* +#include "pc.h" // struct map_session_data #include "../common/cbasetypes.h" #include "../common/malloc.h" // aMalloc, aRealloc, aFree #include "../common/showmsg.h" // ShowError, ShowWarning #include "../common/strlib.h" // safestrncpy -#include "battle.h" // battle_config.* -#include "clif.h" // clif->open_search_store_info, clif->search_store_info_* -#include "pc.h" // struct map_session_data -#include "searchstore.h" // struct s_search_store_info - - -/// failure constants for clif functions -enum e_searchstore_failure { - SSI_FAILED_NOTHING_SEARCH_ITEM = 0, // "No matching stores were found." - SSI_FAILED_OVER_MAXCOUNT = 1, // "There are too many results. Please enter more detailed search term." - SSI_FAILED_SEARCH_CNT = 2, // "You cannot search anymore." - SSI_FAILED_LIMIT_SEARCH_TIME = 3, // "You cannot search yet." - SSI_FAILED_SSILIST_CLICK_TO_OPEN_STORE = 4, // "No sale (purchase) information available." -}; - - -enum e_searchstore_searchtype { - SEARCHTYPE_VENDING = 0, - SEARCHTYPE_BUYING_STORE = 1, -}; - - -enum e_searchstore_effecttype { - EFFECTTYPE_NORMAL = 0, - EFFECTTYPE_CASH = 1, - EFFECTTYPE_MAX -}; - - -/// type for shop search function -typedef bool (*searchstore_search_t)(struct map_session_data* sd, unsigned short nameid); -typedef bool (*searchstore_searchall_t)(struct map_session_data* sd, const struct s_search_store_search* s); +struct searchstore_interface searchstore_s; /// retrieves search function by type static inline searchstore_search_t searchstore_getsearchfunc(unsigned char type) { @@ -135,14 +111,14 @@ void searchstore_query(struct map_session_data* sd, unsigned char type, unsigned // validate lists for( i = 0; i < item_count; i++ ) { - if( !itemdb_exists(itemlist[i]) ) { + if( !itemdb->exists(itemlist[i]) ) { ShowWarning("searchstore_query: Client resolved item %hu is not known.\n", itemlist[i]); clif->search_store_info_failed(sd, SSI_FAILED_NOTHING_SEARCH_ITEM); return; } } for( i = 0; i < card_count; i++ ) { - if( !itemdb_exists(cardlist[i]) ) { + if( !itemdb->exists(cardlist[i]) ) { ShowWarning("searchstore_query: Client resolved card %hu is not known.\n", cardlist[i]); clif->search_store_info_failed(sd, SSI_FAILED_NOTHING_SEARCH_ITEM); return; @@ -273,7 +249,7 @@ void searchstore_click(struct map_session_data* sd, int account_id, int store_id return; } - if( ( pl_sd = iMap->id2sd(account_id) ) == NULL ) {// no longer online + if( ( pl_sd = map->id2sd(account_id) ) == NULL ) {// no longer online clif->search_store_info_failed(sd, SSI_FAILED_SSILIST_CLICK_TO_OPEN_STORE); return; } diff --git a/src/map/searchstore.h b/src/map/searchstore.h index 61e65c7d2..d8abde615 100644 --- a/src/map/searchstore.h +++ b/src/map/searchstore.h @@ -2,11 +2,45 @@ // See the LICENSE file // Portions Copyright (c) Athena Dev Teams -#ifndef _SEARCHSTORE_H_ -#define _SEARCHSTORE_H_ +#ifndef MAP_SEARCHSTORE_H +#define MAP_SEARCHSTORE_H +#include <time.h> + +#include "map.h" // MESSAGE_SIZE +#include "../common/cbasetypes.h" +#include "../common/mmo.h" // MAX_SLOTS + +/** + * Defines + **/ #define SEARCHSTORE_RESULTS_PER_PAGE 10 +/** + * Enumerations + **/ +enum e_searchstore_searchtype { + SEARCHTYPE_VENDING = 0, + SEARCHTYPE_BUYING_STORE = 1, +}; + +enum e_searchstore_effecttype { + EFFECTTYPE_NORMAL = 0, + EFFECTTYPE_CASH = 1, + EFFECTTYPE_MAX +}; +/// failure constants for clif functions +enum e_searchstore_failure { + SSI_FAILED_NOTHING_SEARCH_ITEM = 0, // "No matching stores were found." + SSI_FAILED_OVER_MAXCOUNT = 1, // "There are too many results. Please enter more detailed search term." + SSI_FAILED_SEARCH_CNT = 2, // "You cannot search anymore." + SSI_FAILED_LIMIT_SEARCH_TIME = 3, // "You cannot search yet." + SSI_FAILED_SSILIST_CLICK_TO_OPEN_STORE = 4, // "No sale (purchase) information available." +}; + +/** + * Structures + **/ /// information about the search being performed struct s_search_store_search { struct map_session_data* search_sd; // sd of the searching player @@ -41,6 +75,13 @@ struct s_search_store_info { bool open; }; +/// type for shop search function +typedef bool (*searchstore_search_t)(struct map_session_data* sd, unsigned short nameid); +typedef bool (*searchstore_searchall_t)(struct map_session_data* sd, const struct s_search_store_search* s); + +/** + * Interface + **/ struct searchstore_interface { bool (*open) (struct map_session_data* sd, unsigned int uses, unsigned short effect); void (*query) (struct map_session_data* sd, unsigned char type, unsigned int min_price, unsigned int max_price, const unsigned short* itemlist, unsigned int item_count, const unsigned short* cardlist, unsigned int card_count); @@ -52,10 +93,10 @@ struct searchstore_interface { bool (*queryremote) (struct map_session_data* sd, int account_id); void (*clearremote) (struct map_session_data* sd); bool (*result) (struct map_session_data* sd, unsigned int store_id, int account_id, const char* store_name, unsigned short nameid, unsigned short amount, unsigned int price, const short* card, unsigned char refine); -} searchstore_s; +}; struct searchstore_interface *searchstore; void searchstore_defaults (void); -#endif // _SEARCHSTORE_H_ +#endif /* MAP_SEARCHSTORE_H */ diff --git a/src/map/skill.c b/src/map/skill.c index 685fec353..b82c47a69 100644 --- a/src/map/skill.c +++ b/src/map/skill.c @@ -2,122 +2,67 @@ // See the LICENSE file // Portions Copyright (c) Athena Dev Teams -#include "../common/cbasetypes.h" -#include "../common/timer.h" -#include "../common/nullpo.h" -#include "../common/malloc.h" -#include "../common/random.h" -#include "../common/showmsg.h" -#include "../common/strlib.h" -#include "../common/utils.h" -#include "../common/ers.h" +#define HERCULES_CORE -#include "map.h" -#include "path.h" -#include "clif.h" -#include "pc.h" -#include "status.h" +#include "../config/core.h" // DBPATH, MAGIC_REFLECTION_TYPE, OFFICIAL_WALKPATH, RENEWAL, RENEWAL_CAST, VARCAST_REDUCTION() #include "skill.h" -#include "pet.h" + +#include <math.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#include "battle.h" +#include "battleground.h" +#include "chrif.h" +#include "clif.h" +#include "date.h" +#include "elemental.h" +#include "guild.h" #include "homunculus.h" +#include "intif.h" +#include "itemdb.h" +#include "log.h" +#include "map.h" #include "mercenary.h" -#include "elemental.h" #include "mob.h" #include "npc.h" -#include "battle.h" -#include "battleground.h" #include "party.h" -#include "itemdb.h" +#include "path.h" +#include "pc.h" +#include "pet.h" #include "script.h" -#include "intif.h" -#include "log.h" -#include "chrif.h" -#include "guild.h" -#include "date.h" +#include "status.h" #include "unit.h" - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <time.h> -#include <math.h> - +#include "../common/cbasetypes.h" +#include "../common/ers.h" +#include "../common/malloc.h" +#include "../common/nullpo.h" +#include "../common/random.h" +#include "../common/showmsg.h" +#include "../common/strlib.h" +#include "../common/timer.h" +#include "../common/utils.h" #define SKILLUNITTIMER_INTERVAL 100 // ranges reserved for mapping skill ids to skilldb offsets -#define HM_SKILLRANGEMIN 700 -#define HM_SKILLRANGEMAX HM_SKILLRANGEMIN + MAX_HOMUNSKILL -#define MC_SKILLRANGEMIN HM_SKILLRANGEMAX + 1 -#define MC_SKILLRANGEMAX MC_SKILLRANGEMIN + MAX_MERCSKILL -#define EL_SKILLRANGEMIN MC_SKILLRANGEMAX + 1 -#define EL_SKILLRANGEMAX EL_SKILLRANGEMIN + MAX_ELEMENTALSKILL -#define GD_SKILLRANGEMIN EL_SKILLRANGEMAX + 1 -#define GD_SKILLRANGEMAX GD_SKILLRANGEMIN + MAX_GUILDSKILL +#define HM_SKILLRANGEMIN 750 +#define HM_SKILLRANGEMAX (HM_SKILLRANGEMIN + MAX_HOMUNSKILL) +#define MC_SKILLRANGEMIN (HM_SKILLRANGEMAX + 1) +#define MC_SKILLRANGEMAX (MC_SKILLRANGEMIN + MAX_MERCSKILL) +#define EL_SKILLRANGEMIN (MC_SKILLRANGEMAX + 1) +#define EL_SKILLRANGEMAX (EL_SKILLRANGEMIN + MAX_ELEMENTALSKILL) +#define GD_SKILLRANGEMIN (EL_SKILLRANGEMAX + 1) +#define GD_SKILLRANGEMAX (GD_SKILLRANGEMIN + MAX_GUILDSKILL) #if GD_SKILLRANGEMAX > 999 #error GD_SKILLRANGEMAX is greater than 999 #endif -static struct eri *skill_unit_ers = NULL; //For handling skill_unit's [Skotlex] -static struct eri *skill_timer_ers = NULL; //For handling skill_timerskills [Skotlex] - -DBMap* skillunit_db = NULL; // int id -> struct skill_unit* - -/** - * Skill Cool Down Delay Saving - * Struct skill_cd is not a member of struct map_session_data - * to keep cooldowns in memory between player log-ins. - * All cooldowns are reset when server is restarted. - **/ -DBMap* skillcd_db = NULL; // char_id -> struct skill_cd -struct skill_cd { - int duration[MAX_SKILL_TREE];//milliseconds - short skidx[MAX_SKILL_TREE];//the skill index entries belong to - short nameid[MAX_SKILL_TREE];//skill id - unsigned char cursor; -}; - -/** - * Skill Unit Persistency during endack routes (mostly for songs see bugreport:4574) - **/ -DBMap* skillusave_db = NULL; // char_id -> struct skill_usave -struct skill_usave { - uint16 skill_id, skill_lv; -}; - -struct s_skill_db skill_db[MAX_SKILL_DB]; -struct s_skill_produce_db skill_produce_db[MAX_SKILL_PRODUCE_DB]; -struct s_skill_arrow_db skill_arrow_db[MAX_SKILL_ARROW_DB]; -struct s_skill_abra_db skill_abra_db[MAX_SKILL_ABRA_DB]; -struct s_skill_improvise_db { - uint16 skill_id; - short per;//1-10000 -}; -struct s_skill_improvise_db skill_improvise_db[MAX_SKILL_IMPROVISE_DB]; -bool skill_reproduce_db[MAX_SKILL_DB]; -struct s_skill_changematerial_db { - int itemid; - short rate; - int qty[5]; - short qty_rate[5]; -}; -struct s_skill_changematerial_db skill_changematerial_db[MAX_SKILL_PRODUCE_DB]; - -//Warlock -struct s_skill_spellbook_db { - int nameid; - uint16 skill_id; - int point; -}; -struct s_skill_spellbook_db skill_spellbook_db[MAX_SKILL_SPELLBOOK_DB]; -//Guillotine Cross -struct s_skill_magicmushroom_db skill_magicmushroom_db[MAX_SKILL_MAGICMUSHROOM_DB]; +struct skill_interface skill_s; -struct s_skill_unit_layout skill_unit_layout[MAX_SKILL_UNIT_LAYOUT]; -int firewall_unit_pos; -int icewall_unit_pos; -int earthstrain_unit_pos; //Since only mob-casted splash skills can hit ice-walls static inline int splash_target(struct block_list* bl) { #ifndef RENEWAL @@ -132,7 +77,7 @@ int skill_name2id(const char* name) { if( name == NULL ) return 0; - return strdb_iget(skilldb_name2id, name); + return strdb_iget(skill->name2id_db, name); } /// Maps skill ids to skill db offsets. @@ -176,90 +121,91 @@ int skill_get_index( uint16 skill_id ) { } const char* skill_get_name( uint16 skill_id ) { - return skill_db[skill->get_index(skill_id)].name; + return skill->db[skill->get_index(skill_id)].name; } const char* skill_get_desc( uint16 skill_id ) { - return skill_db[skill->get_index(skill_id)].desc; + return skill->db[skill->get_index(skill_id)].desc; } // out of bounds error checking [celest] -void skill_chk(int16* skill_id) { +void skill_chk(uint16* skill_id) { *skill_id = skill->get_index(*skill_id); // checks/adjusts id } -#define skill_get(var,id) { skill->chk(&id); if(!id) return 0; return var; } -#define skill_get2(var,id,lv) { \ - skill->chk(&id); \ - if(!id) return 0; \ - if( lv >= MAX_SKILL_LEVEL && var > 1 ) { \ - int lv2 = lv; lv = skill_db[id].max; \ - return (var) + (lv2-lv);\ +#define skill_get(var,id) do { skill->chk(&(id)); if(!(id)) return 0; return (var); } while(0) +#define skill_get2(var,id,lv) do { \ + skill->chk(&(id)); \ + if(!(id)) return 0; \ + if( (lv) > MAX_SKILL_LEVEL && (var) > 1 ) { \ + int lv2__ = (lv); (lv) = skill->db[(id)].max; \ + return (var) + ((lv2__-(lv))/2);\ } \ - return var;\ -} -#define skill_glv(lv) min(lv,MAX_SKILL_LEVEL-1) + return (var);\ +} while(0) +#define skill_glv(lv) min((lv),MAX_SKILL_LEVEL-1) // Skill DB -int skill_get_hit( uint16 skill_id ) { skill_get (skill_db[skill_id].hit, skill_id); } -int skill_get_inf( uint16 skill_id ) { skill_get (skill_db[skill_id].inf, skill_id); } -int skill_get_ele( uint16 skill_id , uint16 skill_lv ) { skill_get (skill_db[skill_id].element[skill_glv(skill_lv-1)], skill_id); } -int skill_get_nk( uint16 skill_id ) { skill_get (skill_db[skill_id].nk, skill_id); } -int skill_get_max( uint16 skill_id ) { skill_get (skill_db[skill_id].max, skill_id); } -int skill_get_range( uint16 skill_id , uint16 skill_lv ) { skill_get2 (skill_db[skill_id].range[skill_glv(skill_lv-1)], skill_id, skill_lv); } -int skill_get_splash( uint16 skill_id , uint16 skill_lv ) { skill_get2 ( (skill_db[skill_id].splash[skill_glv(skill_lv-1)]>=0?skill_db[skill_id].splash[skill_glv(skill_lv-1)]:AREA_SIZE), skill_id, skill_lv); } -int skill_get_hp( uint16 skill_id ,uint16 skill_lv ) { skill_get2 (skill_db[skill_id].hp[skill_glv(skill_lv-1)], skill_id, skill_lv); } -int skill_get_sp( uint16 skill_id ,uint16 skill_lv ) { skill_get2 (skill_db[skill_id].sp[skill_glv(skill_lv-1)], skill_id, skill_lv); } -int skill_get_hp_rate(uint16 skill_id, uint16 skill_lv ) { skill_get2 (skill_db[skill_id].hp_rate[skill_glv(skill_lv-1)], skill_id, skill_lv); } -int skill_get_sp_rate(uint16 skill_id, uint16 skill_lv ) { skill_get2 (skill_db[skill_id].sp_rate[skill_glv(skill_lv-1)], skill_id, skill_lv); } -int skill_get_state(uint16 skill_id) { skill_get (skill_db[skill_id].state, skill_id); } -int skill_get_spiritball(uint16 skill_id, uint16 skill_lv) { skill_get2 (skill_db[skill_id].spiritball[skill_glv(skill_lv-1)], skill_id, skill_lv); } -int skill_get_itemid(uint16 skill_id, int idx) { skill_get (skill_db[skill_id].itemid[idx], skill_id); } -int skill_get_itemqty(uint16 skill_id, int idx) { skill_get (skill_db[skill_id].amount[idx], skill_id); } -int skill_get_zeny( uint16 skill_id ,uint16 skill_lv ) { skill_get2 (skill_db[skill_id].zeny[skill_glv(skill_lv-1)], skill_id, skill_lv); } -int skill_get_num( uint16 skill_id ,uint16 skill_lv ) { skill_get2 (skill_db[skill_id].num[skill_glv(skill_lv-1)], skill_id, skill_lv); } -int skill_get_cast( uint16 skill_id ,uint16 skill_lv ) { skill_get2 (skill_db[skill_id].cast[skill_glv(skill_lv-1)], skill_id, skill_lv); } -int skill_get_delay( uint16 skill_id ,uint16 skill_lv ) { skill_get2 (skill_db[skill_id].delay[skill_glv(skill_lv-1)], skill_id, skill_lv); } -int skill_get_walkdelay( uint16 skill_id ,uint16 skill_lv ) { skill_get2 (skill_db[skill_id].walkdelay[skill_glv(skill_lv-1)], skill_id, skill_lv); } -int skill_get_time( uint16 skill_id ,uint16 skill_lv ) { skill_get2 (skill_db[skill_id].upkeep_time[skill_glv(skill_lv-1)], skill_id, skill_lv); } -int skill_get_time2( uint16 skill_id ,uint16 skill_lv ) { skill_get2 (skill_db[skill_id].upkeep_time2[skill_glv(skill_lv-1)], skill_id, skill_lv); } -int skill_get_castdef( uint16 skill_id ) { skill_get (skill_db[skill_id].cast_def_rate, skill_id); } -int skill_get_weapontype( uint16 skill_id ) { skill_get (skill_db[skill_id].weapon, skill_id); } -int skill_get_ammotype( uint16 skill_id ) { skill_get (skill_db[skill_id].ammo, skill_id); } -int skill_get_ammo_qty( uint16 skill_id, uint16 skill_lv ) { skill_get2 (skill_db[skill_id].ammo_qty[skill_glv(skill_lv-1)], skill_id, skill_lv); } -int skill_get_inf2( uint16 skill_id ) { skill_get (skill_db[skill_id].inf2, skill_id); } -int skill_get_castcancel( uint16 skill_id ) { skill_get (skill_db[skill_id].castcancel, skill_id); } -int skill_get_maxcount( uint16 skill_id ,uint16 skill_lv ) { skill_get2 (skill_db[skill_id].maxcount[skill_glv(skill_lv-1)], skill_id, skill_lv); } -int skill_get_blewcount( uint16 skill_id ,uint16 skill_lv ) { skill_get2 (skill_db[skill_id].blewcount[skill_glv(skill_lv-1)], skill_id, skill_lv); } -int skill_get_mhp( uint16 skill_id ,uint16 skill_lv ) { skill_get2 (skill_db[skill_id].mhp[skill_glv(skill_lv-1)], skill_id, skill_lv); } -int skill_get_castnodex( uint16 skill_id ,uint16 skill_lv ) { skill_get2 (skill_db[skill_id].castnodex[skill_glv(skill_lv-1)], skill_id, skill_lv); } -int skill_get_delaynodex( uint16 skill_id ,uint16 skill_lv ){ skill_get2 (skill_db[skill_id].delaynodex[skill_glv(skill_lv-1)], skill_id, skill_lv); } -int skill_get_type( uint16 skill_id ) { skill_get (skill_db[skill_id].skill_type, skill_id); } -int skill_get_unit_id ( uint16 skill_id, int flag ){ skill_get (skill_db[skill_id].unit_id[flag], skill_id); } -int skill_get_unit_interval( uint16 skill_id ) { skill_get (skill_db[skill_id].unit_interval, skill_id); } -int skill_get_unit_range( uint16 skill_id, uint16 skill_lv ) { skill_get2 (skill_db[skill_id].unit_range[skill_glv(skill_lv-1)], skill_id, skill_lv); } -int skill_get_unit_target( uint16 skill_id ) { skill_get (skill_db[skill_id].unit_target&BCT_ALL, skill_id); } -int skill_get_unit_bl_target( uint16 skill_id ) { skill_get (skill_db[skill_id].unit_target&BL_ALL, skill_id); } -int skill_get_unit_flag( uint16 skill_id ) { skill_get (skill_db[skill_id].unit_flag, skill_id); } -int skill_get_unit_layout_type( uint16 skill_id ,uint16 skill_lv ){ skill_get2 (skill_db[skill_id].unit_layout_type[skill_glv(skill_lv-1)], skill_id, skill_lv); } -int skill_get_cooldown( uint16 skill_id, uint16 skill_lv ) { skill_get2 (skill_db[skill_id].cooldown[skill_glv(skill_lv-1)], skill_id, skill_lv); } +int skill_get_hit( uint16 skill_id ) { skill_get (skill->db[skill_id].hit, skill_id); } +int skill_get_inf( uint16 skill_id ) { skill_get (skill->db[skill_id].inf, skill_id); } +int skill_get_ele( uint16 skill_id , uint16 skill_lv ) { skill_get (skill->db[skill_id].element[skill_glv(skill_lv-1)], skill_id); } +int skill_get_nk( uint16 skill_id ) { skill_get (skill->db[skill_id].nk, skill_id); } +int skill_get_max( uint16 skill_id ) { skill_get (skill->db[skill_id].max, skill_id); } +int skill_get_range( uint16 skill_id , uint16 skill_lv ) { skill_get2 (skill->db[skill_id].range[skill_glv(skill_lv-1)], skill_id, skill_lv); } +int skill_get_splash( uint16 skill_id , uint16 skill_lv ) { skill_get2 ( (skill->db[skill_id].splash[skill_glv(skill_lv-1)]>=0?skill->db[skill_id].splash[skill_glv(skill_lv-1)]:AREA_SIZE), skill_id, skill_lv); } +int skill_get_hp( uint16 skill_id ,uint16 skill_lv ) { skill_get2 (skill->db[skill_id].hp[skill_glv(skill_lv-1)], skill_id, skill_lv); } +int skill_get_sp( uint16 skill_id ,uint16 skill_lv ) { skill_get2 (skill->db[skill_id].sp[skill_glv(skill_lv-1)], skill_id, skill_lv); } +int skill_get_hp_rate(uint16 skill_id, uint16 skill_lv ) { skill_get2 (skill->db[skill_id].hp_rate[skill_glv(skill_lv-1)], skill_id, skill_lv); } +int skill_get_sp_rate(uint16 skill_id, uint16 skill_lv ) { skill_get2 (skill->db[skill_id].sp_rate[skill_glv(skill_lv-1)], skill_id, skill_lv); } +int skill_get_state(uint16 skill_id) { skill_get (skill->db[skill_id].state, skill_id); } +int skill_get_spiritball(uint16 skill_id, uint16 skill_lv) { skill_get2 (skill->db[skill_id].spiritball[skill_glv(skill_lv-1)], skill_id, skill_lv); } +int skill_get_itemid(uint16 skill_id, int idx) { skill_get (skill->db[skill_id].itemid[idx], skill_id); } +int skill_get_itemqty(uint16 skill_id, int idx) { skill_get (skill->db[skill_id].amount[idx], skill_id); } +int skill_get_zeny( uint16 skill_id ,uint16 skill_lv ) { skill_get2 (skill->db[skill_id].zeny[skill_glv(skill_lv-1)], skill_id, skill_lv); } +int skill_get_num( uint16 skill_id ,uint16 skill_lv ) { skill_get2 (skill->db[skill_id].num[skill_glv(skill_lv-1)], skill_id, skill_lv); } +int skill_get_cast( uint16 skill_id ,uint16 skill_lv ) { skill_get2 (skill->db[skill_id].cast[skill_glv(skill_lv-1)], skill_id, skill_lv); } +int skill_get_delay( uint16 skill_id ,uint16 skill_lv ) { skill_get2 (skill->db[skill_id].delay[skill_glv(skill_lv-1)], skill_id, skill_lv); } +int skill_get_walkdelay( uint16 skill_id ,uint16 skill_lv ) { skill_get2 (skill->db[skill_id].walkdelay[skill_glv(skill_lv-1)], skill_id, skill_lv); } +int skill_get_time( uint16 skill_id ,uint16 skill_lv ) { skill_get2 (skill->db[skill_id].upkeep_time[skill_glv(skill_lv-1)], skill_id, skill_lv); } +int skill_get_time2( uint16 skill_id ,uint16 skill_lv ) { skill_get2 (skill->db[skill_id].upkeep_time2[skill_glv(skill_lv-1)], skill_id, skill_lv); } +int skill_get_castdef( uint16 skill_id ) { skill_get (skill->db[skill_id].cast_def_rate, skill_id); } +int skill_get_weapontype( uint16 skill_id ) { skill_get (skill->db[skill_id].weapon, skill_id); } +int skill_get_ammotype( uint16 skill_id ) { skill_get (skill->db[skill_id].ammo, skill_id); } +int skill_get_ammo_qty( uint16 skill_id, uint16 skill_lv ) { skill_get2 (skill->db[skill_id].ammo_qty[skill_glv(skill_lv-1)], skill_id, skill_lv); } +int skill_get_inf2( uint16 skill_id ) { skill_get (skill->db[skill_id].inf2, skill_id); } +int skill_get_castcancel( uint16 skill_id ) { skill_get (skill->db[skill_id].castcancel, skill_id); } +int skill_get_maxcount( uint16 skill_id ,uint16 skill_lv ) { skill_get2 (skill->db[skill_id].maxcount[skill_glv(skill_lv-1)], skill_id, skill_lv); } +int skill_get_blewcount( uint16 skill_id ,uint16 skill_lv ) { skill_get2 (skill->db[skill_id].blewcount[skill_glv(skill_lv-1)], skill_id, skill_lv); } +int skill_get_mhp( uint16 skill_id ,uint16 skill_lv ) { skill_get2 (skill->db[skill_id].mhp[skill_glv(skill_lv-1)], skill_id, skill_lv); } +int skill_get_castnodex( uint16 skill_id ,uint16 skill_lv ) { skill_get2 (skill->db[skill_id].castnodex[skill_glv(skill_lv-1)], skill_id, skill_lv); } +int skill_get_delaynodex( uint16 skill_id ,uint16 skill_lv ){ skill_get2 (skill->db[skill_id].delaynodex[skill_glv(skill_lv-1)], skill_id, skill_lv); } +int skill_get_type( uint16 skill_id ) { skill_get (skill->db[skill_id].skill_type, skill_id); } +int skill_get_unit_id ( uint16 skill_id, int flag ){ skill_get (skill->db[skill_id].unit_id[flag], skill_id); } +int skill_get_unit_interval( uint16 skill_id ) { skill_get (skill->db[skill_id].unit_interval, skill_id); } +int skill_get_unit_range( uint16 skill_id, uint16 skill_lv ) { skill_get2 (skill->db[skill_id].unit_range[skill_glv(skill_lv-1)], skill_id, skill_lv); } +int skill_get_unit_target( uint16 skill_id ) { skill_get (skill->db[skill_id].unit_target&BCT_ALL, skill_id); } +int skill_get_unit_bl_target( uint16 skill_id ) { skill_get (skill->db[skill_id].unit_target&BL_ALL, skill_id); } +int skill_get_unit_flag( uint16 skill_id ) { skill_get (skill->db[skill_id].unit_flag, skill_id); } +int skill_get_unit_layout_type( uint16 skill_id ,uint16 skill_lv ){ skill_get2 (skill->db[skill_id].unit_layout_type[skill_glv(skill_lv-1)], skill_id, skill_lv); } +int skill_get_cooldown( uint16 skill_id, uint16 skill_lv ) { skill_get2 (skill->db[skill_id].cooldown[skill_glv(skill_lv-1)], skill_id, skill_lv); } +int skill_get_fixed_cast( uint16 skill_id ,uint16 skill_lv ) { #ifdef RENEWAL_CAST -int skill_get_fixed_cast( uint16 skill_id ,uint16 skill_lv ){ skill_get2 (skill_db[skill_id].fixed_cast[skill_glv(skill_lv-1)], skill_id, skill_lv); } + skill_get2 (skill->db[skill_id].fixed_cast[skill_glv(skill_lv-1)], skill_id, skill_lv); +#else + return 0; #endif +} int skill_tree_get_max(uint16 skill_id, int b_class) { int i; b_class = pc->class2idx(b_class); - ARR_FIND( 0, MAX_SKILL_TREE, i, skill_tree[b_class][i].id == 0 || skill_tree[b_class][i].id == skill_id ); - if( i < MAX_SKILL_TREE && skill_tree[b_class][i].id == skill_id ) - return skill_tree[b_class][i].max; + ARR_FIND( 0, MAX_SKILL_TREE, i, pc->skill_tree[b_class][i].id == 0 || pc->skill_tree[b_class][i].id == skill_id ); + if( i < MAX_SKILL_TREE && pc->skill_tree[b_class][i].id == skill_id ) + return pc->skill_tree[b_class][i].max; else return skill->get_max(skill_id); } -int enchant_eff[5] = { 10, 14, 17, 19, 20 }; -int deluge_eff[5] = { 5, 9, 12, 14, 15 }; - int skill_get_casttype (uint16 skill_id) { int inf = skill->get_inf(skill_id); if (inf&(INF_GROUND_SKILL)) @@ -277,17 +223,17 @@ int skill_get_casttype (uint16 skill_id) { } int skill_get_casttype2 (uint16 index) { - int inf = skill_db[index].inf; + int inf = skill->db[index].inf; if (inf&(INF_GROUND_SKILL)) return CAST_GROUND; if (inf&INF_SUPPORT_SKILL) return CAST_NODAMAGE; if (inf&INF_SELF_SKILL) { - if(skill_db[index].inf2&INF2_NO_TARGET_SELF) + if(skill->db[index].inf2&INF2_NO_TARGET_SELF) return CAST_DAMAGE; //Combo skill. return CAST_NODAMAGE; } - if (skill_db[index].nk&NK_NO_DAMAGE) + if (skill->db[index].nk&NK_NO_DAMAGE) return CAST_NODAMAGE; return CAST_DAMAGE; } @@ -379,18 +325,20 @@ int skill_get_range2 (struct block_list *bl, uint16 skill_id, uint16 skill_lv) { } int skill_calc_heal(struct block_list *src, struct block_list *target, uint16 skill_id, uint16 skill_lv, bool heal) { - int skill, hp; + int skill2_lv, hp; struct map_session_data *sd = BL_CAST(BL_PC, src); struct map_session_data *tsd = BL_CAST(BL_PC, target); struct status_change* sc; + nullpo_ret(src); + switch( skill_id ) { case BA_APPLEIDUN: - #ifdef RENEWAL +#ifdef RENEWAL hp = 100+5*skill_lv+5*(status_get_vit(src)/10); // HP recovery - #else +#else // not RENEWAL hp = 30+5*skill_lv+5*(status_get_vit(src)/10); // HP recovery - #endif +#endif // RENEWAL if( sd ) hp += 5*pc->checkskill(sd,BA_MUSICALLESSON); break; @@ -403,32 +351,37 @@ int skill_calc_heal(struct block_list *src, struct block_list *target, uint16 sk default: if (skill_lv >= battle_config.max_heal_lv) return battle_config.max_heal; - #ifdef RENEWAL - /** - * Renewal Heal Formula - * Formula: ( [(Base Level + INT) / 5] ? 30 ) ? (Heal Level / 10) ? (Modifiers) + MATK - **/ - hp = (status_get_lv(src) + status_get_int(src)) / 5 * 30 * skill_lv / 10; - #else - hp = ( status_get_lv(src) + status_get_int(src) ) / 8 * (4 + ( skill_id == AB_HIGHNESSHEAL ? ( sd ? pc->checkskill(sd,AL_HEAL) : 10 ) : skill_lv ) * 8); - #endif - if( sd && ((skill = pc->checkskill(sd, HP_MEDITATIO)) > 0) ) - hp += hp * skill * 2 / 100; - else if( src->type == BL_HOM && (skill = homun->checkskill(((TBL_HOM*)src), HLIF_BRAIN)) > 0 ) - hp += hp * skill * 2 / 100; +#ifdef RENEWAL + /** + * Renewal Heal Formula + * Formula: ( [(Base Level + INT) / 5] ? 30 ) ? (Heal Level / 10) ? (Modifiers) + MATK + **/ + hp = (status->get_lv(src) + status_get_int(src)) / 5 * 30 * skill_lv / 10; +#else // not RENEWAL + hp = ( status->get_lv(src) + status_get_int(src) ) / 8 * (4 + ( skill_id == AB_HIGHNESSHEAL ? ( sd ? pc->checkskill(sd,AL_HEAL) : 10 ) : skill_lv ) * 8); +#endif // RENEWAL + if( sd && ((skill2_lv = pc->checkskill(sd, HP_MEDITATIO)) > 0) ) + hp += hp * skill2_lv * 2 / 100; + else if( src->type == BL_HOM && (skill2_lv = homun->checkskill(((TBL_HOM*)src), HLIF_BRAIN)) > 0 ) + hp += hp * skill2_lv * 2 / 100; break; } if( ( (target && target->type == BL_MER) || !heal ) && skill_id != NPC_EVILLAND ) hp >>= 1; - if( sd && (skill = pc->skillheal_bonus(sd, skill_id)) ) - hp += hp*skill/100; + if( sd && (skill2_lv = pc->skillheal_bonus(sd, skill_id)) ) + hp += hp*skill2_lv/100; - if( tsd && (skill = pc->skillheal2_bonus(tsd, skill_id)) ) - hp += hp*skill/100; + if( tsd && (skill2_lv = pc->skillheal2_bonus(tsd, skill_id)) ) + hp += hp*skill2_lv/100; - sc = status_get_sc(target); + sc = status->get_sc(src); + if( sc && sc->count && sc->data[SC_OFFERTORIUM] ) { + if( skill_id == AB_HIGHNESSHEAL || skill_id == AB_CHEAL || skill_id == PR_SANCTUARY || skill_id == AL_HEAL ) + hp += hp * sc->data[SC_OFFERTORIUM]->val2 / 100; + } + sc = status->get_sc(target); if( sc && sc->count ) { if( sc->data[SC_CRITICALWOUND] && heal ) // Critical Wound has no effect on offensive heal. [Inkfish] hp -= hp * sc->data[SC_CRITICALWOUND]->val2/100; @@ -438,20 +391,22 @@ int skill_calc_heal(struct block_list *src, struct block_list *target, uint16 sk hp += hp * sc->data[SC_HEALPLUS]->val1/100; // Only affects Heal, Sanctuary and PotionPitcher.(like bHealPower) [Inkfish] if( sc->data[SC_WATER_INSIGNIA] && sc->data[SC_WATER_INSIGNIA]->val1 == 2) hp += hp / 10; - if( sc->data[SC_OFFERTORIUM] && (skill_id == AB_HIGHNESSHEAL || skill_id == AB_CHEAL || skill_id == PR_SANCTUARY || skill_id == AL_HEAL) ) - hp += hp * sc->data[SC_OFFERTORIUM]->val2 / 100; + if ( sc && sc->data[SC_VITALITYACTIVATION] ) + hp = hp * 150 / 100; } #ifdef RENEWAL - // MATK part of the RE heal formula [malufett] - // Note: in this part matk bonuses from items or skills are not applied + // MATK part of the RE heal formula [malufett] + // Note: in this part matk bonuses from items or skills are not applied switch( skill_id ) { - case BA_APPLEIDUN: case PR_SANCTUARY: - case NPC_EVILLAND: break; + case BA_APPLEIDUN: + case PR_SANCTUARY: + case NPC_EVILLAND: + break; default: - hp += status_get_matk(src, 3); + hp += status->get_matk(src, 3); } -#endif +#endif // RENEWAL return hp; } @@ -478,10 +433,14 @@ int can_copy (struct map_session_data *sd, uint16 skill_id, struct block_list* b return 0; // Couldn't preserve 3rd Class skills except only when using Reproduce skill. [Jobbie] - if( !(sd->sc.data[SC__REPRODUCE]) && (skill_id >= RK_ENCHANTBLADE && skill_id <= SR_RIDEINLIGHTNING) ) + if( !(sd->sc.data[SC__REPRODUCE]) && ((skill_id >= RK_ENCHANTBLADE && skill_id <= SR_RIDEINLIGHTNING) || (skill_id >= KO_YAMIKUMO && skill_id <= OB_AKAITSUKI))) return 0; // Reproduce will only copy skills according on the list. [Jobbie] - else if( sd->sc.data[SC__REPRODUCE] && !skill_reproduce_db[skill->get_index(skill_id)] ) + else if( sd->sc.data[SC__REPRODUCE] && !skill->reproduce_db[skill->get_index(skill_id)] ) + return 0; + + //Never copy new 3rd class skills By OmegaRed + if(skill_id >= GC_DARKCROW && skill_id <= ALL_FULL_THROTTLE) return 0; return 1; @@ -509,12 +468,12 @@ int skillnotok (uint16 skill_id, struct map_session_data *sd) // allowing a skill to be cast. This is to prevent no-delay ACT files from spamming skills such as // AC_DOUBLE which do not have a skill delay and are not regarded in terms of attack motion. if( !sd->state.autocast && sd->skillitem != skill_id && sd->canskill_tick && - DIFF_TICK(iTimer->gettick(), sd->canskill_tick) < (sd->battle_status.amotion * (battle_config.skill_amotion_leniency) / 100) ) + DIFF_TICK(timer->gettick(), sd->canskill_tick) < (sd->battle_status.amotion * (battle_config.skill_amotion_leniency) / 100) ) {// attempted to cast a skill before the attack motion has finished return 1; } - if (sd->blockskill[idx] > 0) { + if (sd->blockskill[idx]) { clif->skill_fail(sd, skill_id, USESKILL_FAIL_SKILLINTERVAL, 0); return 1; } @@ -533,7 +492,7 @@ int skillnotok (uint16 skill_id, struct map_session_data *sd) case AL_WARP: case RETURN_TO_ELDICASTES: case ALL_GUARDIAN_RECALL: - if(map[m].flag.nowarp) { + if(map->list[m].flag.nowarp) { clif->skill_mapinfomessage(sd,0); return 1; } @@ -541,7 +500,7 @@ int skillnotok (uint16 skill_id, struct map_session_data *sd) case AL_TELEPORT: case SC_FATALMENACE: case SC_DIMENSIONDOOR: - if(map[m].flag.noteleport) { + if(map->list[m].flag.noteleport) { clif->skill_mapinfomessage(sd,0); return 1; } @@ -549,17 +508,17 @@ int skillnotok (uint16 skill_id, struct map_session_data *sd) case WE_CALLPARTNER: case WE_CALLPARENT: case WE_CALLBABY: - if (map[m].flag.nomemo) { + if (map->list[m].flag.nomemo) { clif->skill_mapinfomessage(sd,1); return 1; } break; case MC_VENDING: case ALL_BUYING_STORE: - if( npc_isnear(&sd->bl) ) { + if( npc->isnear(&sd->bl) ) { // uncomment for more verbose message. //char output[150]; - //sprintf(output, msg_txt(662), battle_config.min_npc_vendchat_distance); + //sprintf(output, msg_txt(862), battle_config.min_npc_vendchat_distance); // "You're too close to a NPC, you must be at least %d cells away from any NPC." //clif->message(sd->fd, output); clif->skill_fail(sd,skill_id,USESKILL_FAIL_THERE_ARE_NPC_AROUND,0); return 1; @@ -568,50 +527,31 @@ int skillnotok (uint16 skill_id, struct map_session_data *sd) return 0; // always allowed case WZ_ICEWALL: // noicewall flag [Valaris] - if (map[m].flag.noicewall) { + if (map->list[m].flag.noicewall) { clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); return 1; } break; case GC_DARKILLUSION: - if( map_flag_gvg(m) ) { + if( map_flag_gvg2(m) ) { clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); return 1; } break; case GD_EMERGENCYCALL: - if ( - !(battle_config.emergency_call&((iMap->agit_flag || iMap->agit2_flag)?2:1)) || - !(battle_config.emergency_call&(map[m].flag.gvg || map[m].flag.gvg_castle?8:4)) || - (battle_config.emergency_call&16 && map[m].flag.nowarpto && !map[m].flag.gvg_castle) - ) { + if( !(battle_config.emergency_call&((map->agit_flag || map->agit2_flag)?2:1)) + || !(battle_config.emergency_call&(map->list[m].flag.gvg || map->list[m].flag.gvg_castle?8:4)) + || (battle_config.emergency_call&16 && map->list[m].flag.nowarpto && !map->list[m].flag.gvg_castle) + ) { clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); return 1; } break; - case BS_GREED: - case WS_CARTBOOST: - case BS_HAMMERFALL: - case BS_ADRENALINE: - case MC_CARTREVOLUTION: - case MC_MAMMONITE: - case WS_MELTDOWN: - case MG_SIGHT: - case TF_HIDING: - /** - * These skills cannot be used while in mado gear (credits to Xantara) - **/ - if( pc_ismadogear(sd) ) { - clif->skill_fail(sd,skill_id,USESKILL_FAIL_MADOGEAR_RIDE,0); - return 1; - } - break; - case WM_SIRCLEOFNATURE: - case WM_SOUND_OF_DESTRUCTION: case SC_MANHOLE: - case WM_LULLABY_DEEPSLEEP: + case WM_SOUND_OF_DESTRUCTION: case WM_SATURDAY_NIGHT_FEVER: + case WM_LULLABY_DEEPSLEEP: if( !map_flag_vs(m) ) { clif->skill_mapinfomessage(sd,2); // This skill uses this msg instead of skill fails. return 1; @@ -619,7 +559,7 @@ int skillnotok (uint16 skill_id, struct map_session_data *sd) break; } - return (map[m].flag.noskill); + return (map->list[m].flag.noskill); } int skillnotok_hom(uint16 skill_id, struct homun_data *hd) @@ -634,12 +574,12 @@ int skillnotok_hom(uint16 skill_id, struct homun_data *hd) return 1; switch(skill_id){ case MH_LIGHT_OF_REGENE: - if(hd->homunculus.intimacy <= 750) //if not cordial - return 1; - break; - case MH_OVERED_BOOST: - if(hd->homunculus.hunger <= 1) //if we starving - return 1; + if( homun->get_intimacy_grade(hd) != 4 ){ + if( hd->master ) + clif->skill_fail(hd->master, skill_id, USESKILL_FAIL_RELATIONGRADE, 0); + return 1; + } + break; case MH_GOLDENE_FERSE: //can be used with angriff if(hd->sc.data[SC_ANGRIFFS_MODUS]) return 1; @@ -676,32 +616,30 @@ struct s_skill_unit_layout* skill_get_unit_layout (uint16 skill_id, uint16 skill } if (pos != -1) // simple single-definition layout - return &skill_unit_layout[pos]; + return &skill->unit_layout[pos]; - dir = (src->x == x && src->y == y) ? 6 : iMap->calc_dir(src,x,y); // 6 - default aegis direction + dir = (src->x == x && src->y == y) ? 6 : map->calc_dir(src,x,y); // 6 - default aegis direction if (skill_id == MG_FIREWALL) - return &skill_unit_layout [firewall_unit_pos + dir]; + return &skill->unit_layout [skill->firewall_unit_pos + dir]; else if (skill_id == WZ_ICEWALL) - return &skill_unit_layout [icewall_unit_pos + dir]; + return &skill->unit_layout [skill->icewall_unit_pos + dir]; else if( skill_id == WL_EARTHSTRAIN ) //Warlock - return &skill_unit_layout [earthstrain_unit_pos + dir]; + return &skill->unit_layout [skill->earthstrain_unit_pos + dir]; ShowError("skill_get_unit_layout: unknown unit layout for skill %d (level %d)\n", skill_id, skill_lv); - return &skill_unit_layout[0]; // default 1x1 layout + return &skill->unit_layout[0]; // default 1x1 layout } /*========================================== * *------------------------------------------*/ -int skill_additional_effect (struct block_list* src, struct block_list *bl, uint16 skill_id, uint16 skill_lv, int attack_type, int dmg_lv, unsigned int tick) -{ +int skill_additional_effect(struct block_list* src, struct block_list *bl, uint16 skill_id, uint16 skill_lv, int attack_type, int dmg_lv, int64 tick) { struct map_session_data *sd, *dstsd; struct mob_data *md, *dstmd; struct status_data *sstatus, *tstatus; struct status_change *sc, *tsc; - enum sc_type status; int temp; int rate; @@ -718,10 +656,10 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, uint dstsd = BL_CAST(BL_PC, bl); dstmd = BL_CAST(BL_MOB, bl); - sc = status_get_sc(src); - tsc = status_get_sc(bl); - sstatus = status_get_status_data(src); - tstatus = status_get_status_data(bl); + sc = status->get_sc(src); + tsc = status->get_sc(bl); + sstatus = status->get_status_data(src); + tstatus = status->get_status_data(bl); if (!tsc) //skill additional effect is about adding effects to the target... //So if the target can't be inflicted with statuses, this is pointless. return 0; @@ -754,13 +692,13 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, uint } type = sd->addeff[i].id; - temp = skill->get_time2(status_sc2skill(type),7); + temp = skill->get_time2(status->sc2skill(type),7); if (sd->addeff[i].flag&ATF_TARGET) - status_change_start(bl,type,rate,7,0,0,0,temp,0); + status->change_start(src,bl,type,rate,7,0,(type == SC_BURNING)?src->id:0,0,temp,0); if (sd->addeff[i].flag&ATF_SELF) - status_change_start(src,type,rate,7,0,0,0,temp,0); + status->change_start(src,src,type,rate,7,0,(type == SC_BURNING)?src->id:0,0,temp,0); } } @@ -772,12 +710,12 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, uint if( skill_id != sd->addeff3[i].skill || !sd->addeff3[i].rate ) continue; type = sd->addeff3[i].id; - temp = skill->get_time2(status_sc2skill(type),7); + temp = skill->get_time2(status->sc2skill(type),7); if( sd->addeff3[i].target&ATF_TARGET ) - status_change_start(bl,type,sd->addeff3[i].rate,7,0,0,0,temp,0); + status->change_start(src,bl,type,sd->addeff3[i].rate,7,0,0,0,temp,0); if( sd->addeff3[i].target&ATF_SELF ) - status_change_start(src,type,sd->addeff3[i].rate,7,0,0,0,temp,0); + status->change_start(src,src,type,sd->addeff3[i].rate,7,0,0,0,temp,0); } } } @@ -811,15 +749,18 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, uint // Chance to trigger Taekwon kicks [Dralnu] if(sc && !sc->data[SC_COMBOATTACK]) { if(sc->data[SC_STORMKICK_READY] && - sc_start(src,SC_COMBOATTACK, 15, TK_STORMKICK, + sc_start4(src,src,SC_COMBOATTACK, 15, TK_STORMKICK, + bl->id, 2, 0, (2000 - 4*sstatus->agi - 2*sstatus->dex))) ; //Stance triggered else if(sc->data[SC_DOWNKICK_READY] && - sc_start(src,SC_COMBOATTACK, 15, TK_DOWNKICK, + sc_start4(src,src,SC_COMBOATTACK, 15, TK_DOWNKICK, + bl->id, 2, 0, (2000 - 4*sstatus->agi - 2*sstatus->dex))) ; //Stance triggered else if(sc->data[SC_TURNKICK_READY] && - sc_start(src,SC_COMBOATTACK, 15, TK_TURNKICK, + sc_start4(src,src,SC_COMBOATTACK, 15, TK_TURNKICK, + bl->id, 2, 0, (2000 - 4*sstatus->agi - 2*sstatus->dex))) ; //Stance triggered else if (sc->data[SC_COUNTERKICK_READY]) { //additional chance from SG_FRIEND [Komurka] @@ -828,7 +769,7 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, uint rate += rate*sc->data[SC_SKILLRATE_UP]->val2/100; status_change_end(src, SC_SKILLRATE_UP, INVALID_TIMER); } - sc_start2(src, SC_COMBOATTACK, rate, TK_COUNTER, bl->id, + sc_start2(src, src, SC_COMBOATTACK, rate, TK_COUNTER, bl->id, (2000 - 4*sstatus->agi - 2*sstatus->dex)); } } @@ -840,26 +781,24 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, uint struct status_change_entry *sce; // Enchant Poison gives a chance to poison attacked enemies if((sce=sc->data[SC_ENCHANTPOISON])) //Don't use sc_start since chance comes in 1/10000 rate. - status_change_start(bl,SC_POISON,sce->val2, sce->val1,src->id,0,0, + status->change_start(src,bl,SC_POISON,sce->val2, sce->val1,src->id,0,0, skill->get_time2(AS_ENCHANTPOISON,sce->val1),0); // Enchant Deadly Poison gives a chance to deadly poison attacked enemies if((sce=sc->data[SC_EDP])) - sc_start4(bl,SC_DPOISON,sce->val2, sce->val1,src->id,0,0, + sc_start4(src,bl,SC_DPOISON,sce->val2, sce->val1,src->id,0,0, skill->get_time2(ASC_EDP,sce->val1)); } } break; case SM_BASH: - if( sd && skill_lv > 5 && pc->checkskill(sd,SM_FATALBLOW)>0 ){ - //TODO: How much % per base level it actually is? - sc_start(bl,SC_STUN,(5*(skill_lv-5)+(int)sd->status.base_level/10), - skill_lv,skill->get_time2(SM_FATALBLOW,skill_lv)); - } + if( sd && skill_lv > 5 && pc->checkskill(sd,SM_FATALBLOW)>0 ) + status->change_start(src,bl,SC_STUN,500*(skill_lv-5)*sd->status.base_level/50, + skill_lv,0,0,0,skill->get_time2(SM_FATALBLOW,skill_lv),0); break; case MER_CRASH: - sc_start(bl,SC_STUN,(6*skill_lv),skill_lv,skill->get_time2(skill_id,skill_lv)); + sc_start(src,bl,SC_STUN,(6*skill_lv),skill_lv,skill->get_time2(skill_id,skill_lv)); break; case AS_VENOMKNIFE: @@ -867,30 +806,32 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, uint skill_lv = pc->checkskill(sd, TF_POISON); case TF_POISON: case AS_SPLASHER: - if(!sc_start2(bl,SC_POISON,(4*skill_lv+10),skill_lv,src->id,skill->get_time2(skill_id,skill_lv)) + if(!sc_start2(src,bl,SC_POISON,(4*skill_lv+10),skill_lv,src->id,skill->get_time2(skill_id,skill_lv)) && sd && skill_id==TF_POISON ) clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); break; case AS_SONICBLOW: - sc_start(bl,SC_STUN,(2*skill_lv+10),skill_lv,skill->get_time2(skill_id,skill_lv)); + sc_start(src,bl,SC_STUN,(2*skill_lv+10),skill_lv,skill->get_time2(skill_id,skill_lv)); break; case WZ_FIREPILLAR: - unit_set_walkdelay(bl, tick, skill->get_time2(skill_id, skill_lv), 1); + unit->set_walkdelay(bl, tick, skill->get_time2(skill_id, skill_lv), 1); break; case MG_FROSTDIVER: #ifndef RENEWAL case WZ_FROSTNOVA: #endif - sc_start(bl,SC_FREEZE,skill_lv*3+35,skill_lv,skill->get_time2(skill_id,skill_lv)); + if( !sc_start(src,bl,SC_FREEZE,skill_lv*3+35,skill_lv,skill->get_time2(skill_id,skill_lv)) + && sd && skill_id == MG_FROSTDIVER ) + clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); break; #ifdef RENEWAL case WZ_FROSTNOVA: - sc_start(bl,SC_FREEZE,skill_lv*5+33,skill_lv,skill->get_time2(skill_id,skill_lv)); + sc_start(src,bl,SC_FREEZE,skill_lv*5+33,skill_lv,skill->get_time2(skill_id,skill_lv)); break; #endif @@ -899,11 +840,11 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, uint * Storm Gust counter was dropped in renewal **/ #ifdef RENEWAL - sc_start(bl,SC_FREEZE,65-(5*skill_lv),skill_lv,skill->get_time2(skill_id,skill_lv)); + sc_start(src,bl,SC_FREEZE,65-(5*skill_lv),skill_lv,skill->get_time2(skill_id,skill_lv)); #else - //Tharis pointed out that this is normal freeze chance with a base of 300% + // [Tharis] pointed out that this is normal freeze chance with a base of 300% if(tsc->sg_counter >= 3 && - sc_start(bl,SC_FREEZE,300,skill_lv,skill->get_time2(skill_id,skill_lv))) + sc_start(src,bl,SC_FREEZE,300,skill_lv,skill->get_time2(skill_id,skill_lv))) tsc->sg_counter = 0; /** * being it only resets on success it'd keep stacking and eventually overflowing on mvps, so we reset at a high value @@ -914,25 +855,25 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, uint break; case WZ_METEOR: - sc_start(bl,SC_STUN,3*skill_lv,skill_lv,skill->get_time2(skill_id,skill_lv)); + sc_start(src,bl,SC_STUN,3*skill_lv,skill_lv,skill->get_time2(skill_id,skill_lv)); break; case WZ_VERMILION: - sc_start(bl,SC_BLIND,4*skill_lv,skill_lv,skill->get_time2(skill_id,skill_lv)); + sc_start(src,bl,SC_BLIND,4*skill_lv,skill_lv,skill->get_time2(skill_id,skill_lv)); break; case HT_FREEZINGTRAP: case MA_FREEZINGTRAP: - sc_start(bl,SC_FREEZE,(3*skill_lv+35),skill_lv,skill->get_time2(skill_id,skill_lv)); + sc_start(src,bl,SC_FREEZE,(3*skill_lv+35),skill_lv,skill->get_time2(skill_id,skill_lv)); break; case HT_FLASHER: - sc_start(bl,SC_BLIND,(10*skill_lv+30),skill_lv,skill->get_time2(skill_id,skill_lv)); + sc_start(src,bl,SC_BLIND,(10*skill_lv+30),skill_lv,skill->get_time2(skill_id,skill_lv)); break; case HT_LANDMINE: case MA_LANDMINE: - sc_start(bl,SC_STUN,(5*skill_lv+30),skill_lv,skill->get_time2(skill_id,skill_lv)); + sc_start(src,bl,SC_STUN,(5*skill_lv+30),skill_lv,skill->get_time2(skill_id,skill_lv)); break; case HT_SHOCKWAVE: @@ -941,33 +882,32 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, uint case HT_SANDMAN: case MA_SANDMAN: - sc_start(bl,SC_SLEEP,(10*skill_lv+40),skill_lv,skill->get_time2(skill_id,skill_lv)); + sc_start(src,bl,SC_SLEEP,(10*skill_lv+40),skill_lv,skill->get_time2(skill_id,skill_lv)); break; case TF_SPRINKLESAND: - sc_start(bl,SC_BLIND,20,skill_lv,skill->get_time2(skill_id,skill_lv)); + sc_start(src,bl,SC_BLIND,20,skill_lv,skill->get_time2(skill_id,skill_lv)); break; case TF_THROWSTONE: - sc_start(bl,SC_STUN,3,skill_lv,skill->get_time(skill_id,skill_lv)); - sc_start(bl,SC_BLIND,3,skill_lv,skill->get_time2(skill_id,skill_lv)); + if( !sc_start(src,bl,SC_STUN,3,skill_lv,skill->get_time(skill_id,skill_lv)) ) + sc_start(src,bl,SC_BLIND,3,skill_lv,skill->get_time2(skill_id,skill_lv)); break; case NPC_DARKCROSS: case CR_HOLYCROSS: - sc_start(bl,SC_BLIND,3*skill_lv,skill_lv,skill->get_time2(skill_id,skill_lv)); + sc_start(src,bl,SC_BLIND,3*skill_lv,skill_lv,skill->get_time2(skill_id,skill_lv)); break; case CR_GRANDCROSS: case NPC_GRANDDARKNESS: //Chance to cause blind status vs demon and undead element, but not against players if(!dstsd && (battle->check_undead(tstatus->race,tstatus->def_ele) || tstatus->race == RC_DEMON)) - sc_start(bl,SC_BLIND,100,skill_lv,skill->get_time2(skill_id,skill_lv)); - attack_type |= BF_WEAPON; + sc_start(src,bl,SC_BLIND,100,skill_lv,skill->get_time2(skill_id,skill_lv)); break; case AM_ACIDTERROR: - sc_start2(bl,SC_BLOODING,(skill_lv*3),skill_lv,src->id,skill->get_time2(skill_id,skill_lv)); + sc_start2(src,bl,SC_BLOODING,(skill_lv*3),skill_lv,src->id,skill->get_time2(skill_id,skill_lv)); if (skill->break_equip(bl, EQP_ARMOR, 100*skill->get_time(skill_id,skill_lv), BCT_ENEMY)) clif->emotion(bl,E_OMG); break; @@ -977,7 +917,7 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, uint break; case CR_SHIELDCHARGE: - sc_start(bl,SC_STUN,(15+skill_lv*5),skill_lv,skill->get_time2(skill_id,skill_lv)); + sc_start(src,bl,SC_STUN,(15+skill_lv*5),skill_lv,skill->get_time2(skill_id,skill_lv)); break; case PA_PRESSURE: @@ -985,28 +925,28 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, uint break; case RG_RAID: - sc_start(bl,SC_STUN,(10+3*skill_lv),skill_lv,skill->get_time(skill_id,skill_lv)); - sc_start(bl,SC_BLIND,(10+3*skill_lv),skill_lv,skill->get_time2(skill_id,skill_lv)); + sc_start(src,bl,SC_STUN,(10+3*skill_lv),skill_lv,skill->get_time(skill_id,skill_lv)); + sc_start(src,bl,SC_BLIND,(10+3*skill_lv),skill_lv,skill->get_time2(skill_id,skill_lv)); #ifdef RENEWAL - sc_start(bl,SC_RAID,100,7,5000); + sc_start(src,bl,SC_RAID,100,7,5000); break; case RG_BACKSTAP: - sc_start(bl,SC_STUN,(5+2*skill_lv),skill_lv,skill->get_time(skill_id,skill_lv)); + sc_start(src,bl,SC_STUN,(5+2*skill_lv),skill_lv,skill->get_time(skill_id,skill_lv)); #endif break; case BA_FROSTJOKER: - sc_start(bl,SC_FREEZE,(15+5*skill_lv),skill_lv,skill->get_time2(skill_id,skill_lv)); + sc_start(src,bl,SC_FREEZE,(15+5*skill_lv),skill_lv,skill->get_time2(skill_id,skill_lv)); break; case DC_SCREAM: - sc_start(bl,SC_STUN,(25+5*skill_lv),skill_lv,skill->get_time2(skill_id,skill_lv)); + sc_start(src,bl,SC_STUN,(25+5*skill_lv),skill_lv,skill->get_time2(skill_id,skill_lv)); break; case BD_LULLABY: - sc_start(bl,SC_SLEEP,15,skill_lv,skill->get_time2(skill_id,skill_lv)); + sc_start(src,bl,SC_SLEEP,15,skill_lv,skill->get_time2(skill_id,skill_lv)); break; case DC_UGLYDANCE: @@ -1017,11 +957,11 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, uint break; case SL_STUN: if (tstatus->size==SZ_MEDIUM) //Only stuns mid-sized mobs. - sc_start(bl,SC_STUN,(30+10*skill_lv),skill_lv,skill->get_time(skill_id,skill_lv)); + sc_start(src,bl,SC_STUN,(30+10*skill_lv),skill_lv,skill->get_time(skill_id,skill_lv)); break; case NPC_PETRIFYATTACK: - sc_start4(bl,status_skill2sc(skill_id),50+10*skill_lv, + sc_start4(src,bl,status->skill2sc(skill_id),50+10*skill_lv, skill_lv,0,0,skill->get_time(skill_id,skill_lv), skill->get_time2(skill_id,skill_lv)); break; @@ -1032,19 +972,20 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, uint case NPC_SILENCEATTACK: case NPC_STUNATTACK: case NPC_HELLPOWER: - sc_start(bl,status_skill2sc(skill_id),50+10*skill_lv,skill_lv,skill->get_time2(skill_id,skill_lv)); + sc_start(src,bl,status->skill2sc(skill_id),50+10*skill_lv,skill_lv,skill->get_time2(skill_id,skill_lv)); break; case NPC_ACIDBREATH: case NPC_ICEBREATH: - sc_start(bl,status_skill2sc(skill_id),70,skill_lv,skill->get_time2(skill_id,skill_lv)); + sc_start(src,bl,status->skill2sc(skill_id),70,skill_lv,skill->get_time2(skill_id,skill_lv)); break; case NPC_BLEEDING: - sc_start2(bl,SC_BLOODING,(20*skill_lv),skill_lv,src->id,skill->get_time2(skill_id,skill_lv)); + sc_start2(src,bl,SC_BLOODING,(20*skill_lv),skill_lv,src->id,skill->get_time2(skill_id,skill_lv)); break; case NPC_MENTALBREAKER: - { //Based on observations by Tharis, Mental Breaker should do SP damage + { + //Based on observations by [Tharis], Mental Breaker should do SP damage //equal to Matk*skLevel. - rate = status_get_matk(src, 2); + rate = status->get_matk(src, 2); rate*=skill_lv; status_zap(bl, 0, rate); break; @@ -1064,32 +1005,32 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, uint break; case CH_TIGERFIST: - sc_start(bl,SC_STOP,(10+skill_lv*10),0,skill->get_time2(skill_id,skill_lv)); + sc_start(src,bl,SC_STOP,(10+skill_lv*10),0,skill->get_time2(skill_id,skill_lv)); break; case LK_SPIRALPIERCE: case ML_SPIRALPIERCE: - sc_start(bl,SC_STOP,(15+skill_lv*5),0,skill->get_time2(skill_id,skill_lv)); + sc_start(src,bl,SC_ANKLESNARE,100,0,skill->get_time2(skill_id,skill_lv)); break; case ST_REJECTSWORD: - sc_start(bl,SC_AUTOCOUNTER,(skill_lv*15),skill_lv,skill->get_time(skill_id,skill_lv)); + sc_start(src,bl,SC_AUTOCOUNTER,(skill_lv*15),skill_lv,skill->get_time(skill_id,skill_lv)); break; case PF_FOGWALL: if (src != bl && !tsc->data[SC_DELUGE]) - sc_start(bl,SC_BLIND,100,skill_lv,skill->get_time2(skill_id,skill_lv)); + sc_start(src,bl,SC_BLIND,100,skill_lv,skill->get_time2(skill_id,skill_lv)); break; - case LK_HEADCRUSH: //Headcrush has chance of causing Bleeding status, except on demon and undead element + case LK_HEADCRUSH: // Headcrush has chance of causing Bleeding status, except on demon and undead element if (!(battle->check_undead(tstatus->race, tstatus->def_ele) || tstatus->race == RC_DEMON)) - sc_start2(bl, SC_BLOODING,50, skill_lv, src->id, skill->get_time2(skill_id,skill_lv)); + sc_start2(src, bl, SC_BLOODING,50, skill_lv, src->id, skill->get_time2(skill_id,skill_lv)); break; case LK_JOINTBEAT: - status = status_skill2sc(skill_id); if (tsc->jb_flag) { - sc_start4(bl,status,(5*skill_lv+5),skill_lv,tsc->jb_flag&BREAK_FLAGS,src->id,0,skill->get_time2(skill_id,skill_lv)); + enum sc_type type = status->skill2sc(skill_id); + sc_start4(src,bl,type,(5*skill_lv+5),skill_lv,tsc->jb_flag&BREAK_FLAGS,src->id,0,skill->get_time2(skill_id,skill_lv)); tsc->jb_flag = 0; } break; @@ -1097,22 +1038,22 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, uint //Any enemies hit by this skill will receive Stun, Darkness, or external bleeding status ailment with a 5%+5*skill_lv% chance. switch(rnd()%3) { case 0: - sc_start(bl,SC_BLIND,(5+skill_lv*5),skill_lv,skill->get_time2(skill_id,1)); + sc_start(src,bl,SC_BLIND,(5+skill_lv*5),skill_lv,skill->get_time2(skill_id,1)); break; case 1: - sc_start(bl,SC_STUN,(5+skill_lv*5),skill_lv,skill->get_time2(skill_id,2)); + sc_start(src,bl,SC_STUN,(5+skill_lv*5),skill_lv,skill->get_time2(skill_id,2)); break; default: - sc_start2(bl,SC_BLOODING,(5+skill_lv*5),skill_lv,src->id,skill->get_time2(skill_id,3)); + sc_start2(src,bl,SC_BLOODING,(5+skill_lv*5),skill_lv,src->id,skill->get_time2(skill_id,3)); } break; case HW_NAPALMVULCAN: - sc_start(bl,SC_CURSE,5*skill_lv,skill_lv,skill->get_time2(skill_id,skill_lv)); + sc_start(src,bl,SC_CURSE,5*skill_lv,skill_lv,skill->get_time2(skill_id,skill_lv)); break; case WS_CARTTERMINATION: // Cart termination - sc_start(bl,SC_STUN,5*skill_lv,skill_lv,skill->get_time2(skill_id,skill_lv)); + sc_start(src,bl,SC_STUN,5*skill_lv,skill_lv,skill->get_time2(skill_id,skill_lv)); break; case CR_ACIDDEMONSTRATION: @@ -1120,7 +1061,7 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, uint break; case TK_DOWNKICK: - sc_start(bl,SC_STUN,100,skill_lv,skill->get_time2(skill_id,skill_lv)); + sc_start(src,bl,SC_STUN,100,skill_lv,skill->get_time2(skill_id,skill_lv)); break; case TK_JUMPKICK: @@ -1137,20 +1078,20 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, uint case TK_TURNKICK: case MO_BALKYOUNG: //Note: attack_type is passed as BF_WEAPON for the actual target, BF_MISC for the splash-affected mobs. if(attack_type&BF_MISC) //70% base stun chance... - sc_start(bl,SC_STUN,70,skill_lv,skill->get_time2(skill_id,skill_lv)); + sc_start(src,bl,SC_STUN,70,skill_lv,skill->get_time2(skill_id,skill_lv)); break; case GS_BULLSEYE: //0.1% coma rate. if(tstatus->race == RC_BRUTE || tstatus->race == RC_DEMIHUMAN) - status_change_start(bl,SC_COMA,10,skill_lv,0,src->id,0,0,0); + status->change_start(src,bl,SC_COMA,10,skill_lv,0,src->id,0,0,0); break; case GS_PIERCINGSHOT: - sc_start2(bl,SC_BLOODING,(skill_lv*3),skill_lv,src->id,skill->get_time2(skill_id,skill_lv)); + sc_start2(src,bl,SC_BLOODING,(skill_lv*3),skill_lv,src->id,skill->get_time2(skill_id,skill_lv)); break; case NJ_HYOUSYOURAKU: - sc_start(bl,SC_FREEZE,(10+10*skill_lv),skill_lv,skill->get_time2(skill_id,skill_lv)); + sc_start(src,bl,SC_FREEZE,(10+10*skill_lv),skill_lv,skill->get_time2(skill_id,skill_lv)); break; case GS_FLING: - sc_start(bl,SC_FLING,100, sd?sd->spiritball_old:5,skill->get_time(skill_id,skill_lv)); + sc_start(src,bl,SC_FLING,100, sd?sd->spiritball_old:5,skill->get_time(skill_id,skill_lv)); break; case GS_DISARM: rate = 3*skill_lv; @@ -1160,112 +1101,132 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, uint clif->skill_nodamage(src,bl,skill_id,skill_lv,1); break; case NPC_EVILLAND: - sc_start(bl,SC_BLIND,5*skill_lv,skill_lv,skill->get_time2(skill_id,skill_lv)); + sc_start(src,bl,SC_BLIND,5*skill_lv,skill_lv,skill->get_time2(skill_id,skill_lv)); break; case NPC_HELLJUDGEMENT: - sc_start(bl,SC_CURSE,100,skill_lv,skill->get_time2(skill_id,skill_lv)); + sc_start(src,bl,SC_CURSE,100,skill_lv,skill->get_time2(skill_id,skill_lv)); break; case NPC_CRITICALWOUND: - sc_start(bl,SC_CRITICALWOUND,100,skill_lv,skill->get_time2(skill_id,skill_lv)); - break; - case RK_HUNDREDSPEAR: - if( !sd || pc->checkskill(sd,KN_SPEARBOOMERANG) == 0 ) - break; // Spear Boomerang auto cast chance only works if you have mastered Spear Boomerang. - rate = 10 + 3 * skill_lv; - if( rnd()%100 < rate ) - skill->castend_damage_id(src,bl,KN_SPEARBOOMERANG,1,tick,0); + sc_start(src,bl,SC_CRITICALWOUND,100,skill_lv,skill->get_time2(skill_id,skill_lv)); break; case RK_WINDCUTTER: - sc_start(bl,SC_FEAR,3+2*skill_lv,skill_lv,skill->get_time(skill_id,skill_lv)); + sc_start(src,bl,SC_FEAR,3+2*skill_lv,skill_lv,skill->get_time(skill_id,skill_lv)); break; case RK_DRAGONBREATH: - sc_start4(bl,SC_BURNING,5+5*skill_lv,skill_lv,0,src->id,0,skill->get_time(skill_id,skill_lv)); + sc_start4(src,bl,SC_BURNING,15,skill_lv,1000,src->id,0,skill->get_time(skill_id,skill_lv)); break; case RK_DRAGONBREATH_WATER: - sc_start4(bl,SC_FROSTMISTY,5+5*skill_lv,skill_lv,0,src->id,0,skill->get_time(skill_id,skill_lv)); + sc_start4(src,bl,SC_FROSTMISTY,15,skill_lv,1000,src->id,0,skill->get_time(skill_id,skill_lv)); break; case AB_ADORAMUS: if( tsc && !tsc->data[SC_DEC_AGI] ) //Prevent duplicate agi-down effect. - sc_start(bl, SC_ADORAMUS, 100, skill_lv, skill->get_time(skill_id, skill_lv)); + sc_start(src, bl, SC_ADORAMUS, skill_lv * 4 + (sd? sd->status.job_level:50)/2, skill_lv, skill->get_time(skill_id, skill_lv)); break; case WL_CRIMSONROCK: - sc_start(bl, SC_STUN, 40, skill_lv, skill->get_time(skill_id, skill_lv)); + sc_start(src, bl, SC_STUN, 40, skill_lv, skill->get_time(skill_id, skill_lv)); break; case WL_COMET: - sc_start4(bl,SC_BURNING,100,skill_lv,0,src->id,0,skill->get_time2(skill_id,skill_lv)); + sc_start4(src,bl,SC_BURNING,100,skill_lv,0,src->id,0,skill->get_time2(skill_id,skill_lv)); break; case WL_EARTHSTRAIN: { - // lv 1 & 2 = Strip Helm, lv 3 = Strip Armor, lv 4 = Strip Weapon and lv 5 = Strip Accessory. [malufett] - const int pos[5] = { EQP_HELM, EQP_HELM, EQP_ARMOR, EQP_WEAPON, EQP_ACC }; - skill->strip_equip(bl, pos[skill_lv], 6 * skill_lv + status_get_lv(src) / 4 + status_get_dex(src) / 10, - skill_lv, skill->get_time2(skill_id,skill_lv)); + int i; + const int pos[5] = { EQP_WEAPON, EQP_HELM, EQP_SHIELD, EQP_ARMOR, EQP_ACC }; + + for( i = 0; i < skill_lv; i++ ) + skill->strip_equip(bl,pos[i], (5 + skill_lv) * skill_lv, + skill_lv,skill->get_time2(skill_id,skill_lv)); } break; case WL_JACKFROST: - sc_start(bl,SC_FREEZE,100,skill_lv,skill->get_time(skill_id,skill_lv)); + sc_start(src,bl,SC_FREEZE,100,skill_lv,skill->get_time(skill_id,skill_lv)); break; case WL_FROSTMISTY: - sc_start(bl,SC_FROSTMISTY,25 + 5 * skill_lv,skill_lv,skill->get_time(skill_id,skill_lv)); + sc_start(src,bl,SC_FROSTMISTY,25 + 5 * skill_lv,skill_lv,skill->get_time(skill_id,skill_lv)); break; case RA_WUGBITE: - sc_start(bl, SC_WUGBITE, (sd ? pc->checkskill(sd,RA_TOOTHOFWUG)*2 : 0), skill_lv, (skill->get_time(skill_id,skill_lv) + (sd ? pc->checkskill(sd,RA_TOOTHOFWUG)*500 : 0)) ); + rate = 50 + 10 * skill_lv + 2 * (sd ? pc->checkskill(sd,RA_TOOTHOFWUG) : 0) - tstatus->agi / 4; + if ( rate < 50 ) + rate = 50; + sc_start(src,bl,SC_WUGBITE, rate, skill_lv, skill->get_time(skill_id, skill_lv) + (sd ? pc->checkskill(sd,RA_TOOTHOFWUG) * 500 : 0)); break; case RA_SENSITIVEKEEN: if( rnd()%100 < 8 * skill_lv ) skill->castend_damage_id(src, bl, RA_WUGBITE, sd ? pc->checkskill(sd, RA_WUGBITE):skill_lv, tick, SD_ANIMATION); break; + case RA_MAGENTATRAP: + case RA_COBALTTRAP: + case RA_MAIZETRAP: + case RA_VERDURETRAP: + if( dstmd && !(dstmd->status.mode&MD_BOSS) ) + sc_start2(src,bl,SC_ARMOR_PROPERTY,100,skill_lv,skill->get_ele(skill_id,skill_lv),skill->get_time2(skill_id,skill_lv)); + break; case RA_FIRINGTRAP: case RA_ICEBOUNDTRAP: - sc_start4(bl, (skill_id == RA_FIRINGTRAP) ? SC_BURNING:SC_FROSTMISTY, 40 + 10 * skill_lv, skill_lv, 0, src->id, 0, skill->get_time2(skill_id, skill_lv)); + sc_start4(src, bl, (skill_id == RA_FIRINGTRAP) ? SC_BURNING:SC_FROSTMISTY, 50 + 10 * skill_lv, skill_lv, 0, src->id, 0, skill->get_time2(skill_id, skill_lv)); break; case NC_PILEBUNKER: - if( rnd()%100 < 5 + 15*skill_lv ) - { //Deactivatable Statuses: Kyrie Eleison, Auto Guard, Steel Body, Assumptio, and Millennium Shield + if( rnd()%100 < 25 + 15 *skill_lv ) { + //Deactivatable Statuses: Kyrie Eleison, Auto Guard, Steel Body, Assumptio, and Millennium Shield status_change_end(bl, SC_KYRIE, INVALID_TIMER); - status_change_end(bl, SC_AUTOGUARD, INVALID_TIMER); - status_change_end(bl, SC_STEELBODY, INVALID_TIMER); status_change_end(bl, SC_ASSUMPTIO, INVALID_TIMER); + status_change_end(bl, SC_STEELBODY, INVALID_TIMER); + status_change_end(bl, SC_GENTLETOUCH_CHANGE, INVALID_TIMER); + status_change_end(bl, SC_GENTLETOUCH_REVITALIZE, INVALID_TIMER); + status_change_end(bl, SC_AUTOGUARD, INVALID_TIMER); + status_change_end(bl, SC_REFLECTSHIELD, INVALID_TIMER); + status_change_end(bl, SC_DEFENDER, INVALID_TIMER); + status_change_end(bl, SC_LG_REFLECTDAMAGE, INVALID_TIMER); + status_change_end(bl, SC_PRESTIGE, INVALID_TIMER); + status_change_end(bl, SC_BANDING, INVALID_TIMER); status_change_end(bl, SC_MILLENNIUMSHIELD, INVALID_TIMER); } break; case NC_FLAMELAUNCHER: - sc_start4(bl, SC_BURNING, 50 + 10 * skill_lv, skill_lv, 0, src->id, 0, skill->get_time2(skill_id, skill_lv)); + sc_start4(src, bl, SC_BURNING, 20 + 10 * skill_lv, skill_lv, 0, src->id, 0, skill->get_time2(skill_id, skill_lv)); break; case NC_COLDSLOWER: - sc_start(bl, SC_FREEZE, 10 * skill_lv, skill_lv, skill->get_time(skill_id, skill_lv)); - sc_start(bl, SC_FROSTMISTY, 20 + 10 * skill_lv, skill_lv, skill->get_time(skill_id, skill_lv)); + sc_start(src, bl, SC_FREEZE, 10 * skill_lv, skill_lv, skill->get_time(skill_id, skill_lv)); + if ( tsc && !tsc->data[SC_FREEZE] ) + sc_start(src, bl, SC_FROSTMISTY, 20 + 10 * skill_lv, skill_lv, skill->get_time2(skill_id, skill_lv)); break; case NC_POWERSWING: - sc_start(bl, SC_STUN, 5*skill_lv, skill_lv, skill->get_time(skill_id, skill_lv)); + // Use flag=2, the stun duration is not vit-reduced. + status->change_start(src, bl, SC_STUN, 5*skill_lv*100, skill_lv, 0, 0, 0, skill->get_time(skill_id, skill_lv), 2); if( rnd()%100 < 5*skill_lv ) skill->castend_damage_id(src, bl, NC_AXEBOOMERANG, pc->checkskill(sd, NC_AXEBOOMERANG), tick, 1); break; case NC_MAGMA_ERUPTION: - sc_start4(bl, SC_BURNING, 10 * skill_lv, skill_lv, 0, src->id, 0, skill->get_time2(skill_id, skill_lv)); - sc_start(bl, SC_STUN, 10 * skill_lv, skill_lv, skill->get_time(skill_id, skill_lv)); + sc_start4(src, bl, SC_BURNING, 10 * skill_lv, skill_lv, 0, src->id, 0, skill->get_time2(skill_id, skill_lv)); + sc_start(src, bl, SC_STUN, 10 * skill_lv, skill_lv, skill->get_time(skill_id, skill_lv)); break; case GC_WEAPONCRUSH: skill->castend_nodamage_id(src,bl,skill_id,skill_lv,tick,BCT_ENEMY); break; case GC_DARKCROW: - sc_start(bl, SC_DARKCROW, 10 * skill_lv, skill_lv, skill->get_time(skill_id, skill_lv)); + sc_start(src, bl, SC_DARKCROW, 100, skill_lv, skill->get_time(skill_id, skill_lv)); break; case LG_SHIELDPRESS: - sc_start(bl, SC_STUN, 30 + 8 * skill_lv, skill_lv, skill->get_time(skill_id,skill_lv)); + rate = 30 + 8 * skill_lv + sstatus->dex / 10 + (sd? sd->status.job_level:0) / 4; + sc_start(src, bl, SC_STUN, rate, skill_lv, skill->get_time(skill_id,skill_lv)); break; case LG_PINPOINTATTACK: - rate = 30 + (((5 * (sd?pc->checkskill(sd,LG_PINPOINTATTACK):skill_lv)) + (sstatus->agi + status_get_lv(src))) / 10); + rate = 30 + 5 * (sd ? pc->checkskill(sd,LG_PINPOINTATTACK) : 1) + (sstatus->agi + status->get_lv(src)) / 10; switch( skill_lv ) { case 1: - sc_start2(bl,SC_BLOODING,rate,skill_lv,src->id,skill->get_time(skill_id,skill_lv)); + sc_start(src, bl,SC_BLOODING,rate,skill_lv,skill->get_time(skill_id,skill_lv)); break; case 2: - if( dstsd && dstsd->spiritball && rnd()%100 < rate ) - pc->delspiritball(dstsd, dstsd->spiritball, 0); + skill->break_equip(bl, EQP_HELM, rate*100, BCT_ENEMY); break; - default: - skill->break_equip(bl,(skill_lv == 3) ? EQP_SHIELD : (skill_lv == 4) ? EQP_ARMOR : EQP_WEAPON,rate * 100,BCT_ENEMY); + case 3: + skill->break_equip(bl, EQP_SHIELD, rate*100, BCT_ENEMY); + break; + case 4: + skill->break_equip(bl, EQP_ARMOR, rate*100, BCT_ENEMY); + break; + case 5: + skill->break_equip(bl, EQP_WEAPON, rate*100, BCT_ENEMY); break; } break; @@ -1274,149 +1235,123 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, uint if( rnd()%100 < rate && dstsd ) // Uses skill->addtimerskill to avoid damage and setsit packet overlaping. Officially clif->setsit is received about 500 ms after damage packet. skill->addtimerskill(src,tick+500,bl->id,0,0,skill_id,skill_lv,BF_WEAPON,0); else if( dstmd && !is_boss(bl) ) - sc_start(bl,SC_STOP,100,skill_lv,skill->get_time(skill_id,skill_lv)); + sc_start(src, bl,SC_STOP,100,skill_lv,skill->get_time(skill_id,skill_lv)); break; case LG_RAYOFGENESIS: // 50% chance to cause Blind on Undead and Demon monsters. if ( battle->check_undead(tstatus->race, tstatus->def_ele) || tstatus->race == RC_DEMON ) - sc_start(bl, SC_BLIND,50, skill_lv, skill->get_time(skill_id,skill_lv)); + sc_start(src, bl, SC_BLIND,50, skill_lv, skill->get_time(skill_id,skill_lv)); break; case LG_EARTHDRIVE: - skill->break_equip(src, EQP_SHIELD, 500, BCT_SELF); - sc_start(bl, SC_EARTHDRIVE, 100, skill_lv, skill->get_time(skill_id, skill_lv)); + skill->break_equip(src, EQP_SHIELD, 100 * skill_lv, BCT_SELF); + sc_start(src, bl, SC_EARTHDRIVE, 100, skill_lv, skill->get_time(skill_id, skill_lv)); break; case SR_DRAGONCOMBO: - sc_start(bl, SC_STUN, 1 + skill_lv, skill_lv, skill->get_time(skill_id, skill_lv)); + sc_start(src, bl, SC_STUN, 1 + skill_lv, skill_lv, skill->get_time(skill_id, skill_lv)); break; case SR_FALLENEMPIRE: - sc_start(bl, SC_STOP, 100, skill_lv, skill->get_time(skill_id, skill_lv)); + sc_start(src, bl, SC_FALLENEMPIRE, 100, skill_lv, skill->get_time(skill_id, skill_lv)); break; case SR_WINDMILL: if( dstsd ) skill->addtimerskill(src,tick+status_get_amotion(src),bl->id,0,0,skill_id,skill_lv,BF_WEAPON,0); else if( dstmd && !is_boss(bl) ) - sc_start(bl, SC_STUN, 100, skill_lv, 1000 + 1000 * (rnd() %3)); + sc_start(src, bl, SC_STUN, 100, skill_lv, 1000 + 1000 * (rnd() %3)); break; case SR_GENTLETOUCH_QUIET: // [(Skill Level x 5) + (Caster?s DEX + Caster?s Base Level) / 10] - sc_start(bl, SC_SILENCE, 5 * skill_lv + (sstatus->dex + status_get_lv(src)) / 10, skill_lv, skill->get_time(skill_id, skill_lv)); + sc_start(src, bl, SC_SILENCE, 5 * skill_lv + (sstatus->dex + status->get_lv(src)) / 10, skill_lv, skill->get_time(skill_id, skill_lv)); break; case SR_EARTHSHAKER: - sc_start(bl,SC_STUN, 25 + 5 * skill_lv,skill_lv,skill->get_time(skill_id,skill_lv)); + sc_start(src, bl,SC_STUN, 25 + 5 * skill_lv,skill_lv,skill->get_time(skill_id,skill_lv)); break; case SR_HOWLINGOFLION: - sc_start(bl, SC_FEAR, 5 + 5 * skill_lv, skill_lv, skill->get_time(skill_id, skill_lv)); - break; - case WM_SOUND_OF_DESTRUCTION: - if( rnd()%100 < 5 + 5 * skill_lv ) { // Temporarly Check Until We Get the Official Formula - status_change_end(bl, SC_DANCING, INVALID_TIMER); - status_change_end(bl, SC_RICHMANKIM, INVALID_TIMER); - status_change_end(bl, SC_ETERNALCHAOS, INVALID_TIMER); - status_change_end(bl, SC_DRUMBATTLE, INVALID_TIMER); - status_change_end(bl, SC_NIBELUNGEN, INVALID_TIMER); - status_change_end(bl, SC_INTOABYSS, INVALID_TIMER); - status_change_end(bl, SC_SIEGFRIED, INVALID_TIMER); - status_change_end(bl, SC_WHISTLE, INVALID_TIMER); - status_change_end(bl, SC_ASSNCROS, INVALID_TIMER); - status_change_end(bl, SC_POEMBRAGI, INVALID_TIMER); - status_change_end(bl, SC_APPLEIDUN, INVALID_TIMER); - status_change_end(bl, SC_HUMMING, INVALID_TIMER); - status_change_end(bl, SC_FORTUNE, INVALID_TIMER); - status_change_end(bl, SC_SERVICEFORYOU, INVALID_TIMER); - status_change_end(bl, SC_LONGING, INVALID_TIMER); - status_change_end(bl, SC_SWING, INVALID_TIMER); - status_change_end(bl, SC_SYMPHONY_LOVE, INVALID_TIMER); - status_change_end(bl, SC_MOONLIT_SERENADE, INVALID_TIMER); - status_change_end(bl, SC_RUSH_WINDMILL, INVALID_TIMER); - status_change_end(bl, SC_ECHOSONG, INVALID_TIMER); - status_change_end(bl, SC_HARMONIZE, INVALID_TIMER); - status_change_end(bl, SC_DC_WINKCHARM, INVALID_TIMER); - status_change_end(bl, SC_SONG_OF_MANA, INVALID_TIMER); - status_change_end(bl, SC_DANCE_WITH_WUG, INVALID_TIMER); - status_change_end(bl, SC_LERADS_DEW, INVALID_TIMER); - status_change_end(bl, SC_MELODYOFSINK, INVALID_TIMER); - status_change_end(bl, SC_BEYOND_OF_WARCRY, INVALID_TIMER); - status_change_end(bl, SC_UNLIMITED_HUMMING_VOICE, INVALID_TIMER); - } + sc_start(src, bl, SC_FEAR, 5 + 5 * skill_lv, skill_lv, skill->get_time(skill_id, skill_lv)); break; case SO_EARTHGRAVE: - sc_start2(bl, SC_BLOODING, 5 * skill_lv, skill_lv, src->id, skill->get_time2(skill_id, skill_lv)); // Need official rate. [LimitLine] + sc_start2(src, bl, SC_BLOODING, 5 * skill_lv, skill_lv, src->id, skill->get_time2(skill_id, skill_lv)); // Need official rate. [LimitLine] break; case SO_DIAMONDDUST: rate = 5 + 5 * skill_lv; if( sc && sc->data[SC_COOLER_OPTION] ) - rate += rate * sc->data[SC_COOLER_OPTION]->val2 / 100; - sc_start(bl, SC_CRYSTALIZE, rate, skill_lv, skill->get_time2(skill_id, skill_lv)); + rate += sc->data[SC_COOLER_OPTION]->val3 / 5; + sc_start(src, bl, SC_COLD, rate, skill_lv, skill->get_time2(skill_id, skill_lv)); break; case SO_VARETYR_SPEAR: - sc_start(bl, SC_STUN, 5 + 5 * skill_lv, skill_lv, skill->get_time2(skill_id, skill_lv)); + sc_start(src, bl, SC_STUN, 5 + 5 * skill_lv, skill_lv, skill->get_time(skill_id, skill_lv)); break; case GN_SLINGITEM_RANGEMELEEATK: if( sd ) { switch( sd->itemid ) { // Starting SCs here instead of do it in skill->additional_effect to simplify the code. - case 13261: - sc_start(bl, SC_STUN, 100, skill_lv, skill->get_time2(GN_SLINGITEM, skill_lv)); - sc_start2(bl, SC_BLOODING, 100, skill_lv, src->id, skill->get_time2(GN_SLINGITEM, skill_lv)); + case ITEMID_COCONUT_BOMB: + sc_start(src, bl, SC_STUN, 100, skill_lv, 5000); // 5 seconds until I get official + sc_start(src, bl, SC_BLOODING, 100, skill_lv, 10000); break; - case 13262: - sc_start(bl, SC_MELON_BOMB, 100, skill_lv, skill->get_time(GN_SLINGITEM, skill_lv)); // Reduces ASPD and moviment speed + case ITEMID_MELON_BOMB: + sc_start(src, bl, SC_MELON_BOMB, 100, skill_lv, 60000); // Reduces ASPD and movement speed break; - case 13264: - sc_start(bl, SC_BANANA_BOMB, 100, skill_lv, skill->get_time(GN_SLINGITEM, skill_lv)); // Reduces LUK ??Needed confirm it, may be it's bugged in kRORE? - sc_start(bl, SC_BANANA_BOMB_SITDOWN_POSTDELAY, 75, skill_lv, skill->get_time(GN_SLINGITEM_RANGEMELEEATK,skill_lv)); // Sitdown for 3 seconds. + case ITEMID_BANANA_BOMB: + sc_start(src, bl, SC_BANANA_BOMB, 100, skill_lv, 60000); // Reduces LUK? Needed confirm it, may be it's bugged in kRORE? + sc_start(src, bl, SC_BANANA_BOMB_SITDOWN_POSTDELAY, (sd? sd->status.job_level:0) + sstatus->dex / 6 + tstatus->agi / 4 - tstatus->luk / 5 - status->get_lv(bl) + status->get_lv(src), skill_lv, 1000); // Sit down for 3 seconds. break; } sd->itemid = -1; } break; case GN_HELLS_PLANT_ATK: - sc_start(bl, SC_STUN, 5 + 5 * skill_lv, skill_lv, skill->get_time2(skill_id, skill_lv)); - sc_start2(bl, SC_BLOODING, 20 + 10 * skill_lv, skill_lv, src->id,skill->get_time2(skill_id, skill_lv)); + sc_start(src, bl, SC_STUN, 20 + 10 * skill_lv, skill_lv, skill->get_time2(skill_id, skill_lv)); + sc_start2(src, bl, SC_BLOODING, 5 + 5 * skill_lv, skill_lv, src->id,skill->get_time2(skill_id, skill_lv)); break; case EL_WIND_SLASH: // Non confirmed rate. - sc_start2(bl, SC_BLOODING, 25, skill_lv, src->id, skill->get_time(skill_id,skill_lv)); + sc_start2(src, bl, SC_BLOODING, 25, skill_lv, src->id, skill->get_time(skill_id,skill_lv)); break; case EL_STONE_HAMMER: rate = 10 * skill_lv; - sc_start(bl, SC_STUN, rate, skill_lv, skill->get_time(skill_id,skill_lv)); + sc_start(src, bl, SC_STUN, rate, skill_lv, skill->get_time(skill_id,skill_lv)); break; case EL_ROCK_CRUSHER: case EL_ROCK_CRUSHER_ATK: - sc_start(bl,status_skill2sc(skill_id),50,skill_lv,skill->get_time(EL_ROCK_CRUSHER,skill_lv)); + sc_start(src, bl,status->skill2sc(skill_id),50,skill_lv,skill->get_time(EL_ROCK_CRUSHER,skill_lv)); break; case EL_TYPOON_MIS: - sc_start(bl,SC_SILENCE,10*skill_lv,skill_lv,skill->get_time(skill_id,skill_lv)); + sc_start(src, bl,SC_SILENCE,10*skill_lv,skill_lv,skill->get_time(skill_id,skill_lv)); break; case KO_JYUMONJIKIRI: - sc_start(bl,SC_KO_JYUMONJIKIRI,90,skill_lv,skill->get_time(skill_id,skill_lv)); + sc_start(src, bl,SC_KO_JYUMONJIKIRI,90,skill_lv,skill->get_time(skill_id,skill_lv)); break; case KO_MAKIBISHI: - sc_start(bl, SC_STUN, 10 * skill_lv, skill_lv, 1000 * (skill_lv / 2 + 2)); + sc_start(src, bl, SC_STUN, 10 * skill_lv, skill_lv, 1000 * (skill_lv / 2 + 2)); break; case MH_LAVA_SLIDE: - if (tsc && !tsc->data[SC_BURNING]) sc_start4(bl, SC_BURNING, 10 * skill_lv, skill_lv, 0, src->id, 0, skill->get_time(skill_id, skill_lv)); + if (tsc && !tsc->data[SC_BURNING]) sc_start4(src, bl, SC_BURNING, 10 * skill_lv, skill_lv, 0, src->id, 0, skill->get_time(skill_id, skill_lv)); break; case MH_STAHL_HORN: - sc_start(bl, SC_STUN, (20 + 4 * (skill_lv-1)), skill_lv, skill->get_time(skill_id, skill_lv)); + sc_start(src, bl, SC_STUN, (20 + 4 * (skill_lv-1)), skill_lv, skill->get_time(skill_id, skill_lv)); break; case MH_NEEDLE_OF_PARALYZE: - sc_start(bl, SC_NEEDLE_OF_PARALYZE, 40 + (5*skill_lv), skill_lv, skill->get_time(skill_id, skill_lv)); + sc_start(src, bl, SC_NEEDLE_OF_PARALYZE, 40 + (5*skill_lv), skill_lv, skill->get_time(skill_id, skill_lv)); + break; + case GN_ILLUSIONDOPING: + if( sc_start(src, bl, SC_ILLUSIONDOPING, 10 * skill_lv, skill_lv, skill->get_time(skill_id, skill_lv)) ) //custom rate. + sc_start(src, bl, SC_ILLUSION, 100, skill_lv, skill->get_time(skill_id, skill_lv)); + break; + case MH_XENO_SLASHER: + sc_start2(src, bl, SC_BLOODING, 10 * skill_lv, skill_lv, src->id, skill->get_time(skill_id,skill_lv)); break; } - if (md && battle_config.summons_trigger_autospells && md->master_id && md->special_state.ai) - { //Pass heritage to Master for status causing effects. [Skotlex] - sd = iMap->id2sd(md->master_id); + if (md && battle_config.summons_trigger_autospells && md->master_id && md->special_state.ai) { + //Pass heritage to Master for status causing effects. [Skotlex] + sd = map->id2sd(md->master_id); src = sd?&sd->bl:src; } - if( attack_type&BF_WEAPON ) - { // Coma, Breaking Equipment - if( sd && sd->special_state.bonus_coma ) - { + if( attack_type&BF_WEAPON && skill_id != CR_REFLECTSHIELD ) { + // Coma, Breaking Equipment + if( sd && sd->special_state.bonus_coma ) { rate = sd->weapon_coma_ele[tstatus->def_ele]; rate += sd->weapon_coma_race[tstatus->race]; rate += sd->weapon_coma_race[tstatus->mode&MD_BOSS?RC_BOSS:RC_NONBOSS]; if (rate) - status_change_start(bl, SC_COMA, rate, 0, 0, src->id, 0, 0, 0); + status->change_start(src, bl, SC_COMA, rate, 0, 0, src->id, 0, 0, 0); } if( sd && battle_config.equip_self_break_rate ) { // Self weapon breaking @@ -1453,10 +1388,18 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, uint if( rate ) skill->break_equip(bl, EQP_ARMOR, rate, BCT_ENEMY); } + if (sd && !skill_id && bl->type == BL_PC) { // This effect does not work with skills. + if (sd->def_set_race[tstatus->race].rate) + status->change_start(src,bl, SC_DEFSET, sd->def_set_race[tstatus->race].rate, sd->def_set_race[tstatus->race].value, + 0, 0, 0, sd->def_set_race[tstatus->race].tick, 2); + if (sd->def_set_race[tstatus->race].rate) + status->change_start(src,bl, SC_MDEFSET, sd->mdef_set_race[tstatus->race].rate, sd->mdef_set_race[tstatus->race].value, + 0, 0, 0, sd->mdef_set_race[tstatus->race].tick, 2); + } } - if( sd && sd->ed && sc && !status_isdead(bl) && !skill_id ){ - struct unit_data *ud = unit_bl2ud(src); + if( sd && sd->ed && sc && !status->isdead(bl) && !skill_id ) { + struct unit_data *ud = unit->bl2ud(src); if( sc->data[SC_WILD_STORM_OPTION] ) temp = sc->data[SC_WILD_STORM_OPTION]->val2; @@ -1484,11 +1427,10 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, uint } // Autospell when attacking - if( sd && !status_isdead(bl) && sd->autospell[0].id ) - { + if( sd && !status->isdead(bl) && sd->autospell[0].id ) { struct block_list *tbl; struct unit_data *ud; - int i, skill_lv, type, notok; + int i, auto_skill_lv, type, notok; for (i = 0; i < ARRAYLENGTH(sd->autospell) && sd->autospell[i].id; i++) { @@ -1506,8 +1448,8 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, uint if ( notok ) continue; - skill_lv = sd->autospell[i].lv?sd->autospell[i].lv:1; - if (skill_lv < 0) skill_lv = 1+rnd()%(-skill_lv); + auto_skill_lv = sd->autospell[i].lv?sd->autospell[i].lv:1; + if (auto_skill_lv < 0) auto_skill_lv = 1+rnd()%(-auto_skill_lv); rate = (!sd->state.arrow_atk) ? sd->autospell[i].rate : sd->autospell[i].rate / 2; @@ -1520,18 +1462,18 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, uint int maxcount = 0; if( !(BL_PC&battle_config.skill_reiteration) && skill->get_unit_flag(temp)&UF_NOREITERATION && - skill->check_unit_range(src,tbl->x,tbl->y,temp,skill_lv) + skill->check_unit_range(src,tbl->x,tbl->y,temp,auto_skill_lv) ) { continue; } if( BL_PC&battle_config.skill_nofootset && skill->get_unit_flag(temp)&UF_NOFOOTSET && - skill->check_unit_range2(src,tbl->x,tbl->y,temp,skill_lv) + skill->check_unit_range2(src,tbl->x,tbl->y,temp,auto_skill_lv) ) { continue; } if( BL_PC&battle_config.land_skill_limit && - (maxcount = skill->get_maxcount(temp, skill_lv)) > 0 + (maxcount = skill->get_maxcount(temp, auto_skill_lv)) > 0 ) { int v; for(v=0;v<MAX_SKILLUNITGROUP && sd->ud.skillunit[v] && maxcount;v++) { @@ -1544,7 +1486,7 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, uint } } if( battle_config.autospell_check_range && - !battle->check_range(src, tbl, skill->get_range2(src, temp,skill_lv) + (temp == RG_CLOSECONFINE?0:1)) ) + !battle->check_range(src, tbl, skill->get_range2(src, temp,auto_skill_lv) + (temp == RG_CLOSECONFINE?0:1)) ) continue; if (temp == AS_SONICBLOW) @@ -1553,24 +1495,24 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, uint type = CAST_GROUND; sd->state.autocast = 1; - skill->consume_requirement(sd,temp,skill_lv,1); + skill->consume_requirement(sd,temp,auto_skill_lv,1); skill->toggle_magicpower(src, temp); switch (type) { case CAST_GROUND: - skill->castend_pos2(src, tbl->x, tbl->y, temp, skill_lv, tick, 0); + skill->castend_pos2(src, tbl->x, tbl->y, temp, auto_skill_lv, tick, 0); break; case CAST_NODAMAGE: - skill->castend_nodamage_id(src, tbl, temp, skill_lv, tick, 0); + skill->castend_nodamage_id(src, tbl, temp, auto_skill_lv, tick, 0); break; case CAST_DAMAGE: - skill->castend_damage_id(src, tbl, temp, skill_lv, tick, 0); + skill->castend_damage_id(src, tbl, temp, auto_skill_lv, tick, 0); break; } sd->state.autocast = 0; //Set canact delay. [Skotlex] - ud = unit_bl2ud(src); + ud = unit->bl2ud(src); if (ud) { - rate = skill->delay_fix(src, temp, skill_lv); + rate = skill->delay_fix(src, temp, auto_skill_lv); if (DIFF_TICK(ud->canact_tick, tick + rate) < 0){ ud->canact_tick = tick+rate; if ( battle_config.display_status_timers && sd ) @@ -1603,27 +1545,27 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, uint dstmd && !(tstatus->mode&MD_BOSS) && (rnd()%10000 < sd->bonus.classchange)) { - struct mob_db *mob; + struct mob_db *monster; int class_; temp = 0; do { do { class_ = rnd() % MAX_MOB_DB; - } while (!mobdb_checkid(class_)); + } while (!mob->db_checkid(class_)); rate = rnd() % 1000000; - mob = mob_db(class_); + monster = mob->db(class_); } while ( - (mob->status.mode&(MD_BOSS|MD_PLANT) || mob->summonper[0] <= rate) && + (monster->status.mode&(MD_BOSS|MD_PLANT) || monster->summonper[0] <= rate) && (temp++) < 2000); if (temp < 2000) - mob_class_change(dstmd,class_); + mob->class_change(dstmd,class_); } return 0; } -int skill_onskillusage(struct map_session_data *sd, struct block_list *bl, uint16 skill_id, unsigned int tick) { +int skill_onskillusage(struct map_session_data *sd, struct block_list *bl, uint16 skill_id, int64 tick) { int temp, skill_lv, i, type, notok; struct block_list *tbl; @@ -1713,8 +1655,7 @@ int skill_onskillusage(struct map_session_data *sd, struct block_list *bl, uint1 return 1; } - -/* Splitted off from skill->additional_effect, which is never called when the +/* Split off from skill->additional_effect, which is never called when the * attack skill kills the enemy. Place in this function counter status effects * when using skills (eg: Asura's sp regen penalty, or counter-status effects * from cards) that will take effect on the source, not the target. [Skotlex] @@ -1722,8 +1663,7 @@ int skill_onskillusage(struct map_session_data *sd, struct block_list *bl, uint1 * type of skills, so not every instance of skill->additional_effect needs a call * to this one. */ -int skill_counter_additional_effect (struct block_list* src, struct block_list *bl, uint16 skill_id, uint16 skill_lv, int attack_type, unsigned int tick) -{ +int skill_counter_additional_effect(struct block_list* src, struct block_list *bl, uint16 skill_id, uint16 skill_lv, int attack_type, int64 tick) { int rate; struct map_session_data *sd=NULL; struct map_session_data *dstsd=NULL; @@ -1731,47 +1671,46 @@ int skill_counter_additional_effect (struct block_list* src, struct block_list * nullpo_ret(src); nullpo_ret(bl); - if(skill_id > 0 && !skill_lv) return 0; // don't forget auto attacks! - celest + if(skill_id > 0 && !skill_lv) return 0; // don't forget auto attacks! [celest] sd = BL_CAST(BL_PC, src); dstsd = BL_CAST(BL_PC, bl); - if(dstsd && attack_type&BF_WEAPON) - { //Counter effects. + if(dstsd && attack_type&BF_WEAPON) { + //Counter effects. enum sc_type type; int i, time; - for(i=0; i < ARRAYLENGTH(dstsd->addeff2) && dstsd->addeff2[i].flag; i++) - { + for(i=0; i < ARRAYLENGTH(dstsd->addeff2) && dstsd->addeff2[i].flag; i++) { rate = dstsd->addeff2[i].rate; if (attack_type&BF_LONG) rate+=dstsd->addeff2[i].arrow_rate; if (!rate) continue; - if ((dstsd->addeff2[i].flag&(ATF_LONG|ATF_SHORT)) != (ATF_LONG|ATF_SHORT)) - { //Trigger has range consideration. + if ((dstsd->addeff2[i].flag&(ATF_LONG|ATF_SHORT)) != (ATF_LONG|ATF_SHORT)) { + //Trigger has range consideration. if((dstsd->addeff2[i].flag&ATF_LONG && !(attack_type&BF_LONG)) || (dstsd->addeff2[i].flag&ATF_SHORT && !(attack_type&BF_SHORT))) continue; //Range Failed. } type = dstsd->addeff2[i].id; - time = skill->get_time2(status_sc2skill(type),7); + time = skill->get_time2(status->sc2skill(type),7); if (dstsd->addeff2[i].flag&ATF_TARGET) - status_change_start(src,type,rate,7,0,0,0,time,0); + status->change_start(bl,src,type,rate,7,0,0,0,time,0); - if (dstsd->addeff2[i].flag&ATF_SELF && !status_isdead(bl)) - status_change_start(bl,type,rate,7,0,0,0,time,0); + if (dstsd->addeff2[i].flag&ATF_SELF && !status->isdead(bl)) + status->change_start(bl,bl,type,rate,7,0,0,0,time,0); } } switch(skill_id){ case MO_EXTREMITYFIST: - sc_start(src,SC_EXTREMITYFIST,100,skill_lv,skill->get_time2(skill_id,skill_lv)); + sc_start(src,src,SC_EXTREMITYFIST,100,skill_lv,skill->get_time2(skill_id,skill_lv)); break; case GS_FULLBUSTER: - sc_start(src,SC_BLIND,2*skill_lv,skill_lv,skill->get_time2(skill_id,skill_lv)); + sc_start(src,src,SC_BLIND,2*skill_lv,skill_lv,skill->get_time2(skill_id,skill_lv)); break; - case HFLI_SBR44: //[orn] + case HFLI_SBR44: // [orn] case HVAN_EXPLOSION: if(src->type == BL_HOM){ TBL_HOM *hd = (TBL_HOM*)src; @@ -1786,20 +1725,25 @@ int skill_counter_additional_effect (struct block_list* src, struct block_list * break; } - if(sd && (sd->class_&MAPID_UPPERMASK) == MAPID_STAR_GLADIATOR && - rnd()%10000 < battle_config.sg_miracle_skill_ratio) //SG_MIRACLE [Komurka] - sc_start(src,SC_MIRACLE,100,1,battle_config.sg_miracle_skill_duration); + if( sd && (sd->class_&MAPID_UPPERMASK) == MAPID_STAR_GLADIATOR + && rnd()%10000 < battle_config.sg_miracle_skill_ratio) // SG_MIRACLE [Komurka] + sc_start(src,src,SC_MIRACLE,100,1,battle_config.sg_miracle_skill_duration); - if(sd && skill_id && attack_type&BF_MAGIC && status_isdead(bl) && - !(skill->get_inf(skill_id)&(INF_GROUND_SKILL|INF_SELF_SKILL)) && - (rate=pc->checkskill(sd,HW_SOULDRAIN))>0 - ){ //Soul Drain should only work on targetted spells [Skotlex] - if (pc_issit(sd)) pc->setstand(sd); //Character stuck in attacking animation while 'sitting' fix. [Skotlex] - clif->skill_nodamage(src,bl,HW_SOULDRAIN,rate,1); - status_heal(src, 0, status_get_lv(bl)*(95+15*rate)/100, 2); + if( sd && skill_id && attack_type&BF_MAGIC && status->isdead(bl) + && !(skill->get_inf(skill_id)&(INF_GROUND_SKILL|INF_SELF_SKILL)) + && (rate=pc->checkskill(sd,HW_SOULDRAIN)) > 0 + ) { + // Soul Drain should only work on targeted spells [Skotlex] + if( pc_issit(sd) ) pc->setstand(sd); // Character stuck in attacking animation while 'sitting' fix. [Skotlex] + if( skill->get_nk(skill_id)&NK_SPLASH && skill->area_temp[1] != bl->id ) + ; + else { + clif->skill_nodamage(src,bl,HW_SOULDRAIN,rate,1); + status->heal(src, 0, status->get_lv(bl)*(95+15*rate)/100, 2); + } } - if( sd && status_isdead(bl) ) { + if( sd && status->isdead(bl) ) { int sp = 0, hp = 0; if( attack_type&BF_WEAPON ) { sp += sd->bonus.sp_gain_value; @@ -1810,26 +1754,28 @@ int skill_counter_additional_effect (struct block_list* src, struct block_list * if( attack_type&BF_MAGIC ) { sp += sd->bonus.magic_sp_gain_value; hp += sd->bonus.magic_hp_gain_value; - if( skill_id == WZ_WATERBALL ) {//(bugreport:5303) + if( skill_id == WZ_WATERBALL ) {// (bugreport:5303) struct status_change *sc = NULL; - if( ( sc = status_get_sc(src) ) ) { - if(sc->data[SC_SOULLINK] && - sc->data[SC_SOULLINK]->val2 == SL_WIZARD && - sc->data[SC_SOULLINK]->val3 == WZ_WATERBALL) - sc->data[SC_SOULLINK]->val3 = 0; //Clear bounced spell check. + if( ( sc = status->get_sc(src) ) ) { + if( sc->data[SC_SOULLINK] + && sc->data[SC_SOULLINK]->val2 == SL_WIZARD + && sc->data[SC_SOULLINK]->val3 == WZ_WATERBALL + ) + sc->data[SC_SOULLINK]->val3 = 0; //Clear bounced spell check. } } } - if( hp || sp ) { // updated to force healing to allow healing through berserk - status_heal(src, hp, sp, battle_config.show_hp_sp_gain ? 3 : 1); + if( hp || sp ) { + // updated to force healing to allow healing through berserk + status->heal(src, hp, sp, battle_config.show_hp_sp_gain ? 3 : 1); } } // Trigger counter-spells to retaliate against damage causing skills. - if(dstsd && !status_isdead(bl) && dstsd->autospell2[0].id && !(skill_id && skill->get_nk(skill_id)&NK_NO_DAMAGE)) { + if(dstsd && !status->isdead(bl) && dstsd->autospell2[0].id && !(skill_id && skill->get_nk(skill_id)&NK_NO_DAMAGE)) { struct block_list *tbl; struct unit_data *ud; - int i, skill_id, skill_lv, rate, type, notok; + int i, auto_skill_id, auto_skill_lv, type, notok; for (i = 0; i < ARRAYLENGTH(dstsd->autospell2) && dstsd->autospell2[i].id; i++) { @@ -1838,16 +1784,16 @@ int skill_counter_additional_effect (struct block_list* src, struct block_list * dstsd->autospell2[i].flag&attack_type&BF_SKILLMASK)) continue; // one or more trigger conditions were not fulfilled - skill_id = (dstsd->autospell2[i].id > 0) ? dstsd->autospell2[i].id : -dstsd->autospell2[i].id; - skill_lv = dstsd->autospell2[i].lv?dstsd->autospell2[i].lv:1; - if (skill_lv < 0) skill_lv = 1+rnd()%(-skill_lv); + auto_skill_id = (dstsd->autospell2[i].id > 0) ? dstsd->autospell2[i].id : -dstsd->autospell2[i].id; + auto_skill_lv = dstsd->autospell2[i].lv?dstsd->autospell2[i].lv:1; + if (auto_skill_lv < 0) auto_skill_lv = 1+rnd()%(-auto_skill_lv); rate = dstsd->autospell2[i].rate; if (attack_type&BF_LONG) rate>>=1; dstsd->state.autocast = 1; - notok = skill->not_ok(skill_id, dstsd); + notok = skill->not_ok(auto_skill_id, dstsd); dstsd->state.autocast = 0; if ( notok ) @@ -1858,26 +1804,26 @@ int skill_counter_additional_effect (struct block_list* src, struct block_list * tbl = (dstsd->autospell2[i].id < 0) ? bl : src; - if( (type = skill->get_casttype(skill_id)) == CAST_GROUND ) { + if( (type = skill->get_casttype(auto_skill_id)) == CAST_GROUND ) { int maxcount = 0; if( !(BL_PC&battle_config.skill_reiteration) && - skill->get_unit_flag(skill_id)&UF_NOREITERATION && - skill->check_unit_range(bl,tbl->x,tbl->y,skill_id,skill_lv) + skill->get_unit_flag(auto_skill_id)&UF_NOREITERATION && + skill->check_unit_range(bl,tbl->x,tbl->y,auto_skill_id,auto_skill_lv) ) { continue; } if( BL_PC&battle_config.skill_nofootset && - skill->get_unit_flag(skill_id)&UF_NOFOOTSET && - skill->check_unit_range2(bl,tbl->x,tbl->y,skill_id,skill_lv) + skill->get_unit_flag(auto_skill_id)&UF_NOFOOTSET && + skill->check_unit_range2(bl,tbl->x,tbl->y,auto_skill_id,auto_skill_lv) ) { continue; } if( BL_PC&battle_config.land_skill_limit && - (maxcount = skill->get_maxcount(skill_id, skill_lv)) > 0 + (maxcount = skill->get_maxcount(auto_skill_id, auto_skill_lv)) > 0 ) { int v; for(v=0;v<MAX_SKILLUNITGROUP && dstsd->ud.skillunit[v] && maxcount;v++) { - if(dstsd->ud.skillunit[v]->skill_id == skill_id) + if(dstsd->ud.skillunit[v]->skill_id == auto_skill_id) maxcount--; } if( maxcount == 0 ) { @@ -1886,27 +1832,27 @@ int skill_counter_additional_effect (struct block_list* src, struct block_list * } } - if( !battle->check_range(src, tbl, skill->get_range2(src, skill_id,skill_lv) + (skill_id == RG_CLOSECONFINE?0:1)) && battle_config.autospell_check_range ) + if( !battle->check_range(src, tbl, skill->get_range2(src, auto_skill_id,auto_skill_lv) + (auto_skill_id == RG_CLOSECONFINE?0:1)) && battle_config.autospell_check_range ) continue; dstsd->state.autocast = 1; - skill->consume_requirement(dstsd,skill_id,skill_lv,1); + skill->consume_requirement(dstsd,auto_skill_id,auto_skill_lv,1); switch (type) { case CAST_GROUND: - skill->castend_pos2(bl, tbl->x, tbl->y, skill_id, skill_lv, tick, 0); + skill->castend_pos2(bl, tbl->x, tbl->y, auto_skill_id, auto_skill_lv, tick, 0); break; case CAST_NODAMAGE: - skill->castend_nodamage_id(bl, tbl, skill_id, skill_lv, tick, 0); + skill->castend_nodamage_id(bl, tbl, auto_skill_id, auto_skill_lv, tick, 0); break; case CAST_DAMAGE: - skill->castend_damage_id(bl, tbl, skill_id, skill_lv, tick, 0); + skill->castend_damage_id(bl, tbl, auto_skill_id, auto_skill_lv, tick, 0); break; } dstsd->state.autocast = 0; - //Set canact delay. [Skotlex] - ud = unit_bl2ud(bl); + // Set canact delay. [Skotlex] + ud = unit->bl2ud(bl); if (ud) { - rate = skill->delay_fix(bl, skill_id, skill_lv); + rate = skill->delay_fix(bl, auto_skill_id, auto_skill_lv); if (DIFF_TICK(ud->canact_tick, tick + rate) < 0){ ud->canact_tick = tick+rate; if ( battle_config.display_status_timers && dstsd ) @@ -1917,7 +1863,7 @@ int skill_counter_additional_effect (struct block_list* src, struct block_list * } //Autobonus when attacked - if( dstsd && !status_isdead(bl) && dstsd->autobonus2[0].rate && !(skill_id && skill->get_nk(skill_id)&NK_NO_DAMAGE) ) { + if( dstsd && !status->isdead(bl) && dstsd->autobonus2[0].rate && !(skill_id && skill->get_nk(skill_id)&NK_NO_DAMAGE) ) { int i; for( i = 0; i < ARRAYLENGTH(dstsd->autobonus2); i++ ) { if( rnd()%1000 >= dstsd->autobonus2[i].rate ) @@ -1944,7 +1890,7 @@ int skill_break_equip (struct block_list *bl, unsigned short where, int rate, in const int where_list[4] = {EQP_WEAPON, EQP_ARMOR, EQP_SHIELD, EQP_HELM}; const enum sc_type scatk[4] = {SC_NOEQUIPWEAPON, SC_NOEQUIPARMOR, SC_NOEQUIPSHIELD, SC_NOEQUIPHELM}; const enum sc_type scdef[4] = {SC_PROTECTWEAPON, SC_PROTECTARMOR, SC_PROTECTSHIELD, SC_PROTECTHELM}; - struct status_change *sc = status_get_sc(bl); + struct status_change *sc = status->get_sc(bl); int i,j; TBL_PC *sd; sd = BL_CAST(BL_PC, bl); @@ -1986,7 +1932,7 @@ int skill_break_equip (struct block_list *bl, unsigned short where, int rate, in else if (rnd()%10000 >= rate) where&=~where_list[i]; else if (!sd && !(status_get_mode(bl)&MD_BOSS)) //Cause Strip effect. - sc_start(bl,scatk[i],100,0,skill->get_time(status_sc2skill(scatk[i]),1)); + sc_start(bl,bl,scatk[i],100,0,skill->get_time(status->sc2skill(scatk[i]),1)); } } if (!where) //Nothing to break. @@ -2040,8 +1986,8 @@ int skill_strip_equip(struct block_list *bl, unsigned short where, int rate, int if (rnd()%100 >= rate) return 0; - sc = status_get_sc(bl); - if (!sc || sc->option&OPTION_MADOGEAR ) //Mado Gear cannot be divested [Ind] + sc = status->get_sc(bl); + if (!sc || sc->option&OPTION_MADOGEAR ) // Mado Gear cannot be divested [Ind] return 0; for (i = 0; i < ARRAYLENGTH(pos); i++) { @@ -2051,13 +1997,11 @@ int skill_strip_equip(struct block_list *bl, unsigned short where, int rate, int if (!where) return 0; for (i = 0; i < ARRAYLENGTH(pos); i++) { - if (where&pos[i] && !sc_start(bl, sc_atk[i], 100, lv, time)) + if (where&pos[i] && !sc_start(bl, bl, sc_atk[i], 100, lv, time)) where&=~pos[i]; } return where?1:0; } -//Early declaration -static int skill_area_temp[8]; /*========================================================================= Used to knock back players, monsters, traps, etc - 'count' is the number of squares to knock back @@ -2071,17 +2015,17 @@ int skill_blown(struct block_list* src, struct block_list* target, int count, in nullpo_ret(src); - if (src != target && map[src->m].flag.noknockback) - return 0; //No knocking + if (src != target && map->list[src->m].flag.noknockback) + return 0; // No knocking if (count == 0) - return 0; //Actual knockback distance is 0. + return 0; // Actual knockback distance is 0. switch (target->type) { case BL_MOB: { struct mob_data* md = BL_CAST(BL_MOB, target); if( md->class_ == MOBID_EMPERIUM ) return 0; - if(src != target && is_boss(target)) //Bosses can't be knocked-back + if(src != target && is_boss(target)) // Bosses can't be knocked-back return 0; } break; @@ -2095,13 +2039,13 @@ int skill_blown(struct block_list* src, struct block_list* target, int count, in break; case BL_SKILL: su = (struct skill_unit *)target; - if( su && su->group && su->group->unit_id == UNT_ANKLESNARE ) + if( su && su->group && (su->group->unit_id == UNT_ANKLESNARE || su->group->unit_id == UNT_REVERBERATION)) return 0; // ankle snare cannot be knocked back break; } if (dir == -1) // <optimized>: do the computation here instead of outside - dir = iMap->calc_dir(target, src->x, src->y); // direction from src to target, reversed + dir = map->calc_dir(target, src->x, src->y); // direction from src to target, reversed if (dir >= 0 && dir < 8) { // take the reversed 'direction' and reverse it @@ -2109,14 +2053,19 @@ int skill_blown(struct block_list* src, struct block_list* target, int count, in dy = -diry[dir]; } - return unit_blown(target, dx, dy, count, flag); // send over the proper flag + return unit->blown(target, dx, dy, count, flag); // send over the proper flag } -//Checks if 'bl' should reflect back a spell cast by 'src'. -//type is the type of magic attack: 0: indirect (aoe), 1: direct (targetted) +/* + Checks if 'bl' should reflect back a spell cast by 'src'. + type is the type of magic attack: 0: indirect (aoe), 1: direct (targeted) + In case of success returns type of reflection, otherwise 0 + 1 - Regular reflection (Maya) + 2 - SL_KAITE reflection +*/ int skill_magic_reflect(struct block_list* src, struct block_list* bl, int type) { - struct status_change *sc = status_get_sc(bl); + struct status_change *sc = status->get_sc(bl); struct map_session_data* sd = BL_CAST(BL_PC, bl); if( sc && sc->data[SC_KYOMU] ) // Nullify reflecting ability @@ -2136,7 +2085,7 @@ int skill_magic_reflect(struct block_list* src, struct block_list* bl, int type) if( sc->data[SC_MAGICMIRROR] && rnd()%100 < sc->data[SC_MAGICMIRROR]->val2 ) return 1; - if( sc->data[SC_KAITE] && (src->type == BL_PC || status_get_lv(src) <= 80) ) + if( sc->data[SC_KAITE] && (src->type == BL_PC || status->get_lv(src) <= 80) ) {// Kaite only works against non-players if they are low-level. clif->specialeffect(bl, 438, AREA); if( --sc->data[SC_KAITE]->val2 <= 0 ) @@ -2161,38 +2110,46 @@ int skill_magic_reflect(struct block_list* src, struct block_list* bl, int type) * flag&0x2000 is used to signal that the skill_lv should be passed as -1 to the * client (causes player characters to not scream skill name) *-------------------------------------------------------------------------*/ -int skill_attack (int attack_type, struct block_list* src, struct block_list *dsrc, struct block_list *bl, uint16 skill_id, uint16 skill_lv, unsigned int tick, int flag) -{ +int skill_attack(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) { struct Damage dmg; struct status_data *sstatus, *tstatus; struct status_change *sc; struct map_session_data *sd, *tsd; - int type,damage; - int8 rmdamage=0;//magic reflected - bool additional_effects = true; + int type; + int64 damage; + bool rmdamage = false;//magic reflected + bool additional_effects = true, shadow_flag = false; if(skill_id > 0 && !skill_lv) return 0; - nullpo_ret(src); //Source is the master behind the attack (player/mob/pet) - nullpo_ret(dsrc); //dsrc is the actual originator of the damage, can be the same as src, or a skill casted by src. + nullpo_ret(src); // Source is the master behind the attack (player/mob/pet) + nullpo_ret(dsrc); // dsrc is the actual originator of the damage, can be the same as src, or a skill casted by src. nullpo_ret(bl); //Target to be attacked. if (src != dsrc) { //When caster is not the src of attack, this is a ground skill, and as such, do the relevant target checking. [Skotlex] - if (!status_check_skilluse(battle_config.skill_caster_check?src:NULL, bl, skill_id, 2)) + if (!status->check_skilluse(battle_config.skill_caster_check?src:NULL, bl, skill_id, 2)) return 0; } else if ((flag&SD_ANIMATION) && skill->get_nk(skill_id)&NK_SPLASH) { - //Note that splash attacks often only check versus the targetted mob, those around the splash area normally don't get checked for being hidden/cloaked/etc. [Skotlex] - if (!status_check_skilluse(src, bl, skill_id, 2)) + //Note that splash attacks often only check versus the targeted mob, those around the splash area normally don't get checked for being hidden/cloaked/etc. [Skotlex] + if (!status->check_skilluse(src, bl, skill_id, 2)) return 0; } sd = BL_CAST(BL_PC, src); tsd = BL_CAST(BL_PC, bl); - sstatus = status_get_status_data(src); - tstatus = status_get_status_data(bl); - sc= status_get_sc(bl); + // To block skills that aren't called via battle_check_target [Panikon] + // issue: 8203 + if( sd + && ( (bl->type == BL_MOB && pc_has_permission(sd, PC_PERM_DISABLE_PVM)) + || (bl->type == BL_PC && pc_has_permission(sd, PC_PERM_DISABLE_PVP)) ) + ) + return 0; + + sstatus = status->get_status_data(src); + tstatus = status->get_status_data(bl); + sc = status->get_sc(bl); if (sc && !sc->count) sc = NULL; //Don't need it. // Is this check really needed? FrostNova won't hurt you if you step right where the caster is? @@ -2220,28 +2177,29 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds } } - if( dmg.flag&BF_MAGIC && ( skill_id != NPC_EARTHQUAKE || (battle_config.eq_single_target_reflectable && (flag&0xFFF) == 1) ) ) - { // Earthquake on multiple targets is not counted as a target skill. [Inkfish] - if( (dmg.damage || dmg.damage2) && (type = skill->magic_reflect(src, bl, src==dsrc)) ) - { //Magic reflection, switch caster/target + if( dmg.flag&BF_MAGIC && ( skill_id != NPC_EARTHQUAKE || (battle_config.eq_single_target_reflectable && (flag&0xFFF) == 1) ) ) { + // Earthquake on multiple targets is not counted as a target skill. [Inkfish] + if( (dmg.damage || dmg.damage2) && (type = skill->magic_reflect(src, bl, src==dsrc)) ) { + //Magic reflection, switch caster/target struct block_list *tbl = bl; - rmdamage = 1; + rmdamage = true; bl = src; src = tbl; dsrc = tbl; sd = BL_CAST(BL_PC, src); tsd = BL_CAST(BL_PC, bl); - sc = status_get_sc(bl); + sc = status->get_sc(bl); if (sc && !sc->count) sc = NULL; //Don't need it. /* bugreport:2564 flag&2 disables double casting trigger */ flag |= 2; - + /* bugreport:7859 magical reflected zeroes blow count */ + dmg.blewcount = 0; //Spirit of Wizard blocks Kaite's reflection - if( type == 2 && sc && sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_WIZARD ) - { //Consume one Fragment per hit of the casted skill? [Skotlex] - type = tsd?pc->search_inventory (tsd, 7321):0; - if (type >= 0) { + if (type == 2 && sc && sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_WIZARD) { + //Consume one Fragment per hit of the casted skill? [Skotlex] + type = tsd ? pc->search_inventory(tsd, ITEMID_FRAGMENT_OF_CRYSTAL) : 0; + if (type != INDEX_NOT_FOUND) { if ( tsd ) pc->delitem(tsd, type, 1, 0, 1, LOG_TYPE_CONSUME); dmg.damage = dmg.damage2 = 0; dmg.dmg_lv = ATK_MISS; @@ -2255,31 +2213,38 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds * Official Magic Reflection Behavior : damage reflected depends on gears caster wears, not target **/ #if MAGIC_REFLECTION_TYPE - if( dmg.dmg_lv != ATK_MISS ){ //Wiz SL cancelled and consumed fragment + + #ifdef RENEWAL + if( dmg.dmg_lv != ATK_MISS ) // Wiz SL canceled and consumed fragment + #else + // issue:6415 in pre-renewal Kaite reflected the entire damage received + // regardless of caster's equipment (Aegis 11.1) + if( dmg.dmg_lv != ATK_MISS && type == 1 ) //Wiz SL canceled and consumed fragment + #endif + { short s_ele = skill->get_ele(skill_id, skill_lv); if (s_ele == -1) // the skill takes the weapon's element s_ele = sstatus->rhw.ele; else if (s_ele == -2) //Use status element - s_ele = status_get_attack_sc_element(src,status_get_sc(src)); + s_ele = status_get_attack_sc_element(src,status->get_sc(src)); else if( s_ele == -3 ) //Use random element s_ele = rnd()%ELE_MAX; dmg.damage = battle->attr_fix(bl, bl, dmg.damage, s_ele, status_get_element(bl), status_get_element_level(bl)); if( sc && sc->data[SC_ENERGYCOAT] ) { - struct status_data *status = status_get_status_data(bl); - int per = 100*status->sp / status->max_sp -1; //100% should be counted as the 80~99% interval + struct status_data *st = status->get_status_data(bl); + int per = 100*st->sp / st->max_sp -1; //100% should be counted as the 80~99% interval per /=20; //Uses 20% SP intervals. //SP Cost: 1% + 0.5% per every 20% SP - if (!status_charge(bl, 0, (10+5*per)*status->max_sp/1000)) + if (!status->charge(bl, 0, (10+5*per)*st->max_sp/1000)) status_change_end(bl, SC_ENERGYCOAT, INVALID_TIMER); //Reduction: 6% + 6% every 20% dmg.damage -= dmg.damage * (6 * (1+per)) / 100; } - } - #endif + #endif /* MAGIC_REFLECTION_TYPE */ } if(sc && sc->data[SC_MAGICROD] && src == dsrc) { int sp = skill->get_sp(skill_id,skill_lv); @@ -2288,7 +2253,7 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds sp = sp * sc->data[SC_MAGICROD]->val2 / 100; if(skill_id == WZ_WATERBALL && skill_lv > 1) sp = sp/((skill_lv|1)*(skill_lv|1)); //Estimate SP cost of a single water-ball - status_heal(bl, 0, sp, 2); + status->heal(bl, 0, sp, 2); } } @@ -2327,7 +2292,7 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds } if(sd) { - int flag = 0; //Used to signal if this skill can be combo'ed later on. + int combo = 0; //Used to signal if this skill can be combo'ed later on. struct status_change_entry *sce; if ((sce = sd->sc.data[SC_COMBOATTACK])) {//End combo state after skill is invoked. [Skotlex] switch (skill_id) { @@ -2339,11 +2304,11 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds sce->val1 = skill_id; //Update combo-skill sce->val3 = skill_id; if( sce->timer != INVALID_TIMER ) - iTimer->delete_timer(sce->timer, status_change_timer); - sce->timer = iTimer->add_timer(tick+sce->val4, status_change_timer, src->id, SC_COMBOATTACK); + timer->delete(sce->timer, status->change_timer); + sce->timer = timer->add(tick+sce->val4, status->change_timer, src->id, SC_COMBOATTACK); break; } - unit_cancel_combo(src); // Cancel combo wait + unit->cancel_combo(src); // Cancel combo wait break; default: if( src == dsrc ) // Ground skills are exceptions. [Inkfish] @@ -2353,29 +2318,30 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds switch(skill_id) { case MO_TRIPLEATTACK: if (pc->checkskill(sd, MO_CHAINCOMBO) > 0 || pc->checkskill(sd, SR_DRAGONCOMBO) > 0) - flag=1; + combo=1; break; case MO_CHAINCOMBO: if(pc->checkskill(sd, MO_COMBOFINISH) > 0 && sd->spiritball > 0) - flag=1; + combo=1; break; case MO_COMBOFINISH: if (sd->status.party_id>0) //bonus from SG_FRIEND [Komurka] party->skill_check(sd, sd->status.party_id, MO_COMBOFINISH, skill_lv); if (pc->checkskill(sd, CH_TIGERFIST) > 0 && sd->spiritball > 0) - flag=1; + combo=1; case CH_TIGERFIST: - if (!flag && pc->checkskill(sd, CH_CHAINCRUSH) > 0 && sd->spiritball > 1) - flag=1; + if (!combo && pc->checkskill(sd, CH_CHAINCRUSH) > 0 && sd->spiritball > 1) + combo=1; case CH_CHAINCRUSH: - if (!flag && pc->checkskill(sd, MO_EXTREMITYFIST) > 0 && sd->spiritball > 0 && sd->sc.data[SC_EXPLOSIONSPIRITS]) - flag=1; + if (!combo && pc->checkskill(sd, MO_EXTREMITYFIST) > 0 && sd->spiritball > 0 && sd->sc.data[SC_EXPLOSIONSPIRITS]) + combo=1; break; case AC_DOUBLE: - if( (tstatus->race == RC_BRUTE || tstatus->race == RC_INSECT) && pc->checkskill(sd, HT_POWER)) - { - //TODO: This code was taken from Triple Blows, is this even how it should be? [Skotlex] - sc_start2(src,SC_COMBOATTACK,100,HT_POWER,bl->id,2000); + // AC_DOUBLE can start the combo with other monster types, but the + // monster that's going to be hit by HT_POWER should be RC_BRUTE or RC_INSECT [Panikon] + if( pc->checkskill(sd, HT_POWER) ) + { + sc_start4(NULL,src,SC_COMBOATTACK,100,HT_POWER,0,1,0,2000); clif->combo_delay(src,2000); } break; @@ -2389,7 +2355,7 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds case SL_STIN: case SL_STUN: if (skill_lv >= 7 && !sd->sc.data[SC_SMA_READY]) - sc_start(src,SC_SMA_READY,100,skill_lv,skill->get_time(SL_SMA, skill_lv)); + sc_start(src, src,SC_SMA_READY,100,skill_lv,skill->get_time(SL_SMA, skill_lv)); break; case GS_FULLBUSTER: //Can't attack nor use items until skill's delay expires. [Skotlex] @@ -2397,21 +2363,21 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds break; case TK_DODGE: if( pc->checkskill(sd, TK_JUMPKICK) > 0 ) - flag = 1; + combo = 1; break; case SR_DRAGONCOMBO: if( pc->checkskill(sd, SR_FALLENEMPIRE) > 0 ) - flag = 1; + combo = 1; break; case SR_FALLENEMPIRE: if( pc->checkskill(sd, SR_TIGERCANNON) > 0 || pc->checkskill(sd, SR_GATEOFHELL) > 0 ) - flag = 1; + combo = 1; break; } //Switch End - if (flag) { //Possible to chain - if ( (flag = DIFF_TICK(sd->ud.canact_tick, tick)) < 50 ) flag = 50;/* less is a waste. */ - sc_start2(src,SC_COMBOATTACK,100,skill_id,bl->id,flag); - clif->combo_delay(src, flag); + if (combo) { //Possible to chain + if ( (combo = DIFF_TICK32(sd->ud.canact_tick, tick)) < 50 ) combo = 50;/* less is a waste. */ + sc_start2(NULL,src,SC_COMBOATTACK,100,skill_id,bl->id,combo); + clif->combo_delay(src, combo); } } @@ -2431,7 +2397,7 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds case NPC_CRITICALSLASH: case TF_DOUBLE: case GS_CHAINACTION: - dmg.dmotion = clif->damage(src,bl,tick,dmg.amotion,dmg.dmotion,damage,dmg.div_,dmg.type,dmg.damage2); + dmg.dmotion = clif->damage(src,bl,dmg.amotion,dmg.dmotion,damage,dmg.div_,dmg.type,dmg.damage2); break; case AS_SPLASHER: @@ -2456,7 +2422,11 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds dmg.dmotion = clif->skill_damage(src,bl,tick,dmg.amotion,dmg.dmotion,damage,1,WL_CHAINLIGHTNING,-2,6); break; case LG_OVERBRAND_BRANDISH: + case LG_OVERBRAND: + dmg.amotion = status_get_amotion(src) * 2; case LG_OVERBRAND_PLUSATK: + dmg.dmotion = clif->skill_damage(dsrc,bl,tick,status_get_amotion(src),dmg.dmotion,damage,dmg.div_,skill_id,-1,5); + break; case EL_FIRE_BOMB: case EL_FIRE_BOMB_ATK: case EL_FIRE_WAVE: @@ -2473,19 +2443,26 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds case EL_ROCK_CRUSHER_ATK: case EL_HURRICANE: case EL_HURRICANE_ATK: + case EL_TYPOON_MIS: + case EL_TYPOON_MIS_ATK: case KO_BAKURETSU: - case GN_CRAZYWEED_ATK: case NC_MAGMA_ERUPTION: dmg.dmotion = clif->skill_damage(src,bl,tick,dmg.amotion,dmg.dmotion,damage,dmg.div_,skill_id,-1,5); break; case GN_SLINGITEM_RANGEMELEEATK: dmg.dmotion = clif->skill_damage(src,bl,tick,dmg.amotion,dmg.dmotion,damage,dmg.div_,GN_SLINGITEM,-2,6); break; + case SC_FEINTBOMB: + dmg.dmotion = clif->skill_damage(src,bl,tick,dmg.amotion,dmg.dmotion,damage,1,skill_id,skill_lv,5); + break; + case GN_CRAZYWEED_ATK: + dmg.dmotion = clif->skill_damage(src,bl,tick,dmg.amotion,dmg.dmotion,damage,dmg.div_,skill_id, -2, 6); + break; case EL_STONE_RAIN: dmg.dmotion = clif->skill_damage(dsrc,bl,tick,dmg.amotion,dmg.dmotion,damage,dmg.div_,skill_id,-1,(flag&1)?8:5); break; case WM_SEVERE_RAINSTORM_MELEE: - dmg.dmotion = clif->skill_damage(src,bl,tick,dmg.amotion,dmg.dmotion,damage,dmg.div_,WM_SEVERE_RAINSTORM,skill_lv,5); + dmg.dmotion = clif->skill_damage(src,bl,tick,dmg.amotion,dmg.dmotion,damage,dmg.div_,WM_SEVERE_RAINSTORM,-2,6); break; case WM_REVERBERATION_MELEE: case WM_REVERBERATION_MAGIC: @@ -2528,7 +2505,7 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds break; } - iMap->freeblock_lock(); + map->freeblock_lock(); if(damage > 0 && dmg.flag&BF_SKILL && tsd && pc->checkskill(tsd,RG_PLAGIARISM) @@ -2537,7 +2514,7 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds { //Updated to not be able to copy skills if the blow will kill you. [Skotlex] int copy_skill = skill_id, cidx = 0; /** - * Copy Referal: dummy skills should point to their source upon copying + * Copy Referral: dummy skills should point to their source upon copying **/ switch( skill_id ) { case AB_DUPLELIGHT_MELEE: @@ -2560,6 +2537,9 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds case GN_HELLS_PLANT_ATK: copy_skill = GN_HELLS_PLANT; break; + case GN_SLINGITEM_RANGEMELEEATK: + copy_skill = GN_SLINGITEM; + break; case LG_OVERBRAND_BRANDISH: case LG_OVERBRAND_PLUSATK: copy_skill = LG_OVERBRAND; @@ -2585,8 +2565,8 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds } tsd->reproduceskill_id = copy_skill; - pc_setglobalreg(tsd, "REPRODUCE_SKILL", copy_skill); - pc_setglobalreg(tsd, "REPRODUCE_SKILL_LV", lv); + pc_setglobalreg(tsd, script->add_str("REPRODUCE_SKILL"), copy_skill); + pc_setglobalreg(tsd, script->add_str("REPRODUCE_SKILL_LV"), lv); tsd->status.skill[cidx].id = copy_skill; tsd->status.skill[cidx].lv = lv; @@ -2608,8 +2588,8 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds lv = type; tsd->cloneskill_id = copy_skill; - pc_setglobalreg(tsd, "CLONE_SKILL", copy_skill); - pc_setglobalreg(tsd, "CLONE_SKILL_LV", lv); + pc_setglobalreg(tsd, script->add_str("CLONE_SKILL"), copy_skill); + pc_setglobalreg(tsd, script->add_str("CLONE_SKILL_LV"), lv); tsd->status.skill[cidx].id = copy_skill; tsd->status.skill[cidx].lv = lv; @@ -2622,76 +2602,74 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds if (dmg.dmg_lv >= ATK_MISS && (type = skill->get_walkdelay(skill_id, skill_lv)) > 0) { //Skills with can't walk delay also stop normal attacking for that //duration when the attack connects. [Skotlex] - struct unit_data *ud = unit_bl2ud(src); + struct unit_data *ud = unit->bl2ud(src); if (ud && DIFF_TICK(ud->attackabletime, tick + type) < 0) ud->attackabletime = tick + type; } + + shadow_flag = skill->check_shadowform(bl, damage, dmg.div_); if( !dmg.amotion ) { //Instant damage - if( !sc || (!sc->data[SC_DEVOTION] && skill_id != CR_REFLECTSHIELD) ) + if( (!sc || (!sc->data[SC_DEVOTION] && skill_id != CR_REFLECTSHIELD)) && !shadow_flag) status_fix_damage(src,bl,damage,dmg.dmotion); //Deal damage before knockback to allow stuff like firewall+storm gust combo. - if( !status_isdead(bl) && additional_effects ) + if( !status->isdead(bl) && additional_effects ) skill->additional_effect(src,bl,skill_id,skill_lv,dmg.flag,dmg.dmg_lv,tick); if( damage > 0 ) //Counter status effects [Skotlex] skill->counter_additional_effect(src,bl,skill_id,skill_lv,dmg.flag,tick); } // Hell Inferno burning status only starts if Fire part hits. if( skill_id == WL_HELLINFERNO && dmg.damage > 0 && !(flag&ELE_DARK) ) - sc_start4(bl,SC_BURNING,55+5*skill_lv,skill_lv,0,src->id,0,skill->get_time(skill_id,skill_lv)); + sc_start4(src,bl,SC_BURNING,55+5*skill_lv,skill_lv,0,src->id,0,skill->get_time(skill_id,skill_lv)); // Apply knock back chance in SC_TRIANGLESHOT skill. else if( skill_id == SC_TRIANGLESHOT && rnd()%100 > (1 + skill_lv) ) dmg.blewcount = 0; //Only knockback if it's still alive, otherwise a "ghost" is left behind. [Skotlex] //Reflected spells do not bounce back (bl == dsrc since it only happens for direct skills) - if (dmg.blewcount > 0 && bl!=dsrc && !status_isdead(bl)) { + if (dmg.blewcount > 0 && bl!=dsrc && !status->isdead(bl)) { int8 dir = -1; // default switch(skill_id) {//direction case MG_FIREWALL: case PR_SANCTUARY: case SC_TRIANGLESHOT: - case LG_OVERBRAND: case SR_KNUCKLEARROW: case GN_WALLOFTHORN: case EL_FIRE_MANTLE: - dir = unit_getdir(bl);// backwards + dir = unit->getdir(bl);// backwards break; // This ensures the storm randomly pushes instead of exactly a cell backwards per official mechanics. case WZ_STORMGUST: - dir = rand()%8; + dir = rnd()%8; break; case WL_CRIMSONROCK: - dir = iMap->calc_dir(bl,skill_area_temp[4],skill_area_temp[5]); + dir = map->calc_dir(bl,skill->area_temp[4],skill->area_temp[5]); + break; + case MC_CARTREVOLUTION: + dir = 6; // Official servers push target to the West break; } + + /* monsters with skill lv higher than MAX_SKILL_LEVEL may get this value beyond the max depending on conditions, we cap to the system's limit */ + if( dsrc && dsrc->type == BL_MOB && skill_lv > MAX_SKILL_LEVEL && dmg.blewcount > 25 ) + dmg.blewcount = 25; + //blown-specific handling switch( skill_id ) { - case LG_OVERBRAND: - if( skill->blown(dsrc,bl,dmg.blewcount,dir,0) ) { - short dir_x, dir_y; - dir_x = dirx[(dir+4)%8]; - dir_y = diry[(dir+4)%8]; - if( iMap->getcell(bl->m, bl->x+dir_x, bl->y+dir_y, CELL_CHKNOPASS) != 0 ) - skill->addtimerskill(src, tick + status_get_amotion(src), bl->id, 0, 0, LG_OVERBRAND_PLUSATK, skill_lv, BF_WEAPON, flag ); - } else - skill->addtimerskill(src, tick + status_get_amotion(src), bl->id, 0, 0, LG_OVERBRAND_PLUSATK, skill_lv, BF_WEAPON, flag ); + case LG_OVERBRAND_BRANDISH: + if( skill->blown(dsrc,bl,dmg.blewcount,dir,0) < dmg.blewcount ) + skill->addtimerskill(src, tick + status_get_amotion(src), bl->id, 0, 0, LG_OVERBRAND_PLUSATK, skill_lv, BF_WEAPON, flag|SD_ANIMATION); break; case SR_KNUCKLEARROW: if( skill->blown(dsrc,bl,dmg.blewcount,dir,0) && !(flag&4) ) { short dir_x, dir_y; dir_x = dirx[(dir+4)%8]; dir_y = diry[(dir+4)%8]; - if( iMap->getcell(bl->m, bl->x+dir_x, bl->y+dir_y, CELL_CHKNOPASS) != 0 ) + if( map->getcell(bl->m, bl->x+dir_x, bl->y+dir_y, CELL_CHKNOPASS) != 0 ) skill->addtimerskill(src, tick + 300 * ((flag&2) ? 1 : 2), bl->id, 0, 0, skill_id, skill_lv, BF_WEAPON, flag|4); } break; - case GN_WALLOFTHORN: - unit_stop_walking(bl,1); - skill->blown(dsrc,bl,dmg.blewcount,dir, 0x2 ); - clif->fixpos(bl); - break; default: skill->blown(dsrc,bl,dmg.blewcount,dir, 0x0 ); if ( !dmg.blewcount && bl->type == BL_SKILL && damage > 0 ){ @@ -2704,12 +2682,19 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds } //Delayed damage must be dealt after the knockback (it needs to know actual position of target) - if (dmg.amotion) - battle->delay_damage(tick, dmg.amotion,src,bl,dmg.flag,skill_id,skill_lv,damage,dmg.dmg_lv,dmg.dmotion, additional_effects); + if (dmg.amotion){ + if( shadow_flag ){ + if( !status->isdead(bl) && additional_effects ) + skill->additional_effect(src,bl,skill_id,skill_lv,dmg.flag,dmg.dmg_lv,tick); + if( dmg.flag > ATK_BLOCK ) + skill->counter_additional_effect(src,bl,skill_id,skill_lv,dmg.flag,tick); + }else + battle->delay_damage(tick, dmg.amotion,src,bl,dmg.flag,skill_id,skill_lv,damage,dmg.dmg_lv,dmg.dmotion, additional_effects); + } if( sc && sc->data[SC_DEVOTION] && skill_id != PA_PRESSURE ) { struct status_change_entry *sce = sc->data[SC_DEVOTION]; - struct block_list *d_bl = iMap->id2bl(sce->val1); + struct block_list *d_bl = map->id2bl(sce->val1); if( d_bl && ( (d_bl->type == BL_MER && ((TBL_MER*)d_bl)->master && ((TBL_MER*)d_bl)->master->bl.id == bl->id) || @@ -2717,12 +2702,12 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds ) && check_distance_bl(bl, d_bl, sce->val3) ) { if(!rmdamage){ - clif->damage(d_bl,d_bl, iTimer->gettick(), 0, 0, damage, 0, 0, 0); + clif->damage(d_bl,d_bl, 0, 0, damage, 0, 0, 0); status_fix_damage(NULL,d_bl, damage, 0); } else{ //Reflected magics are done directly on the target not on paladin //This check is only for magical skill. //For BF_WEAPON skills types track var rdamage and function battle_calc_return_damage - clif->damage(bl,bl, iTimer->gettick(), 0, 0, damage, 0, 0, 0); + clif->damage(bl,bl, 0, 0, damage, 0, 0, 0); status_fix_damage(bl,bl, damage, 0); } } @@ -2736,11 +2721,11 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds if(damage > 0 && !(tstatus->mode&MD_BOSS)) { if( skill_id == RG_INTIMIDATE ) { int rate = 50 + skill_lv * 5; - rate = rate + (status_get_lv(src) - status_get_lv(bl)); + rate = rate + (status->get_lv(src) - status->get_lv(bl)); if(rnd()%100 < rate) skill->addtimerskill(src,tick + 800,bl->id,0,0,skill_id,skill_lv,0,flag); } else if( skill_id == SC_FATALMENACE ) - skill->addtimerskill(src,tick + 800,bl->id,skill_area_temp[4],skill_area_temp[5],skill_id,skill_lv,0,flag); + skill->addtimerskill(src,tick + 800,bl->id,skill->area_temp[4],skill->area_temp[5],skill_id,skill_lv,0,flag); } if(skill_id == CR_GRANDCROSS || skill_id == NPC_GRANDDARKNESS) @@ -2761,17 +2746,18 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds * Post-damage effects **/ switch( skill_id ) { - case RK_CRUSHSTRIKE: - skill->break_equip(src,EQP_WEAPON,2000,BCT_SELF); // 20% chance to destroy the weapon. - break; - case GC_VENOMPRESSURE: { - struct status_change *ssc = status_get_sc(src); - if( ssc && ssc->data[SC_POISONINGWEAPON] && rnd()%100 < 70 + 5*skill_lv ) { - sc_start(bl,ssc->data[SC_POISONINGWEAPON]->val2,100,ssc->data[SC_POISONINGWEAPON]->val1,skill->get_time2(GC_POISONINGWEAPON, 1)); - status_change_end(src,SC_POISONINGWEAPON,INVALID_TIMER); - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - } + case GC_VENOMPRESSURE: + { + struct status_change *ssc = status->get_sc(src); + if( ssc && ssc->data[SC_POISONINGWEAPON] && rnd()%100 < 70 + 5*skill_lv ) { + short rate = 100; + if ( ssc->data[SC_POISONINGWEAPON]->val1 == 9 )// Oblivion Curse gives a 2nd success chance after the 1st one passes which is reducible. [Rytech] + rate = 100 - tstatus->int_ * 4 / 5; + sc_start(src, bl,ssc->data[SC_POISONINGWEAPON]->val2,rate,ssc->data[SC_POISONINGWEAPON]->val1,skill->get_time2(GC_POISONINGWEAPON,1) - (tstatus->vit + tstatus->luk) / 2 * 1000); + status_change_end(src,SC_POISONINGWEAPON,-1); + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); } + } break; case WM_METALICSOUND: status_zap(bl, 0, damage*100/(100*(110-pc->checkskill(sd,WM_LESSON)*10))); @@ -2784,52 +2770,49 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds skill->onskillusage(sd, bl, skill_id, tick); } - if (!(flag&2) && - ( - skill_id == MG_COLDBOLT || skill_id == MG_FIREBOLT || skill_id == MG_LIGHTNINGBOLT - ) && - (sc = status_get_sc(src)) && - sc->data[SC_DOUBLECASTING] && - rnd() % 100 < sc->data[SC_DOUBLECASTING]->val2) - { -// skill->addtimerskill(src, tick + dmg.div_*dmg.amotion, bl->id, 0, 0, skill_id, skill_lv, BF_MAGIC, flag|2); + if (!(flag&2) + && (skill_id == MG_COLDBOLT || skill_id == MG_FIREBOLT || skill_id == MG_LIGHTNINGBOLT) + && (sc = status->get_sc(src)) + && sc->data[SC_DOUBLECASTING] + && rnd() % 100 < sc->data[SC_DOUBLECASTING]->val2 + ) { + //skill->addtimerskill(src, tick + dmg.div_*dmg.amotion, bl->id, 0, 0, skill_id, skill_lv, BF_MAGIC, flag|2); skill->addtimerskill(src, tick + dmg.amotion, bl->id, 0, 0, skill_id, skill_lv, BF_MAGIC, flag|2); } - iMap->freeblock_unlock(); + map->freeblock_unlock(); - return damage; + return (int)cap_value(damage,INT_MIN,INT_MAX); } /*========================================== - * sub fonction for recursive skill call. - * Checking bl battle flag and display dammage + * sub function for recursive skill call. + * Checking bl battle flag and display damage * then call func with source,target,skill_id,skill_lv,tick,flag *------------------------------------------*/ -typedef int (*SkillFunc)(struct block_list *, struct block_list *, int, int, unsigned int, int); -int skill_area_sub (struct block_list *bl, va_list ap) { +int skill_area_sub(struct block_list *bl, va_list ap) { struct block_list *src; uint16 skill_id,skill_lv; int flag; - unsigned int tick; + int64 tick; SkillFunc func; nullpo_ret(bl); - src=va_arg(ap,struct block_list *); - skill_id=va_arg(ap,int); - skill_lv=va_arg(ap,int); - tick=va_arg(ap,unsigned int); - flag=va_arg(ap,int); - func=va_arg(ap,SkillFunc); + src = va_arg(ap,struct block_list *); + skill_id = va_arg(ap,int); + skill_lv = va_arg(ap,int); + tick = va_arg(ap,int64); + flag = va_arg(ap,int); + func = va_arg(ap,SkillFunc); if(battle->check_target(src,bl,flag) > 0) { // several splash skills need this initial dummy packet to display correctly - if (flag&SD_PREAMBLE && skill_area_temp[2] == 0) + if (flag&SD_PREAMBLE && skill->area_temp[2] == 0) clif->skill_damage(src,bl,tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6); if (flag&(SD_SPLASH|SD_PREAMBLE)) - skill_area_temp[2]++; + skill->area_temp[2]++; return func(src,bl,skill_id,skill_lv,tick,flag); } @@ -2837,26 +2820,27 @@ int skill_area_sub (struct block_list *bl, va_list ap) { } int skill_check_unit_range_sub (struct block_list *bl, va_list ap) { - struct skill_unit *unit; + struct skill_unit *su; uint16 skill_id,g_skill_id; - unit = (struct skill_unit *)bl; + su = (struct skill_unit *)bl; if(bl->prev == NULL || bl->type != BL_SKILL) return 0; - if(!unit->alive) + if(!su->alive) return 0; skill_id = va_arg(ap,int); - g_skill_id = unit->group->skill_id; + g_skill_id = su->group->skill_id; switch (skill_id) { case MH_STEINWAND: case MG_SAFETYWALL: case AL_PNEUMA: case SC_MAELSTROM: - if(g_skill_id != MH_STEINWAND && g_skill_id != MG_SAFETYWALL && g_skill_id != AL_PNEUMA && g_skill_id != SC_MAELSTROM) + case SO_ELEMENTAL_SHIELD: + if(g_skill_id != MH_STEINWAND && g_skill_id != MG_SAFETYWALL && g_skill_id != AL_PNEUMA && g_skill_id != SC_MAELSTROM && g_skill_id != SO_ELEMENTAL_SHIELD) return 0; break; case AL_WARP: @@ -2885,6 +2869,8 @@ int skill_check_unit_range_sub (struct block_list *bl, va_list ap) { case RA_ICEBOUNDTRAP: case SC_DIMENSIONDOOR: case SC_BLOODYLUST: + case SC_CHAOSPANIC: + case GN_HELLS_PLANT: //Non stackable on themselves and traps (including venom dust which does not has the trap inf2 set) if (skill_id != g_skill_id && !(skill->get_inf2(g_skill_id)&INF2_TRAP) && g_skill_id != AS_VENOMDUST && g_skill_id != MH_POISON_MIST) return 0; @@ -2908,7 +2894,7 @@ int skill_check_unit_range (struct block_list *bl, int x, int y, uint16 skill_id } range += layout_type; - return iMap->foreachinarea(skill->check_unit_range_sub,bl->m,x-range,y-range,x+range,y+range,BL_SKILL,skill_id); + return map->foreachinarea(skill->check_unit_range_sub,bl->m,x-range,y-range,x+range,y+range,BL_SKILL,skill_id); } int skill_check_unit_range2_sub (struct block_list *bl, va_list ap) { @@ -2919,7 +2905,7 @@ int skill_check_unit_range2_sub (struct block_list *bl, va_list ap) { skill_id = va_arg(ap,int); - if( status_isdead(bl) && skill_id != AL_WARP ) + if( status->isdead(bl) && skill_id != AL_WARP ) return 0; if( skill_id == HP_BASILICA && bl->type == BL_PC ) @@ -2937,6 +2923,12 @@ int skill_check_unit_range2 (struct block_list *bl, int x, int y, uint16 skill_i case WZ_ICEWALL: range = 2; break; + case SC_MANHOLE: + range = 0; + break; + case GN_HELLS_PLANT: + range = 0; + break; default: { int layout_type = skill->get_unit_layout_type(skill_id,skill_lv); if (layout_type==-1 || layout_type>MAX_SQUARE_LAYOUT) { @@ -2955,27 +2947,9 @@ int skill_check_unit_range2 (struct block_list *bl, int x, int y, uint16 skill_i else type = BL_PC; - return iMap->foreachinarea(skill->check_unit_range2_sub, bl->m, - x - range, y - range, x + range, y + range, - type, skill_id); -} - -int skill_guildaura_sub (struct map_session_data* sd, int id, int strvit, int agidex) -{ - if(id == sd->bl.id && battle_config.guild_aura&16) - return 0; // Do not affect guild leader - - if (sd->sc.data[SC_GUILDAURA]) { - struct status_change_entry *sce = sd->sc.data[SC_GUILDAURA]; - if( sce->val3 != strvit || sce->val4 != agidex ) { - sce->val3 = strvit; - sce->val4 = agidex; - status_calc_bl(&sd->bl, status_sc2scb_flag(SC_GUILDAURA)); - } - return 0; - } - sc_start4(&sd->bl, SC_GUILDAURA,100, 1, id, strvit, agidex, 1000); - return 1; + return map->foreachinarea(skill->check_unit_range2_sub, bl->m, + x - range, y - range, x + range, y + range, + type, skill_id); } /*========================================== @@ -2985,7 +2959,7 @@ int skill_guildaura_sub (struct map_session_data* sd, int id, int strvit, int ag * &2: picked menu entry (Warp Portal, Teleport and other menu based skills) *------------------------------------------*/ int skill_check_condition_mercenary(struct block_list *bl, int skill_id, int lv, int type) { - struct status_data *status; + struct status_data *st; struct map_session_data *sd = NULL; int i, hp, sp, hp_rate, sp_rate, state, mhp; uint16 idx; @@ -2995,39 +2969,38 @@ int skill_check_condition_mercenary(struct block_list *bl, int skill_id, int lv, return 0; nullpo_ret(bl); - switch( bl->type ) - { + switch( bl->type ) { case BL_HOM: sd = ((TBL_HOM*)bl)->master; break; case BL_MER: sd = ((TBL_MER*)bl)->master; break; } - status = status_get_status_data(bl); + st = status->get_status_data(bl); if( (idx = skill->get_index(skill_id)) == 0 ) return 0; - // Requeriments + // Requirements for( i = 0; i < ARRAYLENGTH(itemid); i++ ) { - itemid[i] = skill_db[idx].itemid[i]; - amount[i] = skill_db[idx].amount[i]; - } - hp = skill_db[idx].hp[lv-1]; - sp = skill_db[idx].sp[lv-1]; - hp_rate = skill_db[idx].hp_rate[lv-1]; - sp_rate = skill_db[idx].sp_rate[lv-1]; - state = skill_db[idx].state; - if( (mhp = skill_db[idx].mhp[lv-1]) > 0 ) - hp += (status->max_hp * mhp) / 100; + itemid[i] = skill->db[idx].itemid[i]; + amount[i] = skill->db[idx].amount[i]; + } + hp = skill->db[idx].hp[lv-1]; + sp = skill->db[idx].sp[lv-1]; + hp_rate = skill->db[idx].hp_rate[lv-1]; + sp_rate = skill->db[idx].sp_rate[lv-1]; + state = skill->db[idx].state; + if( (mhp = skill->db[idx].mhp[lv-1]) > 0 ) + hp += (st->max_hp * mhp) / 100; if( hp_rate > 0 ) - hp += (status->hp * hp_rate) / 100; + hp += (st->hp * hp_rate) / 100; else - hp += (status->max_hp * (-hp_rate)) / 100; + hp += (st->max_hp * (-hp_rate)) / 100; if( sp_rate > 0 ) - sp += (status->sp * sp_rate) / 100; + sp += (st->sp * sp_rate) / 100; else - sp += (status->max_sp * (-sp_rate)) / 100; + sp += (st->max_sp * (-sp_rate)) / 100; - if( bl->type == BL_HOM ) { // Intimacy Requeriments + if( bl->type == BL_HOM ) { // Intimacy Requirements struct homun_data *hd = BL_CAST(BL_HOM, bl); switch( skill_id ) { case HFLI_SBR44: @@ -3042,11 +3015,11 @@ int skill_check_condition_mercenary(struct block_list *bl, int skill_id, int lv, } if( !(type&2) ) { - if( hp > 0 && status->hp <= (unsigned int)hp ) { + if( hp > 0 && st->hp <= (unsigned int)hp ) { clif->skill_fail(sd, skill_id, USESKILL_FAIL_HP_INSUFFICIENT, 0); return 0; } - if( sp > 0 && status->sp <= (unsigned int)sp ) { + if( sp > 0 && st->sp <= (unsigned int)sp ) { clif->skill_fail(sd, skill_id, USESKILL_FAIL_SP_INSUFFICIENT, 0); return 0; } @@ -3055,7 +3028,7 @@ int skill_check_condition_mercenary(struct block_list *bl, int skill_id, int lv, if( !type ) switch( state ) { case ST_MOVE_ENABLE: - if( !unit_can_move(bl) ) { + if( !unit->can_move(bl) ) { clif->skill_fail(sd, skill_id, USESKILL_FAIL_LEVEL, 0); return 0; } @@ -3065,22 +3038,20 @@ int skill_check_condition_mercenary(struct block_list *bl, int skill_id, int lv, return 1; // Check item existences - for( i = 0; i < ARRAYLENGTH(itemid); i++ ) - { - index[i] = -1; - if( itemid[i] < 1 ) continue; // No item + for (i = 0; i < ARRAYLENGTH(itemid); i++) { + index[i] = INDEX_NOT_FOUND; + if (itemid[i] < 1) continue; // No item index[i] = pc->search_inventory(sd, itemid[i]); - if( index[i] < 0 || sd->status.inventory[index[i]].amount < amount[i] ) - { + if (index[i] == INDEX_NOT_FOUND || sd->status.inventory[index[i]].amount < amount[i]) { clif->skill_fail(sd, skill_id, USESKILL_FAIL_NEED_ITEM, amount[i]|(itemid[i] << 16)); return 0; } } // Consume items - for( i = 0; i < ARRAYLENGTH(itemid); i++ ) - { - if( index[i] >= 0 ) pc->delitem(sd, index[i], amount[i], 0, 1, LOG_TYPE_CONSUME); + for (i = 0; i < ARRAYLENGTH(itemid); i++) { + if (index[i] != INDEX_NOT_FOUND) + pc->delitem(sd, index[i], amount[i], 0, 1, LOG_TYPE_CONSUME); } if( type&2 ) @@ -3095,16 +3066,16 @@ int skill_check_condition_mercenary(struct block_list *bl, int skill_id, int lv, /*========================================== * what the hell it doesn't need to receive this many params, it doesn't do anything ~_~ *------------------------------------------*/ -int skill_area_sub_count (struct block_list *src, struct block_list *target, uint16 skill_id, uint16 skill_lv, unsigned int tick, int flag) { +int skill_area_sub_count(struct block_list *src, struct block_list *target, uint16 skill_id, uint16 skill_lv, int64 tick, int flag) { return 1; } /*========================================== * *------------------------------------------*/ -int skill_timerskill(int tid, unsigned int tick, int id, intptr_t data) { - struct block_list *src = iMap->id2bl(id),*target; - struct unit_data *ud = unit_bl2ud(src); +int skill_timerskill(int tid, int64 tick, int id, intptr_t data) { + struct block_list *src = map->id2bl(id),*target; + struct unit_data *ud = unit->bl2ud(src); struct skill_timerskill *skl; int range; @@ -3118,7 +3089,7 @@ int skill_timerskill(int tid, unsigned int tick, int id, intptr_t data) { if(src->prev == NULL) break; // Source not on Map if(skl->target_id) { - target = iMap->id2bl(skl->target_id); + target = map->id2bl(skl->target_id); if( ( skl->skill_id == RG_INTIMIDATE || skl->skill_id == SC_FATALMENACE ) && (!target || target->prev == NULL || !check_distance_bl(src,target,AREA_SIZE)) ) target = src; //Required since it has to warp. if(target == NULL) @@ -3127,42 +3098,61 @@ int skill_timerskill(int tid, unsigned int tick, int id, intptr_t data) { break; // Target not on Map if(src->m != target->m) break; // Different Maps - if(status_isdead(src)) - break; // Caster is Dead - if(status_isdead(target) && skl->skill_id != RG_INTIMIDATE && skl->skill_id != WZ_WATERBALL) + if(status->isdead(src)){ + // Exceptions + switch(skl->skill_id){ + case WL_CHAINLIGHTNING_ATK: + case WL_TETRAVORTEX_FIRE: + case WL_TETRAVORTEX_WATER: + case WL_TETRAVORTEX_WIND: + case WL_TETRAVORTEX_GROUND: + // SR_FLASHCOMBO + case SR_DRAGONCOMBO: + case SR_FALLENEMPIRE: + case SR_TIGERCANNON: + case SR_SKYNETBLOW: + break; + default: + continue; // Caster is Dead + } + } + if(status->isdead(target) && skl->skill_id != RG_INTIMIDATE && skl->skill_id != WZ_WATERBALL) break; switch(skl->skill_id) { case RG_INTIMIDATE: - if (unit_warp(src,-1,-1,-1,CLR_TELEPORT) == 0) { + if (unit->warp(src,-1,-1,-1,CLR_TELEPORT) == 0) { short x,y; - iMap->search_freecell(src, 0, &x, &y, 1, 1, 0); - if (target != src && !status_isdead(target)) - unit_warp(target, -1, x, y, CLR_TELEPORT); + map->search_freecell(src, 0, &x, &y, 1, 1, 0); + if (target != src && !status->isdead(target)) + unit->warp(target, -1, x, y, CLR_TELEPORT); } break; case BA_FROSTJOKER: case DC_SCREAM: range= skill->get_splash(skl->skill_id, skl->skill_lv); - iMap->foreachinarea(skill->frostjoke_scream,skl->map,skl->x-range,skl->y-range, - skl->x+range,skl->y+range,BL_CHAR,src,skl->skill_id,skl->skill_lv,tick); + map->foreachinarea(skill->frostjoke_scream,skl->map,skl->x-range,skl->y-range, + skl->x+range,skl->y+range,BL_CHAR,src,skl->skill_id,skl->skill_lv,tick); + break; + case KN_AUTOCOUNTER: + clif->skill_nodamage(src,target,skl->skill_id,skl->skill_lv,1); break; case NPC_EARTHQUAKE: if( skl->type > 1 ) skill->addtimerskill(src,tick+250,src->id,0,0,skl->skill_id,skl->skill_lv,skl->type-1,skl->flag); - skill_area_temp[0] = iMap->foreachinrange(skill->area_sub, src, skill->get_splash(skl->skill_id, skl->skill_lv), BL_CHAR, src, skl->skill_id, skl->skill_lv, tick, BCT_ENEMY, skill->area_sub_count); - skill_area_temp[1] = src->id; - skill_area_temp[2] = 0; - iMap->foreachinrange(skill->area_sub, src, skill->get_splash(skl->skill_id, skl->skill_lv), splash_target(src), src, skl->skill_id, skl->skill_lv, tick, skl->flag, skill->castend_damage_id); + skill->area_temp[0] = map->foreachinrange(skill->area_sub, src, skill->get_splash(skl->skill_id, skl->skill_lv), BL_CHAR, src, skl->skill_id, skl->skill_lv, tick, BCT_ENEMY, skill->area_sub_count); + skill->area_temp[1] = src->id; + skill->area_temp[2] = 0; + map->foreachinrange(skill->area_sub, src, skill->get_splash(skl->skill_id, skl->skill_lv), splash_target(src), src, skl->skill_id, skl->skill_lv, tick, skl->flag, skill->castend_damage_id); break; case WZ_WATERBALL: skill->toggle_magicpower(src, skl->skill_id); // only the first hit will be amplify - if (!status_isdead(target)) + if (!status->isdead(target)) skill->attack(BF_MAGIC,src,src,target,skl->skill_id,skl->skill_lv,tick,skl->flag); - if (skl->type>1 && !status_isdead(target) && !status_isdead(src)) { + if (skl->type>1 && !status->isdead(target) && !status->isdead(src)) { skill->addtimerskill(src,tick+125,target->id,0,0,skl->skill_id,skl->skill_lv,skl->type-1,skl->flag); } else { - struct status_change *sc = status_get_sc(src); + struct status_change *sc = status->get_sc(src); if(sc) { if(sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_WIZARD && @@ -3185,7 +3175,7 @@ int skill_timerskill(int tid, unsigned int tick, int id, intptr_t data) { BL_CHAR|BL_SKILL, target->id); // Search for a new Target around current one... if( nbl == NULL) skl->x++; - else + else skl->x = 0; skill->addtimerskill(src, tick + 651, (nbl?nbl:target)->id, skl->x, 0, WL_CHAINLIGHTNING_ATK, skl->skill_lv, skl->type + 1, skl->flag); @@ -3197,25 +3187,25 @@ int skill_timerskill(int tid, unsigned int tick, int id, intptr_t data) { case WL_TETRAVORTEX_WIND: case WL_TETRAVORTEX_GROUND: clif->skill_nodamage(src, target, skl->skill_id, skl->skill_lv, 1); - skill_attack(BF_MAGIC, src, src, target, skl->skill_id, skl->skill_lv, tick, skl->flag); + skill->attack(BF_MAGIC, src, src, target, skl->skill_id, skl->skill_lv, tick, skl->flag); skill->toggle_magicpower(src, skl->skill_id); // only the first hit will be amplify - if( skl->type == 4 ){ + if( skl->type == 4 ){ const enum sc_type scs[] = { SC_BURNING, SC_BLOODING, SC_FROSTMISTY, SC_STUN }; // status inflicts are depend on what summoned element is used. int rate = skl->y, index = skl->x-1; - sc_start2(target, scs[index], rate, skl->skill_lv, src->id, skill->get_time(WL_TETRAVORTEX,index)); + sc_start2(src,target, scs[index], rate, skl->skill_lv, src->id, skill->get_time(WL_TETRAVORTEX,index+1)); } break; case WM_REVERBERATION_MELEE: case WM_REVERBERATION_MAGIC: - skill->castend_damage_id(src, target, skl->skill_id, skl->skill_lv, tick, skl->flag|SD_LEVEL); // damage should split among targets + skill->attack(skill->get_type(skl->skill_id),src, src, target, skl->skill_id, skl->skill_lv, 0, SD_LEVEL); break; case SC_FATALMENACE: if( src == target ) // Casters Part - unit_warp(src, -1, skl->x, skl->y, 3); + unit->warp(src, -1, skl->x, skl->y, CLR_TELEPORT); else { // Target's Part short x = skl->x, y = skl->y; - iMap->search_freecell(NULL, target->m, &x, &y, 2, 2, 1); - unit_warp(target,-1,x,y,3); + map->search_freecell(NULL, target->m, &x, &y, 2, 2, 1); + unit->warp(target,-1,x,y,CLR_TELEPORT); } break; case LG_MOONSLASHER: @@ -3229,38 +3219,55 @@ int skill_timerskill(int tid, unsigned int tick, int id, intptr_t data) { } } break; - case LG_OVERBRAND_BRANDISH: - case LG_OVERBRAND_PLUSATK: case SR_KNUCKLEARROW: skill->attack(BF_WEAPON, src, src, target, skl->skill_id, skl->skill_lv, tick, skl->flag|SD_LEVEL); break; case GN_SPORE_EXPLOSION: - iMap->foreachinrange(skill->area_sub, target, skill->get_splash(skl->skill_id, skl->skill_lv), BL_CHAR, - src, skl->skill_id, skl->skill_lv, 0, skl->flag|1|BCT_ENEMY, skill->castend_damage_id); + map->foreachinrange(skill->area_sub, target, skill->get_splash(skl->skill_id, skl->skill_lv), BL_CHAR, + src, skl->skill_id, skl->skill_lv, (int64)0, skl->flag|1|BCT_ENEMY, skill->castend_damage_id); break; - case SR_FLASHCOMBO_ATK_STEP1: - case SR_FLASHCOMBO_ATK_STEP2: - case SR_FLASHCOMBO_ATK_STEP3: - case SR_FLASHCOMBO_ATK_STEP4: - if( src->type == BL_PC ) { - struct map_session_data *sd = NULL; - const enum e_skill combos[] = {SR_DRAGONCOMBO, SR_FALLENEMPIRE, SR_TIGERCANNON, SR_SKYNETBLOW}; - if( (sd = ((TBL_PC*)src)) ){ - uint16 cid = combos[skl->skill_id-SR_FLASHCOMBO_ATK_STEP1]; - skill->castend_damage_id(src, target, cid, pc->checkskill(sd, cid), tick, 0); - } + // SR_FLASHCOMBO + case SR_DRAGONCOMBO: + case SR_FALLENEMPIRE: + case SR_TIGERCANNON: + case SR_SKYNETBLOW: + { + struct map_session_data *sd = NULL; + + if( src->type == BL_PC && (sd = ((TBL_PC*)src)) ) { + if( distance_xy(src->x, src->y, target->x, target->y) >= 3 ) + break; + + skill->castend_damage_id(src, target, skl->skill_id, pc->checkskill(sd, skl->skill_id), tick, 0); + } + break; + } + case SC_ESCAPE: + if( skl->type < 4+skl->skill_lv ){ + clif->skill_damage(src,src,tick,0,0,-30000,1,skl->skill_id,skl->skill_lv,5); + skill->blown(src,src,1,unit->getdir(src),0); + skill->addtimerskill(src,tick+80,src->id,0,0,skl->skill_id,skl->skill_lv,skl->type+1,0); } break; + case RK_HUNDREDSPEAR: + if(src->type == BL_PC) { + int skill_lv = pc->checkskill((TBL_PC *)src, KN_SPEARBOOMERANG); + if(skill_lv > 0) + skill->attack(BF_WEAPON, src, src, target, KN_SPEARBOOMERANG, skill_lv, tick, skl->flag); + } else + skill->attack(BF_WEAPON, src, src, target, KN_SPEARBOOMERANG, 1, tick, skl->flag); + break; case CH_PALMSTRIKE: - { - struct status_change* tsc = status_get_sc(target); - struct status_change* sc = status_get_sc(src); - if( ( tsc && tsc->option&OPTION_HIDE ) || - ( sc && sc->option&OPTION_HIDE ) ){ - skill->blown(src,target,skill->get_blewcount(skl->skill_id, skl->skill_lv), -1, 0x0 ); - break; - } + { + struct status_change* tsc = status->get_sc(target); + struct status_change* sc = status->get_sc(src); + if( (tsc && tsc->option&OPTION_HIDE) + || (sc && sc->option&OPTION_HIDE) + ) { + skill->blown(src,target,skill->get_blewcount(skl->skill_id, skl->skill_lv), -1, 0x0 ); + break; } + } default: skill->attack(skl->type,src,src,target,skl->skill_id,skl->skill_lv,tick,skl->flag); break; @@ -3272,48 +3279,56 @@ int skill_timerskill(int tid, unsigned int tick, int id, intptr_t data) { case WZ_METEOR: if( skl->type >= 0 ) { int x = skl->type>>16, y = skl->type&0xFFFF; - if( path_search_long(NULL, src->m, src->x, src->y, x, y, CELL_CHKWALL) ) + if( path->search_long(NULL, src->m, src->x, src->y, x, y, CELL_CHKWALL) ) skill->unitsetting(src,skl->skill_id,skl->skill_lv,x,y,skl->flag); - if( path_search_long(NULL, src->m, src->x, src->y, skl->x, skl->y, CELL_CHKWALL) ) + if( path->search_long(NULL, src->m, src->x, src->y, skl->x, skl->y, CELL_CHKWALL) ) clif->skill_poseffect(src,skl->skill_id,skl->skill_lv,skl->x,skl->y,tick); } - else if( path_search_long(NULL, src->m, src->x, src->y, skl->x, skl->y, CELL_CHKWALL) ) + else if( path->search_long(NULL, src->m, src->x, src->y, skl->x, skl->y, CELL_CHKWALL) ) skill->unitsetting(src,skl->skill_id,skl->skill_lv,skl->x,skl->y,skl->flag); break; - case GN_CRAZYWEED_ATK: { - int dummy = 1, i = skill->get_unit_range(skl->skill_id,skl->skill_lv); - iMap->foreachinarea(skill->cell_overlap, src->m, skl->x-i, skl->y-i, skl->x+i, skl->y+i, BL_SKILL, skl->skill_id, &dummy, src); - } + // fall through ... case WL_EARTHSTRAIN: skill->unitsetting(src,skl->skill_id,skl->skill_lv,skl->x,skl->y,(skl->type<<16)|skl->flag); break; - + case LG_OVERBRAND_BRANDISH: + skill->area_temp[1] = 0; + map->foreachinpath(skill->attack_area,src->m,src->x,src->y,skl->x,skl->y,4,2,BL_CHAR, + skill->get_type(skl->skill_id),src,src,skl->skill_id,skl->skill_lv,tick,skl->flag,BCT_ENEMY); + break; + case GN_CRAZYWEED: + if( skl->type >= 0 ) { + int x = skl->type>>16, y = skl->type&0xFFFF; + if( path->search_long(NULL, src->m, src->x, src->y, skl->x, skl->y, CELL_CHKWALL) ) + skill->castend_pos2(src, x, y, GN_CRAZYWEED_ATK, skl->skill_lv, tick, skl->flag); + } else if( path->search_long(NULL, src->m, src->x, src->y, skl->x, skl->y, CELL_CHKWALL) ) + skill->castend_pos2(src, skl->x, skl->y, GN_CRAZYWEED_ATK, skl->skill_lv, tick, skl->flag); + break; } } } while (0); //Free skl now that it is no longer needed. - ers_free(skill_timer_ers, skl); + ers_free(skill->timer_ers, skl); return 0; } /*========================================== * *------------------------------------------*/ -int skill_addtimerskill (struct block_list *src, unsigned int tick, int target, int x,int y, uint16 skill_id, uint16 skill_lv, int type, int flag) -{ +int skill_addtimerskill(struct block_list *src, int64 tick, int target, int x,int y, uint16 skill_id, uint16 skill_lv, int type, int flag) { int i; struct unit_data *ud; nullpo_retr(1, src); if (src->prev == NULL) return 0; - ud = unit_bl2ud(src); + ud = unit->bl2ud(src); nullpo_retr(1, ud); ARR_FIND( 0, MAX_SKILLTIMERSKILL, i, ud->skilltimerskill[i] == 0 ); if( i == MAX_SKILLTIMERSKILL ) return 1; - ud->skilltimerskill[i] = ers_alloc(skill_timer_ers, struct skill_timerskill); - ud->skilltimerskill[i]->timer = iTimer->add_timer(tick, skill->timerskill, src->id, i); + ud->skilltimerskill[i] = ers_alloc(skill->timer_ers, struct skill_timerskill); + ud->skilltimerskill[i]->timer = timer->add(tick, skill->timerskill, src->id, i); ud->skilltimerskill[i]->src_id = src->id; ud->skilltimerskill[i]->target_id = target; ud->skilltimerskill[i]->skill_id = skill_id; @@ -3334,26 +3349,40 @@ int skill_cleartimerskill (struct block_list *src) int i; struct unit_data *ud; nullpo_ret(src); - ud = unit_bl2ud(src); + ud = unit->bl2ud(src); nullpo_ret(ud); for(i=0;i<MAX_SKILLTIMERSKILL;i++) { if(ud->skilltimerskill[i]) { - iTimer->delete_timer(ud->skilltimerskill[i]->timer, skill->timerskill); - ers_free(skill_timer_ers, ud->skilltimerskill[i]); + switch(ud->skilltimerskill[i]->skill_id){ + case WL_TETRAVORTEX_FIRE: + case WL_TETRAVORTEX_WATER: + case WL_TETRAVORTEX_WIND: + case WL_TETRAVORTEX_GROUND: + // SR_FLASHCOMBO + case SR_DRAGONCOMBO: + case SR_FALLENEMPIRE: + case SR_TIGERCANNON: + case SR_SKYNETBLOW: + continue; + } + timer->delete(ud->skilltimerskill[i]->timer, skill->timerskill); + ers_free(skill->timer_ers, ud->skilltimerskill[i]); ud->skilltimerskill[i]=NULL; } } return 1; } -int skill_activate_reverbetion( struct block_list *bl, va_list ap) { +int skill_activate_reverberation(struct block_list *bl, va_list ap) { struct skill_unit *su = (TBL_SKILL*)bl; struct skill_unit_group *sg; if( bl->type != BL_SKILL ) return 0; - if( su->alive && (sg = su->group) && sg->skill_id == WM_REVERBERATION ) { - iMap->foreachinrange(skill->trap_splash, bl, skill->get_splash(sg->skill_id, sg->skill_lv), sg->bl_flag, bl, iTimer->gettick()); - su->limit=DIFF_TICK(iTimer->gettick(),sg->tick); + if( su->alive && (sg = su->group) && sg->skill_id == WM_REVERBERATION && sg->unit_id == UNT_REVERBERATION ) { + int64 tick = timer->gettick(); + clif->changetraplook(bl,UNT_USED_TRAPS); + map->foreachinrange(skill->trap_splash, bl, skill->get_splash(sg->skill_id, sg->skill_lv), sg->bl_flag, bl, tick); + su->limit = DIFF_TICK32(tick,sg->tick)+1500; sg->unit_id = UNT_USED_TRAPS; } return 0; @@ -3364,7 +3393,7 @@ int skill_reveal_trap (struct block_list *bl, va_list ap) { if (su->alive && su->group && skill->get_inf2(su->group->skill_id)&INF2_TRAP) { //Reveal trap. //Change look is not good enough, the client ignores it as an actual trap still. [Skotlex] //clif->changetraplook(bl, su->group->unit_id); - clif->skill_setunit(su); + clif->getareachar_skillunit(&su->bl,su,AREA); return 1; } return 0; @@ -3374,8 +3403,7 @@ int skill_reveal_trap (struct block_list *bl, va_list ap) { * * *------------------------------------------*/ -int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint16 skill_id, uint16 skill_lv, unsigned int tick, int flag) -{ +int skill_castend_damage_id(struct block_list* src, struct block_list *bl, uint16 skill_id, uint16 skill_lv, int64 tick, int flag) { struct map_session_data *sd = NULL; struct status_data *tstatus; struct status_change *sc; @@ -3393,25 +3421,25 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint sd = BL_CAST(BL_PC, src); - if (status_isdead(bl)) + if (status->isdead(bl)) return 1; - if (skill_id && skill->get_type(skill_id) == BF_MAGIC && status_isimmune(bl) == 100) { - //GTB makes all targetted magic display miss with a single bolt. - sc_type sct = status_skill2sc(skill_id); + if (skill_id && skill->get_type(skill_id) == BF_MAGIC && status->isimmune(bl) == 100) { + //GTB makes all targeted magic display miss with a single bolt. + sc_type sct = status->skill2sc(skill_id); if(sct != SC_NONE) status_change_end(bl, sct, INVALID_TIMER); clif->skill_damage(src, bl, tick, status_get_amotion(src), status_get_dmotion(bl), 0, 1, skill_id, skill_lv, skill->get_hit(skill_id)); return 1; } - sc = status_get_sc(src); + sc = status->get_sc(src); if (sc && !sc->count) sc = NULL; //Unneeded - tstatus = status_get_status_data(bl); + tstatus = status->get_status_data(bl); - iMap->freeblock_lock(); + map->freeblock_lock(); switch(skill_id) { case MER_CRASH: @@ -3480,7 +3508,6 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint case WS_CARTTERMINATION: // Cart Termination case AS_VENOMKNIFE: case HT_PHANTASMIC: - case HT_POWER: case TK_DOWNKICK: case TK_COUNTER: case GS_CHAINACTION: @@ -3503,9 +3530,7 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint case NPC_CRITICALWOUND: case NPC_HELLPOWER: case RK_SONICWAVE: - case RK_HUNDREDSPEAR: case RK_STORMBLAST: - case RK_CRUSHSTRIKE: case AB_DUPLELIGHT_MELEE: case RA_AIMEDBOLT: case NC_AXEBOOMERANG: @@ -3525,10 +3550,13 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint case SR_GENTLETOUCH_QUIET: case WM_SEVERE_RAINSTORM_MELEE: case WM_GREAT_ECHO: + case GN_CRAZYWEED_ATK: case GN_SLINGITEM_RANGEMELEEATK: case KO_JYUMONJIKIRI: case KO_SETSUDAN: case GC_DARKCROW: + case LG_OVERBRAND_BRANDISH: + case LG_OVERBRAND: skill->attack(BF_WEAPON,src,src,bl,skill_id,skill_lv,tick,flag); break; @@ -3537,9 +3565,7 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint **/ case NC_BOOSTKNUCKLE: case NC_PILEBUNKER: - case NC_VULCANARM: case NC_COLDSLOWER: - case NC_ARMSCANNON: if (sd) pc->overheat(sd,1); case RK_WINDCUTTER: skill->attack(BF_WEAPON,src,src,bl,skill_id,skill_lv,tick,flag|SD_ANIMATION); @@ -3555,46 +3581,46 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint case 5: flag |= BREAK_NECK; break; } //TODO: is there really no cleaner way to do this? - sc = status_get_sc(bl); + sc = status->get_sc(bl); if (sc) sc->jb_flag = flag; skill->attack(BF_WEAPON,src,src,bl,skill_id,skill_lv,tick,flag); break; case MO_COMBOFINISH: - if (!(flag&1) && sc && sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_MONK) - { //Becomes a splash attack when Soul Linked. - iMap->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); + 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), + src,skill_id,skill_lv,tick, flag|BCT_ENEMY|1, + skill->castend_damage_id); } else skill->attack(BF_WEAPON,src,src,bl,skill_id,skill_lv,tick,flag); break; case TK_STORMKICK: // Taekwon kicks [Dralnu] clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - skill_area_temp[1] = 0; - iMap->foreachinrange(skill->attack_area, src, - skill->get_splash(skill_id, skill_lv), splash_target(src), - BF_WEAPON, src, src, skill_id, skill_lv, tick, flag, BCT_ENEMY); + skill->area_temp[1] = 0; + map->foreachinrange(skill->attack_area, src, + skill->get_splash(skill_id, skill_lv), splash_target(src), + BF_WEAPON, src, src, skill_id, skill_lv, tick, flag, BCT_ENEMY); break; case KN_CHARGEATK: { - bool path = path_search_long(NULL, src->m, src->x, src->y, bl->x, bl->y,CELL_CHKWALL); + bool path_exists = path->search_long(NULL, src->m, src->x, src->y, bl->x, bl->y,CELL_CHKWALL); unsigned int dist = distance_bl(src, bl); - uint8 dir = iMap->calc_dir(bl, src->x, src->y); + uint8 dir = map->calc_dir(bl, src->x, src->y); // teleport to target (if not on WoE grounds) - if( !map_flag_gvg(src->m) && !map[src->m].flag.battleground && unit_movepos(src, bl->x, bl->y, 0, 1) ) + if( !map_flag_gvg2(src->m) && !map->list[src->m].flag.battleground && unit->movepos(src, bl->x, bl->y, 0, 1) ) clif->slide(src, bl->x, bl->y); // cause damage and knockback if the path to target was a straight one - if( path ) { + if( path_exists ) { skill->attack(BF_WEAPON, src, src, bl, skill_id, skill_lv, tick, dist); skill->blown(src, bl, dist, dir, 0); //HACK: since knockback officially defaults to the left, the client also turns to the left... therefore, // make the caster look in the direction of the target - unit_setdir(src, (dir+4)%8); + unit->setdir(src, (dir+4)%8); } } @@ -3608,10 +3634,10 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint case LG_CANNONSPEAR: //It won't shoot through walls since on castend there has to be a direct //line of sight between caster and target. - skill_area_temp[1] = bl->id; - iMap->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_type(skill_id),src,src,skill_id,skill_lv,tick,flag,BCT_ENEMY); + 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_type(skill_id),src,src,skill_id,skill_lv,tick,flag,BCT_ENEMY); break; case NPC_ACIDBREATH: @@ -3619,10 +3645,10 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint case NPC_FIREBREATH: case NPC_ICEBREATH: case NPC_THUNDERBREATH: - skill_area_temp[1] = bl->id; - iMap->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_type(skill_id),src,src,skill_id,skill_lv,tick,flag,BCT_ENEMY); + 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_type(skill_id),src,src,skill_id,skill_lv,tick,flag,BCT_ENEMY); break; case MO_INVESTIGATE: @@ -3632,12 +3658,12 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint case RG_BACKSTAP: { - uint8 dir = iMap->calc_dir(src, bl->x, bl->y), t_dir = unit_getdir(bl); - if ((!check_distance_bl(src, bl, 0) && !iMap->check_dir(dir, t_dir)) || bl->type == BL_SKILL) { + uint8 dir = map->calc_dir(src, bl->x, bl->y), t_dir = unit->getdir(bl); + if ((!check_distance_bl(src, bl, 0) && !map->check_dir(dir, t_dir)) || bl->type == BL_SKILL) { status_change_end(src, SC_HIDING, INVALID_TIMER); skill->attack(BF_WEAPON, src, src, bl, skill_id, skill_lv, tick, flag); dir = dir < 4 ? dir+4 : dir-4; // change direction [Celest] - unit_setdir(bl,dir); + unit->setdir(bl,dir); } else if (sd) clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); @@ -3668,43 +3694,46 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint skill->attack(BF_WEAPON,src,src,bl,skill_id,skill_lv,tick,flag); - if( skill_id == MO_EXTREMITYFIST ) - { + if( skill_id == MO_EXTREMITYFIST ) { mbl = src; i = 3; // for Asura(from caster) - status_set_sp(src, 0, 0); + status->set_sp(src, 0, 0); status_change_end(src, SC_EXPLOSIONSPIRITS, INVALID_TIMER); status_change_end(src, SC_BLADESTOP, INVALID_TIMER); - #ifdef RENEWAL - sc_start(src,SC_EXTREMITYFIST2,100,skill_lv,skill->get_time(skill_id,skill_lv)); - #endif - }else{ +#ifdef RENEWAL + sc_start(src, src,SC_EXTREMITYFIST2,100,skill_lv,skill->get_time(skill_id,skill_lv)); +#endif // RENEWAL + } else { status_change_end(src, SC_NJ_NEN, INVALID_TIMER); status_change_end(src, SC_HIDING, INVALID_TIMER); - status_set_hp(src, - #ifdef RENEWAL - max(status_get_max_hp(src)/100, 1) - #else - 1 - #endif - , 0); +#ifdef RENEWAL + status->set_hp(src, max(status_get_max_hp(src)/100, 1), 0); +#else // not RENEWAL + status->set_hp(src, 1, 0); +#endif // RENEWAL } - dir = iMap->calc_dir(src,bl->x,bl->y); + dir = map->calc_dir(src,bl->x,bl->y); if( dir > 0 && dir < 4) x = -i; else if( dir > 4 ) x = i; else x = 0; if( dir > 2 && dir < 6 ) y = -i; else if( dir == 7 || dir < 2 ) y = i; else y = 0; - if( (mbl == src || (!map_flag_gvg(src->m) && !map[src->m].flag.battleground) ) && // only NJ_ISSEN don't have slide effect in GVG - unit_movepos(src, mbl->x+x, mbl->y+y, 1, 1) ) { + if( (mbl == src || (!map_flag_gvg2(src->m) && !map->list[src->m].flag.battleground) ) // only NJ_ISSEN don't have slide effect in GVG + && unit->movepos(src, mbl->x+x, mbl->y+y, 1, 1) + ) { clif->slide(src, src->x, src->y); - //uncomment this if you want to remove MO_EXTREMITYFIST glitchy walking effect. [malufett] - //clif->fixpos(src); + clif->fixpos(src); + clif->spiritball(src); } } break; + case HT_POWER: + if( tstatus->race == RC_BRUTE || tstatus->race == RC_INSECT ) + skill->attack(BF_WEAPON,src,src,bl,skill_id,skill_lv,tick,flag); + break; + //Splash attack skills. case AS_GRIMTOOTH: case MC_CARTREVOLUTION: @@ -3737,6 +3766,8 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint case WL_JACKFROST: case RA_ARROWSTORM: case RA_WUGDASH: + case NC_VULCANARM: + case NC_ARMSCANNON: case NC_SELFDESTRUCTION: case NC_AXETORNADO: case GC_ROLLINGCUTTER: @@ -3748,9 +3779,7 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint case SR_SKYNETBLOW: case SR_WINDMILL: case SR_RIDEINLIGHTNING: - case WM_SOUND_OF_DESTRUCTION: - case WM_REVERBERATION_MELEE: - case WM_REVERBERATION_MAGIC: + case WM_REVERBERATION: case SO_VARETYR_SPEAR: case GN_CART_TORNADO: case GN_CARTCANNON: @@ -3758,20 +3787,22 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint case KO_HUUMARANKA: case KO_MUCHANAGE: case KO_BAKURETSU: + case GN_ILLUSIONDOPING: + case MH_XENO_SLASHER: if( flag&1 ) {//Recursive invocation - // skill_area_temp[0] holds number of targets in area - // skill_area_temp[1] holds the id of the original target - // skill_area_temp[2] counts how many targets have already been processed - int sflag = skill_area_temp[0] & 0xFFF, heal; + // skill->area_temp[0] holds number of targets in area + // skill->area_temp[1] holds the id of the original target + // skill->area_temp[2] counts how many targets have already been processed + int sflag = skill->area_temp[0] & 0xFFF, heal; if( flag&SD_LEVEL ) sflag |= SD_LEVEL; // -1 will be used in packets instead of the skill level - if( (skill_area_temp[1] != bl->id && !(skill->get_inf2(skill_id)&INF2_NPC_SKILL)) || flag&SD_ANIMATION ) + if( (skill->area_temp[1] != bl->id && !(skill->get_inf2(skill_id)&INF2_NPC_SKILL)) || flag&SD_ANIMATION ) sflag |= SD_ANIMATION; // original target gets no animation (as well as all NPC skills) heal = skill->attack(skill->get_type(skill_id), src, src, bl, skill_id, skill_lv, tick, sflag); if( skill_id == NPC_VAMPIRE_GIFT && heal > 0 ) { clif->skill_nodamage(NULL, src, AL_HEAL, heal, 1); - status_heal(src,heal,0,0); + status->heal(src,heal,0,0); } } else { switch ( skill_id ) { @@ -3781,8 +3812,11 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint clif->skill_nodamage(src,bl,skill_id,skill_lv,1); break; case SR_TIGERCANNON: + case GC_COUNTERSLASH: + case GC_ROLLINGCUTTER: flag |= SD_ANIMATION; case LG_MOONSLASHER: + case MH_XENO_SLASHER: clif->skill_damage(src,bl,tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6); break; case NPC_EARTHQUAKE://FIXME: Isn't EarthQuake a ground skill after all? @@ -3791,30 +3825,32 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint break; } - skill_area_temp[0] = 0; - skill_area_temp[1] = bl->id; - skill_area_temp[2] = 0; + skill->area_temp[0] = 0; + skill->area_temp[1] = bl->id; + skill->area_temp[2] = 0; if( skill_id == WL_CRIMSONROCK ) { - skill_area_temp[4] = bl->x; - skill_area_temp[5] = bl->y; + skill->area_temp[4] = bl->x; + skill->area_temp[5] = bl->y; } - if( skill_id == WM_REVERBERATION_MELEE || skill_id == WM_REVERBERATION_MAGIC ) - skill_area_temp[1] = 0; + + if( skill_id == NC_VULCANARM ) + if (sd) pc->overheat(sd,1); + // if skill damage should be split among targets, count them //SD_LEVEL -> Forced splash damage for Auto Blitz-Beat -> count targets //special case: Venom Splasher uses a different range for searching than for splashing if( flag&SD_LEVEL || skill->get_nk(skill_id)&NK_SPLASHSPLIT ) - skill_area_temp[0] = iMap->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); + 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 - iMap->foreachinrange(skill->area_sub, bl, skill->get_splash(skill_id, skill_lv), ( skill_id == WM_REVERBERATION_MELEE || skill_id == WM_REVERBERATION_MAGIC )?BL_CHAR: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), splash_target(src), src, skill_id, skill_lv, tick, flag|BCT_ENEMY|SD_SPLASH|1, skill->castend_damage_id); } break; case KN_BRANDISHSPEAR: case ML_BRANDISH: //Coded apart for it needs the flag passed to the damage calculation. - if (skill_area_temp[1] != bl->id) + if (skill->area_temp[1] != bl->id) skill->attack(skill->get_type(skill_id), src, src, bl, skill_id, skill_lv, tick, flag|SD_ANIMATION); else skill->attack(skill->get_type(skill_id), src, src, bl, skill_id, skill_lv, tick, flag); @@ -3822,50 +3858,95 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint case KN_BOWLINGBASH: case MS_BOWLINGBASH: - if(flag&1){ - if(bl->id==skill_area_temp[1]) - break; - //two hits for 500% - skill->attack(BF_WEAPON,src,src,bl,skill_id,skill_lv,tick,SD_ANIMATION); - skill->attack(BF_WEAPON,src,src,bl,skill_id,skill_lv,tick,SD_ANIMATION); - } else { - int i,c; - c = skill->get_blewcount(skill_id,skill_lv); - // keep moving target in the direction that src is looking, square by square - for(i=0;i<c;i++){ - if (!skill->blown(src,bl,1,(unit_getdir(src)+4)%8,0x1)) - break; //Can't knockback - skill_area_temp[0] = iMap->foreachinrange(skill->area_sub, bl, skill->get_splash(skill_id, skill_lv), BL_CHAR, src, skill_id, skill_lv, tick, flag|BCT_ENEMY, skill->area_sub_count); - if( skill_area_temp[0] > 1 ) break; // collision - } - clif->blown(bl); //Update target pos. - if (i!=c) { //Splash - skill_area_temp[1] = bl->id; - iMap->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); + { + int min_x,max_x,min_y,max_y,i,c,dir,tx,ty; + // Chain effect and check range gets reduction by recursive depth, as this can reach 0, we don't use blowcount + c = (skill_lv-(flag&0xFFF)+1)/2; + // Determine the Bowling Bash area depending on configuration + if (battle_config.bowling_bash_area == 0) { + // Gutter line system + min_x = ((src->x)-c) - ((src->x)-c)%40; + if(min_x < 0) min_x = 0; + max_x = min_x + 39; + min_y = ((src->y)-c) - ((src->y)-c)%40; + if(min_y < 0) min_y = 0; + max_y = min_y + 39; + } else if (battle_config.bowling_bash_area == 1) { + // Gutter line system without demi gutter bug + min_x = src->x - (src->x)%40; + max_x = min_x + 39; + min_y = src->y - (src->y)%40; + max_y = min_y + 39; + } else { + // Area around caster + min_x = src->x - battle_config.bowling_bash_area; + max_x = src->x + battle_config.bowling_bash_area; + min_y = src->y - battle_config.bowling_bash_area; + max_y = src->y + battle_config.bowling_bash_area; + } + // Initialization, break checks, direction + if((flag&0xFFF) > 0) { + // Ignore monsters outside area + if(bl->x < min_x || bl->x > max_x || bl->y < min_y || bl->y > max_y) + break; + // Ignore monsters already in list + if(idb_exists(skill->bowling_db, bl->id)) + break; + // Random direction + dir = rnd()%8; + } else { + // Create an empty list of already hit targets + db_clear(skill->bowling_db); + // Direction is walkpath + dir = (unit->getdir(src)+4)%8; + } + // Add current target to the list of already hit targets + idb_put(skill->bowling_db, bl->id, bl); + // Keep moving target in direction square by square + tx = bl->x; + ty = bl->y; + for(i=0;i<c;i++) { + // Target coordinates (get changed even if knockback fails) + tx -= dirx[dir]; + ty -= diry[dir]; + // If target cell is a wall then break + if(map->getcell(bl->m,tx,ty,CELL_CHKWALL)) + break; + skill_blown(src,bl,1,dir,0); + // 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))) { + // 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); + // 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); + break; + } } - //Weirdo dual-hit property, two attacks for 500% - skill->attack(BF_WEAPON,src,src,bl,skill_id,skill_lv,tick,0); - skill->attack(BF_WEAPON,src,src,bl,skill_id,skill_lv,tick,0); + // Original hit or chain hit depending on flag + skill->attack(BF_WEAPON,src,src,bl,skill_id,skill_lv,tick,(flag&0xFFF)>0?SD_ANIMATION:0); } break; case KN_SPEARSTAB: if(flag&1) { - if (bl->id==skill_area_temp[1]) + if (bl->id==skill->area_temp[1]) break; if (skill->attack(BF_WEAPON,src,src,bl,skill_id,skill_lv,tick,SD_ANIMATION)) - skill->blown(src,bl,skill_area_temp[2],-1,0); + skill->blown(src,bl,skill->area_temp[2],-1,0); } else { int x=bl->x,y=bl->y,i,dir; - dir = iMap->calc_dir(bl,src->x,src->y); - skill_area_temp[1] = bl->id; - skill_area_temp[2] = skill->get_blewcount(skill_id,skill_lv); + dir = map->calc_dir(bl,src->x,src->y); + skill->area_temp[1] = bl->id; + skill->area_temp[2] = skill->get_blewcount(skill_id,skill_lv); // all the enemies between the caster and the target are hit, as well as the target if (skill->attack(BF_WEAPON,src,src,bl,skill_id,skill_lv,tick,0)) - skill->blown(src,bl,skill_area_temp[2],-1,0); + skill->blown(src,bl,skill->area_temp[2],-1,0); for (i=0;i<4;i++) { - iMap->foreachincell(skill->area_sub,bl->m,x,y,BL_CHAR, - src,skill_id,skill_lv,tick,flag|BCT_ENEMY|1,skill->castend_damage_id); + map->foreachincell(skill->area_sub,bl->m,x,y,BL_CHAR,src,skill_id,skill_lv, + tick,flag|BCT_ENEMY|1,skill->castend_damage_id); x += dirx[dir]; y += diry[dir]; } @@ -3875,17 +3956,17 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint case TK_TURNKICK: case MO_BALKYOUNG: //Active part of the attack. Skill-attack [Skotlex] { - skill_area_temp[1] = bl->id; //NOTE: This is used in skill->castend_nodamage_id to avoid affecting the target. + skill->area_temp[1] = bl->id; //NOTE: This is used in skill->castend_nodamage_id to avoid affecting the target. if (skill->attack(BF_WEAPON,src,src,bl,skill_id,skill_lv,tick,flag)) - iMap->foreachinrange(skill->area_sub,bl, - skill->get_splash(skill_id, skill_lv),BL_CHAR, - src,skill_id,skill_lv,tick,flag|BCT_ENEMY|1, - skill->castend_nodamage_id); + map->foreachinrange(skill->area_sub,bl, + skill->get_splash(skill_id, skill_lv),BL_CHAR, + src,skill_id,skill_lv,tick,flag|BCT_ENEMY|1, + skill->castend_nodamage_id); } break; case CH_PALMSTRIKE: // Palm Strike takes effect 1sec after casting. [Skotlex] // clif->skill_nodamage(src,bl,skill_id,skill_lv,0); //Can't make this one display the correct attack animation delay :/ - clif->damage(src,bl,tick,status_get_amotion(src),0,-1,1,4,0); //Display an absorbed damage attack. + clif->damage(src,bl,status_get_amotion(src),0,-1,1,4,0); //Display an absorbed damage attack. skill->addtimerskill(src, tick + (1000+status_get_amotion(src)), bl->id, 0, 0, skill_id, skill_lv, BF_WEAPON, flag); break; @@ -3925,7 +4006,7 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint case NPC_MAGICALATTACK: skill->attack(BF_MAGIC,src,src,bl,skill_id,skill_lv,tick,flag); - sc_start(src,status_skill2sc(skill_id),100,skill_lv,skill->get_time(skill_id,skill_lv)); + sc_start(src, src,status->skill2sc(skill_id),100,skill_lv,skill->get_time(skill_id,skill_lv)); break; case HVAN_CAPRICE: //[blackhole89] @@ -3948,10 +4029,9 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint int maxlv = skill->get_max(skill_id); // learnable level int count = 0; int x, y; - struct skill_unit* unit; + struct skill_unit *su; - if( skill_lv > maxlv ) - { + if( skill_lv > maxlv ) { if( src->type == BL_MOB && skill_lv == 10 ) range = 4; else @@ -3959,16 +4039,14 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint } for( y = src->y - range; y <= src->y + range; ++y ) - for( x = src->x - range; x <= src->x + range; ++x ) - { - if( !iMap->find_skill_unit_oncell(src,x,y,SA_LANDPROTECTOR,NULL,1) ) - { - if( src->type != BL_PC || iMap->getcell(src->m,x,y,CELL_CHKWATER) ) // non-players bypass the water requirement + for( x = src->x - range; x <= src->x + range; ++x ) { + if( !map->find_skill_unit_oncell(src,x,y,SA_LANDPROTECTOR,NULL,1) ) { + if( src->type != BL_PC || map->getcell(src->m,x,y,CELL_CHKWATER) ) // non-players bypass the water requirement count++; // natural water cell - else if( (unit = iMap->find_skill_unit_oncell(src,x,y,SA_DELUGE,NULL,1)) != NULL || (unit = iMap->find_skill_unit_oncell(src,x,y,NJ_SUITON,NULL,1)) != NULL ) - { + else if( (su = map->find_skill_unit_oncell(src,x,y,SA_DELUGE,NULL,1)) != NULL + || (su = map->find_skill_unit_oncell(src,x,y,NJ_SUITON,NULL,1)) != NULL ) { count++; // skill-induced water cell - skill->delunit(unit); // consume cell + skill->delunit(su); // consume cell } } } @@ -3990,7 +4068,7 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint case SL_STIN: case SL_STUN: if (sd && !battle_config.allow_es_magic_pc && bl->type != BL_MOB) { - status_change_start(src,SC_STUN,10000,skill_lv,0,0,0,500,10); + status->change_start(src,src,SC_STUN,10000,skill_lv,0,0,0,500,10); clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); break; } @@ -4017,18 +4095,18 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint * Rune Knight **/ case RK_DRAGONBREATH_WATER: - case RK_DRAGONBREATH: { - struct status_change *tsc = NULL; - if( (tsc = status_get_sc(bl)) && (tsc->data[SC_HIDING] )) { - clif->skill_nodamage(src,src,skill_id,skill_lv,1); - } else - skill->attack(BF_MISC,src,src,bl,skill_id,skill_lv,tick,flag); - } + case RK_DRAGONBREATH: + { + struct status_change *tsc = NULL; + if( (tsc = status->get_sc(bl)) && (tsc->data[SC_HIDING] )) { + clif->skill_nodamage(src,src,skill_id,skill_lv,1); + } else + skill->attack(BF_MISC,src,src,bl,skill_id,skill_lv,tick,flag); + } break; - case NPC_SELFDESTRUCTION: { struct status_change *tsc = NULL; - if( (tsc = status_get_sc(bl)) && tsc->data[SC_HIDING] ) + if( (tsc = status->get_sc(bl)) && tsc->data[SC_HIDING] ) break; } case HVAN_EXPLOSION: @@ -4036,7 +4114,7 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint skill->attack(BF_MISC,src,src,bl,skill_id,skill_lv,tick,flag); break; - // Celest + // [Celest] case PF_SOULBURN: if (rnd()%100 < (skill_lv < 5 ? 30 + skill_lv * 10 : 70)) { clif->skill_nodamage(src,bl,skill_id,skill_lv,1); @@ -4053,14 +4131,14 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint case NPC_BLOODDRAIN: case NPC_ENERGYDRAIN: - { - int heal = skill->attack( (skill_id == NPC_BLOODDRAIN) ? BF_WEAPON : BF_MAGIC, - src, src, bl, skill_id, skill_lv, tick, flag); - if (heal > 0){ - clif->skill_nodamage(NULL, src, AL_HEAL, heal, 1); - status_heal(src, heal, 0, 0); - } + { + int heal = skill->attack( (skill_id == NPC_BLOODDRAIN) ? BF_WEAPON : BF_MAGIC, + src, src, bl, skill_id, skill_lv, tick, flag); + if (heal > 0){ + clif->skill_nodamage(NULL, src, AL_HEAL, heal, 1); + status->heal(src, heal, 0, 0); } + } break; case GS_BULLSEYE: @@ -4069,32 +4147,47 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint case NJ_KASUMIKIRI: if (skill->attack(BF_WEAPON,src,src,bl,skill_id,skill_lv,tick,flag) > 0) - sc_start(src,SC_HIDING,100,skill_lv,skill->get_time(skill_id,skill_lv)); + sc_start(src,src,SC_HIDING,100,skill_lv,skill->get_time(skill_id,skill_lv)); break; case NJ_KIRIKAGE: - if( !map_flag_gvg(src->m) && !map[src->m].flag.battleground ) - { //You don't move on GVG grounds. + if( !map_flag_gvg2(src->m) && !map->list[src->m].flag.battleground ) { + //You don't move on GVG grounds. short x, y; - iMap->search_freecell(bl, 0, &x, &y, 1, 1, 0); - if (unit_movepos(src, x, y, 0, 0)) + map->search_freecell(bl, 0, &x, &y, 1, 1, 0); + if (unit->movepos(src, x, y, 0, 0)) clif->slide(src,src->x,src->y); } status_change_end(src, SC_HIDING, INVALID_TIMER); skill->attack(BF_WEAPON,src,src,bl,skill_id,skill_lv,tick,flag); break; + case RK_HUNDREDSPEAR: + skill->attack(BF_WEAPON,src,src,bl,skill_id,skill_lv,tick,flag); + if(rnd()%100 < (10 + 3*skill_lv)) { + if( !sd || pc->checkskill(sd,KN_SPEARBOOMERANG) == 0 ) + break; // Spear Boomerang auto cast chance only works if you have mastered Spear Boomerang. + skill->blown(src,bl,6,-1,0); + skill->addtimerskill(src,tick+800,bl->id,0,0,skill_id,skill_lv,BF_WEAPON,flag); + skill->castend_damage_id(src,bl,KN_SPEARBOOMERANG,1,tick,0); + } + break; case RK_PHANTOMTHRUST: - unit_setdir(src,iMap->calc_dir(src, bl->x, bl->y)); + { + struct map_session_data *tsd = BL_CAST(BL_PC, bl); + unit->setdir(src,map->calc_dir(src, bl->x, bl->y)); clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - skill->blown(src,bl,distance_bl(src,bl)-1,unit_getdir(src),0); - if( battle->check_target(src,bl,BCT_ENEMY) > 0 ) + skill->blown(src,bl,distance_bl(src,bl)-1,unit->getdir(src),0); + if( sd && tsd && sd->status.party_id && sd->status.party_id && sd->status.party_id == tsd->status.party_id ) // Don't damage party members. + ; // No damage to Members + else skill->attack(BF_WEAPON,src,src,bl,skill_id,skill_lv,tick,flag); + } break; case GC_DARKILLUSION: { short x, y; - short dir = iMap->calc_dir(src,bl->x,bl->y); + short dir = map->calc_dir(src,bl->x,bl->y); if( dir > 0 && dir < 4) x = 2; else if( dir > 4 ) x = -2; @@ -4103,10 +4196,10 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint else if( dir == 7 || dir < 2 ) y = -2; else y = 0; - if( unit_movepos(src, bl->x+x, bl->y+y, 1, 1) ) + if( unit->movepos(src, bl->x+x, bl->y+y, 1, 1) ) { clif->slide(src,bl->x+x,bl->y+y); - clif->fixpos(src); // the official server send these two packts. + clif->fixpos(src); // the official server send these two packets. skill->attack(BF_WEAPON,src,src,bl,skill_id,skill_lv,tick,flag); if( rnd()%100 < 4 * skill_lv ) skill->castend_damage_id(src,bl,GC_CROSSIMPACT,skill_lv,tick,flag); @@ -4132,9 +4225,9 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint break; case GC_PHANTOMMENACE: - if( flag&1 ) - { // Only Hits Invisible Targets - struct status_change *tsc = status_get_sc(bl); + if( flag&1 ) { + // Only Hits Invisible Targets + struct status_change *tsc = status->get_sc(bl); if(tsc && (tsc->option&(OPTION_HIDE|OPTION_CLOAK|OPTION_CHASEWALK) || tsc->data[SC__INVISIBILITY]) ) skill->attack(BF_WEAPON,src,src,bl,skill_id,skill_lv,tick,flag); } @@ -4144,27 +4237,26 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint skill->addtimerskill(src,tick+status_get_amotion(src),bl->id,0,0,WL_CHAINLIGHTNING_ATK,skill_lv,0,flag); break; case WL_DRAINLIFE: - { - int heal = skill->attack(skill->get_type(skill_id), src, src, bl, skill_id, skill_lv, tick, flag); - int rate = 70 + 5 * skill_lv; + { + int heal = skill->attack(skill->get_type(skill_id), src, src, bl, skill_id, skill_lv, tick, flag); + int rate = 70 + 5 * skill_lv; - heal = heal * (5 + 5 * skill_lv) / 100; + heal = heal * (5 + 5 * skill_lv) / 100; - if( bl->type == BL_SKILL || status_get_hp(src) == status_get_max_hp(src)) // Don't absorb when caster was in full HP - heal = 0; // Don't absorb heal from Ice Walls or other skill units. + if( bl->type == BL_SKILL || status_get_hp(src) == status_get_max_hp(src)) // Don't absorb when caster was in full HP + heal = 0; // Don't absorb heal from Ice Walls or other skill units. - if( heal && rnd()%100 < rate ) - { - status_heal(src, heal, 0, 0); - clif->skill_nodamage(NULL, src, AL_HEAL, heal, 1); - } + if( heal && rnd()%100 < rate ) { + status->heal(src, heal, 0, 0); + clif->skill_nodamage(NULL, src, AL_HEAL, heal, 1); } + } break; case WL_TETRAVORTEX: if( sc ){ int i = SC_SUMMON5, x = 0; - int types[][2] = {{0, 0}, {0, 0}, {0, 0}, {0, 0}}; + int types[][2] = {{0, 0}, {0, 0}, {0, 0}, {0, 0}}; for(; i >= SC_SUMMON1; i--){ if( sc->data[i] ){ int skillid = WL_TETRAVORTEX_FIRE + (sc->data[i]->val1 - WLS_FIRE) + (sc->data[i]->val1 == WLS_WIND) - (sc->data[i]->val1 == WLS_WATER), sc_index = 0, rate = 0; @@ -4173,7 +4265,7 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint types[x][1] = 25; // 25% each for equal sharing if( x == 3 ){ x = 0; - sc_index = types[rand()%4][0]; + sc_index = types[rnd()%4][0]; for(; x < 4; x++) if(types[x][0] == sc_index) rate += types[x][1]; @@ -4194,7 +4286,7 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint skill->toggle_magicpower(src, skill_id); // Priority is to release SpellBook if( sc && sc->data[SC_READING_SB] ) { // SpellBook - uint16 skill_id, skill_lv, point, s = 0; + uint16 spell_skill_id, spell_skill_lv, point, s = 0; int spell[SC_SPELLBOOK7-SC_SPELLBOOK1 + 1]; for(i = SC_SPELLBOOK7; i >= SC_SPELLBOOK1; i--) // List all available spell to be released @@ -4203,10 +4295,10 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint if ( s == 0 ) break; - i = spell[s==1?0:rand()%s];// Random select of spell to be released. + i = spell[s==1?0:rnd()%s];// Random select of spell to be released. if( s && sc->data[i] ){// Now extract the data from the preserved spell - skill_id = sc->data[i]->val1; - skill_lv = sc->data[i]->val2; + spell_skill_id = sc->data[i]->val1; + spell_skill_lv = sc->data[i]->val2; point = sc->data[i]->val3; status_change_end(src, (sc_type)i, INVALID_TIMER); }else //something went wrong :( @@ -4217,36 +4309,35 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint else // Last spell to be released status_change_end(src, SC_READING_SB, INVALID_TIMER); - if( !skill->check_condition_castbegin(sd, skill_id, skill_lv) ) + if( !skill->check_condition_castbegin(sd, spell_skill_id, spell_skill_lv) ) break; - switch( skill->get_casttype(skill_id) ) { + switch( skill->get_casttype(spell_skill_id) ) { case CAST_GROUND: - skill->castend_pos2(src, bl->x, bl->y, skill_id, skill_lv, tick, 0); + skill->castend_pos2(src, bl->x, bl->y, spell_skill_id, spell_skill_lv, tick, 0); break; case CAST_NODAMAGE: - skill->castend_nodamage_id(src, bl, skill_id, skill_lv, tick, 0); + skill->castend_nodamage_id(src, bl, spell_skill_id, spell_skill_lv, tick, 0); break; case CAST_DAMAGE: - skill->castend_damage_id(src, bl, skill_id, skill_lv, tick, 0); + skill->castend_damage_id(src, bl, spell_skill_id, spell_skill_lv, tick, 0); break; } - sd->ud.canact_tick = tick + skill->delay_fix(src, skill_id, skill_lv); - clif->status_change(src, SI_POSTDELAY, 1, skill->delay_fix(src, skill_id, skill_lv), 0, 0, 0); + sd->ud.canact_tick = tick + skill->delay_fix(src, spell_skill_id, spell_skill_lv); + clif->status_change(src, SI_POSTDELAY, 1, skill->delay_fix(src, spell_skill_id, spell_skill_lv), 0, 0, 0); - cooldown = skill_get_cooldown(skill_id, skill_lv); + cooldown = skill->get_cooldown(spell_skill_id, spell_skill_lv); for (i = 0; i < ARRAYLENGTH(sd->skillcooldown) && sd->skillcooldown[i].id; i++) { - if (sd->skillcooldown[i].id == skill_id){ + if (sd->skillcooldown[i].id == spell_skill_id){ cooldown += sd->skillcooldown[i].val; break; - } + } } if(cooldown) - skill->blockpc_start(sd, skill_id, cooldown, false); + skill->blockpc_start(sd, spell_skill_id, cooldown); }else if( sc ){ // Summon Balls - int i = SC_SUMMON5; - for(; i >= SC_SUMMON1; i--){ + for(i = SC_SUMMON5; i >= SC_SUMMON1; i--){ if( sc->data[i] ){ int skillid = WL_SUMMON_ATK_FIRE + (sc->data[i]->val1 - WLS_FIRE); skill->addtimerskill(src, tick + status_get_adelay(src) * (SC_SUMMON5 - i), bl->id, 0, 0, skillid, skill_lv, BF_MAGIC, flag); @@ -4260,7 +4351,7 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint break; case WL_FROSTMISTY: // Doesn't deal damage through non-shootable walls. - if( path_search(NULL,src->m,src->x,src->y,bl->x,bl->y,1,CELL_CHKWALL) ) + if( path->search(NULL,src->m,src->x,src->y,bl->x,bl->y,1,CELL_CHKWALL) ) skill->attack(BF_MAGIC,src,src,bl,skill_id,skill_lv,tick,flag|SD_ANIMATION); break; case WL_HELLINFERNO: @@ -4271,9 +4362,9 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint if( sd && pc_isridingwug(sd) ){ short x[8]={0,-1,-1,-1,0,1,1,1}; short y[8]={1,1,0,-1,-1,-1,0,1}; - uint8 dir = iMap->calc_dir(bl, src->x, src->y); + uint8 dir = map->calc_dir(bl, src->x, src->y); - if( unit_movepos(src, bl->x+x[dir], bl->y+y[dir], 1, 1) ) + if( unit->movepos(src, bl->x+x[dir], bl->y+y[dir], 1, 1) ) { clif->slide(src, bl->x+x[dir], bl->y+y[dir]); clif->fixpos(src); @@ -4282,7 +4373,7 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint break; } case RA_WUGBITE: - if( path_search(NULL,src->m,src->x,src->y,bl->x,bl->y,1,CELL_CHKNOREACH) ) { + if( path->search(NULL,src->m,src->x,src->y,bl->x,bl->y,1,CELL_CHKNOREACH) ) { skill->attack(BF_WEAPON,src,src,bl,skill_id,skill_lv,tick,flag); }else if( sd && skill_id == RA_WUGBITE ) // Only RA_WUGBITE has the skill fail message. clif->skill_fail(sd, skill_id, USESKILL_FAIL_LEVEL, 0); @@ -4291,91 +4382,78 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint case RA_SENSITIVEKEEN: if( bl->type != BL_SKILL ) { // Only Hits Invisible Targets - struct status_change * tsc = status_get_sc(bl); + struct status_change * tsc = status->get_sc(bl); if( tsc && tsc->option&(OPTION_HIDE|OPTION_CLOAK) ){ skill->attack(BF_WEAPON,src,src,bl,skill_id,skill_lv,tick,flag); status_change_end(bl, SC_CLOAKINGEXCEED, INVALID_TIMER); } - } - else - { + } else { struct skill_unit *su = BL_CAST(BL_SKILL,bl); struct skill_unit_group* sg; - if( su && (sg=su->group) && skill->get_inf2(sg->skill_id)&INF2_TRAP ) - { - if( !(sg->unit_id == UNT_USED_TRAPS || (sg->unit_id == UNT_ANKLESNARE && sg->val2 != 0 )) ) - { + if( su && (sg=su->group) && skill->get_inf2(sg->skill_id)&INF2_TRAP ) { + if( !(sg->unit_id == UNT_USED_TRAPS || (sg->unit_id == UNT_ANKLESNARE && sg->val2 != 0 )) ) { struct item item_tmp; memset(&item_tmp,0,sizeof(item_tmp)); item_tmp.nameid = sg->item_id?sg->item_id:ITEMID_TRAP; item_tmp.identify = 1; if( item_tmp.nameid ) - iMap->addflooritem(&item_tmp,1,bl->m,bl->x,bl->y,0,0,0,0); + map->addflooritem(&item_tmp,1,bl->m,bl->x,bl->y,0,0,0,0); } skill->delunit(su); } } break; case NC_INFRAREDSCAN: - if( flag&1 ) - { //TODO: Need a confirmation if the other type of hidden status is included to be scanned. [Jobbie] - if( rnd()%100 < 50 ) - sc_start(bl, SC_INFRAREDSCAN, 10000, skill_lv, skill->get_time(skill_id, skill_lv)); + if( flag&1 ) { + //TODO: Need a confirmation if the other type of hidden status is included to be scanned. [Jobbie] + sc_start(src, bl, SC_INFRAREDSCAN, 10000, skill_lv, skill->get_time(skill_id, skill_lv)); status_change_end(bl, SC_HIDING, INVALID_TIMER); status_change_end(bl, SC_CLOAKING, INVALID_TIMER); status_change_end(bl, SC_CLOAKINGEXCEED, INVALID_TIMER); // Need confirm it. - } - else - { - iMap->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); + } 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); clif->skill_damage(src,src,tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6); if( sd ) pc->overheat(sd,1); } break; case NC_MAGNETICFIELD: - sc_start2(bl,SC_MAGNETICFIELD,100,skill_lv,src->id,skill->get_time(skill_id,skill_lv)); + sc_start2(src,bl,SC_MAGNETICFIELD,100,skill_lv,src->id,skill->get_time(skill_id,skill_lv)); break; case SC_FATALMENACE: if( flag&1 ) skill->attack(BF_WEAPON,src,src,bl,skill_id,skill_lv,tick,flag); - else - { + else { short x, y; - iMap->search_freecell(src, 0, &x, &y, -1, -1, 0); + map->search_freecell(src, 0, &x, &y, -1, -1, 0); // Destination area - skill_area_temp[4] = x; - skill_area_temp[5] = y; - iMap->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); + 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); 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,6); } break; case LG_PINPOINTATTACK: - if( !map_flag_gvg(src->m) && !map[src->m].flag.battleground && unit_movepos(src, bl->x, bl->y, 1, 1) ) + if( !map_flag_gvg2(src->m) && !map->list[src->m].flag.battleground && unit->movepos(src, bl->x, bl->y, 1, 1) ) clif->slide(src,bl->x,bl->y); skill->attack(BF_WEAPON,src,src,bl,skill_id,skill_lv,tick,flag); break; case LG_SHIELDSPELL: - // flag&1: Phisycal Attack, flag&2: Magic Attack. - skill->attack((flag&1)?BF_WEAPON:BF_MAGIC,src,src,bl,skill_id,skill_lv,tick,flag); - break; - - case LG_OVERBRAND: - skill->attack(BF_WEAPON, src, src, bl, skill_id, skill_lv, tick, flag|SD_LEVEL); + if ( skill_lv == 1 ) + skill->attack(BF_WEAPON,src,src,bl,skill_id,skill_lv,tick,flag); + else if ( skill_lv == 2 ) + skill->attack(BF_MAGIC,src,src,bl,skill_id,skill_lv,tick,flag); break; - case LG_OVERBRAND_BRANDISH: - skill->addtimerskill(src, tick + status_get_amotion(src)*8/10, bl->id, 0, 0, skill_id, skill_lv, BF_WEAPON, flag|SD_LEVEL); - break; case SR_DRAGONCOMBO: skill->attack(BF_WEAPON,src,src,bl,skill_id,skill_lv,tick,flag); break; case SR_KNUCKLEARROW: - if( !map_flag_gvg(src->m) && !map[src->m].flag.battleground && unit_movepos(src, bl->x, bl->y, 1, 1) ) { + if( !map_flag_gvg2(src->m) && !map->list[src->m].flag.battleground && unit->movepos(src, bl->x, bl->y, 1, 1) ) { clif->slide(src,bl->x,bl->y); clif->fixpos(src); // Aegis send this packet too. } @@ -4393,9 +4471,13 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint status_change_end(bl, SC_RUSH_WINDMILL, INVALID_TIMER); status_change_end(bl, SC_ECHOSONG, INVALID_TIMER); status_change_end(bl, SC_HARMONIZE, INVALID_TIMER); + status_change_end(bl, SC_SIREN, INVALID_TIMER); + status_change_end(bl, SC_DEEP_SLEEP, INVALID_TIMER); status_change_end(bl, SC_SIRCLEOFNATURE, INVALID_TIMER); - status_change_end(bl, SC_SATURDAY_NIGHT_FEVER, INVALID_TIMER); + status_change_end(bl, SC_GLOOMYDAY, INVALID_TIMER); + status_change_end(bl, SC_SONG_OF_MANA, INVALID_TIMER); status_change_end(bl, SC_DANCE_WITH_WUG, INVALID_TIMER); + status_change_end(bl, SC_SATURDAY_NIGHT_FEVER, INVALID_TIMER); status_change_end(bl, SC_LERADS_DEW, INVALID_TIMER); status_change_end(bl, SC_MELODYOFSINK, INVALID_TIMER); status_change_end(bl, SC_BEYOND_OF_WARCRY, INVALID_TIMER); @@ -4409,28 +4491,61 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint status_change_end(bl, SC_HIDING, INVALID_TIMER); status_change_end(bl, SC_CLOAKINGEXCEED, INVALID_TIMER); } else{ - iMap->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), 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, 6); - } + } break; - case SO_POISON_BUSTER: { - struct status_change *tsc = status_get_sc(bl); - if( tsc && tsc->data[SC_POISON] ) { - skill->attack(skill->get_type(skill_id), src, src, bl, skill_id, skill_lv, tick, flag); - status_change_end(bl, SC_POISON, INVALID_TIMER); - } - else if( sd ) - clif->skill_fail(sd, skill_id, USESKILL_FAIL_LEVEL, 0); - } + case WM_SOUND_OF_DESTRUCTION: + { + struct status_change *tsc = status->get_sc(bl); + if( tsc && tsc->count && ( tsc->data[SC_SWING] || tsc->data[SC_SYMPHONY_LOVE] || tsc->data[SC_MOONLIT_SERENADE] || + tsc->data[SC_RUSH_WINDMILL] || tsc->data[SC_ECHOSONG] || tsc->data[SC_HARMONIZE] || + tsc->data[SC_SIREN] || tsc->data[SC_DEEP_SLEEP] || tsc->data[SC_SIRCLEOFNATURE] || + tsc->data[SC_GLOOMYDAY] || tsc->data[SC_SONG_OF_MANA] || + tsc->data[SC_DANCE_WITH_WUG] || tsc->data[SC_SATURDAY_NIGHT_FEVER] || tsc->data[SC_LERADS_DEW] || + tsc->data[SC_MELODYOFSINK] || tsc->data[SC_BEYOND_OF_WARCRY] || tsc->data[SC_UNLIMITED_HUMMING_VOICE] ) && + rnd()%100 < 4 * skill_lv + 2 * (sd ? pc->checkskill(sd,WM_LESSON) : 10) + 10 * battle->calc_chorusbonus(sd)) { + skill->attack(BF_MISC,src,src,bl,skill_id,skill_lv,tick,flag); + status->change_start(src,bl,SC_STUN,10000,skill_lv,0,0,0,skill->get_time(skill_id,skill_lv),8); + status_change_end(bl, SC_SWING, INVALID_TIMER); + status_change_end(bl, SC_SYMPHONY_LOVE, INVALID_TIMER); + status_change_end(bl, SC_MOONLIT_SERENADE, INVALID_TIMER); + status_change_end(bl, SC_RUSH_WINDMILL, INVALID_TIMER); + status_change_end(bl, SC_ECHOSONG, INVALID_TIMER); + status_change_end(bl, SC_HARMONIZE, INVALID_TIMER); + status_change_end(bl, SC_SIREN, INVALID_TIMER); + status_change_end(bl, SC_DEEP_SLEEP, INVALID_TIMER); + status_change_end(bl, SC_SIRCLEOFNATURE, INVALID_TIMER); + status_change_end(bl, SC_GLOOMYDAY, INVALID_TIMER); + status_change_end(bl, SC_SONG_OF_MANA, INVALID_TIMER); + status_change_end(bl, SC_DANCE_WITH_WUG, INVALID_TIMER); + status_change_end(bl, SC_SATURDAY_NIGHT_FEVER, INVALID_TIMER); + status_change_end(bl, SC_LERADS_DEW, INVALID_TIMER); + status_change_end(bl, SC_MELODYOFSINK, INVALID_TIMER); + status_change_end(bl, SC_BEYOND_OF_WARCRY, INVALID_TIMER); + status_change_end(bl, SC_UNLIMITED_HUMMING_VOICE, INVALID_TIMER); + } + } + break; + + case SO_POISON_BUSTER: + { + struct status_change *tsc = status->get_sc(bl); + if( tsc && tsc->data[SC_POISON] ) { + skill->attack(skill->get_type(skill_id), src, src, bl, skill_id, skill_lv, tick, flag); + status_change_end(bl, SC_POISON, INVALID_TIMER); + } else if( sd ) + clif->skill_fail(sd, skill_id, USESKILL_FAIL_LEVEL, 0); + } break; case GN_SPORE_EXPLOSION: if( flag&1 ) - skill->attack(skill->get_type(skill_id), src, src, bl, skill_id, skill_lv, tick, flag); + skill->attack(BF_WEAPON, src, src, bl, skill_id, skill_lv, tick, flag); else { clif->skill_nodamage(src, bl, skill_id, 0, 1); - skill->addtimerskill(src, iTimer->gettick() + skill->get_time(skill_id, skill_lv) - 1000, bl->id, 0, 0, skill_id, skill_lv, 0, 0); + skill->addtimerskill(src, timer->gettick() + skill->get_time(skill_id, skill_lv), bl->id, 0, 0, skill_id, skill_lv, 0, 0); } break; @@ -4446,7 +4561,7 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint clif->skill_nodamage(src,battle->get_master(src),skill_id,skill_lv,1); clif->skill_damage(src, bl, tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6); if( rnd()%100 < 30 ) - iMap->foreachinrange(skill->area_sub,bl,i,BL_CHAR,src,skill_id,skill_lv,tick,flag|BCT_ENEMY|1,skill->castend_damage_id); + map->foreachinrange(skill->area_sub,bl,i,BL_CHAR,src,skill_id,skill_lv,tick,flag|BCT_ENEMY|1,skill->castend_damage_id); else skill->attack(skill->get_type(skill_id),src,src,bl,skill_id,skill_lv,tick,flag); } @@ -4469,7 +4584,7 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint clif->skill_nodamage(src,battle->get_master(src),skill_id,skill_lv,1); clif->skill_damage(src, src, tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6); if( rnd()%100 < 30 ) - iMap->foreachinrange(skill->area_sub,bl,i,BL_CHAR,src,skill_id,skill_lv,tick,flag|BCT_ENEMY|1,skill->castend_damage_id); + map->foreachinrange(skill->area_sub,bl,i,BL_CHAR,src,skill_id,skill_lv,tick,flag|BCT_ENEMY|1,skill->castend_damage_id); else skill->attack(skill->get_type(skill_id),src,src,bl,skill_id,skill_lv,tick,flag); } @@ -4487,34 +4602,33 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint case EL_TIDAL_WEAPON: if( src->type == BL_ELEM ) { struct elemental_data *ele = BL_CAST(BL_ELEM,src); - struct status_change *sc = status_get_sc(&ele->bl); - struct status_change *tsc = status_get_sc(bl); - sc_type type = status_skill2sc(skill_id), type2; + struct status_change *esc = status->get_sc(&ele->bl); + struct status_change *tsc = status->get_sc(bl); + sc_type type = status->skill2sc(skill_id), type2; type2 = type-1; clif->skill_nodamage(src,battle->get_master(src),skill_id,skill_lv,1); clif->skill_damage(src, src, tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6); - if( (sc && sc->data[type2]) || (tsc && tsc->data[type]) ) { - elemental_clean_single_effect(ele, skill_id); + if( (esc && esc->data[type2]) || (tsc && tsc->data[type]) ) { + elemental->clean_single_effect(ele, skill_id); } if( rnd()%100 < 50 ) skill->attack(skill->get_type(skill_id),src,src,bl,skill_id,skill_lv,tick,flag); else { - sc_start(src,type2,100,skill_lv,skill->get_time(skill_id,skill_lv)); - sc_start(battle->get_master(src),type,100,ele->bl.id,skill->get_time(skill_id,skill_lv)); + sc_start(src, src,type2,100,skill_lv,skill->get_time(skill_id,skill_lv)); + sc_start(src, battle->get_master(src),type,100,ele->bl.id,skill->get_time(skill_id,skill_lv)); } clif->skill_nodamage(src,src,skill_id,skill_lv,1); } break; - //recursive homon skill + // Recursive homun skill case MH_MAGMA_FLOW: - case MH_XENO_SLASHER: case MH_HEILIGE_STANGE: if(flag & 1) skill->attack(skill->get_type(skill_id), src, src, bl, skill_id, skill_lv, tick, flag); else { - iMap->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), splash_target(src), src, skill_id, skill_lv, tick, flag | BCT_ENEMY | SD_SPLASH | 1, skill->castend_damage_id); } break; @@ -4523,7 +4637,7 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint skill->attack(BF_WEAPON, src, src, bl, skill_id, skill_lv, tick, flag); break; case MH_TINDER_BREAKER: - if (unit_movepos(src, bl->x, bl->y, 1, 1)) { + if (unit->movepos(src, bl->x, bl->y, 1, 1)) { #if PACKETVER >= 20111005 clif->snap(src, bl->x, bl->y); #else @@ -4531,21 +4645,21 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint #endif } clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start4(bl,SC_RG_CCONFINE_S,100,skill_lv,src->id,0,0,skill->get_time(skill_id,skill_lv))); + sc_start4(src,bl,SC_RG_CCONFINE_S,100,skill_lv,src->id,0,0,skill->get_time(skill_id,skill_lv))); skill->attack(BF_WEAPON, src, src, bl, skill_id, skill_lv, tick, flag); break; case 0:/* no skill - basic/normal attack */ if(sd) { if (flag & 3){ - if (bl->id != skill_area_temp[1]) + if (bl->id != skill->area_temp[1]) skill->attack(BF_WEAPON, src, src, bl, skill_id, skill_lv, tick, SD_LEVEL|flag); } else { - skill_area_temp[1] = bl->id; - iMap->foreachinrange(skill->area_sub, bl, - sd->bonus.splash_range, BL_CHAR, - src, skill_id, skill_lv, tick, flag | BCT_ENEMY | 1, - skill->castend_damage_id); + skill->area_temp[1] = bl->id; + map->foreachinrange(skill->area_sub, bl, + sd->bonus.splash_range, BL_CHAR, + src, skill_id, skill_lv, tick, flag | BCT_ENEMY | 1, + skill->castend_damage_id); flag|=1; //Set flag to 1 so ammo is not double-consumed. [Skotlex] } } @@ -4556,18 +4670,18 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint clif->skill_damage(src, bl, tick, status_get_amotion(src), tstatus->dmotion, 0, abs(skill->get_num(skill_id, skill_lv)), skill_id, skill_lv, skill->get_hit(skill_id)); - iMap->freeblock_unlock(); + map->freeblock_unlock(); return 1; } if( sc && sc->data[SC_CURSEDCIRCLE_ATKER] ) //Should only remove after the skill has been casted. status_change_end(src,SC_CURSEDCIRCLE_ATKER,INVALID_TIMER); - iMap->freeblock_unlock(); + map->freeblock_unlock(); if( sd && !(flag&1) ) {// ensure that the skill last-cast tick is recorded - sd->canskill_tick = iTimer->gettick(); + sd->canskill_tick = timer->gettick(); if( sd->state.arrow_atk ) {// consume arrow on last invocation to this skill. @@ -4584,8 +4698,7 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, uint /*========================================== * *------------------------------------------*/ -int skill_castend_id(int tid, unsigned int tick, int id, intptr_t data) -{ +int skill_castend_id(int tid, int64 tick, int id, intptr_t data) { struct block_list *target, *src; struct map_session_data *sd; struct mob_data *md; @@ -4593,14 +4706,14 @@ int skill_castend_id(int tid, unsigned int tick, int id, intptr_t data) struct status_change *sc = NULL; int inf,inf2,flag = 0; - src = iMap->id2bl(id); + src = map->id2bl(id); if( src == NULL ) { ShowDebug("skill_castend_id: src == NULL (tid=%d, id=%d)\n", tid, id); return 0;// not found } - ud = unit_bl2ud(src); + ud = unit->bl2ud(src); if( ud == NULL ) { ShowDebug("skill_castend_id: ud == NULL (tid=%d, id=%d)\n", tid, id); @@ -4615,7 +4728,7 @@ int skill_castend_id(int tid, unsigned int tick, int id, intptr_t data) return 0; } - if(ud->skill_id != SA_CASTCANCEL && ud->skill_id != SO_SPELLFIST) {// otherwise handled in unit_skillcastcancel() + if(ud->skill_id != SA_CASTCANCEL && ud->skill_id != SO_SPELLFIST) {// otherwise handled in unit->skillcastcancel() if( ud->skilltimer != tid ) { ShowError("skill_castend_id: Timer mismatch %d!=%d!\n", ud->skilltimer, tid); ud->skilltimer = INVALID_TIMER; @@ -4634,13 +4747,13 @@ int skill_castend_id(int tid, unsigned int tick, int id, intptr_t data) if (ud->skilltarget == id) target = src; else - target = iMap->id2bl(ud->skilltarget); + target = map->id2bl(ud->skilltarget); // Use a do so that you can break out of it when the skill fails. do { if(!target || target->prev==NULL) break; - if(src->m != target->m || status_isdead(src)) break; + if(src->m != target->m || status->isdead(src)) break; switch (ud->skill_id) { //These should become skill_castend_pos @@ -4654,7 +4767,7 @@ int skill_castend_id(int tid, unsigned int tick, int id, intptr_t data) inf2 = skill->get_splash(ud->skill_id, ud->skill_lv); ud->skillx = target->x + inf2; ud->skilly = target->y + inf2; - if (inf2 && !iMap->random_dir(target, &ud->skillx, &ud->skilly)) { + if (inf2 && !map->random_dir(target, &ud->skillx, &ud->skilly)) { ud->skillx = target->x; ud->skilly = target->y; } @@ -4668,26 +4781,25 @@ int skill_castend_id(int tid, unsigned int tick, int id, intptr_t data) } if(ud->skill_id == RG_BACKSTAP) { - uint8 dir = iMap->calc_dir(src,target->x,target->y),t_dir = unit_getdir(target); - if(check_distance_bl(src, target, 0) || iMap->check_dir(dir,t_dir)) { + uint8 dir = map->calc_dir(src,target->x,target->y),t_dir = unit->getdir(target); + if(check_distance_bl(src, target, 0) || map->check_dir(dir,t_dir)) { break; } } if( ud->skill_id == PR_TURNUNDEAD ) { - struct status_data *tstatus = status_get_status_data(target); + struct status_data *tstatus = status->get_status_data(target); if( !battle->check_undead(tstatus->race, tstatus->def_ele) ) break; } if( ud->skill_id == RA_WUGSTRIKE ){ - if( !path_search(NULL,src->m,src->x,src->y,target->x,target->y,1,CELL_CHKNOREACH)) + if( !path->search(NULL,src->m,src->x,src->y,target->x,target->y,1,CELL_CHKNOREACH)) break; } - if( ud->skill_id == PR_LEXDIVINA || ud->skill_id == MER_LEXDIVINA ) - { - sc = status_get_sc(target); + if( ud->skill_id == PR_LEXDIVINA || ud->skill_id == MER_LEXDIVINA ) { + sc = status->get_sc(target); if( battle->check_target(src,target, BCT_ENEMY) <= 0 && (!sc || !sc->data[SC_SILENCE]) ) { //If it's not an enemy, and not silenced, you can't use the skill on them. [Skotlex] clif->skill_nodamage (src, target, ud->skill_id, ud->skill_lv, 0); @@ -4717,10 +4829,10 @@ int skill_castend_id(int tid, unsigned int tick, int id, intptr_t data) inf &= ~BCT_NEUTRAL; } - if( sd && (inf2&INF2_CHORUS_SKILL) && skill->check_pc_partner(sd, ud->skill_id, &ud->skill_lv, 1, 0) < 1 ) { - clif->skill_fail(sd, ud->skill_id, USESKILL_FAIL_NEED_HELPER, 0); - break; - } + if( sd && (inf2&INF2_CHORUS_SKILL) && skill->check_pc_partner(sd, ud->skill_id, &ud->skill_lv, 1, 0) < 1 ) { + clif->skill_fail(sd, ud->skill_id, USESKILL_FAIL_NEED_HELPER, 0); + break; + } if( ud->skill_id >= SL_SKE && ud->skill_id <= SL_SKA && target->type == BL_MOB ) { @@ -4730,18 +4842,23 @@ int skill_castend_id(int tid, unsigned int tick, int id, intptr_t data) else if (inf && battle->check_target(src, target, inf) <= 0){ if (sd) clif->skill_fail(sd,ud->skill_id,USESKILL_FAIL_LEVEL,0); break; + } else if( ud->skill_id == RK_PHANTOMTHRUST && target->type != BL_MOB ) { + if( !map_flag_vs(src->m) && battle->check_target(src,target,BCT_PARTY) <= 0 ) + break; // You can use Phantom Thurst on party members in normal maps too. [pakpil] } - if(inf&BCT_ENEMY && (sc = status_get_sc(target)) && - sc->data[SC_FOGWALL] && - rnd() % 100 < 75) { //Fogwall makes all offensive-type targetted skills fail at 75% - if (sd) clif->skill_fail(sd, ud->skill_id, USESKILL_FAIL_LEVEL, 0); - break; + if( inf&BCT_ENEMY + && (sc = status->get_sc(target)) && sc->data[SC_FOGWALL] + && rnd() % 100 < 75 + ) { + // Fogwall makes all offensive-type targeted skills fail at 75% + if (sd) clif->skill_fail(sd, ud->skill_id, USESKILL_FAIL_LEVEL, 0); + break; } } //Avoid doing double checks for instant-cast skills. - if (tid != INVALID_TIMER && !status_check_skilluse(src, target, ud->skill_id, 1)) + if (tid != INVALID_TIMER && !status->check_skilluse(src, target, ud->skill_id, 1)) break; if(md) { @@ -4769,7 +4886,7 @@ int skill_castend_id(int tid, unsigned int tick, int id, intptr_t data) skill->consume_requirement(sd,ud->skill_id,ud->skill_lv,1); } #ifdef OFFICIAL_WALKPATH - if( !path_search_long(NULL, src->m, src->x, src->y, target->x, target->y, CELL_CHKWALL) ) + if( !path->search_long(NULL, src->m, src->x, src->y, target->x, target->y, CELL_CHKWALL) ) break; #endif if( (src->type == BL_MER || src->type == BL_HOM) && !skill->check_condition_mercenary(src, ud->skill_id, ud->skill_lv, 1) ) @@ -4782,11 +4899,11 @@ int skill_castend_id(int tid, unsigned int tick, int id, intptr_t data) } if (ud->walktimer != INVALID_TIMER && ud->skill_id != TK_RUN && ud->skill_id != RA_WUGDASH) - unit_stop_walking(src,1); + unit->stop_walking(src,1); if( !sd || sd->skillitem != ud->skill_id || skill->get_delay(ud->skill_id,ud->skill_lv) ) - ud->canact_tick = tick + skill->delay_fix(src, ud->skill_id, ud->skill_lv); //Tests show wings don't overwrite the delay but skill scrolls do. [Inkfish] - if (sd) { //Cooldown application + ud->canact_tick = tick + skill->delay_fix(src, ud->skill_id, ud->skill_lv); // Tests show wings don't overwrite the delay but skill scrolls do. [Inkfish] + if (sd) { // Cooldown application int i, cooldown = skill->get_cooldown(ud->skill_id, ud->skill_lv); for (i = 0; i < ARRAYLENGTH(sd->skillcooldown) && sd->skillcooldown[i].id; i++) { // Increases/Decreases cooldown of a skill by item/card bonuses. if (sd->skillcooldown[i].id == ud->skill_id){ @@ -4795,7 +4912,7 @@ int skill_castend_id(int tid, unsigned int tick, int id, intptr_t data) } } if(cooldown) - skill->blockpc_start(sd, ud->skill_id, cooldown, false); + skill->blockpc_start(sd, ud->skill_id, cooldown); } if( battle_config.display_status_timers && sd ) clif->status_change(src, SI_POSTDELAY, 1, skill->delay_fix(src, ud->skill_id, ud->skill_lv), 0, 0, 0); @@ -4808,45 +4925,48 @@ int skill_castend_id(int tid, unsigned int tick, int id, intptr_t data) break; case CR_GRANDCROSS: case NPC_GRANDDARKNESS: - if( (sc = status_get_sc(src)) && sc->data[SC_NOEQUIPSHIELD] ) - { - const struct TimerData *timer = iTimer->get_timer(sc->data[SC_NOEQUIPSHIELD]->timer); - if( timer && timer->func == status_change_timer && DIFF_TICK(timer->tick,iTimer->gettick()+skill->get_time(ud->skill_id, ud->skill_lv)) > 0 ) + if( (sc = status->get_sc(src)) && sc->data[SC_NOEQUIPSHIELD] ) { + const struct TimerData *td = timer->get(sc->data[SC_NOEQUIPSHIELD]->timer); + if( td && td->func == status->change_timer && DIFF_TICK(td->tick,timer->gettick()+skill->get_time(ud->skill_id, ud->skill_lv)) > 0 ) break; } - sc_start2(src, SC_NOEQUIPSHIELD, 100, 0, 1, skill->get_time(ud->skill_id, ud->skill_lv)); + sc_start2(src,src, SC_NOEQUIPSHIELD, 100, 0, 1, skill->get_time(ud->skill_id, ud->skill_lv)); break; } } if (skill->get_state(ud->skill_id) != ST_MOVE_ENABLE) - unit_set_walkdelay(src, tick, battle_config.default_walk_delay+skill->get_walkdelay(ud->skill_id, ud->skill_lv), 1); + unit->set_walkdelay(src, tick, battle_config.default_walk_delay+skill->get_walkdelay(ud->skill_id, ud->skill_lv), 1); if(battle_config.skill_log && battle_config.skill_log&src->type) ShowInfo("Type %d, ID %d skill castend id [id =%d, lv=%d, target ID %d]\n", src->type, src->id, ud->skill_id, ud->skill_lv, target->id); - iMap->freeblock_lock(); + map->freeblock_lock(); // SC_MAGICPOWER needs to switch states before any damage is actually dealt skill->toggle_magicpower(src, ud->skill_id); + + /* On aegis damage skills are also increase by camouflage. Need confirmation on kRO. if( ud->skill_id != RA_CAMOUFLAGE ) // only normal attack and auto cast skills benefit from its bonuses status_change_end(src,SC_CAMOUFLAGE, INVALID_TIMER); + */ if (skill->get_casttype(ud->skill_id) == CAST_NODAMAGE) skill->castend_nodamage_id(src,target,ud->skill_id,ud->skill_lv,tick,flag); else skill->castend_damage_id(src,target,ud->skill_id,ud->skill_lv,tick,flag); - sc = status_get_sc(src); + sc = status->get_sc(src); if(sc && sc->count) { - if(sc->data[SC_SOULLINK] && - sc->data[SC_SOULLINK]->val2 == SL_WIZARD && - sc->data[SC_SOULLINK]->val3 == ud->skill_id && - ud->skill_id != WZ_WATERBALL) + if( sc->data[SC_SOULLINK] + && sc->data[SC_SOULLINK]->val2 == SL_WIZARD + && sc->data[SC_SOULLINK]->val3 == ud->skill_id + && ud->skill_id != WZ_WATERBALL + ) sc->data[SC_SOULLINK]->val3 = 0; //Clear bounced spell check. if( sc->data[SC_DANCING] && skill->get_inf2(ud->skill_id)&INF2_SONG_DANCE && sd ) - skill->blockpc_start(sd,BD_ADAPTATION,3000, false); + skill->blockpc_start(sd,BD_ADAPTATION,3000); } if( sd && ud->skill_id != SA_ABRACADABRA && ud->skill_id != WM_RANDOMIZESPELL ) // they just set the data so leave it as it is.[Inkfish] @@ -4857,39 +4977,39 @@ int skill_castend_id(int tid, unsigned int tick, int id, intptr_t data) else ud->skill_id = 0; //mobs can't clear this one as it is used for skill condition 'afterskill' ud->skill_lv = ud->skilltarget = 0; } - iMap->freeblock_unlock(); + map->freeblock_unlock(); return 1; } while(0); //Skill failed. - if (ud->skill_id == MO_EXTREMITYFIST && sd && !(sc && sc->data[SC_FOGWALL])) - { //When Asura fails... (except when it fails from Fog of Wall) + if (ud->skill_id == MO_EXTREMITYFIST && sd && !(sc && sc->data[SC_FOGWALL])) { + //When Asura fails... (except when it fails from Fog of Wall) //Consume SP/spheres skill->consume_requirement(sd,ud->skill_id, ud->skill_lv,1); - status_set_sp(src, 0, 0); + status->set_sp(src, 0, 0); sc = &sd->sc; if (sc->count) { //End states status_change_end(src, SC_EXPLOSIONSPIRITS, INVALID_TIMER); status_change_end(src, SC_BLADESTOP, INVALID_TIMER); #ifdef RENEWAL - sc_start(src, SC_EXTREMITYFIST2, 100, ud->skill_lv, skill->get_time(ud->skill_id, ud->skill_lv)); + sc_start(src, src, SC_EXTREMITYFIST2, 100, ud->skill_lv, skill->get_time(ud->skill_id, ud->skill_lv)); #endif } - if (target && target->m == src->m) - { //Move character to target anyway. + if (target && target->m == src->m) { + //Move character to target anyway. int dir, x, y; - dir = iMap->calc_dir(src,target->x,target->y); + dir = map->calc_dir(src,target->x,target->y); if( dir > 0 && dir < 4) x = -2; else if( dir > 4 ) x = 2; else x = 0; if( dir > 2 && dir < 6 ) y = -2; else if( dir == 7 || dir < 2 ) y = 2; else y = 0; - if (unit_movepos(src, src->x+x, src->y+y, 1, 1)) + if (unit->movepos(src, src->x+x, src->y+y, 1, 1)) { //Display movement + animation. clif->slide(src,src->x,src->y); - clif->skill_damage(src,target,tick,sd->battle_status.amotion,0,0,1,ud->skill_id, ud->skill_lv, 5); + clif->spiritball(src); } clif->skill_fail(sd,ud->skill_id,USESKILL_FAIL_LEVEL,0); } @@ -4911,8 +5031,7 @@ int skill_castend_id(int tid, unsigned int tick, int id, intptr_t data) /*========================================== * *------------------------------------------*/ -int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, uint16 skill_id, uint16 skill_lv, unsigned int tick, int flag) -{ +int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uint16 skill_id, uint16 skill_lv, int64 tick, int flag) { struct map_session_data *sd, *dstsd; struct mob_data *md, *dstmd; struct homun_data *hd; @@ -4921,10 +5040,10 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui struct status_change *tsc; struct status_change_entry *tsce; - int i = 0; + int element = 0; enum sc_type type; - if(skill_id > 0 && !skill_lv) return 0; // celest + if(skill_id > 0 && !skill_lv) return 0; // [Celest] nullpo_retr(1, src); nullpo_retr(1, bl); @@ -4942,10 +5061,10 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui if(bl->prev == NULL) return 1; - if(status_isdead(src)) + if(status->isdead(src)) return 1; - if( src != bl && status_isdead(bl) ) { + if( src != bl && status->isdead(bl) ) { /** * Skills that may be cast on dead targets **/ @@ -4960,41 +5079,94 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui } } - tstatus = status_get_status_data(bl); - sstatus = status_get_status_data(src); + // Supportive skills that can't be cast in users with mado + if( sd && dstsd && pc_ismadogear(dstsd) ) { + switch( skill_id ) { + case AL_HEAL: + case AL_INCAGI: + case AL_DECAGI: + case AB_RENOVATIO: + case AB_HIGHNESSHEAL: + clif->skill_fail(sd,skill_id,USESKILL_FAIL_TOTARGET,0); + return 0; + default: + break; + } + } + + tstatus = status->get_status_data(bl); + sstatus = status->get_status_data(src); //Check for undead skills that convert a no-damage skill into a damage one. [Skotlex] switch (skill_id) { - case HLIF_HEAL: //[orn] + case HLIF_HEAL: // [orn] if (bl->type != BL_HOM) { if (sd) clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0) ; break ; } case AL_HEAL: - case ALL_RESURRECTION: - case PR_ASPERSIO: + /** * Arch Bishop **/ case AB_RENOVATIO: case AB_HIGHNESSHEAL: + case AL_INCAGI: + case ALL_RESURRECTION: + case PR_ASPERSIO: //Apparently only player casted skills can be offensive like this. - if (sd && battle->check_undead(tstatus->race,tstatus->def_ele)) { + if (sd && battle->check_undead(tstatus->race,tstatus->def_ele) && skill_id != AL_INCAGI) { if (battle->check_target(src, bl, BCT_ENEMY) < 1) { //Offensive heal does not works on non-enemies. [Skotlex] clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); return 0; } - return skill->castend_damage_id (src, bl, skill_id, skill_lv, tick, flag); + return skill->castend_damage_id(src, bl, skill_id, skill_lv, tick, flag); + } + break; + case SO_ELEMENTAL_SHIELD: + { + struct party_data *p; + short ret = 0; + int x0, y0, x1, y1, range, i; + + if(sd == NULL || !sd->ed) + break; + if((p = party->search(sd->status.party_id)) == NULL) + break; + + range = skill_get_splash(skill_id,skill_lv); + x0 = sd->bl.x - range; + y0 = sd->bl.y - range; + x1 = sd->bl.x + range; + y1 = sd->bl.y + range; + + elemental->delete(sd->ed,0); + + if(!skill->check_unit_range(src,src->x,src->y,skill_id,skill_lv)) + ret = skill->castend_pos2(src,src->x,src->y,skill_id,skill_lv,tick,flag); + for(i = 0; i < MAX_PARTY; i++) { + struct map_session_data *psd = p->data[i].sd; + if(!psd) + continue; + if(psd->bl.m != sd->bl.m || !psd->bl.prev) + continue; + if(range && (psd->bl.x < x0 || psd->bl.y < y0 || + psd->bl.x > x1 || psd->bl.y > y1)) + continue; + if(!skill->check_unit_range(bl,psd->bl.x,psd->bl.y,skill_id,skill_lv)) + ret |= skill->castend_pos2(bl,psd->bl.x,psd->bl.y,skill_id,skill_lv,tick,flag); + } + return ret; } break; case NPC_SMOKING: //Since it is a self skill, this one ends here rather than in damage_id. [Skotlex] - return skill->castend_damage_id (src, bl, skill_id, skill_lv, tick, flag); + return skill->castend_damage_id(src, bl, skill_id, skill_lv, tick, flag); case MH_STEINWAND: { struct block_list *s_src = battle->get_master(src); short ret = 0; if(!skill->check_unit_range(src, src->x, src->y, skill_id, skill_lv)) //prevent reiteration - ret = skill->castend_pos2(src,src->x,src->y,skill_id,skill_lv,tick,flag); //cast on homon + ret = skill->castend_pos2(src,src->x,src->y,skill_id,skill_lv,tick,flag); //cast on homun if(s_src && !skill->check_unit_range(s_src, s_src->x, s_src->y, skill_id, skill_lv)) ret |= skill->castend_pos2(s_src,s_src->x,s_src->y,skill_id,skill_lv,tick,flag); //cast on master if (hd) @@ -5012,9 +5184,9 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case RK_FIGHTINGSPIRIT: case RK_ABUNDANCE: if( sd && !pc->checkskill(sd, RK_RUNEMASTERY) ){ - if( status_change_start(&sd->bl, (sc_type)(rnd()%SC_CONFUSION), 1000, 1, 0, 0, 0, skill->get_time2(skill_id,skill_lv),8) ){ + if( status->change_start(src,&sd->bl, (sc_type)(rnd()%SC_CONFUSION), 1000, 1, 0, 0, 0, skill->get_time2(skill_id,skill_lv),8) ){ skill->consume_requirement(sd,skill_id,skill_lv,2); - iMap->freeblock_unlock(); + map->freeblock_unlock(); return 0; } } @@ -5025,19 +5197,19 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui return skill->castend_pos2(src,bl->x,bl->y,skill_id,skill_lv,tick,0); } - type = status_skill2sc(skill_id); - tsc = status_get_sc(bl); + type = status->skill2sc(skill_id); + tsc = status->get_sc(bl); tsce = (tsc && type != -1)?tsc->data[type]:NULL; if (src!=bl && type > -1 && - (i = skill->get_ele(skill_id, skill_lv)) > ELE_NEUTRAL && + (element = skill->get_ele(skill_id, skill_lv)) > ELE_NEUTRAL && skill->get_inf(skill_id) != INF_SUPPORT_SKILL && - battle->attr_fix(NULL, NULL, 100, i, tstatus->def_ele, tstatus->ele_lv) <= 0) + battle->attr_fix(NULL, NULL, 100, element, tstatus->def_ele, tstatus->ele_lv) <= 0) return 1; //Skills that cause an status should be blocked if the target element blocks its element. - iMap->freeblock_lock(); + map->freeblock_lock(); switch(skill_id) { - case HLIF_HEAL: //[orn] + case HLIF_HEAL: // [orn] case AL_HEAL: /** * Arch Bishop @@ -5046,13 +5218,12 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui { int heal = skill->calc_heal(src, bl, (skill_id == AB_HIGHNESSHEAL)?AL_HEAL:skill_id, (skill_id == AB_HIGHNESSHEAL)?10:skill_lv, true); int heal_get_jobexp; - //Highness Heal: starts at 1.5 boost + 0.5 for each level + //Highness Heal: starts at 1.7 boost + 0.3 for each level if( skill_id == AB_HIGHNESSHEAL ) { - heal = heal * ( 15 + 5 * skill_lv ) / 10; + heal = heal * ( 17 + 3 * skill_lv ) / 10; } - if( status_isimmune(bl) || - (dstmd && (dstmd->class_ == MOBID_EMPERIUM || mob_is_battleground(dstmd))) || - (dstsd && pc_ismadogear(dstsd)) )//Mado is immune to heal + if( status->isimmune(bl) || + (dstmd && (dstmd->class_ == MOBID_EMPERIUM || mob_is_battleground(dstmd))) ) heal=0; if( sd && dstsd && sd->status.partner_id == dstsd->status.char_id && (sd->class_&MAPID_UPPERMASK) == MAPID_SUPER_NOVICE && sd->status.sex == 0 ) @@ -5071,13 +5242,13 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui dstsd = sd; } } - else if (tsc->data[SC_BERSERK] || tsc->data[SC_SATURDAY_NIGHT_FEVER] || tsc->data[SC__BLOODYLUST]) + else if (tsc->data[SC_BERSERK]) heal = 0; //Needed so that it actually displays 0 when healing. } clif->skill_nodamage (src, bl, skill_id, heal, 1); if( tsc && tsc->data[SC_AKAITSUKI] && heal && skill_id != HLIF_HEAL ) heal = ~heal + 1; - heal_get_jobexp = status_heal(bl,heal,0,0); + heal_get_jobexp = status->heal(bl,heal,0,0); if(sd && dstsd && heal > 0 && sd != dstsd && battle_config.heal_exp > 0){ heal_get_jobexp = heal_get_jobexp * battle_config.heal_exp / 100; @@ -5094,45 +5265,45 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); break; } - skill_area_temp[0] = 0; - party_foreachsamemap(skill->area_sub, + skill->area_temp[0] = 0; + party->foreachsamemap(skill->area_sub, sd,skill->get_splash(skill_id, skill_lv), src,skill_id,skill_lv,tick, flag|BCT_PARTY|1, skill->castend_nodamage_id); - if (skill_area_temp[0] == 0) { + if (skill->area_temp[0] == 0) { clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); break; } - skill_area_temp[0] = 5 - skill_area_temp[0]; // The actual penalty... - if (skill_area_temp[0] > 0 && !map[src->m].flag.noexppenalty) { //Apply penalty - sd->status.base_exp -= min(sd->status.base_exp, pc->nextbaseexp(sd) * skill_area_temp[0] * 2/1000); //0.2% penalty per each. - sd->status.job_exp -= min(sd->status.job_exp, pc->nextjobexp(sd) * skill_area_temp[0] * 2/1000); + skill->area_temp[0] = 5 - skill->area_temp[0]; // The actual penalty... + if (skill->area_temp[0] > 0 && !map->list[src->m].flag.noexppenalty) { //Apply penalty + sd->status.base_exp -= min(sd->status.base_exp, pc->nextbaseexp(sd) * skill->area_temp[0] * 2/1000); //0.2% penalty per each. + sd->status.job_exp -= min(sd->status.job_exp, pc->nextjobexp(sd) * skill->area_temp[0] * 2/1000); clif->updatestatus(sd,SP_BASEEXP); clif->updatestatus(sd,SP_JOBEXP); } - status_set_hp(src, 1, 0); - status_set_sp(src, 0, 0); + status->set_hp(src, 1, 0); + status->set_sp(src, 0, 0); break; - } else if (status_isdead(bl) && flag&1) { //Revive - skill_area_temp[0]++; //Count it in, then fall-through to the Resurrection code. + } else if (status->isdead(bl) && flag&1) { //Revive + skill->area_temp[0]++; //Count it in, then fall-through to the Resurrection code. skill_lv = 3; //Resurrection level 3 is used } else //Invalid target, skip resurrection. break; case ALL_RESURRECTION: - if(sd && (map_flag_gvg(bl->m) || map[bl->m].flag.battleground)) - { //No reviving in WoE grounds! + if(sd && (map_flag_gvg2(bl->m) || map->list[bl->m].flag.battleground)) { + //No reviving in WoE grounds! clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); break; } - if (!status_isdead(bl)) + if (!status->isdead(bl)) break; { int per = 0, sper = 0; if (tsc && tsc->data[SC_HELLPOWER]) break; - if (map[bl->m].flag.pvp && dstsd && dstsd->pvp_point < 0) + if (map->list[bl->m].flag.pvp && dstsd && dstsd->pvp_point < 0) break; switch(skill_lv){ @@ -5143,7 +5314,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui } if(dstsd && dstsd->special_state.restart_full_recover) per = sper = 100; - if (status_revive(bl, per, sper)) + if (status->revive(bl, per, sper)) { clif->skill_nodamage(src,bl,ALL_RESURRECTION,skill_lv,1); //Both Redemptio and Res show this skill-animation. if(sd && dstsd && battle_config.resurrection_exp > 0) @@ -5166,17 +5337,24 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui break; case AL_DECAGI: - case MER_DECAGI: clif->skill_nodamage (src, bl, skill_id, skill_lv, - sc_start(bl, type, (40 + skill_lv * 2 + (status_get_lv(src) + sstatus->int_)/5), skill_lv, skill->get_time(skill_id,skill_lv))); + sc_start(src, bl, type, (40 + skill_lv * 2 + (status->get_lv(src) + sstatus->int_)/5), skill_lv, + /* monsters using lvl 48 get the rate benefit but the duration of lvl 10 */ + ( src->type == BL_MOB && skill_lv == 48 ) ? skill->get_time(skill_id,10) : skill->get_time(skill_id,skill_lv))); + break; + + case MER_DECAGI: + if( tsc && !tsc->data[SC_ADORAMUS] ) //Prevent duplicate agi-down effect. + clif->skill_nodamage(src, bl, skill_id, skill_lv, + sc_start(src, bl, type, (40 + skill_lv * 2 + (status->get_lv(src) + sstatus->int_)/5), skill_lv, skill->get_time(skill_id,skill_lv))); break; case AL_CRUCIS: if (flag&1) - sc_start(bl,type, 23+skill_lv*4 +status_get_lv(src) -status_get_lv(bl), skill_lv,skill->get_time(skill_id,skill_lv)); + sc_start(src, bl,type, 23+skill_lv*4 +status->get_lv(src) -status->get_lv(bl), skill_lv,skill->get_time(skill_id,skill_lv)); else { - iMap->foreachinrange(skill->area_sub, src, skill->get_splash(skill_id, skill_lv), BL_CHAR, - src, skill_id, skill_lv, tick, flag|BCT_ENEMY|1, skill->castend_nodamage_id); + map->foreachinrange(skill->area_sub, src, skill->get_splash(skill_id, skill_lv), BL_CHAR, + src, skill_id, skill_lv, tick, flag|BCT_ENEMY|1, skill->castend_nodamage_id); clif->skill_nodamage(src, bl, skill_id, skill_lv, 1); } break; @@ -5186,19 +5364,19 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui if( tsce ) status_change_end(bl,type, INVALID_TIMER); else - sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv)); + sc_start(src, bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv)); clif->skill_nodamage (src, bl, skill_id, skill_lv, 1); break; case SA_ABRACADABRA: { - int abra_skill_id = 0, abra_skill_lv; + int abra_skill_id = 0, abra_skill_lv, abra_idx; do { - i = rnd() % MAX_SKILL_ABRA_DB; - abra_skill_id = skill_abra_db[i].skill_id; + abra_idx = rnd() % MAX_SKILL_ABRA_DB; + abra_skill_id = skill->abra_db[abra_idx].skill_id; } while (abra_skill_id == 0 || - skill_abra_db[i].req_lv > skill_lv || //Required lv for it to appear - rnd()%10000 >= skill_abra_db[i].per + skill->abra_db[abra_idx].req_lv > skill_lv || //Required lv for it to appear + rnd()%10000 >= skill->abra_db[abra_idx].per ); abra_skill_lv = min(skill_lv, skill->get_max(abra_skill_id)); clif->skill_nodamage (src, bl, skill_id, skill_lv, 1); @@ -5212,14 +5390,14 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui } else {// mob-casted - struct unit_data *ud = unit_bl2ud(src); + struct unit_data *ud = unit->bl2ud(src); int inf = skill->get_inf(abra_skill_id); if (!ud) break; if (inf&INF_SELF_SKILL || inf&INF_SUPPORT_SKILL) { if (src->type == BL_PET) bl = (struct block_list*)((TBL_PET*)src)->msd; if (!bl) bl = src; - unit_skilluse_id(src, bl->id, abra_skill_id, abra_skill_lv); + unit->skilluse_id(src, bl->id, abra_skill_id, abra_skill_lv); } else { //Assume offensive skills int target_id = 0; if (ud->target) @@ -5231,11 +5409,11 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui if (!target_id) break; if (skill->get_casttype(abra_skill_id) == CAST_GROUND) { - bl = iMap->id2bl(target_id); + bl = map->id2bl(target_id); if (!bl) bl = src; - unit_skilluse_pos(src, bl->x, bl->y, abra_skill_id, abra_skill_lv); + unit->skilluse_pos(src, bl->x, bl->y, abra_skill_id, abra_skill_lv); } else - unit_skilluse_id(src, target_id, abra_skill_id, abra_skill_lv); + unit->skilluse_id(src, target_id, abra_skill_id, abra_skill_lv); } } } @@ -5243,31 +5421,31 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case SA_COMA: clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start(bl,type,100,skill_lv,skill->get_time2(skill_id,skill_lv))); + sc_start(src, bl,type,100,skill_lv,skill->get_time2(skill_id,skill_lv))); break; case SA_FULLRECOVERY: clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - if (status_isimmune(bl)) + if (status->isimmune(bl)) break; status_percent_heal(bl, 100, 100); break; case NPC_ALLHEAL: - { - int heal; - if( status_isimmune(bl) ) - break; - heal = status_percent_heal(bl, 100, 0); - clif->skill_nodamage(NULL, bl, AL_HEAL, heal, 1); - if( dstmd ) - { // Reset Damage Logs - memset(dstmd->dmglog, 0, sizeof(dstmd->dmglog)); - dstmd->tdmg = 0; - } + { + int heal; + if( status->isimmune(bl) ) + break; + heal = status_percent_heal(bl, 100, 0); + clif->skill_nodamage(NULL, bl, AL_HEAL, heal, 1); + if( dstmd ) { + // Reset Damage Logs + memset(dstmd->dmglog, 0, sizeof(dstmd->dmglog)); + dstmd->tdmg = 0; } + } break; case SA_SUMMONMONSTER: clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - if (sd) mob_once_spawn(sd, src->m, src->x, src->y," --ja--", -1, 1, "", SZ_SMALL, AI_NONE); + if (sd) mob->once_spawn(sd, src->m, src->x, src->y," --ja--", -1, 1, "", SZ_MEDIUM, AI_NONE); break; case SA_LEVELUP: clif->skill_nodamage(src,bl,skill_id,skill_lv,1); @@ -5275,7 +5453,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui break; case SA_INSTANTDEATH: clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - status_set_hp(bl,1,0); + status->set_hp(bl,1,0); break; case SA_QUESTION: case SA_GRAVITY: @@ -5291,11 +5469,12 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); break; } - class_ = skill_id==SA_MONOCELL?1002:mob_get_random_id(4, 1, 0); + class_ = skill_id==SA_MONOCELL?1002:mob->get_random_id(4, 1, 0); clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - mob_class_change(dstmd,class_); + mob->class_change(dstmd,class_); if( tsc && dstmd->status.mode&MD_BOSS ) { + int i; const enum sc_type scs[] = { SC_QUAGMIRE, SC_PROVOKE, SC_ROKISWEIL, SC_GRAVITATION, SC_NJ_SUITON, SC_NOEQUIPWEAPON, SC_NOEQUIPSHIELD, SC_NOEQUIPARMOR, SC_NOEQUIPHELM, SC_BLADESTOP }; for (i = SC_COMMON_MIN; i <= SC_COMMON_MAX; i++) if (tsc->data[i]) status_change_end(bl, (sc_type)i, INVALID_TIMER); @@ -5314,19 +5493,21 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui status_kill(bl); break; case SA_REVERSEORCISH: + case ALL_REVERSEORCISH: clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start(bl,type,100,skill_lv,skill->get_time(skill_id, skill_lv))); + sc_start(src, bl,type,100,skill_lv,skill->get_time(skill_id, skill_lv))); break; case SA_FORTUNE: clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - if(sd) pc->getzeny(sd,status_get_lv(bl)*100,LOG_TYPE_STEAL,NULL); + if(sd) pc->getzeny(sd,status->get_lv(bl)*100,LOG_TYPE_STEAL,NULL); break; case SA_TAMINGMONSTER: clif->skill_nodamage(src,bl,skill_id,skill_lv,1); if (sd && dstmd) { - ARR_FIND( 0, MAX_PET_DB, i, dstmd->class_ == pet_db[i].class_ ); + int i; + ARR_FIND( 0, MAX_PET_DB, i, dstmd->class_ == pet->db[i].class_ ); if( i < MAX_PET_DB ) - pet_catch_process1(sd, dstmd->class_); + pet->catch_process1(sd, dstmd->class_); } break; @@ -5334,46 +5515,39 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui if(sd && dstsd){ //Check they are not another crusader [Skotlex] if ((dstsd->class_&MAPID_UPPERMASK) == MAPID_CRUSADER) { clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - iMap->freeblock_unlock(); + map->freeblock_unlock(); return 1; } } clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); + sc_start(src, bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); break; case CG_MARIONETTE: { - struct status_change* sc = status_get_sc(src); + struct status_change* sc = status->get_sc(src); - if( sd && dstsd && (dstsd->class_&MAPID_UPPERMASK) == MAPID_BARDDANCER && dstsd->status.sex == sd->status.sex ) - {// Cannot cast on another bard/dancer-type class of the same gender as caster + if( sd && dstsd && (dstsd->class_&MAPID_UPPERMASK) == MAPID_BARDDANCER && dstsd->status.sex == sd->status.sex ) { + // Cannot cast on another bard/dancer-type class of the same gender as caster clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - iMap->freeblock_unlock(); + map->freeblock_unlock(); return 1; } - if( sc && tsc ) - { - if( !sc->data[SC_MARIONETTE_MASTER] && !tsc->data[SC_MARIONETTE] ) - { - sc_start(src,SC_MARIONETTE_MASTER,100,bl->id,skill->get_time(skill_id,skill_lv)); - sc_start(bl,SC_MARIONETTE,100,src->id,skill->get_time(skill_id,skill_lv)); + if( sc && tsc ) { + if( !sc->data[SC_MARIONETTE_MASTER] && !tsc->data[SC_MARIONETTE] ) { + sc_start(src,src,SC_MARIONETTE_MASTER,100,bl->id,skill->get_time(skill_id,skill_lv)); + sc_start(src,bl,SC_MARIONETTE,100,src->id,skill->get_time(skill_id,skill_lv)); clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - } - else - if( sc->data[SC_MARIONETTE_MASTER ] && sc->data[SC_MARIONETTE_MASTER ]->val1 == bl->id && - tsc->data[SC_MARIONETTE] && tsc->data[SC_MARIONETTE]->val1 == src->id ) - { + } else if( sc->data[SC_MARIONETTE_MASTER ] && sc->data[SC_MARIONETTE_MASTER ]->val1 == bl->id + && tsc->data[SC_MARIONETTE] && tsc->data[SC_MARIONETTE]->val1 == src->id + ) { status_change_end(src, SC_MARIONETTE_MASTER, INVALID_TIMER); status_change_end(bl, SC_MARIONETTE, INVALID_TIMER); - } - else - { + } else { if( sd ) clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - - iMap->freeblock_unlock(); + map->freeblock_unlock(); return 1; } } @@ -5382,7 +5556,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case RG_CLOSECONFINE: clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start4(bl,type,100,skill_lv,src->id,0,0,skill->get_time(skill_id,skill_lv))); + sc_start4(src,bl,type,100,skill_lv,src->id,0,0,skill->get_time(skill_id,skill_lv))); break; case SA_FLAMELAUNCHER: // added failure chance and chance to break weapon if turned on [Valaris] case SA_FROSTWEAPON: @@ -5391,7 +5565,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui if (dstsd) { if(dstsd->status.weapon == W_FIST || (dstsd->sc.count && !dstsd->sc.data[type] && - ( //Allow re-enchanting to lenghten time. [Skotlex] + ( //Allow re-enchanting to lengthen time. [Skotlex] dstsd->sc.data[SC_PROPERTYFIRE] || dstsd->sc.data[SC_PROPERTYWATER] || dstsd->sc.data[SC_PROPERTYWIND] || @@ -5407,11 +5581,11 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui } } // 100% success rate at lv4 & 5, but lasts longer at lv5 - if(!clif->skill_nodamage(src,bl,skill_id,skill_lv, sc_start(bl,type,(60+skill_lv*10),skill_lv, skill->get_time(skill_id,skill_lv)))) { + if(!clif->skill_nodamage(src,bl,skill_id,skill_lv, sc_start(src,bl,type,(60+skill_lv*10),skill_lv, skill->get_time(skill_id,skill_lv)))) { if (sd) clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); if (skill->break_equip(bl, EQP_WEAPON, 10000, BCT_PARTY) && sd && sd != dstsd) - clif->message(sd->fd, msg_txt(669)); + clif->message(sd->fd, msg_txt(869)); // "You broke the target's weapon." } break; @@ -5421,12 +5595,12 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui break; } clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); + sc_start(src,bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); break; case ITEM_ENCHANTARMS: clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start2(bl,type,100,skill_lv, + sc_start2(src,bl,type,100,skill_lv, skill->get_ele(skill_id,skill_lv), skill->get_time(skill_id,skill_lv))); break; @@ -5441,37 +5615,37 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case ELE_HOLY : type = SC_ASPERSIO; break; } clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); + sc_start(src,bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); - sc_start2(bl,SC_TK_SEVENWIND,100,skill_lv,skill->get_ele(skill_id,skill_lv),skill->get_time(skill_id,skill_lv)); + sc_start2(src,bl,SC_TK_SEVENWIND,100,skill_lv,skill->get_ele(skill_id,skill_lv),skill->get_time(skill_id,skill_lv)); break; case PR_KYRIE: case MER_KYRIE: clif->skill_nodamage(bl,bl,skill_id,skill_lv, - sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); + sc_start(src,bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); break; //Passive Magnum, should had been casted on yourself. case SM_MAGNUM: case MS_MAGNUM: - skill_area_temp[1] = 0; - iMap->foreachinrange(skill->area_sub, src, skill->get_splash(skill_id, skill_lv), BL_SKILL|BL_CHAR, - src,skill_id,skill_lv,tick, flag|BCT_ENEMY|1, skill->castend_damage_id); + skill->area_temp[1] = 0; + map->foreachinrange(skill->area_sub, src, skill->get_splash(skill_id, skill_lv), BL_SKILL|BL_CHAR, + src,skill_id,skill_lv,tick, flag|BCT_ENEMY|1, skill->castend_damage_id); clif->skill_nodamage (src,src,skill_id,skill_lv,1); // Initiate 10% of your damage becomes fire element. - sc_start4(src,SC_WATK_ELEMENT,100,3,20,0,0,skill->get_time2(skill_id, skill_lv)); + sc_start4(src,src,SC_SUB_WEAPONPROPERTY,100,3,20,0,0,skill->get_time2(skill_id, skill_lv)); if( sd ) - skill->blockpc_start(sd, skill_id, skill->get_time(skill_id, skill_lv), false); + skill->blockpc_start(sd, skill_id, skill->get_time(skill_id, skill_lv)); else if( bl->type == BL_MER ) skill->blockmerc_start((TBL_MER*)bl, skill_id, skill->get_time(skill_id, skill_lv)); break; case TK_JUMPKICK: - /* Check if the target is an enemy; if not, skill should fail so the character doesn't unit_movepos (exploitable) */ + /* Check if the target is an enemy; if not, skill should fail so the character doesn't unit->movepos (exploitable) */ if( battle->check_target(src, bl, BCT_ENEMY) > 0 ) { - if( unit_movepos(src, bl->x, bl->y, 1, 1) ) + if( unit->movepos(src, bl->x, bl->y, 1, 1) ) { skill->attack(BF_WEAPON,src,src,bl,skill_id,skill_lv,tick,flag); clif->slide(src,bl->x,bl->y); @@ -5496,7 +5670,6 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case PR_BENEDICTIO: case LK_BERSERK: case MS_BERSERK: - case KN_AUTOCOUNTER: case KN_TWOHANDQUICKEN: case KN_ONEHAND: case MER_QUICKEN: @@ -5548,6 +5721,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case NC_SHAPESHIFT: case WL_RECOGNIZEDSPELL: case GC_VENOMIMPRESS: + case SC_INVISIBILITY: case SC_DEADLYINFECT: case LG_EXEEDBREAK: case LG_PRESTIGE: @@ -5564,8 +5738,14 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case RK_VITALITYACTIVATION: case RK_ABUNDANCE: case RK_CRUSHSTRIKE: + case ALL_ODINS_POWER: clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); + sc_start(src,bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); + break; + + case KN_AUTOCOUNTER: + sc_start(src,bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv)); + skill->addtimerskill(src, tick + 100, bl->id, 0, 0, skill_id, skill_lv, BF_WEAPON, flag); break; case SO_STRIKING: @@ -5574,7 +5754,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui bonus += (pc->checkskill(sd, SA_FLAMELAUNCHER)+pc->checkskill(sd, SA_FROSTWEAPON)+pc->checkskill(sd, SA_LIGHTNINGLOADER)+pc->checkskill(sd, SA_SEISMICWEAPON))*5; clif->skill_nodamage( src, bl, skill_id, skill_lv, battle->check_target(src,bl,BCT_PARTY) > 0 ? - sc_start2(bl, type, 100, skill_lv, bonus, skill->get_time(skill_id,skill_lv)) : + sc_start2(src, bl, type, 100, skill_lv, bonus, skill->get_time(skill_id,skill_lv)) : 0 ); } @@ -5582,15 +5762,15 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case NPC_STOP: if( clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start2(bl,type,100,skill_lv,src->id,skill->get_time(skill_id,skill_lv)) ) ) - sc_start2(src,type,100,skill_lv,bl->id,skill->get_time(skill_id,skill_lv)); + sc_start2(src,bl,type,100,skill_lv,src->id,skill->get_time(skill_id,skill_lv)) ) ) + sc_start2(src,src,type,100,skill_lv,bl->id,skill->get_time(skill_id,skill_lv)); break; case HP_ASSUMPTIO: if( sd && dstmd ) clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); else clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); + sc_start(src,bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); break; case MG_SIGHT: case MER_SIGHT: @@ -5600,40 +5780,48 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case NPC_STONESKIN: case NPC_ANTIMAGIC: clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start2(bl,type,100,skill_lv,skill_id,skill->get_time(skill_id,skill_lv))); + sc_start2(src,bl,type,100,skill_lv,skill_id,skill->get_time(skill_id,skill_lv))); break; case HLIF_AVOID: case HAMI_DEFENCE: - i = skill->get_time(skill_id,skill_lv); - clif->skill_nodamage(bl,bl,skill_id,skill_lv,sc_start(bl,type,100,skill_lv,i)); // Master - clif->skill_nodamage(src,src,skill_id,skill_lv,sc_start(src,type,100,skill_lv,i)); // Homunc + { + int duration = skill->get_time(skill_id,skill_lv); + clif->skill_nodamage(bl,bl,skill_id,skill_lv,sc_start(src,bl,type,100,skill_lv,duration)); // Master + clif->skill_nodamage(src,src,skill_id,skill_lv,sc_start(src,src,type,100,skill_lv,duration)); // Homun + } break; case NJ_BUNSINJYUTSU: clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); + sc_start(src,bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); status_change_end(bl, SC_NJ_NEN, INVALID_TIMER); break; - /* Was modified to only affect targetted char. [Skotlex] +#if 0 /* Was modified to only affect targetted char. [Skotlex] */ case HP_ASSUMPTIO: if (flag&1) - sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv)); - else - { - iMap->foreachinrange(skill->area_sub, bl, - skill->get_splash(skill_id, skill_lv), BL_PC, - src, skill_id, skill_lv, tick, flag|BCT_ALL|1, - skill->castend_nodamage_id); + sc_start(src,bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv)); + else { + map->foreachinrange(skill->area_sub, bl, + skill->get_splash(skill_id, skill_lv), BL_PC, + src, skill_id, skill_lv, tick, flag|BCT_ALL|1, + skill->castend_nodamage_id); clif->skill_nodamage(src,bl,skill_id,skill_lv,1); } break; - */ +#endif // 0 case SM_ENDURE: clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); + sc_start(src,bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); if (sd) - skill->blockpc_start (sd, skill_id, skill->get_time2(skill_id,skill_lv), false); + skill->blockpc_start (sd, skill_id, skill->get_time2(skill_id,skill_lv)); break; + case ALL_ANGEL_PROTECT: + if( dstsd ) + clif->skill_nodamage(src,bl,skill_id,skill_lv, + sc_start(src,bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); + else if( sd ) + clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + break; case AS_ENCHANTPOISON: // Prevent spamming [Valaris] if (sd && dstsd && dstsd->sc.count) { if (dstsd->sc.data[SC_PROPERTYFIRE] || @@ -5650,12 +5838,12 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui } } clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); + sc_start(src,bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); break; case LK_TENSIONRELAX: clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start4(bl,type,100,skill_lv,0,0,skill->get_time2(skill_id,skill_lv), + sc_start4(src,bl,type,100,skill_lv,0,0,skill->get_time2(skill_id,skill_lv), skill->get_time(skill_id,skill_lv))); break; @@ -5671,48 +5859,48 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); break; } - id = mob_get_random_id(0,0xF, sd->status.base_level); + id = mob->get_random_id(0,0xF, sd->status.base_level); if (!id) { clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); break; } sd->mission_mobid = id; sd->mission_count = 0; - pc_setglobalreg(sd,"TK_MISSION_ID", id); + pc_setglobalreg(sd,script->add_str("TK_MISSION_ID"), id); clif->mission_info(sd, id, 0); clif->skill_nodamage(src,bl,skill_id,skill_lv,1); } break; case AC_CONCENTRATION: - { - clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); - iMap->foreachinrange( status_change_timer_sub, src, - skill->get_splash(skill_id, skill_lv), BL_CHAR, - src,NULL,type,tick); - } + { + clif->skill_nodamage(src,bl,skill_id,skill_lv, + sc_start(src,bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); + map->foreachinrange(status->change_timer_sub, src, + skill->get_splash(skill_id, skill_lv), BL_CHAR, + src,NULL,type,tick); + } break; case SM_PROVOKE: case SM_SELFPROVOKE: case MER_PROVOKE: - if( (tstatus->mode&MD_BOSS) || battle->check_undead(tstatus->race,tstatus->def_ele) ) - { - iMap->freeblock_unlock(); + { + int failure; + if( (tstatus->mode&MD_BOSS) || battle->check_undead(tstatus->race,tstatus->def_ele) ) { + map->freeblock_unlock(); return 1; } //TODO: How much does base level affects? Dummy value of 1% per level difference used. [Skotlex] clif->skill_nodamage(src,bl,skill_id == SM_SELFPROVOKE ? SM_PROVOKE : skill_id,skill_lv, - (i = sc_start(bl,type, skill_id == SM_SELFPROVOKE ? 100:( 50 + 3*skill_lv + status_get_lv(src) - status_get_lv(bl)), skill_lv, skill->get_time(skill_id,skill_lv)))); - if( !i ) - { + (failure = sc_start(src,bl,type, skill_id == SM_SELFPROVOKE ? 100:( 50 + 3*skill_lv + status->get_lv(src) - status->get_lv(bl)), skill_lv, skill->get_time(skill_id,skill_lv)))); + if( !failure ) { if( sd ) clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - iMap->freeblock_unlock(); + map->freeblock_unlock(); return 0; } - unit_skillcastcancel(bl, 2); + unit->skillcastcancel(bl, 2); if( tsc && tsc->count ) { @@ -5726,14 +5914,15 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui if( dstmd ) { dstmd->state.provoke_flag = src->id; - mob_target(dstmd, src, skill->get_range2(src,skill_id,skill_lv)); + mob->target(dstmd, src, skill->get_range2(src,skill_id,skill_lv)); } + } break; case ML_DEVOTION: case CR_DEVOTION: { - int count, lv; + int count, lv, i; if( !dstsd || (!sd && !mer) ) { // Only players can be devoted if( sd ) @@ -5741,7 +5930,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui break; } - if( (lv = status_get_lv(src) - dstsd->status.base_level) < 0 ) + if( (lv = status->get_lv(src) - dstsd->status.base_level) < 0 ) lv = -lv; if( lv > battle_config.devotion_level_difference || // Level difference requeriments (dstsd->sc.data[type] && dstsd->sc.data[type]->val1 != src->id) || // Cannot Devote a player devoted from another source @@ -5751,7 +5940,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui { if( sd ) clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - iMap->freeblock_unlock(); + map->freeblock_unlock(); return 1; } @@ -5763,10 +5952,10 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui if( i == count ) { ARR_FIND(0, count, i, sd->devotion[i] == 0 ); - if( i == count ) - { // No free slots, skill Fail + if( i == count ) { + // No free slots, skill Fail clif->skill_fail(sd, skill_id, USESKILL_FAIL_LEVEL, 0); - iMap->freeblock_unlock(); + map->freeblock_unlock(); return 1; } } @@ -5777,7 +5966,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui mer->devotion_flag = 1; // Mercenary Devoting Owner clif->skill_nodamage(src, bl, skill_id, skill_lv, - sc_start4(bl, type, 100, src->id, i, skill->get_range2(src,skill_id,skill_lv),0, skill->get_time2(skill_id, skill_lv))); + sc_start4(src, bl, type, 100, src->id, i, skill->get_range2(src,skill_id,skill_lv),0, skill->get_time2(skill_id, skill_lv))); clif->devotion(src, NULL); } break; @@ -5794,7 +5983,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case CH_SOULCOLLECT: if(sd) { - int limit = 5; + int limit = 5, i; if( sd->sc.data[SC_RAISINGDRAGON] ) limit += sd->sc.data[SC_RAISINGDRAGON]->val1; clif->skill_nodamage(src,bl,skill_id,skill_lv,1); @@ -5804,32 +5993,34 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui break; case MO_KITRANSLATION: - if(dstsd && (dstsd->class_&MAPID_BASEMASK)!=MAPID_GUNSLINGER) { + if(dstsd && ((dstsd->class_&MAPID_BASEMASK)!=MAPID_GUNSLINGER || (dstsd->class_&MAPID_UPPERMASK)!=MAPID_REBELLION)) { pc->addspiritball(dstsd,skill->get_time(skill_id,skill_lv),5); } break; case TK_TURNKICK: case MO_BALKYOUNG: //Passive part of the attack. Splash knock-back+stun. [Skotlex] - if (skill_area_temp[1] != bl->id) { + if (skill->area_temp[1] != bl->id) { skill->blown(src,bl,skill->get_blewcount(skill_id,skill_lv),-1,0); skill->additional_effect(src,bl,skill_id,skill_lv,BF_MISC,ATK_DEF,tick); //Use Misc rather than weapon to signal passive pushback } break; case MO_ABSORBSPIRITS: - i = 0; - if (dstsd && dstsd->spiritball && (sd == dstsd || map_flag_vs(src->m)) && (dstsd->class_&MAPID_BASEMASK)!=MAPID_GUNSLINGER) + { + int sp = 0; + if (dstsd && dstsd->spiritball && (sd == dstsd || map_flag_vs(src->m) || (sd->duel_group && sd->duel_group == dstsd->duel_group)) && ((dstsd->class_&MAPID_BASEMASK)!=MAPID_GUNSLINGER || (dstsd->class_&MAPID_UPPERMASK)!=MAPID_REBELLION)) { // split the if for readability, and included gunslingers in the check so that their coins cannot be removed [Reddozen] - i = dstsd->spiritball * 7; + sp = dstsd->spiritball * 7; pc->delspiritball(dstsd,dstsd->spiritball,0); } else if (dstmd && !(tstatus->mode&MD_BOSS) && rnd() % 100 < 20) { // check if target is a monster and not a Boss, for the 20% chance to absorb 2 SP per monster's level [Reddozen] - i = 2 * dstmd->level; - mob_target(dstmd,src,0); + sp = 2 * dstmd->level; + mob->target(dstmd,src,0); } - if (i) status_heal(src, 0, i, 3); - clif->skill_nodamage(src,bl,skill_id,skill_lv,i?1:0); + if (sp) status->heal(src, 0, sp, 3); + clif->skill_nodamage(src,bl,skill_id,skill_lv,sp?1:0); + } break; case AC_MAKINGARROW: @@ -5855,15 +6046,15 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case BS_HAMMERFALL: clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start(bl,SC_STUN,(20 + 10 * skill_lv),skill_lv,skill->get_time2(skill_id,skill_lv))); + sc_start(src,bl,SC_STUN,(20 + 10 * skill_lv),skill_lv,skill->get_time2(skill_id,skill_lv))); break; case RG_RAID: - skill_area_temp[1] = 0; + skill->area_temp[1] = 0; clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - iMap->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), 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); break; @@ -5876,12 +6067,15 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case SR_RAMPAGEBLASTER: case SR_HOWLINGOFLION: case KO_HAPPOKUNAI: - skill_area_temp[1] = 0; + { + int count = 0; + skill->area_temp[1] = 0; clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - i = iMap->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); - if( !i && ( skill_id == NC_AXETORNADO || skill_id == SR_SKYNETBLOW || skill_id == KO_HAPPOKUNAI ) ) + count = 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); + 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, 6); + } break; case NC_EMERGENCYCOOL: @@ -5911,36 +6105,38 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui //Passive side of the attack. status_change_end(src, SC_SIGHT, INVALID_TIMER); clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - iMap->foreachinrange(skill->area_sub,src, - skill->get_splash(skill_id, skill_lv),BL_CHAR|BL_SKILL, - src,skill_id,skill_lv,tick, flag|BCT_ENEMY|1, - skill->castend_damage_id); + map->foreachinrange(skill->area_sub,src, + skill->get_splash(skill_id, skill_lv),BL_CHAR|BL_SKILL, + src,skill_id,skill_lv,tick, flag|BCT_ENEMY|1, + skill->castend_damage_id); break; case NJ_HYOUSYOURAKU: case NJ_RAIGEKISAI: case WZ_FROSTNOVA: clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - skill_area_temp[1] = 0; - iMap->foreachinrange(skill->attack_area, src, - skill->get_splash(skill_id, skill_lv), splash_target(src), - BF_MAGIC, src, src, skill_id, skill_lv, tick, flag, BCT_ENEMY); + skill->area_temp[1] = 0; + map->foreachinrange(skill->attack_area, src, + skill->get_splash(skill_id, skill_lv), splash_target(src), + BF_MAGIC, src, src, skill_id, skill_lv, tick, flag, BCT_ENEMY); break; - case HVAN_EXPLOSION: //[orn] + case HVAN_EXPLOSION: // [orn] case NPC_SELFDESTRUCTION: + { //Self Destruction hits everyone in range (allies+enemies) //Except for Summoned Marine spheres on non-versus maps, where it's just enemy. - i = ((!md || md->special_state.ai == 2) && !map_flag_vs(src->m))? + int targetmask = ((!md || md->special_state.ai == 2) && !map_flag_vs(src->m))? BCT_ENEMY:BCT_ALL; clif->skill_nodamage(src, src, skill_id, -1, 1); - iMap->delblock(src); //Required to prevent chain-self-destructions hitting back. - iMap->foreachinrange(skill->area_sub, bl, - skill->get_splash(skill_id, skill_lv), splash_target(src), - src, skill_id, skill_lv, tick, flag|i, - skill->castend_damage_id); - iMap->addblock(src); - status_damage(src, src, sstatus->max_hp,0,0,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), + src, skill_id, skill_lv, tick, flag|targetmask, + skill->castend_damage_id); + map->addblock(src); + status->damage(src, src, sstatus->max_hp,0,0,1); + } break; case AL_ANGELUS: @@ -5952,18 +6148,18 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case CASH_ASSUMPTIO: case WM_FRIGG_SONG: if( sd == NULL || sd->status.party_id == 0 || (flag & 1) ) - clif->skill_nodamage(bl, bl, skill_id, skill_lv, sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); + clif->skill_nodamage(bl, bl, skill_id, skill_lv, sc_start(src,bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); else if( sd ) - party_foreachsamemap(skill->area_sub, sd, skill->get_splash(skill_id, skill_lv), src, skill_id, skill_lv, tick, flag|BCT_PARTY|1, skill->castend_nodamage_id); + party->foreachsamemap(skill->area_sub, sd, skill->get_splash(skill_id, skill_lv), src, skill_id, skill_lv, tick, flag|BCT_PARTY|1, skill->castend_nodamage_id); break; case MER_MAGNIFICAT: if( mer != NULL ) { - clif->skill_nodamage(bl, bl, skill_id, skill_lv, sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); + clif->skill_nodamage(bl, bl, skill_id, skill_lv, sc_start(src,bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); if( mer->master && mer->master->status.party_id != 0 && !(flag&1) ) - party_foreachsamemap(skill->area_sub, mer->master, skill->get_splash(skill_id, skill_lv), src, skill_id, skill_lv, tick, flag|BCT_PARTY|1, skill->castend_nodamage_id); + party->foreachsamemap(skill->area_sub, mer->master, skill->get_splash(skill_id, skill_lv), src, skill_id, skill_lv, tick, flag|BCT_PARTY|1, skill->castend_nodamage_id); else if( mer->master && !(flag&1) ) - clif->skill_nodamage(src, &mer->master->bl, skill_id, skill_lv, sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); + clif->skill_nodamage(src, &mer->master->bl, skill_id, skill_lv, sc_start(src,bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); } break; @@ -5973,9 +6169,9 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case BS_OVERTHRUST: if (sd == NULL || sd->status.party_id == 0 || (flag & 1)) { clif->skill_nodamage(bl,bl,skill_id,skill_lv, - sc_start2(bl,type,100,skill_lv,(src == bl)? 1:0,skill->get_time(skill_id,skill_lv))); + sc_start2(src,bl,type,100,skill_lv,(src == bl)? 1:0,skill->get_time(skill_id,skill_lv))); } else if (sd) { - party_foreachsamemap(skill->area_sub, + party->foreachsamemap(skill->area_sub, sd,skill->get_splash(skill_id, skill_lv), src,skill_id,skill_lv,tick, flag|BCT_PARTY|1, skill->castend_nodamage_id); @@ -5999,10 +6195,10 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui if( tsce ) { clif->skill_nodamage(src,bl,skill_id,skill_lv,status_change_end(bl, type, INVALID_TIMER)); - iMap->freeblock_unlock(); + map->freeblock_unlock(); return 0; } - clif->skill_nodamage(src,bl,skill_id,skill_lv,sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); + clif->skill_nodamage(src,bl,skill_id,skill_lv,sc_start(src,bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); break; case SL_KAITE: case SL_KAAHI: @@ -6010,75 +6206,80 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case SL_KAUPE: if (sd) { if (!dstsd || !( - (sd->sc.data[SC_SOULLINK] && sd->sc.data[SC_SOULLINK]->val2 == SL_SOULLINKER) || - (dstsd->class_&MAPID_UPPERMASK) == MAPID_SOUL_LINKER || - dstsd->status.char_id == sd->status.char_id || - dstsd->status.char_id == sd->status.partner_id || - dstsd->status.char_id == sd->status.child - )) { - status_change_start(src,SC_STUN,10000,skill_lv,0,0,0,500,8); + (sd->sc.data[SC_SOULLINK] && sd->sc.data[SC_SOULLINK]->val2 == SL_SOULLINKER) + || (dstsd->class_&MAPID_UPPERMASK) == MAPID_SOUL_LINKER + || dstsd->status.char_id == sd->status.char_id + || dstsd->status.char_id == sd->status.partner_id + || dstsd->status.char_id == sd->status.child + ) + ) { + status->change_start(src,src,SC_STUN,10000,skill_lv,0,0,0,500,8); clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); break; } } clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start(bl,type,100,skill_lv,skill->get_time(skill_id, skill_lv))); + sc_start(src,bl,type,100,skill_lv,skill->get_time(skill_id, skill_lv))); break; case SM_AUTOBERSERK: case MER_AUTOBERSERK: + { + int failure; if( tsce ) - i = status_change_end(bl, type, INVALID_TIMER); + failure = status_change_end(bl, type, INVALID_TIMER); else - i = sc_start(bl,type,100,skill_lv,60000); - clif->skill_nodamage(src,bl,skill_id,skill_lv,i); + failure = sc_start(src,bl,type,100,skill_lv,60000); + clif->skill_nodamage(src,bl,skill_id,skill_lv,failure); + } break; case TF_HIDING: case ST_CHASEWALK: case KO_YAMIKUMO: - if (tsce) - { + if (tsce) { clif->skill_nodamage(src,bl,skill_id,-1,status_change_end(bl, type, INVALID_TIMER)); //Hide skill-scream animation. - iMap->freeblock_unlock(); + map->freeblock_unlock(); return 0; } else if( tsc && tsc->option&OPTION_MADOGEAR ) { //Mado Gear cannot hide if( sd ) clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - iMap->freeblock_unlock(); + map->freeblock_unlock(); return 0; } - clif->skill_nodamage(src,bl,skill_id,-1,sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); + clif->skill_nodamage(src,bl,skill_id,-1,sc_start(src,bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); break; case TK_RUN: - if (tsce) - { + if (tsce) { clif->skill_nodamage(src,bl,skill_id,skill_lv,status_change_end(bl, type, INVALID_TIMER)); - iMap->freeblock_unlock(); + map->freeblock_unlock(); return 0; } - clif->skill_nodamage(src,bl,skill_id,skill_lv,sc_start4(bl,type,100,skill_lv,unit_getdir(bl),0,0,0)); - if (sd) // If the client receives a skill-use packet inmediately before a walkok packet, it will discard the walk packet! [Skotlex] + clif->skill_nodamage(src,bl,skill_id,skill_lv,sc_start4(src,bl,type,100,skill_lv,unit->getdir(bl),0,0,0)); + if (sd) // If the client receives a skill-use packet immediately before a walkok packet, it will discard the walk packet! [Skotlex] clif->walkok(sd); // So aegis has to resend the walk ok. break; case AS_CLOAKING: case GC_CLOAKINGEXCEED: case LG_FORCEOFVANGUARD: case SC_REPRODUCE: - case SC_INVISIBILITY: if (tsce) { - i = status_change_end(bl, type, INVALID_TIMER); - if( i ) - clif->skill_nodamage(src,bl,skill_id,( skill_id == LG_FORCEOFVANGUARD ) ? skill_lv : -1,i); + int failure = status_change_end(bl, type, INVALID_TIMER); + if( failure ) + clif->skill_nodamage(src,bl,skill_id,( skill_id == LG_FORCEOFVANGUARD ) ? skill_lv : -1,failure); else if( sd ) clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - iMap->freeblock_unlock(); + if ( skill_id == LG_FORCEOFVANGUARD ) + break; + map->freeblock_unlock(); return 0; } case RA_CAMOUFLAGE: - i = sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv)); - if( i ) - clif->skill_nodamage(src,bl,skill_id,( skill_id == LG_FORCEOFVANGUARD ) ? skill_lv : -1,i); + { + int failure = sc_start(src,bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv)); + if( failure ) + clif->skill_nodamage(src,bl,skill_id,( skill_id == LG_FORCEOFVANGUARD ) ? skill_lv : -1,failure); else if( sd ) clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + } break; case BD_ADAPTATION: @@ -6097,27 +6298,25 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui // custom hack to make the mob display the skill, because these skills don't show the skill use text themselves //NOTE: mobs don't have the sprite animation that is used when performing this skill (will cause glitches) char temp[70]; - snprintf(temp, sizeof(temp), "%s : %s !!",md->name,skill_db[skill_id].desc); + snprintf(temp, sizeof(temp), "%s : %s !!",md->name,skill->db[skill_id].desc); clif->disp_overhead(&md->bl,temp); } break; case BA_PANGVOICE: - clif->skill_nodamage(src,bl,skill_id,skill_lv, sc_start(bl,SC_CONFUSION,50,7,skill->get_time(skill_id,skill_lv))); + clif->skill_nodamage(src,bl,skill_id,skill_lv, sc_start(src,bl,SC_CONFUSION,50,7,skill->get_time(skill_id,skill_lv))); break; case DC_WINKCHARM: if( dstsd ) - clif->skill_nodamage(src,bl,skill_id,skill_lv, sc_start(bl,SC_CONFUSION,30,7,skill->get_time2(skill_id,skill_lv))); - else - if( dstmd ) - { - if( status_get_lv(src) > status_get_lv(bl) - && (tstatus->race == RC_DEMON || tstatus->race == RC_DEMIHUMAN || tstatus->race == RC_ANGEL) - && !(tstatus->mode&MD_BOSS) ) - clif->skill_nodamage(src,bl,skill_id,skill_lv, sc_start2(bl,type,70,skill_lv,src->id,skill->get_time(skill_id,skill_lv))); - else - { + clif->skill_nodamage(src,bl,skill_id,skill_lv, sc_start(src,bl,SC_CONFUSION,30,7,skill->get_time2(skill_id,skill_lv))); + else if( dstmd ) { + if( status->get_lv(src) > status->get_lv(bl) + && (tstatus->race == RC_DEMON || tstatus->race == RC_DEMIHUMAN || tstatus->race == RC_ANGEL) + && !(tstatus->mode&MD_BOSS) + ) { + clif->skill_nodamage(src,bl,skill_id,skill_lv, sc_start2(src,bl,type,70,skill_lv,src->id,skill->get_time(skill_id,skill_lv))); + } else { clif->skill_nodamage(src,bl,skill_id,skill_lv,0); if(sd) clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); } @@ -6135,15 +6334,14 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case RG_STEALCOIN: if(sd) { - if(pc->steal_coin(sd,bl)) - { + int amount = pc->steal_coin(sd, bl); + if( amount > 0 ) { dstmd->state.provoke_flag = src->id; - mob_target(dstmd, src, skill->get_range2(src,skill_id,skill_lv)); - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + mob->target(dstmd, src, skill->get_range2(src, skill_id, skill_lv)); + clif->skill_nodamage(src, bl, skill_id, amount, 1); - } - else - clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + } else + clif->skill_fail(sd, skill_id, USESKILL_FAIL_LEVEL, 0); } break; @@ -6154,7 +6352,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui if (sd) clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); break; } - if(status_isimmune(bl) || !tsc) + if(status->isimmune(bl) || !tsc) break; if (sd && sd->sc.data[SC_PETROLOGY_OPTION]) @@ -6165,16 +6363,16 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui if (sd) clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); break; } - if (sc_start4(bl,SC_STONE,(skill_lv*4+20)+brate, + if (sc_start4(src,bl,SC_STONE,(skill_lv*4+20)+brate, skill_lv, 0, 0, skill->get_time(skill_id, skill_lv), skill->get_time2(skill_id,skill_lv))) clif->skill_nodamage(src,bl,skill_id,skill_lv,1); else if(sd) { clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); // Level 6-10 doesn't consume a red gem if it fails [celest] - if (skill_lv > 5) - { // not to consume items - iMap->freeblock_unlock(); + if (skill_lv > 5) { + // not to consume items + map->freeblock_unlock(); return 0; } } @@ -6183,11 +6381,11 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case NV_FIRSTAID: clif->skill_nodamage(src,bl,skill_id,5,1); - status_heal(bl,5,0,0); + status->heal(bl,5,0,0); break; case AL_CURE: - if(status_isimmune(bl)) { + if(status->isimmune(bl)) { clif->skill_nodamage(src,bl,skill_id,skill_lv,0); break; } @@ -6204,7 +6402,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui break; case PR_STRECOVERY: - if(status_isimmune(bl)) { + if(status->isimmune(bl)) { clif->skill_nodamage(src,bl,skill_id,skill_lv,0); break; } @@ -6217,14 +6415,13 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui } //Is this equation really right? It looks so... special. if( battle->check_undead(tstatus->race,tstatus->def_ele) ) { - status_change_start(bl, SC_BLIND, - 100*(100-(tstatus->int_/2+tstatus->vit/3+tstatus->luk/10)), - 1,0,0,0, - skill->get_time2(skill_id, skill_lv) * (100-(tstatus->int_+tstatus->vit)/2)/100,0); + status->change_start(src, bl, SC_BLIND, + 100*(100-(tstatus->int_/2+tstatus->vit/3+tstatus->luk/10)), 1,0,0,0, + skill->get_time2(skill_id, skill_lv) * (100-(tstatus->int_+tstatus->vit)/2)/100,0); } clif->skill_nodamage(src,bl,skill_id,skill_lv,1); if(dstmd) - mob_unlocktarget(dstmd,tick); + mob->unlocktarget(dstmd,tick); break; // Mercenary Supportive Skills @@ -6258,10 +6455,9 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui break; case MER_SCAPEGOAT: - if( mer && mer->master ) - { - status_heal(&mer->master->bl, mer->battle_status.hp, 0, 2); - status_damage(src, src, mer->battle_status.max_hp, 0, 0, 1); + if( mer && mer->master ) { + status->heal(&mer->master->bl, mer->battle_status.hp, 0, 2); + status->damage(src, src, mer->battle_status.max_hp, 0, 0, 1); } break; @@ -6294,11 +6490,11 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case MC_IDENTIFY: if(sd) { clif->item_identify_list(sd); - if( sd->menuskill_id != MC_IDENTIFY ) {/* failed, dont consume anything, return */ - iMap->freeblock_unlock(); + if( sd->menuskill_id != MC_IDENTIFY ) {/* failed, don't consume anything, return */ + map->freeblock_unlock(); return 1; } - status_zap(src,0,skill_db[skill->get_index(skill_id)].sp[skill_lv]); // consume sp only if succeeded + status_zap(src,0,skill->db[skill->get_index(skill_id)].sp[skill_lv]); // consume sp only if succeeded } break; @@ -6313,7 +6509,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case MC_VENDING: if(sd) { //Prevent vending of GMs with unnecessary Level to trade/drop. [Skotlex] - if ( !pc->can_give_items(sd) ) + if ( !pc_can_give_items(sd) ) clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); else { sd->state.prevend = sd->state.workinprogress = 3; @@ -6323,9 +6519,8 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui break; case AL_TELEPORT: - if(sd) - { - if (map[bl->m].flag.noteleport && skill_lv <= 2) { + if(sd) { + if (map->list[bl->m].flag.noteleport && skill_lv <= 2) { clif->skill_mapinfomessage(sd,0); break; } @@ -6350,12 +6545,12 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui else clif->skill_warppoint(sd,skill_id,skill_lv, (unsigned short)-1,sd->status.save_point.map,0,0); } else - unit_warp(bl,-1,-1,-1,CLR_TELEPORT); + unit->warp(bl,-1,-1,-1,CLR_TELEPORT); break; case NPC_EXPULSION: clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - unit_warp(bl,-1,-1,-1,CLR_TELEPORT); + unit->warp(bl,-1,-1,-1,CLR_TELEPORT); break; case AL_HOLYWATER: @@ -6382,7 +6577,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui eflag = pc->additem(sd,&item_tmp,1,LOG_TYPE_PRODUCE); if(eflag) { clif->additem(sd,0,0,eflag); - iMap->addflooritem(&item_tmp,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0); + map->addflooritem(&item_tmp,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0); } } break; @@ -6401,18 +6596,18 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case GC_WEAPONCRUSH: case SC_STRIPACCESSARY: { unsigned short location = 0; - int d = 0; + int d = 0, rate; //Rate in percent if ( skill_id == ST_FULLSTRIP ) { - i = 5 + 2*skill_lv + (sstatus->dex - tstatus->dex)/5; + rate = 5 + 2*skill_lv + (sstatus->dex - tstatus->dex)/5; } else if( skill_id == SC_STRIPACCESSARY ) { - i = 12 + 2 * skill_lv + (sstatus->dex - tstatus->dex)/5; + rate = 12 + 2 * skill_lv + (sstatus->dex - tstatus->dex)/5; } else { - i = 5 + 5*skill_lv + (sstatus->dex - tstatus->dex)/5; + rate = 5 + 5*skill_lv + (sstatus->dex - tstatus->dex)/5; } - if (i < 5) i = 5; //Minimum rate 5% + if (rate < 5) rate = 5; //Minimum rate 5% //Duration in ms if( skill_id == GC_WEAPONCRUSH){ @@ -6456,78 +6651,82 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui } //Attempts to strip at rate i and duration d - if( (i = skill->strip_equip(bl, location, i, skill_lv, d)) || (skill_id != ST_FULLSTRIP && skill_id != GC_WEAPONCRUSH ) ) - clif->skill_nodamage(src,bl,skill_id,skill_lv,i); + if( (rate = skill->strip_equip(bl, location, rate, skill_lv, d)) || (skill_id != ST_FULLSTRIP && skill_id != GC_WEAPONCRUSH ) ) + clif->skill_nodamage(src,bl,skill_id,skill_lv,rate); //Nothing stripped. - if( sd && !i ) + if( sd && !rate ) clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); break; } case AM_BERSERKPITCHER: - case AM_POTIONPITCHER: { + case AM_POTIONPITCHER: + { int i,sp = 0; int64 hp = 0; if( dstmd && dstmd->class_ == MOBID_EMPERIUM ) { - iMap->freeblock_unlock(); + map->freeblock_unlock(); return 1; } if( sd ) { - int x,bonus=100; + int x,bonus=100, potion = min(500+skill_lv,505); x = skill_lv%11 - 1; - i = pc->search_inventory(sd,skill_db[skill_id].itemid[x]); - if( i < 0 || skill_db[skill_id].itemid[x] <= 0 ) { + i = pc->search_inventory(sd,skill->db[skill_id].itemid[x]); + if (i == INDEX_NOT_FOUND || skill->db[skill_id].itemid[x] <= 0) { clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - iMap->freeblock_unlock(); + map->freeblock_unlock(); return 1; } - if(sd->inventory_data[i] == NULL || sd->status.inventory[i].amount < skill_db[skill_id].amount[x]) { + if(sd->inventory_data[i] == NULL || sd->status.inventory[i].amount < skill->db[skill_id].amount[x]) { clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - iMap->freeblock_unlock(); + map->freeblock_unlock(); return 1; } if( skill_id == AM_BERSERKPITCHER ) { if( dstsd && dstsd->status.base_level < (unsigned int)sd->inventory_data[i]->elv ) { clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - iMap->freeblock_unlock(); + map->freeblock_unlock(); return 1; } } - potion_flag = 1; - potion_hp = potion_sp = potion_per_hp = potion_per_sp = 0; - potion_target = bl->id; - run_script(sd->inventory_data[i]->script,0,sd->bl.id,0); - potion_flag = potion_target = 0; + script->potion_flag = 1; + script->potion_hp = script->potion_sp = script->potion_per_hp = script->potion_per_sp = 0; + script->potion_target = bl->id; + script->run(sd->inventory_data[i]->script,0,sd->bl.id,0); + script->potion_flag = script->potion_target = 0; if( sd->sc.data[SC_SOULLINK] && sd->sc.data[SC_SOULLINK]->val2 == SL_ALCHEMIST ) bonus += sd->status.base_level; - if( potion_per_hp > 0 || potion_per_sp > 0 ) { - hp = tstatus->max_hp * potion_per_hp / 100; + if( script->potion_per_hp > 0 || script->potion_per_sp > 0 ) { + hp = tstatus->max_hp * script->potion_per_hp / 100; hp = hp * (100 + pc->checkskill(sd,AM_POTIONPITCHER)*10 + pc->checkskill(sd,AM_LEARNINGPOTION)*5)*bonus/10000; if( dstsd ) { - sp = dstsd->status.max_sp * potion_per_sp / 100; + sp = dstsd->status.max_sp * script->potion_per_sp / 100; sp = sp * (100 + pc->checkskill(sd,AM_POTIONPITCHER)*10 + pc->checkskill(sd,AM_LEARNINGPOTION)*5)*bonus/10000; } } else { - if( potion_hp > 0 ) { - hp = potion_hp * (100 + pc->checkskill(sd,AM_POTIONPITCHER)*10 + pc->checkskill(sd,AM_LEARNINGPOTION)*5)*bonus/10000; + if( script->potion_hp > 0 ) { + hp = script->potion_hp * (100 + pc->checkskill(sd,AM_POTIONPITCHER)*10 + pc->checkskill(sd,AM_LEARNINGPOTION)*5)*bonus/10000; hp = hp * (100 + (tstatus->vit<<1)) / 100; if( dstsd ) hp = hp * (100 + pc->checkskill(dstsd,SM_RECOVERY)*10) / 100; } - if( potion_sp > 0 ) { - sp = potion_sp * (100 + pc->checkskill(sd,AM_POTIONPITCHER)*10 + pc->checkskill(sd,AM_LEARNINGPOTION)*5)*bonus/10000; + if( script->potion_sp > 0 ) { + sp = script->potion_sp * (100 + pc->checkskill(sd,AM_POTIONPITCHER)*10 + pc->checkskill(sd,AM_LEARNINGPOTION)*5)*bonus/10000; sp = sp * (100 + (tstatus->int_<<1)) / 100; if( dstsd ) sp = sp * (100 + pc->checkskill(dstsd,MG_SRECOVERY)*10) / 100; } } - if (sd->itemgrouphealrate[IG_POTION]>0) { - hp += hp * sd->itemgrouphealrate[IG_POTION] / 100; - sp += sp * sd->itemgrouphealrate[IG_POTION] / 100; + for(i = 0; i < ARRAYLENGTH(sd->itemhealrate) && sd->itemhealrate[i].nameid; i++) { + if (sd->itemhealrate[i].nameid == potion) { + hp += hp * sd->itemhealrate[i].rate / 100; + sp += sp * sd->itemhealrate[i].rate / 100; + break; + } } - + if( (i = pc->skillheal_bonus(sd, skill_id)) ) { hp += hp * i / 100; sp += sp * i / 100; @@ -6565,31 +6764,53 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui if( tsc && tsc->data[SC_EXTREMITYFIST2] ) sp = 0; #endif - status_heal(bl,(int)hp,sp,0); + status->heal(bl,(int)hp,sp,0); } break; case AM_CP_WEAPON: - case AM_CP_SHIELD: - case AM_CP_ARMOR: - case AM_CP_HELM: - { - unsigned int equip[] = {EQP_WEAPON, EQP_SHIELD, EQP_ARMOR, EQP_HEAD_TOP}; - - if( sd && ( bl->type != BL_PC || ( dstsd && pc->checkequip(dstsd,equip[skill_id - AM_CP_WEAPON]) < 0 ) ) ){ + if(dstsd && dstsd->inventory_data[dstsd->equip_index[EQI_HAND_R]]) + clif->skill_nodamage(src,bl,skill_id,skill_lv, + sc_start(src,bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); + else { + clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + return 0; + } + break; + case AM_CP_SHIELD: { + int i; + if(dstsd && (i=dstsd->equip_index[EQI_HAND_L])>=0 && dstsd->inventory_data[i] && + dstsd->inventory_data[i]->type==IT_ARMOR) + clif->skill_nodamage(src,bl,skill_id,skill_lv, + sc_start(src,bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); + else { clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - iMap->freeblock_unlock(); // Don't consume item requirements return 0; } - + } + break; + case AM_CP_ARMOR: + if(dstsd && dstsd->inventory_data[dstsd->equip_index[EQI_ARMOR]]) + clif->skill_nodamage(src,bl,skill_id,skill_lv, + sc_start(src,bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); + else { + clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + return 0; + } + break; + case AM_CP_HELM: + if(dstsd && dstsd->inventory_data[dstsd->equip_index[EQI_HEAD_TOP]]) clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); + sc_start(src,bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); + else { + clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + return 0; } break; case AM_TWILIGHT1: if (sd) { clif->skill_nodamage(src,bl,skill_id,skill_lv,1); //Prepare 200 White Potions. - if (!skill->produce_mix(sd, skill_id, 504, 0, 0, 0, 200)) + if (!skill->produce_mix(sd, skill_id, ITEMID_WHITE_POTION, 0, 0, 0, 200)) clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); } break; @@ -6597,56 +6818,57 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui if (sd) { clif->skill_nodamage(src,bl,skill_id,skill_lv,1); //Prepare 200 Slim White Potions. - if (!skill->produce_mix(sd, skill_id, 547, 0, 0, 0, 200)) + if (!skill->produce_mix(sd, skill_id, ITEMID_WHITE_SLIM_POTION, 0, 0, 0, 200)) clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); } break; case AM_TWILIGHT3: if (sd) { - int ebottle = pc->search_inventory(sd,713); - if( ebottle >= 0 ) + int ebottle = pc->search_inventory(sd,ITEMID_EMPTY_BOTTLE); + if (ebottle != INDEX_NOT_FOUND) ebottle = sd->status.inventory[ebottle].amount; //check if you can produce all three, if not, then fail: - if (!skill->can_produce_mix(sd,970,-1, 100) //100 Alcohol - || !skill->can_produce_mix(sd,7136,-1, 50) //50 Acid Bottle - || !skill->can_produce_mix(sd,7135,-1, 50) //50 Flame Bottle + if (!skill->can_produce_mix(sd,ITEMID_ALCHOL,-1, 100) //100 Alcohol + || !skill->can_produce_mix(sd,ITEMID_ACID_BOTTLE,-1, 50) //50 Acid Bottle + || !skill->can_produce_mix(sd,ITEMID_FIRE_BOTTLE,-1, 50) //50 Flame Bottle || ebottle < 200 //200 empty bottle are required at total. ) { clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); break; } clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - skill->produce_mix(sd, skill_id, 970, 0, 0, 0, 100); - skill->produce_mix(sd, skill_id, 7136, 0, 0, 0, 50); - skill->produce_mix(sd, skill_id, 7135, 0, 0, 0, 50); + skill->produce_mix(sd, skill_id, ITEMID_ALCHOL, 0, 0, 0, 100); + skill->produce_mix(sd, skill_id, ITEMID_ACID_BOTTLE, 0, 0, 0, 50); + skill->produce_mix(sd, skill_id, ITEMID_FIRE_BOTTLE, 0, 0, 0, 50); } break; case SA_DISPELL: - if (flag&1 || (i = skill->get_splash(skill_id, skill_lv)) < 1) - { + { + int splash; + if (flag&1 || (splash = skill->get_splash(skill_id, skill_lv)) < 1) { + int i; + if( sd && dstsd && !map_flag_vs(sd->bl.m) + && (sd->status.party_id == 0 || sd->status.party_id != dstsd->status.party_id) ) { + // Outside PvP it should only affect party members and no skill fail message. + break; + } clif->skill_nodamage(src,bl,skill_id,skill_lv,1); if((dstsd && (dstsd->class_&MAPID_UPPERMASK) == MAPID_SOUL_LINKER) - || (tsc && tsc->data[SC_SOULLINK] && tsc->data[SC_SOULLINK]->val2 == SL_ROGUE) //Rogue's spirit defends againt dispel. + || (tsc && tsc->data[SC_SOULLINK] && tsc->data[SC_SOULLINK]->val2 == SL_ROGUE) //Rogue's spirit defends against dispel. + || (dstsd && pc_ismadogear(dstsd)) || rnd()%100 >= 50+10*skill_lv ) { if (sd) clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); break; } - if(status_isimmune(bl) || !tsc || !tsc->count) - break; - - if( sd && dstsd && !map_flag_vs(sd->bl.m) && sd->status.guild_id == dstsd->status.guild_id ) { - clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + if(status->isimmune(bl) || !tsc || !tsc->count) break; - } - - for(i = 0; i < SC_MAX; i++) - { + for(i = 0; i < SC_MAX; i++) { if ( !tsc->data[i] ) continue; - if( SC_COMMON_MAX < i ){ - if ( status_get_sc_type(i)&SC_NO_DISPELL ) + if( SC_COMMON_MAX < i ) { + if ( status->get_sc_type(i)&SC_NO_DISPELL ) continue; } switch (i) { @@ -6676,25 +6898,28 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui status_change_end(bl, (sc_type)i, INVALID_TIMER); } break; + } else { + //Affect all targets on splash area. + map->foreachinrange(skill->area_sub, bl, splash, BL_CHAR, + src, skill_id, skill_lv, tick, flag|1, + skill->castend_damage_id); } - //Affect all targets on splash area. - iMap->foreachinrange(skill->area_sub, bl, i, BL_CHAR, - src, skill_id, skill_lv, tick, flag|1, - skill->castend_damage_id); + } break; case TF_BACKSLIDING: //This is the correct implementation as per packet logging information. [Skotlex] clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - skill->blown(src,bl,skill->get_blewcount(skill_id,skill_lv),unit_getdir(bl),0); + skill->blown(src,bl,skill->get_blewcount(skill_id,skill_lv),unit->getdir(bl),0); + clif->fixpos(bl); break; case TK_HIGHJUMP: { - int x,y, dir = unit_getdir(src); + int x,y, dir = unit->getdir(src); //Fails on noteleport maps, except for GvG and BG maps [Skotlex] - if( map[src->m].flag.noteleport && - !(map[src->m].flag.battleground || map_flag_gvg2(src->m) ) + if( map->list[src->m].flag.noteleport + && !(map->list[src->m].flag.battleground || map_flag_gvg2(src->m)) ) { x = src->x; y = src->y; @@ -6704,9 +6929,9 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui } clif->skill_nodamage(src,bl,TK_HIGHJUMP,skill_lv,1); - if(!iMap->count_oncell(src->m,x,y,BL_PC|BL_NPC|BL_MOB) && iMap->getcell(src->m,x,y,CELL_CHKREACH)) { + if(!map->count_oncell(src->m,x,y,BL_PC|BL_NPC|BL_MOB) && map->getcell(src->m,x,y,CELL_CHKREACH)) { clif->slide(src,x,y); - unit_movepos(src, x, y, 1, 0); + unit->movepos(src, x, y, 1, 0); } } break; @@ -6714,11 +6939,11 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case SA_CASTCANCEL: case SO_SPELLFIST: clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - unit_skillcastcancel(src,1); + unit->skillcastcancel(src,1); if(sd) { int sp = skill->get_sp(sd->skill_id_old,sd->skill_lv_old); if( skill_id == SO_SPELLFIST ){ - sc_start4(src,type,100,skill_lv+1,skill_lv,sd->skill_id_old,sd->skill_lv_old,skill->get_time(skill_id,skill_lv)); + sc_start4(src,src,type,100,skill_lv+1,skill_lv,sd->skill_id_old,sd->skill_lv_old,skill->get_time(skill_id,skill_lv)); sd->skill_id_old = sd->skill_lv_old = 0; break; } @@ -6734,10 +6959,10 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui sp = skill->get_sp(skill_id,skill_lv); sp = sp * tsc->data[SC_MAGICROD]->val2 / 100; if(sp < 1) sp = 1; - status_heal(bl,0,sp,2); + status->heal(bl,0,sp,2); status_percent_damage(bl, src, 0, -20, false); //20% max SP damage. } else { - struct unit_data *ud = unit_bl2ud(bl); + struct unit_data *ud = unit->bl2ud(bl); int bl_skill_id=0,bl_skill_lv=0,hp = 0; if (!ud || ud->skilltimer == INVALID_TIMER) break; //Nothing to cancel. @@ -6754,7 +6979,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui hp = tstatus->max_hp/50; //Recover 2% HP [Skotlex] clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - unit_skillcastcancel(bl,0); + unit->skillcastcancel(bl,0); sp = skill->get_sp(bl_skill_id,bl_skill_lv); status_zap(bl, hp, sp); @@ -6767,19 +6992,20 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui sp = sp*(25*(skill_lv-1))/100; if(hp || sp) - status_heal(src, hp, sp, 2); + status->heal(src, hp, sp, 2); } } break; case SA_MAGICROD: clif->skill_nodamage(src,src,SA_MAGICROD,skill_lv,1); - sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv)); + sc_start(src,bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv)); break; case SA_AUTOSPELL: clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - if(sd) + if(sd){ + sd->state.workinprogress = 3; clif->autospell(sd,skill_lv); - else { + }else { int maxlv=1,spellid=0; static const int spellarray[3] = { MG_COLDBOLT,MG_FIREBOLT,MG_LIGHTNINGBOLT }; if(skill_lv >= 10) { @@ -6807,7 +7033,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui maxlv = 3; } if(spellid > 0) - sc_start4(src,SC_AUTOSPELL,100,skill_lv,spellid,maxlv,0, + sc_start4(src,src,SC_AUTOSPELL,100,skill_lv,spellid,maxlv,0, skill->get_time(SA_AUTOSPELL,skill_lv)); } break; @@ -6815,8 +7041,8 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case BS_GREED: if(sd){ clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - iMap->foreachinrange(skill->greed,bl, - skill->get_splash(skill_id, skill_lv),BL_ITEM,bl); + map->foreachinrange(skill->greed,bl, + skill->get_splash(skill_id, skill_lv),BL_ITEM,bl); } break; @@ -6838,7 +7064,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case NPC_CHANGEDARKNESS: case NPC_CHANGETELEKINESIS: clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start2(bl, type, 100, skill_lv, skill->get_ele(skill_id,skill_lv), + sc_start2(src, bl, type, 100, skill_lv, skill->get_ele(skill_id,skill_lv), skill->get_time(skill_id, skill_lv))); break; case NPC_CHANGEUNDEAD: @@ -6846,22 +7072,22 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui //TO-DO This is ugly, fix it if(tstatus->def_ele==ELE_UNDEAD || tstatus->def_ele==ELE_DARK) break; clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start2(bl, type, 100, skill_lv, skill->get_ele(skill_id,skill_lv), + sc_start2(src, bl, type, 100, skill_lv, skill->get_ele(skill_id,skill_lv), skill->get_time(skill_id, skill_lv))); break; case NPC_PROVOCATION: clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - if (md) mob_unlocktarget(md, tick); + if (md) mob->unlocktarget(md, tick); break; case NPC_KEEPING: case NPC_BARRIER: { int skill_time = skill->get_time(skill_id,skill_lv); - struct unit_data *ud = unit_bl2ud(bl); + struct unit_data *ud = unit->bl2ud(bl); if (clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start(bl,type,100,skill_lv,skill_time)) + sc_start(src,bl,type,100,skill_lv,skill_time)) && ud) { //Disable attacking/acting/moving for skill's duration. ud->attackabletime = ud->canact_tick = @@ -6873,18 +7099,18 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case NPC_REBIRTH: if( md && md->state.rebirth ) break; // only works once - sc_start(bl,type,100,skill_lv,-1); + sc_start(src,bl,type,100,skill_lv,-1); break; case NPC_DARKBLESSING: clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start2(bl,type,(50+skill_lv*5),skill_lv,skill_lv,skill->get_time2(skill_id,skill_lv))); + sc_start2(src,bl,type,(50+skill_lv*5),skill_lv,skill_lv,skill->get_time2(skill_id,skill_lv))); break; case NPC_LICK: status_zap(bl, 0, 100); clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start(bl,type,(skill_lv*5),skill_lv,skill->get_time2(skill_id,skill_lv))); + sc_start(src,bl,type,(skill_lv*5),skill_lv,skill->get_time2(skill_id,skill_lv))); break; case NPC_SUICIDE: @@ -6895,17 +7121,17 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case NPC_SUMMONSLAVE: case NPC_SUMMONMONSTER: if(md && md->skill_idx >= 0) - mob_summonslave(md,md->db->skill[md->skill_idx].val,skill_lv,skill_id); + mob->summonslave(md,md->db->skill[md->skill_idx].val,skill_lv,skill_id); break; case NPC_CALLSLAVE: - mob_warpslave(src,MOB_SLAVEDISTANCE); + mob->warpslave(src,MOB_SLAVEDISTANCE); break; case NPC_RANDOMMOVE: if (md) { md->next_walktime = tick - 1; - mob_randomwalk(md,tick); + mob->randomwalk(md,tick); } break; @@ -6916,7 +7142,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui if (i > SC_ATTHASTE_INFINITY) i = SC_ATTHASTE_INFINITY; clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start(bl,(sc_type)i,100,skill_lv,skill_lv * 60000)); + sc_start(src,bl,(sc_type)i,100,skill_lv,skill_lv * 60000)); } break; @@ -6924,32 +7150,32 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui // not really needed... but adding here anyway ^^ if (md && md->master_id > 0) { struct block_list *mbl, *tbl; - if ((mbl = iMap->id2bl(md->master_id)) == NULL || + if ((mbl = map->id2bl(md->master_id)) == NULL || (tbl = battle->get_targeted(mbl)) == NULL) break; md->state.provoke_flag = tbl->id; - mob_target(md, tbl, sstatus->rhw.range); + mob->target(md, tbl, sstatus->rhw.range); } break; case NPC_RUN: { const int mask[8][2] = {{0,-1},{1,-1},{1,0},{1,1},{0,1},{-1,1},{-1,0},{-1,-1}}; - uint8 dir = (bl == src)?unit_getdir(src):iMap->calc_dir(src,bl->x,bl->y); //If cast on self, run forward, else run away. - unit_stop_attack(src); + uint8 dir = (bl == src)?unit->getdir(src):map->calc_dir(src,bl->x,bl->y); //If cast on self, run forward, else run away. + unit->stop_attack(src); //Run skillv tiles overriding the can-move check. - if (unit_walktoxy(src, src->x + skill_lv * mask[dir][0], src->y + skill_lv * mask[dir][1], 2) && md) - md->state.skillstate = MSS_WALK; //Otherwise it isn't updated in the ai. + if (unit->walktoxy(src, src->x + skill_lv * mask[dir][0], src->y + skill_lv * mask[dir][1], 2) && md) + md->state.skillstate = MSS_WALK; //Otherwise it isn't updated in the AI. } break; case NPC_TRANSFORMATION: case NPC_METAMORPHOSIS: if(md && md->skill_idx >= 0) { - int class_ = mob_random_class (md->db->skill[md->skill_idx].val,0); + int class_ = mob->random_class (md->db->skill[md->skill_idx].val,0); if (skill_lv > 1) //Multiply the rest of mobs. [Skotlex] - mob_summonslave(md,md->db->skill[md->skill_idx].val,skill_lv-1,skill_id); - if (class_) mob_class_change(md, class_); + mob->summonslave(md,md->db->skill[md->skill_idx].val,skill_lv-1,skill_id); + if (class_) mob->class_change(md, class_); } break; @@ -6968,10 +7194,10 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui //If mode gets set by NPC_EMOTION then the target should be reset [Playtester] if(skill_id == NPC_EMOTION && md->db->skill[md->skill_idx].val[1]) - mob_unlocktarget(md,tick); + mob->unlocktarget(md,tick); if(md->db->skill[md->skill_idx].val[1] || md->db->skill[md->skill_idx].val[2]) - sc_start4(src, type, 100, skill_lv, + sc_start4(src, src, type, 100, skill_lv, md->db->skill[md->skill_idx].val[1], md->db->skill[md->skill_idx].val[2], md->db->skill[md->skill_idx].val[3], @@ -6980,21 +7206,21 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui break; case NPC_POWERUP: - sc_start(bl,SC_INCATKRATE,100,200,skill->get_time(skill_id, skill_lv)); + sc_start(src,bl,SC_INCATKRATE,100,200,skill->get_time(skill_id, skill_lv)); clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start(bl,type,100,100,skill->get_time(skill_id, skill_lv))); + sc_start(src,bl,type,100,100,skill->get_time(skill_id, skill_lv))); break; case NPC_AGIUP: - sc_start(bl,SC_MOVHASTE_INFINITY,100,skill_lv,skill->get_time(skill_id, skill_lv)); + sc_start(src,bl,SC_MOVHASTE_INFINITY,100,skill_lv,skill->get_time(skill_id, skill_lv)); clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start(bl,type,100,100,skill->get_time(skill_id, skill_lv))); + sc_start(src,bl,type,100,100,skill->get_time(skill_id, skill_lv))); break; case NPC_INVISIBLE: //Have val4 passed as 6 is for "infinite cloak" (do not end on attack/skill use). clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start4(bl,type,100,skill_lv,0,0,6,skill->get_time(skill_id,skill_lv))); + sc_start4(src,bl,type,100,skill_lv,0,0,6,skill->get_time(skill_id,skill_lv))); break; case NPC_SIEGEMODE: @@ -7003,49 +7229,58 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui break; case WE_MALE: - { - int hp_rate=(!skill_lv)? 0:skill_db[skill_id].hp_rate[skill_lv-1]; - int gain_hp= tstatus->max_hp*abs(hp_rate)/100; // The earned is the same % of the target HP than it costed the caster. [Skotlex] - clif->skill_nodamage(src,bl,skill_id,status_heal(bl, gain_hp, 0, 0),1); - } + { + int hp_rate = (!skill_lv)? 0:skill->db[skill_id].hp_rate[skill_lv-1]; + int gain_hp = tstatus->max_hp*abs(hp_rate)/100; // The earned is the same % of the target HP than it cost the caster. [Skotlex] + clif->skill_nodamage(src,bl,skill_id,status->heal(bl, gain_hp, 0, 0),1); + } break; case WE_FEMALE: - { - int sp_rate=(!skill_lv)? 0:skill_db[skill_id].sp_rate[skill_lv-1]; - int gain_sp=tstatus->max_sp*abs(sp_rate)/100;// The earned is the same % of the target SP than it costed the caster. [Skotlex] - clif->skill_nodamage(src,bl,skill_id,status_heal(bl, 0, gain_sp, 0),1); - } + { + int sp_rate = (!skill_lv)? 0:skill->db[skill_id].sp_rate[skill_lv-1]; + int gain_sp = tstatus->max_sp*abs(sp_rate)/100;// The earned is the same % of the target SP than it cost the caster. [Skotlex] + clif->skill_nodamage(src,bl,skill_id,status->heal(bl, 0, gain_sp, 0),1); + } break; // parent-baby skills case WE_BABY: - if(sd){ + if(sd) { struct map_session_data *f_sd = pc->get_father(sd); struct map_session_data *m_sd = pc->get_mother(sd); - // if neither was found - if(!f_sd && !m_sd){ + bool we_baby_parents = false; + if(m_sd && check_distance_bl(bl,&m_sd->bl,AREA_SIZE)) { + sc_start(src,&m_sd->bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv)); + clif->specialeffect(&m_sd->bl,408,AREA); + we_baby_parents = true; + } + if(f_sd && check_distance_bl(bl,&f_sd->bl,AREA_SIZE)) { + sc_start(src,&f_sd->bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv)); + clif->specialeffect(&f_sd->bl,408,AREA); + we_baby_parents = true; + } + if (!we_baby_parents) { clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - iMap->freeblock_unlock(); + map->freeblock_unlock(); return 0; } - status_change_start(bl,SC_STUN,10000,skill_lv,0,0,0,skill->get_time2(skill_id,skill_lv),8); - if (f_sd) sc_start(&f_sd->bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv)); - if (m_sd) sc_start(&m_sd->bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv)); + else + status->change_start(src,bl,SC_STUN,10000,skill_lv,0,0,0,skill->get_time2(skill_id,skill_lv),8); } break; case PF_HPCONVERSION: - { - int hp, sp; - hp = sstatus->max_hp/10; - sp = hp * 10 * skill_lv / 100; - if (!status_charge(src,hp,0)) { - if (sd) clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - break; - } - clif->skill_nodamage(src, bl, skill_id, skill_lv, 1); - status_heal(bl,0,sp,2); + { + int hp, sp; + hp = sstatus->max_hp/10; + sp = hp * 10 * skill_lv / 100; + if (!status->charge(src,hp,0)) { + if (sd) clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + break; } + clif->skill_nodamage(src, bl, skill_id, skill_lv, 1); + status->heal(bl,0,sp,2); + } break; case MA_REMOVETRAP: @@ -7060,37 +7295,33 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui if( su && (sg = su->group) && (src->type == BL_MER || sg->src_id == src->id || map_flag_vs(bl->m)) && (skill->get_inf2(sg->skill_id)&INF2_TRAP) ) { clif->skill_nodamage(src, bl, skill_id, skill_lv, 1); - if( sd && !(sg->unit_id == UNT_USED_TRAPS || (sg->unit_id == UNT_ANKLESNARE && sg->val2 != 0 )) ) - { // prevent picking up expired traps - if( battle_config.skill_removetrap_type ) - { // get back all items used to deploy the trap - for( i = 0; i < 10; i++ ) - { - if( skill_db[su->group->skill_id].itemid[i] > 0 ) - { - int flag; + if( sd && !(sg->unit_id == UNT_USED_TRAPS || (sg->unit_id == UNT_ANKLESNARE && sg->val2 != 0 )) && sg->unit_id != UNT_THORNS_TRAP ) { + // prevent picking up expired traps + if( battle_config.skill_removetrap_type ) { + int i; + // get back all items used to deploy the trap + for( i = 0; i < 10; i++ ) { + if( skill->db[su->group->skill_id].itemid[i] > 0 ) { + int success; struct item item_tmp; memset(&item_tmp,0,sizeof(item_tmp)); - item_tmp.nameid = skill_db[su->group->skill_id].itemid[i]; + item_tmp.nameid = skill->db[su->group->skill_id].itemid[i]; item_tmp.identify = 1; - if( item_tmp.nameid && (flag=pc->additem(sd,&item_tmp,skill_db[su->group->skill_id].amount[i],LOG_TYPE_OTHER)) ) - { - clif->additem(sd,0,0,flag); - iMap->addflooritem(&item_tmp,skill_db[su->group->skill_id].amount[i],sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0); + if( item_tmp.nameid && (success=pc->additem(sd,&item_tmp,skill->db[su->group->skill_id].amount[i],LOG_TYPE_OTHER)) ) { + clif->additem(sd,0,0,success); + map->addflooritem(&item_tmp,skill->db[su->group->skill_id].amount[i],sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0); } } } - } - else - { // get back 1 trap + } else { + // get back 1 trap struct item item_tmp; memset(&item_tmp,0,sizeof(item_tmp)); item_tmp.nameid = su->group->item_id?su->group->item_id:ITEMID_TRAP; item_tmp.identify = 1; - if( item_tmp.nameid && (flag=pc->additem(sd,&item_tmp,1,LOG_TYPE_OTHER)) ) - { + if( item_tmp.nameid && (flag=pc->additem(sd,&item_tmp,1,LOG_TYPE_OTHER)) ) { clif->additem(sd,0,0,flag); - iMap->addflooritem(&item_tmp,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0); + map->addflooritem(&item_tmp,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0); } } } @@ -7111,7 +7342,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui // if it is already trapping something don't spring it, // remove trap should be used instead break; - // otherwise fallthrough to below + // otherwise fall through to below case UNT_BLASTMINE: case UNT_SKIDTRAP: case UNT_LANDMINE: @@ -7123,8 +7354,8 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case UNT_TALKIEBOX: su->group->unit_id = UNT_USED_TRAPS; clif->changetraplook(bl, UNT_USED_TRAPS); - su->group->limit=DIFF_TICK(tick+1500,su->group->tick); - su->limit=DIFF_TICK(tick+1500,su->group->tick); + su->group->limit=DIFF_TICK32(tick+1500,su->group->tick); + su->limit=DIFF_TICK32(tick+1500,su->group->tick); } } } @@ -7132,53 +7363,51 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case BD_ENCORE: clif->skill_nodamage(src,bl,skill_id,skill_lv,1); if(sd) - unit_skilluse_id(src,src->id,sd->skill_id_dance,sd->skill_lv_dance); + unit->skilluse_id(src,src->id,sd->skill_id_dance,sd->skill_lv_dance); break; case AS_SPLASHER: - if(tstatus->mode&MD_BOSS - /** - * Renewal dropped the 3/4 hp requirement - **/ - #ifndef RENEWAL - || tstatus-> hp > tstatus->max_hp*3/4 - #endif - ) { + if( tstatus->mode&MD_BOSS +#ifndef RENEWAL + /** Renewal dropped the 3/4 hp requirement **/ + || tstatus-> hp > tstatus->max_hp*3/4 +#endif // RENEWAL + ) { if (sd) clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - iMap->freeblock_unlock(); + map->freeblock_unlock(); return 1; } clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start4(bl,type,100,skill_lv,skill_id,src->id,skill->get_time(skill_id,skill_lv),1000)); + sc_start4(src,bl,type,100,skill_lv,skill_id,src->id,skill->get_time(skill_id,skill_lv),1000)); #ifndef RENEWAL - if (sd) skill->blockpc_start (sd, skill_id, skill->get_time(skill_id, skill_lv)+3000, false); + if (sd) skill->blockpc_start (sd, skill_id, skill->get_time(skill_id, skill_lv)+3000); #endif break; case PF_MINDBREAKER: { if(tstatus->mode&MD_BOSS || battle->check_undead(tstatus->race,tstatus->def_ele) ) { - iMap->freeblock_unlock(); + map->freeblock_unlock(); return 1; } - if (tsce) - { //HelloKitty2 (?) explained that this silently fails when target is + if (tsce) { + //HelloKitty2 (?) explained that this silently fails when target is //already inflicted. [Skotlex] - iMap->freeblock_unlock(); + map->freeblock_unlock(); return 1; } //Has a 55% + skill_lv*5% success chance. if (!clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start(bl,type,55+5*skill_lv,skill_lv,skill->get_time(skill_id,skill_lv)))) - { + sc_start(src,bl,type,55+5*skill_lv,skill_lv,skill->get_time(skill_id,skill_lv))) + ) { if (sd) clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - iMap->freeblock_unlock(); + map->freeblock_unlock(); return 0; } - unit_skillcastcancel(bl,0); + unit->skillcastcancel(bl,0); if(tsc && tsc->count){ status_change_end(bl, SC_FREEZE, INVALID_TIMER); @@ -7188,7 +7417,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui } if(dstmd) - mob_target(dstmd,src,skill->get_range2(src,skill_id,skill_lv)); + mob->target(dstmd,src,skill->get_range2(src,skill_id,skill_lv)); } break; @@ -7202,20 +7431,20 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui } dstmd->state.soul_change_flag = 1; sp2 = sstatus->max_sp * 3 /100; - status_heal(src, 0, sp2, 2); + status->heal(src, 0, sp2, 2); clif->skill_nodamage(src,bl,skill_id,skill_lv,1); break; } sp1 = sstatus->sp; sp2 = tstatus->sp; - #ifdef RENEWAL - sp1 = sp1 / 2; - sp2 = sp2 / 2; - if( tsc && tsc->data[SC_EXTREMITYFIST2] ) - sp1 = tstatus->sp; - #endif - status_set_sp(src, sp2, 3); - status_set_sp(bl, sp1, 3); +#ifdef RENEWAL + sp1 = sp1 / 2; + sp2 = sp2 / 2; + if( tsc && tsc->data[SC_EXTREMITYFIST2] ) + sp1 = tstatus->sp; +#endif // RENEWAL + status->set_sp(src, sp2, 3); + status->set_sp(bl, sp1, 3); clif->skill_nodamage(src,bl,skill_id,skill_lv,1); } break; @@ -7225,8 +7454,8 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui // Updated to block Slim Pitcher from working on barricades and guardian stones. if( dstmd && (dstmd->class_ == MOBID_EMPERIUM || (dstmd->class_ >= MOBID_BARRICADE1 && dstmd->class_ <= MOBID_GUARIDAN_STONE2)) ) break; - if (potion_hp || potion_sp) { - int hp = potion_hp, sp = potion_sp; + if (script->potion_hp || script->potion_sp) { + int hp = script->potion_hp, sp = script->potion_sp; hp = hp * (100 + (tstatus->vit<<1))/100; sp = sp * (100 + (tstatus->int_<<1))/100; if (dstsd) { @@ -7253,29 +7482,34 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui clif->skill_nodamage(NULL,bl,AL_HEAL,hp,1); if(sp > 0) clif->skill_nodamage(NULL,bl,MG_SRECOVERY,sp,1); - status_heal(bl,hp,sp,0); + status->heal(bl,hp,sp,0); } break; // Full Chemical Protection - case CR_FULLPROTECTION: - { - unsigned int equip[] = {EQP_WEAPON, EQP_SHIELD, EQP_ARMOR, EQP_HEAD_TOP}; - int i, s = 0, skilltime = skill->get_time(skill_id,skill_lv); - - for (i=0 ; i<4; i++) { - if( bl->type != BL_PC || ( dstsd && pc->checkequip(dstsd,equip[i]) < 0 ) ) - continue; - sc_start(bl,(sc_type)(SC_PROTECTWEAPON + i),100,skill_lv,skilltime); - s++; - } - if( sd && !s ){ - clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - iMap->freeblock_unlock(); // Don't consume item requirements - return 0; - } + case CR_FULLPROTECTION: { + bool iused=false; + int i; + if(dstsd && dstsd->inventory_data[dstsd->equip_index[EQI_HAND_R]]) { + iused=true; + clif->skill_nodamage(src,bl,skill_id,skill_lv,sc_start(src,bl,SC_PROTECTWEAPON,100,skill_lv,skill->get_time(skill_id,skill_lv))); + } if(dstsd && (i=dstsd->equip_index[EQI_HAND_L])>=0 && dstsd->inventory_data[i] && + dstsd->inventory_data[i]->type==IT_ARMOR) { + iused=true; + clif->skill_nodamage(src,bl,skill_id,skill_lv,sc_start(src,bl,SC_PROTECTSHIELD,100,skill_lv,skill->get_time(skill_id,skill_lv))); + } if(dstsd && dstsd->inventory_data[dstsd->equip_index[EQI_ARMOR]]) { + iused=true; + clif->skill_nodamage(src,bl,skill_id,skill_lv,sc_start(src,bl,SC_PROTECTARMOR,100,skill_lv,skill->get_time(skill_id,skill_lv))); + } if(dstsd && dstsd->inventory_data[dstsd->equip_index[EQI_HEAD_TOP]]) { + iused=true; + clif->skill_nodamage(src,bl,skill_id,skill_lv,sc_start(src,bl,SC_PROTECTHELM,100,skill_lv,skill->get_time(skill_id,skill_lv))); + } if(iused) clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + else { + clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + return 0; } - break; + } + break; case RG_CLEANER: //AppleGirl clif->skill_nodamage(src,bl,skill_id,skill_lv,1); @@ -7287,7 +7521,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui && (tsce->val1&0xFFFF) != CG_MOONLIT) //Can't use Longing for Freedom while under Moonlight Petals. [Skotlex] { clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); + sc_start(src,bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); } } break; @@ -7296,18 +7530,17 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui { int eff, count = -1; if( tsc && tsc->data[type] ){ - iMap->freeblock_unlock(); + map->freeblock_unlock(); return 0; } - if( rnd() % 100 > skill_lv * 8 || (dstmd && ((dstmd->guardian_data && dstmd->class_ == MOBID_EMPERIUM) || mob_is_battleground(dstmd))) ) - { + if( rnd() % 100 > skill_lv * 8 || (dstmd && ((dstmd->guardian_data && dstmd->class_ == MOBID_EMPERIUM) || mob_is_battleground(dstmd))) ) { if( sd ) clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - iMap->freeblock_unlock(); + map->freeblock_unlock(); return 0; } - status_zap(src,0,skill_db[skill->get_index(skill_id)].sp[skill_lv]); // consume sp only if succeeded [Inkfish] + status_zap(src,0,skill->db[skill->get_index(skill_id)].sp[skill_lv]); // consume sp only if succeeded [Inkfish] do { eff = rnd() % 14; if( eff == 5 ) @@ -7320,70 +7553,70 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui status_percent_damage(src, bl, 0, 100, false); break; case 1: // matk halved - sc_start(bl,SC_INCMATKRATE,100,-50,skill->get_time2(skill_id,skill_lv)); + sc_start(src,bl,SC_INCMATKRATE,100,-50,skill->get_time2(skill_id,skill_lv)); break; case 2: // all buffs removed - status_change_clear_buffs(bl,1); + status->change_clear_buffs(bl,1); break; case 3: // 1000 damage, random armor destroyed { status_fix_damage(src, bl, 1000, 0); - clif->damage(src,bl,tick,0,0,1000,0,0,0); - if( !status_isdead(bl) ) { + clif->damage(src,bl,0,0,1000,0,0,0); + if( !status->isdead(bl) ) { int where[] = { EQP_ARMOR, EQP_SHIELD, EQP_HELM, EQP_SHOES, EQP_GARMENT }; skill->break_equip(bl, where[rnd()%5], 10000, BCT_ENEMY); } } break; case 4: // atk halved - sc_start(bl,SC_INCATKRATE,100,-50,skill->get_time2(skill_id,skill_lv)); + sc_start(src,bl,SC_INCATKRATE,100,-50,skill->get_time2(skill_id,skill_lv)); break; case 5: // 2000HP heal, random teleported - status_heal(src, 2000, 0, 0); + status->heal(src, 2000, 0, 0); if( !map_flag_vs(bl->m) ) - unit_warp(bl, -1,-1,-1, CLR_TELEPORT); + unit->warp(bl, -1,-1,-1, CLR_TELEPORT); break; case 6: // random 2 other effects if (count == -1) count = 3; else - count++; //Should not retrigger this one. + count++; //Should not re-trigger this one. break; case 7: // stop freeze or stoned { enum sc_type sc[] = { SC_STOP, SC_FREEZE, SC_STONE }; - sc_start(bl,sc[rnd()%3],100,skill_lv,skill->get_time2(skill_id,skill_lv)); + sc_start(src,bl,sc[rnd()%3],100,skill_lv,skill->get_time2(skill_id,skill_lv)); } break; case 8: // curse coma and poison - sc_start(bl,SC_COMA,100,skill_lv,skill->get_time2(skill_id,skill_lv)); - sc_start(bl,SC_CURSE,100,skill_lv,skill->get_time2(skill_id,skill_lv)); - sc_start(bl,SC_POISON,100,skill_lv,skill->get_time2(skill_id,skill_lv)); + sc_start(src,bl,SC_COMA,100,skill_lv,skill->get_time2(skill_id,skill_lv)); + sc_start(src,bl,SC_CURSE,100,skill_lv,skill->get_time2(skill_id,skill_lv)); + sc_start(src,bl,SC_POISON,100,skill_lv,skill->get_time2(skill_id,skill_lv)); break; case 9: // confusion - sc_start(bl,SC_CONFUSION,100,skill_lv,skill->get_time2(skill_id,skill_lv)); + sc_start(src,bl,SC_CONFUSION,100,skill_lv,skill->get_time2(skill_id,skill_lv)); break; case 10: // 6666 damage, atk matk halved, cursed status_fix_damage(src, bl, 6666, 0); - clif->damage(src,bl,tick,0,0,6666,0,0,0); - sc_start(bl,SC_INCATKRATE,100,-50,skill->get_time2(skill_id,skill_lv)); - sc_start(bl,SC_INCMATKRATE,100,-50,skill->get_time2(skill_id,skill_lv)); - sc_start(bl,SC_CURSE,skill_lv,100,skill->get_time2(skill_id,skill_lv)); + clif->damage(src,bl,0,0,6666,0,0,0); + sc_start(src,bl,SC_INCATKRATE,100,-50,skill->get_time2(skill_id,skill_lv)); + sc_start(src,bl,SC_INCMATKRATE,100,-50,skill->get_time2(skill_id,skill_lv)); + sc_start(src,bl,SC_CURSE,skill_lv,100,skill->get_time2(skill_id,skill_lv)); break; case 11: // 4444 damage status_fix_damage(src, bl, 4444, 0); - clif->damage(src,bl,tick,0,0,4444,0,0,0); + clif->damage(src,bl,0,0,4444,0,0,0); break; case 12: // stun - sc_start(bl,SC_STUN,100,skill_lv,5000); + sc_start(src,bl,SC_STUN,100,skill_lv,5000); break; case 13: // atk,matk,hit,flee,def reduced - sc_start(bl,SC_INCATKRATE,100,-20,skill->get_time2(skill_id,skill_lv)); - sc_start(bl,SC_INCMATKRATE,100,-20,skill->get_time2(skill_id,skill_lv)); - sc_start(bl,SC_INCHITRATE,100,-20,skill->get_time2(skill_id,skill_lv)); - sc_start(bl,SC_INCFLEERATE,100,-20,skill->get_time2(skill_id,skill_lv)); - sc_start(bl,SC_INCDEFRATE,100,-20,skill->get_time2(skill_id,skill_lv)); - sc_start(bl,type,100,skill_lv,skill->get_time2(skill_id,skill_lv)); + sc_start(src,bl,SC_INCATKRATE,100,-20,skill->get_time2(skill_id,skill_lv)); + sc_start(src,bl,SC_INCMATKRATE,100,-20,skill->get_time2(skill_id,skill_lv)); + sc_start(src,bl,SC_INCHITRATE,100,-20,skill->get_time2(skill_id,skill_lv)); + sc_start(src,bl,SC_INCFLEERATE,100,-20,skill->get_time2(skill_id,skill_lv)); + sc_start(src,bl,SC_INCDEFRATE,100,-20,skill->get_time2(skill_id,skill_lv)); + sc_start(src,bl,type,100,skill_lv,skill->get_time2(skill_id,skill_lv)); break; default: break; @@ -7416,13 +7649,13 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui if (skill_id == SL_SUPERNOVICE && dstsd && dstsd->die_counter && !(rnd()%100)) { //Erase death count 1% of the casts dstsd->die_counter = 0; - pc_setglobalreg(dstsd,"PC_DIE_COUNTER", 0); + pc_setglobalreg(dstsd,script->add_str("PC_DIE_COUNTER"), 0); clif->specialeffect(bl, 0x152, AREA); //SC_SOULLINK invokes status_calc_pc for us. } clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start4(bl,SC_SOULLINK,100,skill_lv,skill_id,0,0,skill->get_time(skill_id,skill_lv))); - sc_start(src,SC_SMA_READY,100,skill_lv,skill->get_time(SL_SMA,skill_lv)); + sc_start4(src,bl,SC_SOULLINK,100,skill_lv,skill_id,0,0,skill->get_time(skill_id,skill_lv))); + sc_start(src,src,SC_SMA_READY,100,skill_lv,skill->get_time(SL_SMA,skill_lv)); break; case SL_HIGH: if (sd && !(dstsd && (dstsd->class_&JOBL_UPPER) && !(dstsd->class_&JOBL_2) && dstsd->status.base_level < 70)) { @@ -7430,15 +7663,15 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui break; } clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start4(bl,type,100,skill_lv,skill_id,0,0,skill->get_time(skill_id,skill_lv))); - sc_start(src,SC_SMA_READY,100,skill_lv,skill->get_time(SL_SMA,skill_lv)); + sc_start4(src,bl,type,100,skill_lv,skill_id,0,0,skill->get_time(skill_id,skill_lv))); + sc_start(src,src,SC_SMA_READY,100,skill_lv,skill->get_time(SL_SMA,skill_lv)); break; case SL_SWOO: if (tsce) { if(sd) clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - status_change_start(src,SC_STUN,10000,skill_lv,0,0,0,10000,8); + status->change_start(src,src,SC_STUN,10000,skill_lv,0,0,0,10000,8); status_change_end(bl, SC_SWOO, INVALID_TIMER); break; } @@ -7446,53 +7679,53 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case SL_SKE: if (sd && !battle_config.allow_es_magic_pc && bl->type != BL_MOB) { clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - status_change_start(src,SC_STUN,10000,skill_lv,0,0,0,500,10); + status->change_start(src,src,SC_STUN,10000,skill_lv,0,0,0,500,10); break; } - clif->skill_nodamage(src,bl,skill_id,skill_lv,sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); + clif->skill_nodamage(src,bl,skill_id,skill_lv,sc_start(src,bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); if (skill_id == SL_SKE) - sc_start(src,SC_SMA_READY,100,skill_lv,skill->get_time(SL_SMA,skill_lv)); + sc_start(src,src,SC_SMA_READY,100,skill_lv,skill->get_time(SL_SMA,skill_lv)); break; // New guild skills [Celest] case GD_BATTLEORDER: if(flag&1) { - if (status_get_guild_id(src) == status_get_guild_id(bl)) - sc_start(bl,type,100,skill_lv,skill->get_time(skill_id, skill_lv)); - } else if (status_get_guild_id(src)) { + if (status->get_guild_id(src) == status->get_guild_id(bl)) + sc_start(src,bl,type,100,skill_lv,skill->get_time(skill_id, skill_lv)); + } else if (status->get_guild_id(src)) { clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - iMap->foreachinrange(skill->area_sub, src, - skill->get_splash(skill_id, skill_lv), BL_PC, - src,skill_id,skill_lv,tick, flag|BCT_GUILD|1, - skill->castend_nodamage_id); + map->foreachinrange(skill->area_sub, src, + skill->get_splash(skill_id, skill_lv), BL_PC, + src,skill_id,skill_lv,tick, flag|BCT_GUILD|1, + skill->castend_nodamage_id); if (sd) guild->block_skill(sd,skill->get_time2(skill_id,skill_lv)); } break; case GD_REGENERATION: if(flag&1) { - if (status_get_guild_id(src) == status_get_guild_id(bl)) - sc_start(bl,type,100,skill_lv,skill->get_time(skill_id, skill_lv)); - } else if (status_get_guild_id(src)) { + if (status->get_guild_id(src) == status->get_guild_id(bl)) + sc_start(src,bl,type,100,skill_lv,skill->get_time(skill_id, skill_lv)); + } else if (status->get_guild_id(src)) { clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - iMap->foreachinrange(skill->area_sub, src, - skill->get_splash(skill_id, skill_lv), BL_PC, - src,skill_id,skill_lv,tick, flag|BCT_GUILD|1, - skill->castend_nodamage_id); + map->foreachinrange(skill->area_sub, src, + skill->get_splash(skill_id, skill_lv), BL_PC, + src,skill_id,skill_lv,tick, flag|BCT_GUILD|1, + skill->castend_nodamage_id); if (sd) guild->block_skill(sd,skill->get_time2(skill_id,skill_lv)); } break; case GD_RESTORE: if(flag&1) { - if (status_get_guild_id(src) == status_get_guild_id(bl)) + if (status->get_guild_id(src) == status->get_guild_id(bl)) clif->skill_nodamage(src,bl,AL_HEAL,status_percent_heal(bl,90,90),1); - } else if (status_get_guild_id(src)) { + } else if (status->get_guild_id(src)) { clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - iMap->foreachinrange(skill->area_sub, src, - skill->get_splash(skill_id, skill_lv), BL_PC, - src,skill_id,skill_lv,tick, flag|BCT_GUILD|1, - skill->castend_nodamage_id); + map->foreachinrange(skill->area_sub, src, + skill->get_splash(skill_id, skill_lv), BL_PC, + src,skill_id,skill_lv,tick, flag|BCT_GUILD|1, + skill->castend_nodamage_id); if (sd) guild->block_skill(sd,skill->get_time2(skill_id,skill_lv)); } @@ -7501,19 +7734,19 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui { int dx[9]={-1, 1, 0, 0,-1, 1,-1, 1, 0}; int dy[9]={ 0, 0, 1,-1, 1,-1,-1, 1, 0}; - int j = 0; + int i, j = 0; struct guild *g; // i don't know if it actually summons in a circle, but oh well. ;P - g = sd?sd->state.gmaster_flag:guild->search(status_get_guild_id(src)); + g = sd ? sd->guild : guild->search(status->get_guild_id(src)); if (!g) break; clif->skill_nodamage(src,bl,skill_id,skill_lv,1); for(i = 0; i < g->max_member; i++, j++) { if (j>8) j=0; if ((dstsd = g->member[i].sd) != NULL && sd != dstsd && !dstsd->state.autotrade && !pc_isdead(dstsd)) { - if (map[dstsd->bl.m].flag.nowarp && !map_flag_gvg2(dstsd->bl.m)) + if (map->list[dstsd->bl.m].flag.nowarp && !map_flag_gvg2(dstsd->bl.m)) continue; - if(iMap->getcell(src->m,src->x+dx[j],src->y+dy[j],CELL_CHKNOREACH)) + if(map->getcell(src->m,src->x+dx[j],src->y+dy[j],CELL_CHKNOREACH)) dx[j] = dy[j] = 0; pc->setpos(dstsd, map_id2index(src->m), src->x+dx[j], src->y+dy[j], CLR_RESPAWN); } @@ -7555,28 +7788,32 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui /* per official standards, this skill works on players and mobs. */ if (sd && (dstsd || dstmd)) { - i =65 -5*distance_bl(src,bl); //Base rate - if (i < 30) i = 30; + int rate = 65 -5*distance_bl(src,bl); //Base rate + if (rate < 30) rate = 30; clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - sc_start(bl,SC_STUN, i,skill_lv,skill->get_time2(skill_id,skill_lv)); + sc_start(src,bl,SC_STUN, rate,skill_lv,skill->get_time2(skill_id,skill_lv)); } break; - case AM_CALLHOMUN: //[orn] - if (sd && homun->call(sd)) - clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + case AM_CALLHOMUN: // [orn] + if( sd ) { + if (homun->call(sd)) + clif->skill_nodamage(src, bl, skill_id, skill_lv, 1); + else + clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + } break; case AM_REST: if (sd) { - if (homun->vaporize(sd,1)) + if (homun->vaporize(sd,HOM_ST_REST)) clif->skill_nodamage(src, bl, skill_id, skill_lv, 1); else clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); } break; - case HAMI_CASTLE: //[orn] + case HAMI_CASTLE: // [orn] if(rnd()%100 < 20*skill_lv && src != bl) { int x,y; @@ -7585,18 +7822,18 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui if (hd) skill->blockhomun_start(hd, skill_id, skill->get_time2(skill_id,skill_lv)); - if (unit_movepos(src,bl->x,bl->y,0,0)) { - clif->skill_nodamage(src,src,skill_id,skill_lv,1); // Homunc + if (unit->movepos(src,bl->x,bl->y,0,0)) { + clif->skill_nodamage(src,src,skill_id,skill_lv,1); // Homun clif->slide(src,bl->x,bl->y) ; - if (unit_movepos(bl,x,y,0,0)) + if (unit->movepos(bl,x,y,0,0)) { clif->skill_nodamage(bl,bl,skill_id,skill_lv,1); // Master clif->slide(bl,x,y) ; } //TODO: Shouldn't also players and the like switch targets? - iMap->foreachinrange(skill->chastle_mob_changetarget,src, - AREA_SIZE, BL_MOB, bl, src); + map->foreachinrange(skill->chastle_mob_changetarget,src, + AREA_SIZE, BL_MOB, bl, src); } } // Failed @@ -7605,27 +7842,28 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui else if (sd) clif->skill_fail(sd, skill_id, USESKILL_FAIL_LEVEL, 0); break; - case HVAN_CHAOTIC: //[orn] + case HVAN_CHAOTIC: // [orn] { static const int per[5][2]={{20,50},{50,60},{25,75},{60,64},{34,67}}; int r = rnd()%100; - i = (skill_lv-1)%5; - if(r<per[i][0]) //Self + int target = (skill_lv-1)%5; + int hp; + if(r<per[target][0]) //Self bl = src; - else if(r<per[i][1]) //Master + else if(r<per[target][1]) //Master bl = battle->get_master(src); else //Enemy - bl = iMap->id2bl(battle->get_target(src)); + bl = map->id2bl(battle->get_target(src)); if (!bl) bl = src; - i = skill->calc_heal(src, bl, skill_id, 1+rnd()%skill_lv, true); + hp = skill->calc_heal(src, bl, skill_id, 1+rnd()%skill_lv, true); //Eh? why double skill packet? - clif->skill_nodamage(src,bl,AL_HEAL,i,1); - clif->skill_nodamage(src,bl,skill_id,i,1); - status_heal(bl, i, 0, 0); + clif->skill_nodamage(src,bl,AL_HEAL,hp,1); + clif->skill_nodamage(src,bl,skill_id,hp,1); + status->heal(bl, hp, 0, 0); } break; - //Homun single-target support skills [orn] + // Homun single-target support skills [orn] case HAMI_BLOODLUST: case HFLI_FLEET: case HFLI_SPEED: @@ -7633,7 +7871,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case MH_ANGRIFFS_MODUS: case MH_GOLDENE_FERSE: clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); + sc_start(src,bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); if (hd) skill->blockhomun_start(hd, skill_id, skill->get_time2(skill_id,skill_lv)); break; @@ -7641,9 +7879,9 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case NPC_DRAGONFEAR: if (flag&1) { const enum sc_type sc[] = { SC_STUN, SC_SILENCE, SC_CONFUSION, SC_BLOODING }; - int j; + int i, j; j = i = rnd()%ARRAYLENGTH(sc); - while ( !sc_start2(bl,sc[i],100,skill_lv,src->id,skill->get_time2(skill_id,i+1)) ) { + while ( !sc_start2(src,bl,sc[i],100,skill_lv,src->id,skill->get_time2(skill_id,i+1)) ) { i++; if ( i == ARRAYLENGTH(sc) ) i = 0; @@ -7662,27 +7900,42 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case NPC_WIDESTUN: case NPC_SLOWCAST: case NPC_WIDEHELLDIGNITY: - if (flag&1) - sc_start2(bl,type,100,skill_lv,src->id,skill->get_time2(skill_id,skill_lv)); - else { - skill_area_temp[2] = 0; //For SD_PREAMBLE + case NPC_WIDEHEALTHFEAR: + case NPC_WIDEBODYBURNNING: + case NPC_WIDEFROSTMISTY: + case NPC_WIDECOLD: + case NPC_WIDE_DEEP_SLEEP: + case NPC_WIDESIREN: + if (flag&1){ + switch( type ){ + case SC_BURNING: + sc_start4(src,bl,type,100,skill_lv,0,src->id,0,skill->get_time2(skill_id,skill_lv)); + break; + case SC_SIREN: + sc_start2(src,bl,type,100,skill_lv,src->id,skill->get_time2(skill_id,skill_lv)); + break; + default: + sc_start2(src,bl,type,100,skill_lv,src->id,skill->get_time2(skill_id,skill_lv)); + } + } else { + skill->area_temp[2] = 0; //For SD_PREAMBLE clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - iMap->foreachinrange(skill->area_sub, bl, - skill->get_splash(skill_id, skill_lv),BL_CHAR, - src,skill_id,skill_lv,tick, flag|BCT_ENEMY|SD_PREAMBLE|1, - skill->castend_nodamage_id); + map->foreachinrange(skill->area_sub, bl, + skill->get_splash(skill_id, skill_lv),BL_CHAR, + src,skill_id,skill_lv,tick, flag|BCT_ENEMY|SD_PREAMBLE|1, + skill->castend_nodamage_id); } break; case NPC_WIDESOULDRAIN: if (flag&1) status_percent_damage(src,bl,0,((skill_lv-1)%5+1)*20,false); else { - skill_area_temp[2] = 0; //For SD_PREAMBLE + skill->area_temp[2] = 0; //For SD_PREAMBLE clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - iMap->foreachinrange(skill->area_sub, bl, - skill->get_splash(skill_id, skill_lv),BL_CHAR, - src,skill_id,skill_lv,tick, flag|BCT_ENEMY|SD_PREAMBLE|1, - skill->castend_nodamage_id); + map->foreachinrange(skill->area_sub, bl, + skill->get_splash(skill_id, skill_lv),BL_CHAR, + src,skill_id,skill_lv,tick, flag|BCT_ENEMY|SD_PREAMBLE|1, + skill->castend_nodamage_id); } break; case ALL_PARTYFLEE: @@ -7693,13 +7946,15 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); break; } - party_foreachsamemap(skill->area_sub, sd, skill->get_splash(skill_id, skill_lv), src, skill_id, skill_lv, tick, flag|BCT_PARTY|1, skill->castend_nodamage_id); + party->foreachsamemap(skill->area_sub, sd, skill->get_splash(skill_id, skill_lv), src, skill_id, skill_lv, tick, flag|BCT_PARTY|1, skill->castend_nodamage_id); } else - clif->skill_nodamage(src,bl,skill_id,skill_lv,sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); + clif->skill_nodamage(src,bl,skill_id,skill_lv,sc_start(src,bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); break; case NPC_TALK: case ALL_WEWISH: + case ALL_CATCRY: + case ALL_DREAM_SUMMERNIGHT: clif->skill_nodamage(src,bl,skill_id,skill_lv,1); break; case ALL_BUYING_STORE: @@ -7710,76 +7965,143 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui break; case RK_ENCHANTBLADE: clif->skill_nodamage(src,bl,skill_id,skill_lv,// formula not confirmed - sc_start2(bl,type,100,skill_lv,100+20*skill_lv/*+sstatus->int_/2+status_get_lv(bl)/10*/,skill->get_time(skill_id,skill_lv))); + sc_start2(src,bl,type,100,skill_lv,(100+20*skill_lv)*status->get_lv(src)/150+sstatus->int_,skill->get_time(skill_id,skill_lv))); break; case RK_DRAGONHOWLING: if( flag&1) - sc_start(bl,type,50 + 6 * skill_lv,skill_lv,skill->get_time(skill_id,skill_lv)); - else - { - skill_area_temp[2] = 0; + sc_start(src,bl,type,50 + 6 * skill_lv,skill_lv,skill->get_time(skill_id,skill_lv)); + else { + skill->area_temp[2] = 0; clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - iMap->foreachinrange(skill->area_sub, src, - skill->get_splash(skill_id,skill_lv),BL_CHAR, - src,skill_id,skill_lv,tick,flag|BCT_ENEMY|SD_PREAMBLE|1, - skill->castend_nodamage_id); + map->foreachinrange(skill->area_sub, src, + skill->get_splash(skill_id,skill_lv),BL_CHAR, + src,skill_id,skill_lv,tick,flag|BCT_ENEMY|SD_PREAMBLE|1, + skill->castend_nodamage_id); } break; case RK_IGNITIONBREAK: case LG_EARTHDRIVE: + { + int splash; clif->skill_damage(src,bl,tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6); - i = skill->get_splash(skill_id,skill_lv); + splash = skill->get_splash(skill_id,skill_lv); if( skill_id == LG_EARTHDRIVE ) { int dummy = 1; - iMap->foreachinarea(skill->cell_overlap, src->m, src->x-i, src->y-i, src->x+i, src->y+i, BL_SKILL, LG_EARTHDRIVE, &dummy, src); + map->foreachinarea(skill->cell_overlap, src->m, src->x-splash, src->y-splash, src->x+splash, src->y+splash, BL_SKILL, LG_EARTHDRIVE, &dummy, src); } - iMap->foreachinrange(skill->area_sub, bl,i,BL_CHAR, - src,skill_id,skill_lv,tick,flag|BCT_ENEMY|1,skill->castend_damage_id); + map->foreachinrange(skill->area_sub, bl,splash,BL_CHAR, + src,skill_id,skill_lv,tick,flag|BCT_ENEMY|1,skill->castend_damage_id); + } break; case RK_STONEHARDSKIN: - if( sd ) - { - int heal = sstatus->hp / 4; // 25% HP - if( status_charge(bl,heal,0) ) - clif->skill_nodamage(src,bl,skill_id,skill_lv,sc_start2(bl,type,100,skill_lv,heal,skill->get_time(skill_id,skill_lv))); + if( sd ) { + int heal = sstatus->hp / 5; // 20% HP + if( status->charge(bl,heal,0) ) + clif->skill_nodamage(src,bl,skill_id,skill_lv,sc_start2(src,bl,type,100,skill_lv,heal,skill->get_time(skill_id,skill_lv))); else clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); } break; case RK_REFRESH: - { - int heal = status_get_max_hp(bl) * 25 / 100; - clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); - status_heal(bl,heal,0,1); - status_change_clear_buffs(bl,4); - } + { + int heal = status_get_max_hp(bl) * 25 / 100; + clif->skill_nodamage(src,bl,skill_id,skill_lv, + sc_start(src,bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); + status->heal(bl,heal,0,1); + status->change_clear_buffs(bl,4); + } break; case RK_MILLENNIUMSHIELD: - if( sd ){ - short shields = (rnd()%100<50) ? 4 : ((rnd()%100<80) ? 3 : 2); - sc_start4(bl,type,100,skill_lv,shields,1000,0,skill->get_time(skill_id,skill_lv)); - clif->millenniumshield(sd,shields); + if( sd && pc->checkskill(sd,RK_RUNEMASTERY) >= 9 ) { + short chance = 0; + short num_shields = 0; + chance = rnd()%100 + 1;//Generates a random number between 1 - 100 which is then used to determine how many shields will generate. + if ( chance >= 1 && chance <= 20 )//20% chance for 4 shields. + num_shields = 4; + else if ( chance >= 21 && chance <= 50 )//30% chance for 3 shields. + num_shields = 3; + else if ( chance >= 51 && chance <= 100 )//50% chance for 2 shields. + num_shields = 2; + sc_start4(src,bl,type,100,skill_lv,num_shields,1000,0,skill->get_time(skill_id,skill_lv)); + clif->millenniumshield(src,num_shields); clif->skill_nodamage(src,bl,skill_id,1,1); } break; case RK_FIGHTINGSPIRIT: if( flag&1 ) { + int atkbonus = 7 * party->foreachsamemap(skill->area_sub,sd,skill->get_splash(skill_id,skill_lv),src,skill_id,skill_lv,tick,BCT_PARTY,skill->area_sub_count); if( src == bl ) - sc_start2(bl,type,100,skill_area_temp[5],10*(sd?pc->checkskill(sd,RK_RUNEMASTERY):10),skill->get_time(skill_id,skill_lv)); + sc_start2(src,bl,type,100,atkbonus,10*(sd?pc->checkskill(sd,RK_RUNEMASTERY):10),skill->get_time(skill_id,skill_lv)); else - sc_start(bl,type,100,skill_area_temp[5]/4,skill->get_time(skill_id,skill_lv)); - } else if( sd ) { - if( sd->status.party_id ) { - i = party_foreachsamemap(skill->area_sub,sd,skill->get_splash(skill_id,skill_lv),src,skill_id,skill_lv,tick,BCT_PARTY,skill->area_sub_count); - skill_area_temp[5] = 7 * i; // ATK - party_foreachsamemap(skill->area_sub,sd,skill->get_splash(skill_id,skill_lv),src,skill_id,skill_lv,tick,flag|BCT_PARTY|1,skill->castend_nodamage_id); - } else - sc_start2(bl,type,100,7,5,skill->get_time(skill_id,skill_lv)); + sc_start(src,bl,type,100,atkbonus / 4,skill->get_time(skill_id,skill_lv)); + } else if( sd && pc->checkskill(sd,RK_RUNEMASTERY) >= 5 ) { + if( sd->status.party_id ) + party->foreachsamemap(skill->area_sub,sd,skill->get_splash(skill_id,skill_lv),src,skill_id,skill_lv,tick,flag|BCT_PARTY|1,skill->castend_nodamage_id); + else + sc_start2(src,bl,type,100,7,10*(sd?pc->checkskill(sd,RK_RUNEMASTERY):10),skill->get_time(skill_id,skill_lv)); + clif->skill_nodamage(src,bl,skill_id,1,1); + } + break; + + case RK_LUXANIMA: + if( sd == NULL || sd->status.party_id == 0 || flag&1 ){ + if( src == bl ) + break; + while( skill->area_temp[5] >= 0x10 ){ + int value = 0; + type = SC_NONE; + if( skill->area_temp[5]&0x10 ){ + value = (rnd()%100<50) ? 4 : ((rnd()%100<80) ? 3 : 2); + clif->millenniumshield(bl,value); + skill->area_temp[5] &= ~0x10; + type = SC_MILLENNIUMSHIELD; + }else if( skill->area_temp[5]&0x20 ){ + value = status_get_max_hp(bl) * 25 / 100; + status->change_clear_buffs(bl,4); + skill->area_temp[5] &= ~0x20; + status->heal(bl,value,0,1); + type = SC_REFRESH; + }else if( skill->area_temp[5]&0x40 ){ + skill->area_temp[5] &= ~0x40; + type = SC_GIANTGROWTH; + }else if( skill->area_temp[5]&0x80 ){ + if( dstsd ){ + value = sstatus->hp / 4; + if( status->charge(bl,value,0) ) + type = SC_STONEHARDSKIN; + skill->area_temp[5] &= ~0x80; + } + }else if( skill->area_temp[5]&0x100 ){ + skill->area_temp[5] &= ~0x100; + type = SC_VITALITYACTIVATION; + }else if( skill->area_temp[5]&0x200 ){ + skill->area_temp[5] &= ~0x200; + type = SC_ABUNDANCE; + } + if( type > SC_NONE ) + clif->skill_nodamage(bl, bl, skill_id, skill_lv, + sc_start4(src,bl, type, 100, skill_lv, value, 0, 1, skill->get_time(skill_id, skill_lv))); + } + }else if( sd ){ + if( tsc && tsc->count ){ + if(tsc->data[SC_MILLENNIUMSHIELD]) + skill->area_temp[5] |= 0x10; + if(tsc->data[SC_REFRESH]) + skill->area_temp[5] |= 0x20; + if(tsc->data[SC_GIANTGROWTH]) + skill->area_temp[5] |= 0x40; + if(tsc->data[SC_STONEHARDSKIN]) + skill->area_temp[5] |= 0x80; + if(tsc->data[SC_VITALITYACTIVATION]) + skill->area_temp[5] |= 0x100; + if(tsc->data[SC_ABUNDANCE]) + skill->area_temp[5] |= 0x200; + } + clif->skill_nodamage(src, bl, skill_id, skill_lv, 1); + party->foreachsamemap(skill->area_sub, sd, skill->get_splash(skill_id, skill_lv), src, skill_id, skill_lv, tick, flag|BCT_PARTY|1, skill->castend_nodamage_id); } - clif->skill_nodamage(src,bl,skill_id,1,1); break; /** * Guilotine Cross @@ -7787,16 +8109,16 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case GC_ROLLINGCUTTER: { short count = 1; - skill_area_temp[2] = 0; - iMap->foreachinrange(skill->area_sub,src,skill->get_splash(skill_id,skill_lv),BL_CHAR,src,skill_id,skill_lv,tick,flag|BCT_ENEMY|SD_PREAMBLE|SD_SPLASH|1,skill->castend_damage_id); + skill->area_temp[2] = 0; + map->foreachinrange(skill->area_sub,src,skill->get_splash(skill_id,skill_lv),BL_CHAR,src,skill_id,skill_lv,tick,flag|BCT_ENEMY|SD_PREAMBLE|SD_SPLASH|1,skill->castend_damage_id); if( tsc && tsc->data[SC_ROLLINGCUTTER] ) { // Every time the skill is casted the status change is reseted adding a counter. count += (short)tsc->data[SC_ROLLINGCUTTER]->val1; if( count > 10 ) - count = 10; // Max coounter + count = 10; // Max counter status_change_end(bl, SC_ROLLINGCUTTER, INVALID_TIMER); } - sc_start(bl,SC_ROLLINGCUTTER,100,count,skill->get_time(skill_id,skill_lv)); + sc_start(src,bl,SC_ROLLINGCUTTER,100,count,skill->get_time(skill_id,skill_lv)); clif->skill_nodamage(src,src,skill_id,skill_lv,1); } break; @@ -7805,7 +8127,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui if( tsc && tsc->data[SC_WEAPONBLOCKING] ) status_change_end(bl, SC_WEAPONBLOCKING, INVALID_TIMER); else - sc_start(bl,SC_WEAPONBLOCKING,100,skill_lv,skill->get_time(skill_id,skill_lv)); + sc_start(src,bl,SC_WEAPONBLOCKING,100,skill_lv,skill->get_time(skill_id,skill_lv)); clif->skill_nodamage(src,bl,skill_id,skill_lv,1); break; @@ -7840,25 +8162,29 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui break; case GC_PHANTOMMENACE: + { + int r; clif->skill_damage(src,bl,tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6); clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - iMap->foreachinrange(skill->area_sub,src,skill->get_splash(skill_id,skill_lv),BL_CHAR, + r = skill->get_splash(skill_id, skill_lv); + map->foreachinrange(skill->area_sub,src,skill->get_splash(skill_id,skill_lv),BL_CHAR, src,skill_id,skill_lv,tick,flag|BCT_ENEMY|1,skill->castend_damage_id); + map->foreachinarea( status->change_timer_sub, + src->m, src->x-r, src->y-r, src->x+r, src->y+r, BL_CHAR, src, NULL, SC_SIGHT, tick); + } break; - case GC_HALLUCINATIONWALK: { - int heal = status_get_max_hp(bl) / 10; + int heal = status_get_max_hp(bl) * ( 18 - 2 * skill_lv ) / 100; if( status_get_hp(bl) < heal ) { // if you haven't enough HP skill fails. if( sd ) clif->skill_fail(sd,skill_id,USESKILL_FAIL_HP_INSUFFICIENT,0); break; } - if( !status_charge(bl,heal,0) ) - { + if( !status->charge(bl,heal,0) ) { if( sd ) clif->skill_fail(sd,skill_id,USESKILL_FAIL_HP_INSUFFICIENT,0); break; } - clif->skill_nodamage(src,bl,skill_id,skill_lv,sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); + clif->skill_nodamage(src,bl,skill_id,skill_lv,sc_start(src,bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); } break; /** @@ -7873,57 +8199,72 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case AB_CLEMENTIA: case AB_CANTO: - { - int bless_lv = pc->checkskill(sd,AL_BLESSING) + (sd->status.job_level / 10); - int agi_lv = pc->checkskill(sd,AL_INCAGI) + (sd->status.job_level / 10); - if( sd == NULL || sd->status.party_id == 0 || flag&1 ) - clif->skill_nodamage(bl, bl, skill_id, skill_lv, sc_start(bl,type,100, - (skill_id == AB_CLEMENTIA)? bless_lv : (skill_id == AB_CANTO)? agi_lv : skill_lv, skill->get_time(skill_id,skill_lv))); - else if( sd ) - party_foreachsamemap(skill->area_sub, sd, skill->get_splash(skill_id, skill_lv), src, skill_id, skill_lv, tick, flag|BCT_PARTY|1, skill->castend_nodamage_id); + { + int level = 0; + if( sd ) + level = skill_id == AB_CLEMENTIA ? pc->checkskill(sd,AL_BLESSING) : pc->checkskill(sd,AL_INCAGI); + if( sd == NULL || sd->status.party_id == 0 || flag&1 ) + clif->skill_nodamage(bl, bl, skill_id, skill_lv, sc_start(src, bl, type, 100, level + (sd?(sd->status.job_level / 10):0), skill->get_time(skill_id,skill_lv))); + else if( sd ) { + if( !level ) + clif->skill_fail(sd,skill_id,USESKILL_FAIL,0); + else + party->foreachsamemap(skill->area_sub, sd, skill->get_splash(skill_id, skill_lv), src, skill_id, skill_lv, tick, flag|BCT_PARTY|1, skill->castend_nodamage_id); } + } break; case AB_PRAEFATIO: - if( sd == NULL || sd->status.party_id == 0 || flag&1 ) - clif->skill_nodamage(bl, bl, skill_id, skill_lv, sc_start4(bl, type, 100, skill_lv, 0, 0, 1, skill->get_time(skill_id, skill_lv))); - else if( sd ) - party_foreachsamemap(skill->area_sub, sd, skill->get_splash(skill_id, skill_lv), src, skill_id, skill_lv, tick, flag|BCT_PARTY|1, skill->castend_nodamage_id); - break; + if( (flag&1) || sd == NULL || sd->status.party_id == 0 ) { + int count = 1; + + if( dstsd && dstsd->special_state.no_magic_damage ) + break; + + if( sd && sd->status.party_id != 0 ) + count = party->foreachsamemap(party->sub_count, sd, 0); + clif->skill_nodamage(bl, bl, skill_id, skill_lv, + sc_start4(src, bl, type, 100, skill_lv, 0, 0, count, skill->get_time(skill_id, skill_lv))); + } else if( sd ) + party->foreachsamemap(skill->area_sub, sd, skill->get_splash(skill_id, skill_lv), src, skill_id, skill_lv, tick, flag|BCT_PARTY|1, skill->castend_nodamage_id); + break; case AB_CHEAL: if( sd == NULL || sd->status.party_id == 0 || flag&1 ) { - if( sd && tstatus && !battle->check_undead(tstatus->race, tstatus->def_ele) ) { - i = skill->calc_heal(src, bl, AL_HEAL, pc->checkskill(sd, AL_HEAL), true); - - if( (dstsd && pc_ismadogear(dstsd)) || status_isimmune(bl)) - i = 0; // Should heal by 0 or won't do anything?? in iRO it breaks the healing to members.. [malufett] + if( sd && tstatus && !battle->check_undead(tstatus->race, tstatus->def_ele) && !tsc->data[SC_BERSERK] ) { + int lv = pc->checkskill(sd, AL_HEAL); + int heal = skill_calc_heal(src, bl, AL_HEAL, lv, true); + + if( sd->status.party_id ) { + int partycount = party->foreachsamemap(party->sub_count, sd, 0); + if (partycount > 1) + heal += ((heal / 100) * (partycount * 10) / 4); + } + if( status->isimmune(bl) || (dstsd && pc_ismadogear(dstsd)) ) + heal = 0; - clif->skill_nodamage(bl, bl, skill_id, i, 1); - if( tsc && tsc->data[SC_AKAITSUKI] && i ) - i = ~i + 1; - status_heal(bl, i, 0, 0); + clif->skill_nodamage(bl, bl, skill_id, heal, 1); + if( tsc && tsc->data[SC_AKAITSUKI] && heal ) + heal = ~heal + 1; + status->heal(bl, heal, 0, 1); } - } - else if( sd ) - party_foreachsamemap(skill->area_sub, sd, skill->get_splash(skill_id, skill_lv), src, skill_id, skill_lv, tick, flag|BCT_PARTY|1, skill->castend_nodamage_id); + } else if( sd ) + party->foreachsamemap(skill->area_sub, sd, skill->get_splash(skill_id, skill_lv), src, skill_id, skill_lv, tick, flag|BCT_PARTY|1, skill->castend_nodamage_id); break; - case AB_ORATIO: if( flag&1 ) - sc_start(bl, type, 40 + 5 * skill_lv, skill_lv, skill->get_time(skill_id, skill_lv)); - else - { - iMap->foreachinrange(skill->area_sub, src, skill->get_splash(skill_id, skill_lv), BL_CHAR, + sc_start(src, bl, type, 40 + 5 * skill_lv, skill_lv, skill->get_time(skill_id, skill_lv)); + else { + map->foreachinrange(skill->area_sub, src, skill->get_splash(skill_id, skill_lv), BL_CHAR, src, skill_id, skill_lv, tick, flag|BCT_ENEMY|1, skill->castend_nodamage_id); clif->skill_nodamage(src, bl, skill_id, skill_lv, 1); } break; case AB_LAUDAAGNUS: - if( flag&1 || sd == NULL ) { + if( (flag&1 || sd == NULL) || !sd->status.party_id) { if( tsc && (tsc->data[SC_FREEZE] || tsc->data[SC_STONE] || tsc->data[SC_BLIND] || - tsc->data[SC_BURNING] || tsc->data[SC_FROSTMISTY] || tsc->data[SC_CRYSTALIZE])) { + tsc->data[SC_BURNING] || tsc->data[SC_FROSTMISTY] || tsc->data[SC_COLD])) { // Success Chance: (40 + 10 * Skill Level) % if( rnd()%100 > 40+10*skill_lv ) break; status_change_end(bl, SC_FREEZE, INVALID_TIMER); @@ -7931,50 +8272,57 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui status_change_end(bl, SC_BLIND, INVALID_TIMER); status_change_end(bl, SC_BURNING, INVALID_TIMER); status_change_end(bl, SC_FROSTMISTY, INVALID_TIMER); - status_change_end(bl, SC_CRYSTALIZE, INVALID_TIMER); + status_change_end(bl, SC_COLD, INVALID_TIMER); }else //Success rate only applies to the curing effect and not stat bonus. Bonus status only applies to non infected targets clif->skill_nodamage(bl, bl, skill_id, skill_lv, - sc_start(bl, type, 100, skill_lv, skill->get_time(skill_id, skill_lv))); + sc_start(src, bl, type, 100, skill_lv, skill->get_time(skill_id, skill_lv))); } else if( sd ) - party_foreachsamemap(skill->area_sub, sd, skill->get_splash(skill_id, skill_lv), + party->foreachsamemap(skill->area_sub, sd, skill->get_splash(skill_id, skill_lv), src, skill_id, skill_lv, tick, flag|BCT_PARTY|1, skill->castend_nodamage_id); break; case AB_LAUDARAMUS: - if( flag&1 || sd == NULL ) { - if( tsc && (tsc->data[SC_SLEEP] || tsc->data[SC_STUN] || tsc->data[SC_MANDRAGORA] || tsc->data[SC_SILENCE]) ){ + if( (flag&1 || sd == NULL) || !sd->status.party_id ) { + if( tsc && (tsc->data[SC_SLEEP] || tsc->data[SC_STUN] || tsc->data[SC_MANDRAGORA] || + tsc->data[SC_SILENCE] || tsc->data[SC_DEEP_SLEEP]) ){ // Success Chance: (40 + 10 * Skill Level) % if( rnd()%100 > 40+10*skill_lv ) break; status_change_end(bl, SC_SLEEP, INVALID_TIMER); status_change_end(bl, SC_STUN, INVALID_TIMER); status_change_end(bl, SC_MANDRAGORA, INVALID_TIMER); status_change_end(bl, SC_SILENCE, INVALID_TIMER); + status_change_end(bl, SC_DEEP_SLEEP, INVALID_TIMER); }else // Success rate only applies to the curing effect and not stat bonus. Bonus status only applies to non infected targets clif->skill_nodamage(bl, bl, skill_id, skill_lv, - sc_start(bl, type, 100, skill_lv, skill->get_time(skill_id, skill_lv))); + sc_start(src, bl, type, 100, skill_lv, skill->get_time(skill_id, skill_lv))); } else if( sd ) - party_foreachsamemap(skill->area_sub, sd, skill->get_splash(skill_id, skill_lv), + party->foreachsamemap(skill->area_sub, sd, skill->get_splash(skill_id, skill_lv), src, skill_id, skill_lv, tick, flag|BCT_PARTY|1, skill->castend_nodamage_id); break; case AB_CLEARANCE: - if( flag&1 || (i = skill->get_splash(skill_id, skill_lv)) < 1 ) - { //As of the behavior in official server Clearance is just a super version of Dispell skill. [Jobbie] + { + int splash; + if( flag&1 || (splash = skill->get_splash(skill_id, skill_lv)) < 1 ) { + int i; + //As of the behavior in official server Clearance is just a super version of Dispell skill. [Jobbie] + if( bl->type != BL_MOB && battle->check_target(src,bl,BCT_PARTY) <= 0 ) // Only affect mob or party. + break; + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - if((dstsd && (dstsd->class_&MAPID_UPPERMASK) == MAPID_SOUL_LINKER) || rnd()%100 >= 30 + 10 * skill_lv) - { + + if((dstsd && (dstsd->class_&MAPID_UPPERMASK) == MAPID_SOUL_LINKER) || rnd()%100 >= 60 + 8 * skill_lv) { if (sd) clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); break; } - if(status_isimmune(bl) || !tsc || !tsc->count) + if(status->isimmune(bl) || !tsc || !tsc->count) break; - for(i = 0; i < SC_MAX; i++) - { + for(i = 0; i < SC_MAX; i++) { if ( !tsc->data[i] ) continue; if( SC_COMMON_MAX > i ) - if ( status_get_sc_type(i)&SC_NO_CLEARANCE ) + if ( status->get_sc_type(i)&SC_NO_CLEARANCE ) continue; switch (i) { case SC_ASSUMPTIO: @@ -7989,13 +8337,15 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui status_change_end(bl,(sc_type)i,INVALID_TIMER); } break; + } else { + map->foreachinrange(skill->area_sub, bl, splash, BL_CHAR, src, skill_id, skill_lv, tick, flag|1, skill->castend_damage_id); } - iMap->foreachinrange(skill->area_sub, bl, i, BL_CHAR, src, skill_id, skill_lv, tick, flag|1, skill->castend_damage_id); + } break; case AB_SILENTIUM: // Should the level of Lex Divina be equivalent to the level of Silentium or should the highest level learned be used? [LimitLine] - iMap->foreachinrange(skill->area_sub, src, skill->get_splash(skill_id, skill_lv), BL_CHAR, + map->foreachinrange(skill->area_sub, src, skill->get_splash(skill_id, skill_lv), BL_CHAR, src, PR_LEXDIVINA, skill_lv, tick, flag|BCT_ENEMY|1, skill->castend_nodamage_id); clif->skill_nodamage(src, bl, skill_id, skill_lv, 1); break; @@ -8004,10 +8354,9 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui **/ case WL_STASIS: if( flag&1 ) - sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv)); - else - { - iMap->foreachinrange(skill->area_sub,src,skill->get_splash(skill_id, skill_lv),BL_CHAR,src,skill_id,skill_lv,tick,(map_flag_vs(src->m)?BCT_ALL:BCT_ENEMY|BCT_SELF)|flag|1,skill->castend_nodamage_id); + sc_start(src,bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv)); + else { + map->foreachinrange(skill->area_sub,src,skill->get_splash(skill_id, skill_lv),BL_CHAR,src,skill_id,skill_lv,tick,(map_flag_vs(src->m)?BCT_ALL:BCT_ENEMY|BCT_SELF)|flag|1,skill->castend_nodamage_id); clif->skill_nodamage(src, bl, skill_id, skill_lv, 1); } break; @@ -8022,12 +8371,12 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui else rate += 40 + 10 * skill_lv; // On Monsters, (40 + 10 * Skill Level) % if( sd ) - skill->blockpc_start(sd,skill_id,4000, false); + skill->blockpc_start(sd,skill_id,4000); if( !(tsc && tsc->data[type]) ){ - i = sc_start2(bl,type,rate,skill_lv,src->id,(src == bl)?5000:(bl->type == BL_PC)?skill->get_time(skill_id,skill_lv):skill->get_time2(skill_id, skill_lv)); - clif->skill_nodamage(src,bl,skill_id,skill_lv,i); - if( sd && !i ) + int failure = sc_start2(src,bl,type,rate,skill_lv,src->id,(src == bl)?5000:(bl->type == BL_PC)?skill->get_time(skill_id,skill_lv):skill->get_time2(skill_id, skill_lv)); + clif->skill_nodamage(src,bl,skill_id,skill_lv,failure); + if( sd && !failure ) clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); } }else @@ -8036,33 +8385,37 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui break; case WL_FROSTMISTY: + if( tsc && (tsc->option&(OPTION_HIDE|OPTION_CLOAK|OPTION_CHASEWALK))) + break; // Doesn't hit/cause Freezing to invisible enemy // Really? [Rytech] clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - iMap->foreachinrange(skill->area_sub,bl,skill->get_splash(skill_id,skill_lv),BL_CHAR|BL_SKILL,src,skill_id,skill_lv,tick,flag|BCT_ENEMY,skill->castend_damage_id); + map->foreachinrange(skill->area_sub,bl,skill->get_splash(skill_id,skill_lv),BL_CHAR|BL_SKILL,src,skill_id,skill_lv,tick,flag|BCT_ENEMY,skill->castend_damage_id); break; case WL_JACKFROST: + if( tsc && (tsc->option&(OPTION_HIDE|OPTION_CLOAK|OPTION_CHASEWALK))) + break; // Do not hit invisible enemy clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - iMap->foreachinshootrange(skill->area_sub,bl,skill->get_splash(skill_id,skill_lv),BL_CHAR|BL_SKILL,src,skill_id,skill_lv,tick,flag|BCT_ENEMY|1,skill->castend_damage_id); + map->foreachinshootrange(skill->area_sub,bl,skill->get_splash(skill_id,skill_lv),BL_CHAR|BL_SKILL,src,skill_id,skill_lv,tick,flag|BCT_ENEMY|1,skill->castend_damage_id); break; case WL_MARSHOFABYSS: clif->skill_nodamage(src, bl, skill_id, skill_lv, - sc_start(bl, type, 100, skill_lv, skill->get_time(skill_id, skill_lv))); + sc_start(src, bl, type, 100, skill_lv, skill->get_time(skill_id, skill_lv))); break; case WL_SIENNAEXECRATE: if( flag&1 ) { - if( status_isimmune(bl) || !tsc ) + if( status->isimmune(bl) || !tsc ) break; if( tsc && tsc->data[SC_STONE] ) status_change_end(bl,SC_STONE,INVALID_TIMER); else - status_change_start(bl,SC_STONE,10000,skill_lv,0,0,500,skill->get_time(skill_id, skill_lv),2); + status->change_start(src,bl,SC_STONE,10000,skill_lv,0,0,500,skill->get_time(skill_id, skill_lv),2); } else { int rate = 45 + 5 * skill_lv; if( rnd()%100 < rate ){ clif->skill_nodamage(src, bl, skill_id, skill_lv, 1); - iMap->foreachinrange(skill_area_sub,bl,skill->get_splash(skill_id,skill_lv),BL_CHAR,src,skill_id,skill_lv,tick,flag|BCT_ENEMY|1,skill_castend_nodamage_id); + map->foreachinrange(skill->area_sub,bl,skill->get_splash(skill_id,skill_lv),BL_CHAR,src,skill_id,skill_lv,tick,flag|BCT_ENEMY|1,skill->castend_nodamage_id); }else if( sd ) // Failure on Rate clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); } @@ -8072,19 +8425,23 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case WL_SUMMONBL: case WL_SUMMONWB: case WL_SUMMONSTONE: + { + int i; for( i = SC_SUMMON1; i <= SC_SUMMON5; i++ ){ if( tsc && !tsc->data[i] ){ // officially it doesn't work like a stack int ele = WLS_FIRE + (skill_id - WL_SUMMONFB) - (skill_id == WL_SUMMONSTONE ? 4 : 0); clif->skill_nodamage(src, bl, skill_id, skill_lv, - sc_start(bl, (sc_type)i, 100, ele, skill->get_time(skill_id, skill_lv))); + sc_start(src, bl, (sc_type)i, 100, ele, skill->get_time(skill_id, skill_lv))); break; } } + } break; case WL_READING_SB: if( sd ) { - struct status_change *sc = status_get_sc(bl); + struct status_change *sc = status->get_sc(bl); + int i; for( i = SC_SPELLBOOK1; i <= SC_SPELLBOOK7; i++) if( sc && !sc->data[i] ) @@ -8094,7 +8451,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui break; } - sc_start(bl, SC_STOP, 100, skill_lv, INVALID_TIMER); //Can't move while selecting a spellbook. + sc_start(src, bl, SC_STOP, 100, skill_lv, INVALID_TIMER); //Can't move while selecting a spellbook. clif->spellbook_list(sd); clif->skill_nodamage(src, bl, skill_id, skill_lv, 1); } @@ -8104,7 +8461,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui **/ case RA_FEARBREEZE: clif->skill_damage(src, src, tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6); - clif->skill_nodamage(src, bl, skill_id, skill_lv, sc_start(bl, type, 100, skill_lv, skill->get_time(skill_id, skill_lv))); + clif->skill_nodamage(src, bl, skill_id, skill_lv, sc_start(src, bl, type, 100, skill_lv, skill->get_time(skill_id, skill_lv))); break; case RA_WUGMASTERY: @@ -8133,11 +8490,11 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case RA_WUGDASH: if( tsce ) { clif->skill_nodamage(src,bl,skill_id,skill_lv,status_change_end(bl, type, INVALID_TIMER)); - iMap->freeblock_unlock(); + map->freeblock_unlock(); return 0; } if( sd && pc_isridingwug(sd) ) { - clif->skill_nodamage(src,bl,skill_id,skill_lv,sc_start4(bl,type,100,skill_lv,unit_getdir(bl),0,0,1)); + clif->skill_nodamage(src,bl,skill_id,skill_lv,sc_start4(src,bl,type,100,skill_lv,unit->getdir(bl),0,0,1)); clif->walkok(sd); } break; @@ -8145,7 +8502,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case RA_SENSITIVEKEEN: clif->skill_nodamage(src,bl,skill_id,skill_lv,1); clif->skill_damage(src,src,tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6); - iMap->foreachinrange(skill->area_sub,src,skill->get_splash(skill_id,skill_lv),BL_CHAR|BL_SKILL,src,skill_id,skill_lv,tick,flag|BCT_ENEMY,skill->castend_damage_id); + map->foreachinrange(skill->area_sub,src,skill->get_splash(skill_id,skill_lv),BL_CHAR|BL_SKILL,src,skill_id,skill_lv,tick,flag|BCT_ENEMY,skill->castend_damage_id); break; /** * Mechanic @@ -8153,7 +8510,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case NC_F_SIDESLIDE: case NC_B_SIDESLIDE: { - uint8 dir = (skill_id == NC_F_SIDESLIDE) ? (unit_getdir(src)+4)%8 : unit_getdir(src); + uint8 dir = (skill_id == NC_F_SIDESLIDE) ? (unit->getdir(src)+4)%8 : unit->getdir(src); skill->blown(src,bl,skill->get_blewcount(skill_id,skill_lv),dir,0); clif->slide(src,src->x,src->y); clif->skill_nodamage(src,bl,skill_id,skill_lv,1); @@ -8166,41 +8523,46 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui pc->setmadogear(sd, 0); clif->skill_nodamage(src, bl, skill_id, skill_lv, 1); skill->castend_damage_id(src, src, skill_id, skill_lv, tick, flag); - status_set_sp(src, 0, 0); + status->set_sp(src, 0, 0); } break; case NC_ANALYZE: clif->skill_damage(src, bl, tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6); clif->skill_nodamage(src, bl, skill_id, skill_lv, - sc_start(bl,type, 30 + 12 * skill_lv,skill_lv,skill->get_time(skill_id,skill_lv))); + sc_start(src,bl,type, 30 + 12 * skill_lv,skill_lv,skill->get_time(skill_id,skill_lv))); if( sd ) pc->overheat(sd,1); break; case NC_MAGNETICFIELD: - if( (i = sc_start2(bl,type,100,skill_lv,src->id,skill->get_time(skill_id,skill_lv))) ) + { + int failure; + if( (failure = sc_start2(src,bl,type,100,skill_lv,src->id,skill->get_time(skill_id,skill_lv))) ) { - iMap->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),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,6); if (sd) pc->overheat(sd,1); } - clif->skill_nodamage(src,src,skill_id,skill_lv,i); + clif->skill_nodamage(src,src,skill_id,skill_lv,failure); + } break; case NC_REPAIR: - if( sd ) - { - int heal; - if( dstsd && pc_ismadogear(dstsd) ) - { - heal = dstsd->status.max_hp * (3+3*skill_lv) / 100; - status_heal(bl,heal,0,2); - } else { - heal = sd->status.max_hp * (3+3*skill_lv) / 100; - status_heal(src,heal,0,2); + if( sd ) { + int heal, hp = 0; // % of max hp regen + if( !dstsd || !pc_ismadogear(dstsd) ) { + clif->skill_fail(sd, skill_id,USESKILL_FAIL_TOTARGET,0); + break; } - - clif->skill_damage(src, src, tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6); + switch (cap_value(skill_lv, 1, 5)) { + case 1: hp = 4; break; + case 2: hp = 7; break; + case 3: hp = 13; break; + case 4: hp = 17; break; + case 5: hp = 23; break; + } + heal = tstatus->max_hp * hp / 100; + status->heal(bl,heal,0,2); clif->skill_nodamage(src, bl, skill_id, skill_lv, heal); } break; @@ -8208,7 +8570,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case NC_DISJOINT: { if( bl->type != BL_MOB ) break; - md = iMap->id2md(bl->id); + md = map->id2md(bl->id); if( md && md->class_ >= MOBID_SILVERSNIPER && md->class_ <= MOBID_MAGICDECOY_WIND ) status_kill(bl); clif->skill_nodamage(src, bl, skill_id, skill_lv, 1); @@ -8218,7 +8580,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui if( sd ) { int idx1 = skill->get_index(sd->reproduceskill_id), idx2 = skill->get_index(sd->cloneskill_id); if( sd->status.skill[idx1].id || sd->status.skill[idx2].id ) { - sc_start(src,SC_STOP,100,skill_lv,-1);// The skill_lv is stored in val1 used in skill_select_menu to determine the used skill lvl [Xazax] + sc_start(src,src,SC_STOP,100,skill_lv,-1);// The skill_lv is stored in val1 used in skill_select_menu to determine the used skill lvl [Xazax] clif->autoshadowspell_list(sd); clif->skill_nodamage(src,bl,skill_id,1,1); } @@ -8229,7 +8591,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case SC_SHADOWFORM: if( sd && dstsd && src != bl && !dstsd->shadowform_id ) { - if( clif->skill_nodamage(src,bl,skill_id,skill_lv,sc_start4(src,type,100,skill_lv,bl->id,4+skill_lv,0,skill->get_time(skill_id, skill_lv))) ) + if( clif->skill_nodamage(src,bl,skill_id,skill_lv,sc_start4(src,src,type,100,skill_lv,bl->id,4+skill_lv,0,skill->get_time(skill_id, skill_lv))) ) dstsd->shadowform_id = src->id; } else if( sd ) @@ -8239,171 +8601,171 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case SC_BODYPAINT: if( flag&1 ) { if( tsc && (tsc->data[SC_HIDING] || tsc->data[SC_CLOAKING] || - tsc->data[SC_CHASEWALK] || tsc->data[SC_CLOAKINGEXCEED] || - tsc->data[SC__INVISIBILITY]) ) { + tsc->data[SC_CHASEWALK] || tsc->data[SC_CLOAKINGEXCEED] ) ) { status_change_end(bl, SC_HIDING, INVALID_TIMER); status_change_end(bl, SC_CLOAKING, INVALID_TIMER); status_change_end(bl, SC_CHASEWALK, INVALID_TIMER); status_change_end(bl, SC_CLOAKINGEXCEED, INVALID_TIMER); - status_change_end(bl, SC__INVISIBILITY, INVALID_TIMER); - sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv)); - sc_start(bl,SC_BLIND,53 + 2 * skill_lv,skill_lv,skill->get_time(skill_id,skill_lv)); + sc_start(src,bl,type,20 + 5 * skill_lv,skill_lv,skill->get_time(skill_id,skill_lv)); + sc_start(src,bl,SC_BLIND,53 + 2 * skill_lv,skill_lv,skill->get_time(skill_id,skill_lv)); } } else { clif->skill_nodamage(src, bl, skill_id, 0, 1); - iMap->foreachinrange(skill->area_sub, bl, skill->get_splash(skill_id, skill_lv), BL_CHAR, - src, skill_id, skill_lv, tick, flag|BCT_ENEMY|1, skill->castend_nodamage_id); + map->foreachinrange(skill->area_sub, bl, skill->get_splash(skill_id, skill_lv), BL_CHAR, + src, skill_id, skill_lv, tick, flag|BCT_ENEMY|1, skill->castend_nodamage_id); } break; case SC_ENERVATION: case SC_GROOMY: + case SC_IGNORANCE: case SC_LAZINESS: case SC_UNLUCKY: case SC_WEAKNESS: if( !(tsc && tsc->data[type]) ) { - //((rand(myDEX / 12, myDEX / 4) + myJobLevel + 10 * skLevel) + myLevel / 10) - (targetLevel / 10 + targetLUK / 10 + (targetMaxWeight - targetWeight) / 1000 + rand(targetAGI / 6, targetAGI / 3)) - int rate = rnd_value(sstatus->dex/12,sstatus->dex/4) + 10*skill_lv + (sd?sd->status.job_level:0) + status_get_lv(src)/10 - - status_get_lv(bl)/10 - tstatus->luk/10 - (dstsd?(dstsd->max_weight-dstsd->weight)/10000:0) - rnd_value(tstatus->agi/6,tstatus->agi/3); - rate = cap_value(rate, skill_lv+sstatus->dex/20, 100); - clif->skill_nodamage(src,bl,skill_id,0,sc_start(bl,type,rate,skill_lv,skill->get_time(skill_id,skill_lv))); - } else if( sd ) - clif->skill_fail(sd,skill_id,0,0); - break; - - case SC_IGNORANCE: - if( !(tsc && tsc->data[type]) ) { - int rate = rnd_value(sstatus->dex/12,sstatus->dex/4) + 10*skill_lv + (sd?sd->status.job_level:0) + status_get_lv(src)/10 - - status_get_lv(bl)/10 - tstatus->luk/10 - (dstsd?(dstsd->max_weight-dstsd->weight)/10000:0) - rnd_value(tstatus->agi/6,tstatus->agi/3); - rate = cap_value(rate, skill_lv+sstatus->dex/20, 100); - if (clif->skill_nodamage(src,bl,skill_id,0,sc_start(bl,type,rate,skill_lv,skill->get_time(skill_id,skill_lv)))) { - int sp = 200 * skill_lv; + int joblvbonus = 0; + int rate = 0; + if (is_boss(bl)) break; + joblvbonus = ( sd ? sd->status.job_level : 50 ); + //First we set the success chance based on the caster's build which increases the chance. + rate = 10 * skill_lv + rnd_value( sstatus->dex / 12, sstatus->dex / 4 ) + joblvbonus + status->get_lv(src) / 10; + // We then reduce the success chance based on the target's build. + rate -= rnd_value( tstatus->agi / 6, tstatus->agi / 3 ) + tstatus->luk / 10 + ( dstsd ? (dstsd->max_weight / 10 - dstsd->weight / 10 ) / 100 : 0 ) + status->get_lv(bl) / 10; + //Finally we set the minimum success chance cap based on the caster's skill level and DEX. + rate = cap_value( rate, skill_lv + sstatus->dex / 20, 100); + clif->skill_nodamage(src,bl,skill_id,0,sc_start(src,bl,type,rate,skill_lv,skill->get_time(skill_id,skill_lv))); + if ( tsc && tsc->data[SC__IGNORANCE] && skill_id == SC_IGNORANCE) { + //If the target was successfully inflected with the Ignorance status, drain some of the targets SP. + int sp = 100 * skill_lv; if( dstmd ) sp = dstmd->level * 2; if( status_zap(bl,0,sp) ) - status_heal(src,0,sp/2,3); + status->heal(src,0,sp/2,3);//What does flag 3 do? [Rytech] + } + if ( tsc && tsc->data[SC__UNLUCKY] && skill_id == SC_UNLUCKY) { + //If the target was successfully inflected with the Unlucky status, give 1 of 3 random status's. + switch(rnd()%3) {//Targets in the Unlucky status will be affected by one of the 3 random status's regardless of resistance. + case 0: + status->change_start(src,bl,SC_POISON,10000,skill_lv,0,0,0,skill->get_time(skill_id,skill_lv),10); + break; + case 1: + status->change_start(src,bl,SC_SILENCE,10000,skill_lv,0,0,0,skill->get_time(skill_id,skill_lv),10); + break; + case 2: + status->change_start(src,bl,SC_BLIND,10000,skill_lv,0,0,0,skill->get_time(skill_id,skill_lv),10); + } } - else if( sd ) clif->skill_fail(sd,skill_id,0,0); } else if( sd ) - clif->skill_fail(sd,skill_id,0,0); + clif->skill_fail(sd, skill_id, USESKILL_FAIL_LEVEL, 0); break; case LG_TRAMPLE: clif->skill_damage(src,bl,tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6); - iMap->foreachinrange(skill->destroy_trap,bl,skill->get_splash(skill_id,skill_lv),BL_SKILL,tick); + map->foreachinrange(skill->destroy_trap,bl,skill->get_splash(skill_id,skill_lv),BL_SKILL,tick); break; case LG_REFLECTDAMAGE: if( tsc && tsc->data[type] ) status_change_end(bl,type,INVALID_TIMER); else - sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv)); + sc_start(src,bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv)); clif->skill_nodamage(src,bl,skill_id,skill_lv,1); break; case LG_SHIELDSPELL: + if( !sd ) + break; if( flag&1 ) { - int duration = (sd) ? sd->bonus.shieldmdef * 2000 : 10000; - sc_start(bl,SC_SILENCE,100,skill_lv,duration); - } else if( sd ) { - int opt = skill_lv; - int rate = rnd()%100; - int val, brate; + sc_start(src,bl,SC_SILENCE,100,skill_lv,sd->bonus.shieldmdef * 30000); + } else { + int opt = 0, val = 0, splashrange = 0; + struct item_data *shield_data = sd->inventory_data[sd->equip_index[EQI_HAND_L]]; + if( !shield_data || shield_data->type != IT_ARMOR ) { + //Skill will first check if a shield is equipped. If none is found on the caster the skill will fail. + clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + break; + } + //Generates a number between 1 - 3. The number generated will determine which effect will be triggered. + opt = rnd()%3 + 1; switch( skill_lv ) { case 1: - { - struct item_data *shield_data = sd->inventory_data[sd->equip_index[EQI_HAND_L]]; - if( !shield_data || shield_data->type != IT_ARMOR ) { // No shield? - clif->skill_fail(sd, skill_id, USESKILL_FAIL_LEVEL, 0); + if ( shield_data->def >= 0 && shield_data->def <= 40) + splashrange = 1; + else if ( shield_data->def >= 41 && shield_data->def <= 80) + splashrange = 2; + else + splashrange = 3; + switch( opt ) { + case 1: + sc_start(src,bl,SC_SHIELDSPELL_DEF,100,opt,INVALID_TIMER); //Splash AoE ATK + clif->skill_damage(src,bl,tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6); + map->foreachinrange(skill->area_sub,src,splashrange,BL_CHAR,src,skill_id,skill_lv,tick,flag|BCT_ENEMY|1,skill->castend_damage_id); + status_change_end(bl,SC_SHIELDSPELL_DEF,INVALID_TIMER); + break; + case 2: + val = shield_data->def/10; //Damage Reflecting Increase. + sc_start2(src,bl,SC_SHIELDSPELL_DEF,100,opt,val,shield_data->def * 1000); + break; + case 3: + //Weapon Attack Increase. + val = shield_data->def; + sc_start2(src,bl,SC_SHIELDSPELL_DEF,100,opt,val,shield_data->def * 3000); break; - } - brate = shield_data->def * 10; - if( rate < 50 ) - opt = 1; - else if( rate < 75 ) - opt = 2; - else - opt = 3; - - switch( opt ) { - case 1: - sc_start(bl,SC_SHIELDSPELL_DEF,100,opt,-1); - clif->skill_damage(src,bl,tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6); - if( rate < brate ) - iMap->foreachinrange(skill->area_sub,src,skill->get_splash(skill_id,skill_lv),BL_CHAR,src,skill_id,skill_lv,tick,flag|BCT_ENEMY|1,skill->castend_damage_id); - status_change_end(bl,SC_SHIELDSPELL_DEF,INVALID_TIMER); - break; - case 2: - val = shield_data->def / 10; // % Reflected damage. - sc_start2(bl,SC_SHIELDSPELL_DEF,brate,opt,val,shield_data->def * 1000); - break; - case 3: - val = shield_data->def; // Attack increase. - sc_start2(bl,SC_SHIELDSPELL_DEF,brate,opt,val,shield_data->def * 3000); - break; - } } break; - case 2: - brate = sd->bonus.shieldmdef * 20; - if( rate < 30 ) - opt = 1; - else if( rate < 60 ) - opt = 2; + if( sd->bonus.shieldmdef == 0 ) + break; // Nothing should happen if the shield has no mdef, not even displaying a message + if ( sd->bonus.shieldmdef >= 1 && sd->bonus.shieldmdef <= 3 ) + splashrange = 1; + else if ( sd->bonus.shieldmdef >= 4 && sd->bonus.shieldmdef <= 5 ) + splashrange = 2; else - opt = 3; + splashrange = 3; switch( opt ) { case 1: - sc_start(bl,SC_SHIELDSPELL_MDEF,100,opt,-1); + sc_start(src,bl,SC_SHIELDSPELL_MDEF,100,opt,INVALID_TIMER); //Splash AoE MATK clif->skill_damage(src,bl,tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6); - if( rate < brate ) - iMap->foreachinrange(skill->area_sub,src,skill->get_splash(skill_id,skill_lv),BL_CHAR,src,skill_id,skill_lv,tick,flag|BCT_ENEMY|2,skill->castend_damage_id); + map->foreachinrange(skill->area_sub,src,splashrange,BL_CHAR,src,skill_id,skill_lv,tick,flag|BCT_ENEMY|1,skill->castend_damage_id); status_change_end(bl,SC_SHIELDSPELL_MDEF,INVALID_TIMER); break; case 2: - sc_start(bl,SC_SHIELDSPELL_MDEF,100,opt,-1); - clif->skill_damage(src,bl,tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6); - if( rate < brate ) - iMap->foreachinrange(skill->area_sub,src,skill->get_splash(skill_id,skill_lv),BL_CHAR,src,skill_id,skill_lv,tick,flag|BCT_ENEMY|1,skill->castend_nodamage_id); + sc_start(src,bl,SC_SHIELDSPELL_MDEF,100,opt,sd->bonus.shieldmdef * 2000); //Splash AoE Lex Divina + clif->skill_damage(src,bl,tick,status_get_amotion(src),0,-30000,1,skill_id,skill_lv,6); + map->foreachinrange(skill->area_sub,src,splashrange,BL_CHAR,src,skill_id,skill_lv,tick,flag|BCT_ENEMY|1,skill->castend_nodamage_id); break; case 3: - if( sc_start(bl,SC_SHIELDSPELL_MDEF,brate,opt,sd->bonus.shieldmdef * 30000) ) + if( sc_start(src,bl,SC_SHIELDSPELL_MDEF,100,opt,sd->bonus.shieldmdef * 30000) ) //Magnificat clif->skill_nodamage(src,bl,PR_MAGNIFICAT,skill_lv, - sc_start(bl,SC_MAGNIFICAT,100,1,sd->bonus.shieldmdef * 30000)); + sc_start(src,bl,SC_MAGNIFICAT,100,1,sd->bonus.shieldmdef * 30000)); break; } break; - case 3: { - struct item *it = &sd->status.inventory[sd->equip_index[EQI_HAND_L]]; - if( !it ) { // No shield? - clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - break; - } - brate = it->refine * 5; - if( rate < 25 ) - opt = 1; - else if( rate < 50 ) - opt = 2; - else - opt = 3; + int rate = 0; + struct item *shield = &sd->status.inventory[sd->equip_index[EQI_HAND_L]]; + + if( shield->refine == 0 ) + break; // Nothing should happen if the shield has no refine, not even displaying a message + switch( opt ) { case 1: - val = 105 * it->refine / 10; - sc_start2(bl,SC_SHIELDSPELL_REF,brate,opt,val,skill->get_time(skill_id,skill_lv)); + sc_start(src,bl,SC_SHIELDSPELL_REF,100,opt,shield->refine * 30000); //Now breaks Armor at 100% rate break; - case 2: case 3: - if( rate < brate ) - { - val = sstatus->max_hp * (11 + it->refine) / 100; - status_heal(bl, val, 0, 3); - } + case 2: + val = shield->refine * 10 * status->get_lv(src) / 100; //DEF Increase + rate = (shield->refine * 2) + (status_get_luk(src) / 10); //Status Resistance Rate + if( sc_start2(src,bl,SC_SHIELDSPELL_REF,100,opt,val,shield->refine * 20000)) + clif->skill_nodamage(src,bl,SC_SCRESIST,skill_lv, + sc_start(src,bl,SC_SCRESIST,100,rate,shield->refine * 30000)); + break; + case 3: + sc_start(src,bl,SC_SHIELDSPELL_REF,100,opt,INVALID_TIMER); //HP Recovery + val = sstatus->max_hp * ((status->get_lv(src) / 10) + (shield->refine + 1)) / 100; + status->heal(bl, val, 0, 2); + status_change_end(bl,SC_SHIELDSPELL_REF,INVALID_TIMER); break; - /*case 3: - // Full protection. I need confirm what effect should be here. Moved to case 2 to until we got it. - break;*/ } } break; @@ -8414,16 +8776,17 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case LG_PIETY: if( flag&1 ) - sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv)); + sc_start(src,bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv)); else { - skill_area_temp[2] = 0; - iMap->foreachinrange(skill->area_sub,bl,skill->get_splash(skill_id,skill_lv),BL_PC,src,skill_id,skill_lv,tick,flag|SD_PREAMBLE|BCT_PARTY|BCT_SELF|1,skill->castend_nodamage_id); + skill->area_temp[2] = 0; + map->foreachinrange(skill->area_sub,bl,skill->get_splash(skill_id,skill_lv),BL_PC,src,skill_id,skill_lv,tick,flag|SD_PREAMBLE|BCT_PARTY|BCT_SELF|1,skill->castend_nodamage_id); clif->skill_nodamage(src,bl,skill_id,skill_lv,1); } break; case LG_KINGS_GRACE: if( flag&1 ){ - sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv)); + int i; + sc_start(src,bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv)); for(i=0; i<SC_MAX; i++) { if (!tsc->data[i]) @@ -8435,75 +8798,76 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case SC_BLOODING: case SC_CURSE: case SC_CONFUSION: case SC_ILLUSION: case SC_SILENCE: case SC_BURNING: - case SC_CRYSTALIZE: case SC_FROSTMISTY: + case SC_COLD: case SC_FROSTMISTY: case SC_DEEP_SLEEP: case SC_FEAR: - case SC_MANDRAGORA: + case SC_MANDRAGORA: case SC__CHAOS: status_change_end(bl, (sc_type)i, INVALID_TIMER); } } }else { - skill_area_temp[2] = 0; + skill->area_temp[2] = 0; if( !map_flag_vs(src->m) && !map_flag_gvg(src->m) ) flag |= BCT_GUILD; - iMap->foreachinrange(skill->area_sub,bl,skill->get_splash(skill_id,skill_lv),BL_PC,src,skill_id,skill_lv,tick,flag|SD_PREAMBLE|BCT_PARTY|BCT_SELF|1,skill->castend_nodamage_id); + map->foreachinrange(skill->area_sub,bl,skill->get_splash(skill_id,skill_lv),BL_PC,src,skill_id,skill_lv,tick,flag|SD_PREAMBLE|BCT_PARTY|BCT_SELF|1,skill->castend_nodamage_id); clif->skill_nodamage(src,bl,skill_id,skill_lv,1); } break; case LG_INSPIRATION: - if( sd && !map[sd->bl.m].flag.noexppenalty && sd->status.base_level != MAX_LEVEL ) { + if( sd && !map->list[sd->bl.m].flag.noexppenalty && sd->status.base_level != MAX_LEVEL ) { sd->status.base_exp -= min(sd->status.base_exp, pc->nextbaseexp(sd) * 1 / 100); // 1% penalty. sd->status.job_exp -= min(sd->status.job_exp, pc->nextjobexp(sd) * 1 / 100); clif->updatestatus(sd,SP_BASEEXP); clif->updatestatus(sd,SP_JOBEXP); } clif->skill_nodamage(bl,src,skill_id,skill_lv, - sc_start(bl, type, 100, skill_lv, skill->get_time(skill_id, skill_lv))); + sc_start(src,bl, type, 100, skill_lv, skill->get_time(skill_id, skill_lv))); break; case SR_CURSEDCIRCLE: if( flag&1 ) { if( is_boss(bl) ) break; - if( sc_start2(bl, type, 100, skill_lv, src->id, skill->get_time(skill_id, skill_lv))) { + if( sc_start2(src,bl, type, 100, skill_lv, src->id, skill->get_time(skill_id, skill_lv))) { if( bl->type == BL_MOB ) - mob_unlocktarget((TBL_MOB*)bl,iTimer->gettick()); - unit_stop_attack(bl); + mob->unlocktarget((TBL_MOB*)bl,timer->gettick()); + unit->stop_attack(bl); clif->bladestop(src, bl->id, 1); - iMap->freeblock_unlock(); + map->freeblock_unlock(); return 1; } } else { int count = 0; clif->skill_damage(src, bl, tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6); - count = iMap->forcountinrange(skill->area_sub, src, skill->get_splash(skill_id,skill_lv), (sd)?sd->spiritball_old:15, // Assume 15 spiritballs in non-charactors + count = map->forcountinrange(skill->area_sub, src, skill->get_splash(skill_id,skill_lv), (sd)?sd->spiritball_old:15, // Assume 15 spiritballs in non-characters BL_CHAR, src, skill_id, skill_lv, tick, flag|BCT_ENEMY|1, skill->castend_nodamage_id); if( sd ) pc->delspiritball(sd, count, 0); clif->skill_nodamage(src, src, skill_id, skill_lv, - sc_start2(src, SC_CURSEDCIRCLE_ATKER, 100, skill_lv, count, skill->get_time(skill_id,skill_lv))); + sc_start2(src, src, SC_CURSEDCIRCLE_ATKER, 100, skill_lv, count, skill->get_time(skill_id,skill_lv))); } break; case SR_RAISINGDRAGON: if( sd ) { short max = 5 + skill_lv; - sc_start(bl, SC_EXPLOSIONSPIRITS, 100, skill_lv, skill->get_time(skill_id, skill_lv)); + int i; + sc_start(src, bl, SC_EXPLOSIONSPIRITS, 100, skill_lv, skill->get_time(skill_id, skill_lv)); for( i = 0; i < max; i++ ) // Don't call more than max available spheres. pc->addspiritball(sd, skill->get_time(skill_id, skill_lv), max); - clif->skill_nodamage(src, bl, skill_id, skill_lv, sc_start(bl, type, 100, skill_lv,skill->get_time(skill_id, skill_lv))); + clif->skill_nodamage(src, bl, skill_id, skill_lv, sc_start(src, bl, type, 100, skill_lv,skill->get_time(skill_id, skill_lv))); } break; case SR_ASSIMILATEPOWER: if( flag&1 ) { - i = 0; + int sp = 0; if( dstsd && dstsd->spiritball && (sd == dstsd || map_flag_vs(src->m)) && (dstsd->class_&MAPID_BASEMASK)!=MAPID_GUNSLINGER ) { - i = dstsd->spiritball; //1%sp per spiritball. + sp = dstsd->spiritball; //1%sp per spiritball. pc->delspiritball(dstsd, dstsd->spiritball, 0); + status_percent_heal(src, 0, sp); } - if( i ) status_percent_heal(src, 0, i); - clif->skill_nodamage(src, bl, skill_id, skill_lv, i ? 1:0); + 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, 6); - iMap->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), splash_target(src), src, skill_id, skill_lv, tick, flag|BCT_ENEMY|BCT_SELF|SD_SPLASH|1, skill->castend_nodamage_id); } break; @@ -8511,6 +8875,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui if( !dstsd ) break; if( sd && dstsd->spiritball <= 5 ) { + int i; for(i = 0; i <= 5; i++) { pc->addspiritball(dstsd, skill->get_time(MO_CALLSPIRITS, pc->checkskill(sd,MO_CALLSPIRITS)), i); pc->delspiritball(sd, sd->spiritball, 0); @@ -8523,24 +8888,22 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui { int heal; - if( status_isimmune(bl) ) - { + if( status->isimmune(bl) ) { clif->skill_nodamage(src,bl,skill_id,skill_lv,0); break; } heal = 120 * skill_lv + status_get_max_hp(bl) * (2 + skill_lv) / 100; - status_heal(bl, heal, 0, 0); + status->heal(bl, heal, 0, 0); - if( (tsc && tsc->opt1) && (rnd()%100 < ((skill_lv * 5) + (status_get_dex(src) + status_get_lv(src)) / 4) - (1 + (rnd() % 10))) ) - { + if( (tsc && tsc->opt1) && (rnd()%100 < ((skill_lv * 5) + (status_get_dex(src) + status->get_lv(src)) / 4) - (1 + (rnd() % 10))) ) { status_change_end(bl, SC_STONE, INVALID_TIMER); status_change_end(bl, SC_FREEZE, INVALID_TIMER); status_change_end(bl, SC_STUN, INVALID_TIMER); status_change_end(bl, SC_POISON, INVALID_TIMER); status_change_end(bl, SC_SILENCE, INVALID_TIMER); status_change_end(bl, SC_BLIND, INVALID_TIMER); - status_change_end(bl, SC_ILLUSION, INVALID_TIMER); + status_change_end(bl, SC_ILLUSION, INVALID_TIMER); status_change_end(bl, SC_BURNING, INVALID_TIMER); status_change_end(bl, SC_FROSTMISTY, INVALID_TIMER); } @@ -8551,146 +8914,156 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case SR_GENTLETOUCH_CHANGE: case SR_GENTLETOUCH_REVITALIZE: clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start2(bl,type,100,skill_lv,src->id,skill->get_time(skill_id,skill_lv))); + sc_start2(src,bl,type,100,skill_lv,bl->id,skill->get_time(skill_id,skill_lv))); break; case SR_FLASHCOMBO: - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - for(i = SR_FLASHCOMBO_ATK_STEP1; i <= SR_FLASHCOMBO_ATK_STEP4; i++) - skill->addtimerskill(src, tick + 500 * (i - SR_FLASHCOMBO_ATK_STEP1), bl->id, 0, 0, i, skill_lv, BF_WEAPON, flag|SD_LEVEL); - break; - case WA_SWING_DANCE: - case WA_MOONLIT_SERENADE: - if( sd == NULL || sd->status.party_id == 0 || (flag & 1) ) - sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv)); - else if( sd ) { // Only shows effects on caster. - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - party_foreachsamemap(skill->area_sub, sd, skill->get_splash(skill_id, skill_lv), src, skill_id, skill_lv, tick, flag|BCT_PARTY|1, skill->castend_nodamage_id); - } - break; + { + const int combo[] = { + SR_DRAGONCOMBO, SR_FALLENEMPIRE, SR_TIGERCANNON, SR_SKYNETBLOW + }; + int i; + + clif->skill_nodamage(src,bl,skill_id,skill_lv, + sc_start2(src,bl,type,100,skill_lv,bl->id,skill->get_time(skill_id,skill_lv))); + + for( i = 0; i < ARRAYLENGTH(combo); i++ ) + skill->addtimerskill(src, tick + 400 * i, bl->id, 0, 0, combo[i], skill_lv, BF_WEAPON, flag|SD_LEVEL); + break; + } + case WA_SWING_DANCE: case WA_SYMPHONY_OF_LOVER: + case WA_MOONLIT_SERENADE: case MI_RUSH_WINDMILL: case MI_ECHOSONG: - if( sd == NULL || sd->status.party_id == 0 || (flag & 1) ) - sc_start4(bl,type,100,skill_lv,6*skill_lv,(sd?pc->checkskill(sd,WM_LESSON):0),(sd?sd->status.job_level:0),skill->get_time(skill_id,skill_lv)); - else if( sd ) { // Only shows effects on caster. + if( flag&1 ) + sc_start2(src,bl,type,100,skill_lv,(sd?pc->checkskill(sd,WM_LESSON):0),skill->get_time(skill_id,skill_lv)); + else if( sd ) { + party->foreachsamemap(skill->area_sub,sd,skill->get_splash(skill_id,skill_lv),src,skill_id,skill_lv,tick,flag|BCT_PARTY|1,skill->castend_nodamage_id); + sc_start2(src,bl,type,100,skill_lv,pc->checkskill(sd,WM_LESSON),skill->get_time(skill_id,skill_lv)); clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - party_foreachsamemap(skill->area_sub, sd, skill->get_splash(skill_id, skill_lv), src, skill_id, skill_lv, tick, flag|BCT_PARTY|1, skill->castend_nodamage_id); } break; case MI_HARMONIZE: - if( src != bl ) - clif->skill_nodamage(src, src, skill_id, skill_lv, sc_start(src, type, 100, skill_lv, skill->get_time(skill_id,skill_lv))); - clif->skill_nodamage(src, bl, skill_id, skill_lv, sc_start(bl, type, 100, skill_lv, skill->get_time(skill_id,skill_lv))); + clif->skill_nodamage(src,bl,skill_id,skill_lv,sc_start2(src,bl,type,100,skill_lv,(sd?pc->checkskill(sd,WM_LESSON):1),skill->get_time(skill_id,skill_lv))); break; case WM_DEADHILLHERE: if( bl->type == BL_PC ) { - if( !status_isdead(bl) ) + if( !status->isdead(bl) ) break; if( rnd()%100 < 88 + 2 * skill_lv ) { - int heal = tstatus->sp; - if( heal <= 0 ) + int heal = 0; + status_zap(bl, 0, tstatus->sp * (60 - 10 * skill_lv) / 100); + heal = tstatus->sp; + if ( heal <= 0 ) heal = 1; - tstatus->hp = heal; - tstatus->sp -= tstatus->sp * ( 120 - 20 * skill_lv ) / 100; + status->fixed_revive(bl, heal, 0); clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - pc->revive((TBL_PC*)bl,heal,0); - clif->resurrection(bl,1); + status->set_sp(bl, 0, 0); } } break; + case WM_LULLABY_DEEPSLEEP: + if ( flag&1 ) + sc_start2(src,bl,type,100,skill_lv,src->id,skill->get_time(skill_id,skill_lv)); + else if ( sd ) { + int rate = 4 * skill_lv + 2 * pc->checkskill(sd,WM_LESSON) + status->get_lv(src)/15 + sd->status.job_level/5; + if ( rnd()%100 < rate ) { + flag |= BCT_PARTY|BCT_GUILD; + map->foreachinrange(skill->area_sub, src, skill->get_splash(skill_id,skill_lv),BL_CHAR|BL_NPC|BL_SKILL, src, skill_id, skill_lv, tick, flag|BCT_ENEMY|1, skill->castend_nodamage_id); + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + status_change_end(bl, SC_DEEP_SLEEP, INVALID_TIMER); + } + } + break; case WM_SIRCLEOFNATURE: flag |= BCT_SELF|BCT_PARTY|BCT_GUILD; case WM_VOICEOFSIREN: if( skill_id != WM_SIRCLEOFNATURE ) flag &= ~BCT_SELF; if( flag&1 ) { - sc_start2(bl,type,(skill_id==WM_VOICEOFSIREN)?20+10*skill_lv:100,skill_lv,(skill_id==WM_VOICEOFSIREN)?src->id:0,skill->get_time(skill_id,skill_lv)); - } else { - iMap->foreachinrange(skill->area_sub, src, skill->get_splash(skill_id,skill_lv),(skill_id==WM_VOICEOFSIREN)?BL_CHAR|BL_SKILL:BL_PC, src, skill_id, skill_lv, tick, flag|BCT_ENEMY|1, skill->castend_nodamage_id); - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + sc_start2(src,bl,type,100,skill_lv,(skill_id==WM_VOICEOFSIREN)?src->id:0,skill->get_time(skill_id,skill_lv)); + } else if( sd ) { + int rate = 6 * skill_lv + pc->checkskill(sd,WM_LESSON) + sd->status.job_level/2; + if ( rnd()%100 < rate ) { + flag |= BCT_PARTY|BCT_GUILD; + map->foreachinrange(skill->area_sub, src, skill->get_splash(skill_id,skill_lv),(skill_id==WM_VOICEOFSIREN)?BL_CHAR|BL_NPC|BL_SKILL:BL_PC, src, skill_id, skill_lv, tick, flag|BCT_ENEMY|1, skill->castend_nodamage_id); + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + status_change_end(bl, SC_SIREN, INVALID_TIMER); + } } break; case WM_GLOOMYDAY: - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - if( dstsd && ( pc->checkskill(dstsd,KN_BRANDISHSPEAR) || pc->checkskill(dstsd,LK_SPIRALPIERCE) || - pc->checkskill(dstsd,CR_SHIELDCHARGE) || pc->checkskill(dstsd,CR_SHIELDBOOMERANG) || - pc->checkskill(dstsd,PA_SHIELDCHAIN) || pc->checkskill(dstsd,LG_SHIELDPRESS) ) ) - { - sc_start(bl,SC_GLOOMYDAY_SK,100,skill_lv,skill->get_time(skill_id,skill_lv)); - break; - } - sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv)); - break; - - case WM_SATURDAY_NIGHT_FEVER: - if( flag&1 ) { // Affect to all targets arround the caster and caster too. - if( !(tsc && tsc->data[type]) ) - sc_start(bl, type, 100, skill_lv,skill->get_time(skill_id, skill_lv)); - } else if( flag&2 ) { - if( src->id != bl->id && battle->check_target(src,bl,BCT_ENEMY) > 0 ) - status_fix_damage(src,bl,9999,clif->damage(src,bl,tick,0,0,9999,0,0,0)); - } else if( sd ) { - short chance = sstatus->int_/6 + sd->status.job_level/5 + skill_lv*4; - if( !sd->status.party_id || (rnd()%100 > chance)) { - clif->skill_fail(sd,skill_id,USESKILL_FAIL_NEED_HELPER,0); - break; - } - if( iMap->foreachinrange(skill->area_sub, bl, skill->get_splash(skill_id,skill_lv), - BL_PC, src, skill_id, skill_lv, tick, BCT_ENEMY, skill->area_sub_count) > 7 ) - flag |= 2; - else - flag |= 1; - iMap->foreachinrange(skill->area_sub, src, skill->get_splash(skill_id,skill_lv),BL_PC, src, skill_id, skill_lv, tick, flag|BCT_ENEMY|BCT_SELF, skill->castend_nodamage_id); - clif->skill_nodamage(src, bl, skill_id, skill_lv, - sc_start(src,SC_STOP,100,skill_lv,skill->get_time2(skill_id,skill_lv))); - if( flag&2 ) // Dealed here to prevent conflicts - status_fix_damage(src,bl,9999,clif->damage(src,bl,tick,0,0,9999,0,0,0)); + if ( tsc && tsc->data[type] ) { + clif->skill_fail(sd, skill_id, USESKILL_FAIL_LEVEL, 0); + break; } + // val4 indicates caster's voice lesson level + sc_start4(src,bl,type,100,skill_lv, 0, 0, sd?pc->checkskill(sd,WM_LESSON):10, skill->get_time(skill_id,skill_lv)); + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); break; case WM_SONG_OF_MANA: case WM_DANCE_WITH_WUG: case WM_LERADS_DEW: - if( flag&1 ) { // These affect to to all party members near the caster. - struct status_change *sc = status_get_sc(src); - if( sc && sc->data[type] ) { - sc_start2(bl,type,100,skill_lv,sc->data[type]->val2,skill->get_time(skill_id,skill_lv)); - } - } else if( sd ) { - short lv = (short)skill_lv; - int count = skill->check_pc_partner(sd,skill_id,&lv,skill->get_splash(skill_id,skill_lv),1); - if( sc_start2(bl,type,100,skill_lv,count,skill->get_time(skill_id,skill_lv)) ) - party_foreachsamemap(skill->area_sub,sd,skill->get_splash(skill_id,skill_lv),src,skill_id,skill_lv,tick,flag|BCT_PARTY|1,skill->castend_nodamage_id); + case WM_UNLIMITED_HUMMING_VOICE: + { + int chorusbonus = battle->calc_chorusbonus(sd); + if( flag&1 ) + sc_start2(src,bl,type,100,skill_lv,chorusbonus,skill->get_time(skill_id,skill_lv)); + else if( sd ) { + party->foreachsamemap(skill->area_sub,sd,skill->get_splash(skill_id,skill_lv),src,skill_id,skill_lv,tick,flag|BCT_PARTY|1,skill->castend_nodamage_id); + sc_start2(src,bl,type,100,skill_lv,chorusbonus,skill->get_time(skill_id,skill_lv)); clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - } + } + break; + case WM_SATURDAY_NIGHT_FEVER: + { + if( flag&1 ) { + int madnesscheck = 0; + if ( sd )//Required to check if the lord of madness effect will be applied. + madnesscheck = map->foreachinrange(skill->area_sub, src, skill->get_splash(skill_id,skill_lv),BL_PC, src, skill_id, skill_lv, tick, flag|BCT_ENEMY, skill->area_sub_count); + sc_start(src, bl, type, 100, skill_lv,skill->get_time(skill_id, skill_lv)); + if ( madnesscheck >= 8 )//The god of madness deals 9999 fixed unreduceable damage when 8 or more enemy players are affected. + status_fix_damage(src, bl, 9999, clif->damage(src, bl, 0, 0, 9999, 0, 0, 0)); + //skill->attack(BF_MISC,src,src,bl,skillid,skilllv,tick,flag);//To renable when I can confirm it deals damage like this. Data shows its dealt as reflected damage which I don't have it coded like that yet. [Rytech] + } else if( sd ) { + int rate = sstatus->int_ / 6 + (sd? sd->status.job_level:0) / 5 + skill_lv * 4; + if ( rnd()%100 < rate ) { + map->foreachinrange(skill->area_sub, src, skill->get_splash(skill_id,skill_lv),BL_PC, src, skill_id, skill_lv, tick, flag|BCT_ENEMY|1, skill->castend_nodamage_id); + clif->skill_nodamage(src, bl, skill_id, skill_lv, 1); + } + } + } break; case WM_MELODYOFSINK: case WM_BEYOND_OF_WARCRY: - case WM_UNLIMITED_HUMMING_VOICE: - if( flag&1 ) { - sc_start2(bl,type,100,skill_lv,skill_area_temp[0],skill->get_time(skill_id,skill_lv)); - } else { // These affect to all targets arround the caster. - short lv = (short)skill_lv; - skill_area_temp[0] = (sd) ? skill->check_pc_partner(sd,skill_id,&lv,skill->get_splash(skill_id,skill_lv),1) : 50; // 50% chance in non BL_PC (clones). - iMap->foreachinrange(skill->area_sub, src, skill->get_splash(skill_id,skill_lv),BL_PC, src, skill_id, skill_lv, tick, flag|BCT_ENEMY|1, skill->castend_nodamage_id); - clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + { + int chorusbonus = battle->calc_chorusbonus(sd); + if( flag&1 ) + sc_start2(src,bl,type,100,skill_lv,chorusbonus,skill->get_time(skill_id,skill_lv)); + else if( sd ) { + if ( rnd()%100 < 15 + 5 * skill_lv + 5 * chorusbonus ) { + map->foreachinrange(skill->area_sub, src, skill->get_splash(skill_id,skill_lv),BL_PC, src, skill_id, skill_lv, tick, flag|BCT_ENEMY|1, skill->castend_nodamage_id); + clif->skill_nodamage(src,bl,skill_id,skill_lv,1); + } } + } break; case WM_RANDOMIZESPELL: { - int improv_skill_id = 0, improv_skill_lv; + int improv_skill_id = 0, improv_skill_lv, improv_idx; do { - i = rnd() % MAX_SKILL_IMPROVISE_DB; - improv_skill_id = skill_improvise_db[i].skill_id; - } while( improv_skill_id == 0 || rnd()%10000 >= skill_improvise_db[i].per ); + improv_idx = rnd() % MAX_SKILL_IMPROVISE_DB; + improv_skill_id = skill->improvise_db[improv_idx].skill_id; + } while( improv_skill_id == 0 || rnd()%10000 >= skill->improvise_db[improv_idx].per ); improv_skill_lv = 4 + skill_lv; clif->skill_nodamage (src, bl, skill_id, skill_lv, 1); @@ -8700,14 +9073,14 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui sd->skillitemlv = improv_skill_lv; clif->item_skill(sd, improv_skill_id, improv_skill_lv); } else { - struct unit_data *ud = unit_bl2ud(src); + struct unit_data *ud = unit->bl2ud(src); int inf = skill->get_inf(improv_skill_id); if (!ud) break; if (inf&INF_SELF_SKILL || inf&INF_SUPPORT_SKILL) { if (src->type == BL_PET) bl = (struct block_list*)((TBL_PET*)src)->msd; if (!bl) bl = src; - unit_skilluse_id(src, bl->id, improv_skill_id, improv_skill_lv); + unit->skilluse_id(src, bl->id, improv_skill_id, improv_skill_lv); } else { int target_id = 0; if (ud->target) @@ -8719,11 +9092,11 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui if (!target_id) break; if (skill->get_casttype(improv_skill_id) == CAST_GROUND) { - bl = iMap->id2bl(target_id); + bl = map->id2bl(target_id); if (!bl) bl = src; - unit_skilluse_pos(src, bl->x, bl->y, improv_skill_id, improv_skill_lv); + unit->skilluse_pos(src, bl->x, bl->y, improv_skill_id, improv_skill_lv); } else - unit_skilluse_id(src, target_id, improv_skill_id, improv_skill_lv); + unit->skilluse_id(src, target_id, improv_skill_id, improv_skill_lv); } } } @@ -8735,28 +9108,25 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui if( sd ) { short x, y; // Destiny position. - unsigned short mapindex; + unsigned short map_index; - if( skill_id == RETURN_TO_ELDICASTES) - { + if( skill_id == RETURN_TO_ELDICASTES) { x = 198; y = 187; - mapindex = mapindex_name2id(MAP_DICASTES); - } - else - { + map_index = mapindex->name2id(MAP_DICASTES); + } else { x = 44; y = 151; - mapindex = mapindex_name2id(MAP_MORA); + map_index = mapindex->name2id(MAP_MORA); } - if(!mapindex) - { //Given map not found? + if(!map_index) { + //Given map not found? clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - iMap->freeblock_unlock(); + map->freeblock_unlock(); return 0; } - pc->setpos(sd, mapindex, x, y, CLR_TELEPORT); + pc->setpos(sd, map_index, x, y, CLR_TELEPORT); } break; @@ -8774,23 +9144,10 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case SO_ARRULLO: { // [(15 + 5 * Skill Level) + ( Caster?s INT / 5 ) + ( Caster?s Job Level / 5 ) - ( Target?s INT / 6 ) - ( Target?s LUK / 10 )] % - int rate = (15 + 5 * skill_lv) + status_get_int(src)/5 + (sd ? sd->status.job_level : 0); + int rate = (15 + 5 * skill_lv) + status_get_int(src)/5 + (sd? sd->status.job_level:0)/5; rate -= status_get_int(bl)/6 - status_get_luk(bl)/10; clif->skill_nodamage(src, bl, skill_id, skill_lv, 1); - sc_start2(bl, type, rate, skill_lv, 1, skill->get_time(skill_id, skill_lv)); - } - break; - - case WM_LULLABY_DEEPSLEEP: - if( flag&1 ){ - //[(Skill Level x 4) + (Voice Lessons Skill Level x 2) + (Caster?s Base Level / 15) + (Caster?s Job Level / 5)] % - int rate = (4 * skill_lv) + ( (sd) ? pc->checkskill(sd,WM_LESSON)*2 + sd->status.job_level/5 : 0 ) + status_get_lv(src) / 15; - if( bl != src ) - sc_start(bl,type,rate,skill_lv,skill->get_time(skill_id,skill_lv)); - }else { - clif->skill_nodamage(src, bl, skill_id, skill_lv, 1); - iMap->foreachinrange(skill->area_sub, bl, skill->get_splash(skill_id, skill_lv), BL_CHAR, - src, skill_id, skill_lv, tick, flag|BCT_ALL|1, skill->castend_nodamage_id); + sc_start2(src,bl, type, rate, skill_lv, 1, skill->get_time(skill_id, skill_lv)); } break; @@ -8801,13 +9158,13 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui if( sd ) { int elemental_class = skill->get_elemental_type(skill_id,skill_lv); - // Remove previous elemental fisrt. + // Remove previous elemental first. if( sd->ed ) - elemental_delete(sd->ed,0); + elemental->delete(sd->ed,0); // Summoning the new one. - if( !elemental_create(sd,elemental_class,skill->get_time(skill_id,skill_lv)) ) { - clif->skill_fail(sd,skill_id,0,0); + if( !elemental->create(sd,elemental_class,skill->get_time(skill_id,skill_lv)) ) { + clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); break; } clif->skill_nodamage(src,bl,skill_id,skill_lv,1); @@ -8821,14 +9178,14 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui if( !sd->ed ) break; if( skill_lv == 4 ) {// At level 4 delete elementals. - elemental_delete(sd->ed, 0); + elemental->delete(sd->ed, 0); break; } - switch( skill_lv ) {// Select mode bassed on skill level used. + switch( skill_lv ) {// Select mode based on skill level used. case 2: mode = EL_MODE_ASSIST; break; case 3: mode = EL_MODE_AGGRESSIVE; break; } - if( !elemental_change_mode(sd->ed,mode) ) { + if( !elemental->change_mode(sd->ed,mode) ) { clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); break; } @@ -8838,22 +9195,26 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case SO_EL_ACTION: if( sd ) { - int duration = 3000; - if( !sd->ed ) break; + int duration = 3000; + if( !sd->ed ) + break; + + switch(sd->ed->db->class_){ + case 2115:case 2124: + case 2118:case 2121: + duration = 6000; + break; + case 2116:case 2119: + case 2122:case 2125: + duration = 9000; + break; + } + sd->skill_id_old = skill_id; - elemental_action(sd->ed, bl, tick); + elemental->action(sd->ed, bl, tick); clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - switch(sd->ed->db->class_){ - case 2115:case 2124: - case 2118:case 2121: - duration = 6000; - break; - case 2116:case 2119: - case 2122:case 2125: - duration = 9000; - break; - } - skill->blockpc_start(sd, skill_id, duration, false); + + skill->blockpc_start(sd, skill_id, duration); } break; @@ -8864,13 +9225,13 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui int e_hp, e_sp; if( !ed ) break; - if( !status_charge(&sd->bl,s_hp,s_sp) ) { + if( !status->charge(&sd->bl,s_hp,s_sp) ) { clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); break; } e_hp = ed->battle_status.max_hp * 10 / 100; e_sp = ed->battle_status.max_sp * 10 / 100; - status_heal(&ed->bl,e_hp,e_sp,3); + status->heal(&ed->bl,e_hp,e_sp,3); clif->skill_nodamage(src,&ed->bl,skill_id,skill_lv,1); } break; @@ -8885,7 +9246,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case GN_BLOOD_SUCKER: { - struct status_change *sc = status_get_sc(src); + struct status_change *sc = status->get_sc(src); if( sc && sc->bs_counter < skill->get_maxcount( skill_id , skill_lv) ) { if( tsc && tsc->data[type] ){ @@ -8893,7 +9254,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui status_change_end(src, type, INVALID_TIMER); // the first one cancels and the last one will take effect resetting the timer } clif->skill_nodamage(src, bl, skill_id, skill_lv, 1); - sc_start2(bl, type, 100, skill_lv, src->id, skill->get_time(skill_id,skill_lv)); + sc_start2(src,bl, type, 100, skill_lv, src->id, skill->get_time(skill_id,skill_lv)); (sc->bs_counter)++; } else if( sd ) { clif->skill_fail(sd, skill_id, USESKILL_FAIL_LEVEL, 0); @@ -8904,40 +9265,45 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case GN_MANDRAGORA: if( flag&1 ) { - if ( clif->skill_nodamage(bl, src, skill_id, skill_lv, - sc_start(bl, type, 25 + 10 * skill_lv, skill_lv, skill->get_time(skill_id, skill_lv))) ) - status_zap(bl, 0, status_get_max_sp(bl) * (25 + 5 * skill_lv) / 100); - } else - iMap->foreachinrange(skill->area_sub, bl, skill->get_splash(skill_id, skill_lv), BL_CHAR, - src, skill_id, skill_lv, tick, flag|BCT_ENEMY|1, skill->castend_nodamage_id); + int chance = 25 + 10 * skill_lv - (status_get_vit(bl) + status_get_luk(bl)) / 5; + if ( chance < 10 ) + chance = 10;//Minimal chance is 10%. + if ( rnd()%100 < chance ) {//Coded to both inflect the status and drain the target's SP only when successful. [Rytech] + sc_start(src, bl, type, 100, skill_lv, skill->get_time(skill_id, skill_lv)); + status_zap(bl, 0, status_get_max_sp(bl) * (25 + 5 * skill_lv) / 100); + } + } else if ( sd ) { + map->foreachinrange(skill->area_sub, bl, skill->get_splash(skill_id, skill_lv), BL_CHAR,src, skill_id, skill_lv, tick, flag|BCT_ENEMY|1, skill->castend_nodamage_id); + clif->skill_nodamage(bl, src, skill_id, skill_lv, 1); + } break; case GN_SLINGITEM: if( sd ) { short ammo_id; - i = sd->equip_index[EQI_AMMO]; - if( i <= 0 ) + int equip_idx = sd->equip_index[EQI_AMMO]; + if( equip_idx <= 0 ) break; // No ammo. - ammo_id = sd->inventory_data[i]->nameid; + ammo_id = sd->inventory_data[equip_idx]->nameid; if( ammo_id <= 0 ) break; sd->itemid = ammo_id; if( itemdb_is_GNbomb(ammo_id) ) { if(battle->check_target(src,bl,BCT_ENEMY) > 0) {// Only attack if the target is an enemy. - if( ammo_id == 13263 ) - iMap->foreachincell(skill->area_sub,bl->m,bl->x,bl->y,BL_CHAR,src,GN_SLINGITEM_RANGEMELEEATK,skill_lv,tick,flag|BCT_ENEMY|1,skill->castend_damage_id); + if( ammo_id == ITEMID_PINEAPPLE_BOMB ) + map->foreachincell(skill->area_sub,bl->m,bl->x,bl->y,BL_CHAR,src,GN_SLINGITEM_RANGEMELEEATK,skill_lv,tick,flag|BCT_ENEMY|1,skill->castend_damage_id); else skill->attack(BF_WEAPON,src,src,bl,GN_SLINGITEM_RANGEMELEEATK,skill_lv,tick,flag); } else //Otherwise, it fails, shows animation and removes items. clif->skill_fail(sd,GN_SLINGITEM_RANGEMELEEATK,0xa,0); - } else if( itemdb_is_GNthrowable(ammo_id) ){ - struct script_code *script = sd->inventory_data[i]->script; - if( !script ) + } else if( itemdb_is_GNthrowable(ammo_id) ) { + struct script_code *scriptroot = sd->inventory_data[equip_idx]->script; + if( !scriptroot ) break; if( dstsd ) - run_script(script,0,dstsd->bl.id,fake_nd->bl.id); + script->run(scriptroot,0,dstsd->bl.id,npc->fake_nd->bl.id); else - run_script(script,0,src->id,0); + script->run(scriptroot,0,src->id,0); } } clif->skill_nodamage(src,bl,skill_id,skill_lv,1); @@ -8975,24 +9341,25 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case EL_WIND_CURTAIN: case EL_SOLID_SKIN: case EL_STONE_SHIELD: - case EL_WIND_STEP: { - struct elemental_data *ele = BL_CAST(BL_ELEM, src); - if( ele ) { - sc_type type2 = type-1; - struct status_change *sc = status_get_sc(&ele->bl); - - if( (sc && sc->data[type2]) || (tsc && tsc->data[type]) ) { - elemental_clean_single_effect(ele, skill_id); - } else { - clif->skill_nodamage(src,src,skill_id,skill_lv,1); - clif->skill_damage(src, ( skill_id == EL_GUST || skill_id == EL_BLAST || skill_id == EL_WILD_STORM )?src:bl, tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6); - if( skill_id == EL_WIND_STEP ) // There aren't teleport, just push the master away. - skill->blown(src,bl,(rnd()%skill->get_blewcount(skill_id,skill_lv))+1,rand()%8,0); - sc_start(src,type2,100,skill_lv,skill->get_time(skill_id,skill_lv)); - sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv)); - } + case EL_WIND_STEP: + { + struct elemental_data *ele = BL_CAST(BL_ELEM, src); + if( ele ) { + sc_type type2 = type-1; + struct status_change *sc = status->get_sc(&ele->bl); + + if( (sc && sc->data[type2]) || (tsc && tsc->data[type]) ) { + elemental->clean_single_effect(ele, skill_id); + } else { + clif->skill_nodamage(src,src,skill_id,skill_lv,1); + clif->skill_damage(src, ( skill_id == EL_GUST || skill_id == EL_BLAST || skill_id == EL_WILD_STORM )?src:bl, tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6); + if( skill_id == EL_WIND_STEP ) // There aren't teleport, just push the master away. + skill->blown(src,bl,(rnd()%skill->get_blewcount(skill_id,skill_lv))+1,rnd()%8,0); + sc_start(src, src,type2,100,skill_lv,skill->get_time(skill_id,skill_lv)); + sc_start(src, bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv)); } } + } break; case EL_FIRE_MANTLE: @@ -9004,23 +9371,24 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui skill->unitsetting(src,skill_id,skill_lv,bl->x,bl->y,0); break; - case EL_WATER_SCREEN: { - struct elemental_data *ele = BL_CAST(BL_ELEM, src); - if( ele ) { - struct status_change *sc = status_get_sc(&ele->bl); - sc_type type2 = type-1; + case EL_WATER_SCREEN: + { + struct elemental_data *ele = BL_CAST(BL_ELEM, src); + if( ele ) { + struct status_change *sc = status->get_sc(&ele->bl); + sc_type type2 = type-1; - clif->skill_nodamage(src,src,skill_id,skill_lv,1); - if( (sc && sc->data[type2]) || (tsc && tsc->data[type]) ) { - elemental_clean_single_effect(ele, skill_id); - } else { - // This not heals at the end. - clif->skill_damage(src, src, tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6); - sc_start(src,type2,100,skill_lv,skill->get_time(skill_id,skill_lv)); - sc_start(bl,type,100,src->id,skill->get_time(skill_id,skill_lv)); - } + clif->skill_nodamage(src,src,skill_id,skill_lv,1); + if( (sc && sc->data[type2]) || (tsc && tsc->data[type]) ) { + elemental->clean_single_effect(ele, skill_id); + } else { + // This not heals at the end. + clif->skill_damage(src, src, tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6); + sc_start(src, src,type2,100,skill_lv,skill->get_time(skill_id,skill_lv)); + sc_start(src, bl,type,100,src->id,skill->get_time(skill_id,skill_lv)); } } + } break; case KO_KAHU_ENTEN: @@ -9028,6 +9396,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case KO_KAZEHU_SEIRAN: case KO_DOHU_KOUKAI: if(sd) { + int i; int ttype = skill->get_ele(skill_id, skill_lv); clif->skill_nodamage(src, bl, skill_id, skill_lv, 1); ARR_FIND(1, 6, i, sd->charm[i] > 0 && ttype != i); @@ -9038,21 +9407,20 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui break; case KO_ZANZOU: - if(sd){ - struct mob_data *md; - - md = mob_once_spawn_sub(src, src->m, src->x, src->y, status_get_name(src), 2308, "", SZ_SMALL, AI_NONE); - if( md ) - { - md->master_id = src->id; - md->special_state.ai = AI_ZANZOU; - if( md->deletetimer != INVALID_TIMER ) - iTimer->delete_timer(md->deletetimer, mob_timer_delete); - md->deletetimer = iTimer->add_timer (iTimer->gettick() + skill->get_time(skill_id, skill_lv), mob_timer_delete, md->bl.id, 0); - mob_spawn( md ); + if(sd) { + struct mob_data *summon_md; + + summon_md = mob->once_spawn_sub(src, src->m, src->x, src->y, status->get_name(src), 2308, "", SZ_MEDIUM, AI_NONE); + if( summon_md ) { + summon_md->master_id = src->id; + summon_md->special_state.ai = AI_ZANZOU; + if( summon_md->deletetimer != INVALID_TIMER ) + timer->delete(summon_md->deletetimer, mob->timer_delete); + summon_md->deletetimer = timer->add(timer->gettick() + skill->get_time(skill_id, skill_lv), mob->timer_delete, summon_md->bl.id, 0); + mob->spawn( summon_md ); pc->setinvincibletimer(sd,500);// unlock target lock clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - skill->blown(src,bl,skill->get_blewcount(skill_id,skill_lv),unit_getdir(bl),0); + skill->blown(src,bl,skill->get_blewcount(skill_id,skill_lv),unit->getdir(bl),0); } } break; @@ -9060,48 +9428,49 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case KO_KYOUGAKU: { int rate = max(5, (45 + 5 * skill_lv - status_get_int(bl) / 10)); - if( sd && !map_flag_gvg(src->m) ){ + if( sd && !map_flag_gvg2(src->m) ){ clif->skill_fail(sd, skill_id, USESKILL_FAIL_SIZE, 0); break; } if( dstsd && tsc && !tsc->data[type] && rand()%100 < rate ){ clif->skill_nodamage(src, bl, skill_id, skill_lv, - sc_start(bl, type, 100, skill_lv, skill->get_time(skill_id, skill_lv))); + sc_start(src, bl, type, 100, skill_lv, skill->get_time(skill_id, skill_lv))); }else if( sd ) clif->skill_fail(sd, skill_id, USESKILL_FAIL_LEVEL, 0); } break; case KO_JYUSATSU: - if( dstsd && tsc && !tsc->data[type] && - rand()%100 < (10 * (5 * skill_lv - status_get_int(bl) / 2 + 45 + 5 * skill_lv)) ){ + if( dstsd && tsc && !tsc->data[type] + && rand()%100 < (10 * (5 * skill_lv - status_get_int(bl) / 2 + 45 + 5 * skill_lv)) + ) { clif->skill_nodamage(src, bl, skill_id, skill_lv, - status_change_start(bl, type, 10000, skill_lv, 0, 0, 0, skill->get_time(skill_id, skill_lv), 1)); + status->change_start(src, bl, type, 10000, skill_lv, 0, 0, 0, skill->get_time(skill_id, skill_lv), 1)); status_zap(bl, tstatus->max_hp * skill_lv * 5 / 100 , 0); - if( status_get_lv(bl) <= status_get_lv(src) ) - status_change_start(bl, SC_COMA, skill_lv, skill_lv, 0, src->id, 0, 0, 0); - }else if( sd ) + if( status->get_lv(bl) <= status->get_lv(src) ) + status->change_start(src, bl, SC_COMA, skill_lv, skill_lv, 0, src->id, 0, 0, 0); + } else if( sd ) clif->skill_fail(sd, skill_id, USESKILL_FAIL_LEVEL, 0); break; case KO_GENWAKU: - if ( !map_flag_gvg(src->m) && ( dstsd || dstmd ) && !(tstatus->mode&MD_PLANT) && battle->check_target(src,bl,BCT_ENEMY) > 0 ) { + if ( !map_flag_gvg2(src->m) && ( dstsd || dstmd ) && !(tstatus->mode&MD_PLANT) && battle->check_target(src,bl,BCT_ENEMY) > 0 ) { int x = src->x, y = src->y; if( sd && rnd()%100 > max(5, (45 + 5 * skill_lv) - status_get_int(bl) / 10) ){//[(Base chance of success) - ( target's int / 10)]%. clif->skill_fail(sd, skill_id, USESKILL_FAIL_LEVEL, 0); break; } - if (unit_movepos(src, bl->x, bl->y, 0, 0)) { + if (unit->movepos(src, bl->x, bl->y, 0, 0)) { clif->skill_nodamage(src, src, skill_id, skill_lv, 1); clif->slide(src, bl->x, bl->y) ; - sc_start(src, SC_CONFUSION, 25, skill_lv, skill->get_time(skill_id, skill_lv)); - if ( !is_boss(bl) && unit_stop_walking(&sd->bl, 1) && unit_movepos(bl, x, y, 0, 0) ) + sc_start(src, src, SC_CONFUSION, 25, skill_lv, skill->get_time(skill_id, skill_lv)); + if ( !is_boss(bl) && unit->stop_walking(&sd->bl, 1) && unit->movepos(bl, x, y, 0, 0) ) { if( dstsd && pc_issit(dstsd) ) pc->setstand(dstsd); clif->slide(bl, x, y) ; - sc_start(bl, SC_CONFUSION, 75, skill_lv, skill->get_time(skill_id, skill_lv)); + sc_start(src, bl, SC_CONFUSION, 75, skill_lv, skill->get_time(skill_id, skill_lv)); } } } @@ -9119,7 +9488,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui case KG_KYOMU: case KG_KAGEMUSYA: clif->skill_nodamage(src,bl,skill_id,skill_lv, - sc_start(bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); + sc_start(src, bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv))); clif->skill_damage(src,bl,tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6); break; @@ -9128,8 +9497,8 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui if(tsc && ( tsc->option&(OPTION_CLOAK|OPTION_HIDE) || tsc->data[SC_CAMOUFLAGE] || tsc->data[SC__SHADOWFORM] || tsc->data[SC_MARIONETTE_MASTER] || tsc->data[SC_HARMONIZE])){ - sc_start(src, type, 100, skill_lv, skill->get_time(skill_id, skill_lv)); - sc_start(bl, type, 100, skill_lv, skill->get_time(skill_id, skill_lv)); + sc_start(src, src, type, 100, skill_lv, skill->get_time(skill_id, skill_lv)); + sc_start(src, bl, type, 100, skill_lv, skill->get_time(skill_id, skill_lv)); status_change_end(bl, SC_HIDING, INVALID_TIMER); status_change_end(bl, SC_CLOAKING, INVALID_TIMER); status_change_end(bl, SC_CLOAKINGEXCEED, INVALID_TIMER); @@ -9138,153 +9507,141 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui status_change_end(bl, SC_MARIONETTE_MASTER, INVALID_TIMER); status_change_end(bl, SC_HARMONIZE, INVALID_TIMER); } - if( skill_area_temp[2] == 1 ){ + if( skill->area_temp[2] == 1 ){ clif->skill_damage(src,src,tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6); - sc_start(src, SC_STOP, 100, skill_lv, skill->get_time(skill_id, skill_lv)); + sc_start(src, src, SC_STOP, 100, skill_lv, skill->get_time(skill_id, skill_lv)); } - }else{ - skill_area_temp[2] = 0; - iMap->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); + } 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); } break; - case MH_SILENT_BREEZE: { - struct status_change *ssc = status_get_sc(src); - struct block_list *m_bl = battle->get_master(src); - const enum sc_type scs[] = { - SC_MANDRAGORA, SC_HARMONIZE, SC_DEEP_SLEEP, SC_SIREN, SC_SLEEP, SC_CONFUSION, SC_ILLUSION - }; - int heal; - if(tsc){ - for (i = 0; i < ARRAYLENGTH(scs); i++) { - if (tsc->data[scs[i]]) status_change_end(bl, scs[i], INVALID_TIMER); - } - if (!tsc->data[SC_SILENCE]) //put inavoidable silence on target - status_change_start(bl, SC_SILENCE, 100, skill_lv, 0,0,0, skill->get_time(skill_id, skill_lv),1|2|8); + case MH_LIGHT_OF_REGENE: + if( hd && battle->get_master(src) ) { + hd->homunculus.intimacy = (751 + rnd()%99) * 100; // random between 751 ~ 850 + clif->send_homdata(hd->master, SP_INTIMATE, hd->homunculus.intimacy / 100); //refresh intimacy info + sc_start(src, battle->get_master(src), type, 100, skill_lv, skill->get_time(skill_id, skill_lv)); } - heal = status_get_matk_min(src)*4; - status_heal(bl, heal, 0, 7); + break; - //now inflict silence on everyone - if(ssc && !ssc->data[SC_SILENCE]) //put inavoidable silence on homun - status_change_start(src, SC_SILENCE, 100, skill_lv, 0,0,0, skill->get_time(skill_id, skill_lv),1|2|8); - if(m_bl){ - struct status_change *msc = status_get_sc(m_bl); - if(msc && !msc->data[SC_SILENCE]) //put inavoidable silence on master - status_change_start(m_bl, SC_SILENCE, 100, skill_lv, 0,0,0, skill->get_time(skill_id, skill_lv),1|2|8); + case MH_OVERED_BOOST: + if ( hd && battle->get_master(src) ) { + sc_start(src, bl, type, 100, skill_lv, skill->get_time(skill_id, skill_lv)); + sc_start(src, battle->get_master(src), type, 100, skill_lv, skill->get_time(skill_id, skill_lv)); } - if (hd) - skill->blockhomun_start(hd, skill_id, skill->get_cooldown(skill_id, skill_lv)); - } - break; - case MH_OVERED_BOOST: - if (hd){ - struct block_list *s_bl = battle->get_master(src); - if(hd->homunculus.hunger>50) //reduce hunger - hd->homunculus.hunger = hd->homunculus.hunger/2; - else - hd->homunculus.hunger = min(1,hd->homunculus.hunger); - if(s_bl && s_bl->type==BL_PC){ - status_set_sp(s_bl,status_get_max_sp(s_bl)/2,0); //master drain 50% sp - clif->send_homdata(((TBL_PC *)s_bl), SP_HUNGRY, hd->homunculus.hunger); //refresh hunger info - sc_start(s_bl, type, 100, skill_lv, skill->get_time(skill_id, skill_lv)); //gene bonus - } - sc_start(bl, type, 100, skill_lv, skill->get_time(skill_id, skill_lv)); - skill->blockhomun_start(hd, skill_id, skill->get_cooldown(skill_id, skill_lv)); - } - break; - case MH_GRANITIC_ARMOR: - case MH_PYROCLASTIC: { - struct block_list *s_bl = battle->get_master(src); - if(s_bl) - sc_start2(s_bl, type, 100, skill_lv, hd->homunculus.level, skill->get_time(skill_id, skill_lv)); //start on master - sc_start2(bl, type, 100, skill_lv, hd->homunculus.level, skill->get_time(skill_id, skill_lv)); - if (hd) - skill->blockhomun_start(hd, skill_id, skill->get_cooldown(skill_id, skill_lv)); + break; + + case MH_SILENT_BREEZE: + { + const enum sc_type scs[] = { + SC_MANDRAGORA, SC_HARMONIZE, SC_DEEP_SLEEP, SC_SIREN, SC_SLEEP, SC_CONFUSION, SC_ILLUSION + }; + int heal; + if(tsc){ + int i; + for (i = 0; i < ARRAYLENGTH(scs); i++) { + if (tsc->data[scs[i]]) status_change_end(bl, scs[i], INVALID_TIMER); } - break; + } + heal = 5 * status->get_lv(&hd->bl) + status->base_matk(&hd->battle_status, status->get_lv(&hd->bl)); + status->heal(bl, heal, 0, 0); + clif->skill_nodamage(src, src, skill_id, skill_lv, clif->skill_nodamage(src, bl, AL_HEAL, heal, 1)); + status->change_start(src, src, type, 1000, skill_lv, 0, 0, 0, skill->get_time(skill_id,skill_lv), 1|2|8); + status->change_start(src, bl, type, 1000, skill_lv, 0, 0, 0, skill->get_time(skill_id,skill_lv), 1|2|8); + } + break; - case MH_LIGHT_OF_REGENE: - if(hd){ - hd->homunculus.intimacy = 251; //change to neutral (can't be cast if < 750) - if(sd) clif->send_homdata(sd, SP_INTIMATE, hd->homunculus.intimacy); //refresh intimacy info - } - //don't break need to start status and start block timer - case MH_STYLE_CHANGE: - case MH_MAGMA_FLOW: - case MH_PAIN_KILLER: - sc_start(bl, type, 100, skill_lv, skill->get_time(skill_id, skill_lv)); - if (hd) - skill->blockhomun_start(hd, skill_id, skill->get_cooldown(skill_id, skill_lv)); - break; - case MH_SUMMON_LEGION: - { - int summons[5] = {1004, 1303, 1303, 1994, 1994}; - int qty[5] = {3 , 3 , 4 , 4 , 5}; - struct mob_data *md; - int i, dummy = 0; + case MH_GRANITIC_ARMOR: + case MH_PYROCLASTIC: + if( hd ){ + struct block_list *s_bl = battle->get_master(src); + + if(s_bl) + sc_start2(src, s_bl, type, 100, skill_lv, hd->homunculus.level, skill->get_time(skill_id, skill_lv)); //start on master + + sc_start2(src, bl, type, 100, skill_lv, hd->homunculus.level, skill->get_time(skill_id, skill_lv)); + + skill->blockhomun_start(hd, skill_id, skill->get_cooldown(skill_id, skill_lv)); + } + break; - i = iMap->foreachinmap(skill->check_condition_mob_master_sub ,hd->bl.m, BL_MOB, hd->bl.id, summons[skill_lv-1], skill_id, &dummy); - if(i >= qty[skill_lv-1]) - break; - - for(i=0; i<qty[skill_lv - 1]; i++){ //easy way - md = mob_once_spawn_sub(src, src->m, src->x, src->y, status_get_name(src), summons[skill_lv - 1], "", SZ_SMALL, AI_ATTACK); - if (md) { - md->master_id = src->id; - if (md->deletetimer != INVALID_TIMER) - iTimer->delete_timer(md->deletetimer, mob_timer_delete); - md->deletetimer = iTimer->add_timer(iTimer->gettick() + skill->get_time(skill_id, skill_lv), mob_timer_delete, md->bl.id, 0); - mob_spawn(md); //Now it is ready for spawning. - sc_start4(&md->bl, SC_MODECHANGE, 100, 1, 0, MD_CANATTACK|MD_AGGRESSIVE, 0, 60000); - } - } - if (hd) - skill->blockhomun_start(hd, skill_id, skill->get_cooldown(skill_id, skill_lv)); - } + case MH_MAGMA_FLOW: + case MH_PAIN_KILLER: + sc_start(src, bl, type, 100, skill_lv, skill->get_time(skill_id, skill_lv)); + if (hd) + skill->blockhomun_start(hd, skill_id, skill->get_cooldown(skill_id, skill_lv)); + break; + case MH_SUMMON_LEGION: + { + int summons[5] = {1004, 1303, 1303, 1994, 1994}; + int qty[5] = {3 , 3 , 4 , 4 , 5}; + struct mob_data *summon_md; + int i, dummy = 0; + + i = map->foreachinmap(skill->check_condition_mob_master_sub, src->m, BL_MOB, src->id, summons[skill_lv-1], skill_id, &dummy); + if(i >= qty[skill_lv-1]) break; + + for(i=0; i<qty[skill_lv - 1]; i++){ //easy way + summon_md = mob->once_spawn_sub(src, src->m, src->x, src->y, status->get_name(src), summons[skill_lv - 1], "", SZ_MEDIUM, AI_ATTACK); + if (summon_md) { + summon_md->master_id = src->id; + if (summon_md->deletetimer != INVALID_TIMER) + timer->delete(summon_md->deletetimer, mob->timer_delete); + summon_md->deletetimer = timer->add(timer->gettick() + skill->get_time(skill_id, skill_lv), mob->timer_delete, summon_md->bl.id, 0); + mob->spawn(summon_md); //Now it is ready for spawning. + sc_start4(src,&summon_md->bl, SC_MODECHANGE, 100, 1, 0, MD_CANATTACK|MD_AGGRESSIVE, 0, 60000); + } + } + if (hd) + skill->blockhomun_start(hd, skill_id, skill->get_cooldown(skill_id, skill_lv)); + } + break; + case SO_ELEMENTAL_SHIELD:/* somehow its handled outside this switch, so we need a empty case otherwise default would be triggered. */ + break; default: ShowWarning("skill_castend_nodamage_id: Unknown skill used:%d\n",skill_id); clif->skill_nodamage(src,bl,skill_id,skill_lv,1); - iMap->freeblock_unlock(); + map->freeblock_unlock(); return 1; } - if(skill_id != SR_CURSEDCIRCLE){ - struct status_change *sc = status_get_sc(src); + if(skill_id != SR_CURSEDCIRCLE) { + struct status_change *sc = status->get_sc(src); if( sc && sc->data[SC_CURSEDCIRCLE_ATKER] )//Should only remove after the skill had been casted. status_change_end(src,SC_CURSEDCIRCLE_ATKER,INVALID_TIMER); } if (dstmd) { //Mob skill event for no damage skills (damage ones are handled in battle_calc_damage) [Skotlex] - mob_log_damage(dstmd, src, 0); //Log interaction (counts as 'attacker' for the exp bonus) - mobskill_event(dstmd, src, tick, MSC_SKILLUSED|(skill_id<<16)); + mob->log_damage(dstmd, src, 0); //Log interaction (counts as 'attacker' for the exp bonus) + mob->skill_event(dstmd, src, tick, MSC_SKILLUSED|(skill_id<<16)); } if( sd && !(flag&1) ) { // ensure that the skill last-cast tick is recorded - sd->canskill_tick = iTimer->gettick(); + sd->canskill_tick = timer->gettick(); if( sd->state.arrow_atk ) { // consume arrow on last invocation to this skill. battle->consume_ammo(sd, skill_id, skill_lv); } skill->onskillusage(sd, bl, skill_id, tick); // perform skill requirement consumption - skill->consume_requirement(sd,skill_id,skill_lv,2); + if( skill_id != NC_SELFDESTRUCTION ) + skill->consume_requirement(sd,skill_id,skill_lv,2); } - iMap->freeblock_unlock(); + map->freeblock_unlock(); return 0; } /*========================================== * *------------------------------------------*/ -int skill_castend_pos(int tid, unsigned int tick, int id, intptr_t data) -{ - struct block_list* src = iMap->id2bl(id); +int skill_castend_pos(int tid, int64 tick, int id, intptr_t data) { + struct block_list* src = map->id2bl(id); int maxcount; struct map_session_data *sd; - struct unit_data *ud = unit_bl2ud(src); + struct unit_data *ud = unit->bl2ud(src); struct mob_data *md; nullpo_ret(ud); @@ -9312,7 +9669,7 @@ int skill_castend_pos(int tid, unsigned int tick, int id, intptr_t data) ud->skilltimer = INVALID_TIMER; do { - if( status_isdead(src) ) + if( status->isdead(src) ) break; if( !(src->type&battle_config.skill_reiteration) && @@ -9346,9 +9703,9 @@ int skill_castend_pos(int tid, unsigned int tick, int id, intptr_t data) } } - if(tid != INVALID_TIMER) - { //Avoid double checks on instant cast skills. [Skotlex] - if (!status_check_skilluse(src, NULL, ud->skill_id, 1)) + if(tid != INVALID_TIMER) { + //Avoid double checks on instant cast skills. [Skotlex] + if (!status->check_skilluse(src, NULL, ud->skill_id, 1)) break; if(battle_config.skill_add_range && !check_distance_blxy(src, ud->skillx, ud->skilly, skill->get_range2(src,ud->skill_id,ud->skill_lv)+battle_config.skill_add_range)) { @@ -9380,7 +9737,7 @@ int skill_castend_pos(int tid, unsigned int tick, int id, intptr_t data) src->type, src->id, ud->skill_id, ud->skill_lv, ud->skillx, ud->skilly); if (ud->walktimer != INVALID_TIMER) - unit_stop_walking(src,1); + unit->stop_walking(src,1); if( !sd || sd->skillitem != ud->skill_id || skill->get_delay(ud->skill_id,ud->skill_lv) ) ud->canact_tick = tick + skill->delay_fix(src, ud->skill_id, ud->skill_lv); @@ -9393,7 +9750,7 @@ int skill_castend_pos(int tid, unsigned int tick, int id, intptr_t data) } } if(cooldown) - skill->blockpc_start(sd, ud->skill_id, cooldown, false); + skill->blockpc_start(sd, ud->skill_id, cooldown); } if( battle_config.display_status_timers && sd ) clif->status_change(src, SI_POSTDELAY, 1, skill->delay_fix(src, ud->skill_id, ud->skill_lv), 0, 0, 0); @@ -9406,9 +9763,9 @@ int skill_castend_pos(int tid, unsigned int tick, int id, intptr_t data) // break; // } // } - unit_set_walkdelay(src, tick, battle_config.default_walk_delay+skill->get_walkdelay(ud->skill_id, ud->skill_lv), 1); + unit->set_walkdelay(src, tick, battle_config.default_walk_delay+skill->get_walkdelay(ud->skill_id, ud->skill_lv), 1); status_change_end(src,SC_CAMOUFLAGE, INVALID_TIMER);// only normal attack and auto cast skills benefit from its bonuses - iMap->freeblock_lock(); + map->freeblock_lock(); skill->castend_pos2(src,ud->skillx,ud->skilly,ud->skill_id,ud->skill_lv,tick,0); if( sd && sd->skillitem != AL_WARP ) // Warp-Portal thru items will clear data in skill_castend_map. [Inkfish] @@ -9420,7 +9777,7 @@ int skill_castend_pos(int tid, unsigned int tick, int id, intptr_t data) ud->skill_lv = ud->skillx = ud->skilly = 0; } - iMap->freeblock_unlock(); + map->freeblock_unlock(); return 1; } while(0); @@ -9434,6 +9791,14 @@ int skill_castend_pos(int tid, unsigned int tick, int id, intptr_t data) return 0; } +static int check_npc_chaospanic(struct block_list* bl, va_list args) { + TBL_NPC* nd = (TBL_NPC*)bl; + + if( nd->option&(OPTION_HIDE|OPTION_INVISIBLE) || nd->class_ != 45 ) + return 0; + + return 1; +} /* skill count without self */ static int skill_count_wos(struct block_list *bl,va_list ap) { struct block_list* src = va_arg(ap, struct block_list*); @@ -9446,12 +9811,11 @@ static int skill_count_wos(struct block_list *bl,va_list ap) { /*========================================== * *------------------------------------------*/ -int skill_castend_map (struct map_session_data *sd, uint16 skill_id, const char *map) -{ +int skill_castend_map (struct map_session_data *sd, uint16 skill_id, const char *mapname) { nullpo_ret(sd); //Simplify skill_failed code. -#define skill_failed(sd) { sd->menuskill_id = sd->menuskill_val = 0; } +#define skill_failed(sd) ( (sd)->menuskill_id = (sd)->menuskill_val = 0 ) if(skill_id != sd->menuskill_id) return 0; @@ -9470,7 +9834,7 @@ int skill_castend_map (struct map_session_data *sd, uint16 skill_id, const char sd->sc.data[SC_AUTOCOUNTER] || sd->sc.data[SC_STEELBODY] || (sd->sc.data[SC_DANCING] && skill_id < RK_ENCHANTBLADE && !pc->checkskill(sd, WM_LESSON)) || - sd->sc.data[SC_BERSERK] || sd->sc.data[SC__BLOODYLUST] || + sd->sc.data[SC_BERSERK] || sd->sc.data[SC_BASILICA] || sd->sc.data[SC_MARIONETTE_MASTER] || sd->sc.data[SC_WHITEIMPRISON] || @@ -9488,19 +9852,24 @@ int skill_castend_map (struct map_session_data *sd, uint16 skill_id, const char pc_stop_walking(sd,0); if(battle_config.skill_log && battle_config.skill_log&BL_PC) - ShowInfo("PC %d skill castend skill =%d map=%s\n",sd->bl.id,skill_id,map); + ShowInfo("PC %d skill castend skill =%d map=%s\n",sd->bl.id,skill_id,mapname); - if(strcmp(map,"cancel")==0) { + if(strcmp(mapname,"cancel")==0) { skill_failed(sd); return 0; } switch(skill_id) { case AL_TELEPORT: - if(strcmp(map,"Random")==0) + // The storage window is closed automatically by the client when there's + // any kind of map change, so we need to restore it automatically + // issue: 8027 + if(strcmp(mapname,"Random")==0) pc->randomwarp(sd,CLR_TELEPORT); else if (sd->menuskill_val > 1) //Need lv2 to be able to warp here. pc->setpos(sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,CLR_TELEPORT); + + clif->refresh_storagewindow(sd); break; case AL_WARP: @@ -9510,11 +9879,10 @@ int skill_castend_map (struct map_session_data *sd, uint16 skill_id, const char int i, lv, wx, wy; int maxcount=0; int x,y; - unsigned short mapindex; + unsigned short map_index; - mapindex = mapindex_name2id((char*)map); - sd->state.workinprogress = 0; - if(!mapindex) { //Given map not found? + map_index = mapindex->name2id(mapname); + if(!map_index) { //Given map not found? clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); skill_failed(sd); return 0; @@ -9544,7 +9912,7 @@ int skill_castend_map (struct map_session_data *sd, uint16 skill_id, const char if( lv > 4 ) lv = 4; // crash prevention // check if the chosen map exists in the memo list - ARR_FIND( 0, lv, i, mapindex == p[i]->map ); + ARR_FIND( 0, lv, i, map_index == p[i]->map ); if( i < lv ) { x=p[i]->x; y=p[i]->y; @@ -9569,7 +9937,7 @@ int skill_castend_map (struct map_session_data *sd, uint16 skill_id, const char group->val1 = (group->val1<<16)|(short)0; // record the destination coordinates group->val2 = (x<<16)|y; - group->val3 = mapindex; + group->val3 = map_index; } break; } @@ -9582,27 +9950,26 @@ int skill_castend_map (struct map_session_data *sd, uint16 skill_id, const char /*========================================== * *------------------------------------------*/ -int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, uint16 skill_lv, unsigned int tick, int flag) -{ +int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, uint16 skill_lv, int64 tick, int flag) { struct map_session_data* sd; struct status_change* sc; struct status_change_entry *sce; struct skill_unit_group* sg; enum sc_type type; - int i; + int r; //if(skill_lv <= 0) return 0; - if(skill_id > 0 && !skill_lv) return 0; // celest + if(skill_id > 0 && !skill_lv) return 0; // [Celest] nullpo_ret(src); - if(status_isdead(src)) + if(status->isdead(src)) return 0; sd = BL_CAST(BL_PC, src); - sc = status_get_sc(src); - type = status_skill2sc(skill_id); + sc = status->get_sc(src); + type = status->skill2sc(skill_id); sce = (sc && type != -1)?sc->data[type]:NULL; switch (skill_id) { //Skill effect. @@ -9611,6 +9978,7 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui case CR_CULTIVATION: case HW_GANBANTEIN: case LG_EARTHDRIVE: + case SC_ESCAPE: break; //Effect is displayed on respective switch case. default: if(skill->get_inf(skill_id)&INF_SELF_SKILL) @@ -9624,50 +9992,49 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui switch(skill_id) { case PR_BENEDICTIO: - skill_area_temp[1] = src->id; - i = skill->get_splash(skill_id, skill_lv); - iMap->foreachinarea(skill->area_sub, - src->m, x-i, y-i, x+i, y+i, BL_PC, - src, skill_id, skill_lv, tick, flag|BCT_ALL|1, - skill->castend_nodamage_id); - iMap->foreachinarea(skill->area_sub, - src->m, x-i, y-i, x+i, y+i, BL_CHAR, - src, skill_id, skill_lv, tick, flag|BCT_ENEMY|1, - skill->castend_damage_id); + r = skill->get_splash(skill_id, skill_lv); + skill->area_temp[1] = src->id; + map->foreachinarea(skill->area_sub, + src->m, x-r, y-r, x+r, y+r, BL_PC, + src, skill_id, skill_lv, tick, flag|BCT_ALL|1, + skill->castend_nodamage_id); + map->foreachinarea(skill->area_sub, + src->m, x-r, y-r, x+r, y+r, BL_CHAR, + src, skill_id, skill_lv, tick, flag|BCT_ENEMY|1, + skill->castend_damage_id); break; case BS_HAMMERFALL: - i = skill->get_splash(skill_id, skill_lv); - iMap->foreachinarea (skill->area_sub, - src->m, x-i, y-i, x+i, y+i, BL_CHAR, - src, skill_id, skill_lv, tick, flag|BCT_ENEMY|2, - skill->castend_nodamage_id); + r = skill->get_splash(skill_id, skill_lv); + map->foreachinarea(skill->area_sub, + src->m, x-r, y-r, x+r, y+r, BL_CHAR, + src, skill_id, skill_lv, tick, flag|BCT_ENEMY|2, + skill->castend_nodamage_id); break; case HT_DETECTING: - i = skill->get_splash(skill_id, skill_lv); - iMap->foreachinarea( status_change_timer_sub, - src->m, x-i, y-i, x+i,y+i,BL_CHAR, - src,NULL,SC_SIGHT,tick); + r = skill->get_splash(skill_id, skill_lv); + map->foreachinarea(status->change_timer_sub, + src->m, x-r, y-r, x+r,y+r,BL_CHAR, + src,NULL,SC_SIGHT,tick); if(battle_config.traps_setting&1) - iMap->foreachinarea( skill_reveal_trap, - src->m, x-i, y-i, x+i,y+i,BL_SKILL); + map->foreachinarea(skill_reveal_trap, + src->m, x-r, y-r, x+r, y+r, BL_SKILL); break; case SR_RIDEINLIGHTNING: - i = skill->get_splash(skill_id, skill_lv); - iMap->foreachinarea(skill->area_sub, src->m, x-i, y-i, x+i, y+i, BL_CHAR, - src, skill_id, skill_lv, tick, flag|BCT_ENEMY|1, skill->castend_damage_id); + r = skill->get_splash(skill_id, skill_lv); + map->foreachinarea(skill->area_sub, src->m, x-r, y-r, x+r, y+r, BL_CHAR, + src, skill_id, skill_lv, tick, flag|BCT_ENEMY|1, skill->castend_damage_id); break; case SA_VOLCANO: case SA_DELUGE: case SA_VIOLENTGALE: - { //Does not consumes if the skill is already active. [Skotlex] - struct skill_unit_group *sg; + //Does not consumes if the skill is already active. [Skotlex] if ((sg= skill->locate_element_field(src)) != NULL && ( sg->skill_id == SA_VOLCANO || sg->skill_id == SA_DELUGE || sg->skill_id == SA_VIOLENTGALE )) { - if (sg->limit - DIFF_TICK(iTimer->gettick(), sg->tick) > 0) { + if (sg->limit - DIFF_TICK(timer->gettick(), sg->tick) > 0) { skill->unitsetting(src,skill_id,skill_lv,x,y,0); return 0; // not to consume items } else @@ -9675,7 +10042,14 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui } skill->unitsetting(src,skill_id,skill_lv,x,y,0); break; - } + + 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 ) { + clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + break; + } + case MG_SAFETYWALL: case MG_FIREWALL: case MG_THUNDERSTORM: @@ -9756,8 +10130,7 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui case RA_ICEBOUNDTRAP: case SC_MANHOLE: case SC_DIMENSIONDOOR: - case SC_CHAOSPANIC: - case SC_MAELSTROM: + case SC_BLOODYLUST: case WM_REVERBERATION: case WM_SEVERE_RAINSTORM: case WM_POEMOFNETHERWORLD: @@ -9781,10 +10154,14 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui case MH_VOLCANIC_ASH: case MH_POISON_MIST: case MH_STEINWAND: - case MH_XENO_SLASHER: case NC_MAGMA_ERUPTION: + case SO_ELEMENTAL_SHIELD: + case RL_B_TRAP: + case MH_XENO_SLASHER: flag|=1;//Set flag to 1 to prevent deleting ammo (it will be deleted on group-delete). case GS_GROUNDDRIFT: //Ammo should be deleted right away. + if ( skill_id == WM_SEVERE_RAINSTORM ) + sc_start(src,src,SC_NO_SWITCH_EQUIP,100,0,skill->get_time(skill_id,skill_lv)); skill->unitsetting(src,skill_id,skill_lv,x,y,0); break; case RG_GRAFFITI: /* Graffiti [Valaris] */ @@ -9796,7 +10173,7 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui if( 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( iMap->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; @@ -9804,20 +10181,20 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui skill->clear_unitgroup(src); if( skill->unitsetting(src,skill_id,skill_lv,x,y,0) ) - sc_start4(src,type,100,skill_lv,0,0,src->id,skill->get_time(skill_id,skill_lv)); + sc_start4(src,src,type,100,skill_lv,0,0,src->id,skill->get_time(skill_id,skill_lv)); flag|=1; } break; case CG_HERMODE: skill->clear_unitgroup(src); if ((sg = skill->unitsetting(src,skill_id,skill_lv,x,y,0))) - sc_start4(src,SC_DANCING,100, + sc_start4(src,src,SC_DANCING,100, skill_id,0,skill_lv,sg->group_id,skill->get_time(skill_id,skill_lv)); flag|=1; break; case RG_CLEANER: // [Valaris] - i = skill->get_splash(skill_id, skill_lv); - iMap->foreachinarea(skill->graffitiremover,src->m,x-i,y-i,x+i,y+i,BL_SKILL); + r = skill->get_splash(skill_id, skill_lv); + map->foreachinarea(skill->graffitiremover,src->m,x-r,y-r,x+r,y+r,BL_SKILL); break; case SO_WARMER: @@ -9826,16 +10203,18 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui skill->unitsetting(src,skill_id,skill_lv,x,y,0); break; - case WZ_METEOR: { + case WZ_METEOR: + { int area = skill->get_splash(skill_id, skill_lv); short tmpx = 0, tmpy = 0, x1 = 0, y1 = 0; + int i; for( i = 0; i < 2 + (skill_lv>>1); i++ ) { // Creates a random Cell in the Splash Area tmpx = x - area + rnd()%(area * 2 + 1); tmpy = y - area + rnd()%(area * 2 + 1); - if( i == 0 && path_search_long(NULL, src->m, src->x, src->y, tmpx, tmpy, CELL_CHKWALL) ) + if( i == 0 && path->search_long(NULL, src->m, src->x, src->y, tmpx, tmpy, CELL_CHKWALL) ) clif->skill_poseffect(src,skill_id,skill_lv,tmpx,tmpy,tick); if( i > 0 ) @@ -9863,19 +10242,19 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui return 0; // not to consume item. case MO_BODYRELOCATION: - if (unit_movepos(src, x, y, 1, 1)) { + if (unit->movepos(src, x, y, 1, 1)) { #if PACKETVER >= 20111005 clif->snap(src, src->x, src->y); #else clif->skill_poseffect(src,skill_id,skill_lv,src->x,src->y,tick); #endif if (sd) - skill->blockpc_start (sd, MO_EXTREMITYFIST, 2000, false); + skill->blockpc_start (sd, MO_EXTREMITYFIST, 2000); } break; case NJ_SHADOWJUMP: - if( !map_flag_gvg(src->m) && !map[src->m].flag.battleground ) { //You don't move on GVG grounds. - unit_movepos(src, x, y, 1, 0); + if( !map_flag_gvg2(src->m) && !map->list[src->m].flag.battleground ) { //You don't move on GVG grounds. + unit->movepos(src, x, y, 1, 0); clif->slide(src,x,y); } status_change_end(src, SC_HIDING, INVALID_TIMER); @@ -9888,15 +10267,15 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui int class_ = skill_id==AM_SPHEREMINE?1142:summons[skill_lv-1]; struct mob_data *md; - // Correct info, don't change any of this! [celest] - md = mob_once_spawn_sub(src, src->m, x, y, status_get_name(src), class_, "", SZ_SMALL, AI_NONE); + // Correct info, don't change any of this! [Celest] + md = mob->once_spawn_sub(src, src->m, x, y, status->get_name(src), class_, "", SZ_MEDIUM, AI_NONE); if (md) { md->master_id = src->id; md->special_state.ai = (skill_id == AM_SPHEREMINE) ? AI_SPHERE : AI_FLORA; if( md->deletetimer != INVALID_TIMER ) - iTimer->delete_timer(md->deletetimer, mob_timer_delete); - md->deletetimer = iTimer->add_timer (iTimer->gettick() + skill->get_time(skill_id,skill_lv), mob_timer_delete, md->bl.id, 0); - mob_spawn (md); //Now it is ready for spawning. + timer->delete(md->deletetimer, mob->timer_delete); + md->deletetimer = timer->add(timer->gettick() + skill->get_time(skill_id,skill_lv), mob->timer_delete, md->bl.id, 0); + mob->spawn (md); //Now it is ready for spawning. } } break; @@ -9905,54 +10284,55 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui case CR_SLIMPITCHER: if (sd) { int i = skill_lv%11 - 1; - int j = pc->search_inventory(sd,skill_db[skill_id].itemid[i]); - if( j < 0 || skill_db[skill_id].itemid[i] <= 0 || sd->inventory_data[j] == NULL || sd->status.inventory[j].amount < skill_db[skill_id].amount[i] ) - { + int j = pc->search_inventory(sd,skill->db[skill_id].itemid[i]); + if (j == INDEX_NOT_FOUND || skill->db[skill_id].itemid[i] <= 0 + || sd->inventory_data[j] == NULL || sd->status.inventory[j].amount < skill->db[skill_id].amount[i] + ) { clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); return 1; } - potion_flag = 1; - potion_hp = 0; - potion_sp = 0; - run_script(sd->inventory_data[j]->script,0,sd->bl.id,0); - potion_flag = 0; + script->potion_flag = 1; + script->potion_hp = 0; + script->potion_sp = 0; + script->run(sd->inventory_data[j]->script,0,sd->bl.id,0); + script->potion_flag = 0; //Apply skill bonuses i = pc->checkskill(sd,CR_SLIMPITCHER)*10 + pc->checkskill(sd,AM_POTIONPITCHER)*10 + pc->checkskill(sd,AM_LEARNINGPOTION)*5 + pc->skillheal_bonus(sd, skill_id); - potion_hp = potion_hp * (100+i)/100; - potion_sp = potion_sp * (100+i)/100; + script->potion_hp = script->potion_hp * (100+i)/100; + script->potion_sp = script->potion_sp * (100+i)/100; - if(potion_hp > 0 || potion_sp > 0) { + if(script->potion_hp > 0 || script->potion_sp > 0) { i = skill->get_splash(skill_id, skill_lv); - iMap->foreachinarea(skill->area_sub, - src->m,x-i,y-i,x+i,y+i,BL_CHAR, - src,skill_id,skill_lv,tick,flag|BCT_PARTY|BCT_GUILD|1, - skill->castend_nodamage_id); + map->foreachinarea(skill->area_sub, + src->m,x-i,y-i,x+i,y+i,BL_CHAR, + src,skill_id,skill_lv,tick,flag|BCT_PARTY|BCT_GUILD|1, + skill->castend_nodamage_id); } } else { int i = skill_lv%11 - 1; struct item_data *item; - i = skill_db[skill_id].itemid[i]; - item = itemdb_search(i); - potion_flag = 1; - potion_hp = 0; - potion_sp = 0; - run_script(item->script,0,src->id,0); - potion_flag = 0; + i = skill->db[skill_id].itemid[i]; + item = itemdb->search(i); + script->potion_flag = 1; + script->potion_hp = 0; + script->potion_sp = 0; + script->run(item->script,0,src->id,0); + script->potion_flag = 0; i = skill->get_max(CR_SLIMPITCHER)*10; - potion_hp = potion_hp * (100+i)/100; - potion_sp = potion_sp * (100+i)/100; + script->potion_hp = script->potion_hp * (100+i)/100; + script->potion_sp = script->potion_sp * (100+i)/100; - if(potion_hp > 0 || potion_sp > 0) { + if(script->potion_hp > 0 || script->potion_sp > 0) { i = skill->get_splash(skill_id, skill_lv); - iMap->foreachinarea(skill->area_sub, - src->m,x-i,y-i,x+i,y+i,BL_CHAR, - src,skill_id,skill_lv,tick,flag|BCT_PARTY|BCT_GUILD|1, - skill->castend_nodamage_id); + map->foreachinarea(skill->area_sub, + src->m,x-i,y-i,x+i,y+i,BL_CHAR, + src,skill_id,skill_lv,tick,flag|BCT_PARTY|BCT_GUILD|1, + skill->castend_nodamage_id); } } break; @@ -9961,8 +10341,8 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui if (rnd()%100 < 80) { int dummy = 1; clif->skill_poseffect(src,skill_id,skill_lv,x,y,tick); - i = skill->get_splash(skill_id, skill_lv); - iMap->foreachinarea(skill->cell_overlap, src->m, x-i, y-i, x+i, y+i, BL_SKILL, HW_GANBANTEIN, &dummy, src); + r = skill->get_splash(skill_id, skill_lv); + map->foreachinarea(skill->cell_overlap, src->m, x-r, y-r, x+r, y+r, BL_SKILL, HW_GANBANTEIN, &dummy, src); } else { if (sd) clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); return 1; @@ -9971,15 +10351,14 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui case HW_GRAVITATION: if ((sg = skill->unitsetting(src,skill_id,skill_lv,x,y,0))) - sc_start4(src,type,100,skill_lv,0,BCT_SELF,sg->group_id,skill->get_time(skill_id,skill_lv)); + sc_start4(src,src,type,100,skill_lv,0,BCT_SELF,sg->group_id,skill->get_time(skill_id,skill_lv)); flag|=1; break; // Plant Cultivation [Celest] case CR_CULTIVATION: if (sd) { - if( iMap->count_oncell(src->m,x,y,BL_CHAR) > 0 ) - { + if( map->count_oncell(src->m,x,y,BL_CHAR) > 0 ) { clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); return 1; } @@ -9987,16 +10366,16 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui if (rnd()%100 < 50) { clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); } else { - TBL_MOB* md = mob_once_spawn_sub(src, src->m, x, y, "--ja--",(skill_lv < 2 ? 1084+rnd()%2 : 1078+rnd()%6),"", SZ_SMALL, AI_NONE); + TBL_MOB* md = mob->once_spawn_sub(src, src->m, x, y, "--ja--",(skill_lv < 2 ? 1084+rnd()%2 : 1078+rnd()%6),"", SZ_MEDIUM, AI_NONE); int i; if (!md) break; if ((i = skill->get_time(skill_id, skill_lv)) > 0) { if( md->deletetimer != INVALID_TIMER ) - iTimer->delete_timer(md->deletetimer, mob_timer_delete); - md->deletetimer = iTimer->add_timer (tick + i, mob_timer_delete, md->bl.id, 0); + timer->delete(md->deletetimer, mob->timer_delete); + md->deletetimer = timer->add(tick + i, mob->timer_delete, md->bl.id, 0); } - mob_spawn (md); + mob->spawn (md); } } break; @@ -10006,32 +10385,30 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui case SG_STAR_WARM: skill->clear_unitgroup(src); if ((sg = skill->unitsetting(src,skill_id,skill_lv,src->x,src->y,0))) - sc_start4(src,type,100,skill_lv,0,0,sg->group_id,skill->get_time(skill_id,skill_lv)); + sc_start4(src,src,type,100,skill_lv,0,0,sg->group_id,skill->get_time(skill_id,skill_lv)); flag|=1; break; case PA_GOSPEL: - if (sce && sce->val4 == BCT_SELF) - { + if (sce && sce->val4 == BCT_SELF) { status_change_end(src, SC_GOSPEL, INVALID_TIMER); return 0; - } - else - { + } else { sg = skill->unitsetting(src,skill_id,skill_lv,src->x,src->y,0); if (!sg) break; if (sce) status_change_end(src, type, INVALID_TIMER); //Was under someone else's Gospel. [Skotlex] - sc_start4(src,type,100,skill_lv,0,sg->group_id,BCT_SELF,skill->get_time(skill_id,skill_lv)); + status->change_clear_buffs(src,3); + sc_start4(src,src,type,100,skill_lv,0,sg->group_id,BCT_SELF,skill->get_time(skill_id,skill_lv)); clif->skill_poseffect(src, skill_id, skill_lv, 0, 0, tick); // PA_GOSPEL music packet } break; case NJ_TATAMIGAESHI: if (skill->unitsetting(src,skill_id,skill_lv,src->x,src->y,0)) - sc_start(src,type,100,skill_lv,skill->get_time2(skill_id,skill_lv)); + sc_start(src,src,type,100,skill_lv,skill->get_time2(skill_id,skill_lv)); break; - case AM_RESURRECTHOMUN: //[orn] + case AM_RESURRECTHOMUN: // [orn] if (sd) { if (!homun->ressurect(sd, 20*skill_lv, x, y)) { clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); @@ -10043,18 +10420,33 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui case RK_WINDCUTTER: clif->skill_damage(src, src, tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6); case NC_COLDSLOWER: - case NC_ARMSCANNON: case RK_DRAGONBREATH: case RK_DRAGONBREATH_WATER: - i = skill->get_splash(skill_id,skill_lv); - iMap->foreachinarea(skill->area_sub,src->m,x-i,y-i,x+i,y+i,splash_target(src), - src,skill_id,skill_lv,tick,flag|BCT_ENEMY|1,skill->castend_damage_id); + 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), + src,skill_id,skill_lv,tick,flag|BCT_ENEMY|1,skill->castend_damage_id); + break; + case WM_GREAT_ECHO: + case WM_SOUND_OF_DESTRUCTION: + r = skill->get_splash(skill_id,skill_lv); + map->foreachinarea(skill->area_sub,src->m,x-r,y-r,x+r,y+r,BL_CHAR,src,skill_id,skill_lv,tick,flag|BCT_ENEMY|1,skill->castend_damage_id); + break; + + case WM_LULLABY_DEEPSLEEP: + r = skill->get_splash(skill_id,skill_lv); + map->foreachinarea(skill->area_sub,src->m,x-r,y-r,x+r,y+r,BL_CHAR, + src,skill_id,skill_lv,tick,flag|BCT_ALL|1,skill->castend_damage_id); break; + case WM_VOICEOFSIREN: + r = skill->get_splash(skill_id,skill_lv); + map->foreachinarea(skill->area_sub,src->m,x-r,y-r,x+r,y+r,BL_CHAR, + src,skill_id,skill_lv,tick,flag|BCT_ALL|1,skill->castend_damage_id); + break; case SO_ARRULLO: - i = skill->get_splash(skill_id,skill_lv); - iMap->foreachinarea(skill->area_sub,src->m,x-i,y-i,x+i,y+i,splash_target(src), - src, skill_id, skill_lv, tick, flag|BCT_ENEMY|1, skill->castend_nodamage_id); + 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), + src, skill_id, skill_lv, tick, flag|BCT_ENEMY|1, skill->castend_nodamage_id); break; /** * Guilotine Cross @@ -10074,14 +10466,14 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui **/ case AB_EPICLESIS: if( (sg = skill->unitsetting(src, skill_id, skill_lv, x, y, 0)) ) { - i = sg->unit->range; - iMap->foreachinarea(skill->area_sub, src->m, x - i, y - i, x + i, y + i, BL_CHAR, src, ALL_RESURRECTION, 1, tick, flag|BCT_NOENEMY|1,skill->castend_nodamage_id); + r = sg->unit->range; + map->foreachinarea(skill->area_sub, src->m, x - r, y - r, x + r, y + r, BL_CHAR, src, ALL_RESURRECTION, 1, tick, flag|BCT_NOENEMY|1,skill->castend_nodamage_id); } break; case WL_EARTHSTRAIN: { - int i, wave = skill_lv + 4, dir = iMap->calc_dir(src,x,y); + int i, wave = skill_lv + 4, dir = map->calc_dir(src,x,y); int sx = x = src->x, sy = y = src->y; // Store first caster's location to avoid glitch on unit setting for( i = 1; i <= wave; i++ ) @@ -10092,7 +10484,7 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui case 2: sx = x - i; break; case 6: sx = x + i; break; } - skill->addtimerskill(src,iTimer->gettick() + (50 * i),0,sx,sy,skill_id,skill_lv,dir,flag&2); + skill->addtimerskill(src,timer->gettick() + (140 * i),0,sx,sy,skill_id,skill_lv,dir,flag&2); } } break; @@ -10100,8 +10492,8 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui * Ranger **/ case RA_DETONATOR: - i = skill->get_splash(skill_id, skill_lv); - iMap->foreachinarea(skill->detonator, src->m, x-i, y-i, x+i, y+i, BL_SKILL, src); + r = skill->get_splash(skill_id, skill_lv); + map->foreachinarea(skill->detonator, src->m, x-r, y-r, x+r, y+r, BL_SKILL, src); clif->skill_damage(src, src, tick, status_get_amotion(src), 0, -30000, 1, skill_id, skill_lv, 6); break; /** @@ -10111,7 +10503,7 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui case NC_STEALTHFIELD: skill->clear_unitgroup(src); // To remove previous skills - cannot used combined if( (sg = skill->unitsetting(src,skill_id,skill_lv,src->x,src->y,0)) != NULL ) { - sc_start2(src,skill_id == NC_NEUTRALBARRIER ? SC_NEUTRALBARRIER_MASTER : SC_STEALTHFIELD_MASTER,100,skill_lv,sg->group_id,skill->get_time(skill_id,skill_lv)); + sc_start2(src,src,skill_id == NC_NEUTRALBARRIER ? SC_NEUTRALBARRIER_MASTER : SC_STEALTHFIELD_MASTER,100,skill_lv,sg->group_id,skill->get_time(skill_id,skill_lv)); if( sd ) pc->overheat(sd,1); } break; @@ -10121,15 +10513,14 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui int class_ = 2042; struct mob_data *md; - md = mob_once_spawn_sub(src, src->m, x, y, status_get_name(src), class_, "", SZ_SMALL, AI_NONE); - if( md ) - { + md = mob->once_spawn_sub(src, src->m, x, y, status->get_name(src), class_, "", SZ_MEDIUM, AI_NONE); + if( md ) { md->master_id = src->id; md->special_state.ai = AI_FLORA; if( md->deletetimer != INVALID_TIMER ) - iTimer->delete_timer(md->deletetimer, mob_timer_delete); - md->deletetimer = iTimer->add_timer (iTimer->gettick() + skill->get_time(skill_id, skill_lv), mob_timer_delete, md->bl.id, 0); - mob_spawn( md ); + timer->delete(md->deletetimer, mob->timer_delete); + md->deletetimer = timer->add(timer->gettick() + skill->get_time(skill_id, skill_lv), mob->timer_delete, md->bl.id, 0); + mob->spawn( md ); } } break; @@ -10139,67 +10530,83 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui break; case SC_FEINTBOMB: - skill->unitsetting(src,skill_id,skill_lv,x,y,0); // Set bomb on current Position - clif->skill_nodamage(src,src,skill_id,skill_lv,1); - if( skill->blown(src,src,6,unit_getdir(src),0) ) - skill->castend_nodamage_id(src,src,TF_HIDING,1,tick,0x2); + skill->unitsetting(src, skill_id, skill_lv, x, y, 0); // Set bomb on current Position + clif->skill_nodamage(src, src, skill_id, skill_lv, 1); + if( skill->blown(src, src, 3 * skill_lv, unit->getdir(src), 0) && sc) { + sc_start(src, src, SC__FEINTBOMB_MASTER, 100, 0, skill->get_unit_interval(SC_FEINTBOMB)); + } + break; + + case SC_ESCAPE: + clif->skill_nodamage(src,src,skill_id,-1,1); + skill->unitsetting(src,HT_ANKLESNARE,skill_lv,x,y,2); + skill->addtimerskill(src,tick,src->id,0,0,skill_id,skill_lv,0,0); break; case LG_OVERBRAND: - { - int width;//according to data from irowiki it actually is a square - for( width = 0; width < 7; width++ ) - for( i = 0; i < 7; i++ ) - iMap->foreachincell(skill->area_sub, src->m, x-2+i, y-2+width, splash_target(src), src, LG_OVERBRAND_BRANDISH, skill_lv, tick, flag|BCT_ENEMY,skill->castend_damage_id); - for( width = 0; width < 7; width++ ) - for( i = 0; i < 7; i++ ) - iMap->foreachincell(skill->area_sub, src->m, x-2+i, y-2+width, splash_target(src), src, skill_id, skill_lv, tick, flag|BCT_ENEMY,skill->castend_damage_id); - } + skill->area_temp[1] = 0; + map->foreachinpath(skill->attack_area,src->m,src->x,src->y,x,y,1,5,BL_CHAR, + skill->get_type(skill_id),src,src,skill_id,skill_lv,tick,flag,BCT_ENEMY); + skill->addtimerskill(src,timer->gettick() + status_get_amotion(src), 0, x, y, LG_OVERBRAND_BRANDISH, skill_lv, 0, flag); break; case LG_BANDING: if( sc && sc->data[SC_BANDING] ) status_change_end(src,SC_BANDING,INVALID_TIMER); else if( (sg = skill->unitsetting(src,skill_id,skill_lv,src->x,src->y,0)) != NULL ) { - sc_start4(src,SC_BANDING,100,skill_lv,0,0,sg->group_id,skill->get_time(skill_id,skill_lv)); + sc_start4(src,src,SC_BANDING,100,skill_lv,0,0,sg->group_id,skill->get_time(skill_id,skill_lv)); if( sd ) pc->banding(sd,skill_lv); } clif->skill_nodamage(src,src,skill_id,skill_lv,1); break; case LG_RAYOFGENESIS: - if( status_charge(src,status_get_max_hp(src)*3*skill_lv / 100,0) ) { - i = skill->get_splash(skill_id,skill_lv); - iMap->foreachinarea(skill->area_sub,src->m,x-i,y-i,x+i,y+i,splash_target(src), + 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), 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); break; case WM_DOMINION_IMPULSE: - i = skill->get_splash(skill_id, skill_lv); - iMap->foreachinarea( skill->activate_reverberation, - src->m, x-i, y-i, x+i,y+i,BL_SKILL); + r = skill->get_splash(skill_id, skill_lv); + map->foreachinarea( skill->activate_reverberation,src->m, x-r, y-r, x+r,y+r,BL_SKILL); break; - case WM_GREAT_ECHO: - flag|=1; // Should counsume 1 item per skill usage. - iMap->foreachinrange(skill->area_sub, src, skill->get_splash(skill_id,skill_lv),splash_target(src), src, skill_id, skill_lv, tick, flag|BCT_ENEMY, skill->castend_damage_id); - break; - case GN_CRAZYWEED: { - int area = skill->get_splash(GN_CRAZYWEED_ATK, skill_lv); - short x1 = 0, y1 = 0; + case GN_CRAZYWEED: + { + int area = skill->get_splash(skill_id, skill_lv); + short tmpx = 0, tmpy = 0, x1 = 0, y1 = 0; - for( i = 0; i < 3 + (skill_lv/2); i++ ) { - x1 = x - area + rnd()%(area * 2 + 1); - y1 = y - area + rnd()%(area * 2 + 1); - skill->addtimerskill(src,tick+i*150,0,x1,y1,GN_CRAZYWEED_ATK,skill_lv,-1,0); + for( r = 0; r < 3 + (skill_lv>>1); r++ ) { + // Creates a random Cell in the Splash Area + tmpx = x - area + rnd()%(area * 2 + 1); + tmpy = y - area + rnd()%(area * 2 + 1); + + if( r > 0 ) + skill->addtimerskill(src,tick+r*250,0,tmpx,tmpy,GN_CRAZYWEED,skill_lv,(x1<<16)|y1,flag); + + x1 = tmpx; + y1 = tmpy; } + + skill->addtimerskill(src,tick+r*250,0,tmpx,tmpy,GN_CRAZYWEED,skill_lv,-1,flag); + } + break; + + case GN_CRAZYWEED_ATK: { + int dummy = 1; + //Enable if any unique animation gets added to this skill ID in the future. [Rytech] + //clif_skill_poseffect(src,skillid,skilllv,x,y,tick); + r = skill->get_splash(skill_id, skill_lv); + map->foreachinarea(skill->cell_overlap, src->m, x-r, y-r, x+r, y+r, BL_SKILL, skill_id, &dummy, src); + map->foreachinarea(skill->area_sub, src->m, x-r, y-r, x+r, y+r, BL_CHAR, src, skill_id, skill_lv, tick, flag|BCT_ENEMY|1, skill->castend_damage_id); } break; case GN_FIRE_EXPANSION: { int i; - struct unit_data *ud = unit_bl2ud(src); + struct unit_data *ud = unit->bl2ud(src); if( !ud ) break; @@ -10216,10 +10623,10 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui clif->changetraplook(&ud->skillunit[i]->unit->bl, UNT_FIRE_EXPANSION_TEAR_GAS); break; case 5: - iMap->foreachinarea(skill->area_sub, src->m, - ud->skillunit[i]->unit->bl.x - 3, ud->skillunit[i]->unit->bl.y - 3, - ud->skillunit[i]->unit->bl.x + 3, ud->skillunit[i]->unit->bl.y + 3, BL_CHAR, - src, CR_ACIDDEMONSTRATION, sd ? pc->checkskill(sd, CR_ACIDDEMONSTRATION) : skill_lv, tick, flag|BCT_ENEMY|1|SD_LEVEL, skill->castend_damage_id); + map->foreachinarea(skill->area_sub, src->m, + ud->skillunit[i]->unit->bl.x - 3, ud->skillunit[i]->unit->bl.y - 3, + ud->skillunit[i]->unit->bl.x + 3, ud->skillunit[i]->unit->bl.y + 3, BL_CHAR, + src, CR_ACIDDEMONSTRATION, sd ? pc->checkskill(sd, CR_ACIDDEMONSTRATION) : skill_lv, tick, flag|BCT_ENEMY|1|SD_LEVEL, skill->castend_damage_id); skill->delunit(ud->skillunit[i]->unit); break; default: @@ -10237,20 +10644,18 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui if( sc && sc->data[type] ) status_change_end(src,type,INVALID_TIMER); clif->skill_nodamage(src, src ,skill_id, skill_lv, - sc_start2(src, type, 100, skill_id, skill_lv, skill->get_time(skill_id, skill_lv))); + sc_start2(src,src, type, 100, skill_id, skill_lv, skill->get_time(skill_id, skill_lv))); break; - case SC_BLOODYLUST: //set in another group so instance will move if recasted - flag |= 33; - skill->unitsetting(src, skill_id, skill_lv, x, y, 0); - break; - case KO_MAKIBISHI: + { + int i; for( i = 0; i < (skill_lv+2); i++ ) { x = src->x - 1 + rnd()%3; y = src->y - 1 + rnd()%3; skill->unitsetting(src,skill_id,skill_lv,x,y,0); } + } break; default: @@ -10262,7 +10667,7 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui status_change_end(src,SC_CURSEDCIRCLE_ATKER,INVALID_TIMER); if( sd ) {// ensure that the skill last-cast tick is recorded - sd->canskill_tick = iTimer->gettick(); + sd->canskill_tick = timer->gettick(); if( sd->state.arrow_atk && !(flag&1) ) { // consume arrow if this is a ground skill @@ -10294,7 +10699,7 @@ int skill_dance_overlap_sub(struct block_list* bl, va_list ap) { else //Remove dissonance target->val2 &= ~UF_ENSEMBLE; - clif->skill_setunit(target); //Update look of affected cell. + clif->getareachar_skillunit(&target->bl,target,AREA); //Update look of affected cell. return 1; } @@ -10302,32 +10707,38 @@ int skill_dance_overlap_sub(struct block_list* bl, va_list ap) { //Does the song/dance overlapping -> dissonance check. [Skotlex] //When flag is 0, this unit is about to be removed, cancel the dissonance effect //When 1, this unit has been positioned, so start the cancel effect. -int skill_dance_overlap(struct skill_unit* unit, int flag) { - if (!unit || !unit->group || !(unit->group->state.song_dance&0x1)) +int skill_dance_overlap(struct skill_unit* su, int flag) { + if (!su || !su->group || !(su->group->state.song_dance&0x1)) return 0; - if (!flag && !(unit->val2&UF_ENSEMBLE)) - return 0; //Nothing to remove, this unit is not overlapped. - - if (unit->val1 != unit->group->skill_id) { + + if (su->val1 != su->group->skill_id) { //Reset state - unit->val1 = unit->group->skill_id; - unit->val2 &= ~UF_ENSEMBLE; + su->val1 = su->group->skill_id; + su->val2 &= ~UF_ENSEMBLE; } - - return iMap->foreachincell(skill->dance_overlap_sub, unit->bl.m,unit->bl.x,unit->bl.y,BL_SKILL, unit,flag); + + return map->foreachincell(skill->dance_overlap_sub, su->bl.m,su->bl.x,su->bl.y,BL_SKILL, su,flag); } -/*========================================== +/** * Converts this group information so that it is handled as a Dissonance or Ugly Dance cell. - * Flag: 0 - Convert, 1 - Revert. - *------------------------------------------*/ -bool skill_dance_switch(struct skill_unit* unit, int flag) { + * This function is safe to call even when the unit or the group were freed by other function + * previously. + * @param su Skill unit data (from BA_DISSONANCE or DC_UGLYDANCE) + * @param flag 0 Convert + * @param flag 1 Revert + * @retval true success + **/ +bool skill_dance_switch(struct skill_unit* su, int flag) { static int prevflag = 1; // by default the backup is empty static struct skill_unit_group backup; - struct skill_unit_group* group = unit->group; + struct skill_unit_group* group; + + if( su == NULL || (group = su->group) == NULL ) + return false; // val2&UF_ENSEMBLE is a hack to indicate dissonance - if ( !(group->state.song_dance&0x1 && unit->val2&UF_ENSEMBLE) ) + if ( !(group->state.song_dance&0x1 && su->val2&UF_ENSEMBLE) ) return false; if( flag == prevflag ) { @@ -10340,7 +10751,7 @@ bool skill_dance_switch(struct skill_unit* unit, int flag) { prevflag = flag; if( !flag ) { //Transform - uint16 skill_id = unit->val2&UF_SONG ? BA_DISSONANCE : DC_UGLYDANCE; + uint16 skill_id = su->val2&UF_SONG ? BA_DISSONANCE : DC_UGLYDANCE; // backup backup.skill_id = group->skill_id; @@ -10377,14 +10788,14 @@ int skill_icewall_block(struct block_list *bl,va_list ap) { nullpo_ret(bl); nullpo_ret(md); - if( !md->target_id || ( target = iMap->id2bl(md->target_id) ) == NULL ) + if( !md->target_id || ( target = map->id2bl(md->target_id) ) == NULL ) return 0; - if( path_search_long(NULL,bl->m,bl->x,bl->y,target->x,target->y,CELL_CHKICEWALL) ) + if( path->search_long(NULL,bl->m,bl->x,bl->y,target->x,target->y,CELL_CHKICEWALL) ) return 0; if( !check_distance_bl(bl, target, status_get_range(bl) ) ) { - mob_unlocktarget(md,iTimer->gettick()); + mob->unlocktarget(md,timer->gettick()); mob_stop_walking(md,1); } @@ -10394,14 +10805,13 @@ int skill_icewall_block(struct block_list *bl,va_list ap) { * Initializes and sets a ground skill. * flag&1 is used to determine when the skill 'morphs' (Warp portal becomes active, or Fire Pillar becomes active) *------------------------------------------*/ -struct skill_unit_group* skill_unitsetting (struct block_list *src, uint16 skill_id, uint16 skill_lv, int16 x, int16 y, int flag) -{ +struct skill_unit_group* skill_unitsetting(struct block_list *src, uint16 skill_id, uint16 skill_lv, int16 x, int16 y, int flag) { struct skill_unit_group *group; int i,limit,val1=0,val2=0,val3=0; int target,interval,range,unit_flag,req_item=0; struct s_skill_unit_layout *layout; struct map_session_data *sd; - struct status_data *status; + struct status_data *st; struct status_change *sc; int active_flag=1; int subunt=0; @@ -10415,19 +10825,22 @@ struct skill_unit_group* skill_unitsetting (struct block_list *src, uint16 skill unit_flag = skill->get_unit_flag(skill_id); layout = skill->get_unit_layout(skill_id,skill_lv,src,x,y); - if( map[src->m].unit_count ) { - ARR_FIND(0, map[src->m].unit_count, i, map[src->m].units[i]->skill_id == skill_id ); + if( map->list[src->m].unit_count ) { + ARR_FIND(0, map->list[src->m].unit_count, i, map->list[src->m].units[i]->skill_id == skill_id ); - if( i < map[src->m].unit_count ) { - limit = limit * map[src->m].units[i]->modifier / 100; + if( i < map->list[src->m].unit_count ) { + limit = limit * map->list[src->m].units[i]->modifier / 100; } } sd = BL_CAST(BL_PC, src); - status = status_get_status_data(src); - sc = status_get_sc(src); // for traps, firewall and fogwall - celest + st = status->get_status_data(src); + sc = status->get_sc(src); // for traps, firewall and fogwall - celest switch( skill_id ) { + case SO_ELEMENTAL_SHIELD: + val2 = 300 * skill_lv + 65 * (st->int_ + status->get_lv(src)) + st->max_sp; + break; case MH_STEINWAND: val2 = 4 + skill_lv; //nb of attack blocked break; @@ -10455,7 +10868,7 @@ struct skill_unit_group* skill_unitsetting (struct block_list *src, uint16 skill { //Warp Portal morphing to active mode, extract relevant data from src. [Skotlex] if( src->type != BL_SKILL ) return NULL; group = ((TBL_SKILL*)src)->group; - src = iMap->id2bl(group->src_id); + src = map->id2bl(group->src_id); if( !src ) return NULL; val2 = group->val2; //Copy the (x,y) position you warp to val3 = group->val3; //as well as the mapindex to warp to. @@ -10471,7 +10884,7 @@ struct skill_unit_group* skill_unitsetting (struct block_list *src, uint16 skill break; case WZ_FIREPILLAR: - if( iMap->getcell(src->m, x, y, CELL_CHKLANDPROTECTOR) ) + if( map->getcell(src->m, x, y, CELL_CHKLANDPROTECTOR) ) return NULL; if((flag&1)!=0) limit=1000; @@ -10480,10 +10893,15 @@ struct skill_unit_group* skill_unitsetting (struct block_list *src, uint16 skill case WZ_QUAGMIRE: //The target changes to "all" if used in a gvg map. [Skotlex] case AM_DEMONSTRATION: case GN_HELLS_PLANT: + if( skill_id == GN_HELLS_PLANT && map->getcell(src->m, x, y, CELL_CHKLANDPROTECTOR) ) + return NULL; if (map_flag_vs(src->m) && battle_config.vs_traps_bctall && (src->type&battle_config.vs_traps_bctall)) target = BCT_ALL; break; + case HT_ANKLESNARE: + if( flag&2 ) + val3 = SC_ESCAPE; case HT_SHOCKWAVE: val1=skill_lv*15+10; case HT_SANDMAN: @@ -10493,7 +10911,6 @@ struct skill_unit_group* skill_unitsetting (struct block_list *src, uint16 skill case MA_SKIDTRAP: case HT_LANDMINE: case MA_LANDMINE: - case HT_ANKLESNARE: case HT_FLASHER: case HT_FREEZINGTRAP: case MA_FREEZINGTRAP: @@ -10512,9 +10929,9 @@ struct skill_unit_group* skill_unitsetting (struct block_list *src, uint16 skill { struct skill_condition req = skill->get_requirement(sd,skill_id,skill_lv); ARR_FIND(0, MAX_SKILL_ITEM_REQUIRE, i, req.itemid[i] && (req.itemid[i] == ITEMID_TRAP || req.itemid[i] == ITEMID_TRAP_ALLOY)); - if( req.itemid[i] ) + if( i != MAX_SKILL_ITEM_REQUIRE && req.itemid[i] ) req_item = req.itemid[i]; - if( map_flag_gvg(src->m) || map[src->m].flag.battleground ) + if( map_flag_gvg2(src->m) || map->list[src->m].flag.battleground ) limit *= 4; // longer trap times in WOE [celest] if( battle_config.vs_traps_bctall && map_flag_vs(src->m) && (src->type&battle_config.vs_traps_bctall) ) target = BCT_ALL; @@ -10536,7 +10953,7 @@ struct skill_unit_group* skill_unitsetting (struct block_list *src, uint16 skill old_sg->skill_id == SA_VIOLENTGALE ) && old_sg->limit > 0) { //Use the previous limit (minus the elapsed time) [Skotlex] - limit = old_sg->limit - DIFF_TICK(iTimer->gettick(), old_sg->tick); + limit = old_sg->limit - DIFF_TICK32(timer->gettick(), old_sg->tick); if (limit < 0) //This can happen... limit = skill->get_time(skill_id,skill_lv); } @@ -10547,18 +10964,18 @@ struct skill_unit_group* skill_unitsetting (struct block_list *src, uint16 skill case BA_DISSONANCE: case DC_UGLYDANCE: - val1 = 10; //FIXME: This value is not used anywhere, what is it for? [Skotlex] + val1 = 10; //FIXME: This value is not used anywhere, what is it for? [Skotlex] break; case BA_WHISTLE: - val1 = skill_lv +status->agi/10; // Flee increase - val2 = ((skill_lv+1)/2)+status->luk/10; // Perfect dodge increase + val1 = skill_lv +st->agi/10; // Flee increase + val2 = ((skill_lv+1)/2)+st->luk/10; // Perfect dodge increase if(sd){ val1 += pc->checkskill(sd,BA_MUSICALLESSON); val2 += pc->checkskill(sd,BA_MUSICALLESSON); } break; case DC_HUMMING: - val1 = 2*skill_lv+status->dex/10; // Hit increase + val1 = 2*skill_lv+st->dex/10; // Hit increase #ifdef RENEWAL val1 *= 2; #endif @@ -10566,9 +10983,9 @@ struct skill_unit_group* skill_unitsetting (struct block_list *src, uint16 skill val1 += pc->checkskill(sd,DC_DANCINGLESSON); break; case BA_POEMBRAGI: - val1 = 3*skill_lv+status->dex/10; // Casting time reduction + val1 = 3*skill_lv+st->dex/10; // Casting time reduction //For some reason at level 10 the base delay reduction is 50%. - val2 = (skill_lv<10?3*skill_lv:50)+status->int_/5; // After-cast delay reduction + val2 = (skill_lv<10?3*skill_lv:50)+st->int_/5; // After-cast delay reduction if(sd){ val1 += 2*pc->checkskill(sd,BA_MUSICALLESSON); val2 += 2*pc->checkskill(sd,BA_MUSICALLESSON); @@ -10576,11 +10993,11 @@ struct skill_unit_group* skill_unitsetting (struct block_list *src, uint16 skill break; case DC_DONTFORGETME: #ifdef RENEWAL - val1 = status->dex/10 + 3*skill_lv; // ASPD decrease - val2 = status->agi/10 + 2*skill_lv; // Movement speed adjustment. + val1 = st->dex/10 + 3*skill_lv; // ASPD decrease + val2 = st->agi/10 + 2*skill_lv; // Movement speed adjustment. #else - val1 = status->dex/10 + 3*skill_lv + 5; // ASPD decrease - val2 = status->agi/10 + 3*skill_lv + 5; // Movement speed adjustment. + val1 = st->dex/10 + 3*skill_lv + 5; // ASPD decrease + val2 = st->agi/10 + 3*skill_lv + 5; // Movement speed adjustment. #endif if(sd){ val1 += pc->checkskill(sd,DC_DANCINGLESSON); @@ -10588,13 +11005,13 @@ struct skill_unit_group* skill_unitsetting (struct block_list *src, uint16 skill } break; case BA_APPLEIDUN: - val1 = 5+2*skill_lv+status->vit/10; // MaxHP percent increase + val1 = 5+2*skill_lv+st->vit/10; // MaxHP percent increase if(sd) val1 += pc->checkskill(sd,BA_MUSICALLESSON); break; case DC_SERVICEFORYOU: - val1 = 15+skill_lv+(status->int_/10); // MaxSP percent increase TO-DO: this INT bonus value is guessed - val2 = 20+3*skill_lv+(status->int_/10); // SP cost reduction + val1 = 15+skill_lv+(st->int_/10); // MaxSP percent increase TO-DO: this INT bonus value is guessed + val2 = 20+3*skill_lv+(st->int_/10); // SP cost reduction if(sd){ val1 += pc->checkskill(sd,DC_DANCINGLESSON); //TO-DO This bonus value is guessed val2 += pc->checkskill(sd,DC_DANCINGLESSON); //TO-DO Should be half this value @@ -10602,17 +11019,17 @@ struct skill_unit_group* skill_unitsetting (struct block_list *src, uint16 skill break; case BA_ASSASSINCROSS: #ifdef RENEWAL - val1 = 10 + skill_lv + (status->agi/10); // ASPD increase + val1 = 10 + skill_lv + (st->agi/10); // ASPD increase if(sd) val1 += 4*pc->checkskill(sd,BA_MUSICALLESSON); #else - val1 = 100+(10*skill_lv)+(status->agi/10); // ASPD increase + val1 = 100+(10*skill_lv)+(st->agi/10); // ASPD increase if(sd) val1 += 5*pc->checkskill(sd,BA_MUSICALLESSON); #endif break; case DC_FORTUNEKISS: - val1 = 10+skill_lv+(status->luk/10); // Critical increase + val1 = 10+skill_lv+(st->luk/10); // Critical increase if(sd) val1 += pc->checkskill(sd,DC_DANCINGLESSON); val1*=10; //Because every 10 crit is an actual cri point. @@ -10660,7 +11077,7 @@ struct skill_unit_group* skill_unitsetting (struct block_list *src, uint16 skill { int element[5]={ELE_WIND,ELE_DARK,ELE_POISON,ELE_WATER,ELE_FIRE}; - val1 = status->rhw.ele; + val1 = st->rhw.ele; if (!val1) val1=element[rnd()%5]; @@ -10706,10 +11123,16 @@ struct skill_unit_group* skill_unitsetting (struct block_list *src, uint16 skill limit = -1; break; case WM_REVERBERATION: - interval = limit; + if( battle_config.vs_traps_bctall && map_flag_vs(src->m) && (src->type&battle_config.vs_traps_bctall) ) + target = BCT_ALL; + val1 = skill_lv + 1; val2 = 1; - case WM_POEMOFNETHERWORLD: // Can't be placed on top of Land Protector. - if( iMap->getcell(src->m, x, y, CELL_CHKLANDPROTECTOR) ) + case WM_POEMOFNETHERWORLD: // Can't be placed on top of Land Protector. + case SO_WATER_INSIGNIA: + case SO_FIRE_INSIGNIA: + case SO_WIND_INSIGNIA: + case SO_EARTH_INSIGNIA: + if( map->getcell(src->m, x, y, CELL_CHKLANDPROTECTOR) ) return NULL; break; case SO_CLOUD_KILL: @@ -10718,12 +11141,6 @@ struct skill_unit_group* skill_unitsetting (struct block_list *src, uint16 skill case SO_WARMER: skill->clear_group(src, 8); break; - case SO_VACUUM_EXTREME: - range++; - break; - case SC_BLOODYLUST: - skill->clear_group(src, 32); - break; case GN_WALLOFTHORN: if( flag&1 ) limit = 3000; @@ -10754,7 +11171,7 @@ struct skill_unit_group* skill_unitsetting (struct block_list *src, uint16 skill group->state.guildaura = ( skill_id >= GD_LEADERSHIP && skill_id <= GD_HAWKEYES )?1:0; group->item_id = req_item; //if tick is greater than current, do not invoke onplace function just yet. [Skotlex] - if (DIFF_TICK(group->tick, iTimer->gettick()) > SKILLUNITTIMER_INTERVAL) + if (DIFF_TICK(group->tick, timer->gettick()) > SKILLUNITTIMER_INTERVAL) active_flag = 0; if(skill_id==HT_TALKIEBOX || skill_id==RG_GRAFFITI){ @@ -10771,7 +11188,7 @@ struct skill_unit_group* skill_unitsetting (struct block_list *src, uint16 skill sd->skill_lv_dance = skill_lv; } if ( - sc_start4(src, SC_DANCING, 100, skill_id, group->group_id, skill_lv, + sc_start4(src,src, SC_DANCING, 100, skill_id, group->group_id, skill_lv, (group->state.song_dance&2?BCT_SELF:0), limit+1000) && sd && group->state.song_dance&2 && skill_id != CG_HERMODE //Hermod is a encore with a warp! ) @@ -10780,16 +11197,16 @@ struct skill_unit_group* skill_unitsetting (struct block_list *src, uint16 skill limit = group->limit; for( i = 0; i < layout->count; i++ ) { - struct skill_unit *unit; + struct skill_unit *su; int ux = x + layout->dx[i]; int uy = y + layout->dy[i]; - int val1 = skill_lv; - int val2 = 0; int alive = 1; + val1 = skill_lv; + val2 = 0; - if( !group->state.song_dance && !iMap->getcell(src->m,ux,uy,CELL_CHKREACH) ) + if( !group->state.song_dance && !map->getcell(src->m,ux,uy,CELL_CHKREACH) ) continue; // don't place skill units on walls (except for songs/dances/encores) - if( battle_config.skill_wall_check && skill->get_unit_flag(skill_id)&UF_PATHCHECK && !path_search_long(NULL,src->m,ux,uy,x,y,CELL_CHKWALL) ) + if( battle_config.skill_wall_check && skill->get_unit_flag(skill_id)&UF_PATHCHECK && !path->search_long(NULL,src->m,ux,uy,x,y,CELL_CHKWALL) ) continue; // no path between cell and center of casting. switch( skill_id ) { @@ -10799,7 +11216,7 @@ struct skill_unit_group* skill_unitsetting (struct block_list *src, uint16 skill break; case WZ_ICEWALL: val1 = (skill_lv <= 1) ? 500 : 200 + 200*skill_lv; - val2 = iMap->getcell(src->m, ux, uy, CELL_GETTYPE); + val2 = map->getcell(src->m, ux, uy, CELL_GETTYPE); break; case HT_LANDMINE: case MA_LANDMINE: @@ -10837,11 +11254,9 @@ struct skill_unit_group* skill_unitsetting (struct block_list *src, uint16 skill if (val1 < 1) val1 = 1; val2 = 0; break; - case WM_REVERBERATION: - val1 = 1 + skill_lv; - break; case GN_WALLOFTHORN: - val1 = 1000 * skill_lv; // Need official value. [LimitLine] + val1 = 2000 + 2000 * skill_lv; + val2 = src->id; break; default: if (group->state.song_dance&0x1) @@ -10852,26 +11267,27 @@ struct skill_unit_group* skill_unitsetting (struct block_list *src, uint16 skill val2 |= UF_RANGEDSINGLEUNIT; // center. if( range <= 0 ) - iMap->foreachincell(skill->cell_overlap,src->m,ux,uy,BL_SKILL,skill_id, &alive, src); + map->foreachincell(skill->cell_overlap,src->m,ux,uy,BL_SKILL,skill_id, &alive, src); if( !alive ) continue; - nullpo_retr(NULL, unit=skill->initunit(group,i,ux,uy,val1,val2)); - unit->limit=limit; - unit->range=range; + nullpo_retr(NULL, su=skill->initunit(group,i,ux,uy,val1,val2)); + su->limit=limit; + su->range=range; if (skill_id == PF_FOGWALL && alive == 2) { //Double duration of cells on top of Deluge/Suiton - unit->limit *= 2; - group->limit = unit->limit; + su->limit *= 2; + group->limit = su->limit; } // execute on all targets standing on this cell if (range==0 && active_flag) - iMap->foreachincell(skill->unit_effect,unit->bl.m,unit->bl.x,unit->bl.y,group->bl_flag,&unit->bl,iTimer->gettick(),1); + map->foreachincell(skill->unit_effect,su->bl.m,su->bl.x,su->bl.y,group->bl_flag,&su->bl,timer->gettick(),1); } - if (!group->alive_count) { //No cells? Something that was blocked completely by Land Protector? + if (!group->alive_count) { + //No cells? Something that was blocked completely by Land Protector? skill->del_unitgroup(group,ALC_MARK); return NULL; } @@ -10879,7 +11295,7 @@ struct skill_unit_group* skill_unitsetting (struct block_list *src, uint16 skill //success, unit created. switch( skill_id ) { case WZ_ICEWALL: - iMap->foreachinrange(skill->icewall_block, src, AREA_SIZE, BL_MOB); + map->foreachinrange(skill->icewall_block, src, AREA_SIZE, BL_MOB); break; case NJ_TATAMIGAESHI: //Store number of tiles. group->val1 = group->alive_count; @@ -10892,7 +11308,7 @@ struct skill_unit_group* skill_unitsetting (struct block_list *src, uint16 skill /*========================================== * *------------------------------------------*/ -int skill_unit_onplace (struct skill_unit *src, struct block_list *bl, unsigned int tick) { +int skill_unit_onplace(struct skill_unit *src, struct block_list *bl, int64 tick) { struct skill_unit_group *sg; struct block_list *ss; struct status_change *sc; @@ -10903,21 +11319,23 @@ int skill_unit_onplace (struct skill_unit *src, struct block_list *bl, unsigned nullpo_ret(src); nullpo_ret(bl); - if(bl->prev==NULL || !src->alive || status_isdead(bl)) + if(bl->prev==NULL || !src->alive || status->isdead(bl)) return 0; nullpo_ret(sg=src->group); - nullpo_ret(ss=iMap->id2bl(sg->src_id)); + nullpo_ret(ss=map->id2bl(sg->src_id)); - if( skill->get_type(sg->skill_id) == BF_MAGIC && iMap->getcell(bl->m, bl->x, bl->y, CELL_CHKLANDPROTECTOR) && sg->skill_id != SA_LANDPROTECTOR ) + if( skill->get_type(sg->skill_id) == BF_MAGIC && map->getcell(bl->m, bl->x, bl->y, CELL_CHKLANDPROTECTOR) && sg->skill_id != SA_LANDPROTECTOR ) return 0; //AoE skills are ineffective. [Skotlex] - - sc = status_get_sc(bl); + sc = status->get_sc(bl); if (sc && sc->option&OPTION_HIDE && sg->skill_id != WZ_HEAVENDRIVE && sg->skill_id != WL_EARTHSTRAIN ) return 0; //Hidden characters are immune to AoE skills except to these. [Skotlex] - type = status_skill2sc(sg->skill_id); + if (sc && sc->data[SC_VACUUM_EXTREME] && map->getcell(bl->m, bl->x, bl->y, CELL_CHKLANDPROTECTOR)) + status_change_end(bl, SC_VACUUM_EXTREME, INVALID_TIMER); + + type = status->skill2sc(sg->skill_id); sce = (sc && type != -1)?sc->data[type]:NULL; skill_id = sg->skill_id; //In case the group is deleted, we need to return the correct skill id, still. switch (sg->unit_id) { @@ -10928,44 +11346,36 @@ int skill_unit_onplace (struct skill_unit *src, struct block_list *bl, unsigned break; } else if( sc && battle->check_target(&sg->unit->bl,bl,sg->target_flag) > 0 ) { int sec = skill->get_time2(sg->skill_id,sg->skill_lv); - if( status_change_start(bl,type,10000,sg->skill_lv,1,sg->group_id,0,sec,8) ) { - const struct TimerData* td = sc->data[type]?iTimer->get_timer(sc->data[type]->timer):NULL; + if( status->change_start(ss, bl,type,10000,sg->skill_lv,1,sg->group_id,0,sec,8) ) { + const struct TimerData* td = sc->data[type]?timer->get(sc->data[type]->timer):NULL; if( td ) - sec = DIFF_TICK(td->tick, tick); - iMap->moveblock(bl, src->bl.x, src->bl.y, tick); + sec = DIFF_TICK32(td->tick, tick); + map->moveblock(bl, src->bl.x, src->bl.y, tick); clif->fixpos(bl); sg->val2 = bl->id; } else sec = 3000; //Couldn't trap it? - sg->limit = DIFF_TICK(tick,sg->tick)+sec; + sg->limit = DIFF_TICK32(tick,sg->tick)+sec; } break; case UNT_SAFETYWALL: if (!sce) - sc_start4(bl,type,100,sg->skill_lv,sg->skill_id,sg->group_id,0,sg->limit); + sc_start4(ss,bl,type,100,sg->skill_lv,sg->skill_id,sg->group_id,0,sg->limit); + break; + case UNT_BLOODYLUST: + if (sg->src_id == bl->id) + break; //Does not affect the caster. + if (bl->type == BL_MOB) + break; //Does not affect the caster. + if( !sce && sc_start4(ss,bl,type,100,sg->skill_lv,0,SC__BLOODYLUST,0,sg->limit) ) + sc_start(ss,bl,SC__BLOODYLUST,100,sg->skill_lv,sg->limit); break; - case UNT_PNEUMA: case UNT_CHAOSPANIC: case UNT_MAELSTROM: if (!sce) - sc_start4(bl,type,100,sg->skill_lv,sg->group_id,0,0,sg->limit); - break; - case UNT_BLOODYLUST: - if (sg->src_id == bl->id) - break; //Does not affect the caster. - if (!sce) { - TBL_PC *sd = BL_CAST(BL_PC, bl); //prevent fullheal exploit - if (sd && sd->bloodylust_tick && DIFF_TICK(iTimer->gettick(), sd->bloodylust_tick) < skill->get_time2(SC_BLOODYLUST, 1)) - clif->skill_nodamage(&src->bl,bl,sg->skill_id,sg->skill_lv, - sc_start4(bl, type, 100, sg->skill_lv, 1, 0, 0, skill->get_time(LK_BERSERK, sg->skill_lv))); - else { - if (sd) sd->bloodylust_tick = iTimer->gettick(); - clif->skill_nodamage(&src->bl,bl,sg->skill_id,sg->skill_lv, - sc_start4(bl, type, 100, sg->skill_lv, 0, 0, 0, skill->get_time(LK_BERSERK, sg->skill_lv))); - } - } + sc_start4(ss,bl,type,100,sg->skill_lv,sg->group_id,0,0,sg->limit); break; case UNT_WARP_WAITING: { @@ -10984,7 +11394,7 @@ int skill_unit_onplace (struct skill_unit *src, struct block_list *bl, unsigned if( --count <= 0 ) skill->del_unitgroup(sg,ALC_MARK); - if ( iMap->mapindex2mapid(sg->val3) == sd->bl.m && x == sd->bl.x && y == sd->bl.y ) + if ( map->mapindex2mapid(sg->val3) == sd->bl.m && x == sd->bl.x && y == sd->bl.y ) working = 1;/* we break it because officials break it, lovely stuff. */ sg->val1 = (count<<16)|working; @@ -10992,35 +11402,35 @@ int skill_unit_onplace (struct skill_unit *src, struct block_list *bl, unsigned pc->setpos(sd,m,x,y,CLR_TELEPORT); } } else if(bl->type == BL_MOB && battle_config.mob_warp&2) { - int16 m = iMap->mapindex2mapid(sg->val3); + int16 m = map->mapindex2mapid(sg->val3); if (m < 0) break; //Map not available on this map-server. - unit_warp(bl,m,sg->val2>>16,sg->val2&0xffff,CLR_TELEPORT); + unit->warp(bl,m,sg->val2>>16,sg->val2&0xffff,CLR_TELEPORT); } } break; case UNT_QUAGMIRE: if( !sce && battle->check_target(&sg->unit->bl,bl,sg->target_flag) > 0 ) - sc_start4(bl,type,100,sg->skill_lv,sg->group_id,0,0,sg->limit); + sc_start4(ss,bl,type,100,sg->skill_lv,sg->group_id,0,0,sg->limit); break; case UNT_VOLCANO: case UNT_DELUGE: case UNT_VIOLENTGALE: if(!sce) - sc_start(bl,type,100,sg->skill_lv,sg->limit); + sc_start(ss,bl,type,100,sg->skill_lv,sg->limit); break; case UNT_SUITON: if(!sce) - sc_start4(bl,type,100,sg->skill_lv, + sc_start4(ss,bl,type,100,sg->skill_lv, map_flag_vs(bl->m) || battle->check_target(&src->bl,bl,BCT_ENEMY)>0?1:0, //Send val3 =1 to reduce agi. 0,0,sg->limit); break; case UNT_HERMODE: if (sg->src_id!=bl->id && battle->check_target(&src->bl,bl,BCT_PARTY|BCT_GUILD) > 0) - status_change_clear_buffs(bl,1); //Should dispell only allies. + status->change_clear_buffs(bl,1); //Should dispell only allies. case UNT_RICHMANKIM: case UNT_ETERNALCHAOS: case UNT_DRUMBATTLEFIELD: @@ -11032,7 +11442,7 @@ int skill_unit_onplace (struct skill_unit *src, struct block_list *bl, unsigned if (sg->src_id==bl->id && !(sc && sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_BARDDANCER)) return skill_id; if (!sce) - sc_start4(bl,type,100,sg->skill_lv,sg->val1,sg->val2,0,sg->limit); + sc_start4(ss,bl,type,100,sg->skill_lv,sg->val1,sg->val2,0,sg->limit); break; case UNT_WHISTLE: case UNT_ASSASSINCROSS: @@ -11047,19 +11457,19 @@ int skill_unit_onplace (struct skill_unit *src, struct block_list *bl, unsigned if (!sc) return 0; if (!sce) - sc_start4(bl,type,100,sg->skill_lv,sg->val1,sg->val2,0,sg->limit); + sc_start4(ss,bl,type,100,sg->skill_lv,sg->val1,sg->val2,0,sg->limit); else if (sce->val4 == 1) { //Readjust timers since the effect will not last long. sce->val4 = 0; - iTimer->delete_timer(sce->timer, status_change_timer); - sce->timer = iTimer->add_timer(tick+sg->limit, status_change_timer, bl->id, type); + timer->delete(sce->timer, status->change_timer); + sce->timer = timer->add(tick+sg->limit, status->change_timer, bl->id, type); } break; case UNT_FOGWALL: if (!sce) { - sc_start4(bl, type, 100, sg->skill_lv, sg->val1, sg->val2, sg->group_id, sg->limit); + sc_start4(ss, bl, type, 100, sg->skill_lv, sg->val1, sg->val2, sg->group_id, sg->limit); if (battle->check_target(&src->bl,bl,BCT_ENEMY)>0) skill->additional_effect (ss, bl, sg->skill_id, sg->skill_lv, BF_MISC, ATK_DEF, tick); } @@ -11067,14 +11477,14 @@ int skill_unit_onplace (struct skill_unit *src, struct block_list *bl, unsigned case UNT_GRAVITATION: if (!sce) - sc_start4(bl,type,100,sg->skill_lv,0,BCT_ENEMY,sg->group_id,sg->limit); + sc_start4(ss,bl,type,100,sg->skill_lv,0,BCT_ENEMY,sg->group_id,sg->limit); break; // officially, icewall has no problems existing on occupied cells [ultramage] // case UNT_ICEWALL: //Destroy the cell. [Skotlex] // src->val1 = 0; // if(src->limit + sg->tick > tick + 700) - // src->limit = DIFF_TICK(tick+700,sg->tick); + // src->limit = DIFF_TICK32(tick+700,sg->tick); // break; case UNT_MOONLIT: @@ -11083,7 +11493,7 @@ int skill_unit_onplace (struct skill_unit *src, struct block_list *bl, unsigned break; if (ss == bl) //Also needed to prevent infinite loop crash. break; - skill->blown(ss,bl,skill->get_blewcount(sg->skill_id,sg->skill_lv),unit_getdir(bl),0); + skill->blown(ss,bl,skill->get_blewcount(sg->skill_id,sg->skill_lv),unit->getdir(bl),0); break; case UNT_WALLOFTHORN: @@ -11093,17 +11503,26 @@ int skill_unit_onplace (struct skill_unit *src, struct block_list *bl, unsigned skill->attack(skill->get_type(sg->skill_id), ss, &src->bl, bl, sg->skill_id, sg->skill_lv, tick, 0); break; + case UNT_REVERBERATION: + if (sg->src_id == bl->id) + break; //Does not affect the caster. + clif->changetraplook(&src->bl,UNT_USED_TRAPS); + map->foreachinrange(skill->trap_splash,&src->bl, skill->get_splash(sg->skill_id, sg->skill_lv), sg->bl_flag, &src->bl,tick); + sg->unit_id = UNT_USED_TRAPS; + sg->limit = DIFF_TICK32(tick,sg->tick) + 1500; + break; + case UNT_VOLCANIC_ASH: if (!sce) - sc_start(bl, SC_VOLCANIC_ASH, 100, sg->skill_lv, skill->get_time(MH_VOLCANIC_ASH, sg->skill_lv)); + sc_start(ss, bl, SC_VOLCANIC_ASH, 100, sg->skill_lv, skill->get_time(MH_VOLCANIC_ASH, sg->skill_lv)); break; case UNT_GD_LEADERSHIP: case UNT_GD_GLORYWOUNDS: case UNT_GD_SOULCOLD: case UNT_GD_HAWKEYES: - if ( !sce ) - sc_start4(bl,type,100,sg->skill_lv,0,0,0,1000); + if ( !sce && battle->check_target(&sg->unit->bl,bl,sg->target_flag) > 0 ) + sc_start4(ss,bl,type,100,sg->skill_lv,0,0,0,1000); break; } return skill_id; @@ -11112,12 +11531,12 @@ int skill_unit_onplace (struct skill_unit *src, struct block_list *bl, unsigned /*========================================== * *------------------------------------------*/ -int skill_unit_onplace_timer (struct skill_unit *src, struct block_list *bl, unsigned int tick) { +int skill_unit_onplace_timer(struct skill_unit *src, struct block_list *bl, int64 tick) { struct skill_unit_group *sg; struct block_list *ss; TBL_PC* tsd; struct status_data *tstatus; - struct status_change *tsc; + struct status_change *tsc, *ssc; struct skill_unit_group_tickset *ts; enum sc_type type; uint16 skill_id; @@ -11126,19 +11545,24 @@ int skill_unit_onplace_timer (struct skill_unit *src, struct block_list *bl, uns nullpo_ret(src); nullpo_ret(bl); - if (bl->prev==NULL || !src->alive || status_isdead(bl)) + if (bl->prev==NULL || !src->alive || status->isdead(bl)) return 0; nullpo_ret(sg=src->group); - nullpo_ret(ss=iMap->id2bl(sg->src_id)); + nullpo_ret(ss=map->id2bl(sg->src_id)); tsd = BL_CAST(BL_PC, bl); - tsc = status_get_sc(bl); + tsc = status->get_sc(bl); + ssc = status->get_sc(ss); // Status Effects for Unit caster. if ( tsc && tsc->data[SC_HOVERING] ) return 0; //Under hovering characters are immune to trap and ground target skills. - tstatus = status_get_status_data(bl); - type = status_skill2sc(sg->skill_id); + // Maestro or Wanderer is unaffected by traps of trappers he or she charmed [SuperHulk] + if ( ssc && ssc->data[SC_SIREN] && ssc->data[SC_SIREN]->val2 == bl->id && (skill->get_inf2(sg->skill_id)&INF2_TRAP) ) + return 0; + + tstatus = status->get_status_data(bl); + type = status->skill2sc(sg->skill_id); skill_id = sg->skill_id; if (sg->interval == -1) { @@ -11156,13 +11580,13 @@ int skill_unit_onplace_timer (struct skill_unit *src, struct block_list *bl, uns if ((ts = skill->unitgrouptickset_search(bl,sg,tick))) { //Not all have it, eg: Traps don't have it even though they can be hit by Heaven's Drive [Skotlex] - diff = DIFF_TICK(tick,ts->tick); + diff = DIFF_TICK32(tick,ts->tick); if (diff < 0) return 0; ts->tick = tick+sg->interval; if ((skill_id==CR_GRANDCROSS || skill_id==NPC_GRANDDARKNESS) && !battle_config.gx_allhit) - ts->tick += sg->interval*(iMap->count_oncell(bl->m,bl->x,bl->y,BL_CHAR)-1); + ts->tick += sg->interval*(map->count_oncell(bl->m,bl->x,bl->y,BL_CHAR)-1); } switch (sg->unit_id) { @@ -11177,8 +11601,8 @@ int skill_unit_onplace_timer (struct skill_unit *src, struct block_list *bl, uns //Take into account these hit more times than the timer interval can handle. do skill->attack(BF_MAGIC,ss,&src->bl,bl,sg->skill_id,sg->skill_lv,tick+count*sg->interval,0); - while(--src->val2 && x == bl->x && y == bl->y && - ++count < SKILLUNITTIMER_INTERVAL/sg->interval && !status_isdead(bl)); + while(--src->val2 && x == bl->x && y == bl->y + && ++count < SKILLUNITTIMER_INTERVAL/sg->interval && !status->isdead(bl)); if (src->val2<=0) skill->delunit(src); @@ -11201,12 +11625,12 @@ int skill_unit_onplace_timer (struct skill_unit *src, struct block_list *bl, uns break; if( tstatus->hp >= tstatus->max_hp ) break; - if( status_isimmune(bl) ) + if( status->isimmune(bl) ) heal = 0; clif->skill_nodamage(&src->bl, bl, AL_HEAL, heal, 1); if( tsc && tsc->data[SC_AKAITSUKI] && heal ) heal = ~heal + 1; - status_heal(bl, heal, 0, 0); + status->heal(bl, heal, 0, 0); if( diff >= 500 ) sg->val1--; } @@ -11216,18 +11640,18 @@ int skill_unit_onplace_timer (struct skill_unit *src, struct block_list *bl, uns case UNT_EVILLAND: //Will heal demon and undead element monsters, but not players. - if ((bl->type == BL_PC) || (!battle->check_undead(tstatus->race, tstatus->def_ele) && tstatus->race!=RC_DEMON)) - { //Damage enemies + if ((bl->type == BL_PC) || (!battle->check_undead(tstatus->race, tstatus->def_ele) && tstatus->race!=RC_DEMON)) { + //Damage enemies if(battle->check_target(&src->bl,bl,BCT_ENEMY)>0) skill->attack(BF_MISC, ss, &src->bl, bl, sg->skill_id, sg->skill_lv, tick, 0); } else { int heal = skill->calc_heal(ss,bl,sg->skill_id,sg->skill_lv,true); if (tstatus->hp >= tstatus->max_hp) break; - if (status_isimmune(bl)) + if (status->isimmune(bl)) heal = 0; clif->skill_nodamage(&src->bl, bl, AL_HEAL, heal, 1); - status_heal(bl, heal, 0, 0); + status->heal(bl, heal, 0, 0); } break; @@ -11238,8 +11662,7 @@ int skill_unit_onplace_timer (struct skill_unit *src, struct block_list *bl, uns break; case UNT_DUMMYSKILL: - switch (sg->skill_id) - { + switch (sg->skill_id) { case SG_SUN_WARM: //SG skills [Komurka] case SG_MOON_WARM: case SG_STAR_WARM: @@ -11247,24 +11670,23 @@ int skill_unit_onplace_timer (struct skill_unit *src, struct block_list *bl, uns int count = 0; const int x = bl->x, y = bl->y; + map->freeblock_lock(); //If target isn't knocked back it should hit every "interval" ms [Playtester] - do - { + do { if( bl->type == BL_PC ) status_zap(bl, 0, 15); // sp damage to players - else // mobs - if( status_charge(ss, 0, 2) ) // costs 2 SP per hit - { + else if( status->charge(ss, 0, 2) ) { // mobs + // costs 2 SP per hit if( !skill->attack(BF_WEAPON,ss,&src->bl,bl,sg->skill_id,sg->skill_lv,tick+count*sg->interval,0) ) - status_charge(ss, 0, 8); //costs additional 8 SP if miss - } - else - { //should end when out of sp. - sg->limit = DIFF_TICK(tick,sg->tick); + status->charge(ss, 0, 8); //costs additional 8 SP if miss + } else { // mobs + //should end when out of sp. + sg->limit = DIFF_TICK32(tick,sg->tick); break; } - } while( x == bl->x && y == bl->y && - ++count < SKILLUNITTIMER_INTERVAL/sg->interval && !status_isdead(bl) ); + } while( x == bl->x && y == bl->y && sg->alive_count + && ++count < SKILLUNITTIMER_INTERVAL/sg->interval && !status->isdead(bl) ); + map->freeblock_unlock(); } break; /** @@ -11282,12 +11704,6 @@ int skill_unit_onplace_timer (struct skill_unit *src, struct block_list *bl, uns if (rnd()%100 < src->val1) skill->attack(BF_WEAPON,ss,&src->bl,bl,sg->skill_id,sg->skill_lv,tick,0); break; - case GN_CRAZYWEED_ATK: - if( bl->type == BL_SKILL ){ - struct skill_unit *su = (struct skill_unit *)bl; - if( su && !(skill->get_inf2(su->group->skill_id)&INF2_TRAP) ) - break; - } default: skill->attack(skill->get_type(sg->skill_id),ss,&src->bl,bl,sg->skill_id,sg->skill_lv,tick,0); } @@ -11300,10 +11716,10 @@ int skill_unit_onplace_timer (struct skill_unit *src, struct block_list *bl, uns case UNT_SKIDTRAP: { - skill->blown(&src->bl,bl,skill->get_blewcount(sg->skill_id,sg->skill_lv),unit_getdir(bl),0); + skill->blown(&src->bl,bl,skill->get_blewcount(sg->skill_id,sg->skill_lv),unit->getdir(bl),0); sg->unit_id = UNT_USED_TRAPS; clif->changetraplook(&src->bl, UNT_USED_TRAPS); - sg->limit=DIFF_TICK(tick,sg->tick)+1500; + sg->limit=DIFF_TICK32(tick,sg->tick)+1500; } break; @@ -11311,12 +11727,12 @@ int skill_unit_onplace_timer (struct skill_unit *src, struct block_list *bl, uns case UNT_MANHOLE: if( sg->val2 == 0 && tsc && (sg->unit_id == UNT_ANKLESNARE || bl->id != sg->src_id) ) { int sec = skill->get_time2(sg->skill_id,sg->skill_lv); - if( status_change_start(bl,type,10000,sg->skill_lv,sg->group_id,0,0,sec, 8) ) { - const struct TimerData* td = tsc->data[type]?iTimer->get_timer(tsc->data[type]->timer):NULL; + if( status->change_start(ss,bl,type,10000,sg->skill_lv,sg->group_id,0,0,sec, 8) ) { + const struct TimerData* td = tsc->data[type]?timer->get(tsc->data[type]->timer):NULL; if( td ) - sec = DIFF_TICK(td->tick, tick); - if( sg->unit_id == UNT_MANHOLE || battle_config.skill_trap_type || !map_flag_gvg(src->bl.m) ) { - unit_movepos(bl, src->bl.x, src->bl.y, 0, 0); + sec = DIFF_TICK32(td->tick, tick); + if( sg->unit_id == UNT_MANHOLE || battle_config.skill_trap_type || !map_flag_gvg2(src->bl.m) ) { + unit->movepos(bl, src->bl.x, src->bl.y, 0, 0); clif->fixpos(bl); } sg->val2 = bl->id; @@ -11331,7 +11747,7 @@ int skill_unit_onplace_timer (struct skill_unit *src, struct block_list *bl, uns **/ clif->changetraplook(&src->bl, UNT_ANKLESNARE); } - sg->limit = DIFF_TICK(tick,sg->tick)+sec; + sg->limit = DIFF_TICK32(tick,sg->tick)+sec; sg->interval = -1; src->range = 0; } @@ -11341,21 +11757,20 @@ int skill_unit_onplace_timer (struct skill_unit *src, struct block_list *bl, uns if( bl->id != ss->id ) { if( status_get_mode(bl)&MD_BOSS ) break; - if( status_change_start(bl,type,10000,sg->skill_lv,sg->group_id,0,0,skill->get_time2(sg->skill_id, sg->skill_lv), 8) ) { - - iMap->moveblock(bl, src->bl.x, src->bl.y, tick); + if( status->change_start(ss,bl,type,10000,sg->skill_lv,sg->group_id,0,0,skill->get_time2(sg->skill_id, sg->skill_lv), 8) ) { + map->moveblock(bl, src->bl.x, src->bl.y, tick); clif->fixpos(bl); } - iMap->foreachinrange(skill->trap_splash, &src->bl, skill->get_splash(sg->skill_id, sg->skill_lv), sg->bl_flag, &src->bl, tick); + map->foreachinrange(skill->trap_splash, &src->bl, skill->get_splash(sg->skill_id, sg->skill_lv), sg->bl_flag, &src->bl, tick); sg->unit_id = UNT_USED_TRAPS; //Changed ID so it does not invoke a for each in area again. } break; case UNT_VENOMDUST: if(tsc && !tsc->data[type]) - status_change_start(bl,type,10000,sg->skill_lv,sg->group_id,0,0,skill->get_time2(sg->skill_id,sg->skill_lv),0); + status->change_start(ss,bl,type,10000,sg->skill_lv,sg->group_id,0,0,skill->get_time2(sg->skill_id,sg->skill_lv),0); break; @@ -11371,17 +11786,20 @@ int skill_unit_onplace_timer (struct skill_unit *src, struct block_list *bl, uns if( bl->id == ss->id )// it won't trigger on caster break; case UNT_LANDMINE: - case UNT_CLAYMORETRAP: case UNT_BLASTMINE: case UNT_SHOCKWAVE: case UNT_SANDMAN: case UNT_FLASHER: case UNT_FREEZINGTRAP: case UNT_FIREPILLAR_ACTIVE: - iMap->foreachinrange(skill->trap_splash,&src->bl, skill->get_splash(sg->skill_id, sg->skill_lv), sg->bl_flag, &src->bl,tick); + case UNT_CLAYMORETRAP: + if( sg->unit_id == UNT_FIRINGTRAP || sg->unit_id == UNT_ICEBOUNDTRAP || sg->unit_id == UNT_CLAYMORETRAP ) + map->foreachinrange(skill->trap_splash,&src->bl, skill->get_splash(sg->skill_id, sg->skill_lv), sg->bl_flag|BL_SKILL|~BCT_SELF, &src->bl,tick); + else + map->foreachinrange(skill->trap_splash,&src->bl, skill->get_splash(sg->skill_id, sg->skill_lv), sg->bl_flag, &src->bl,tick); if (sg->unit_id != UNT_FIREPILLAR_ACTIVE) clif->changetraplook(&src->bl, sg->unit_id==UNT_LANDMINE?UNT_FIREPILLAR_ACTIVE:UNT_USED_TRAPS); - sg->limit=DIFF_TICK(tick,sg->tick)+1500 + + sg->limit=DIFF_TICK32(tick,sg->tick)+1500 + (sg->unit_id== UNT_CLUSTERBOMB || sg->unit_id== UNT_ICEBOUNDTRAP?1000:0);// Cluster Bomb/Icebound has 1s to disappear once activated. sg->unit_id = UNT_USED_TRAPS; //Changed ID so it does not invoke a for each in area again. break; @@ -11393,7 +11811,7 @@ int skill_unit_onplace_timer (struct skill_unit *src, struct block_list *bl, uns clif->talkiebox(&src->bl, sg->valstr); sg->unit_id = UNT_USED_TRAPS; clif->changetraplook(&src->bl, UNT_USED_TRAPS); - sg->limit = DIFF_TICK(tick, sg->tick) + 5000; + sg->limit = DIFF_TICK32(tick, sg->tick) + 5000; sg->val2 = -1; } break; @@ -11427,7 +11845,7 @@ int skill_unit_onplace_timer (struct skill_unit *src, struct block_list *bl, uns if( tsc->data[SC_AKAITSUKI] && heal ) heal = ~heal + 1; clif->skill_nodamage(&src->bl, bl, AL_HEAL, heal, 1); - status_heal(bl, heal, 0, 0); + status->heal(bl, heal, 0, 0); break; } @@ -11444,58 +11862,57 @@ int skill_unit_onplace_timer (struct skill_unit *src, struct block_list *bl, uns int heal; int i = rnd()%13; // Positive buff count int time = skill->get_time2(sg->skill_id, sg->skill_lv); //Duration - switch (i) - { + switch (i) { case 0: // Heal 1~9999 HP heal = rnd() %9999+1; clif->skill_nodamage(ss,bl,AL_HEAL,heal,1); - status_heal(bl,heal,0,0); + status->heal(bl,heal,0,0); break; case 1: // End all negative status - status_change_clear_buffs(bl,2); + status->change_clear_buffs(bl,2); if (tsd) clif->gospel_info(tsd, 0x15); break; case 2: // Immunity to all status - sc_start(bl,SC_SCRESIST,100,100,time); + sc_start(ss,bl,SC_SCRESIST,100,100,time); if (tsd) clif->gospel_info(tsd, 0x16); break; case 3: // MaxHP +100% - sc_start(bl,SC_INCMHPRATE,100,100,time); + sc_start(ss,bl,SC_INCMHPRATE,100,100,time); if (tsd) clif->gospel_info(tsd, 0x17); break; case 4: // MaxSP +100% - sc_start(bl,SC_INCMSPRATE,100,100,time); + sc_start(ss,bl,SC_INCMSPRATE,100,100,time); if (tsd) clif->gospel_info(tsd, 0x18); break; case 5: // All stats +20 - sc_start(bl,SC_INCALLSTATUS,100,20,time); + sc_start(ss,bl,SC_INCALLSTATUS,100,20,time); if (tsd) clif->gospel_info(tsd, 0x19); break; case 6: // Level 10 Blessing - sc_start(bl,SC_BLESSING,100,10,time); + sc_start(ss,bl,SC_BLESSING,100,10,time); break; case 7: // Level 10 Increase AGI - sc_start(bl,SC_INC_AGI,100,10,time); + sc_start(ss,bl,SC_INC_AGI,100,10,time); break; case 8: // Enchant weapon with Holy element - sc_start(bl,SC_ASPERSIO,100,1,time); + sc_start(ss,bl,SC_ASPERSIO,100,1,time); if (tsd) clif->gospel_info(tsd, 0x1c); break; case 9: // Enchant armor with Holy element - sc_start(bl,SC_BENEDICTIO,100,1,time); + sc_start(ss,bl,SC_BENEDICTIO,100,1,time); if (tsd) clif->gospel_info(tsd, 0x1d); break; case 10: // DEF +25% - sc_start(bl,SC_INCDEFRATE,100,25,time); + sc_start(ss,bl,SC_INCDEFRATE,100,25,time); if (tsd) clif->gospel_info(tsd, 0x1e); break; case 11: // ATK +100% - sc_start(bl,SC_INCATKRATE,100,100,time); + sc_start(ss,bl,SC_INCATKRATE,100,100,time); if (tsd) clif->gospel_info(tsd, 0x1f); break; case 12: // HIT/Flee +50 - sc_start(bl,SC_INCHIT,100,50,time); - sc_start(bl,SC_INCFLEE,100,50,time); + sc_start(ss,bl,SC_INCHIT,100,50,time); + sc_start(ss,bl,SC_INCFLEE,100,50,time); if (tsd) clif->gospel_info(tsd, 0x20); break; } @@ -11510,28 +11927,28 @@ int skill_unit_onplace_timer (struct skill_unit *src, struct block_list *bl, uns skill->attack(BF_MISC,ss,&src->bl,bl,sg->skill_id,sg->skill_lv,tick,0); break; case 1: // Curse - sc_start(bl,SC_CURSE,100,1,time); + sc_start(ss,bl,SC_CURSE,100,1,time); break; case 2: // Blind - sc_start(bl,SC_BLIND,100,1,time); + sc_start(ss,bl,SC_BLIND,100,1,time); break; case 3: // Poison - sc_start(bl,SC_POISON,100,1,time); + sc_start(ss,bl,SC_POISON,100,1,time); break; case 4: // Level 10 Provoke - sc_start(bl,SC_PROVOKE,100,10,time); + sc_start(ss,bl,SC_PROVOKE,100,10,time); break; case 5: // DEF -100% - sc_start(bl,SC_INCDEFRATE,100,-100,time); + sc_start(ss,bl,SC_INCDEFRATE,100,-100,time); break; case 6: // ATK -100% - sc_start(bl,SC_INCATKRATE,100,-100,time); + sc_start(ss,bl,SC_INCATKRATE,100,-100,time); break; case 7: // Flee -100% - sc_start(bl,SC_INCFLEERATE,100,-100,time); + sc_start(ss,bl,SC_INCFLEERATE,100,-100,time); break; case 8: // Speed/ASPD -25% - sc_start4(bl,SC_GOSPEL,100,1,0,0,BCT_ENEMY,time); + sc_start4(ss,bl,SC_GOSPEL,100,1,0,0,BCT_ENEMY,time); break; } } @@ -11542,12 +11959,12 @@ int skill_unit_onplace_timer (struct skill_unit *src, struct block_list *bl, uns int i = battle->check_target(&src->bl, bl, BCT_ENEMY); if( i > 0 && !(status_get_mode(bl)&MD_BOSS) ) { // knock-back any enemy except Boss - skill->blown(&src->bl, bl, 2, unit_getdir(bl), 0); + skill->blown(&src->bl, bl, 2, unit->getdir(bl), 0); clif->fixpos(bl); } if( sg->src_id != bl->id && i <= 0 ) - sc_start4(bl, type, 100, 0, 0, 0, src->bl.id, sg->interval + 100); + sc_start4(ss, bl, type, 100, 0, 0, 0, src->bl.id, sg->interval + 100); } break; @@ -11566,19 +11983,23 @@ int skill_unit_onplace_timer (struct skill_unit *src, struct block_list *bl, uns case UNT_GROUNDDRIFT_POISON: case UNT_GROUNDDRIFT_WATER: case UNT_GROUNDDRIFT_FIRE: - iMap->foreachinrange(skill->trap_splash,&src->bl, - skill->get_splash(sg->skill_id, sg->skill_lv), sg->bl_flag, - &src->bl,tick); + map->foreachinrange(skill->trap_splash,&src->bl, + skill->get_splash(sg->skill_id, sg->skill_lv), sg->bl_flag, + &src->bl,tick); sg->unit_id = UNT_USED_TRAPS; //clif->changetraplook(&src->bl, UNT_FIREPILLAR_ACTIVE); - sg->limit=DIFF_TICK(tick,sg->tick)+1500; + sg->limit=DIFF_TICK32(tick,sg->tick)+1500; break; /** * 3rd stuff **/ case UNT_POISONSMOKE: - if( battle->check_target(ss,bl,BCT_ENEMY) > 0 && !(tsc && tsc->data[sg->val2]) && rnd()%100 < 20 ) - sc_start(bl,sg->val2,100,sg->val3,skill->get_time2(GC_POISONINGWEAPON, 1)); + if( battle->check_target(ss,bl,BCT_ENEMY) > 0 && !(tsc && tsc->data[sg->val2]) && rnd()%100 < 50 ) { + short rate = 100; + if ( sg->val1 == 9 )//Oblivion Curse gives a 2nd success chance after the 1st one passes which is reducible. [Rytech] + rate = 100 - tstatus->int_ * 4 / 5 ; + sc_start(ss,bl,sg->val2,rate,sg->val1,skill->get_time2(GC_POISONINGWEAPON,1) - (tstatus->vit + tstatus->luk) / 2 * 1000); + } break; case UNT_EPICLESIS: @@ -11592,14 +12013,15 @@ int skill_unit_onplace_timer (struct skill_unit *src, struct block_list *bl, uns } hp = tstatus->max_hp * hp / 100; sp = tstatus->max_sp * sp / 100; - status_heal(bl, hp, sp, 2); - sc_start(bl, type, 100, sg->skill_lv, (sg->interval * 3) + 100); + status->heal(bl, hp, sp, 2); + sc_start(ss, bl, type, 100, sg->skill_lv, (sg->interval * 3) + 100); } // Reveal hidden players every 5 seconds. if( sg->val2 % 5 == 0 ) { // TODO: check if other hidden status can be removed. status_change_end(bl,SC_HIDING,INVALID_TIMER); status_change_end(bl,SC_CLOAKING,INVALID_TIMER); + status_change_end(bl,SC_CLOAKINGEXCEED,INVALID_TIMER); } } /* Enable this if kRO fix the current skill. Currently no damage on undead and demon monster. [Jobbie] @@ -11609,35 +12031,33 @@ int skill_unit_onplace_timer (struct skill_unit *src, struct block_list *bl, uns case UNT_STEALTHFIELD: if( bl->id == sg->src_id ) - break; // Dont work on Self (video shows that) + break; // Don't work on Self (video shows that) case UNT_NEUTRALBARRIER: - sc_start(bl,type,100,sg->skill_lv,sg->interval + 100); + sc_start(ss,bl,type,100,sg->skill_lv,sg->interval + 100); break; case UNT_DIMENSIONDOOR: - if( tsd && !map[bl->m].flag.noteleport ) + if( tsd && !map->list[bl->m].flag.noteleport ) pc->randomwarp(tsd,3); else if( bl->type == BL_MOB && battle_config.mob_warp&8 ) - unit_warp(bl,-1,-1,-1,3); + unit->warp(bl,-1,-1,-1,3); break; case UNT_REVERBERATION: clif->changetraplook(&src->bl,UNT_USED_TRAPS); - iMap->foreachinrange(skill->trap_splash,&src->bl, skill->get_splash(sg->skill_id, sg->skill_lv), sg->bl_flag, &src->bl,tick); - sg->limit = DIFF_TICK(tick,sg->tick)+1000; + map->foreachinrange(skill->trap_splash,&src->bl, skill->get_splash(sg->skill_id, sg->skill_lv), sg->bl_flag, &src->bl,tick); + sg->limit = DIFF_TICK32(tick,sg->tick)+1500; sg->unit_id = UNT_USED_TRAPS; break; case UNT_SEVERE_RAINSTORM: - if( battle->check_target(&src->bl, bl, BCT_ENEMY) > 0 ) + if( battle->check_target(&src->bl, bl, BCT_ENEMY)) skill->attack(BF_WEAPON,ss,&src->bl,bl,WM_SEVERE_RAINSTORM_MELEE,sg->skill_lv,tick,0); break; case UNT_NETHERWORLD: - if( !(status_get_mode(bl)&MD_BOSS) && ss != bl && battle->check_target(&src->bl, bl, BCT_PARTY) > 0 ) { + if( !(status_get_mode(bl)&MD_BOSS)) { if( !(tsc && tsc->data[type]) ){ - sc_start(bl, type, 100, sg->skill_lv, skill->get_time2(sg->skill_id,sg->skill_lv)); - sg->limit = DIFF_TICK(tick,sg->tick); - sg->unit_id = UNT_USED_TRAPS; + sc_start(ss, bl, type, 100, sg->skill_lv, skill->get_time2(sg->skill_id,sg->skill_lv)); } } break; @@ -11645,16 +12065,16 @@ int skill_unit_onplace_timer (struct skill_unit *src, struct block_list *bl, uns if( tsc ) { if( !sg->val2 ) { int sec = skill->get_time2(sg->skill_id, sg->skill_lv); - if( sc_start(bl, type, 100, sg->skill_lv, sec) ) { - const struct TimerData* td = tsc->data[type]?iTimer->get_timer(tsc->data[type]->timer):NULL; + if( sc_start(ss, bl, type, 100, sg->skill_lv, sec) ) { + const struct TimerData* td = tsc->data[type]?timer->get(tsc->data[type]->timer):NULL; if( td ) - sec = DIFF_TICK(td->tick, tick); - ///iMap->moveblock(bl, src->bl.x, src->bl.y, tick); // in official server it doesn't behave like this. [malufett] + sec = DIFF_TICK32(td->tick, tick); + ///map->moveblock(bl, src->bl.x, src->bl.y, tick); // in official server it doesn't behave like this. [malufett] clif->fixpos(bl); sg->val2 = bl->id; } else sec = 3000; // Couldn't trap it? - sg->limit = DIFF_TICK(tick, sg->tick) + sec; + sg->limit = DIFF_TICK32(tick, sg->tick) + sec; } else if( tsc->data[SC_THORNS_TRAP] && bl->id == sg->val2 ) skill->attack(skill->get_type(GN_THORNS_TRAP), ss, ss, bl, sg->skill_id, sg->skill_lv, tick, SD_LEVEL|SD_ANIMATION); } @@ -11666,7 +12086,7 @@ int skill_unit_onplace_timer (struct skill_unit *src, struct block_list *bl, uns case 1: case 2: default: - sc_start4(bl, SC_BURNING, 4 + 4 * sg->skill_lv, sg->skill_lv, 0, ss->id, 0, + sc_start4(ss, bl, SC_BURNING, 4 + 4 * sg->skill_lv, sg->skill_lv, 0, ss->id, 0, skill->get_time2(sg->skill_id, sg->skill_lv)); skill->attack(skill->get_type(sg->skill_id), ss, &src->bl, bl, sg->skill_id, sg->skill_lv + 10 * sg->val2, tick, 0); @@ -11681,38 +12101,40 @@ int skill_unit_onplace_timer (struct skill_unit *src, struct block_list *bl, uns break; case UNT_FIRE_EXPANSION_SMOKE_POWDER: - sc_start(bl, status_skill2sc(GN_FIRE_EXPANSION_SMOKE_POWDER), 100, sg->skill_lv, 1000); + sc_start(ss, bl, status->skill2sc(GN_FIRE_EXPANSION_SMOKE_POWDER), 100, sg->skill_lv, 1000); break; case UNT_FIRE_EXPANSION_TEAR_GAS: - sc_start(bl, status_skill2sc(GN_FIRE_EXPANSION_TEAR_GAS), 100, sg->skill_lv, 1000); + sc_start(ss, bl, status->skill2sc(GN_FIRE_EXPANSION_TEAR_GAS), 100, sg->skill_lv, 1000); break; case UNT_HELLS_PLANT: if( battle->check_target(&src->bl,bl,BCT_ENEMY) > 0 ) skill->attack(skill->get_type(GN_HELLS_PLANT_ATK), ss, &src->bl, bl, GN_HELLS_PLANT_ATK, sg->skill_lv, tick, 0); if( ss != bl) //The caster is the only one who can step on the Plants, without destroying them - sg->limit = DIFF_TICK(tick, sg->tick) + 100; + sg->limit = DIFF_TICK32(tick, sg->tick) + 100; break; case UNT_CLOUD_KILL: if(tsc && !tsc->data[type]) - status_change_start(bl,type,10000,sg->skill_lv,sg->group_id,0,0,skill->get_time2(sg->skill_id,sg->skill_lv),8); + status->change_start(ss,bl,type,10000,sg->skill_lv,sg->group_id,0,0,skill->get_time2(sg->skill_id,sg->skill_lv),8); skill->attack(skill->get_type(sg->skill_id),ss,&src->bl,bl,sg->skill_id,sg->skill_lv,tick,0); break; case UNT_WARMER: if( bl->type == BL_PC && !battle->check_undead(tstatus->race, tstatus->def_ele) && tstatus->race != RC_DEMON ) { - int hp = 125 * sg->skill_lv; // Officially is 125 * skill_lv. - struct status_change *ssc = status_get_sc(ss); + int hp = 0; if( ssc && ssc->data[SC_HEATER_OPTION] ) - hp += hp * ssc->data[SC_HEATER_OPTION]->val3 / 100; + hp = tstatus->max_hp * 3 * sg->skill_lv / 100; + else + hp = tstatus->max_hp * sg->skill_lv / 100; + status->heal(bl, hp, 0, 0); if( tstatus->hp != tstatus->max_hp ) clif->skill_nodamage(&src->bl, bl, AL_HEAL, hp, 0); if( tsc && tsc->data[SC_AKAITSUKI] && hp ) hp = ~hp + 1; - status_heal(bl, hp, 0, 0); - sc_start(bl, SC_WARMER, 100, sg->skill_lv, skill->get_time2(sg->skill_id,sg->skill_lv)); + status->heal(bl, hp, 0, 0); + sc_start(ss, bl, SC_WARMER, 100, sg->skill_lv, skill->get_time2(sg->skill_id,sg->skill_lv)); } break; @@ -11721,18 +12143,18 @@ int skill_unit_onplace_timer (struct skill_unit *src, struct block_list *bl, uns case UNT_WIND_INSIGNIA: case UNT_EARTH_INSIGNIA: case UNT_ZEPHYR: - sc_start(bl,type, 100, sg->skill_lv, sg->interval); + sc_start(ss, bl,type, 100, sg->skill_lv, sg->interval); if (sg->unit_id != UNT_ZEPHYR && !battle->check_undead(tstatus->race, tstatus->def_ele)) { int hp = tstatus->max_hp / 100; //+1% each 5s if ((sg->val3) % 5) { //each 5s - if (tstatus->def_ele == skill->get_ele(sg->skill_id,sg->skill_lv)){ - status_heal(bl, hp, 0, 2); - } else if((sg->unit_id == UNT_FIRE_INSIGNIA && tstatus->def_ele == ELE_EARTH) - ||(sg->unit_id == UNT_WATER_INSIGNIA && tstatus->def_ele == ELE_FIRE) - ||(sg->unit_id == UNT_WIND_INSIGNIA && tstatus->def_ele == ELE_WATER) - ||(sg->unit_id == UNT_EARTH_INSIGNIA && tstatus->def_ele == ELE_WIND) - ){ - status_heal(bl, -hp, 0, 0); + if (tstatus->def_ele == skill->get_ele(sg->skill_id,sg->skill_lv)) { + status->heal(bl, hp, 0, 2); + } else if( (sg->unit_id == UNT_FIRE_INSIGNIA && tstatus->def_ele == ELE_EARTH) + || (sg->unit_id == UNT_WATER_INSIGNIA && tstatus->def_ele == ELE_FIRE) + || (sg->unit_id == UNT_WIND_INSIGNIA && tstatus->def_ele == ELE_WATER) + || (sg->unit_id == UNT_EARTH_INSIGNIA && tstatus->def_ele == ELE_WIND) + ) { + status->heal(bl, -hp, 0, 0); } } sg->val3++; //timer @@ -11741,31 +12163,11 @@ int skill_unit_onplace_timer (struct skill_unit *src, struct block_list *bl, uns break; case UNT_VACUUM_EXTREME: - {// TODO: official behavior in gvg area. [malufett] - int sec = sg->limit - DIFF_TICK(tick, sg->tick); - int range = skill->get_unit_range(sg->skill_id, sg->skill_lv); - - if( tsc && !tsc->data[type] && - distance_xy(src->bl.x, src->bl.y, bl->x, bl->y) <= range)// don't consider outer bounderies - sc_start(bl, type, 100, sg->skill_lv, sec); - - if( unit_is_walking(bl) && // wait until target stop walking - ( tsc && tsc->data[type] && tsc->data[type]->val4 >= tsc->data[type]->val3-range )) - break; - - if( tsc && ( !tsc->data[type] || (tsc->data[type] && tsc->data[type]->val4 < 1 ) ) ) - break; - - if( unit_is_walking(bl) && - distance_xy(src->bl.x, src->bl.y, bl->x, bl->y) > range )// going outside of boundaries? then force it to stop - unit_stop_walking(bl,1); - - if( !unit_is_walking(bl) && - distance_xy(src->bl.x, src->bl.y, bl->x, bl->y) <= range && // only snap if the target is inside the range or - src->bl.x != bl->x && src->bl.y != bl->y){// diagonal position parallel to VE's center - unit_movepos(bl, src->bl.x, src->bl.y, 0, 0); - clif->fixpos(bl); - } + if ( tsc && tsc->data[SC_HALLUCINATIONWALK] ) { + return 0; + } else { + sg->limit -= 100 * tstatus->str/20; + sc_start(ss, bl, SC_VACUUM_EXTREME, 100, sg->skill_lv, sg->limit); } break; @@ -11781,48 +12183,48 @@ int skill_unit_onplace_timer (struct skill_unit *src, struct block_list *bl, uns if( battle->check_target(&src->bl,bl,BCT_ENEMY) > 0 ){ switch( sg->unit_id ){ case UNT_ZENKAI_WATER: - sc_start(bl, SC_CRYSTALIZE, sg->val1*5, sg->skill_lv, skill->get_time2(sg->skill_id, sg->skill_lv)); - sc_start(bl, SC_FREEZE, sg->val1*5, sg->skill_lv, skill->get_time2(sg->skill_id, sg->skill_lv)); - sc_start(bl, SC_FROSTMISTY, sg->val1*5, sg->skill_lv, skill->get_time2(sg->skill_id, sg->skill_lv)); + sc_start(ss, bl, SC_COLD, sg->val1*5, sg->skill_lv, skill->get_time2(sg->skill_id, sg->skill_lv)); + sc_start(ss, bl, SC_FREEZE, sg->val1*5, sg->skill_lv, skill->get_time2(sg->skill_id, sg->skill_lv)); + sc_start(ss, bl, SC_FROSTMISTY, sg->val1*5, sg->skill_lv, skill->get_time2(sg->skill_id, sg->skill_lv)); break; case UNT_ZENKAI_LAND: - sc_start(bl, SC_STONE, sg->val1*5, sg->skill_lv, skill->get_time2(sg->skill_id, sg->skill_lv)); - sc_start(bl, SC_POISON, sg->val1*5, sg->skill_lv, skill->get_time2(sg->skill_id, sg->skill_lv)); + sc_start(ss, bl, SC_STONE, sg->val1*5, sg->skill_lv, skill->get_time2(sg->skill_id, sg->skill_lv)); + sc_start(ss, bl, SC_POISON, sg->val1*5, sg->skill_lv, skill->get_time2(sg->skill_id, sg->skill_lv)); break; case UNT_ZENKAI_FIRE: - sc_start4(bl, SC_BURNING, sg->val1*5, sg->skill_lv, 0, ss->id, 0, skill->get_time2(sg->skill_id, sg->skill_lv)); + sc_start4(ss, bl, SC_BURNING, sg->val1*5, sg->skill_lv, 0, ss->id, 0, skill->get_time2(sg->skill_id, sg->skill_lv)); break; case UNT_ZENKAI_WIND: - sc_start(bl, SC_SILENCE, sg->val1*5, sg->skill_lv, skill->get_time2(sg->skill_id, sg->skill_lv)); - sc_start(bl, SC_SLEEP, sg->val1*5, sg->skill_lv, skill->get_time2(sg->skill_id, sg->skill_lv)); - sc_start(bl, SC_DEEP_SLEEP, sg->val1*5, sg->skill_lv, skill->get_time2(sg->skill_id, sg->skill_lv)); + sc_start(ss, bl, SC_SILENCE, sg->val1*5, sg->skill_lv, skill->get_time2(sg->skill_id, sg->skill_lv)); + sc_start(ss, bl, SC_SLEEP, sg->val1*5, sg->skill_lv, skill->get_time2(sg->skill_id, sg->skill_lv)); + sc_start(ss, bl, SC_DEEP_SLEEP, sg->val1*5, sg->skill_lv, skill->get_time2(sg->skill_id, sg->skill_lv)); break; } }else - sc_start2(bl,type,100,sg->val1,sg->val2,skill->get_time2(sg->skill_id, sg->skill_lv)); + sc_start2(ss, bl,type,100,sg->val1,sg->val2,skill->get_time2(sg->skill_id, sg->skill_lv)); break; case UNT_LAVA_SLIDE: skill->attack(BF_WEAPON, ss, &src->bl, bl, sg->skill_id, sg->skill_lv, tick, 0); if(++sg->val1 > 4) //after 5 stop hit and destroy me - sg->limit = DIFF_TICK(tick, sg->tick); + sg->limit = DIFF_TICK32(tick, sg->tick); break; case UNT_POISON_MIST: skill->attack(BF_MAGIC, ss, &src->bl, bl, sg->skill_id, sg->skill_lv, tick, 0); - status_change_start(bl, SC_BLIND, rnd() % 100 > sg->skill_lv * 10, sg->skill_lv, sg->skill_id, 0, 0, skill->get_time2(sg->skill_id, sg->skill_lv), 2|8); + status->change_start(ss, bl, SC_BLIND, rnd() % 100 > sg->skill_lv * 10, sg->skill_lv, sg->skill_id, 0, 0, skill->get_time2(sg->skill_id, sg->skill_lv), 2|8); break; } if (bl->type == BL_MOB && ss != bl) - mobskill_event((TBL_MOB*)bl, ss, tick, MSC_SKILLUSED|(skill_id<<16)); + mob->skill_event((TBL_MOB*)bl, ss, tick, MSC_SKILLUSED|(skill_id<<16)); return skill_id; } /*========================================== * Triggered when a char steps out of a skill cell *------------------------------------------*/ -int skill_unit_onout (struct skill_unit *src, struct block_list *bl, unsigned int tick) { +int skill_unit_onout(struct skill_unit *src, struct block_list *bl, int64 tick) { struct skill_unit_group *sg; struct status_change *sc; struct status_change_entry *sce; @@ -11831,12 +12233,13 @@ int skill_unit_onout (struct skill_unit *src, struct block_list *bl, unsigned in nullpo_ret(src); nullpo_ret(bl); nullpo_ret(sg=src->group); - sc = status_get_sc(bl); - type = status_skill2sc(sg->skill_id); + sc = status->get_sc(bl); + type = status->skill2sc(sg->skill_id); sce = (sc && type != -1)?sc->data[type]:NULL; - if( bl->prev==NULL || - (status_isdead(bl) && sg->unit_id != UNT_ANKLESNARE && sg->unit_id != UNT_SPIDERWEB) ) //Need to delete the trap if the source died. + if( bl->prev == NULL + || (status->isdead(bl) && sg->unit_id != UNT_ANKLESNARE && sg->unit_id != UNT_SPIDERWEB && sg->unit_id != UNT_THORNS_TRAP) + ) //Need to delete the trap if the source died. return 0; switch(sg->unit_id){ @@ -11845,6 +12248,7 @@ int skill_unit_onout (struct skill_unit *src, struct block_list *bl, unsigned in case UNT_EPICLESIS://Arch Bishop case UNT_NEUTRALBARRIER: case UNT_STEALTHFIELD: + case UNT_WARMER: if (sce) status_change_end(bl, type, INVALID_TIMER); break; @@ -11858,16 +12262,17 @@ int skill_unit_onout (struct skill_unit *src, struct block_list *bl, unsigned in status_change_end(bl, type, INVALID_TIMER); break; - case UNT_SPIDERWEB: { - struct block_list *target = iMap->id2bl(sg->val2); - if (target && target==bl) - { - if (sce && sce->val3 == sg->group_id) - status_change_end(bl, type, INVALID_TIMER); - sg->limit = DIFF_TICK(tick,sg->tick)+1000; - } - break; + case UNT_THORNS_TRAP: + case UNT_SPIDERWEB: + { + struct block_list *target = map->id2bl(sg->val2); + if (target && target==bl) { + if (sce && sce->val3 == sg->group_id) + status_change_end(bl, type, INVALID_TIMER); + sg->limit = DIFF_TICK32(tick,sg->tick)+1000; } + } + break; } return sg->skill_id; } @@ -11875,17 +12280,16 @@ int skill_unit_onout (struct skill_unit *src, struct block_list *bl, unsigned in /*========================================== * Triggered when a char steps out of a skill group (entirely) [Skotlex] *------------------------------------------*/ -static int skill_unit_onleft (uint16 skill_id, struct block_list *bl, unsigned int tick) -{ +int skill_unit_onleft(uint16 skill_id, struct block_list *bl, int64 tick) { struct status_change *sc; struct status_change_entry *sce; enum sc_type type; - sc = status_get_sc(bl); + sc = status->get_sc(bl); if (sc && !sc->count) sc = NULL; - type = status_skill2sc(skill_id); + type = status->skill2sc(skill_id); sce = (sc && type != -1)?sc->data[type]:NULL; switch (skill_id) { @@ -11909,8 +12313,8 @@ static int skill_unit_onleft (uint16 skill_id, struct block_list *bl, unsigned i //We don't check for SC_LONGING because someone could always have knocked you back and out of the song/dance. //FIXME: This code is not perfect, it doesn't checks for the real ensemble's owner, //it only checks if you are doing the same ensemble. So if there's two chars doing an ensemble - //which overlaps, by stepping outside of the other parther's ensemble will cause you to cancel - //your own. Let's pray that scenario is pretty unlikely and noone will complain too much about it. + //which overlaps, by stepping outside of the other partner's ensemble will cause you to cancel + //your own. Let's pray that scenario is pretty unlikely and none will complain too much about it. status_change_end(bl, SC_DANCING, INVALID_TIMER); } case MH_STEINWAND: @@ -11926,20 +12330,18 @@ static int skill_unit_onleft (uint16 skill_id, struct block_list *bl, unsigned i case EL_WATER_BARRIER: case EL_ZEPHYR: case EL_POWER_OF_GAIA: + case SO_ELEMENTAL_SHIELD: + case SC_BLOODYLUST: + if (sce) + status_change_end(bl, type, INVALID_TIMER); + break; case SO_FIRE_INSIGNIA: case SO_WATER_INSIGNIA: case SO_WIND_INSIGNIA: case SO_EARTH_INSIGNIA: - if (sce) - status_change_end(bl, type, INVALID_TIMER); - break; - case SC_BLOODYLUST: - if (sce) { + if (sce && bl->type != BL_ELEM) status_change_end(bl, type, INVALID_TIMER); - status_set_sp(bl, 0, 0); //set sp to 0 when quitting zone - } break; - case BA_POEMBRAGI: case BA_WHISTLE: case BA_ASSASSINCROSS: @@ -11949,22 +12351,22 @@ static int skill_unit_onleft (uint16 skill_id, struct block_list *bl, unsigned i case DC_FORTUNEKISS: case DC_SERVICEFORYOU: if (sce) { - iTimer->delete_timer(sce->timer, status_change_timer); + timer->delete(sce->timer, status->change_timer); //NOTE: It'd be nice if we could get the skill_lv for a more accurate extra time, but alas... //not possible on our current implementation. sce->val4 = 1; //Store the fact that this is a "reduced" duration effect. - sce->timer = iTimer->add_timer(tick+skill->get_time2(skill_id,1), status_change_timer, bl->id, type); + sce->timer = timer->add(tick+skill->get_time2(skill_id,1), status->change_timer, bl->id, type); } break; case PF_FOGWALL: if (sce) { status_change_end(bl, type, INVALID_TIMER); if ((sce=sc->data[SC_BLIND])) { - if (bl->type == BL_PC) //Players get blind ended inmediately, others have it still for 30 secs. [Skotlex] + if (bl->type == BL_PC) //Players get blind ended immediately, others have it still for 30 secs. [Skotlex] status_change_end(bl, SC_BLIND, INVALID_TIMER); else { - iTimer->delete_timer(sce->timer, status_change_timer); - sce->timer = iTimer->add_timer(30000+tick, status_change_timer, bl->id, SC_BLIND); + timer->delete(sce->timer, status->change_timer); + sce->timer = timer->add(30000+tick, status->change_timer, bl->id, SC_BLIND); } } } @@ -11987,38 +12389,38 @@ static int skill_unit_onleft (uint16 skill_id, struct block_list *bl, unsigned i * flag&1: Invoke onplace function (otherwise invoke onout) * flag&4: Invoke a onleft call (the unit might be scheduled for deletion) *------------------------------------------*/ -int skill_unit_effect (struct block_list* bl, va_list ap) { - struct skill_unit* unit = va_arg(ap,struct skill_unit*); - struct skill_unit_group* group = unit->group; - unsigned int tick = va_arg(ap,unsigned int); +int skill_unit_effect(struct block_list* bl, va_list ap) { + struct skill_unit* su = va_arg(ap,struct skill_unit*); + struct skill_unit_group* group = su->group; + int64 tick = va_arg(ap,int64); unsigned int flag = va_arg(ap,unsigned int); uint16 skill_id; bool dissonance; - if( (!unit->alive && !(flag&4)) || bl->prev == NULL ) + if( (!su->alive && !(flag&4)) || bl->prev == NULL ) return 0; nullpo_ret(group); - dissonance = skill->dance_switch(unit, 0); + dissonance = skill->dance_switch(su, 0); //Necessary in case the group is deleted after calling on_place/on_out [Skotlex] skill_id = group->skill_id; //Target-type check. - if( !(group->bl_flag&bl->type && battle->check_target(&unit->bl,bl,group->target_flag)>0) && (flag&4) ) { - if( group->state.song_dance&0x1 || (group->src_id == bl->id && group->state.song_dance&0x2) ) + if( !(group->bl_flag&bl->type && battle->check_target(&su->bl,bl,group->target_flag)>0) ) { + if( (flag&4) && ( group->state.song_dance&0x1 || (group->src_id == bl->id && group->state.song_dance&0x2) ) ) skill->unit_onleft(skill_id, bl, tick);//Ensemble check to terminate it. } else { if( flag&1 ) - skill->unit_onplace(unit,bl,tick); + skill->unit_onplace(su,bl,tick); else - skill->unit_onout(unit,bl,tick); + skill->unit_onout(su,bl,tick); if( flag&4 ) skill->unit_onleft(skill_id, bl, tick); } - if( dissonance ) skill->dance_switch(unit, 1); + if( dissonance ) skill->dance_switch(su, 1); return 0; } @@ -12026,8 +12428,7 @@ int skill_unit_effect (struct block_list* bl, va_list ap) { /*========================================== * *------------------------------------------*/ -int skill_unit_ondamaged (struct skill_unit *src, struct block_list *bl, int damage, unsigned int tick) -{ +int skill_unit_ondamaged(struct skill_unit *src, struct block_list *bl, int64 damage, int64 tick) { struct skill_unit_group *sg; nullpo_ret(src); @@ -12045,15 +12446,17 @@ int skill_unit_ondamaged (struct skill_unit *src, struct block_list *bl, int dam case UNT_TALKIEBOX: case UNT_ANKLESNARE: case UNT_ICEWALL: - case UNT_REVERBERATION: case UNT_WALLOFTHORN: - src->val1-=damage; + src->val1 -= (int)cap_value(damage,INT_MIN,INT_MAX); + break; + case UNT_REVERBERATION: + src->val1--; break; default: damage = 0; break; } - return damage; + return (int)cap_value(damage,INT_MIN,INT_MAX); } /*========================================== @@ -12095,8 +12498,8 @@ int skill_check_condition_char_sub (struct block_list *bl, va_list ap) { switch(skill_id) { case PR_BENEDICTIO: { - uint8 dir = iMap->calc_dir(&sd->bl,tsd->bl.x,tsd->bl.y); - dir = (unit_getdir(&sd->bl) + dir)%8; //This adjusts dir to account for the direction the sd is facing. + uint8 dir = map->calc_dir(&sd->bl,tsd->bl.x,tsd->bl.y); + dir = (unit->getdir(&sd->bl) + dir)%8; //This adjusts dir to account for the direction the sd is facing. if ((tsd->class_&MAPID_BASEMASK) == MAPID_ACOLYTE && (dir == 2 || dir == 6) //Must be standing to the left/right of Priest. && sd->status.sp >= 10) p_sd[(*c)++]=tsd->bl.id; @@ -12120,7 +12523,7 @@ int skill_check_condition_char_sub (struct block_list *bl, va_list ap) { default: //Warning: Assuming Ensemble Dance/Songs for code speed. [Skotlex] { uint16 skill_lv; - if(pc_issit(tsd) || !unit_can_move(&tsd->bl)) + if(pc_issit(tsd) || !unit->can_move(&tsd->bl)) return 0; if (sd->status.sex != tsd->status.sex && (tsd->class_&MAPID_UPPERMASK) == MAPID_BARDDANCER && @@ -12146,7 +12549,7 @@ int skill_check_condition_char_sub (struct block_list *bl, va_list ap) { /*========================================== * Checks and stores partners for ensemble skills [Skotlex] *------------------------------------------*/ -int skill_check_pc_partner (struct map_session_data *sd, uint16 skill_id, short* skill_lv, int range, int cast_flag) { +int skill_check_pc_partner (struct map_session_data *sd, uint16 skill_id, uint16* skill_lv, int range, int cast_flag) { static int c=0; static int p_sd[2] = { 0, 0 }; int i; @@ -12160,28 +12563,22 @@ int skill_check_pc_partner (struct map_session_data *sd, uint16 skill_id, short* switch (skill_id) { case PR_BENEDICTIO: for (i = 0; i < c; i++) { - if ((tsd = iMap->id2sd(p_sd[i])) != NULL) - status_charge(&tsd->bl, 0, 10); + if ((tsd = map->id2sd(p_sd[i])) != NULL) + status->charge(&tsd->bl, 0, 10); } return c; case AB_ADORAMUS: - if( c > 0 && (tsd = iMap->id2sd(p_sd[0])) != NULL ) { + if( c > 0 && (tsd = map->id2sd(p_sd[0])) != NULL ) { i = 2 * (*skill_lv); - status_charge(&tsd->bl, 0, i); + status->charge(&tsd->bl, 0, i); } break; - case WM_GREAT_ECHO: - for( i = 0; i < c; i++ ) { - if( (tsd = iMap->id2sd(p_sd[i])) != NULL ) - status_zap(&tsd->bl,0,skill->get_sp(skill_id,*skill_lv)/c); - } - break; default: //Warning: Assuming Ensemble skills here (for speed) if( is_chorus ) break;//Chorus skills are not to be parsed as ensambles - if (c > 0 && sd->sc.data[SC_DANCING] && (tsd = iMap->id2sd(p_sd[0])) != NULL) { + if (c > 0 && sd->sc.data[SC_DANCING] && (tsd = map->id2sd(p_sd[0])) != NULL) { sd->sc.data[SC_DANCING]->val4 = tsd->bl.id; - sc_start4(&tsd->bl,SC_DANCING,100,skill_id,sd->sc.data[SC_DANCING]->val2,*skill_lv,sd->bl.id,skill->get_time(skill_id,*skill_lv)+1000); + sc_start4(&tsd->bl,&tsd->bl,SC_DANCING,100,skill_id,sd->sc.data[SC_DANCING]->val2,*skill_lv,sd->bl.id,skill->get_time(skill_id,*skill_lv)+1000); clif->skill_nodamage(&tsd->bl, &sd->bl, skill_id, *skill_lv, 1); tsd->skill_id_dance = skill_id; tsd->skill_lv_dance = *skill_lv; @@ -12194,9 +12591,9 @@ int skill_check_pc_partner (struct map_session_data *sd, uint16 skill_id, short* c = 0; memset (p_sd, 0, sizeof(p_sd)); if( is_chorus ) - i = party_foreachsamemap(skill->check_condition_char_sub,sd,AREA_SIZE,&sd->bl, &c, &p_sd, skill_id, *skill_lv); + i = party->foreachsamemap(skill->check_condition_char_sub,sd,AREA_SIZE,&sd->bl, &c, &p_sd, skill_id, *skill_lv); else - i = iMap->foreachinrange(skill->check_condition_char_sub, &sd->bl, range, BL_PC, &sd->bl, &c, &p_sd, skill_id); + i = map->foreachinrange(skill->check_condition_char_sub, &sd->bl, range, BL_PC, &sd->bl, &c, &p_sd, skill_id); if ( skill_id != PR_BENEDICTIO && skill_id != AB_ADORAMUS && skill_id != WL_COMET ) //Apply the average lv to encore skills. *skill_lv = (i+(*skill_lv))/(c+1); //I know c should be one, but this shows how it could be used for the average of n partners. @@ -12207,15 +12604,15 @@ int skill_check_pc_partner (struct map_session_data *sd, uint16 skill_id, short* * *------------------------------------------*/ int skill_check_condition_mob_master_sub (struct block_list *bl, va_list ap) { - int *c,src_id,mob_class,skill; + int *c,src_id,mob_class,skill_id; struct mob_data *md; md=(struct mob_data*)bl; src_id=va_arg(ap,int); mob_class=va_arg(ap,int); - skill=va_arg(ap,int); + skill_id=va_arg(ap,int); c=va_arg(ap,int *); - if( md->master_id != src_id || md->special_state.ai != (unsigned)(skill == AM_SPHEREMINE?2:skill == KO_ZANZOU?4:skill == MH_SUMMON_LEGION?1:3) ) + if( md->master_id != src_id || md->special_state.ai != (unsigned)(skill_id == AM_SPHEREMINE?2:skill_id == KO_ZANZOU?4:skill_id == MH_SUMMON_LEGION?1:3) ) return 0; //Non alchemist summoned mobs have nothing to do here. if(md->class_==mob_class) (*c)++; @@ -12239,11 +12636,39 @@ int skill_isammotype (struct map_session_data *sd, int skill_id) ); } +/** + * Checks whether a skill can be used in combos or not + **/ +bool skill_is_combo( int skill_id ) +{ + switch( skill_id ) + { + case MO_CHAINCOMBO: + case MO_COMBOFINISH: + case CH_TIGERFIST: + case CH_CHAINCRUSH: + case MO_EXTREMITYFIST: + case TK_TURNKICK: + case TK_STORMKICK: + case TK_DOWNKICK: + case TK_COUNTER: + case TK_JUMPKICK: + case HT_POWER: + case GC_COUNTERSLASH: + case GC_WEAPONCRUSH: + case SR_FALLENEMPIRE: + case SR_DRAGONCOMBO: + case SR_TIGERCANNON: + case SR_GATEOFHELL: + return true; + } + return false; +} + int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id, uint16 skill_lv) { - struct status_data *status; + struct status_data *st; struct status_change *sc; struct skill_condition require; - int i; nullpo_ret(sd); @@ -12276,7 +12701,7 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id return 0; break; } - status = &sd->battle_status; + st = &sd->battle_status; sc = &sd->sc; if( !sc->count ) sc = NULL; @@ -12285,6 +12710,7 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id if( sd->state.abra_flag ) // Hocus-Pocus was used. [Inkfish] sd->state.abra_flag = 0; else { + int i; // When a target was selected, consume items that were skipped in pc_use_item [Skotlex] if( (i = sd->itemindex) == -1 || sd->status.inventory[i].nameid != sd->itemid || @@ -12315,45 +12741,76 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id return 0; switch( skill_id ) { // Turn off check. - case BS_MAXIMIZE: case NV_TRICKDEAD: case TF_HIDING: case AS_CLOAKING: case CR_AUTOGUARD: - case ML_AUTOGUARD: case CR_DEFENDER: case ML_DEFENDER: case ST_CHASEWALK: case PA_GOSPEL: - case CR_SHRINK: case TK_RUN: case GS_GATLINGFEVER: case TK_READYCOUNTER: case TK_READYDOWN: - case TK_READYSTORM: case TK_READYTURN: case SG_FUSION: case RA_WUGDASH: case KO_YAMIKUMO: - if( sc && sc->data[status_skill2sc(skill_id)] ) + case BS_MAXIMIZE: + case NV_TRICKDEAD: + case TF_HIDING: + case AS_CLOAKING: + case CR_AUTOGUARD: + case ML_AUTOGUARD: + case CR_DEFENDER: + case ML_DEFENDER: + case ST_CHASEWALK: + case PA_GOSPEL: + case CR_SHRINK: + case TK_RUN: + case GS_GATLINGFEVER: + case TK_READYCOUNTER: + case TK_READYDOWN: + case TK_READYSTORM: + case TK_READYTURN: + case SG_FUSION: + case RA_WUGDASH: + case KO_YAMIKUMO: + if( sc && sc->data[status->skill2sc(skill_id)] ) return 1; } // Check the skills that can be used while mounted on a warg if( pc_isridingwug(sd) ) { switch( skill_id ) { - case HT_SKIDTRAP: case HT_LANDMINE: case HT_ANKLESNARE: case HT_SHOCKWAVE: - case HT_SANDMAN: case HT_FLASHER: case HT_FREEZINGTRAP: case HT_BLASTMINE: - case HT_CLAYMORETRAP: case HT_SPRINGTRAP: case RA_DETONATOR: case RA_CLUSTERBOMB: - case HT_TALKIEBOX: case RA_FIRINGTRAP: case RA_ICEBOUNDTRAP: - case RA_WUGDASH: case RA_WUGRIDER: case RA_WUGSTRIKE: + // Hunter skills + case HT_SKIDTRAP: + case HT_LANDMINE: + case HT_ANKLESNARE: + case HT_SHOCKWAVE: + case HT_SANDMAN: + case HT_FLASHER: + case HT_FREEZINGTRAP: + case HT_BLASTMINE: + case HT_CLAYMORETRAP: + case HT_TALKIEBOX: + // Ranger skills + case RA_DETONATOR: + case RA_ELECTRICSHOCKER: + case RA_CLUSTERBOMB: + case RA_MAGENTATRAP: + case RA_COBALTTRAP: + case RA_MAIZETRAP: + case RA_VERDURETRAP: + case RA_FIRINGTRAP: + case RA_ICEBOUNDTRAP: + case RA_WUGDASH: + case RA_WUGRIDER: + case RA_WUGSTRIKE: + // Other + case BS_GREED: break; default: // in official there is no message. return 0; } } + + // Check the skills that can be used whiled using mado if( pc_ismadogear(sd) ) { - switch( skill_id ) { //None Mado skills are unusable when Mado is equipped. [Jobbie] - case BS_REPAIRWEAPON: case WS_MELTDOWN: - case BS_HAMMERFALL: case WS_CARTBOOST: - case BS_ADRENALINE: case WS_WEAPONREFINE: - case BS_WEAPONPERFECT: case WS_CARTTERMINATION: - case BS_OVERTHRUST: case WS_OVERTHRUSTMAX: - case BS_MAXIMIZE: - case BS_ADRENALINE2: - case BS_UNFAIRLYTRICK: - case BS_GREED: - clif->skill_fail(sd,skill_id,USESKILL_FAIL_MADOGEAR,0); - return 0; - default: //Only Mechanic exlcusive skill can be used. - break; + if( !(skill_id > NC_MADOLICENCE && skill_id <= NC_DISJOINT) + && skill_id != NC_MAGMA_ERUPTION + && skill_id != BS_GREED ) { + clif->skill_fail(sd,skill_id,USESKILL_FAIL_MADOGEAR,0); + return 0; } } + if( skill_lv < 1 || skill_lv > MAX_SKILL_LEVEL ) return 0; @@ -12404,34 +12861,38 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id return 0; if(sc->data[SC_BLADESTOP]) break; - if( (i=(sc && sc->data[SC_COMBOATTACK])) && sc->data[SC_COMBOATTACK]->val1 == MO_TRIPLEATTACK ) - break; - if( i ) + if( sc && sc->data[SC_COMBOATTACK] ) { + if( sc->data[SC_COMBOATTACK]->val1 == MO_TRIPLEATTACK ) + break; clif->skill_fail(sd, skill_id, USESKILL_FAIL_COMBOSKILL, MO_TRIPLEATTACK); + } return 0; case MO_COMBOFINISH: if(!sc) return 0; - if( (i=(sc && sc->data[SC_COMBOATTACK])) && sc->data[SC_COMBOATTACK]->val1 == MO_CHAINCOMBO ) - break; - if( i ) + if( sc && sc->data[SC_COMBOATTACK] ) { + if ( sc->data[SC_COMBOATTACK]->val1 == MO_CHAINCOMBO ) + break; clif->skill_fail(sd, skill_id, USESKILL_FAIL_COMBOSKILL, MO_CHAINCOMBO); + } return 0; case CH_TIGERFIST: if(!sc) return 0; - if( (i=(sc && sc->data[SC_COMBOATTACK])) && sc->data[SC_COMBOATTACK]->val1 == MO_COMBOFINISH ) - break; - if( i ) + if( sc && sc->data[SC_COMBOATTACK] ) { + if ( sc->data[SC_COMBOATTACK]->val1 == MO_COMBOFINISH ) + break; clif->skill_fail(sd, skill_id, USESKILL_FAIL_COMBOSKILL, MO_COMBOFINISH); + } return 0; case CH_CHAINCRUSH: if(!sc) return 0; - if( (i=(sc && sc->data[SC_COMBOATTACK])) && sc->data[SC_COMBOATTACK]->val1 == CH_TIGERFIST ) - break; - if( i ) + if( sc && sc->data[SC_COMBOATTACK] ) { + if( sc->data[SC_COMBOATTACK]->val1 == CH_TIGERFIST ) + break; clif->skill_fail(sd, skill_id, USESKILL_FAIL_COMBOSKILL, CH_TIGERFIST); + } return 0; case MO_EXTREMITYFIST: // if(sc && sc->data[SC_EXTREMITYFIST]) //To disable Asura during the 5 min skill block uncomment this... @@ -12449,7 +12910,7 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id return 0; } } - else if( !unit_can_move(&sd->bl) ) + else if( !unit->can_move(&sd->bl) ) { //Placed here as ST_MOVE_ENABLE should not apply if rooted or on a combo. [Skotlex] clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); return 0; @@ -12493,7 +12954,7 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id return 0; } if(sc->data[SC_COMBOATTACK]->val1 != skill_id && !( sd && sd->status.base_level >= 90 && pc->famerank(sd->status.char_id, MAPID_TAEKWON) )) { //Cancel combo wait. - unit_cancel_combo(&sd->bl); + unit->cancel_combo(&sd->bl); return 0; } break; //Combo ready. @@ -12536,7 +12997,7 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id break; case CG_HERMODE: - if(!npc_check_areanpc(1,sd->bl.m,sd->bl.x,sd->bl.y,skill->get_splash(skill_id, skill_lv))) + if(!npc->check_areanpc(1,sd->bl.m,sd->bl.x,sd->bl.y,skill->get_splash(skill_id, skill_lv))) { clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); return 0; @@ -12549,7 +13010,7 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id for (i=0;i<size*size;i++) { x = sd->bl.x+(i%size-range); y = sd->bl.y+(i/size-range); - if (iMap->getcell(sd->bl.m,x,y,CELL_CHKWALL)) { + if (map->getcell(sd->bl.m,x,y,CELL_CHKWALL)) { clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); return 0; } @@ -12579,8 +13040,7 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id case SG_STAR_WARM: if (sc && sc->data[SC_MIRACLE]) break; - i = skill_id-SG_SUN_WARM; - if (sd->bl.m == sd->feel_map[i].m) + if (sd->bl.m == sd->feel_map[skill_id-SG_SUN_WARM].m) break; clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); return 0; @@ -12590,9 +13050,8 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id case SG_STAR_COMFORT: if (sc && sc->data[SC_MIRACLE]) break; - i = skill_id-SG_SUN_COMFORT; - if (sd->bl.m == sd->feel_map[i].m && - (battle_config.allow_skill_without_day || sg_info[i].day_func())) + if (sd->bl.m == sd->feel_map[skill_id-SG_SUN_COMFORT].m && + (battle_config.allow_skill_without_day || pc->sg_info[skill_id-SG_SUN_COMFORT].day_func())) break; clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); return 0; @@ -12601,9 +13060,8 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id break; //Auron insists we should implement SP consumption when you are not Soul Linked. [Skotlex] //Only invoke on skill begin cast (instant cast skill). [Kevin] - if( require.sp > 0 ) - { - if (status->sp < (unsigned int)require.sp) + if( require.sp > 0 ) { + if (st->sp < (unsigned int)require.sp) clif->skill_fail(sd,skill_id,USESKILL_FAIL_SP_INSUFFICIENT,0); else status_zap(&sd->bl, 0, require.sp); @@ -12631,9 +13089,9 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id case NJ_ISSEN: #ifdef RENEWAL - if (status->hp < (status->hp/100)) { + if (st->hp < (st->hp/100)) { #else - if (status->hp < 2) { + if (st->hp < 2) { #endif clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); return 0; @@ -12653,7 +13111,7 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id } break; case PF_HPCONVERSION: - if (status->sp == status->max_sp) + if (st->sp == st->max_sp) return 0; //Unusable when at full SP. break; case AM_CALLHOMUN: //Can't summon if a hom is already out @@ -12662,7 +13120,7 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id return 0; } break; - case AM_REST: //Can't vapo homun if you don't have an active homunc or it's hp is < 80% + case AM_REST: //Can't vapo homun if you don't have an active homun or it's hp is < 80% if (!homun_alive(sd->hd) || sd->hd->battle_status.hp < (sd->hd->battle_status.max_hp*80/100)) { clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); @@ -12674,7 +13132,7 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id **/ case AB_ANCILLA: { - int count = 0; + int count = 0, i; for( i = 0; i < MAX_INVENTORY; i ++ ) if( sd->status.inventory[i].nameid == ITEMID_ANCILLA ) count += sd->status.inventory[i].amount; @@ -12701,13 +13159,21 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id * Warlock **/ case WL_COMET: - if( skill->check_pc_partner(sd,skill_id,&skill_lv,1,0) <= 0 && ((i = pc->search_inventory(sd,require.itemid[0])) < 0 || sd->status.inventory[i].amount < require.amount[0]) ) - { + { + int idx; + + if( !require.itemid[0] ) // issue: 7935 + break; + if (skill->check_pc_partner(sd,skill_id,&skill_lv,1,0) <= 0 + && ((idx = pc->search_inventory(sd,require.itemid[0])) == INDEX_NOT_FOUND + || sd->status.inventory[idx].amount < require.amount[0]) + ) { //clif->skill_fail(sd,skill_id,USESKILL_FAIL_NEED_ITEM,require.amount[0],require.itemid[0]); clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); return 0; } break; + } case WL_SUMMONFB: case WL_SUMMONBL: case WL_SUMMONWB: @@ -12715,10 +13181,9 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id case WL_TETRAVORTEX: case WL_RELEASE: { - int x = SC_SUMMON1; - i = 0; - for(; x <= SC_SUMMON5; x++) - if( sc && sc->data[x] ) + int j, i = 0; + for(j = SC_SUMMON1; j <= SC_SUMMON5; j++) + if( sc && sc->data[j] ) i++; switch(skill_id){ @@ -12729,8 +13194,8 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id } break; case WL_RELEASE: - for(x = SC_SPELLBOOK7; x >= SC_SPELLBOOK1; x--) - if( sc && sc->data[x] ) + for(j = SC_SPELLBOOK7; j >= SC_SPELLBOOK1; j--) + if( sc && sc->data[j] ) i++; if( i == 0 ){ clif->skill_fail(sd,skill_id,USESKILL_FAIL_SUMMON_NONE,0); @@ -12803,13 +13268,6 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id return 0; } break; - case LG_RAGEBURST: - if( sd->spiritball == 0 ) { - clif->skill_fail(sd,skill_id,USESKILL_FAIL_SKILLINTERVAL,0); - return 0; - } - sd->spiritball_old = require.spiritball = sd->spiritball; - break; case LG_RAYOFGENESIS: if( sc && sc->data[SC_INSPIRATION] ) return 1; // Don't check for partner. @@ -12826,12 +13284,11 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id } break; case SR_FALLENEMPIRE: - if( !sc ) - return 0; - if( (i=(sc && sc->data[SC_COMBOATTACK])) && sc->data[SC_COMBOATTACK]->val1 == SR_DRAGONCOMBO ) - break; - if( i ) + if( sc && sc->data[SC_COMBOATTACK] ) { + if( sc->data[SC_COMBOATTACK]->val1 == SR_DRAGONCOMBO ) + break; clif->skill_fail(sd, skill_id, USESKILL_FAIL_COMBOSKILL, SR_DRAGONCOMBO); + } return 0; case SR_CRESCENTELBOW: if( sc && sc->data[SC_CRESCENTELBOW] ) { @@ -12840,19 +13297,19 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id } break; case SR_CURSEDCIRCLE: - if (map_flag_gvg(sd->bl.m)) { - if (iMap->foreachinrange(mob_count_sub, &sd->bl, skill->get_splash(skill_id, skill_lv), BL_MOB, - MOBID_EMPERIUM, MOBID_GUARIDAN_STONE1, MOBID_GUARIDAN_STONE2)) { - char output[128]; - sprintf(output, "You're too close to a stone or emperium to do this skill"); - clif->colormes(sd->fd, COLOR_RED, output); - return 0; - } + if (map_flag_gvg2(sd->bl.m)) { + if (map->foreachinrange(mob->count_sub, &sd->bl, skill->get_splash(skill_id, skill_lv), BL_MOB, + MOBID_EMPERIUM, MOBID_GUARIDAN_STONE1, MOBID_GUARIDAN_STONE2)) { + char output[128]; + sprintf(output, "You're too close to a stone or emperium to do this skill"); /* TODO official response? or message.conf it */ + clif->colormes(sd->fd, COLOR_RED, output); + return 0; + } } if( sd->spiritball > 0 ) sd->spiritball_old = require.spiritball = sd->spiritball; else { - clif->skill_fail(sd,skill_id,0,0); + clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); return 0; } break; @@ -12863,7 +13320,7 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id case SC_MANHOLE: case SC_DIMENSIONDOOR: if( sc && sc->data[SC_MAGNETICFIELD] ) { - clif->skill_fail(sd,skill_id,0,0); + clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); return 0; } break; @@ -12877,11 +13334,17 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id require.sp -= require.sp * 20 * count / 100; // -20% each W/M in the party. } break; + case NC_PILEBUNKER: + if ( sd->equip_index[EQI_HAND_R] < 0 || sd->status.inventory[sd->equip_index[EQI_HAND_R]].nameid != ITEMID_PILEBUNCKER ) { + clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + return 0; + } + break; case SO_FIREWALK: case SO_ELECTRICWALK: // Can't be casted until you've walked all cells. if( sc && sc->data[SC_PROPERTYWALK] && sc->data[SC_PROPERTYWALK]->val3 < skill->get_maxcount(sc->data[SC_PROPERTYWALK]->val1,sc->data[SC_PROPERTYWALK]->val2) ) { - clif->skill_fail(sd,skill_id,0x0,0); + clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); return 0; } break; @@ -12897,9 +13360,8 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id return 0; } break; - case LG_REFLECTDAMAGE: case CR_REFLECTSHIELD: - if( sc && sc->data[SC_KYOMU] && rand()%100 < 5 * sc->data[SC_KYOMU]->val1 ){ + if( sc && sc->data[SC_KYOMU] && rnd()%100 < 5 * sc->data[SC_KYOMU]->val1 ){ clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); return 0; } @@ -12918,11 +13380,14 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id break; case KO_KAIHOU: case KO_ZENKAI: - ARR_FIND(1, 6, i, sd->charm[i] > 0); + { + int i; + ARR_FIND(1, 6, i, sd->charm[i] > 0); // FIXME: 4 or 6? if( i > 4 ) { clif->skill_fail(sd,skill_id,USESKILL_FAIL_SUMMON,0); return 0; } + } break; } @@ -12994,9 +13459,9 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id break; case ST_MOVE_ENABLE: if (sc && sc->data[SC_COMBOATTACK] && sc->data[SC_COMBOATTACK]->val1 == skill_id) - sd->ud.canmove_tick = iTimer->gettick(); //When using a combo, cancel the can't move delay to enable the skill. [Skotlex] + sd->ud.canmove_tick = timer->gettick(); //When using a combo, cancel the can't move delay to enable the skill. [Skotlex] - if (!unit_can_move(&sd->bl)) { + if (!unit->can_move(&sd->bl)) { clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); return 0; } @@ -13004,7 +13469,7 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id case ST_WATER: if (sc && (sc->data[SC_DELUGE] || sc->data[SC_NJ_SUITON])) break; - if (iMap->getcell(sd->bl.m,sd->bl.x,sd->bl.y,CELL_CHKWATER)) + if (map->getcell(sd->bl.m,sd->bl.x,sd->bl.y,CELL_CHKWATER)) break; clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); return 0; @@ -13068,7 +13533,7 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id break; } - if(require.mhp > 0 && get_percentage(status->hp, status->max_hp) > require.mhp) { + if(require.mhp > 0 && get_percentage(st->hp, st->max_hp) > require.mhp) { //mhp is the max-hp-requirement, that is, //you must have this % or less of HP to cast it. clif->skill_fail(sd,skill_id,USESKILL_FAIL_HP_INSUFFICIENT,0); @@ -13080,7 +13545,7 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id return 0; } - if( require.sp > 0 && status->sp < (unsigned int)require.sp) { + if( require.sp > 0 && st->sp < (unsigned int)require.sp) { clif->skill_fail(sd,skill_id,USESKILL_FAIL_SP_INSUFFICIENT,0); return 0; } @@ -13095,37 +13560,18 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id return 0; } - if( sd->sc.data[SC_COMBOATTACK] ) { - switch( skill_id ) { - case MO_CHAINCOMBO: - case MO_COMBOFINISH: - case CH_TIGERFIST: - case CH_CHAINCRUSH: - case MO_EXTREMITYFIST: - case TK_TURNKICK: - case TK_STORMKICK: - case TK_DOWNKICK: - case TK_COUNTER: - case TK_JUMPKICK: - case HT_POWER: - case GC_COUNTERSLASH: - case GC_WEAPONCRUSH: - case SR_FALLENEMPIRE: - case SR_DRAGONCOMBO: - case SR_TIGERCANNON: - case SR_GATEOFHELL: - break; - default: return 0; - } - } + // There's no need to check if the skill is part of a combo if it's + // already been checked before, see unit_skilluse_id2 [Panikon] + // Note that if this check is read part of issue:8047 will reappear! + //if( sd->sc.data[SC_COMBOATTACK] && !skill->is_combo(skill_id ) ) + // return 0; return 1; } -int skill_check_condition_castend(struct map_session_data* sd, uint16 skill_id, uint16 skill_lv) -{ +int skill_check_condition_castend(struct map_session_data* sd, uint16 skill_id, uint16 skill_lv) { struct skill_condition require; - struct status_data *status; + struct status_data *st; int i; int index[MAX_SKILL_ITEM_REQUIRE]; @@ -13186,10 +13632,11 @@ int skill_check_condition_castend(struct map_session_data* sd, uint16 skill_id, int maxcount = (skill_id==AM_CANNIBALIZE)? 6-skill_lv : skill->get_maxcount(skill_id,skill_lv); int mob_class = (skill_id==AM_CANNIBALIZE)? summons[skill_lv-1] :1142; if(battle_config.land_skill_limit && maxcount>0 && (battle_config.land_skill_limit&BL_PC)) { - i = iMap->foreachinmap(skill->check_condition_mob_master_sub ,sd->bl.m, BL_MOB, sd->bl.id, mob_class, skill_id, &c); - if(c >= maxcount || - (skill_id==AM_CANNIBALIZE && c != i && battle_config.summon_flora&2)) - { //Fails when: exceed max limit. There are other plant types already out. + i = map->foreachinmap(skill->check_condition_mob_master_sub ,sd->bl.m, BL_MOB, sd->bl.id, mob_class, skill_id, &c); + if( c >= maxcount + || (skill_id==AM_CANNIBALIZE && c != i && battle_config.summon_flora&2) + ) { + //Fails when: exceed max limit. There are other plant types already out. clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); return 0; } @@ -13207,9 +13654,9 @@ int skill_check_condition_castend(struct map_session_data* sd, uint16 skill_id, if( battle_config.land_skill_limit && maxcount > 0 && ( battle_config.land_skill_limit&BL_PC ) ) { if( skill_id == NC_MAGICDECOY ) { for( j = mob_class; j <= 2046; j++ ) - iMap->foreachinmap(skill->check_condition_mob_master_sub, sd->bl.m, BL_MOB, sd->bl.id, j, skill_id, &c); + map->foreachinmap(skill->check_condition_mob_master_sub, sd->bl.m, BL_MOB, sd->bl.id, j, skill_id, &c); } else - iMap->foreachinmap(skill->check_condition_mob_master_sub, sd->bl.m, BL_MOB, sd->bl.id, mob_class, skill_id, &c); + map->foreachinmap(skill->check_condition_mob_master_sub, sd->bl.m, BL_MOB, sd->bl.id, mob_class, skill_id, &c); if( c >= maxcount ) { clif->skill_fail(sd , skill_id, USESKILL_FAIL_LEVEL, 0); return 0; @@ -13219,7 +13666,7 @@ int skill_check_condition_castend(struct map_session_data* sd, uint16 skill_id, break; case KO_ZANZOU: { int c = 0; - i = iMap->foreachinmap(skill->check_condition_mob_master_sub, sd->bl.m, BL_MOB, sd->bl.id, 2308, skill_id, &c); + i = map->foreachinmap(skill->check_condition_mob_master_sub, sd->bl.m, BL_MOB, sd->bl.id, 2308, skill_id, &c); if( c >= skill->get_maxcount(skill_id,skill_lv) || c != i) { clif->skill_fail(sd , skill_id, USESKILL_FAIL_LEVEL, 0); return 0; @@ -13228,11 +13675,11 @@ int skill_check_condition_castend(struct map_session_data* sd, uint16 skill_id, break; } - status = &sd->battle_status; + st = &sd->battle_status; require = skill->get_requirement(sd,skill_id,skill_lv); - if( require.hp > 0 && status->hp <= (unsigned int)require.hp) { + if( require.hp > 0 && st->hp <= (unsigned int)require.hp) { clif->skill_fail(sd,skill_id,USESKILL_FAIL_HP_INSUFFICIENT,0); return 0; } @@ -13270,7 +13717,7 @@ int skill_check_condition_castend(struct map_session_data* sd, uint16 skill_id, if( !require.itemid[i] ) continue; index[i] = pc->search_inventory(sd,require.itemid[i]); - if( index[i] < 0 || sd->status.inventory[index[i]].amount < require.amount[i] ) { + if (index[i] == INDEX_NOT_FOUND || sd->status.inventory[index[i]].amount < require.amount[i]) { useskill_fail_cause cause = USESKILL_FAIL_NEED_ITEM; switch( skill_id ){ case NC_SILVERSNIPER: @@ -13363,7 +13810,7 @@ int skill_consume_requirement( struct map_session_data *sd, uint16 skill_id, uin continue; if( itemid_isgemstone(req.itemid[i]) && skill_id != HW_GANBANTEIN && sc && sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_WIZARD ) - continue; //Gemstones are checked, but not substracted from inventory. + continue; //Gemstones are checked, but not subtracted from inventory. switch( skill_id ){ case SA_SEISMICWEAPON: @@ -13387,7 +13834,7 @@ int skill_consume_requirement( struct map_session_data *sd, uint16 skill_id, uin break; } - if( (n = pc->search_inventory(sd,req.itemid[i])) >= 0 ) + if ((n = pc->search_inventory(sd,req.itemid[i])) != INDEX_NOT_FOUND) pc->delitem(sd,n,req.amount[i],0,1,LOG_TYPE_CONSUME); } } @@ -13395,10 +13842,9 @@ int skill_consume_requirement( struct map_session_data *sd, uint16 skill_id, uin return 1; } -struct skill_condition skill_get_requirement(struct map_session_data* sd, uint16 skill_id, uint16 skill_lv) -{ +struct skill_condition skill_get_requirement(struct map_session_data* sd, uint16 skill_id, uint16 skill_lv) { struct skill_condition req; - struct status_data *status; + struct status_data *st; struct status_change *sc; int i,hp_rate,sp_rate, sp_skill_rate_bonus = 100; uint16 idx; @@ -13407,12 +13853,11 @@ struct skill_condition skill_get_requirement(struct map_session_data* sd, uint16 if( !sd ) return req; - /* temporarily disabled, awaiting for kenpachi to detail this so we can make it work properly */ -#if 0 +#if 0 /* temporarily disabled, awaiting for kenpachi to detail this so we can make it work properly */ if( sd->state.abra_flag ) -#else +#else // not 0 if( sd->skillitem == skill_id ) -#endif +#endif // 0 return req; // Hocus-Pocus don't have requirements. sc = &sd->sc; @@ -13420,11 +13865,26 @@ struct skill_condition skill_get_requirement(struct map_session_data* sd, uint16 sc = NULL; switch( skill_id ) { // Turn off check. - case BS_MAXIMIZE: case NV_TRICKDEAD: case TF_HIDING: case AS_CLOAKING: case CR_AUTOGUARD: - case ML_AUTOGUARD: case CR_DEFENDER: case ML_DEFENDER: case ST_CHASEWALK: case PA_GOSPEL: - case CR_SHRINK: case TK_RUN: case GS_GATLINGFEVER: case TK_READYCOUNTER: case TK_READYDOWN: - case TK_READYSTORM: case TK_READYTURN: case SG_FUSION: case KO_YAMIKUMO: - if( sc && sc->data[status_skill2sc(skill_id)] ) + case BS_MAXIMIZE: + case NV_TRICKDEAD: + case TF_HIDING: + case AS_CLOAKING: + case CR_AUTOGUARD: + case ML_AUTOGUARD: + case CR_DEFENDER: + case ML_DEFENDER: + case ST_CHASEWALK: + case PA_GOSPEL: + case CR_SHRINK: + case TK_RUN: + case GS_GATLINGFEVER: + case TK_READYCOUNTER: + case TK_READYDOWN: + case TK_READYSTORM: + case TK_READYTURN: + case SG_FUSION: + case KO_YAMIKUMO: + if( sc && sc->data[status->skill2sc(skill_id)] ) return req; } @@ -13434,23 +13894,23 @@ struct skill_condition skill_get_requirement(struct map_session_data* sd, uint16 if( skill_lv < 1 || skill_lv > MAX_SKILL_LEVEL ) return req; - status = &sd->battle_status; + st = &sd->battle_status; - req.hp = skill_db[idx].hp[skill_lv-1]; - hp_rate = skill_db[idx].hp_rate[skill_lv-1]; + req.hp = skill->db[idx].hp[skill_lv-1]; + hp_rate = skill->db[idx].hp_rate[skill_lv-1]; if(hp_rate > 0) - req.hp += (status->hp * hp_rate)/100; + req.hp += (st->hp * hp_rate)/100; else - req.hp += (status->max_hp * (-hp_rate))/100; + req.hp += (st->max_hp * (-hp_rate))/100; - req.sp = skill_db[idx].sp[skill_lv-1]; + req.sp = skill->db[idx].sp[skill_lv-1]; if((sd->skill_id_old == BD_ENCORE) && skill_id == sd->skill_id_dance) req.sp /= 2; - sp_rate = skill_db[idx].sp_rate[skill_lv-1]; + sp_rate = skill->db[idx].sp_rate[skill_lv-1]; if(sp_rate > 0) - req.sp += (status->sp * sp_rate)/100; + req.sp += (st->sp * sp_rate)/100; else - req.sp += (status->max_sp * (-sp_rate))/100; + req.sp += (st->max_sp * (-sp_rate))/100; if( sd->dsprate != 100 ) req.sp = req.sp * sd->dsprate / 100; @@ -13467,29 +13927,29 @@ struct skill_condition skill_get_requirement(struct map_session_data* sd, uint16 if( sc->data[SC__LAZINESS] ) req.sp += req.sp + sc->data[SC__LAZINESS]->val1 * 10; if( sc->data[SC_UNLIMITED_HUMMING_VOICE] ) - req.sp += req.sp * sc->data[SC_UNLIMITED_HUMMING_VOICE]->val2 / 100; + req.sp += req.sp * sc->data[SC_UNLIMITED_HUMMING_VOICE]->val3 / 100; if( sc->data[SC_RECOGNIZEDSPELL] ) req.sp += req.sp / 4; if( sc->data[SC_TELEKINESIS_INTENSE] && skill->get_ele(skill_id, skill_lv) == ELE_GHOST) req.sp -= req.sp * sc->data[SC_TELEKINESIS_INTENSE]->val2 / 100; } - req.zeny = skill_db[idx].zeny[skill_lv-1]; + req.zeny = skill->db[idx].zeny[skill_lv-1]; if( sc && sc->data[SC__UNLUCKY] ) req.zeny += sc->data[SC__UNLUCKY]->val1 * 500; - req.spiritball = skill_db[idx].spiritball[skill_lv-1]; + req.spiritball = skill->db[idx].spiritball[skill_lv-1]; - req.state = skill_db[idx].state; + req.state = skill->db[idx].state; - req.mhp = skill_db[idx].mhp[skill_lv-1]; + req.mhp = skill->db[idx].mhp[skill_lv-1]; - req.weapon = skill_db[idx].weapon; + req.weapon = skill->db[idx].weapon; - req.ammo_qty = skill_db[idx].ammo_qty[skill_lv-1]; + req.ammo_qty = skill->db[idx].ammo_qty[skill_lv-1]; if (req.ammo_qty) - req.ammo = skill_db[idx].ammo; + req.ammo = skill->db[idx].ammo; if (!req.ammo && skill_id && skill->isammotype(sd, skill_id)) { //Assume this skill is using the weapon, therefore it requires arrows. @@ -13515,11 +13975,11 @@ struct skill_condition skill_get_requirement(struct map_session_data* sd, uint16 continue; break; case AB_ADORAMUS: - if( itemid_isgemstone(skill_db[idx].itemid[i]) && skill->check_pc_partner(sd,skill_id,&skill_lv, 1, 2) ) + if( itemid_isgemstone(skill->db[idx].itemid[i]) && skill->check_pc_partner(sd,skill_id,&skill_lv, 1, 2) ) continue; break; case WL_COMET: - if( itemid_isgemstone(skill_db[idx].itemid[i]) && skill->check_pc_partner(sd,skill_id,&skill_lv, 1, 0) ) + if( itemid_isgemstone(skill->db[idx].itemid[i]) && skill->check_pc_partner(sd,skill_id,&skill_lv, 1, 0) ) continue; break; case GN_FIRE_EXPANSION: @@ -13539,27 +13999,31 @@ struct skill_condition skill_get_requirement(struct map_session_data* sd, uint16 break; } - req.itemid[i] = skill_db[idx].itemid[i]; - req.amount[i] = skill_db[idx].amount[i]; + req.itemid[i] = skill->db[idx].itemid[i]; + req.amount[i] = skill->db[idx].amount[i]; if( itemid_isgemstone(req.itemid[i]) && skill_id != HW_GANBANTEIN ) { if( sd->special_state.no_gemstone ) - { //Make it substract 1 gem rather than skipping the cost. - if( --req.amount[i] < 1 ) - req.itemid[i] = 0; + { // All gem skills except Hocus Pocus and Ganbantein can cast for free with Mistress card [helvetica] + if( skill_id != SA_ABRACADABRA ) + req.itemid[i] = req.amount[i] = 0; + else if( --req.amount[i] < 1 ) + req.amount[i] = 1; // Hocus Pocus always use at least 1 gem } if(sc && sc->data[SC_INTOABYSS]) { if( skill_id != SA_ABRACADABRA ) req.itemid[i] = req.amount[i] = 0; else if( --req.amount[i] < 1 ) - req.amount[i] = 1; // Hocus Pocus allways use at least 1 gem + req.amount[i] = 1; // Hocus Pocus always use at least 1 gem } } if( skill_id >= HT_SKIDTRAP && skill_id <= HT_TALKIEBOX && pc->checkskill(sd, RA_RESEARCHTRAP) > 0){ - int16 itIndex; - if( (itIndex = pc->search_inventory(sd,req.itemid[i])) < 0 || ( itIndex >= 0 && sd->status.inventory[itIndex].amount < req.amount[i] ) ){ + int16 item_index; + if ((item_index = pc->search_inventory(sd,req.itemid[i])) == INDEX_NOT_FOUND + || sd->status.inventory[item_index].amount < req.amount[i] + ) { req.itemid[i] = ITEMID_TRAP_ALLOY; req.amount[i] = 1; } @@ -13579,10 +14043,26 @@ struct skill_condition skill_get_requirement(struct map_session_data* sd, uint16 case SO_FIRE_INSIGNIA: case SO_WIND_INSIGNIA: case SO_EARTH_INSIGNIA: - req.itemid[skill_lv-1] = skill_db[idx].itemid[skill_lv-1]; - req.amount[skill_lv-1] = skill_db[idx].amount[skill_lv-1]; + req.itemid[skill_lv-1] = skill->db[idx].itemid[skill_lv-1]; + req.amount[skill_lv-1] = skill->db[idx].amount[skill_lv-1]; break; } + if (skill_id == NC_REPAIR) { + switch(skill_lv) { + case 1: + case 2: + req.itemid[1] = ITEMID_REPAIR_A; + break; + case 3: + case 4: + req.itemid[1] = ITEMID_REPAIR_B; + break; + case 5: + req.itemid[1] = ITEMID_REPAIR_C; + break; + } + req.amount[1] = 1; + } // Check for cost reductions due to skills & SCs switch(skill_id) { @@ -13656,10 +14136,14 @@ struct skill_condition skill_get_requirement(struct map_session_data* sd, uint16 case SO_SUMMON_AQUA: case SO_SUMMON_VENTUS: case SO_SUMMON_TERA: - req.sp -= req.sp * (5 + 5 * pc->checkskill(sd,SO_EL_SYMPATHY)) / 100; + { + int spirit_sympathy = pc->checkskill(sd,SO_EL_SYMPATHY); + if (spirit_sympathy) + req.sp -= req.sp * (5 + 5 * spirit_sympathy) / 100; + } break; case SO_PSYCHIC_WAVE: - if( sc && sc->data[SC_BLAST_OPTION] ) + if( sc && (sc->data[SC_HEATER_OPTION] || sc->data[SC_COOLER_OPTION] || sc->data[SC_BLAST_OPTION] || sc->data[SC_CURSED_SOIL_OPTION] )) req.sp += req.sp * 150 / 100; break; } @@ -13720,9 +14204,8 @@ int skill_castfix (struct block_list *bl, uint16 skill_id, uint16 skill_lv) { /*========================================== * Does cast-time reductions based on sc data. *------------------------------------------*/ -int skill_castfix_sc (struct block_list *bl, int time) -{ - struct status_change *sc = status_get_sc(bl); +int skill_castfix_sc (struct block_list *bl, int time) { + struct status_change *sc = status->get_sc(bl); if( time < 0 ) return 0; @@ -13733,8 +14216,8 @@ int skill_castfix_sc (struct block_list *bl, int time) if (sc && sc->count) { if (sc->data[SC_SLOWCAST]) time += time * sc->data[SC_SLOWCAST]->val2 / 100; - if (sc->data[SC_NEEDLE_OF_PARALYZE]) - time += sc->data[SC_NEEDLE_OF_PARALYZE]->val3; + if (sc->data[SC_NEEDLE_OF_PARALYZE]) + time += sc->data[SC_NEEDLE_OF_PARALYZE]->val3; if (sc->data[SC_SUFFRAGIUM]) { time -= time * sc->data[SC_SUFFRAGIUM]->val2 / 100; status_change_end(bl, SC_SUFFRAGIUM, INVALID_TIMER); @@ -13749,15 +14232,14 @@ int skill_castfix_sc (struct block_list *bl, int time) if (sc->data[SC_IZAYOI]) time -= time * 50 / 100; } - time = max(time, 0); + time = max(time, 0); -// ShowInfo("Castime castfix_sc = %d\n",time); + //ShowInfo("Castime castfix_sc = %d\n",time); return time; } +int skill_vfcastfix(struct block_list *bl, double time, uint16 skill_id, uint16 skill_lv) { #ifdef RENEWAL_CAST -int skill_vfcastfix (struct block_list *bl, double time, uint16 skill_id, uint16 skill_lv) -{ - struct status_change *sc = status_get_sc(bl); + struct status_change *sc = status->get_sc(bl); struct map_session_data *sd = BL_CAST(BL_PC,bl); int fixed = skill->get_fixed_cast(skill_id, skill_lv), fixcast_r = 0, varcast_r = 0, i = 0; @@ -13777,9 +14259,9 @@ int skill_vfcastfix (struct block_list *bl, double time, uint16 skill_id, uint16 if( sd->bonus.varcastrate < 0 ) VARCAST_REDUCTION(sd->bonus.varcastrate); if( sd->bonus.add_varcast != 0 ) // bonus bVariableCast - time += sd->bonus.add_varcast; + time += sd->bonus.add_varcast; if( sd->bonus.add_fixcast != 0 ) // bonus bFixedCast - fixed += sd->bonus.add_fixcast; + fixed += sd->bonus.add_fixcast; for (i = 0; i < ARRAYLENGTH(sd->skillfixcast) && sd->skillfixcast[i].id; i++) if (sd->skillfixcast[i].id == skill_id){ // bonus2 bSkillFixedCast fixed += sd->skillfixcast[i].val; @@ -13806,8 +14288,6 @@ int skill_vfcastfix (struct block_list *bl, double time, uint16 skill_id, uint16 if (sc && sc->count && !(skill->get_castnodex(skill_id, skill_lv)&2) ) { // All variable cast additive bonuses must come first - if (sc->data[SC_MAGICPOWER] ) - time += 700; if (sc->data[SC_SLOWCAST]) VARCAST_REDUCTION(-sc->data[SC_SLOWCAST]->val2); if (sc->data[SC_FROSTMISTY]) @@ -13848,13 +14328,15 @@ int skill_vfcastfix (struct block_list *bl, double time, uint16 skill_id, uint16 // Fixed cast reduction bonuses if( sc->data[SC__LAZINESS] ) fixcast_r = max(fixcast_r, sc->data[SC__LAZINESS]->val2); + if( sc->data[SC_DANCE_WITH_WUG]) + fixcast_r = max(fixcast_r, sc->data[SC_DANCE_WITH_WUG]->val4); if( sc->data[SC_SECRAMENT] ) fixcast_r = max(fixcast_r, sc->data[SC_SECRAMENT]->val2); - if( sd && ( skill_lv = pc->checkskill(sd, WL_RADIUS) ) && (skill_id >= WL_WHITEIMPRISON && skill_id < WL_FREEZE_SP) ) - fixcast_r = max(fixcast_r, (status_get_int(bl) + status_get_lv(bl)) / 15 + skill_lv * 5); // [{(Caster?s INT / 15) + (Caster?s Base Level / 15) + (Radius Skill Level x 5)}] % + if( sd && ( skill_lv = pc->checkskill(sd, WL_RADIUS) ) && (skill_id >= WL_WHITEIMPRISON && skill_id < WL_FREEZE_SP) ) + fixcast_r = max(fixcast_r, (status_get_int(bl) + status->get_lv(bl)) / 15 + skill_lv * 5); // [{(Caster?s INT / 15) + (Caster?s Base Level / 15) + (Radius Skill Level x 5)}] % // Fixed cast non percentage bonuses if( sc->data[SC_MANDRAGORA] ) - fixed += sc->data[SC_MANDRAGORA]->val1 * 1000 / 2; + fixed += sc->data[SC_MANDRAGORA]->val1 * 500; if( sc->data[SC_IZAYOI] ) fixed = 0; if( sc->data[SC_GUST_OPTION] || sc->data[SC_BLAST_OPTION] || sc->data[SC_WILD_STORM_OPTION] ) @@ -13864,6 +14346,12 @@ int skill_vfcastfix (struct block_list *bl, double time, uint16 skill_id, uint16 if( sd && !(skill->get_castnodex(skill_id, skill_lv)&4) ){ VARCAST_REDUCTION( max(sd->bonus.varcastrate, 0) + max(i, 0) ); fixcast_r = max(fixcast_r, sd->bonus.fixcastrate) + min(sd->bonus.fixcastrate,0); + for( i = 0; i < ARRAYLENGTH(sd->skillcast) && sd->skillcast[i].id; i++ ) + if( sd->skillcast[i].id == skill_id ){ // bonus2 bVariableCastrate + if( (i=sd->skillcast[i].val) > 0) + VARCAST_REDUCTION(i); + break; + } } if( varcast_r < 0 ) // now compute overall factors @@ -13872,20 +14360,18 @@ int skill_vfcastfix (struct block_list *bl, double time, uint16 skill_id, uint16 time = (1 - sqrt( ((float)(status_get_dex(bl)*2 + status_get_int(bl)) / battle_config.vcast_stat_scale) )) * time; // underflow checking/capping time = max(time, 0) + (1 - (float)min(fixcast_r, 100) / 100) * max(fixed,0); - +#endif return (int)time; } -#endif /*========================================== * Does delay reductions based on dex/agi, sc data, item bonuses, ... *------------------------------------------*/ -int skill_delay_fix (struct block_list *bl, uint16 skill_id, uint16 skill_lv) -{ +int skill_delay_fix (struct block_list *bl, uint16 skill_id, uint16 skill_lv) { int delaynodex = skill->get_delaynodex(skill_id, skill_lv); int time = skill->get_delay(skill_id, skill_lv); struct map_session_data *sd; - struct status_change *sc = status_get_sc(bl); + struct status_change *sc = status->get_sc(bl); nullpo_ret(bl); sd = BL_CAST(BL_PC, bl); @@ -13940,7 +14426,7 @@ int skill_delay_fix (struct block_list *bl, uint16 skill_id, uint16 skill_lv) time /= 2; break; case AS_SONICBLOW: - if (!map_flag_gvg(bl->m) && !map[bl->m].flag.battleground && sc->data[SC_SOULLINK]->val2 == SL_ASSASIN) + if (!map_flag_gvg2(bl->m) && !map->list[bl->m].flag.battleground && sc->data[SC_SOULLINK]->val2 == SL_ASSASIN) time /= 2; break; } @@ -14092,22 +14578,21 @@ void skill_brandishspear_dir (struct square* tc, uint8 dir, int are) { } } -void skill_brandishspear(struct block_list* src, struct block_list* bl, uint16 skill_id, uint16 skill_lv, unsigned int tick, int flag) -{ +void skill_brandishspear(struct block_list* src, struct block_list* bl, uint16 skill_id, uint16 skill_lv, int64 tick, int flag) { int c,n=4; - uint8 dir = iMap->calc_dir(src,bl->x,bl->y); + uint8 dir = map->calc_dir(src,bl->x,bl->y); struct square tc; int x=bl->x,y=bl->y; skill->brandishspear_first(&tc,dir,x,y); skill->brandishspear_dir(&tc,dir,4); - skill_area_temp[1] = bl->id; + skill->area_temp[1] = bl->id; if(skill_lv > 9){ for(c=1;c<4;c++){ - iMap->foreachincell(skill->area_sub, - bl->m,tc.val1[c],tc.val2[c],BL_CHAR, - src,skill_id,skill_lv,tick, flag|BCT_ENEMY|n, - skill->castend_damage_id); + map->foreachincell(skill->area_sub, + bl->m,tc.val1[c],tc.val2[c],BL_CHAR, + src,skill_id,skill_lv,tick, flag|BCT_ENEMY|n, + skill->castend_damage_id); } } if(skill_lv > 6){ @@ -14120,19 +14605,19 @@ void skill_brandishspear(struct block_list* src, struct block_list* bl, uint16 s if(skill_lv > 3){ for(c=0;c<5;c++){ - iMap->foreachincell(skill->area_sub, - bl->m,tc.val1[c],tc.val2[c],BL_CHAR, - src,skill_id,skill_lv,tick, flag|BCT_ENEMY|n, - skill->castend_damage_id); - if(skill_lv > 6 && n==3 && c==4){ - skill_brandishspear_dir(&tc,dir,-1); + map->foreachincell(skill->area_sub, + bl->m,tc.val1[c],tc.val2[c],BL_CHAR, + src,skill_id,skill_lv,tick, flag|BCT_ENEMY|n, + skill->castend_damage_id); + if(skill_lv > 6 && n==3 && c==4) { + skill->brandishspear_dir(&tc,dir,-1); n--;c=-1; } } } for(c=0;c<10;c++){ if(c==0||c==5) skill->brandishspear_dir(&tc,dir,-1); - iMap->foreachincell(skill->area_sub, + map->foreachincell(skill->area_sub, bl->m,tc.val1[c%5],tc.val2[c%5],BL_CHAR, src,skill_id,skill_lv,tick, flag|BCT_ENEMY|1, skill->castend_damage_id); @@ -14144,13 +14629,18 @@ void skill_brandishspear(struct block_list* src, struct block_list* bl, uint16 s *------------------------------------------*/ void skill_repairweapon (struct map_session_data *sd, int idx) { int material; - int materials[4] = { 1002, 998, 999, 756 }; + int materials[4] = { + ITEMID_IRON_ORE, + ITEMID_IRON, + ITEMID_STEEL, + ITEMID_ORIDECON_STONE, + }; struct item *item; struct map_session_data *target_sd; nullpo_retv(sd); - if ( !( target_sd = iMap->id2sd(sd->menuskill_val) ) ) //Failed.... + if ( !( target_sd = map->id2sd(sd->menuskill_val) ) ) //Failed.... return; if( idx == 0xFFFF ) // No item selected ('Cancel' clicked) @@ -14168,10 +14658,10 @@ void skill_repairweapon (struct map_session_data *sd, int idx) { } if ( target_sd->inventory_data[idx]->type == IT_WEAPON ) - material = materials [ target_sd->inventory_data[idx]->wlv - 1 ]; // Lv1/2/3/4 weapons consume 1 Iron Ore/Iron/Steel/Rough Oridecon + material = materials[ target_sd->inventory_data[idx]->wlv - 1 ]; // Lv1/2/3/4 weapons consume 1 Iron Ore/Iron/Steel/Rough Oridecon else - material = materials [2]; // Armors consume 1 Steel - if ( pc->search_inventory(sd,material) < 0 ) { + material = materials[2]; // Armors consume 1 Steel + if (pc->search_inventory(sd,material) == INDEX_NOT_FOUND) { clif->skill_fail(sd,sd->menuskill_id,USESKILL_FAIL_LEVEL,0); return; } @@ -14218,7 +14708,13 @@ void skill_weaponrefine (struct map_session_data *sd, int idx) if (idx >= 0 && idx < MAX_INVENTORY) { int i = 0, ep = 0, per; - int material[5] = { 0, 1010, 1011, 984, 984 }; + int material[5] = { + 0, + ITEMID_PHRACON, + ITEMID_EMVERETARCON, + ITEMID_ORIDECON, + ITEMID_ORIDECON, + }; struct item *item; struct item_data *ditem = sd->inventory_data[idx]; item = &sd->status.inventory[idx]; @@ -14233,12 +14729,12 @@ void skill_weaponrefine (struct map_session_data *sd, int idx) clif->upgrademessage(sd->fd, 2, item->nameid); return; } - if( (i = pc->search_inventory(sd, material [ditem->wlv])) < 0 ){ - clif->upgrademessage(sd->fd, 3, material [ditem->wlv]); + if ((i = pc->search_inventory(sd, material[ditem->wlv])) == INDEX_NOT_FOUND) { + clif->upgrademessage(sd->fd, 3, material[ditem->wlv]); return; } - per = status_get_refine_chance(ditem->wlv, (int)item->refine) * 10; + per = status->get_refine_chance(ditem->wlv, (int)item->refine) * 10; // Aegis leaked formula. [malufett] if( sd->status.class_ == JOB_MECHANIC_T ) @@ -14329,7 +14825,7 @@ int skill_autospell (struct map_session_data *sd, uint16 skill_id) if(maxlv > lv) maxlv = lv; - sc_start4(&sd->bl,SC_AUTOSPELL,100,skill_lv,skill_id,maxlv,0, + sc_start4(&sd->bl,&sd->bl,SC_AUTOSPELL,100,skill_lv,skill_id,maxlv,0, skill->get_time(SA_AUTOSPELL,skill_lv)); return 0; } @@ -14368,8 +14864,8 @@ int skill_sit_in (struct block_list *bl, va_list ap) { if(type&2 && (pc->checkskill(sd,TK_HPTIME) > 0 || pc->checkskill(sd,TK_SPTIME) > 0 )) { sd->state.rest=1; - status_calc_regen(bl, &sd->battle_status, &sd->regen); - status_calc_regen_rate(bl, &sd->regen, &sd->sc); + status->calc_regen(bl, &sd->battle_status, &sd->regen); + status->calc_regen_rate(bl, &sd->regen, &sd->sc); } return 0; @@ -14383,8 +14879,8 @@ int skill_sit_out (struct block_list *bl, va_list ap) { sd->state.gangsterparadise=0; if(sd->state.rest && type&2) { sd->state.rest=0; - status_calc_regen(bl, &sd->battle_status, &sd->regen); - status_calc_regen_rate(bl, &sd->regen, &sd->sc); + status->calc_regen(bl, &sd->battle_status, &sd->regen); + status->calc_regen_rate(bl, &sd->regen, &sd->sc); } return 0; } @@ -14418,11 +14914,11 @@ int skill_sit (struct map_session_data *sd, int type) if (!flag) return 0; if(type) { - if (iMap->foreachinrange(skill->sit_count,&sd->bl, range, BL_PC, flag) > 1) - iMap->foreachinrange(skill->sit_in,&sd->bl, range, BL_PC, flag); + if (map->foreachinrange(skill->sit_count,&sd->bl, range, BL_PC, flag) > 1) + map->foreachinrange(skill->sit_in,&sd->bl, range, BL_PC, flag); } else { - if (iMap->foreachinrange(skill->sit_count,&sd->bl, range, BL_PC, flag) < 2) - iMap->foreachinrange(skill->sit_out,&sd->bl, range, BL_PC, flag); + if (map->foreachinrange(skill->sit_count,&sd->bl, range, BL_PC, flag) < 2) + map->foreachinrange(skill->sit_out,&sd->bl, range, BL_PC, flag); } return 0; } @@ -14430,10 +14926,10 @@ int skill_sit (struct map_session_data *sd, int type) /*========================================== * *------------------------------------------*/ -int skill_frostjoke_scream (struct block_list *bl, va_list ap) { +int skill_frostjoke_scream(struct block_list *bl, va_list ap) { struct block_list *src; uint16 skill_id,skill_lv; - unsigned int tick; + int64 tick; nullpo_ret(bl); nullpo_ret(src=va_arg(ap,struct block_list*)); @@ -14441,9 +14937,9 @@ int skill_frostjoke_scream (struct block_list *bl, va_list ap) { skill_id=va_arg(ap,int); skill_lv=va_arg(ap,int); if(!skill_lv) return 0; - tick=va_arg(ap,unsigned int); + tick=va_arg(ap,int64); - if (src == bl || status_isdead(bl)) + if (src == bl || status->isdead(bl)) return 0; if (bl->type == BL_PC) { struct map_session_data *sd = (struct map_session_data *)bl; @@ -14468,36 +14964,35 @@ void skill_unitsetmapcell (struct skill_unit *src, uint16 skill_id, uint16 skill for( y = src->bl.y - range; y <= src->bl.y + range; ++y ) for( x = src->bl.x - range; x <= src->bl.x + range; ++x ) - map[src->bl.m].setcell(src->bl.m, x, y, cell, flag); + map->list[src->bl.m].setcell(src->bl.m, x, y, cell, flag); } /*========================================== * *------------------------------------------*/ -int skill_attack_area (struct block_list *bl, va_list ap) -{ +int skill_attack_area(struct block_list *bl, va_list ap) { struct block_list *src,*dsrc; int atk_type,skill_id,skill_lv,flag,type; - unsigned int tick; + int64 tick; - if(status_isdead(bl)) + if(status->isdead(bl)) return 0; atk_type = va_arg(ap,int); - src=va_arg(ap,struct block_list*); - dsrc=va_arg(ap,struct block_list*); - skill_id=va_arg(ap,int); - skill_lv=va_arg(ap,int); - tick=va_arg(ap,unsigned int); - flag=va_arg(ap,int); - type=va_arg(ap,int); + src = va_arg(ap,struct block_list*); + dsrc = va_arg(ap,struct block_list*); + skill_id = va_arg(ap,int); + skill_lv = va_arg(ap,int); + tick = va_arg(ap,int64); + flag = va_arg(ap,int); + type = va_arg(ap,int); - if (skill_area_temp[1] == bl->id) //This is the target of the skill, do a full attack and skip target checks. + if (skill->area_temp[1] == bl->id) //This is the target of the skill, do a full attack and skip target checks. return skill->attack(atk_type,src,dsrc,bl,skill_id,skill_lv,tick,flag); - if(battle->check_target(dsrc,bl,type) <= 0 || - !status_check_skilluse(NULL, bl, skill_id, 2)) + if( battle->check_target(dsrc,bl,type) <= 0 + || !status->check_skilluse(NULL, bl, skill_id, 2)) return 0; @@ -14519,7 +15014,7 @@ int skill_attack_area (struct block_list *bl, va_list ap) *------------------------------------------*/ int skill_clear_group (struct block_list *bl, int flag) { - struct unit_data *ud = unit_bl2ud(bl); + struct unit_data *ud = unit->bl2ud(bl); struct skill_unit_group *group[MAX_SKILLUNITGROUP]; int i, count=0; @@ -14538,14 +15033,14 @@ int skill_clear_group (struct block_list *bl, int flag) if (flag&1) group[count++]= ud->skillunit[i]; break; + case SO_CLOUD_KILL: + if( flag&4 ) + group[count++]= ud->skillunit[i]; + break; case SO_WARMER: if( flag&8 ) group[count++]= ud->skillunit[i]; break; - case SC_BLOODYLUST: - if (flag & 32) - group[count++] = ud->skillunit[i]; - break; default: if (flag&2 && skill->get_inf2(ud->skillunit[i]->skill_id)&INF2_TRAP) group[count++]= ud->skillunit[i]; @@ -14562,7 +15057,7 @@ int skill_clear_group (struct block_list *bl, int flag) * Returns the first element field found [Skotlex] *------------------------------------------*/ struct skill_unit_group *skill_locate_element_field(struct block_list *bl) { - struct unit_data *ud = unit_bl2ud(bl); + struct unit_data *ud = unit->bl2ud(bl); int i; nullpo_ret(bl); if (!ud) return NULL; @@ -14574,8 +15069,8 @@ struct skill_unit_group *skill_locate_element_field(struct block_list *bl) { case SA_VIOLENTGALE: case SA_LANDPROTECTOR: case NJ_SUITON: + case SO_CLOUD_KILL: case SO_WARMER: - case SC_BLOODYLUST: return ud->skillunit[i]; } } @@ -14584,16 +15079,16 @@ struct skill_unit_group *skill_locate_element_field(struct block_list *bl) { // for graffiti cleaner [Valaris] int skill_graffitiremover (struct block_list *bl, va_list ap) { - struct skill_unit *unit=NULL; + struct skill_unit *su=NULL; nullpo_ret(bl); nullpo_ret(ap); - if(bl->type!=BL_SKILL || (unit=(struct skill_unit *)bl) == NULL) + if(bl->type!=BL_SKILL || (su=(struct skill_unit *)bl) == NULL) return 0; - if((unit->group) && (unit->group->unit_id == UNT_GRAFFITI)) - skill->delunit(unit); + if((su->group) && (su->group->unit_id == UNT_GRAFFITI)) + skill->delunit(su); return 0; } @@ -14612,9 +15107,8 @@ int skill_greed (struct block_list *bl, va_list ap) { return 0; } //For Ranger's Detonator [Jobbie/3CeAM] -int skill_detonator(struct block_list *bl, va_list ap) -{ - struct skill_unit *unit=NULL; +int skill_detonator(struct block_list *bl, va_list ap) { + struct skill_unit *su=NULL; struct block_list *src; int unit_id; @@ -14622,14 +15116,14 @@ int skill_detonator(struct block_list *bl, va_list ap) nullpo_ret(ap); src = va_arg(ap,struct block_list *); - if( bl->type != BL_SKILL || (unit = (struct skill_unit *)bl) == NULL || !unit->group ) + if( bl->type != BL_SKILL || (su = (struct skill_unit *)bl) == NULL || !su->group ) return 0; - if( unit->group->src_id != src->id ) + if( su->group->src_id != src->id ) return 0; - unit_id = unit->group->unit_id; - switch( unit_id ) - { //List of Hunter and Ranger Traps that can be detonate. + unit_id = su->group->unit_id; + switch( unit_id ) { + //List of Hunter and Ranger Traps that can be detonate. case UNT_BLASTMINE: case UNT_SANDMAN: case UNT_CLAYMORETRAP: @@ -14637,16 +15131,23 @@ int skill_detonator(struct block_list *bl, va_list ap) case UNT_CLUSTERBOMB: case UNT_FIRINGTRAP: case UNT_ICEBOUNDTRAP: - if( unit_id == UNT_TALKIEBOX ) { - clif->talkiebox(bl,unit->group->valstr); - unit->group->val2 = -1; - } else - iMap->foreachinrange(skill->trap_splash,bl,skill->get_splash(unit->group->skill_id,unit->group->skill_lv),unit->group->bl_flag,bl,unit->group->tick); - - clif->changetraplook(bl,unit_id == UNT_FIRINGTRAP ? UNT_DUMMYSKILL : UNT_USED_TRAPS); - unit->group->unit_id = UNT_USED_TRAPS; - unit->group->limit = DIFF_TICK(iTimer->gettick(),unit->group->tick) + - (unit_id == UNT_TALKIEBOX ? 5000 : (unit_id == UNT_CLUSTERBOMB || unit_id == UNT_ICEBOUNDTRAP? 2500 : 1500) ); + switch(unit_id) { + case UNT_TALKIEBOX: + clif->talkiebox(bl,su->group->valstr); + su->group->val2 = -1; + break; + case UNT_CLAYMORETRAP: + case UNT_FIRINGTRAP: + case UNT_ICEBOUNDTRAP: + map->foreachinrange(skill->trap_splash,bl,skill->get_splash(su->group->skill_id,su->group->skill_lv),su->group->bl_flag|BL_SKILL|~BCT_SELF,bl,su->group->tick); + break; + default: + map->foreachinrange(skill->trap_splash,bl,skill->get_splash(su->group->skill_id,su->group->skill_lv),su->group->bl_flag,bl,su->group->tick); + } + clif->changetraplook(bl, UNT_USED_TRAPS); + su->group->limit = DIFF_TICK32(timer->gettick(),su->group->tick) + + (unit_id == UNT_TALKIEBOX ? 5000 : (unit_id == UNT_CLUSTERBOMB || unit_id == UNT_ICEBOUNDTRAP? 2500 : (unit_id == UNT_FIRINGTRAP ? 0 : 1500)) ); + su->group->unit_id = UNT_USED_TRAPS; break; } return 0; @@ -14658,31 +15159,35 @@ int skill_detonator(struct block_list *bl, va_list ap) int skill_cell_overlap(struct block_list *bl, va_list ap) { uint16 skill_id; int *alive; - struct skill_unit *unit; + struct skill_unit *su; skill_id = va_arg(ap,int); alive = va_arg(ap,int *); - unit = (struct skill_unit *)bl; + su = (struct skill_unit *)bl; - if (unit == NULL || unit->group == NULL || (*alive) == 0) + if( su == NULL || su->group == NULL || (*alive) == 0 ) return 0; - + + if( su->group->state.guildaura ) /* guild auras are not canceled! */ + return 0; + switch (skill_id) { case SA_LANDPROTECTOR: - if( unit->group->skill_id == SA_LANDPROTECTOR ) {//Check for offensive Land Protector to delete both. [Skotlex] + if( su->group->skill_id == SA_LANDPROTECTOR ) {//Check for offensive Land Protector to delete both. [Skotlex] (*alive) = 0; - skill->delunit(unit); + skill->delunit(su); return 1; } - if( !(skill->get_inf2(unit->group->skill_id)&(INF2_SONG_DANCE|INF2_TRAP)) || unit->group->skill_id == WZ_FIREPILLAR ) { //It deletes everything except songs/dances and traps - skill->delunit(unit); + if( !(skill->get_inf2(su->group->skill_id)&(INF2_SONG_DANCE|INF2_TRAP)) || su->group->skill_id == WZ_FIREPILLAR || su->group->skill_id == GN_HELLS_PLANT) { //It deletes everything except songs/dances and traps + skill->delunit(su); return 1; } break; case HW_GANBANTEIN: case LG_EARTHDRIVE: - if( !(unit->group->state.song_dance&0x1) ) {// Don't touch song/dance. - skill->delunit(unit); + case GN_CRAZYWEED_ATK: + if( !(su->group->state.song_dance&0x1) ) {// Don't touch song/dance. + skill->delunit(su); return 1; } break; @@ -14692,14 +15197,13 @@ int skill_cell_overlap(struct block_list *bl, va_list ap) { // The official implementation makes them fail to appear when casted on top of ANYTHING // but I wonder if they didn't actually meant to fail when casted on top of each other? // hence, I leave the alternate implementation here, commented. [Skotlex] - if (unit->range <= 0) - { + if (su->range <= 0) { (*alive) = 0; return 1; } /* - switch (unit->group->skill_id) - { //These cannot override each other. + switch (su->group->skill_id) { + //These cannot override each other. case SA_VOLCANO: case SA_DELUGE: case SA_VIOLENTGALE: @@ -14709,7 +15213,7 @@ int skill_cell_overlap(struct block_list *bl, va_list ap) { */ break; case PF_FOGWALL: - switch(unit->group->skill_id) { + switch(su->group->skill_id) { case SA_VOLCANO: //Can't be placed on top of these case SA_VIOLENTGALE: (*alive) = 0; @@ -14722,33 +15226,16 @@ int skill_cell_overlap(struct block_list *bl, va_list ap) { } break; case HP_BASILICA: - if (unit->group->skill_id == HP_BASILICA) - { //Basilica can't be placed on top of itself to avoid map-cell stacking problems. [Skotlex] + if (su->group->skill_id == HP_BASILICA) { + //Basilica can't be placed on top of itself to avoid map-cell stacking problems. [Skotlex] (*alive) = 0; return 1; } break; - case GN_CRAZYWEED_ATK: - switch(unit->group->unit_id){ //TODO: look for other ground skills that are affected. - case UNT_WALLOFTHORN: - case UNT_THORNS_TRAP: - case UNT_BLOODYLUST: - case UNT_CHAOSPANIC: - case UNT_MAELSTROM: - case UNT_FIREPILLAR_ACTIVE: - case UNT_LANDPROTECTOR: - case UNT_VOLCANO: - case UNT_DELUGE: - case UNT_VIOLENTGALE: - case UNT_SAFETYWALL: - case UNT_PNEUMA: - skill->delunit(unit); - return 1; - } - break; } - if (unit->group->skill_id == SA_LANDPROTECTOR && !(skill->get_inf2(skill_id)&(INF2_SONG_DANCE|INF2_TRAP))) { //It deletes everything except songs/dances/traps + if (su->group->skill_id == SA_LANDPROTECTOR && !(skill->get_inf2(skill_id)&(INF2_SONG_DANCE|INF2_TRAP))) { + //It deletes everything except songs/dances/traps (*alive) = 0; return 1; } @@ -14762,7 +15249,7 @@ int skill_cell_overlap(struct block_list *bl, va_list ap) { int skill_chastle_mob_changetarget(struct block_list *bl,va_list ap) { struct mob_data* md; - struct unit_data*ud = unit_bl2ud(bl); + struct unit_data*ud = unit->bl2ud(bl); struct block_list *from_bl; struct block_list *to_bl; md = (struct mob_data*)bl; @@ -14780,21 +15267,21 @@ int skill_chastle_mob_changetarget(struct block_list *bl,va_list ap) /*========================================== * *------------------------------------------*/ -int skill_trap_splash (struct block_list *bl, va_list ap) { +int skill_trap_splash(struct block_list *bl, va_list ap) { struct block_list *src; - int tick; - struct skill_unit *unit; + int64 tick; + struct skill_unit *src_su; struct skill_unit_group *sg; struct block_list *ss; src = va_arg(ap,struct block_list *); - unit = (struct skill_unit *)src; - tick = va_arg(ap,int); + src_su = (struct skill_unit *)src; + tick = va_arg(ap,int64); - if( !unit->alive || bl->prev == NULL ) + if( !src_su->alive || bl->prev == NULL ) return 0; - nullpo_ret(sg = unit->group); - nullpo_ret(ss = iMap->id2bl(sg->src_id)); + nullpo_ret(sg = src_su->group); + nullpo_ret(ss = map->id2bl(sg->src_id)); if(battle->check_target(src,bl,sg->target_flag) <= 0) return 0; @@ -14807,19 +15294,19 @@ int skill_trap_splash (struct block_list *bl, va_list ap) { break; case UNT_GROUNDDRIFT_WIND: if(skill->attack(BF_WEAPON,ss,src,bl,sg->skill_id,sg->skill_lv,tick,sg->val1)) - sc_start(bl,SC_STUN,5,sg->skill_lv,skill->get_time2(sg->skill_id, sg->skill_lv)); + sc_start(src,bl,SC_STUN,5,sg->skill_lv,skill->get_time2(sg->skill_id, sg->skill_lv)); break; case UNT_GROUNDDRIFT_DARK: if(skill->attack(BF_WEAPON,ss,src,bl,sg->skill_id,sg->skill_lv,tick,sg->val1)) - sc_start(bl,SC_BLIND,5,sg->skill_lv,skill->get_time2(sg->skill_id, sg->skill_lv)); + sc_start(src,bl,SC_BLIND,5,sg->skill_lv,skill->get_time2(sg->skill_id, sg->skill_lv)); break; case UNT_GROUNDDRIFT_POISON: if(skill->attack(BF_WEAPON,ss,src,bl,sg->skill_id,sg->skill_lv,tick,sg->val1)) - sc_start(bl,SC_POISON,5,sg->skill_lv,skill->get_time2(sg->skill_id, sg->skill_lv)); + sc_start(src,bl,SC_POISON,5,sg->skill_lv,skill->get_time2(sg->skill_id, sg->skill_lv)); break; case UNT_GROUNDDRIFT_WATER: if(skill->attack(BF_WEAPON,ss,src,bl,sg->skill_id,sg->skill_lv,tick,sg->val1)) - sc_start(bl,SC_FREEZE,5,sg->skill_lv,skill->get_time2(sg->skill_id, sg->skill_lv)); + sc_start(src,bl,SC_FREEZE,5,sg->skill_lv,skill->get_time2(sg->skill_id, sg->skill_lv)); break; case UNT_GROUNDDRIFT_FIRE: if(skill->attack(BF_WEAPON,ss,src,bl,sg->skill_id,sg->skill_lv,tick,sg->val1)) @@ -14828,23 +15315,51 @@ int skill_trap_splash (struct block_list *bl, va_list ap) { case UNT_ELECTRICSHOCKER: clif->skill_damage(src,bl,tick,0,0,-30000,1,sg->skill_id,sg->skill_lv,5); break; - case UNT_FIRINGTRAP: - case UNT_ICEBOUNDTRAP: - case UNT_CLUSTERBOMB: - if( ss != bl ) - skill->attack(BF_MISC,ss,src,bl,sg->skill_id,sg->skill_lv,tick,sg->val1|SD_LEVEL); - break; case UNT_MAGENTATRAP: case UNT_COBALTTRAP: case UNT_MAIZETRAP: case UNT_VERDURETRAP: if( bl->type != BL_PC && !is_boss(bl) ) - sc_start2(bl,SC_ARMOR_PROPERTY,100,sg->skill_lv,skill->get_ele(sg->skill_id,sg->skill_lv),skill->get_time2(sg->skill_id,sg->skill_lv)); + sc_start2(ss,bl,SC_ARMOR_PROPERTY,100,sg->skill_lv,skill->get_ele(sg->skill_id,sg->skill_lv),skill->get_time2(sg->skill_id,sg->skill_lv)); break; case UNT_REVERBERATION: - skill->addtimerskill(ss,tick+50,bl->id,0,0,WM_REVERBERATION_MELEE,sg->skill_lv,BF_WEAPON,0); // for proper skill delay animation when use with Dominion Impulse - skill->addtimerskill(ss,tick+250,bl->id,0,0,WM_REVERBERATION_MAGIC,sg->skill_lv,BF_MAGIC,0); + if( battle->check_target(src,bl,BCT_ENEMY) > 0 ) { + skill->attack(BF_WEAPON,ss,src,bl,WM_REVERBERATION_MELEE,sg->skill_lv,tick,0); + skill->addtimerskill(ss,tick+200,bl->id,0,0,WM_REVERBERATION_MAGIC,sg->skill_lv,BF_MAGIC,SD_LEVEL); + } break; + case UNT_FIRINGTRAP: + case UNT_ICEBOUNDTRAP: + if( src->id == bl->id ) break; + if( bl->type == BL_SKILL ){ + struct skill_unit *su = (struct skill_unit *)bl; + if( su->group->unit_id == UNT_USED_TRAPS ) + break; + } + case UNT_CLUSTERBOMB: + if( ss != bl ) + skill->attack(BF_MISC,ss,src,bl,sg->skill_id,sg->skill_lv,tick,sg->val1|SD_LEVEL); + break; + case UNT_CLAYMORETRAP: + if( src->id == bl->id ) break; + if( bl->type == BL_SKILL ){ + struct skill_unit *su = (struct skill_unit *)bl; + switch( su->group->unit_id ){ + case UNT_CLAYMORETRAP: + case UNT_LANDMINE: + case UNT_BLASTMINE: + case UNT_SHOCKWAVE: + case UNT_SANDMAN: + case UNT_FLASHER: + case UNT_FREEZINGTRAP: + case UNT_FIRINGTRAP: + case UNT_ICEBOUNDTRAP: + clif->changetraplook(bl, UNT_USED_TRAPS); + su->group->limit = DIFF_TICK32(timer->gettick(),su->group->tick) + 1500; + su->group->unit_id = UNT_USED_TRAPS; + } + break; + } default: skill->attack(skill->get_type(sg->skill_id),ss,src,bl,sg->skill_id,sg->skill_lv,tick,0); break; @@ -14855,13 +15370,12 @@ int skill_trap_splash (struct block_list *bl, va_list ap) { /*========================================== * *------------------------------------------*/ -int skill_enchant_elemental_end (struct block_list *bl, int type) -{ +int skill_enchant_elemental_end (struct block_list *bl, int type) { struct status_change *sc; - const enum sc_type scs[] = { SC_ENCHANTPOISON, SC_ASPERSIO, SC_PROPERTYFIRE, SC_PROPERTYWATER, SC_PROPERTYWIND, SC_PROPERTYGROUND, SC_PROPERTYDARK, SC_PROPERTYTELEKINESIS, SC_ENCHANTARMS, SC_EXEEDBREAK }; + const enum sc_type scs[] = { SC_ENCHANTPOISON, SC_ASPERSIO, SC_PROPERTYFIRE, SC_PROPERTYWATER, SC_PROPERTYWIND, SC_PROPERTYGROUND, SC_PROPERTYDARK, SC_PROPERTYTELEKINESIS, SC_ENCHANTARMS }; int i; nullpo_ret(bl); - nullpo_ret(sc= status_get_sc(bl)); + nullpo_ret(sc = status->get_sc(bl)); if (!sc->count) return 0; @@ -14879,10 +15393,11 @@ bool skill_check_cloaking(struct block_list *bl, struct status_change_entry *sce 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. + || (bl->type != BL_PC && battle_config.monster_cloak_check_type&1) + ) { + //Check for walls. int i; - ARR_FIND( 0, 8, i, iMap->getcell(bl->m, bl->x+dx[i], bl->y+dy[i], CELL_CHKNOPASS) != 0 ); + ARR_FIND( 0, 8, i, map->getcell(bl->m, bl->x+dx[i], bl->y+dy[i], CELL_CHKNOPASS) != 0 ); if( i == 8 ) wall = false; } @@ -14905,6 +15420,36 @@ bool skill_check_cloaking(struct block_list *bl, struct status_change_entry *sce return wall; } + +/** + * Verifies if an user can use SC_CLOAKING + **/ +bool skill_can_cloak(struct map_session_data *sd) { + nullpo_retr(false, sd); + + //Avoid cloaking with no wall and low skill level. [Skotlex] + //Due to the cloaking card, we have to check the wall versus to known + //skill level rather than the used one. [Skotlex] + //if (sd && val1 < 3 && skill_check_cloaking(bl,NULL)) + if (pc->checkskill(sd, AS_CLOAKING) < 3 && !skill->check_cloaking(&sd->bl,NULL)) + return false; + + return true; +} + +/** + * Verifies if an user can still be cloaked (AS_CLOAKING) + * Is called via map->foreachinrange when any kind of wall disapears + **/ +int skill_check_cloaking_end(struct block_list *bl, va_list ap) { + TBL_PC *sd = BL_CAST(BL_PC, bl); + + if (sd && sd->sc.data[SC_CLOAKING] && !skill->can_cloak(sd)) + status_change_end(bl, SC_CLOAKING, INVALID_TIMER); + + return 0; +} + bool skill_check_camouflage(struct block_list *bl, struct status_change_entry *sce) { static int dx[] = { 0, 1, 0, -1, -1, 1, 1, -1}; @@ -14913,7 +15458,7 @@ bool skill_check_camouflage(struct block_list *bl, struct status_change_entry *s if( bl->type == BL_PC ) { //Check for walls. int i; - ARR_FIND( 0, 8, i, iMap->getcell(bl->m, bl->x+dx[i], bl->y+dy[i], CELL_CHKNOPASS) != 0 ); + ARR_FIND( 0, 8, i, map->getcell(bl->m, bl->x+dx[i], bl->y+dy[i], CELL_CHKNOPASS) != 0 ); if( i == 8 ) wall = false; } @@ -14932,126 +15477,162 @@ bool skill_check_camouflage(struct block_list *bl, struct status_change_entry *s return wall; } +bool skill_check_shadowform(struct block_list *bl, int64 damage, int hit){ + struct status_change *sc; + struct block_list *src; + + nullpo_retr(false, bl); + + sc = status->get_sc(bl); + + if( sc && sc->data[SC__SHADOWFORM] && damage ) { + src = map->id2bl(sc->data[SC__SHADOWFORM]->val2); + + if( !src || src->m != bl->m ) { + status_change_end(bl, SC__SHADOWFORM, INVALID_TIMER); + return false; + } + + if( src && (status->isdead(src) || !battle->check_target(bl,src,BCT_ENEMY)) ){ + if( src->type == BL_PC ) + ((TBL_PC*)src)->shadowform_id = 0; + status_change_end(bl, SC__SHADOWFORM, INVALID_TIMER); + return false; + } + + status->damage(bl, src, damage, 0, clif->damage(src, src, 500, 500, damage, hit, (hit > 1 ? 8 : 0), 0), 0); + + /* because damage can cancel it */ + if( sc->data[SC__SHADOWFORM] && (--sc->data[SC__SHADOWFORM]->val3) <= 0 ) { + status_change_end(bl, SC__SHADOWFORM, INVALID_TIMER); + if( src->type == BL_PC ) + ((TBL_PC*)src)->shadowform_id = 0; + } + return true; + } + return false; +} /*========================================== * *------------------------------------------*/ -struct skill_unit *skill_initunit (struct skill_unit_group *group, int idx, int x, int y, int val1, int val2) -{ - struct skill_unit *unit; +struct skill_unit *skill_initunit (struct skill_unit_group *group, int idx, int x, int y, int val1, int val2) { + struct skill_unit *su; nullpo_retr(NULL, group); nullpo_retr(NULL, group->unit); // crash-protection against poor coding - nullpo_retr(NULL, unit=&group->unit[idx]); + nullpo_retr(NULL, su=&group->unit[idx]); - if(!unit->alive) + if(!su->alive) group->alive_count++; - unit->bl.id=iMap->get_new_object_id(); - unit->bl.type=BL_SKILL; - unit->bl.m=group->map; - unit->bl.x=x; - unit->bl.y=y; - unit->group=group; - unit->alive=1; - unit->val1=val1; - unit->val2=val2; + su->bl.id=map->get_new_object_id(); + su->bl.type=BL_SKILL; + su->bl.m=group->map; + su->bl.x=x; + su->bl.y=y; + su->group=group; + su->alive=1; + su->val1=val1; + su->val2=val2; - idb_put(skillunit_db, unit->bl.id, unit); - iMap->addiddb(&unit->bl); - iMap->addblock(&unit->bl); + idb_put(skill->unit_db, su->bl.id, su); + map->addiddb(&su->bl); + map->addblock(&su->bl); // perform oninit actions switch (group->skill_id) { case WZ_ICEWALL: - iMap->setgatcell(unit->bl.m,unit->bl.x,unit->bl.y,5); - clif->changemapcell(0,unit->bl.m,unit->bl.x,unit->bl.y,5,AREA); - skill->unitsetmapcell(unit,WZ_ICEWALL,group->skill_lv,CELL_ICEWALL,true); - map[unit->bl.m].icewall_num++; + map->setgatcell(su->bl.m,su->bl.x,su->bl.y,5); + clif->changemapcell(0,su->bl.m,su->bl.x,su->bl.y,5,AREA); + skill->unitsetmapcell(su,WZ_ICEWALL,group->skill_lv,CELL_ICEWALL,true); + map->list[su->bl.m].icewall_num++; break; case SA_LANDPROTECTOR: - skill->unitsetmapcell(unit,SA_LANDPROTECTOR,group->skill_lv,CELL_LANDPROTECTOR,true); + skill->unitsetmapcell(su,SA_LANDPROTECTOR,group->skill_lv,CELL_LANDPROTECTOR,true); break; case HP_BASILICA: - skill->unitsetmapcell(unit,HP_BASILICA,group->skill_lv,CELL_BASILICA,true); - break; - case SC_MAELSTROM: - skill->unitsetmapcell(unit,SC_MAELSTROM,group->skill_lv,CELL_MAELSTROM,true); + skill->unitsetmapcell(su,HP_BASILICA,group->skill_lv,CELL_BASILICA,true); break; default: if (group->state.song_dance&0x1) //Check for dissonance. - skill->dance_overlap(unit, 1); + skill->dance_overlap(su, 1); break; } - clif->skill_setunit(unit); + clif->getareachar_skillunit(&su->bl,su,AREA); - return unit; + return su; } /*========================================== * *------------------------------------------*/ -int skill_delunit (struct skill_unit* unit) { +int skill_delunit (struct skill_unit* su) { struct skill_unit_group *group; - nullpo_ret(unit); - if( !unit->alive ) + nullpo_ret(su); + if( !su->alive ) return 0; - unit->alive=0; + su->alive=0; - nullpo_ret(group=unit->group); + nullpo_ret(group=su->group); if( group->state.song_dance&0x1 ) //Cancel dissonance effect. - skill->dance_overlap(unit, 0); + skill->dance_overlap(su, 0); // invoke onout event - if( !unit->range ) - iMap->foreachincell(skill->unit_effect,unit->bl.m,unit->bl.x,unit->bl.y,group->bl_flag,&unit->bl,iTimer->gettick(),4); + if( !su->range ) + map->foreachincell(skill->unit_effect,su->bl.m,su->bl.x,su->bl.y,group->bl_flag,&su->bl,timer->gettick(),4); // perform ondelete actions switch (group->skill_id) { - case HT_ANKLESNARE: { - struct block_list* target = iMap->id2bl(group->val2); - if( target ) - status_change_end(target, SC_ANKLESNARE, INVALID_TIMER); - } + case HT_ANKLESNARE: + { + struct block_list* target = map->id2bl(group->val2); + if( target ) + status_change_end(target, SC_ANKLESNARE, INVALID_TIMER); + } break; case WZ_ICEWALL: - iMap->setgatcell(unit->bl.m,unit->bl.x,unit->bl.y,unit->val2); - clif->changemapcell(0,unit->bl.m,unit->bl.x,unit->bl.y,unit->val2,ALL_SAMEMAP); // hack to avoid clientside cell bug - skill->unitsetmapcell(unit,WZ_ICEWALL,group->skill_lv,CELL_ICEWALL,false); - map[unit->bl.m].icewall_num--; + map->setgatcell(su->bl.m,su->bl.x,su->bl.y,su->val2); + clif->changemapcell(0,su->bl.m,su->bl.x,su->bl.y,su->val2,ALL_SAMEMAP); // hack to avoid clientside cell bug + skill->unitsetmapcell(su,WZ_ICEWALL,group->skill_lv,CELL_ICEWALL,false); + map->list[su->bl.m].icewall_num--; + // AS_CLOAKING in low levels requires a wall to be cast, thus it needs to be + // checked again when a wall disapears! issue:8182 [Panikon] + map->foreachinarea(skill->check_cloaking_end, su->bl.m, + // Use 3x3 area to check for users near cell + su->bl.x - 1, su->bl.y - 1, + su->bl.x + 1, su->bl.x + 1, + BL_PC); break; case SA_LANDPROTECTOR: - skill->unitsetmapcell(unit,SA_LANDPROTECTOR,group->skill_lv,CELL_LANDPROTECTOR,false); + skill->unitsetmapcell(su,SA_LANDPROTECTOR,group->skill_lv,CELL_LANDPROTECTOR,false); break; case HP_BASILICA: - skill->unitsetmapcell(unit,HP_BASILICA,group->skill_lv,CELL_BASILICA,false); + skill->unitsetmapcell(su,HP_BASILICA,group->skill_lv,CELL_BASILICA,false); break; case RA_ELECTRICSHOCKER: { - struct block_list* target = iMap->id2bl(group->val2); + struct block_list* target = map->id2bl(group->val2); if( target ) status_change_end(target, SC_ELECTRICSHOCKER, INVALID_TIMER); } break; - case SC_MAELSTROM: - skill->unitsetmapcell(unit,SC_MAELSTROM,group->skill_lv,CELL_MAELSTROM,false); - break; case SC_MANHOLE: // Note : Removing the unit don't remove the status (official info) - if( group->val2 ) { // Someone Traped - struct status_change *tsc = status_get_sc( iMap->id2bl(group->val2)); + if( group->val2 ) { // Someone Trapped + struct status_change *tsc = status->get_sc(map->id2bl(group->val2)); if( tsc && tsc->data[SC__MANHOLE] ) tsc->data[SC__MANHOLE]->val4 = 0; // Remove the Unit ID } break; } - clif->skill_delunit(unit); + clif->skill_delunit(su); - unit->group=NULL; - iMap->delblock(&unit->bl); // don't free yet - iMap->deliddb(&unit->bl); - idb_remove(skillunit_db, unit->bl.id); + su->group=NULL; + map->delblock(&su->bl); // don't free yet + map->deliddb(&su->bl); + idb_remove(skill->unit_db, su->bl.id); if(--group->alive_count==0) skill->del_unitgroup(group,ALC_MARK); @@ -15060,31 +15641,26 @@ int skill_delunit (struct skill_unit* unit) { /*========================================== * *------------------------------------------*/ -static DBMap* group_db = NULL;// int group_id -> struct skill_unit_group* - /// Returns the target skill_unit_group or NULL if not found. struct skill_unit_group* skill_id2group(int group_id) { - return (struct skill_unit_group*)idb_get(group_db, group_id); + return (struct skill_unit_group*)idb_get(skill->group_db, group_id); } - -static int skill_unit_group_newid = MAX_SKILL_DB; - -/// Returns a new group_id that isn't being used in group_db. +/// Returns a new group_id that isn't being used in skill->group_db. /// Fatal error if nothing is available. -static int skill_get_new_group_id(void) +int skill_get_new_group_id(void) { - if( skill_unit_group_newid >= MAX_SKILL_DB && skill->id2group(skill_unit_group_newid) == NULL ) - return skill_unit_group_newid++;// available + if( skill->unit_group_newid >= MAX_SKILL_DB && skill->id2group(skill->unit_group_newid) == NULL ) + return skill->unit_group_newid++;// available {// find next id - int base_id = skill_unit_group_newid; - while( base_id != ++skill_unit_group_newid ) + int base_id = skill->unit_group_newid; + while( base_id != ++skill->unit_group_newid ) { - if( skill_unit_group_newid < MAX_SKILL_DB ) - skill_unit_group_newid = MAX_SKILL_DB; - if( skill->id2group(skill_unit_group_newid) == NULL ) - return skill_unit_group_newid++;// available + if( skill->unit_group_newid < MAX_SKILL_DB ) + skill->unit_group_newid = MAX_SKILL_DB; + if( skill->id2group(skill->unit_group_newid) == NULL ) + return skill->unit_group_newid++;// available } // full loop, nothing available ShowFatalError("skill_get_new_group_id: All ids are taken. Exiting..."); @@ -15094,7 +15670,7 @@ static int skill_get_new_group_id(void) struct skill_unit_group* skill_initunitgroup (struct block_list* src, int count, uint16 skill_id, uint16 skill_lv, int unit_id, int limit, int interval) { - struct unit_data* ud = unit_bl2ud( src ); + struct unit_data* ud = unit->bl2ud( src ); struct skill_unit_group* group; int i; @@ -15108,70 +15684,68 @@ struct skill_unit_group* skill_initunitgroup (struct block_list* src, int count, if(i == MAX_SKILLUNITGROUP) { // array is full, make room by discarding oldest group int j=0; - unsigned maxdiff=0,x,tick=iTimer->gettick(); + int64 maxdiff = 0, x, tick = timer->gettick(); for(i=0;i<MAX_SKILLUNITGROUP && ud->skillunit[i];i++) - if((x=DIFF_TICK(tick,ud->skillunit[i]->tick))>maxdiff){ - maxdiff=x; - j=i; + if( (x=DIFF_TICK(tick,ud->skillunit[i]->tick)) > maxdiff ) { + maxdiff = x; + j = i; } skill->del_unitgroup(ud->skillunit[j],ALC_MARK); //Since elements must have shifted, we use the last slot. i = MAX_SKILLUNITGROUP-1; } - group = ers_alloc(skill_unit_ers, struct skill_unit_group); - group->src_id = src->id; - group->party_id = status_get_party_id(src); - group->guild_id = status_get_guild_id(src); - group->bg_id = bg_team_get_id(src); - group->group_id = skill_get_new_group_id(); - group->unit = (struct skill_unit *)aCalloc(count,sizeof(struct skill_unit)); - group->unit_count = count; + group = ers_alloc(skill->unit_ers, struct skill_unit_group); + group->src_id = src->id; + group->party_id = status->get_party_id(src); + group->guild_id = status->get_guild_id(src); + group->bg_id = bg->team_get_id(src); + group->group_id = skill->get_new_group_id(); + group->unit = (struct skill_unit *)aCalloc(count,sizeof(struct skill_unit)); + group->unit_count = count; group->alive_count = 0; - group->val1 = 0; - group->val2 = 0; - group->val3 = 0; - group->skill_id = skill_id; - group->skill_lv = skill_lv; - group->unit_id = unit_id; - group->map = src->m; - group->limit = limit; - group->interval = interval; - group->tick = iTimer->gettick(); - group->valstr = NULL; + group->val1 = 0; + group->val2 = 0; + group->val3 = 0; + group->skill_id = skill_id; + group->skill_lv = skill_lv; + group->unit_id = unit_id; + group->map = src->m; + group->limit = limit; + group->interval = interval; + group->tick = timer->gettick(); + group->valstr = NULL; ud->skillunit[i] = group; if (skill_id == PR_SANCTUARY) //Sanctuary starts healing +1500ms after casted. [Skotlex] group->tick += 1500; - idb_put(group_db, group->group_id, group); + idb_put(skill->group_db, group->group_id, group); return group; } /*========================================== * *------------------------------------------*/ -int skill_delunitgroup(struct skill_unit_group *group, const char* file, int line, const char* func) -{ +int skill_delunitgroup(struct skill_unit_group *group, const char* file, int line, const char* func) { struct block_list* src; struct unit_data *ud; int i,j; - if( group == NULL ) - { + if( group == NULL ) { ShowDebug("skill_delunitgroup: group is NULL (source=%s:%d, %s)! Please report this! (#3504)\n", file, line, func); return 0; } - src=iMap->id2bl(group->src_id); - ud = unit_bl2ud(src); + src=map->id2bl(group->src_id); + ud = unit->bl2ud(src); if(!src || !ud) { ShowError("skill_delunitgroup: Group's source not found! (src_id: %d skill_id: %d)\n", group->src_id, group->skill_id); return 0; } - if( !status_isdead(src) && ((TBL_PC*)src)->state.warping && !((TBL_PC*)src)->state.changemap ) { + if( !status->isdead(src) && ((TBL_PC*)src)->state.warping && !((TBL_PC*)src)->state.changemap ) { switch( group->skill_id ) { case BA_DISSONANCE: case BA_POEMBRAGI: @@ -15188,12 +15762,11 @@ int skill_delunitgroup(struct skill_unit_group *group, const char* file, int lin } } - if (skill->get_unit_flag(group->skill_id)&(UF_DANCE|UF_SONG|UF_ENSEMBLE)) - { - struct status_change* sc = status_get_sc(src); + if (skill->get_unit_flag(group->skill_id)&(UF_DANCE|UF_SONG|UF_ENSEMBLE)) { + struct status_change* sc = status->get_sc(src); if (sc && sc->data[SC_DANCING]) { - sc->data[SC_DANCING]->val2 = 0 ; //This prevents status_change_end attempting to redelete the group. [Skotlex] + sc->data[SC_DANCING]->val2 = 0 ; //This prevents status_change_end attempting to re-delete the group. [Skotlex] status_change_end(src, SC_DANCING, INVALID_TIMER); } } @@ -15201,7 +15774,7 @@ int skill_delunitgroup(struct skill_unit_group *group, const char* file, int lin // end Gospel's status change on 'src' // (needs to be done when the group is deleted by other means than skill deactivation) if (group->unit_id == UNT_GOSPEL) { - struct status_change *sc = status_get_sc(src); + struct status_change *sc = status->get_sc(src); if(sc && sc->data[SC_GOSPEL]) { sc->data[SC_GOSPEL]->val3 = 0; //Remove reference to this group. [Skotlex] status_change_end(src, SC_GOSPEL, INVALID_TIMER); @@ -15212,40 +15785,40 @@ int skill_delunitgroup(struct skill_unit_group *group, const char* file, int lin case SG_SUN_WARM: case SG_MOON_WARM: case SG_STAR_WARM: - { - struct status_change *sc = NULL; - if( (sc = status_get_sc(src)) != NULL && sc->data[SC_WARM] ) { - sc->data[SC_WARM]->val4 = 0; - status_change_end(src, SC_WARM, INVALID_TIMER); - } + { + struct status_change *sc = NULL; + if( (sc = status->get_sc(src)) != NULL && sc->data[SC_WARM] ) { + sc->data[SC_WARM]->val4 = 0; + status_change_end(src, SC_WARM, INVALID_TIMER); } + } break; case NC_NEUTRALBARRIER: - { - struct status_change *sc = NULL; - if( (sc = status_get_sc(src)) != NULL && sc->data[SC_NEUTRALBARRIER_MASTER] ) { - sc->data[SC_NEUTRALBARRIER_MASTER]->val2 = 0; - status_change_end(src,SC_NEUTRALBARRIER_MASTER,INVALID_TIMER); - } + { + struct status_change *sc = NULL; + if( (sc = status->get_sc(src)) != NULL && sc->data[SC_NEUTRALBARRIER_MASTER] ) { + sc->data[SC_NEUTRALBARRIER_MASTER]->val2 = 0; + status_change_end(src,SC_NEUTRALBARRIER_MASTER,INVALID_TIMER); } + } break; case NC_STEALTHFIELD: - { - struct status_change *sc = NULL; - if( (sc = status_get_sc(src)) != NULL && sc->data[SC_STEALTHFIELD_MASTER] ) { - sc->data[SC_STEALTHFIELD_MASTER]->val2 = 0; - status_change_end(src,SC_STEALTHFIELD_MASTER,INVALID_TIMER); - } + { + struct status_change *sc = NULL; + if( (sc = status->get_sc(src)) != NULL && sc->data[SC_STEALTHFIELD_MASTER] ) { + sc->data[SC_STEALTHFIELD_MASTER]->val2 = 0; + status_change_end(src,SC_STEALTHFIELD_MASTER,INVALID_TIMER); } + } break; case LG_BANDING: - { - struct status_change *sc = NULL; - if( (sc = status_get_sc(src)) && sc->data[SC_BANDING] ) { - sc->data[SC_BANDING]->val4 = 0; - status_change_end(src,SC_BANDING,INVALID_TIMER); - } + { + struct status_change *sc = NULL; + if( (sc = status->get_sc(src)) && sc->data[SC_BANDING] ) { + sc->data[SC_BANDING]->val4 = 0; + status_change_end(src,SC_BANDING,INVALID_TIMER); } + } break; } @@ -15265,8 +15838,8 @@ int skill_delunitgroup(struct skill_unit_group *group, const char* file, int lin group->valstr = NULL; } - idb_remove(group_db, group->group_id); - iMap->freeblock(&group->unit->bl); // schedules deallocation of whole array (HACK) + idb_remove(skill->group_db, group->group_id); + map->freeblock(&group->unit->bl); // schedules deallocation of whole array (HACK) group->unit=NULL; group->group_id=0; group->unit_count=0; @@ -15277,7 +15850,7 @@ int skill_delunitgroup(struct skill_unit_group *group, const char* file, int lin if( i < MAX_SKILLUNITGROUP ) { ud->skillunit[i] = ud->skillunit[j]; ud->skillunit[j] = NULL; - ers_free(skill_unit_ers, group); + ers_free(skill->unit_ers, group); } else ShowError("skill_delunitgroup: Group not found! (src_id: %d skill_id: %d)\n", group->src_id, group->skill_id); @@ -15289,7 +15862,7 @@ int skill_delunitgroup(struct skill_unit_group *group, const char* file, int lin *------------------------------------------*/ int skill_clear_unitgroup (struct block_list *src) { - struct unit_data *ud = unit_bl2ud(src); + struct unit_data *ud = unit->bl2ud(src); nullpo_ret(ud); @@ -15302,7 +15875,7 @@ int skill_clear_unitgroup (struct block_list *src) /*========================================== * *------------------------------------------*/ -struct skill_unit_group_tickset *skill_unitgrouptickset_search (struct block_list *bl, struct skill_unit_group *group, int tick) { +struct skill_unit_group_tickset *skill_unitgrouptickset_search(struct block_list *bl, struct skill_unit_group *group, int64 tick) { int i,j=-1,k,s,id; struct unit_data *ud; struct skill_unit_group_tickset *set; @@ -15311,7 +15884,7 @@ struct skill_unit_group_tickset *skill_unitgrouptickset_search (struct block_lis if (group->interval==-1) return NULL; - ud = unit_bl2ud(bl); + ud = unit->bl2ud(bl); if (!ud) return NULL; set = ud->skillunittick; @@ -15342,23 +15915,23 @@ struct skill_unit_group_tickset *skill_unitgrouptickset_search (struct block_lis /*========================================== * *------------------------------------------*/ -int skill_unit_timer_sub_onplace (struct block_list* bl, va_list ap) { - struct skill_unit* unit = va_arg(ap,struct skill_unit *); - struct skill_unit_group* group = unit->group; - unsigned int tick = va_arg(ap,unsigned int); +int skill_unit_timer_sub_onplace(struct block_list* bl, va_list ap) { + struct skill_unit* su = va_arg(ap,struct skill_unit *); + struct skill_unit_group* group = su->group; + int64 tick = va_arg(ap,int64); - if( !unit->alive || bl->prev == NULL ) + if( !su->alive || bl->prev == NULL ) return 0; nullpo_ret(group); - if( !(skill->get_inf2(group->skill_id)&(INF2_SONG_DANCE|INF2_TRAP|INF2_NOLP)) && iMap->getcell(bl->m, bl->x, bl->y, CELL_CHKLANDPROTECTOR) ) + if( !(skill->get_inf2(group->skill_id)&(INF2_SONG_DANCE|INF2_TRAP|INF2_NOLP)) && map->getcell(bl->m, bl->x, bl->y, CELL_CHKLANDPROTECTOR) ) return 0; //AoE skills are ineffective. [Skotlex] - if( battle->check_target(&unit->bl,bl,group->target_flag) <= 0 ) + if( battle->check_target(&su->bl,bl,group->target_flag) <= 0 ) return 0; - skill->unit_onplace_timer(unit,bl,tick); + skill->unit_onplace_timer(su,bl,tick); return 1; } @@ -15367,22 +15940,21 @@ int skill_unit_timer_sub_onplace (struct block_list* bl, va_list ap) { * @see DBApply */ int skill_unit_timer_sub(DBKey key, DBData *data, va_list ap) { - struct skill_unit* unit = DB->data2ptr(data); - struct skill_unit_group* group = unit->group; - unsigned int tick = va_arg(ap,unsigned int); + struct skill_unit* su = DB->data2ptr(data); + struct skill_unit_group* group = su->group; + int64 tick = va_arg(ap,int64); bool dissonance; - struct block_list* bl = &unit->bl; + struct block_list* bl = &su->bl; - if( !unit->alive ) + if( !su->alive ) return 0; nullpo_ret(group); // check for expiration - if( !group->state.guildaura && (DIFF_TICK(tick,group->tick) >= group->limit || DIFF_TICK(tick,group->tick) >= unit->limit) ) - {// skill unit expired (inlined from skill_unit_onlimit()) - switch( group->unit_id ) - { + if( !group->state.guildaura && (DIFF_TICK(tick,group->tick) >= group->limit || DIFF_TICK(tick,group->tick) >= su->limit) ) { + // skill unit expired (inlined from skill_unit_onlimit()) + switch( group->unit_id ) { case UNT_BLASTMINE: #ifdef RENEWAL case UNT_CLAYMORETRAP: @@ -15394,15 +15966,15 @@ int skill_unit_timer_sub(DBKey key, DBData *data, va_list ap) { case UNT_GROUNDDRIFT_FIRE: group->unit_id = UNT_USED_TRAPS; //clif->changetraplook(bl, UNT_FIREPILLAR_ACTIVE); - group->limit=DIFF_TICK(tick+1500,group->tick); - unit->limit=DIFF_TICK(tick+1500,group->tick); + group->limit=DIFF_TICK32(tick+1500,group->tick); + su->limit=DIFF_TICK32(tick+1500,group->tick); break; case UNT_ANKLESNARE: case UNT_ELECTRICSHOCKER: - if( group->val2 > 0 ) { + if( group->val2 > 0 || group->val3 == SC_ESCAPE ) { // Used Trap don't returns back to item - skill->delunit(unit); + skill->delunit(su); break; } case UNT_SKIDTRAP: @@ -15425,93 +15997,94 @@ int skill_unit_timer_sub(DBKey key, DBData *data, va_list ap) { { struct block_list* src; - if( unit->val1 > 0 && (src = iMap->id2bl(group->src_id)) != NULL && src->type == BL_PC ) - { // revert unit back into a trap + if( su->val1 > 0 && (src = map->id2bl(group->src_id)) != NULL && src->type == BL_PC ) { + // revert unit back into a trap struct item item_tmp; memset(&item_tmp,0,sizeof(item_tmp)); item_tmp.nameid = group->item_id?group->item_id:ITEMID_TRAP; item_tmp.identify = 1; - iMap->addflooritem(&item_tmp,1,bl->m,bl->x,bl->y,0,0,0,0); + map->addflooritem(&item_tmp,1,bl->m,bl->x,bl->y,0,0,0,0); } - skill->delunit(unit); + skill->delunit(su); } break; case UNT_WARP_ACTIVE: // warp portal opens (morph to a UNT_WARP_WAITING cell) group->unit_id = skill->get_unit_id(group->skill_id, 1); // UNT_WARP_WAITING - clif->changelook(&unit->bl, LOOK_BASE, group->unit_id); + clif->changelook(&su->bl, LOOK_BASE, group->unit_id); // restart timers group->limit = skill->get_time(group->skill_id,group->skill_lv); - unit->limit = skill->get_time(group->skill_id,group->skill_lv); + su->limit = skill->get_time(group->skill_id,group->skill_lv); // apply effect to all units standing on it - iMap->foreachincell(skill->unit_effect,unit->bl.m,unit->bl.x,unit->bl.y,group->bl_flag,&unit->bl,iTimer->gettick(),1); + map->foreachincell(skill->unit_effect,su->bl.m,su->bl.x,su->bl.y,group->bl_flag,&su->bl,timer->gettick(),1); break; case UNT_CALLFAMILY: { struct map_session_data *sd = NULL; if(group->val1) { - sd = iMap->charid2sd(group->val1); + sd = map->charid2sd(group->val1); group->val1 = 0; - if (sd && !map[sd->bl.m].flag.nowarp) - pc->setpos(sd,map_id2index(unit->bl.m),unit->bl.x,unit->bl.y,CLR_TELEPORT); + if (sd && !map->list[sd->bl.m].flag.nowarp) + pc->setpos(sd,map_id2index(su->bl.m),su->bl.x,su->bl.y,CLR_TELEPORT); } if(group->val2) { - sd = iMap->charid2sd(group->val2); + sd = map->charid2sd(group->val2); group->val2 = 0; - if (sd && !map[sd->bl.m].flag.nowarp) - pc->setpos(sd,map_id2index(unit->bl.m),unit->bl.x,unit->bl.y,CLR_TELEPORT); + if (sd && !map->list[sd->bl.m].flag.nowarp) + pc->setpos(sd,map_id2index(su->bl.m),su->bl.x,su->bl.y,CLR_TELEPORT); } - skill->delunit(unit); + skill->delunit(su); } break; case UNT_REVERBERATION: - if( unit->val1 <= 0 ) { // If it was deactivated. - skill->delunit(unit); + if( su->val1 <= 0 ) { // If it was deactivated. + skill->delunit(su); break; } clif->changetraplook(bl,UNT_USED_TRAPS); - iMap->foreachinrange(skill->trap_splash, bl, skill->get_splash(group->skill_id, group->skill_lv), group->bl_flag, bl, tick); - group->limit = DIFF_TICK(tick,group->tick)+1000; - unit->limit = DIFF_TICK(tick,group->tick)+1000; + map->foreachinrange(skill->trap_splash, bl, skill->get_splash(group->skill_id, group->skill_lv), group->bl_flag, bl, tick); + group->limit = DIFF_TICK32(tick,group->tick)+1500; + su->limit = DIFF_TICK32(tick,group->tick)+1500; group->unit_id = UNT_USED_TRAPS; break; case UNT_FEINTBOMB: { - struct block_list *src = iMap->id2bl(group->src_id); - if( src ) - iMap->foreachinrange(skill->area_sub, &group->unit->bl, unit->range, splash_target(src), src, SC_FEINTBOMB, group->skill_lv, tick, BCT_ENEMY|SD_ANIMATION|1, skill->castend_damage_id); - skill->delunit(unit); + struct block_list *src = map->id2bl(group->src_id); + if( src ) { + map->foreachinrange(skill->area_sub, &group->unit->bl, su->range, 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); break; } case UNT_BANDING: { - struct block_list *src = iMap->id2bl(group->src_id); + struct block_list *src = map->id2bl(group->src_id); struct status_change *sc; - if( !src || (sc = status_get_sc(src)) == NULL || !sc->data[SC_BANDING] ) - { - skill->delunit(unit); + if( !src || (sc = status->get_sc(src)) == NULL || !sc->data[SC_BANDING] ) { + skill->delunit(su); break; } // This unit isn't removed while SC_BANDING is active. - group->limit = DIFF_TICK(tick+group->interval,group->tick); - unit->limit = DIFF_TICK(tick+group->interval,group->tick); + group->limit = DIFF_TICK32(tick+group->interval,group->tick); + su->limit = DIFF_TICK32(tick+group->interval,group->tick); } break; default: - skill->delunit(unit); + skill->delunit(su); } } else {// skill unit is still active switch( group->unit_id ) { case UNT_ICEWALL: // icewall loses 50 hp every second - unit->val1 -= SKILLUNITTIMER_INTERVAL/20; // trap's hp - if( unit->val1 <= 0 && unit->limit + group->tick > tick + 700 ) - unit->limit = DIFF_TICK(tick+700,group->tick); + su->val1 -= SKILLUNITTIMER_INTERVAL/20; // trap's hp + if( su->val1 <= 0 && su->limit + group->tick > tick + 700 ) + su->limit = DIFF_TICK32(tick+700,group->tick); break; case UNT_BLASTMINE: case UNT_SKIDTRAP: @@ -15523,51 +16096,45 @@ int skill_unit_timer_sub(DBKey key, DBData *data, va_list ap) { case UNT_FREEZINGTRAP: case UNT_TALKIEBOX: case UNT_ANKLESNARE: - if( unit->val1 <= 0 ) { + if( su->val1 <= 0 ) { if( group->unit_id == UNT_ANKLESNARE && group->val2 > 0 ) - skill->delunit(unit); + skill->delunit(su); else { clif->changetraplook(bl, group->unit_id==UNT_LANDMINE?UNT_FIREPILLAR_ACTIVE:UNT_USED_TRAPS); - group->limit = DIFF_TICK(tick, group->tick) + 1500; + group->limit = DIFF_TICK32(tick, group->tick) + 1500; group->unit_id = UNT_USED_TRAPS; } } break; case UNT_REVERBERATION: - if( unit->val1 <= 0 ){ - clif->changetraplook(bl,UNT_USED_TRAPS); - iMap->foreachinrange(skill->trap_splash, bl, skill->get_splash(group->skill_id, group->skill_lv), group->bl_flag, bl, tick); - group->limit = DIFF_TICK(tick,group->tick)+1000; - unit->limit = DIFF_TICK(tick,group->tick)+1000; - group->unit_id = UNT_USED_TRAPS; - } + if( su->val1 <= 0 ) + su->limit = DIFF_TICK32(tick + 700,group->tick); break; case UNT_WALLOFTHORN: - if( unit->val1 <= 0 ) { + if( su->val1 <= 0 ) { group->unit_id = UNT_USED_TRAPS; - group->limit = DIFF_TICK(tick, group->tick) + 1500; + group->limit = DIFF_TICK32(tick, group->tick) + 1500; } break; } } //Don't continue if unit or even group is expired and has been deleted. - if( !group || !unit->alive ) + if( !group || !su->alive ) return 0; - dissonance = skill->dance_switch(unit, 0); + dissonance = skill->dance_switch(su, 0); - if( unit->range >= 0 && group->interval != -1 ) - { + if( su->range >= 0 && group->interval != -1 ) { if( battle_config.skill_wall_check ) - iMap->foreachinshootrange(skill->unit_timer_sub_onplace, bl, unit->range, group->bl_flag, bl,tick); + map->foreachinshootrange(skill->unit_timer_sub_onplace, bl, su->range, group->bl_flag, bl,tick); else - iMap->foreachinrange(skill->unit_timer_sub_onplace, bl, unit->range, group->bl_flag, bl,tick); + map->foreachinrange(skill->unit_timer_sub_onplace, bl, su->range, group->bl_flag, bl,tick); - if(unit->range == -1) //Unit disabled, but it should not be deleted yet. + if(su->range == -1) //Unit disabled, but it should not be deleted yet. group->unit_id = UNT_USED_TRAPS; else if( group->unit_id == UNT_TATAMIGAESHI ) { - unit->range = -1; //Disable processed cell. + su->range = -1; //Disable processed cell. if (--group->val1 <= 0) { // number of live cells //All tiles were processed, disable skill. group->target_flag=BCT_NOONE; @@ -15576,33 +16143,32 @@ int skill_unit_timer_sub(DBKey key, DBData *data, va_list ap) { } } - if( dissonance ) skill->dance_switch(unit, 1); + if( dissonance ) skill->dance_switch(su, 1); return 0; } /*========================================== - * Executes on all skill units every SKILLUNITTIMER_INTERVAL miliseconds. + * Executes on all skill units every SKILLUNITTIMER_INTERVAL milliseconds. *------------------------------------------*/ -int skill_unit_timer(int tid, unsigned int tick, int id, intptr_t data) { - iMap->freeblock_lock(); +int skill_unit_timer(int tid, int64 tick, int id, intptr_t data) { + map->freeblock_lock(); - skillunit_db->foreach(skillunit_db, skill->unit_timer_sub, tick); + skill->unit_db->foreach(skill->unit_db, skill->unit_timer_sub, tick); - iMap->freeblock_unlock(); + map->freeblock_unlock(); return 0; } -static int skill_unit_temp[20]; // temporary storage for tracking skill unit skill ids as players move in/out of them /*========================================== * *------------------------------------------*/ -int skill_unit_move_sub (struct block_list* bl, va_list ap) { - struct skill_unit* unit = (struct skill_unit *)bl; - struct skill_unit_group* group = unit->group; +int skill_unit_move_sub(struct block_list* bl, va_list ap) { + struct skill_unit* su = (struct skill_unit *)bl; + struct skill_unit_group* group = su->group; struct block_list* target = va_arg(ap,struct block_list*); - unsigned int tick = va_arg(ap,unsigned int); + int64 tick = va_arg(ap,int64); int flag = va_arg(ap,int); bool dissonance; @@ -15611,37 +16177,37 @@ int skill_unit_move_sub (struct block_list* bl, va_list ap) { nullpo_ret(group); - if( !unit->alive || target->prev == NULL ) + if( !su->alive || target->prev == NULL ) return 0; - if( flag&1 && ( unit->group->skill_id == PF_SPIDERWEB || unit->group->skill_id == GN_THORNS_TRAP ) ) + if( flag&1 && ( su->group->skill_id == PF_SPIDERWEB || su->group->skill_id == GN_THORNS_TRAP ) ) return 0; // Fiberlock is never supposed to trigger on skill->unit_move. [Inkfish] - dissonance = skill->dance_switch(unit, 0); + dissonance = skill->dance_switch(su, 0); //Necessary in case the group is deleted after calling on_place/on_out [Skotlex] - skill_id = unit->group->skill_id; + skill_id = su->group->skill_id; - if( unit->group->interval != -1 && !(skill->get_unit_flag(skill_id)&UF_DUALMODE) && skill_id != BD_LULLABY ) //Lullaby is the exception, bugreport:411 + if( su->group->interval != -1 && !(skill->get_unit_flag(skill_id)&UF_DUALMODE) && skill_id != BD_LULLABY ) //Lullaby is the exception, bugreport:411 { //Non-dualmode unit skills with a timer don't trigger when walking, so just return - if( dissonance ) skill->dance_switch(unit, 1); + if( dissonance ) skill->dance_switch(su, 1); return 0; } //Target-type check. - if( !(group->bl_flag&target->type && battle->check_target(&unit->bl,target,group->target_flag) > 0) ) { + if( !(group->bl_flag&target->type && battle->check_target(&su->bl,target,group->target_flag) > 0) ) { if( group->src_id == target->id && group->state.song_dance&0x2 ) { //Ensemble check to see if they went out/in of the area [Skotlex] if( flag&1 ) { if( flag&2 ) { //Clear this skill id. - ARR_FIND( 0, ARRAYLENGTH(skill_unit_temp), i, skill_unit_temp[i] == skill_id ); - if( i < ARRAYLENGTH(skill_unit_temp) ) - skill_unit_temp[i] = 0; + ARR_FIND( 0, ARRAYLENGTH(skill->unit_temp), i, skill->unit_temp[i] == skill_id ); + if( i < ARRAYLENGTH(skill->unit_temp) ) + skill->unit_temp[i] = 0; } } else { if( flag&2 ) { //Store this skill id. - ARR_FIND( 0, ARRAYLENGTH(skill_unit_temp), i, skill_unit_temp[i] == 0 ); - if( i < ARRAYLENGTH(skill_unit_temp) ) - skill_unit_temp[i] = skill_id; + ARR_FIND( 0, ARRAYLENGTH(skill->unit_temp), i, skill->unit_temp[i] == 0 ); + if( i < ARRAYLENGTH(skill->unit_temp) ) + skill->unit_temp[i] = skill_id; else ShowError("skill_unit_move_sub: Reached limit of unit objects per cell!\n"); } @@ -15652,32 +16218,29 @@ int skill_unit_move_sub (struct block_list* bl, va_list ap) { skill->unit_onleft(skill_id,target,tick); } - if( dissonance ) skill->dance_switch(unit, 1); + if( dissonance ) skill->dance_switch(su, 1); return 0; } else { if( flag&1 ) { - int result = skill->unit_onplace(unit,target,tick); + int result = skill->unit_onplace(su,target,tick); if( flag&2 && result ) { //Clear skill ids we have stored in onout. - ARR_FIND( 0, ARRAYLENGTH(skill_unit_temp), i, skill_unit_temp[i] == result ); - if( i < ARRAYLENGTH(skill_unit_temp) ) - skill_unit_temp[i] = 0; + ARR_FIND( 0, ARRAYLENGTH(skill->unit_temp), i, skill->unit_temp[i] == result ); + if( i < ARRAYLENGTH(skill->unit_temp) ) + skill->unit_temp[i] = 0; } } else { - int result = skill->unit_onout(unit,target,tick); + int result = skill->unit_onout(su,target,tick); if( flag&2 && result ) { //Store this unit id. - ARR_FIND( 0, ARRAYLENGTH(skill_unit_temp), i, skill_unit_temp[i] == 0 ); - if( i < ARRAYLENGTH(skill_unit_temp) ) - skill_unit_temp[i] = skill_id; + ARR_FIND( 0, ARRAYLENGTH(skill->unit_temp), i, skill->unit_temp[i] == 0 ); + if( i < ARRAYLENGTH(skill->unit_temp) ) + skill->unit_temp[i] = skill_id; else ShowError("skill_unit_move_sub: Reached limit of unit objects per cell!\n"); } } - //TODO: Normally, this is dangerous since the unit and group could be freed - //inside the onout/onplace functions. Currently it is safe because we know song/dance - //cells do not get deleted within them. [Skotlex] - if( dissonance ) skill->dance_switch(unit, 1); + if( dissonance ) skill->dance_switch(su, 1); if( flag&4 ) skill->unit_onleft(skill_id,target,tick); @@ -15694,23 +16257,23 @@ int skill_unit_move_sub (struct block_list* bl, va_list ap) { * units to figure out when they have left a group. * flag&4: Force a onleft event (triggered when the bl is killed, for example) *------------------------------------------*/ -int skill_unit_move (struct block_list *bl, unsigned int tick, int flag) { +int skill_unit_move(struct block_list *bl, int64 tick, int flag) { nullpo_ret(bl); if( bl->prev == NULL ) return 0; if( flag&2 && !(flag&1) ) { //Onout, clear data - memset(skill_unit_temp, 0, sizeof(skill_unit_temp)); + memset(skill->unit_temp, 0, sizeof(skill->unit_temp)); } - iMap->foreachincell(skill->unit_move_sub,bl->m,bl->x,bl->y,BL_SKILL,bl,tick,flag); + map->foreachincell(skill->unit_move_sub,bl->m,bl->x,bl->y,BL_SKILL,bl,tick,flag); if( flag&2 && flag&1 ) { //Onplace, check any skill units you have left. int i; - for( i = 0; i < ARRAYLENGTH(skill_unit_temp); i++ ) - if( skill_unit_temp[i] ) - skill->unit_onleft(skill_unit_temp[i], bl, tick); + for( i = 0; i < ARRAYLENGTH(skill->unit_temp); i++ ) + if( skill->unit_temp[i] ) + skill->unit_onleft(skill->unit_temp[i], bl, tick); } return 0; @@ -15719,13 +16282,12 @@ int skill_unit_move (struct block_list *bl, unsigned int tick, int flag) { /*========================================== * *------------------------------------------*/ -int skill_unit_move_unit_group (struct skill_unit_group *group, int16 m, int16 dx, int16 dy) -{ +int skill_unit_move_unit_group(struct skill_unit_group *group, int16 m, int16 dx, int16 dy) { int i,j; - unsigned int tick = iTimer->gettick(); + int64 tick = timer->gettick(); int *m_flag; - struct skill_unit *unit1; - struct skill_unit *unit2; + struct skill_unit *su1; + struct skill_unit *su2; if (group == NULL) return 0; @@ -15746,49 +16308,47 @@ int skill_unit_move_unit_group (struct skill_unit_group *group, int16 m, int16 d // 1: Unit will move to a slot that had another unit of the same group (skill_unit_onplace not needed) // 2: Another unit from same group will end up positioned on this unit (skill_unit_onout not needed) // 3: Both 1+2. - for(i=0;i<group->unit_count;i++){ - unit1=&group->unit[i]; - if (!unit1->alive || unit1->bl.m!=m) + for(i=0;i<group->unit_count;i++) { + su1=&group->unit[i]; + if (!su1->alive || su1->bl.m!=m) continue; - for(j=0;j<group->unit_count;j++){ - unit2=&group->unit[j]; - if (!unit2->alive) + for(j=0;j<group->unit_count;j++) { + su2=&group->unit[j]; + if (!su2->alive) continue; - if (unit1->bl.x+dx==unit2->bl.x && unit1->bl.y+dy==unit2->bl.y){ + if (su1->bl.x+dx==su2->bl.x && su1->bl.y+dy==su2->bl.y) { m_flag[i] |= 0x1; } - if (unit1->bl.x-dx==unit2->bl.x && unit1->bl.y-dy==unit2->bl.y){ + if (su1->bl.x-dx==su2->bl.x && su1->bl.y-dy==su2->bl.y) { m_flag[i] |= 0x2; } } } j = 0; for (i=0;i<group->unit_count;i++) { - unit1=&group->unit[i]; - if (!unit1->alive) + su1=&group->unit[i]; + if (!su1->alive) continue; if (!(m_flag[i]&0x2)) { if (group->state.song_dance&0x1) //Cancel dissonance effect. - skill->dance_overlap(unit1, 0); - iMap->foreachincell(skill->unit_effect,unit1->bl.m,unit1->bl.x,unit1->bl.y,group->bl_flag,&unit1->bl,tick,4); + skill->dance_overlap(su1, 0); + map->foreachincell(skill->unit_effect,su1->bl.m,su1->bl.x,su1->bl.y,group->bl_flag,&su1->bl,tick,4); } //Move Cell using "smart" criteria (avoid useless moving around) - switch(m_flag[i]) - { + switch(m_flag[i]) { case 0: //Cell moves independently, safely move it. - iMap->moveblock(&unit1->bl, unit1->bl.x+dx, unit1->bl.y+dy, tick); + map->moveblock(&su1->bl, su1->bl.x+dx, su1->bl.y+dy, tick); break; case 1: //Cell moves unto another cell, look for a replacement cell that won't collide //and has no cell moving into it (flag == 2) - for(;j<group->unit_count;j++) - { + for(;j<group->unit_count;j++) { if(m_flag[j]!=2 || !group->unit[j].alive) continue; //Move to where this cell would had moved. - unit2 = &group->unit[j]; - iMap->moveblock(&unit1->bl, unit2->bl.x+dx, unit2->bl.y+dy, tick); + su2 = &group->unit[j]; + map->moveblock(&su1->bl, su2->bl.x+dx, su2->bl.y+dy, tick); j++; //Skip this cell as we have used it. break; } @@ -15799,9 +16359,9 @@ int skill_unit_move_unit_group (struct skill_unit_group *group, int16 m, int16 d } if (!(m_flag[i]&0x2)) { //We only moved the cell in 0-1 if (group->state.song_dance&0x1) //Check for dissonance effect. - skill->dance_overlap(unit1, 1); - clif->skill_setunit(unit1); - iMap->foreachincell(skill->unit_effect,unit1->bl.m,unit1->bl.x,unit1->bl.y,group->bl_flag,&unit1->bl,tick,1); + skill->dance_overlap(su1, 1); + clif->getareachar_skillunit(&su1->bl,su1,AREA); + map->foreachincell(skill->unit_effect,su1->bl.m,su1->bl.x,su1->bl.y,group->bl_flag,&su1->bl,tick,1); } } aFree(m_flag); @@ -15821,9 +16381,9 @@ int skill_can_produce_mix (struct map_session_data *sd, int nameid, int trigger, return 0; for(i=0;i<MAX_SKILL_PRODUCE_DB;i++){ - if(skill_produce_db[i].nameid == nameid ){ - if((j=skill_produce_db[i].req_skill)>0 && - pc->checkskill(sd,j) < skill_produce_db[i].req_skill_lv) + if(skill->produce_db[i].nameid == nameid ){ + if((j=skill->produce_db[i].req_skill)>0 && + pc->checkskill(sd,j) < skill->produce_db[i].req_skill_lv) continue; // must iterate again to check other skills that produce it. [malufett] if( j > 0 && sd->menuskill_id > 0 && sd->menuskill_id != j ) continue; // special case @@ -15841,30 +16401,29 @@ int skill_can_produce_mix (struct map_session_data *sd, int nameid, int trigger, if(trigger>=0){ if(trigger>20) { // Non-weapon, non-food item (itemlv must match) - if(skill_produce_db[i].itemlv!=trigger) + if(skill->produce_db[i].itemlv!=trigger) return 0; } else if(trigger>10) { // Food (any item level between 10 and 20 will do) - if(skill_produce_db[i].itemlv<=10 || skill_produce_db[i].itemlv>20) + if(skill->produce_db[i].itemlv<=10 || skill->produce_db[i].itemlv>20) return 0; } else { // Weapon (itemlv must be higher or equal) - if(skill_produce_db[i].itemlv>trigger) + if(skill->produce_db[i].itemlv>trigger) return 0; } } for(j=0;j<MAX_PRODUCE_RESOURCE;j++){ int id,x,y; - if( (id=skill_produce_db[i].mat_id[j]) <= 0 ) + if( (id=skill->produce_db[i].mat_id[j]) <= 0 ) continue; - if(skill_produce_db[i].mat_amount[j] <= 0) { - if(pc->search_inventory(sd,id) < 0) + if (skill->produce_db[i].mat_amount[j] <= 0) { + if (pc->search_inventory(sd,id) == INDEX_NOT_FOUND) return 0; - } - else { + } else { for(y=0,x=0;y<MAX_INVENTORY;y++) if( sd->status.inventory[y].nameid == id ) x+=sd->status.inventory[y].amount; - if(x<qty*skill_produce_db[i].mat_amount[j]) + if(x<qty*skill->produce_db[i].mat_amount[j]) return 0; } } @@ -15874,16 +16433,15 @@ int skill_can_produce_mix (struct map_session_data *sd, int nameid, int trigger, /*========================================== * *------------------------------------------*/ -int skill_produce_mix (struct map_session_data *sd, uint16 skill_id, int nameid, int slot1, int slot2, int slot3, int qty) -{ +int skill_produce_mix(struct map_session_data *sd, uint16 skill_id, int nameid, int slot1, int slot2, int slot3, int qty) { int slot[3]; int i,sc,ele,idx,equip,wlv,make_per = 0,flag = 0,skill_lv = 0; int num = -1; // exclude the recipe - struct status_data *status; + struct status_data *st; struct item_data* data; nullpo_ret(sd); - status = status_get_status_data(&sd->bl); + st = status->get_status_data(&sd->bl); if( sd->skill_id_old == skill_id ) skill_lv = sd->skill_lv_old; @@ -15896,7 +16454,7 @@ int skill_produce_mix (struct map_session_data *sd, uint16 skill_id, int nameid, qty = 1; if (!skill_id) //A skill can be specified for some override cases. - skill_id = skill_produce_db[idx].req_skill; + skill_id = skill->produce_db[idx].req_skill; if( skill_id == GC_RESEARCHNEWPOISON ) skill_id = GC_CREATENEWPOISON; @@ -15910,13 +16468,13 @@ int skill_produce_mix (struct map_session_data *sd, uint16 skill_id, int nameid, if( slot[i]<=0 ) continue; j = pc->search_inventory(sd,slot[i]); - if(j < 0) + if (j == INDEX_NOT_FOUND) continue; - if(slot[i]==1000){ /* Star Crumb */ + if( slot[i]==ITEMID_STAR_CRUMB ) { pc->delitem(sd,j,1,1,0,LOG_TYPE_PRODUCE); sc++; } - if(slot[i]>=994 && slot[i]<=997 && ele==0){ /* Flame Heart . . . Great Nature */ + if( slot[i] >= ITEMID_FLAME_HEART && slot[i] <= ITEMID_GREAT_NATURE && ele == 0 ) { static const int ele_table[4]={3,1,4,2}; pc->delitem(sd,j,1,1,0,LOG_TYPE_PRODUCE); ele=ele_table[slot[i]-994]; @@ -15924,11 +16482,11 @@ int skill_produce_mix (struct map_session_data *sd, uint16 skill_id, int nameid, } if( skill_id == RK_RUNEMASTERY ) { - int temp_qty, skill_lv = pc->checkskill(sd,skill_id); - data = itemdb_search(nameid); + int temp_qty, rune_skill_lv = pc->checkskill(sd,skill_id); + data = itemdb->search(nameid); - if( skill_lv == 10 ) temp_qty = 1 + rnd()%3; - else if( skill_lv > 5 ) temp_qty = 1 + rnd()%2; + if( rune_skill_lv == 10 ) temp_qty = 1 + rnd()%3; + else if( rune_skill_lv > 5 ) temp_qty = 1 + rnd()%2; else temp_qty = 1; if (data->stack.inventory) { @@ -15953,15 +16511,15 @@ int skill_produce_mix (struct map_session_data *sd, uint16 skill_id, int nameid, for(i=0;i<MAX_PRODUCE_RESOURCE;i++){ int j,id,x; - if( (id=skill_produce_db[idx].mat_id[i]) <= 0 ) + if( (id=skill->produce_db[idx].mat_id[i]) <= 0 ) continue; num++; - x=( skill_id == RK_RUNEMASTERY ? 1 : qty)*skill_produce_db[idx].mat_amount[i]; + x=( skill_id == RK_RUNEMASTERY ? 1 : qty)*skill->produce_db[idx].mat_amount[i]; do{ int y=0; j = pc->search_inventory(sd,id); - if(j >= 0){ + if (j != INDEX_NOT_FOUND) { y = sd->status.inventory[j].amount; if(y>x)y=x; pc->delitem(sd,j,y,0,0,LOG_TYPE_PRODUCE); @@ -15972,7 +16530,7 @@ int skill_produce_mix (struct map_session_data *sd, uint16 skill_id, int nameid, }while( j>=0 && x>0 ); } - if( (equip = (itemdb_isequip(nameid) && skill_id != GN_CHANGEMATERIAL && skill_id != GN_MAKEBOMB )) ) + if( (equip = (itemdb->isequip(nameid) && skill_id != GN_CHANGEMATERIAL && skill_id != GN_MAKEBOMB )) ) wlv = itemdb_wlv(nameid); if(!equip) { switch(skill_id){ @@ -15981,24 +16539,24 @@ int skill_produce_mix (struct map_session_data *sd, uint16 skill_id, int nameid, case BS_ENCHANTEDSTONE: // Ores & Metals Refining - skill bonuses are straight from kRO website [DracoRPG] i = pc->checkskill(sd,skill_id); - make_per = sd->status.job_level*20 + status->dex*10 + status->luk*10; //Base chance + make_per = sd->status.job_level*20 + st->dex*10 + st->luk*10; //Base chance switch(nameid){ - case 998: // Iron + case ITEMID_IRON: make_per += 4000+i*500; // Temper Iron bonus: +26/+32/+38/+44/+50 break; - case 999: // Steel + case ITEMID_STEEL: make_per += 3000+i*500; // Temper Steel bonus: +35/+40/+45/+50/+55 break; - case 1000: //Star Crumb + case ITEMID_STAR_CRUMB: make_per = 100000; // Star Crumbs are 100% success crafting rate? (made 1000% so it succeeds even after penalties) [Skotlex] break; default: // Enchanted Stones - make_per += 1000+i*500; // Enchantedstone Craft bonus: +15/+20/+25/+30/+35 + make_per += 1000+i*500; // Enchanted stone Craft bonus: +15/+20/+25/+30/+35 break; } break; case ASC_CDP: - make_per = (2000 + 40*status->dex + 20*status->luk); + make_per = (2000 + 40*st->dex + 20*st->luk); break; case AL_HOLYWATER: /** @@ -16013,39 +16571,39 @@ int skill_produce_mix (struct map_session_data *sd, uint16 skill_id, int nameid, case AM_TWILIGHT3: make_per = pc->checkskill(sd,AM_LEARNINGPOTION)*50 + pc->checkskill(sd,AM_PHARMACY)*300 + sd->status.job_level*20 - + (status->int_/2)*10 + status->dex*10+status->luk*10; + + (st->int_/2)*10 + st->dex*10+st->luk*10; if(homun_alive(sd->hd)) {//Player got a homun - int skill; - if((skill=homun->checkskill(sd->hd,HVAN_INSTRUCT)) > 0) //His homun is a vanil with instruction change - make_per += skill*100; //+1% bonus per level + int skill2_lv; + if((skill2_lv=homun->checkskill(sd->hd,HVAN_INSTRUCT)) > 0) //His homun is a vanil with instruction change + make_per += skill2_lv*100; //+1% bonus per level } switch(nameid){ - case 501: // Red Potion - case 503: // Yellow Potion - case 504: // White Potion + case ITEMID_RED_POTION: + case ITEMID_YELLOW_POTION: + case ITEMID_WHITE_POTION: make_per += (1+rnd()%100)*10 + 2000; break; - case 970: // Alcohol + case ITEMID_ALCHOL: make_per += (1+rnd()%100)*10 + 1000; break; - case 7135: // Bottle Grenade - case 7136: // Acid Bottle - case 7137: // Plant Bottle - case 7138: // Marine Sphere Bottle + case ITEMID_FIRE_BOTTLE: + case ITEMID_ACID_BOTTLE: + case ITEMID_MENEATER_PLANT_BOTTLE: + case ITEMID_MINI_BOTTLE: make_per += (1+rnd()%100)*10; break; - case 546: // Condensed Yellow Potion + case ITEMID_YELLOW_SLIM_POTION: make_per -= (1+rnd()%50)*10; break; - case 547: // Condensed White Potion - case 7139: // Glistening Coat + case ITEMID_WHITE_SLIM_POTION: + case ITEMID_COATING_BOTTLE: make_per -= (1+rnd()%100)*10; break; - //Common items, recieve no bonus or penalty, listed just because they are commonly produced - case 505: // Blue Potion - case 545: // Condensed Red Potion - case 605: // Anodyne - case 606: // Aloevera + //Common items, receive no bonus or penalty, listed just because they are commonly produced + case ITEMID_BLUE_POTION: + case ITEMID_RED_SLIM_POTION: + case ITEMID_ANODYNE: + case ITEMID_ALOEBERA: default: break; } @@ -16061,22 +16619,23 @@ int skill_produce_mix (struct map_session_data *sd, uint16 skill_id, int nameid, case RK_RUNEMASTERY: { int A = 5100 + 200 * pc->checkskill(sd, skill_id); - int B = 10 * status->dex / 3 + (status->luk + sd->status.job_level); + int B = 10 * st->dex / 3 + (st->luk + sd->status.job_level); int C = 100 * cap_value(sd->itemid,0,100); //itemid depend on makerune() int D = 2500; switch (nameid) { //rune rank it_diff 9 craftable rune - case ITEMID_RAIDO: - case ITEMID_THURISAZ: - case ITEMID_HAGALAZ: - case ITEMID_OTHILA: + case ITEMID_RAIDO: + case ITEMID_THURISAZ: + case ITEMID_HAGALAZ: + case ITEMID_OTHILA: D -= 500; //Rank C - case ITEMID_ISA: - case ITEMID_WYRD: + case ITEMID_ISA: + case ITEMID_WYRD: D -= 500; //Rank B - case ITEMID_NAUTHIZ: - case ITEMID_URUZ: + case ITEMID_NAUTHIZ: + case ITEMID_URUZ: D -= 500; //Rank A - case ITEMID_BERKANA: + case ITEMID_BERKANA: + case ITEMID_LUX_ANIMA: D -= 500; //Rank S } make_per = A + B + C - D; @@ -16087,17 +16646,17 @@ int skill_produce_mix (struct map_session_data *sd, uint16 skill_id, int nameid, **/ case GC_CREATENEWPOISON: { - const int min[] = {2, 2, 3, 3, 4, 4, 5, 5, 6, 6}; - const int max[] = {4, 5, 5, 6, 6, 7, 7, 8, 8, 9}; - uint16 lv = pc->checkskill(sd,GC_RESEARCHNEWPOISON); - make_per = 3000 + 500 * lv ; - qty = min[lv] + rand()%(max[lv] - min[lv]); + const int min[10] = {2, 2, 3, 3, 4, 4, 5, 5, 6, 6}; + const int max[10] = {4, 5, 5, 6, 6, 7, 7, 8, 8, 9}; + int lv = max(0, pc->checkskill(sd,GC_RESEARCHNEWPOISON) - 1); + qty = min[lv] + rnd()%(max[lv] - min[lv]); + make_per = 3000 + 500 * lv + st->dex / 3 * 10 + st->luk * 10 + sd->status.job_level * 10; } break; case GN_CHANGEMATERIAL: for(i=0; i<MAX_SKILL_PRODUCE_DB; i++) - if( skill_changematerial_db[i].itemid == nameid ){ - make_per = skill_changematerial_db[i].rate * 10; + if( skill->changematerial_db[i].itemid == nameid ){ + make_per = skill->changematerial_db[i].rate * 10; break; } break; @@ -16107,26 +16666,32 @@ int skill_produce_mix (struct map_session_data *sd, uint16 skill_id, int nameid, difficulty = (620 - 20 * skill_lv);// (620 - 20 * Skill Level) - make_per = status->int_ + status->dex/2 + status->luk + sd->status.job_level + (30+rnd()%120) + // (Caster?s INT) + (Caster?s DEX / 2) + (Caster?s LUK) + (Caster?s Job Level) + Random number between (30 ~ 150) + + make_per = st->int_ + st->dex/2 + st->luk + sd->status.job_level + (30+rnd()%120) + // (Caster?s INT) + (Caster?s DEX / 2) + (Caster?s LUK) + (Caster?s Job Level) + Random number between (30 ~ 150) + (sd->status.base_level-100) + pc->checkskill(sd, AM_LEARNINGPOTION) + pc->checkskill(sd, CR_FULLPROTECTION)*(4+rnd()%6); // (Caster?s Base Level - 100) + (Potion Research x 5) + (Full Chemical Protection Skill Level) x (Random number between 4 ~ 10) switch(nameid){// difficulty factor - case 12422: case 12425: - case 12428: + case ITEMID_HP_INCREASE_POTIONS: + case ITEMID_SP_INCREASE_POTIONS: + case ITEMID_ENRICH_WHITE_POTIONZ: difficulty += 10; break; - case 6212: case 12426: + case ITEMID_BOMB_MUSHROOM_SPORE: + case ITEMID_SP_INCREASE_POTIONM: difficulty += 15; break; - case 13264: case 12423: - case 12427: case 12436: + case ITEMID_BANANA_BOMB: + case ITEMID_HP_INCREASE_POTIONM: + case ITEMID_SP_INCREASE_POTIONL: + case ITEMID_VITATA500: difficulty += 20; break; - case 6210: case 6211: - case 12437: + case ITEMID_SEED_OF_HORNY_PLANT: + case ITEMID_BLOODSUCK_PLANT_SEED: + case ITEMID_ENRICH_CELERMINE_JUICE: difficulty += 30; break; - case 12424: case 12475: + case ITEMID_HP_INCREASE_POTIONL: + case ITEMID_CURE_FREE: difficulty += 40; break; } @@ -16149,22 +16714,27 @@ int skill_produce_mix (struct map_session_data *sd, uint16 skill_id, int nameid, { int difficulty = 30 + rnd()%120; // Random number between (30 ~ 150) - make_per = sd->status.job_level / 4 + status->luk / 2 + status->dex / 3; // (Caster?s Job Level / 4) + (Caster?s LUK / 2) + (Caster?s DEX / 3) + make_per = sd->status.job_level / 4 + st->luk / 2 + st->dex / 3; // (Caster?s Job Level / 4) + (Caster?s LUK / 2) + (Caster?s DEX / 3) qty = ~(5 + rnd()%5) + 1; switch(nameid){// difficulty factor - case 13260: + case ITEMID_APPLE_BOMB: difficulty += 5; break; - case 13261: case 13262: + case ITEMID_COCONUT_BOMB: + case ITEMID_MELON_BOMB: difficulty += 10; break; - case 12429: case 12430: case 12431: - case 12432: case 12433: case 12434: - case 13263: + case ITEMID_SAVAGE_BBQ: + case ITEMID_WUG_BLOOD_COCKTAIL: + case ITEMID_MINOR_BRISKET: + case ITEMID_SIROMA_ICETEA: + case ITEMID_DROCERA_HERB_STEW: + case ITEMID_PETTI_TAIL_NOODLE: + case ITEMID_PINEAPPLE_BOMB: difficulty += 15; break; - case 13264: + case ITEMID_BANANA_BOMB: difficulty += 20; break; } @@ -16197,10 +16767,10 @@ int skill_produce_mix (struct map_session_data *sd, uint16 skill_id, int nameid, else make_per = 1200 * (sd->menuskill_val - 10) + 20 * (sd->status.base_level + 1) - + 20 * (status->dex + 1) + + 20 * (st->dex + 1) + 100 * (rnd()%(30+5*(sd->cook_mastery/400) - (6+sd->cook_mastery/80)) + (6+sd->cook_mastery/80)) - - 400 * (skill_produce_db[idx].itemlv - 11 + 1) - - 10 * (100 - status->luk + 1) + - 400 * (skill->produce_db[idx].itemlv - 11 + 1) + - 10 * (100 - st->luk + 1) - 500 * (num - 1) - 100 * (rnd()%4 + 1); break; @@ -16209,14 +16779,18 @@ int skill_produce_mix (struct map_session_data *sd, uint16 skill_id, int nameid, break; } } else { // Weapon Forging - skill bonuses are straight from kRO website, other things from a jRO calculator [DracoRPG] - make_per = 5000 + sd->status.job_level*20 + status->dex*10 + status->luk*10; // Base + make_per = 5000 + sd->status.job_level*20 + st->dex*10 + st->luk*10; // Base make_per += pc->checkskill(sd,skill_id)*500; // Smithing skills bonus: +5/+10/+15 make_per += pc->checkskill(sd,BS_WEAPONRESEARCH)*100 +((wlv >= 3)? pc->checkskill(sd,BS_ORIDEOCON)*100:0); // Weaponry Research bonus: +1/+2/+3/+4/+5/+6/+7/+8/+9/+10, Oridecon Research bonus (custom): +1/+2/+3/+4/+5 make_per -= (ele?2000:0) + sc*1500 + (wlv>1?wlv*1000:0); // Element Stone: -20%, Star Crumb: -15% each, Weapon level malus: -0/-20/-30 - if(pc->search_inventory(sd,989) > 0) make_per+= 1000; // Emperium Anvil: +10 - else if(pc->search_inventory(sd,988) > 0) make_per+= 500; // Golden Anvil: +5 - else if(pc->search_inventory(sd,987) > 0) make_per+= 300; // Oridecon Anvil: +3 - else if(pc->search_inventory(sd,986) > 0) make_per+= 0; // Anvil: +0? + if (pc->search_inventory(sd,ITEMID_EMPERIUM_ANVIL) != INDEX_NOT_FOUND) + make_per+= 1000; // +10 + else if(pc->search_inventory(sd,ITEMID_GOLDEN_ANVIL) != INDEX_NOT_FOUND) + make_per+= 500; // +5 + else if(pc->search_inventory(sd,ITEMID_ORIDECON_ANVIL) != INDEX_NOT_FOUND) + make_per+= 300; // +3 + else if(pc->search_inventory(sd,ITEMID_ANVIL) != INDEX_NOT_FOUND) + make_per+= 0; // +0? if(battle_config.wp_rate != 100) make_per = make_per * battle_config.wp_rate / 100; } @@ -16298,7 +16872,7 @@ int skill_produce_mix (struct map_session_data *sd, uint16 skill_id, int nameid, } if (rnd()%10000 < make_per || qty == 1) { //Success tmp_item.amount++; - if(nameid < 545 || nameid > 547) + if(nameid < ITEMID_RED_SLIM_POTION || nameid > ITEMID_WHITE_SLIM_POTION) continue; if( skill_id != AM_PHARMACY && skill_id != AM_TWILIGHT1 && @@ -16349,11 +16923,11 @@ int skill_produce_mix (struct map_session_data *sd, uint16 skill_id, int nameid, clif->misceffect(&sd->bl,5); break; default: //Those that don't require a skill? - if( skill_produce_db[idx].itemlv > 10 && skill_produce_db[idx].itemlv <= 20) + if( skill->produce_db[idx].itemlv > 10 && skill->produce_db[idx].itemlv <= 20) { //Cooking items. clif->specialeffect(&sd->bl, 608, AREA); if( sd->cook_mastery < 1999 ) - pc_setglobalreg(sd, "COOK_MASTERY",sd->cook_mastery + ( 1 << ( (skill_produce_db[idx].itemlv - 11) / 2 ) ) * 5); + pc_setglobalreg(sd, script->add_str("COOK_MASTERY"),sd->cook_mastery + ( 1 << ( (skill->produce_db[idx].itemlv - 11) / 2 ) ) * 5); } break; } @@ -16361,13 +16935,13 @@ int skill_produce_mix (struct map_session_data *sd, uint16 skill_id, int nameid, if ( skill_id == GN_CHANGEMATERIAL && tmp_item.amount) { //Success int j, k = 0; for(i=0; i<MAX_SKILL_PRODUCE_DB; i++) - if( skill_changematerial_db[i].itemid == nameid ){ + if( skill->changematerial_db[i].itemid == nameid ){ for(j=0; j<5; j++){ - if( rnd()%1000 < skill_changematerial_db[i].qty_rate[j] ){ - tmp_item.amount = qty * skill_changematerial_db[i].qty[j]; + if( rnd()%1000 < skill->changematerial_db[i].qty_rate[j] ){ + tmp_item.amount = qty * skill->changematerial_db[i].qty[j]; if((flag = pc->additem(sd,&tmp_item,tmp_item.amount,LOG_TYPE_PRODUCE))) { clif->additem(sd,0,0,flag); - iMap->addflooritem(&tmp_item,tmp_item.amount,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0); + map->addflooritem(&tmp_item,tmp_item.amount,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0); } k++; } @@ -16381,7 +16955,7 @@ int skill_produce_mix (struct map_session_data *sd, uint16 skill_id, int nameid, } else if (tmp_item.amount) { //Success if((flag = pc->additem(sd,&tmp_item,tmp_item.amount,LOG_TYPE_PRODUCE))) { clif->additem(sd,0,0,flag); - iMap->addflooritem(&tmp_item,tmp_item.amount,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0); + map->addflooritem(&tmp_item,tmp_item.amount,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0); } if( skill_id == GN_MIX_COOKING || skill_id == GN_MAKEBOMB || skill_id == GN_S_PHARMACY ) clif->msg_skill(sd,skill_id,0x627); @@ -16421,7 +16995,13 @@ int skill_produce_mix (struct map_session_data *sd, uint16 skill_id, int nameid, break; case GN_MIX_COOKING: { struct item tmp_item; - const int compensation[5] = {13265, 13266, 13267, 12435, 13268}; + const int compensation[5] = { + ITEMID_BLACK_LUMP, + ITEMID_BLACK_HARD_LUMP, + ITEMID_VERY_HARD_LUMP, + ITEMID_BLACK_THING, + ITEMID_MYSTERIOUS_POWDER, + }; int rate = rnd()%500; memset(&tmp_item,0,sizeof(tmp_item)); if( rate < 50) i = 4; @@ -16433,7 +17013,7 @@ int skill_produce_mix (struct map_session_data *sd, uint16 skill_id, int nameid, tmp_item.identify = 1; if( pc->additem(sd,&tmp_item,tmp_item.amount,LOG_TYPE_PRODUCE) ) { clif->additem(sd,0,0,flag); - iMap->addflooritem(&tmp_item,tmp_item.amount,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0); + map->addflooritem(&tmp_item,tmp_item.amount,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0); } clif->msg_skill(sd,skill_id,0x628); } @@ -16444,11 +17024,11 @@ int skill_produce_mix (struct map_session_data *sd, uint16 skill_id, int nameid, clif->msg_skill(sd,skill_id,0x628); break; default: - if( skill_produce_db[idx].itemlv > 10 && skill_produce_db[idx].itemlv <= 20 ) + if( skill->produce_db[idx].itemlv > 10 && skill->produce_db[idx].itemlv <= 20 ) { //Cooking items. clif->specialeffect(&sd->bl, 609, AREA); if( sd->cook_mastery > 0 ) - pc_setglobalreg(sd, "COOK_MASTERY", sd->cook_mastery - ( 1 << ((skill_produce_db[idx].itemlv - 11) / 2) ) - ( ( ( 1 << ((skill_produce_db[idx].itemlv - 11) / 2) ) >> 1 ) * 3 )); + pc_setglobalreg(sd, script->add_str("COOK_MASTERY"), sd->cook_mastery - ( 1 << ((skill->produce_db[idx].itemlv - 11) / 2) ) - ( ( ( 1 << ((skill->produce_db[idx].itemlv - 11) / 2) ) >> 1 ) * 3 )); } } } @@ -16466,20 +17046,20 @@ int skill_arrow_create (struct map_session_data *sd, int nameid) return 1; for(i=0;i<MAX_SKILL_ARROW_DB;i++) - if(nameid == skill_arrow_db[i].nameid) { + if(nameid == skill->arrow_db[i].nameid) { index = i; break; } - if(index < 0 || (j = pc->search_inventory(sd,nameid)) < 0) + if(index < 0 || (j = pc->search_inventory(sd,nameid)) == INDEX_NOT_FOUND) return 1; pc->delitem(sd,j,1,0,0,LOG_TYPE_PRODUCE); for(i=0;i<MAX_ARROW_RESOURCE;i++) { memset(&tmp_item,0,sizeof(tmp_item)); tmp_item.identify = 1; - tmp_item.nameid = skill_arrow_db[index].cre_id[i]; - tmp_item.amount = skill_arrow_db[index].cre_amount[i]; + tmp_item.nameid = skill->arrow_db[index].cre_id[i]; + tmp_item.amount = skill->arrow_db[index].cre_amount[i]; if(battle_config.produce_item_name_input&0x4) { tmp_item.card[0]=CARD0_CREATE; tmp_item.card[1]=0; @@ -16490,7 +17070,7 @@ int skill_arrow_create (struct map_session_data *sd, int nameid) continue; if((flag = pc->additem(sd,&tmp_item,tmp_item.amount,LOG_TYPE_PRODUCE))) { clif->additem(sd,0,0,flag); - iMap->addflooritem(&tmp_item,tmp_item.amount,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0); + map->addflooritem(&tmp_item,tmp_item.amount,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0); } } @@ -16500,34 +17080,35 @@ int skill_poisoningweapon( struct map_session_data *sd, int nameid) { sc_type type; int chance, i; nullpo_ret(sd); - if( nameid <= 0 || (i = pc->search_inventory(sd,nameid)) < 0 || pc->delitem(sd,i,1,0,0,LOG_TYPE_CONSUME) ) { + if( nameid <= 0 || (i = pc->search_inventory(sd,nameid)) == INDEX_NOT_FOUND || pc->delitem(sd,i,1,0,0,LOG_TYPE_CONSUME) ) { clif->skill_fail(sd,GC_POISONINGWEAPON,USESKILL_FAIL_LEVEL,0); return 0; } switch( nameid ) { // t_lv used to take duration from skill->get_time2 - case PO_PARALYSE: type = SC_PARALYSE; break; - case PO_PYREXIA: type = SC_PYREXIA; break; - case PO_DEATHHURT: type = SC_DEATHHURT; break; - case PO_LEECHESEND: type = SC_LEECHESEND; break; - case PO_VENOMBLEED: type = SC_VENOMBLEED; break; - case PO_TOXIN: type = SC_TOXIN; break; - case PO_MAGICMUSHROOM: type = SC_MAGICMUSHROOM; break; - case PO_OBLIVIONCURSE: type = SC_OBLIVIONCURSE; break; + case ITEMID_POISON_PARALYSIS: type = SC_PARALYSE; break; + case ITEMID_POISON_FEVER: type = SC_PYREXIA; break; + case ITEMID_POISON_CONTAMINATION: type = SC_DEATHHURT; break; + case ITEMID_POISON_LEECH: type = SC_LEECHESEND; break; + case ITEMID_POISON_FATIGUE: type = SC_VENOMBLEED; break; + case ITEMID_POISON_NUMB: type = SC_TOXIN; break; + case ITEMID_POISON_LAUGHING: type = SC_MAGICMUSHROOM; break; + case ITEMID_POISON_OBLIVION: type = SC_OBLIVIONCURSE; break; default: clif->skill_fail(sd,GC_POISONINGWEAPON,USESKILL_FAIL_LEVEL,0); return 0; } + status_change_end(&sd->bl, SC_POISONINGWEAPON, -1);//Status must be forced to end so that a new poison will be applied if a player decides to change poisons. [Rytech] chance = 2 + 2 * sd->menuskill_val; // 2 + 2 * skill_lv - sc_start4(&sd->bl, SC_POISONINGWEAPON, 100, pc->checkskill(sd, GC_RESEARCHNEWPOISON), //in Aegis it store the level of GC_RESEARCHNEWPOISON in val1 + sc_start4(&sd->bl, &sd->bl, SC_POISONINGWEAPON, 100, pc->checkskill(sd, GC_RESEARCHNEWPOISON), //in Aegis it store the level of GC_RESEARCHNEWPOISON in val1 type, chance, 0, skill->get_time(GC_POISONINGWEAPON, sd->menuskill_val)); return 0; } void skill_toggle_magicpower(struct block_list *bl, uint16 skill_id) { - struct status_change *sc = status_get_sc(bl); + struct status_change *sc = status->get_sc(bl); // non-offensive and non-magic skills do not affect the status if (skill->get_nk(skill_id)&NK_NO_DAMAGE || !(skill->get_type(skill_id)&BF_MAGIC)) @@ -16538,7 +17119,7 @@ void skill_toggle_magicpower(struct block_list *bl, uint16 skill_id) { status_change_end(bl, SC_MAGICPOWER, INVALID_TIMER); } else { sc->data[SC_MAGICPOWER]->val4 = 1; - status_calc_bl(bl, status_sc2scb_flag(SC_MAGICPOWER)); + status_calc_bl(bl, status->sc2scb_flag(SC_MAGICPOWER)); #ifndef RENEWAL if(bl->type == BL_PC){// update current display. clif->updatestatus(((TBL_PC *)bl),SP_MATK1); @@ -16556,8 +17137,9 @@ int skill_magicdecoy(struct map_session_data *sd, int nameid) { nullpo_ret(sd); skill_id = sd->menuskill_val; - if( nameid <= 0 || !itemdb_is_element(nameid) || (i = pc->search_inventory(sd,nameid)) < 0 || !skill_id || pc->delitem(sd,i,1,0,0,LOG_TYPE_CONSUME) ) - { + if (nameid <= 0 || !itemdb_is_element(nameid) || (i = pc->search_inventory(sd,nameid)) == INDEX_NOT_FOUND + || !skill_id || pc->delitem(sd,i,1,0,0,LOG_TYPE_CONSUME) + ) { clif->skill_fail(sd,NC_MAGICDECOY,USESKILL_FAIL_LEVEL,0); return 0; } @@ -16569,17 +17151,17 @@ int skill_magicdecoy(struct map_session_data *sd, int nameid) { sd->sc.comet_x = sd->sc.comet_y = 0; sd->menuskill_val = 0; - class_ = (nameid == 990 || nameid == 991) ? 2043 + nameid - 990 : (nameid == 992) ? 2046 : 2045; + class_ = (nameid == ITEMID_BOODY_RED || nameid == ITEMID_CRYSTAL_BLUE) ? 2043 + nameid - ITEMID_BOODY_RED : (nameid == ITEMID_WIND_OF_VERDURE) ? 2046 : 2045; - md = mob_once_spawn_sub(&sd->bl, sd->bl.m, x, y, sd->status.name, class_, "", SZ_SMALL, AI_NONE); + md = mob->once_spawn_sub(&sd->bl, sd->bl.m, x, y, sd->status.name, class_, "", SZ_MEDIUM, AI_NONE); if( md ) { md->master_id = sd->bl.id; md->special_state.ai = AI_FLORA; if( md->deletetimer != INVALID_TIMER ) - iTimer->delete_timer(md->deletetimer, mob_timer_delete); - md->deletetimer = iTimer->add_timer (iTimer->gettick() + skill->get_time(NC_MAGICDECOY,skill_id), mob_timer_delete, md->bl.id, 0); - mob_spawn(md); + timer->delete(md->deletetimer, mob->timer_delete); + md->deletetimer = timer->add(timer->gettick() + skill->get_time(NC_MAGICDECOY,skill_id), mob->timer_delete, md->bl.id, 0); + mob->spawn(md); md->status.matk_min = md->status.matk_max = 250 + (50 * skill_id); } @@ -16593,7 +17175,7 @@ int skill_spellbook (struct map_session_data *sd, int nameid) { nullpo_ret(sd); - sc = status_get_sc(&sd->bl); + sc = status->get_sc(&sd->bl); status_change_end(&sd->bl, SC_STOP, INVALID_TIMER); for(i=SC_SPELLBOOK1; i <= SC_SPELLBOOK7; i++) if( sc && !sc->data[i] ) break; @@ -16603,18 +17185,18 @@ int skill_spellbook (struct map_session_data *sd, int nameid) { return 0; } - ARR_FIND(0,MAX_SKILL_SPELLBOOK_DB,i,skill_spellbook_db[i].nameid == nameid); // Search for information of this item + ARR_FIND(0,MAX_SKILL_SPELLBOOK_DB,i,skill->spellbook_db[i].nameid == nameid); // Search for information of this item if( i == MAX_SKILL_SPELLBOOK_DB ) return 0; - if( !pc->checkskill(sd, (skill_id = skill_spellbook_db[i].skill_id)) ) + if( !pc->checkskill(sd, (skill_id = skill->spellbook_db[i].skill_id)) ) { // User don't know the skill - sc_start(&sd->bl, SC_SLEEP, 100, 1, skill->get_time(WL_READING_SB, pc->checkskill(sd,WL_READING_SB))); + sc_start(&sd->bl, &sd->bl, SC_SLEEP, 100, 1, skill->get_time(WL_READING_SB, pc->checkskill(sd,WL_READING_SB))); clif->skill_fail(sd, WL_READING_SB, USESKILL_FAIL_SPELLBOOK_DIFFICULT_SLEEP, 0); return 0; } max_preserve = 4 * pc->checkskill(sd, WL_FREEZE_SP) + (status_get_int(&sd->bl) + sd->status.base_level) / 10; - point = skill_spellbook_db[i].point; + point = skill->spellbook_db[i].point; if( sc && sc->data[SC_READING_SB] ) { if( (sc->data[SC_READING_SB]->val2 + point) > max_preserve ) { @@ -16624,13 +17206,13 @@ int skill_spellbook (struct map_session_data *sd, int nameid) { for(i = SC_SPELLBOOK7; i >= SC_SPELLBOOK1; i--){ // This is how official saves spellbook. [malufett] if( !sc->data[i] ){ sc->data[SC_READING_SB]->val2 += point; // increase points - sc_start4(&sd->bl, (sc_type)i, 100, skill_id, pc->checkskill(sd,skill_id), point, 0, INVALID_TIMER); + sc_start4(&sd->bl,&sd->bl, (sc_type)i, 100, skill_id, pc->checkskill(sd,skill_id), point, 0, INVALID_TIMER); break; } } }else{ - sc_start2(&sd->bl, SC_READING_SB, 100, 0, point, INVALID_TIMER); - sc_start4(&sd->bl, SC_SPELLBOOK7, 100, skill_id, pc->checkskill(sd,skill_id), point, 0, INVALID_TIMER); + sc_start2(&sd->bl,&sd->bl, SC_READING_SB, 100, 0, point, INVALID_TIMER); + sc_start4(&sd->bl,&sd->bl, SC_SPELLBOOK7, 100, skill_id, pc->checkskill(sd,skill_id), point, 0, INVALID_TIMER); } return 1; @@ -16655,7 +17237,7 @@ int skill_select_menu(struct map_session_data *sd,uint16 skill_id) { lv = (aslvl + 1) / 2; // The level the skill will be autocasted lv = min(lv,sd->status.skill[idx].lv); prob = (aslvl == 10) ? 15 : (32 - 2 * aslvl); // Probability at level 10 was increased to 15. - sc_start4(&sd->bl,SC__AUTOSHADOWSPELL,100,id,lv,prob,0,skill->get_time(SC_AUTOSHADOWSPELL,aslvl)); + sc_start4(&sd->bl,&sd->bl,SC__AUTOSHADOWSPELL,100,id,lv,prob,0,skill->get_time(SC_AUTOSHADOWSPELL,aslvl)); return 0; } int skill_elementalanalysis(struct map_session_data* sd, int n, uint16 skill_lv, unsigned short* item_list) { @@ -16685,15 +17267,15 @@ int skill_elementalanalysis(struct map_session_data* sd, int n, uint16 skill_lv, switch( nameid ) { // Level 1 - case 994: product = 990; break; // Flame Heart -> Red Blood. - case 995: product = 991; break; // Mystic Frozen -> Crystal Blue. - case 996: product = 992; break; // Rough Wind -> Wind of Verdure. - case 997: product = 993; break; // Great Nature -> Green Live. + case ITEMID_FLAME_HEART: product = ITEMID_BOODY_RED; break; + case ITEMID_MISTIC_FROZEN: product = ITEMID_CRYSTAL_BLUE; break; + case ITEMID_ROUGH_WIND: product = ITEMID_WIND_OF_VERDURE; break; + case ITEMID_GREAT_NATURE: product = ITEMID_YELLOW_LIVE; break; // Level 2 - case 990: product = 994; break; // Red Blood -> Flame Heart. - case 991: product = 995; break; // Crystal Blue -> Mystic Frozen. - case 992: product = 996; break; // Wind of Verdure -> Rough Wind. - case 993: product = 997; break; // Green Live -> Great Nature. + case ITEMID_BOODY_RED: product = ITEMID_FLAME_HEART; break; + case ITEMID_CRYSTAL_BLUE: product = ITEMID_MISTIC_FROZEN; break; + case ITEMID_WIND_OF_VERDURE: product = ITEMID_ROUGH_WIND; break; + case ITEMID_YELLOW_LIVE: product = ITEMID_GREAT_NATURE; break; default: clif->skill_fail(sd,SO_EL_ANALYSIS,USESKILL_FAIL_LEVEL,0); return 1; @@ -16718,7 +17300,7 @@ int skill_elementalanalysis(struct map_session_data* sd, int n, uint16 skill_lv, if( tmp_item.amount ) { if( (flag = pc->additem(sd,&tmp_item,tmp_item.amount,LOG_TYPE_CONSUME)) ) { clif->additem(sd,0,0,flag); - iMap->addflooritem(&tmp_item,tmp_item.amount,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0); + map->addflooritem(&tmp_item,tmp_item.amount,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0); } } @@ -16735,13 +17317,13 @@ int skill_changematerial(struct map_session_data *sd, int n, unsigned short *ite // Search for objects that can be created. for( i = 0; i < MAX_SKILL_PRODUCE_DB; i++ ) { - if( skill_produce_db[i].itemlv == 26 ) { + if( skill->produce_db[i].itemlv == 26 ) { p = 0; do { c = 0; // Verification of overlap between the objects required and the list submitted. for( j = 0; j < MAX_PRODUCE_RESOURCE; j++ ) { - if( skill_produce_db[i].mat_id[j] > 0 ) { + if( skill->produce_db[i].mat_id[j] > 0 ) { for( k = 0; k < n; k++ ) { int idx = item_list[k*2+0]-2; nameid = sd->status.inventory[idx].nameid; @@ -16750,8 +17332,8 @@ int skill_changematerial(struct map_session_data *sd, int n, unsigned short *ite clif->msg_skill(sd,GN_CHANGEMATERIAL,0x62D); return 0; } - if( nameid == skill_produce_db[i].mat_id[j] && (amount-p*skill_produce_db[i].mat_amount[j]) >= skill_produce_db[i].mat_amount[j] - && (amount-p*skill_produce_db[i].mat_amount[j])%skill_produce_db[i].mat_amount[j] == 0 ) // must be in exact amount + if( nameid == skill->produce_db[i].mat_id[j] && (amount-p*skill->produce_db[i].mat_amount[j]) >= skill->produce_db[i].mat_amount[j] + && (amount-p*skill->produce_db[i].mat_amount[j])%skill->produce_db[i].mat_amount[j] == 0 ) // must be in exact amount c++; // match } } @@ -16762,7 +17344,7 @@ int skill_changematerial(struct map_session_data *sd, int n, unsigned short *ite } while(n == j && c == n); p--; if ( p > 0 ) { - skill->produce_mix(sd,GN_CHANGEMATERIAL,skill_produce_db[i].nameid,0,0,0,p); + skill->produce_mix(sd,GN_CHANGEMATERIAL,skill->produce_db[i].nameid,0,0,0,p); return 1; } } @@ -16776,27 +17358,29 @@ int skill_changematerial(struct map_session_data *sd, int n, unsigned short *ite /** * for Royal Guard's LG_TRAMPLE **/ -int skill_destroy_trap( struct block_list *bl, va_list ap ) { +int skill_destroy_trap(struct block_list *bl, va_list ap) { struct skill_unit *su = (struct skill_unit *)bl; struct skill_unit_group *sg; - unsigned int tick; + int64 tick; nullpo_ret(su); - tick = va_arg(ap, unsigned int); + tick = va_arg(ap, int64); if (su->alive && (sg = su->group) && skill->get_inf2(sg->skill_id)&INF2_TRAP) { switch( sg->unit_id ) { - case UNT_LANDMINE: case UNT_CLAYMORETRAP: + case UNT_FIRINGTRAP: + case UNT_ICEBOUNDTRAP: + map->foreachinrange(skill->trap_splash,&su->bl, skill->get_splash(sg->skill_id, sg->skill_lv), sg->bl_flag|BL_SKILL|~BCT_SELF, &su->bl,tick); + break; + case UNT_LANDMINE: case UNT_BLASTMINE: case UNT_SHOCKWAVE: case UNT_SANDMAN: case UNT_FLASHER: case UNT_FREEZINGTRAP: case UNT_CLUSTERBOMB: - case UNT_FIRINGTRAP: - case UNT_ICEBOUNDTRAP: - iMap->foreachinrange(skill->trap_splash,&su->bl, skill->get_splash(sg->skill_id, sg->skill_lv), sg->bl_flag, &su->bl,tick); + map->foreachinrange(skill->trap_splash,&su->bl, skill->get_splash(sg->skill_id, sg->skill_lv), sg->bl_flag, &su->bl,tick); break; } // Traps aren't recovered. @@ -16807,53 +17391,62 @@ int skill_destroy_trap( struct block_list *bl, va_list ap ) { /*========================================== * *------------------------------------------*/ -int skill_blockpc_end(int tid, unsigned int tick, int id, intptr_t data) { - struct map_session_data *sd = iMap->id2sd(id); +int skill_blockpc_end(int tid, int64 tick, int id, intptr_t data) { + struct map_session_data *sd = map->id2sd(id); struct skill_cd * cd = NULL; if (data <= 0 || data >= MAX_SKILL) return 0; - if (!sd) return 0; - if (sd->blockskill[data] != (0x1|(tid&0xFE))) return 0; - - if( ( cd = idb_get(skillcd_db,sd->status.char_id) ) ) { - int i,cursor; - ARR_FIND( 0, cd->cursor+1, cursor, cd->skidx[cursor] == data ); - cd->duration[cursor] = 0; - cd->skidx[cursor] = 0; - cd->nameid[cursor] = 0; - // compact the cool down list - for( i = 0, cursor = 0; i < cd->cursor; i++ ) { - if( cd->duration[i] == 0 ) - continue; - if( cursor != i ) { - cd->duration[cursor] = cd->duration[i]; - cd->skidx[cursor] = cd->skidx[i]; - cd->nameid[cursor] = cd->nameid[i]; + if (!sd || !sd->blockskill[data]) + return 0; + + if( ( cd = idb_get(skill->cd_db,sd->status.char_id) ) ) { + int i; + + for( i = 0; i < cd->cursor; i++ ) { + if( cd->entry[i]->skidx == data ) + break; + } + + if (i == cd->cursor) { + ShowError("skill_blockpc_end: '%s': no data found for '%"PRIdPTR"'\n", sd->status.name, data); + } else { + int cursor = 0; + + ers_free(skill->cd_entry_ers, cd->entry[i]); + + cd->entry[i] = NULL; + + for( i = 0, cursor = 0; i < cd->cursor; i++ ) { + if( !cd->entry[i] ) + continue; + if( cursor != i ) + cd->entry[cursor] = cd->entry[i]; + cursor++; + } + + if( (cd->cursor = cursor) == 0 ) { + idb_remove(skill->cd_db,sd->status.char_id); + ers_free(skill->cd_ers, cd); } - cursor++; } - if( cursor == 0 ) - idb_remove(skillcd_db,sd->status.char_id); - else - cd->cursor = cursor; } - - sd->blockskill[data] = 0; + + sd->blockskill[data] = false; return 1; } /** * flags a singular skill as being blocked from persistent usage. * @param sd the player the skill delay affects - * @param skill_id the skill which should be delayed + * @param skill_id the skill which should be delayed * @param tick the length of time the delay should last - * @param load whether this assignment is being loaded upon player login * @return 0 if successful, -1 otherwise */ -int skill_blockpc_start_(struct map_session_data *sd, uint16 skill_id, int tick, bool load) { +int skill_blockpc_start_(struct map_session_data *sd, uint16 skill_id, int tick) { struct skill_cd* cd = NULL; uint16 idx = skill->get_index(skill_id); + int64 now = timer->gettick(); nullpo_retr (-1, sd); @@ -16861,32 +17454,61 @@ int skill_blockpc_start_(struct map_session_data *sd, uint16 skill_id, int tick, return -1; if (tick < 1) { - sd->blockskill[idx] = 0; + sd->blockskill[idx] = false; return -1; } if( battle_config.display_status_timers ) clif->skill_cooldown(sd, skill_id, tick); - - if( !load ) {// not being loaded initially so ensure the skill delay is recorded - if( !(cd = idb_get(skillcd_db,sd->status.char_id)) ) {// create a new skill cooldown object for map storage - CREATE( cd, struct skill_cd, 1 ); - idb_put( skillcd_db, sd->status.char_id, cd ); + + if( !(cd = idb_get(skill->cd_db,sd->status.char_id)) ) {// create a new skill cooldown object for map storage + cd = ers_alloc(skill->cd_ers, struct skill_cd); + + idb_put( skill->cd_db, sd->status.char_id, cd ); + } else { + int i; + + for(i = 0; i < MAX_SKILL_TREE; i++) { + if( cd->entry[i] && cd->entry[i]->skidx == idx ) + break; } - - // record the skill duration in the database map - cd->duration[cd->cursor] = tick; - cd->skidx[cd->cursor] = idx; - cd->nameid[cd->cursor] = skill_id; - cd->cursor++; + + if( i != MAX_SKILL_TREE ) {/* duplicate, update necessary */ + cd->entry[i]->duration = tick; +#if PACKETVER >= 20120604 + cd->entry[i]->total = tick; +#endif + cd->entry[i]->started = now; + timer->settick(cd->entry[i]->timer,now+tick); + return 0; + } + + } + + if( cd->cursor == MAX_SKILL_TREE ) { + ShowError("skill_blockpc_start: '%s' got over '%d' skill cooldowns, no room to save!\n",sd->status.name,MAX_SKILL_TREE); + return -1; } + + cd->entry[cd->cursor] = ers_alloc(skill->cd_entry_ers,struct skill_cd_entry); + + cd->entry[cd->cursor]->duration = tick; +#if PACKETVER >= 20120604 + cd->entry[cd->cursor]->total = tick; +#endif + cd->entry[cd->cursor]->skidx = idx; + cd->entry[cd->cursor]->skill_id = skill_id; + cd->entry[cd->cursor]->started = now; + cd->entry[cd->cursor]->timer = timer->add(now+tick,skill->blockpc_end,sd->bl.id,idx); + + cd->cursor++; - sd->blockskill[idx] = 0x1|(0xFE&iTimer->add_timer(iTimer->gettick()+tick,skill->blockpc_end,sd->bl.id,idx)); + sd->blockskill[idx] = true; return 0; } -int skill_blockhomun_end(int tid, unsigned int tick, int id, intptr_t data) { //[orn] - struct homun_data *hd = (TBL_HOM*) iMap->id2bl(id); +int skill_blockhomun_end(int tid, int64 tick, int id, intptr_t data) { // [orn] + struct homun_data *hd = (TBL_HOM*)map->id2bl(id); if (data <= 0 || data >= MAX_SKILL) return 0; if (hd) hd->blockskill[data] = 0; @@ -16894,7 +17516,7 @@ int skill_blockhomun_end(int tid, unsigned int tick, int id, intptr_t data) { // return 1; } -int skill_blockhomun_start(struct homun_data *hd, uint16 skill_id, int tick) { //[orn] +int skill_blockhomun_start(struct homun_data *hd, uint16 skill_id, int tick) { // [orn] uint16 idx = skill->get_index(skill_id); nullpo_retr (-1, hd); @@ -16907,11 +17529,11 @@ int skill_blockhomun_start(struct homun_data *hd, uint16 skill_id, int tick) { / return -1; } hd->blockskill[idx] = 1; - return iTimer->add_timer(iTimer->gettick() + tick, skill->blockhomun_end, hd->bl.id, idx); + return timer->add(timer->gettick() + tick, skill->blockhomun_end, hd->bl.id, idx); } -int skill_blockmerc_end(int tid, unsigned int tick, int id, intptr_t data) {//[orn] - struct mercenary_data *md = (TBL_MER*)iMap->id2bl(id); +int skill_blockmerc_end(int tid, int64 tick, int id, intptr_t data) {// [orn] + struct mercenary_data *md = (TBL_MER*)map->id2bl(id); if( data <= 0 || data >= MAX_SKILL ) return 0; if( md ) md->blockskill[data] = 0; @@ -16932,20 +17554,20 @@ int skill_blockmerc_start(struct mercenary_data *md, uint16 skill_id, int tick) return -1; } md->blockskill[idx] = 1; - return iTimer->add_timer(iTimer->gettick() + tick, skill->blockmerc_end, md->bl.id, idx); + return timer->add(timer->gettick() + tick, skill->blockmerc_end, md->bl.id, idx); } /** * Adds a new skill unit entry for this player to recast after map load **/ void skill_usave_add(struct map_session_data * sd, uint16 skill_id, uint16 skill_lv) { - struct skill_usave * sus = NULL; + struct skill_unit_save * sus = NULL; - if( idb_exists(skillusave_db,sd->status.char_id) ) { - idb_remove(skillusave_db,sd->status.char_id); + if( idb_exists(skill->usave_db,sd->status.char_id) ) { + idb_remove(skill->usave_db,sd->status.char_id); } - CREATE( sus, struct skill_usave, 1 ); - idb_put( skillusave_db, sd->status.char_id, sus ); + CREATE( sus, struct skill_unit_save, 1 ); + idb_put( skill->usave_db, sd->status.char_id, sus ); sus->skill_id = skill_id; sus->skill_lv = skill_lv; @@ -16953,15 +17575,15 @@ void skill_usave_add(struct map_session_data * sd, uint16 skill_id, uint16 skill return; } void skill_usave_trigger(struct map_session_data *sd) { - struct skill_usave * sus = NULL; + struct skill_unit_save * sus = NULL; - if( ! (sus = idb_get(skillusave_db,sd->status.char_id)) ) { + if( ! (sus = idb_get(skill->usave_db,sd->status.char_id)) ) { return; } skill->unitsetting(&sd->bl,sus->skill_id,sus->skill_lv,sd->bl.x,sd->bl.y,0); - idb_remove(skillusave_db,sd->status.char_id); + idb_remove(skill->usave_db,sd->status.char_id); return; } @@ -17029,25 +17651,27 @@ int skill_split_atoi (char *str, int *val) { void skill_init_unit_layout (void) { int i,j,size,pos = 0; - memset(skill_unit_layout,0,sizeof(skill_unit_layout)); + //when != it was already cleared during skill_defaults() no need to repeat + if( runflag == MAPSERVER_ST_RUNNING ) + memset(skill->unit_layout,0,sizeof(skill->unit_layout)); // standard square layouts go first for (i=0; i<=MAX_SQUARE_LAYOUT; i++) { size = i*2+1; - skill_unit_layout[i].count = size*size; + skill->unit_layout[i].count = size*size; for (j=0; j<size*size; j++) { - skill_unit_layout[i].dx[j] = (j%size-i); - skill_unit_layout[i].dy[j] = (j/size-i); + skill->unit_layout[i].dx[j] = (j%size-i); + skill->unit_layout[i].dy[j] = (j/size-i); } } // afterwards add special ones pos = i; for (i=0;i<MAX_SKILL_DB;i++) { - if (!skill_db[i].unit_id[0] || skill_db[i].unit_layout_type[0] != -1) + if (!skill->db[i].unit_id[0] || skill->db[i].unit_layout_type[0] != -1) continue; - switch (skill_db[i].nameid) { + switch (skill->db[i].nameid) { case MG_FIREWALL: case WZ_ICEWALL: case WL_EARTHSTRAIN://Warlock @@ -17061,9 +17685,9 @@ void skill_init_unit_layout (void) { static const int dy[]={ -2,-2,-2,-1,-1,-1,-1,-1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2}; - skill_unit_layout[pos].count = 21; - memcpy(skill_unit_layout[pos].dx,dx,sizeof(dx)); - memcpy(skill_unit_layout[pos].dy,dy,sizeof(dy)); + skill->unit_layout[pos].count = 21; + memcpy(skill->unit_layout[pos].dx,dx,sizeof(dx)); + memcpy(skill->unit_layout[pos].dy,dy,sizeof(dy)); } break; case PR_MAGNUS: { @@ -17075,18 +17699,18 @@ void skill_init_unit_layout (void) { -3,-3,-3,-2,-2,-2,-1,-1,-1,-1, -1,-1,-1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 3, 3, 3}; - skill_unit_layout[pos].count = 33; - memcpy(skill_unit_layout[pos].dx,dx,sizeof(dx)); - memcpy(skill_unit_layout[pos].dy,dy,sizeof(dy)); + skill->unit_layout[pos].count = 33; + memcpy(skill->unit_layout[pos].dx,dx,sizeof(dx)); + memcpy(skill->unit_layout[pos].dy,dy,sizeof(dy)); } break; case MH_POISON_MIST: case AS_VENOMDUST: { static const int dx[] = {-1, 0, 0, 0, 1}; static const int dy[] = { 0,-1, 0, 1, 0}; - skill_unit_layout[pos].count = 5; - memcpy(skill_unit_layout[pos].dx,dx,sizeof(dx)); - memcpy(skill_unit_layout[pos].dy,dy,sizeof(dy)); + skill->unit_layout[pos].count = 5; + memcpy(skill->unit_layout[pos].dx,dx,sizeof(dx)); + memcpy(skill->unit_layout[pos].dy,dy,sizeof(dy)); } break; case CR_GRANDCROSS: @@ -17099,9 +17723,9 @@ void skill_init_unit_layout (void) { -4,-3,-2,-2,-2,-1,-1,-1,-1,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 3, 4}; - skill_unit_layout[pos].count = 29; - memcpy(skill_unit_layout[pos].dx,dx,sizeof(dx)); - memcpy(skill_unit_layout[pos].dy,dy,sizeof(dy)); + skill->unit_layout[pos].count = 29; + memcpy(skill->unit_layout[pos].dx,dx,sizeof(dx)); + memcpy(skill->unit_layout[pos].dy,dy,sizeof(dy)); } break; case PF_FOGWALL: { @@ -17109,9 +17733,9 @@ void skill_init_unit_layout (void) { -2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2}; static const int dy[] = { -1,-1,-1,-1,-1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}; - skill_unit_layout[pos].count = 15; - memcpy(skill_unit_layout[pos].dx,dx,sizeof(dx)); - memcpy(skill_unit_layout[pos].dy,dy,sizeof(dy)); + skill->unit_layout[pos].count = 15; + memcpy(skill->unit_layout[pos].dx,dx,sizeof(dx)); + memcpy(skill->unit_layout[pos].dy,dy,sizeof(dy)); } break; case PA_GOSPEL: { @@ -17125,17 +17749,17 @@ void skill_init_unit_layout (void) { -1,-1,-1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 3, 3, 3}; - skill_unit_layout[pos].count = 33; - memcpy(skill_unit_layout[pos].dx,dx,sizeof(dx)); - memcpy(skill_unit_layout[pos].dy,dy,sizeof(dy)); + skill->unit_layout[pos].count = 33; + memcpy(skill->unit_layout[pos].dx,dx,sizeof(dx)); + memcpy(skill->unit_layout[pos].dy,dy,sizeof(dy)); } break; case NJ_KAENSIN: { static const int dx[] = {-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1, 1, 2,-2,-1, 0, 1, 2,-2,-1, 0, 1, 2}; static const int dy[] = { 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 0, 0, 0, 0,-1,-1,-1,-1,-1,-2,-2,-2,-2,-2}; - skill_unit_layout[pos].count = 24; - memcpy(skill_unit_layout[pos].dx,dx,sizeof(dx)); - memcpy(skill_unit_layout[pos].dy,dy,sizeof(dy)); + skill->unit_layout[pos].count = 24; + memcpy(skill->unit_layout[pos].dx,dx,sizeof(dx)); + memcpy(skill->unit_layout[pos].dy,dy,sizeof(dy)); } break; case NJ_TATAMIGAESHI: { @@ -17150,29 +17774,29 @@ void skill_init_unit_layout (void) { static const int dy3[] = { 0, 0, 0, 0, 0, 0,-3,-2,-1, 1, 2, 3}; //lv1 j = 0; - skill_unit_layout[pos].count = 4; - memcpy(skill_unit_layout[pos].dx,dx1,sizeof(dx1)); - memcpy(skill_unit_layout[pos].dy,dy1,sizeof(dy1)); - skill_db[i].unit_layout_type[j] = pos; + skill->unit_layout[pos].count = 4; + memcpy(skill->unit_layout[pos].dx,dx1,sizeof(dx1)); + memcpy(skill->unit_layout[pos].dy,dy1,sizeof(dy1)); + skill->db[i].unit_layout_type[j] = pos; //lv2/3 j++; pos++; - skill_unit_layout[pos].count = 8; - memcpy(skill_unit_layout[pos].dx,dx2,sizeof(dx2)); - memcpy(skill_unit_layout[pos].dy,dy2,sizeof(dy2)); - skill_db[i].unit_layout_type[j] = pos; - skill_db[i].unit_layout_type[++j] = pos; + skill->unit_layout[pos].count = 8; + memcpy(skill->unit_layout[pos].dx,dx2,sizeof(dx2)); + memcpy(skill->unit_layout[pos].dy,dy2,sizeof(dy2)); + skill->db[i].unit_layout_type[j] = pos; + skill->db[i].unit_layout_type[++j] = pos; //lv4/5 j++; pos++; - skill_unit_layout[pos].count = 12; - memcpy(skill_unit_layout[pos].dx,dx3,sizeof(dx3)); - memcpy(skill_unit_layout[pos].dy,dy3,sizeof(dy3)); - skill_db[i].unit_layout_type[j] = pos; - skill_db[i].unit_layout_type[++j] = pos; + skill->unit_layout[pos].count = 12; + memcpy(skill->unit_layout[pos].dx,dx3,sizeof(dx3)); + memcpy(skill->unit_layout[pos].dy,dy3,sizeof(dy3)); + skill->db[i].unit_layout_type[j] = pos; + skill->db[i].unit_layout_type[++j] = pos; //Fill in the rest using lv 5. for (;j<MAX_SKILL_LEVEL;j++) - skill_db[i].unit_layout_type[j] = pos; + skill->db[i].unit_layout_type[j] = pos; //Skip, this way the check below will fail and continue to the next skill. pos++; } @@ -17180,104 +17804,104 @@ void skill_init_unit_layout (void) { case GN_WALLOFTHORN: { static const int dx[] = {-1,-2,-2,-2,-2,-2,-1, 0, 1, 2, 2, 2, 2, 2, 1, 0}; static const int dy[] = { 2, 2, 1, 0,-1,-2,-2,-2,-2,-2,-1, 0, 1, 2, 2, 2}; - skill_unit_layout[pos].count = 16; - memcpy(skill_unit_layout[pos].dx,dx,sizeof(dx)); - memcpy(skill_unit_layout[pos].dy,dy,sizeof(dy)); + skill->unit_layout[pos].count = 16; + memcpy(skill->unit_layout[pos].dx,dx,sizeof(dx)); + memcpy(skill->unit_layout[pos].dy,dy,sizeof(dy)); } break; case EL_FIRE_MANTLE: { static const int dx[] = {-1, 0, 1, 1, 1, 0,-1,-1}; static const int dy[] = { 1, 1, 1, 0,-1,-1,-1, 0}; - skill_unit_layout[pos].count = 8; - memcpy(skill_unit_layout[pos].dx,dx,sizeof(dx)); - memcpy(skill_unit_layout[pos].dy,dy,sizeof(dy)); + skill->unit_layout[pos].count = 8; + memcpy(skill->unit_layout[pos].dx,dx,sizeof(dx)); + memcpy(skill->unit_layout[pos].dy,dy,sizeof(dy)); } break; default: ShowError("unknown unit layout at skill %d\n",i); break; } - if (!skill_unit_layout[pos].count) + if (!skill->unit_layout[pos].count) continue; for (j=0;j<MAX_SKILL_LEVEL;j++) - skill_db[i].unit_layout_type[j] = pos; + skill->db[i].unit_layout_type[j] = pos; pos++; } // firewall and icewall have 8 layouts (direction-dependent) - firewall_unit_pos = pos; + skill->firewall_unit_pos = pos; for (i=0;i<8;i++) { if (i&1) { - skill_unit_layout[pos].count = 5; + skill->unit_layout[pos].count = 5; if (i&0x2) { int dx[] = {-1,-1, 0, 0, 1}; int dy[] = { 1, 0, 0,-1,-1}; - memcpy(skill_unit_layout[pos].dx,dx,sizeof(dx)); - memcpy(skill_unit_layout[pos].dy,dy,sizeof(dy)); + memcpy(skill->unit_layout[pos].dx,dx,sizeof(dx)); + memcpy(skill->unit_layout[pos].dy,dy,sizeof(dy)); } else { int dx[] = { 1, 1 ,0, 0,-1}; int dy[] = { 1, 0, 0,-1,-1}; - memcpy(skill_unit_layout[pos].dx,dx,sizeof(dx)); - memcpy(skill_unit_layout[pos].dy,dy,sizeof(dy)); + memcpy(skill->unit_layout[pos].dx,dx,sizeof(dx)); + memcpy(skill->unit_layout[pos].dy,dy,sizeof(dy)); } } else { - skill_unit_layout[pos].count = 3; + skill->unit_layout[pos].count = 3; if (i%4==0) { int dx[] = {-1, 0, 1}; int dy[] = { 0, 0, 0}; - memcpy(skill_unit_layout[pos].dx,dx,sizeof(dx)); - memcpy(skill_unit_layout[pos].dy,dy,sizeof(dy)); + memcpy(skill->unit_layout[pos].dx,dx,sizeof(dx)); + memcpy(skill->unit_layout[pos].dy,dy,sizeof(dy)); } else { int dx[] = { 0, 0, 0}; int dy[] = {-1, 0, 1}; - memcpy(skill_unit_layout[pos].dx,dx,sizeof(dx)); - memcpy(skill_unit_layout[pos].dy,dy,sizeof(dy)); + memcpy(skill->unit_layout[pos].dx,dx,sizeof(dx)); + memcpy(skill->unit_layout[pos].dy,dy,sizeof(dy)); } } pos++; } - icewall_unit_pos = pos; + skill->icewall_unit_pos = pos; for (i=0;i<8;i++) { - skill_unit_layout[pos].count = 5; + skill->unit_layout[pos].count = 5; if (i&1) { if (i&0x2) { int dx[] = {-2,-1, 0, 1, 2}; int dy[] = { 2, 1, 0,-1,-2}; - memcpy(skill_unit_layout[pos].dx,dx,sizeof(dx)); - memcpy(skill_unit_layout[pos].dy,dy,sizeof(dy)); + memcpy(skill->unit_layout[pos].dx,dx,sizeof(dx)); + memcpy(skill->unit_layout[pos].dy,dy,sizeof(dy)); } else { int dx[] = { 2, 1 ,0,-1,-2}; int dy[] = { 2, 1, 0,-1,-2}; - memcpy(skill_unit_layout[pos].dx,dx,sizeof(dx)); - memcpy(skill_unit_layout[pos].dy,dy,sizeof(dy)); + memcpy(skill->unit_layout[pos].dx,dx,sizeof(dx)); + memcpy(skill->unit_layout[pos].dy,dy,sizeof(dy)); } } else { if (i%4==0) { int dx[] = {-2,-1, 0, 1, 2}; int dy[] = { 0, 0, 0, 0, 0}; - memcpy(skill_unit_layout[pos].dx,dx,sizeof(dx)); - memcpy(skill_unit_layout[pos].dy,dy,sizeof(dy)); + memcpy(skill->unit_layout[pos].dx,dx,sizeof(dx)); + memcpy(skill->unit_layout[pos].dy,dy,sizeof(dy)); } else { int dx[] = { 0, 0, 0, 0, 0}; int dy[] = {-2,-1, 0, 1, 2}; - memcpy(skill_unit_layout[pos].dx,dx,sizeof(dx)); - memcpy(skill_unit_layout[pos].dy,dy,sizeof(dy)); + memcpy(skill->unit_layout[pos].dx,dx,sizeof(dx)); + memcpy(skill->unit_layout[pos].dy,dy,sizeof(dy)); } } pos++; } - earthstrain_unit_pos = pos; + skill->earthstrain_unit_pos = pos; for( i = 0; i < 8; i++ ) { // For each Direction - skill_unit_layout[pos].count = 15; + skill->unit_layout[pos].count = 15; switch( i ) { case 0: case 1: case 3: case 4: case 5: case 7: { int dx[] = {-7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7}; int dy[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - memcpy(skill_unit_layout[pos].dx,dx,sizeof(dx)); - memcpy(skill_unit_layout[pos].dy,dy,sizeof(dy)); + memcpy(skill->unit_layout[pos].dx,dx,sizeof(dx)); + memcpy(skill->unit_layout[pos].dy,dy,sizeof(dy)); } break; case 2: @@ -17285,8 +17909,8 @@ void skill_init_unit_layout (void) { { int dx[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; int dy[] = {-7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7}; - memcpy(skill_unit_layout[pos].dx,dx,sizeof(dx)); - memcpy(skill_unit_layout[pos].dy,dy,sizeof(dy)); + memcpy(skill->unit_layout[pos].dx,dx,sizeof(dx)); + memcpy(skill->unit_layout[pos].dy,dy,sizeof(dy)); } break; } @@ -17297,7 +17921,7 @@ void skill_init_unit_layout (void) { int skill_block_check(struct block_list *bl, sc_type type , uint16 skill_id) { int inf = 0; - struct status_change *sc = status_get_sc(bl); + struct status_change *sc = status->get_sc(bl); if( !sc || !bl || !skill_id ) return 0; // Can do it @@ -17305,7 +17929,7 @@ int skill_block_check(struct block_list *bl, sc_type type , uint16 skill_id) { switch(type){ case SC_STASIS: inf = skill->get_inf2(skill_id); - if( inf == INF2_SONG_DANCE || /*skill->get_inf2(skill_id) == INF2_CHORUS_SKILL ||*/ inf == INF2_SPIRIT_SKILL ) + if( inf == INF2_SONG_DANCE || skill->get_inf2(skill_id) == INF2_CHORUS_SKILL || inf == INF2_SPIRIT_SKILL ) return 1; // Can't do it. switch( skill_id ) { case NV_FIRSTAID: case TF_HIDING: case AS_CLOAKING: case WZ_SIGHTRASHER: @@ -17370,25 +17994,58 @@ int skill_get_elemental_type( uint16 skill_id , uint16 skill_lv ) { } /** + * update stored skill cooldowns for player logout + * @param sd the affected player structure + */ +void skill_cooldown_save(struct map_session_data * sd) { + int i; + struct skill_cd* cd = NULL; + int64 now = 0; + + // always check to make sure the session properly exists + nullpo_retv(sd); + + if( !(cd = idb_get(skill->cd_db, sd->status.char_id)) ) {// no skill cooldown is associated with this character + return; + } + + now = timer->gettick(); + + // process each individual cooldown associated with the character + for( i = 0; i < cd->cursor; i++ ) { + cd->entry[i]->duration = DIFF_TICK32(cd->entry[i]->started+cd->entry[i]->duration,now); + if( cd->entry[i]->timer != INVALID_TIMER ) { + timer->delete(cd->entry[i]->timer,skill->blockpc_end); + cd->entry[i]->timer = INVALID_TIMER; + } + } +} + +/** * reload stored skill cooldowns when a player logs in. * @param sd the affected player structure */ -void skill_cooldown_load(struct map_session_data * sd) -{ +void skill_cooldown_load(struct map_session_data * sd) { int i; struct skill_cd* cd = NULL; + int64 now = 0; // always check to make sure the session properly exists nullpo_retv(sd); - if( !(cd = idb_get(skillcd_db, sd->status.char_id)) ) {// no skill cooldown is associated with this character + if( !(cd = idb_get(skill->cd_db, sd->status.char_id)) ) {// no skill cooldown is associated with this character return; } + clif->cooldown_list(sd->fd,cd); + + now = timer->gettick(); + // process each individual cooldown associated with the character for( i = 0; i < cd->cursor; i++ ) { - // block the skill from usage but ensure it is not recorded (load = true) - skill->blockpc_start( sd, cd->nameid[i], cd->duration[i], true ); + cd->entry[i]->started = now; + cd->entry[i]->timer = timer->add(timer->gettick()+cd->entry[i]->duration,skill->blockpc_end,sd->bl.id,cd->entry[i]->skidx); + sd->blockskill[cd->entry[i]->skidx] = true; } } @@ -17412,35 +18069,36 @@ bool skill_parse_row_skilldb(char* split[], int columns, int current) { if( !idx ) // invalid skill id return false; - skill_db[idx].nameid = skill_id; - skill->split_atoi(split[1],skill_db[idx].range); - skill_db[idx].hit = atoi(split[2]); - skill_db[idx].inf = atoi(split[3]); - skill->split_atoi(split[4],skill_db[idx].element); - skill_db[idx].nk = (int)strtol(split[5], NULL, 0); - skill->split_atoi(split[6],skill_db[idx].splash); - skill_db[idx].max = atoi(split[7]); - skill->split_atoi(split[8],skill_db[idx].num); + skill->db[idx].nameid = skill_id; + skill->split_atoi(split[1],skill->db[idx].range); + skill->db[idx].hit = atoi(split[2]); + skill->db[idx].inf = atoi(split[3]); + skill->split_atoi(split[4],skill->db[idx].element); + skill->db[idx].nk = (int)strtol(split[5], NULL, 0); + skill->split_atoi(split[6],skill->db[idx].splash); + skill->db[idx].max = atoi(split[7]); + skill->split_atoi(split[8],skill->db[idx].num); if( strcmpi(split[9],"yes") == 0 ) - skill_db[idx].castcancel = 1; + skill->db[idx].castcancel = 1; else - skill_db[idx].castcancel = 0; - skill_db[idx].cast_def_rate = atoi(split[10]); - skill_db[idx].inf2 = (int)strtol(split[11], NULL, 0); - skill->split_atoi(split[12],skill_db[idx].maxcount); + skill->db[idx].castcancel = 0; + skill->db[idx].cast_def_rate = atoi(split[10]); + skill->db[idx].inf2 = (int)strtol(split[11], NULL, 0); + skill->split_atoi(split[12],skill->db[idx].maxcount); if( strcmpi(split[13],"weapon") == 0 ) - skill_db[idx].skill_type = BF_WEAPON; + skill->db[idx].skill_type = BF_WEAPON; else if( strcmpi(split[13],"magic") == 0 ) - skill_db[idx].skill_type = BF_MAGIC; + skill->db[idx].skill_type = BF_MAGIC; else if( strcmpi(split[13],"misc") == 0 ) - skill_db[idx].skill_type = BF_MISC; + skill->db[idx].skill_type = BF_MISC; else - skill_db[idx].skill_type = 0; - skill->split_atoi(split[14],skill_db[idx].blewcount); - safestrncpy(skill_db[idx].name, trim(split[15]), sizeof(skill_db[idx].name)); - safestrncpy(skill_db[idx].desc, trim(split[16]), sizeof(skill_db[idx].desc)); - strdb_iput(skilldb_name2id, skill_db[idx].name, skill_id); + skill->db[idx].skill_type = 0; + skill->split_atoi(split[14],skill->db[idx].blewcount); + safestrncpy(skill->db[idx].name, trim(split[15]), sizeof(skill->db[idx].name)); + safestrncpy(skill->db[idx].desc, trim(split[16]), sizeof(skill->db[idx].desc)); + strdb_iput(skill->name2id_db, skill->db[idx].name, skill_id); + script->set_constant2(skill->db[idx].name,(int)skill_id,0); return true; } @@ -17455,22 +18113,22 @@ bool skill_parse_row_requiredb(char* split[], int columns, int current) { if( !idx ) // invalid skill id return false; - skill->split_atoi(split[1],skill_db[idx].hp); - skill->split_atoi(split[2],skill_db[idx].mhp); - skill->split_atoi(split[3],skill_db[idx].sp); - skill->split_atoi(split[4],skill_db[idx].hp_rate); - skill->split_atoi(split[5],skill_db[idx].sp_rate); - skill->split_atoi(split[6],skill_db[idx].zeny); + skill->split_atoi(split[1],skill->db[idx].hp); + skill->split_atoi(split[2],skill->db[idx].mhp); + skill->split_atoi(split[3],skill->db[idx].sp); + skill->split_atoi(split[4],skill->db[idx].hp_rate); + skill->split_atoi(split[5],skill->db[idx].sp_rate); + skill->split_atoi(split[6],skill->db[idx].zeny); - //Wich weapon type are required, see doc/item_db for types + //Which weapon type are required, see doc/item_db for types p = split[7]; for( j = 0; j < 32; j++ ) { int l = atoi(p); if( l == 99 ) { // Any weapon - skill_db[idx].weapon = 0; + skill->db[idx].weapon = 0; break; } else - skill_db[idx].weapon |= 1<<l; + skill->db[idx].weapon |= 1<<l; p = strchr(p,':'); if(!p) break; @@ -17482,49 +18140,49 @@ bool skill_parse_row_requiredb(char* split[], int columns, int current) { for( j = 0; j < 32; j++ ) { int l = atoi(p); if( l == 99 ) { // Any ammo type - skill_db[idx].ammo = 0xFFFFFFFF; + skill->db[idx].ammo = 0xFFFFFFFF; break; } else if( l ) // 0 stands for no requirement - skill_db[idx].ammo |= 1<<l; + skill->db[idx].ammo |= 1<<l; p = strchr(p,':'); if( !p ) break; p++; } - skill->split_atoi(split[9],skill_db[idx].ammo_qty); - - if( strcmpi(split[10],"hiding") == 0 ) skill_db[idx].state = ST_HIDING; - else if( strcmpi(split[10],"cloaking") == 0 ) skill_db[idx].state = ST_CLOAKING; - else if( strcmpi(split[10],"hidden") == 0 ) skill_db[idx].state = ST_HIDDEN; - else if( strcmpi(split[10],"riding") == 0 ) skill_db[idx].state = ST_RIDING; - else if( strcmpi(split[10],"falcon") == 0 ) skill_db[idx].state = ST_FALCON; - else if( strcmpi(split[10],"cart") == 0 ) skill_db[idx].state = ST_CART; - else if( strcmpi(split[10],"shield") == 0 ) skill_db[idx].state = ST_SHIELD; - else if( strcmpi(split[10],"sight") == 0 ) skill_db[idx].state = ST_SIGHT; - else if( strcmpi(split[10],"explosionspirits") == 0 ) skill_db[idx].state = ST_EXPLOSIONSPIRITS; - else if( strcmpi(split[10],"cartboost") == 0 ) skill_db[idx].state = ST_CARTBOOST; - else if( strcmpi(split[10],"recover_weight_rate") == 0 ) skill_db[idx].state = ST_RECOV_WEIGHT_RATE; - else if( strcmpi(split[10],"move_enable") == 0 ) skill_db[idx].state = ST_MOVE_ENABLE; - else if( strcmpi(split[10],"water") == 0 ) skill_db[idx].state = ST_WATER; - else if( strcmpi(split[10],"dragon") == 0 ) skill_db[idx].state = ST_RIDINGDRAGON; - else if( strcmpi(split[10],"warg") == 0 ) skill_db[idx].state = ST_WUG; - else if( strcmpi(split[10],"ridingwarg") == 0 ) skill_db[idx].state = ST_RIDINGWUG; - else if( strcmpi(split[10],"mado") == 0 ) skill_db[idx].state = ST_MADO; - else if( strcmpi(split[10],"elementalspirit") == 0 ) skill_db[idx].state = ST_ELEMENTALSPIRIT; - else if( strcmpi(split[10],"poisonweapon") == 0 ) skill_db[idx].state = ST_POISONINGWEAPON; - else if( strcmpi(split[10],"rollingcutter") == 0 ) skill_db[idx].state = ST_ROLLINGCUTTER; - else if( strcmpi(split[10],"mh_fighting") == 0 ) skill_db[idx].state = ST_MH_FIGHTING; - else if( strcmpi(split[10],"mh_grappling") == 0 ) skill_db[idx].state = ST_MH_GRAPPLING; - else if( strcmpi(split[10],"peco") == 0 ) skill_db[idx].state = ST_PECO; + skill->split_atoi(split[9],skill->db[idx].ammo_qty); + + if( strcmpi(split[10],"hiding") == 0 ) skill->db[idx].state = ST_HIDING; + else if( strcmpi(split[10],"cloaking") == 0 ) skill->db[idx].state = ST_CLOAKING; + else if( strcmpi(split[10],"hidden") == 0 ) skill->db[idx].state = ST_HIDDEN; + else if( strcmpi(split[10],"riding") == 0 ) skill->db[idx].state = ST_RIDING; + else if( strcmpi(split[10],"falcon") == 0 ) skill->db[idx].state = ST_FALCON; + else if( strcmpi(split[10],"cart") == 0 ) skill->db[idx].state = ST_CART; + else if( strcmpi(split[10],"shield") == 0 ) skill->db[idx].state = ST_SHIELD; + else if( strcmpi(split[10],"sight") == 0 ) skill->db[idx].state = ST_SIGHT; + else if( strcmpi(split[10],"explosionspirits") == 0 ) skill->db[idx].state = ST_EXPLOSIONSPIRITS; + else if( strcmpi(split[10],"cartboost") == 0 ) skill->db[idx].state = ST_CARTBOOST; + else if( strcmpi(split[10],"recover_weight_rate") == 0 ) skill->db[idx].state = ST_RECOV_WEIGHT_RATE; + else if( strcmpi(split[10],"move_enable") == 0 ) skill->db[idx].state = ST_MOVE_ENABLE; + else if( strcmpi(split[10],"water") == 0 ) skill->db[idx].state = ST_WATER; + else if( strcmpi(split[10],"dragon") == 0 ) skill->db[idx].state = ST_RIDINGDRAGON; + else if( strcmpi(split[10],"warg") == 0 ) skill->db[idx].state = ST_WUG; + else if( strcmpi(split[10],"ridingwarg") == 0 ) skill->db[idx].state = ST_RIDINGWUG; + else if( strcmpi(split[10],"mado") == 0 ) skill->db[idx].state = ST_MADO; + else if( strcmpi(split[10],"elementalspirit") == 0 ) skill->db[idx].state = ST_ELEMENTALSPIRIT; + else if( strcmpi(split[10],"poisonweapon") == 0 ) skill->db[idx].state = ST_POISONINGWEAPON; + else if( strcmpi(split[10],"rollingcutter") == 0 ) skill->db[idx].state = ST_ROLLINGCUTTER; + else if( strcmpi(split[10],"mh_fighting") == 0 ) skill->db[idx].state = ST_MH_FIGHTING; + else if( strcmpi(split[10],"mh_grappling") == 0 ) skill->db[idx].state = ST_MH_GRAPPLING; + else if( strcmpi(split[10],"peco") == 0 ) skill->db[idx].state = ST_PECO; /** * Unknown or no state **/ - else skill_db[idx].state = ST_NONE; + else skill->db[idx].state = ST_NONE; - skill->split_atoi(split[11],skill_db[idx].spiritball); + skill->split_atoi(split[11],skill->db[idx].spiritball); for( j = 0; j < MAX_SKILL_ITEM_REQUIRE; j++ ) { - skill_db[idx].itemid[j] = atoi(split[12+ 2*j]); - skill_db[idx].amount[j] = atoi(split[13+ 2*j]); + skill->db[idx].itemid[j] = atoi(split[12+ 2*j]); + skill->db[idx].amount[j] = atoi(split[13+ 2*j]); } return true; @@ -17537,14 +18195,14 @@ bool skill_parse_row_castdb(char* split[], int columns, int current) { if( !idx ) // invalid skill id return false; - skill->split_atoi(split[1],skill_db[idx].cast); - skill->split_atoi(split[2],skill_db[idx].delay); - skill->split_atoi(split[3],skill_db[idx].walkdelay); - skill->split_atoi(split[4],skill_db[idx].upkeep_time); - skill->split_atoi(split[5],skill_db[idx].upkeep_time2); - skill->split_atoi(split[6],skill_db[idx].cooldown); + skill->split_atoi(split[1],skill->db[idx].cast); + skill->split_atoi(split[2],skill->db[idx].delay); + skill->split_atoi(split[3],skill->db[idx].walkdelay); + skill->split_atoi(split[4],skill->db[idx].upkeep_time); + skill->split_atoi(split[5],skill->db[idx].upkeep_time2); + skill->split_atoi(split[6],skill->db[idx].cooldown); #ifdef RENEWAL_CAST - skill->split_atoi(split[7],skill_db[idx].fixed_cast); + skill->split_atoi(split[7],skill->db[idx].fixed_cast); #endif return true; } @@ -17556,9 +18214,9 @@ bool skill_parse_row_castnodexdb(char* split[], int columns, int current) { if( !idx ) // invalid skill id return false; - skill->split_atoi(split[1],skill_db[idx].castnodex); + skill->split_atoi(split[1],skill->db[idx].castnodex); if( split[2] ) // optional column - skill->split_atoi(split[2],skill_db[idx].delaynodex); + skill->split_atoi(split[2],skill->db[idx].delaynodex); return true; } @@ -17570,37 +18228,37 @@ bool skill_parse_row_unitdb(char* split[], int columns, int current) { if( !idx ) // invalid skill id return false; - skill_db[idx].unit_id[0] = strtol(split[1],NULL,16); - skill_db[idx].unit_id[1] = strtol(split[2],NULL,16); - skill->split_atoi(split[3],skill_db[idx].unit_layout_type); - skill->split_atoi(split[4],skill_db[idx].unit_range); - skill_db[idx].unit_interval = atoi(split[5]); - - if( strcmpi(split[6],"noenemy")==0 ) skill_db[idx].unit_target = BCT_NOENEMY; - else if( strcmpi(split[6],"friend")==0 ) skill_db[idx].unit_target = BCT_NOENEMY; - else if( strcmpi(split[6],"party")==0 ) skill_db[idx].unit_target = BCT_PARTY; - else if( strcmpi(split[6],"ally")==0 ) skill_db[idx].unit_target = BCT_PARTY|BCT_GUILD; - else if( strcmpi(split[6],"guild")==0 ) skill_db[idx].unit_target = BCT_GUILD; - else if( strcmpi(split[6],"all")==0 ) skill_db[idx].unit_target = BCT_ALL; - else if( strcmpi(split[6],"enemy")==0 ) skill_db[idx].unit_target = BCT_ENEMY; - else if( strcmpi(split[6],"self")==0 ) skill_db[idx].unit_target = BCT_SELF; - else if( strcmpi(split[6],"sameguild")==0 ) skill_db[idx].unit_target = BCT_GUILD|BCT_SAMEGUILD; - else if( strcmpi(split[6],"noone")==0 ) skill_db[idx].unit_target = BCT_NOONE; - else skill_db[idx].unit_target = strtol(split[6],NULL,16); - - skill_db[idx].unit_flag = strtol(split[7],NULL,16); - - if (skill_db[idx].unit_flag&UF_DEFNOTENEMY && battle_config.defnotenemy) - skill_db[idx].unit_target = BCT_NOENEMY; + skill->db[idx].unit_id[0] = (int)strtol(split[1],NULL,16); + skill->db[idx].unit_id[1] = (int)strtol(split[2],NULL,16); + skill->split_atoi(split[3],skill->db[idx].unit_layout_type); + skill->split_atoi(split[4],skill->db[idx].unit_range); + skill->db[idx].unit_interval = atoi(split[5]); + + if( strcmpi(split[6],"noenemy")==0 ) skill->db[idx].unit_target = BCT_NOENEMY; + else if( strcmpi(split[6],"friend")==0 ) skill->db[idx].unit_target = BCT_NOENEMY; + else if( strcmpi(split[6],"party")==0 ) skill->db[idx].unit_target = BCT_PARTY; + else if( strcmpi(split[6],"ally")==0 ) skill->db[idx].unit_target = BCT_PARTY|BCT_GUILD; + else if( strcmpi(split[6],"guild")==0 ) skill->db[idx].unit_target = BCT_GUILD; + else if( strcmpi(split[6],"all")==0 ) skill->db[idx].unit_target = BCT_ALL; + else if( strcmpi(split[6],"enemy")==0 ) skill->db[idx].unit_target = BCT_ENEMY; + else if( strcmpi(split[6],"self")==0 ) skill->db[idx].unit_target = BCT_SELF; + else if( strcmpi(split[6],"sameguild")==0 ) skill->db[idx].unit_target = BCT_GUILD|BCT_SAMEGUILD; + else if( strcmpi(split[6],"noone")==0 ) skill->db[idx].unit_target = BCT_NOONE; + else skill->db[idx].unit_target = (int)strtol(split[6],NULL,16); + + skill->db[idx].unit_flag = (int)strtol(split[7],NULL,16); + + if (skill->db[idx].unit_flag&UF_DEFNOTENEMY && battle_config.defnotenemy) + skill->db[idx].unit_target = BCT_NOENEMY; //By default, target just characters. - skill_db[idx].unit_target |= BL_CHAR; - if (skill_db[idx].unit_flag&UF_NOPC) - skill_db[idx].unit_target &= ~BL_PC; - if (skill_db[idx].unit_flag&UF_NOMOB) - skill_db[idx].unit_target &= ~BL_MOB; - if (skill_db[idx].unit_flag&UF_SKILL) - skill_db[idx].unit_target |= BL_SKILL; + skill->db[idx].unit_target |= BL_CHAR; + if (skill->db[idx].unit_flag&UF_NOPC) + skill->db[idx].unit_target &= ~BL_PC; + if (skill->db[idx].unit_flag&UF_NOMOB) + skill->db[idx].unit_target &= ~BL_MOB; + if (skill->db[idx].unit_flag&UF_SKILL) + skill->db[idx].unit_target |= BL_SKILL; return true; } @@ -17613,14 +18271,14 @@ bool skill_parse_row_producedb(char* split[], int columns, int current) { if( !i ) return false; - skill_produce_db[current].nameid = i; - skill_produce_db[current].itemlv = atoi(split[1]); - skill_produce_db[current].req_skill = atoi(split[2]); - skill_produce_db[current].req_skill_lv = atoi(split[3]); + skill->produce_db[current].nameid = i; + skill->produce_db[current].itemlv = atoi(split[1]); + skill->produce_db[current].req_skill = atoi(split[2]); + skill->produce_db[current].req_skill_lv = atoi(split[3]); for( x = 4, y = 0; x+1 < columns && split[x] && split[x+1] && y < MAX_PRODUCE_RESOURCE; x += 2, y++ ) { - skill_produce_db[current].mat_id[y] = atoi(split[x]); - skill_produce_db[current].mat_amount[y] = atoi(split[x+1]); + skill->produce_db[current].mat_id[y] = atoi(split[x]); + skill->produce_db[current].mat_amount[y] = atoi(split[x+1]); } return true; @@ -17634,11 +18292,11 @@ bool skill_parse_row_createarrowdb(char* split[], int columns, int current) { if( !i ) return false; - skill_arrow_db[current].nameid = i; + skill->arrow_db[current].nameid = i; for( x = 1, y = 0; x+1 < columns && split[x] && split[x+1] && y < MAX_ARROW_RESOURCE; x += 2, y++ ) { - skill_arrow_db[current].cre_id[y] = atoi(split[x]); - skill_arrow_db[current].cre_amount[y] = atoi(split[x+1]); + skill->arrow_db[current].cre_id[y] = atoi(split[x]); + skill->arrow_db[current].cre_amount[y] = atoi(split[x+1]); } return true; @@ -17657,9 +18315,9 @@ bool skill_parse_row_spellbookdb(char* split[], int columns, int current) { if( points < 1 ) ShowError("spellbook_db: PreservePoints have to be 1 or above! (%d/%s)\n", skill_id, skill->get_name(skill_id)); else { - skill_spellbook_db[current].skill_id = skill_id; - skill_spellbook_db[current].point = points; - skill_spellbook_db[current].nameid = nameid; + skill->spellbook_db[current].skill_id = skill_id; + skill->spellbook_db[current].point = points; + skill->spellbook_db[current].nameid = nameid; return true; } @@ -17686,8 +18344,8 @@ bool skill_parse_row_improvisedb(char* split[], int columns, int current) { if( current >= MAX_SKILL_IMPROVISE_DB ) { ShowError("skill_improvise_db: Maximum amount of entries reached (%d), increase MAX_SKILL_IMPROVISE_DB\n",MAX_SKILL_IMPROVISE_DB); } - skill_improvise_db[current].skill_id = skill_id; - skill_improvise_db[current].per = j; // Still need confirm it. + skill->improvise_db[current].skill_id = skill_id; + skill->improvise_db[current].per = j; // Still need confirm it. return true; } @@ -17704,7 +18362,7 @@ bool skill_parse_row_magicmushroomdb(char* split[], int column, int current) { return false; } - skill_magicmushroom_db[current].skill_id = skill_id; + skill->magicmushroom_db[current].skill_id = skill_id; return true; } @@ -17715,7 +18373,7 @@ bool skill_parse_row_reproducedb(char* split[], int column, int current) { if( !idx ) return false; - skill_reproduce_db[idx] = true; + skill->reproduce_db[idx] = true; return true; } @@ -17733,9 +18391,9 @@ bool skill_parse_row_abradb(char* split[], int columns, int current) { return false; } - skill_abra_db[current].skill_id = skill_id; - skill_abra_db[current].req_lv = atoi(split[2]); - skill_abra_db[current].per = atoi(split[3]); + skill->abra_db[current].skill_id = skill_id; + skill->abra_db[current].req_lv = atoi(split[2]); + skill->abra_db[current].per = atoi(split[3]); return true; } @@ -17747,8 +18405,8 @@ bool skill_parse_row_changematerialdb(char* split[], int columns, int current) { int x,y; for(x=0; x<MAX_SKILL_PRODUCE_DB; x++){ - if( skill_produce_db[x].nameid == skill_id ) - if( skill_produce_db[x].req_skill == GN_CHANGEMATERIAL ) + if( skill->produce_db[x].nameid == skill_id ) + if( skill->produce_db[x].req_skill == GN_CHANGEMATERIAL ) break; } @@ -17761,12 +18419,12 @@ bool skill_parse_row_changematerialdb(char* split[], int columns, int current) { ShowError("skill_changematerial_db: Maximum amount of entries reached (%d), increase MAX_SKILL_PRODUCE_DB\n",MAX_SKILL_PRODUCE_DB); } - skill_changematerial_db[current].itemid = skill_id; - skill_changematerial_db[current].rate = j; + skill->changematerial_db[current].itemid = skill_id; + skill->changematerial_db[current].rate = j; for( x = 2, y = 0; x+1 < columns && split[x] && split[x+1] && y < 5; x += 2, y++ ) { - skill_changematerial_db[current].qty[y] = atoi(split[x]); - skill_changematerial_db[current].qty_rate[y] = atoi(split[x+1]); + skill->changematerial_db[current].qty[y] = atoi(split[x]); + skill->changematerial_db[current].qty_rate[y] = atoi(split[x+1]); } return true; @@ -17784,43 +18442,59 @@ bool skill_parse_row_changematerialdb(char* split[], int columns, int current) { * create_arrow_db.txt * abra_db.txt *------------------------------*/ -void skill_readdb(void) { +void skill_readdb(bool minimal) { // init skill db structures - db_clear(skilldb_name2id); - memset(skill_db,0,sizeof(skill_db)); - memset(skill_produce_db,0,sizeof(skill_produce_db)); - memset(skill_arrow_db,0,sizeof(skill_arrow_db)); - memset(skill_abra_db,0,sizeof(skill_abra_db)); - memset(skill_spellbook_db,0,sizeof(skill_spellbook_db)); - memset(skill_magicmushroom_db,0,sizeof(skill_magicmushroom_db)); - memset(skill_reproduce_db,0,sizeof(skill_reproduce_db)); - memset(skill_changematerial_db,0,sizeof(skill_changematerial_db)); + db_clear(skill->name2id_db); + + /* when != it was called during init and this procedure was already performed by skill_defaults() */ + if( runflag == MAPSERVER_ST_RUNNING ) { + memset(skill->db,0,sizeof(skill->db) + + sizeof(skill->produce_db) + + sizeof(skill->arrow_db) + + sizeof(skill->abra_db) + + sizeof(skill->magicmushroom_db) + + sizeof(skill->improvise_db) + + sizeof(skill->changematerial_db) + + sizeof(skill->spellbook_db) + + sizeof(skill->reproduce_db) + ); + } // load skill databases - safestrncpy(skill_db[0].name, "UNKNOWN_SKILL", sizeof(skill_db[0].name)); - safestrncpy(skill_db[0].desc, "Unknown Skill", sizeof(skill_db[0].desc)); + safestrncpy(skill->db[0].name, "UNKNOWN_SKILL", sizeof(skill->db[0].name)); + safestrncpy(skill->db[0].desc, "Unknown Skill", sizeof(skill->db[0].desc)); + +#ifdef ENABLE_CASE_CHECK + script->parser_current_file = DBPATH"skill_db.txt"; +#endif // ENABLE_CASE_CHECK + sv->readdb(map->db_path, DBPATH"skill_db.txt", ',', 17, 17, MAX_SKILL_DB, skill->parse_row_skilldb); +#ifdef ENABLE_CASE_CHECK + script->parser_current_file = NULL; +#endif // ENABLE_CASE_CHECK + + if (minimal) + return; - sv->readdb(iMap->db_path, DBPATH"skill_db.txt" , ',', 17, 17, MAX_SKILL_DB, skill->parse_row_skilldb); - sv->readdb(iMap->db_path, DBPATH"skill_require_db.txt" , ',', 32, 32, MAX_SKILL_DB, skill->parse_row_requiredb); + sv->readdb(map->db_path, DBPATH"skill_require_db.txt", ',', 32, 32, MAX_SKILL_DB, skill->parse_row_requiredb); #ifdef RENEWAL_CAST - sv->readdb(iMap->db_path, "re/skill_cast_db.txt" , ',', 8, 8, MAX_SKILL_DB, skill->parse_row_castdb); + sv->readdb(map->db_path, "re/skill_cast_db.txt", ',', 8, 8, MAX_SKILL_DB, skill->parse_row_castdb); #else - sv->readdb(iMap->db_path, "pre-re/skill_cast_db.txt" , ',', 7, 7, MAX_SKILL_DB, skill->parse_row_castdb); + sv->readdb(map->db_path, "pre-re/skill_cast_db.txt", ',', 7, 7, MAX_SKILL_DB, skill->parse_row_castdb); #endif - sv->readdb(iMap->db_path, DBPATH"skill_castnodex_db.txt", ',', 2, 3, MAX_SKILL_DB, skill->parse_row_castnodexdb); - sv->readdb(iMap->db_path, DBPATH"skill_unit_db.txt" , ',', 8, 8, MAX_SKILL_DB, skill->parse_row_unitdb); + sv->readdb(map->db_path, DBPATH"skill_castnodex_db.txt", ',', 2, 3, MAX_SKILL_DB, skill->parse_row_castnodexdb); + sv->readdb(map->db_path, DBPATH"skill_unit_db.txt", ',', 8, 8, MAX_SKILL_DB, skill->parse_row_unitdb); skill->init_unit_layout(); - sv->readdb(iMap->db_path, "produce_db.txt" , ',', 4, 4+2*MAX_PRODUCE_RESOURCE, MAX_SKILL_PRODUCE_DB, skill->parse_row_producedb); - sv->readdb(iMap->db_path, "create_arrow_db.txt" , ',', 1+2, 1+2*MAX_ARROW_RESOURCE, MAX_SKILL_ARROW_DB, skill->parse_row_createarrowdb); - sv->readdb(iMap->db_path, "abra_db.txt" , ',', 4, 4, MAX_SKILL_ABRA_DB, skill->parse_row_abradb); + sv->readdb(map->db_path, "produce_db.txt", ',', 4, 4+2*MAX_PRODUCE_RESOURCE, MAX_SKILL_PRODUCE_DB, skill->parse_row_producedb); + sv->readdb(map->db_path, "create_arrow_db.txt", ',', 1+2, 1+2*MAX_ARROW_RESOURCE, MAX_SKILL_ARROW_DB, skill->parse_row_createarrowdb); + sv->readdb(map->db_path, "abra_db.txt", ',', 4, 4, MAX_SKILL_ABRA_DB, skill->parse_row_abradb); //Warlock - sv->readdb(iMap->db_path, "spellbook_db.txt" , ',', 3, 3, MAX_SKILL_SPELLBOOK_DB, skill->parse_row_spellbookdb); + sv->readdb(map->db_path, "spellbook_db.txt", ',', 3, 3, MAX_SKILL_SPELLBOOK_DB, skill->parse_row_spellbookdb); //Guillotine Cross - sv->readdb(iMap->db_path, "magicmushroom_db.txt" , ',', 1, 1, MAX_SKILL_MAGICMUSHROOM_DB, skill->parse_row_magicmushroomdb); - sv->readdb(iMap->db_path, "skill_reproduce_db.txt", ',', 1, 1, MAX_SKILL_DB, skill->parse_row_reproducedb); - sv->readdb(iMap->db_path, "skill_improvise_db.txt" , ',', 2, 2, MAX_SKILL_IMPROVISE_DB, skill->parse_row_improvisedb); - sv->readdb(iMap->db_path, "skill_changematerial_db.txt" , ',', 4, 4+2*5, MAX_SKILL_PRODUCE_DB, skill->parse_row_changematerialdb); + sv->readdb(map->db_path, "magicmushroom_db.txt", ',', 1, 1, MAX_SKILL_MAGICMUSHROOM_DB, skill->parse_row_magicmushroomdb); + sv->readdb(map->db_path, "skill_reproduce_db.txt", ',', 1, 1, MAX_SKILL_DB, skill->parse_row_reproducedb); + sv->readdb(map->db_path, "skill_improvise_db.txt", ',', 2, 2, MAX_SKILL_IMPROVISE_DB, skill->parse_row_improvisedb); + sv->readdb(map->db_path, "skill_changematerial_db.txt", ',', 4, 4+2*5, MAX_SKILL_PRODUCE_DB, skill->parse_row_changematerialdb); } void skill_reload (void) { @@ -17828,21 +18502,21 @@ void skill_reload (void) { struct map_session_data *sd; int i,c,k; - skill->read_db(); + skill->read_db(false); //[Ind/Hercules] refresh index cache for(c = 0; c < CLASS_COUNT; c++) { for( i = 0; i < MAX_SKILL_TREE; i++ ) { - if( skill_tree[c][i].id ) { - skill_tree[c][i].idx = skill->get_index(skill_tree[c][i].id); + if( pc->skill_tree[c][i].id ) { + pc->skill_tree[c][i].idx = skill->get_index(pc->skill_tree[c][i].id); for(k = 0; k < MAX_PC_SKILL_REQUIRE; k++) { - if( skill_tree[c][i].need[k].id ) - skill_tree[c][i].need[k].idx = skill->get_index(skill_tree[c][i].need[k].id); + if( pc->skill_tree[c][i].need[k].id ) + pc->skill_tree[c][i].need[k].idx = skill->get_index(pc->skill_tree[c][i].need[k].id); } } } } - chrif_skillid2idx(0); + chrif->skillid2idx(0); /* lets update all players skill tree : so that if any skill modes were changed they're properly updated */ iter = mapit_getallusers(); for( sd = (TBL_PC*)mapit->first(iter); mapit->exists(iter); sd = (TBL_PC*)mapit->next(iter) ) @@ -17854,47 +18528,97 @@ void skill_reload (void) { /*========================================== * *------------------------------------------*/ -int do_init_skill (void) { - skilldb_name2id = strdb_alloc(DB_OPT_DUP_KEY|DB_OPT_RELEASE_DATA, 0); - skill->read_db(); - - group_db = idb_alloc(DB_OPT_BASE); - skillunit_db = idb_alloc(DB_OPT_BASE); - skillcd_db = idb_alloc(DB_OPT_RELEASE_DATA); - skillusave_db = idb_alloc(DB_OPT_RELEASE_DATA); - skill_unit_ers = ers_new(sizeof(struct skill_unit_group),"skill.c::skill_unit_ers",ERS_OPT_NONE); - skill_timer_ers = ers_new(sizeof(struct skill_timerskill),"skill.c::skill_timer_ers",ERS_OPT_NONE); +int do_init_skill(bool minimal) { + skill->name2id_db = strdb_alloc(DB_OPT_DUP_KEY|DB_OPT_RELEASE_DATA, MAX_SKILL_NAME_LENGTH); + skill->read_db(minimal); - iTimer->add_timer_func_list(skill->unit_timer,"skill_unit_timer"); - iTimer->add_timer_func_list(skill->castend_id,"skill_castend_id"); - iTimer->add_timer_func_list(skill->castend_pos,"skill_castend_pos"); - iTimer->add_timer_func_list(skill->timerskill,"skill_timerskill"); - iTimer->add_timer_func_list(skill->blockpc_end, "skill_blockpc_end"); + if (minimal) + return 0; - iTimer->add_timer_interval(iTimer->gettick()+SKILLUNITTIMER_INTERVAL,skill->unit_timer,0,0,SKILLUNITTIMER_INTERVAL); + skill->group_db = idb_alloc(DB_OPT_BASE); + skill->unit_db = idb_alloc(DB_OPT_BASE); + skill->cd_db = idb_alloc(DB_OPT_BASE); + skill->usave_db = idb_alloc(DB_OPT_RELEASE_DATA); + skill->bowling_db = idb_alloc(DB_OPT_BASE); + skill->unit_ers = ers_new(sizeof(struct skill_unit_group),"skill.c::skill_unit_ers",ERS_OPT_CLEAN|ERS_OPT_FLEX_CHUNK); + skill->timer_ers = ers_new(sizeof(struct skill_timerskill),"skill.c::skill_timer_ers",ERS_OPT_NONE|ERS_OPT_FLEX_CHUNK); + skill->cd_ers = ers_new(sizeof(struct skill_cd),"skill.c::skill_cd_ers",ERS_OPT_CLEAR|ERS_OPT_CLEAN|ERS_OPT_FLEX_CHUNK); + skill->cd_entry_ers = ers_new(sizeof(struct skill_cd_entry),"skill.c::skill_cd_entry_ers",ERS_OPT_CLEAR|ERS_OPT_FLEX_CHUNK); + + ers_chunk_size(skill->cd_ers, 25); + ers_chunk_size(skill->cd_entry_ers, 100); + ers_chunk_size(skill->unit_ers, 150); + ers_chunk_size(skill->timer_ers, 150); + + timer->add_func_list(skill->unit_timer,"skill_unit_timer"); + timer->add_func_list(skill->castend_id,"skill_castend_id"); + timer->add_func_list(skill->castend_pos,"skill_castend_pos"); + timer->add_func_list(skill->timerskill,"skill_timerskill"); + timer->add_func_list(skill->blockpc_end, "skill_blockpc_end"); + timer->add_interval(timer->gettick()+SKILLUNITTIMER_INTERVAL,skill->unit_timer,0,0,SKILLUNITTIMER_INTERVAL); + return 0; } -int do_final_skill(void) -{ - db_destroy(skilldb_name2id); - db_destroy(group_db); - db_destroy(skillunit_db); - db_destroy(skillcd_db); - db_destroy(skillusave_db); - ers_destroy(skill_unit_ers); - ers_destroy(skill_timer_ers); +int do_final_skill(void) { + + db_destroy(skill->name2id_db); + db_destroy(skill->group_db); + db_destroy(skill->unit_db); + db_destroy(skill->cd_db); + db_destroy(skill->usave_db); + db_destroy(skill->bowling_db); + ers_destroy(skill->unit_ers); + ers_destroy(skill->timer_ers); + ers_destroy(skill->cd_ers); + ers_destroy(skill->cd_entry_ers); return 0; } /* initialize the interface */ void skill_defaults(void) { + const int skill_enchant_eff[5] = { 10, 14, 17, 19, 20 }; + const int skill_deluge_eff[5] = { 5, 9, 12, 14, 15 }; + skill = &skill_s; skill->init = do_init_skill; skill->final = do_final_skill; skill->reload = skill_reload; skill->read_db = skill_readdb; - /* accesssors */ + /* */ + skill->cd_db = NULL; + skill->name2id_db = NULL; + skill->unit_db = NULL; + skill->usave_db = NULL; + skill->bowling_db = NULL; + skill->group_db = NULL; + /* */ + skill->unit_ers = NULL; + skill->timer_ers = NULL; + skill->cd_ers = NULL; + skill->cd_entry_ers = NULL; + /* one huge 0, follows skill.h order */ + memset(skill->db,0,sizeof(skill->db) + + sizeof(skill->produce_db) + + sizeof(skill->arrow_db) + + sizeof(skill->abra_db) + + sizeof(skill->magicmushroom_db) + + sizeof(skill->improvise_db) + + sizeof(skill->changematerial_db) + + sizeof(skill->spellbook_db) + + sizeof(skill->reproduce_db) + + sizeof(skill->unit_layout) + ); + /* */ + memcpy(skill->enchant_eff, skill_enchant_eff, sizeof(skill->enchant_eff)); + memcpy(skill->deluge_eff, skill_deluge_eff, sizeof(skill->deluge_eff)); + skill->firewall_unit_pos = 0; + skill->icewall_unit_pos = 0; + skill->earthstrain_unit_pos = 0; + memset(&skill->area_temp,0,sizeof(skill->area_temp)); + memset(&skill->unit_temp,0,sizeof(skill->unit_temp)); + skill->unit_group_newid = 0; + /* accessors */ skill->get_index = skill_get_index; skill->get_type = skill_get_type; skill->get_hit = skill_get_hit; @@ -17909,6 +18633,7 @@ void skill_defaults(void) { skill->get_mhp = skill_get_mhp; skill->get_sp = skill_get_sp; skill->get_state = skill_get_state; + skill->get_spiritball = skill_get_spiritball; skill->get_zeny = skill_get_zeny; skill->get_num = skill_get_num; skill->get_cast = skill_get_cast; @@ -17931,7 +18656,6 @@ void skill_defaults(void) { skill->get_unit_target = skill_get_unit_target; skill->get_unit_interval = skill_get_unit_interval; skill->get_unit_bl_target = skill_get_unit_bl_target; - skill->get_spiritball = skill_get_spiritball; skill->get_unit_layout_type = skill_get_unit_layout_type; skill->get_unit_range = skill_get_unit_range; skill->get_cooldown = skill_get_cooldown; @@ -17941,6 +18665,7 @@ void skill_defaults(void) { skill->chk = skill_chk; skill->get_casttype = skill_get_casttype; skill->get_casttype2 = skill_get_casttype2; + skill->is_combo = skill_is_combo; skill->name2id = skill_name2id; skill->isammotype = skill_isammotype; skill->castend_id = skill_castend_id; @@ -17964,22 +18689,18 @@ void skill_defaults(void) { skill->unit_onplace = skill_unit_onplace; skill->unit_ondamaged = skill_unit_ondamaged; skill->cast_fix = skill_castfix; - skill->cast_fix_sc = skill_castfix_sc; -#ifdef RENEWAL_CAST + skill->cast_fix_sc = skill_castfix_sc; skill->vf_cast_fix = skill_vfcastfix; -#endif skill->delay_fix = skill_delay_fix; skill->check_condition_castbegin = skill_check_condition_castbegin; skill->check_condition_castend = skill_check_condition_castend; - skill->check_condition_char_sub = skill_check_condition_char_sub; + skill->consume_requirement = skill_consume_requirement; skill->get_requirement = skill_get_requirement; skill->check_pc_partner = skill_check_pc_partner; - skill->consume_requirement = skill_consume_requirement; skill->unit_move = skill_unit_move; - skill->unit_move_unit_group = skill_unit_move_unit_group; skill->unit_onleft = skill_unit_onleft; skill->unit_onout = skill_unit_onout; - skill->guildaura_sub = skill_guildaura_sub; + skill->unit_move_unit_group = skill_unit_move_unit_group; skill->sit = skill_sit; skill->brandishspear = skill_brandishspear; skill->repairweapon = skill_repairweapon; @@ -17988,6 +18709,8 @@ void skill_defaults(void) { skill->autospell = skill_autospell; skill->calc_heal = skill_calc_heal; skill->check_cloaking = skill_check_cloaking; + skill->check_cloaking_end = skill_check_cloaking_end; + skill->can_cloak = skill_can_cloak; skill->enchant_elemental_end = skill_enchant_elemental_end; skill->not_ok = skillnotok; skill->not_ok_hom = skillnotok_hom; @@ -18019,7 +18742,7 @@ void skill_defaults(void) { skill->check_condition_mercenary = skill_check_condition_mercenary; skill->locate_element_field = skill_locate_element_field; skill->graffitiremover = skill_graffitiremover; - skill->activate_reverberation = skill_activate_reverbetion; + skill->activate_reverberation = skill_activate_reverberation; skill->dance_overlap = skill_dance_overlap; skill->dance_overlap_sub = skill_dance_overlap_sub; skill->get_unit_layout = skill_get_unit_layout; @@ -18033,9 +18756,7 @@ void skill_defaults(void) { skill->check_condition_mob_master_sub = skill_check_condition_mob_master_sub; skill->brandishspear_first = skill_brandishspear_first; skill->brandishspear_dir = skill_brandishspear_dir; -#ifdef RENEWAL_CAST skill->get_fixed_cast = skill_get_fixed_cast; -#endif skill->sit_count = skill_sit_count; skill->sit_in = skill_sit_in; skill->sit_out = skill_sit_out; @@ -18077,5 +18798,7 @@ void skill_defaults(void) { skill->elementalanalysis = skill_elementalanalysis; skill->changematerial = skill_changematerial; skill->get_elemental_type = skill_get_elemental_type; - + skill->cooldown_save = skill_cooldown_save; + skill->get_new_group_id = skill_get_new_group_id; + skill->check_shadowform = skill_check_shadowform; } diff --git a/src/map/skill.h b/src/map/skill.h index cc9ac4bfc..6373d9275 100644 --- a/src/map/skill.h +++ b/src/map/skill.h @@ -2,22 +2,26 @@ // See the LICENSE file // Portions Copyright (c) Athena Dev Teams -#ifndef _SKILL_H_ -#define _SKILL_H_ +#ifndef MAP_SKILL_H +#define MAP_SKILL_H + +#include "../config/core.h" // RENEWAL_CAST -#include "../common/mmo.h" // MAX_SKILL, struct square -#include "../common/db.h" #include "map.h" // struct block_list +#include "status.h" // enum sc_type +#include "../common/cbasetypes.h" +#include "../common/db.h" +#include "../common/mmo.h" // MAX_SKILL, struct square /** * Declarations **/ -struct map_session_data; struct homun_data; +struct map_session_data; +struct mercenary_data; struct skill_unit; -struct skill_unit_group; -struct status_change_entry; struct square; +struct status_change_entry; /** * Defines @@ -37,6 +41,7 @@ struct square; #define MAX_SKILLUNITGROUP 25 #define MAX_SKILL_ITEM_REQUIRE 10 #define MAX_SKILLUNITGROUPTICKSET 25 +#define MAX_SKILL_NAME_LENGTH 30 // (Epoque:) To-do: replace this macro with some sort of skill tree check (rather than hard-coded skill names) #define skill_ischangesex(id) ( \ @@ -161,7 +166,7 @@ enum { enum e_skill { NV_BASIC = 1, - + SM_SWORD, SM_TWOHAND, SM_RECOVERY, @@ -169,7 +174,7 @@ enum e_skill { SM_PROVOKE, SM_MAGNUM, SM_ENDURE, - + MG_SRECOVERY, MG_SIGHT, MG_NAPALMBEAT, @@ -183,7 +188,7 @@ enum e_skill { MG_FIREBOLT, MG_LIGHTNINGBOLT, MG_THUNDERSTORM, - + AL_DP, AL_DEMONBANE, AL_RUWACH, @@ -198,7 +203,7 @@ enum e_skill { AL_ANGELUS, AL_BLESSING, AL_CURE, - + MC_INCCARRY, MC_DISCOUNT, MC_OVERCHARGE, @@ -206,22 +211,22 @@ enum e_skill { MC_IDENTIFY, MC_VENDING, MC_MAMMONITE, - + AC_OWL, AC_VULTURE, AC_CONCENTRATION, AC_DOUBLE, AC_SHOWER, - + TF_DOUBLE, TF_MISS, TF_STEAL, TF_HIDING, TF_POISON, TF_DETOXIFY, - + ALL_RESURRECTION, - + KN_SPEARMASTERY, KN_PIERCE, KN_BRANDISHSPEAR, @@ -232,7 +237,7 @@ enum e_skill { KN_BOWLINGBASH, KN_RIDING, KN_CAVALIERMASTERY, - + PR_MACEMASTERY, PR_IMPOSITIO, PR_SUFFRAGIUM, @@ -248,7 +253,7 @@ enum e_skill { PR_TURNUNDEAD, PR_LEXAETERNA, PR_MAGNUS, - + WZ_FIREPILLAR, WZ_SIGHTRASHER, WZ_FIREIVY, @@ -263,7 +268,7 @@ enum e_skill { WZ_HEAVENDRIVE, WZ_QUAGMIRE, WZ_ESTIMATION, - + BS_IRON, BS_STEEL, BS_ENCHANTEDSTONE, @@ -285,7 +290,7 @@ enum e_skill { BS_WEAPONPERFECT, BS_OVERTHRUST, BS_MAXIMIZE, - + HT_SKIDTRAP, HT_LANDMINE, HT_ANKLESNARE, @@ -303,7 +308,7 @@ enum e_skill { HT_BLITZBEAT, HT_DETECTING, HT_SPRINGTRAP, - + AS_RIGHT, AS_LEFT, AS_KATAR, @@ -314,7 +319,7 @@ enum e_skill { AS_POISONREACT, AS_VENOMDUST, AS_SPLASHER, - + NV_FIRSTAID, NV_TRICKDEAD, SM_MOVINGRECOVERY, @@ -331,7 +336,7 @@ enum e_skill { MC_LOUD, AL_HOLYLIGHT, MG_ENERGYCOAT, - + NPC_PIERCINGATT, NPC_MENTALBREAKER, NPC_RANGEATTACK, @@ -384,7 +389,7 @@ enum e_skill { NPC_HALLUCINATION, NPC_REBIRTH, NPC_SUMMONMONSTER, - + RG_SNATCHER, RG_STEALCOIN, RG_BACKSTAP, @@ -401,7 +406,7 @@ enum e_skill { RG_GANGSTER, RG_COMPULSION, RG_PLAGIARISM, - + AM_AXEMASTERY, AM_LEARNINGPOTION, AM_PHARMACY, @@ -424,7 +429,7 @@ enum e_skill { AM_DRILLMASTER, AM_HEALHOMUN, AM_RESURRECTHOMUN, - + CR_TRUST, CR_AUTOGUARD, CR_SHIELDCHARGE, @@ -436,7 +441,7 @@ enum e_skill { CR_PROVIDENCE, CR_DEFENDER, CR_SPEARQUICKEN, - + MO_IRONHAND, MO_SPIRITSRECOVERY, MO_CALLSPIRITS, @@ -452,7 +457,7 @@ enum e_skill { MO_EXTREMITYFIST, MO_CHAINCOMBO, MO_COMBOFINISH, - + SA_ADVANCEDBOOK, SA_CASTCANCEL, SA_MAGICROD, @@ -483,7 +488,7 @@ enum e_skill { SA_INSTANTDEATH, SA_FULLRECOVERY, SA_COMA, - + BD_ADAPTATION, BD_ENCORE, BD_LULLABY, @@ -495,7 +500,7 @@ enum e_skill { BD_INTOABYSS, BD_SIEGFRIED, BD_RAGNAROK, - + BA_MUSICALLESSON, BA_MUSICALSTRIKE, BA_DISSONANCE, @@ -504,7 +509,7 @@ enum e_skill { BA_ASSASSINCROSS, BA_POEMBRAGI, BA_APPLEIDUN, - + DC_DANCINGLESSON, DC_THROWARROW, DC_UGLYDANCE, @@ -513,17 +518,17 @@ enum e_skill { DC_DONTFORGETME, DC_FORTUNEKISS, DC_SERVICEFORYOU, - + NPC_RANDOMMOVE, NPC_SPEEDUP, NPC_REVENGE, - + WE_MALE, WE_FEMALE, WE_CALLPARTNER, - + ITM_TOMAHAWK, - + NPC_DARKCROSS, NPC_GRANDDARKNESS, NPC_DARKSTRIKE, @@ -541,7 +546,7 @@ enum e_skill { NPC_CALLSLAVE, NPC_INVISIBLE, NPC_RUN, - + LK_AURABLADE, LK_PARRYING, LK_CONCENTRATION, @@ -595,10 +600,11 @@ enum e_skill { PF_SPIDERWEB, ASC_METEORASSAULT, ASC_CDP, + WE_BABY, WE_CALLPARENT, WE_CALLBABY, - + TK_RUN, TK_READYSTORM, TK_STORMKICK, @@ -615,7 +621,7 @@ enum e_skill { TK_POWER, TK_SEVENWIND, TK_HIGHJUMP, - + SG_FEEL, SG_SUN_WARM, SG_MOON_WARM, @@ -634,7 +640,7 @@ enum e_skill { SG_FRIEND, SG_KNOWLEDGE, SG_FUSION, - + SL_ALCHEMIST, AM_BERSERKPITCHER, SL_MONK, @@ -663,7 +669,7 @@ enum e_skill { SL_SWOO, SL_SKE, SL_SKA, - + SM_SELFPROVOKE, NPC_EMOTION_ON, ST_PRESERVE, @@ -691,7 +697,7 @@ enum e_skill { AM_TWILIGHT2, AM_TWILIGHT3, HT_POWER, - + GS_GLITTERING, GS_FLING, GS_TRIPLEACTION, @@ -714,7 +720,7 @@ enum e_skill { GS_FULLBUSTER, GS_SPREADATTACK, GS_GROUNDDRIFT, - + NJ_TOBIDOUGU, NJ_SYURIKEN, NJ_KUNAI, @@ -738,7 +744,7 @@ enum e_skill { NJ_KAMAITACHI, NJ_NEN, NJ_ISSEN, - + MB_FIGHTING, MB_NEUTRAL, MB_TAIMING_PUTI, @@ -766,7 +772,7 @@ enum e_skill { MB_M_WALLCRASH, MB_M_REINCARNATION, MB_B_EQUIP, - + SL_DEATHKNIGHT, SL_COLLECTOR, SL_NINJA, @@ -775,7 +781,7 @@ enum e_skill { DA_RESET, DE_BERSERKAIZER, DA_DARKPOWER, - + DE_PASSIVE, DE_PATTACK, DE_PSPEED, @@ -815,7 +821,7 @@ enum e_skill { DE_TWINATTACK, DE_WINDATTACK, DE_WATERATTACK, - + DA_ENERGY, DA_CLOUD, DA_FIRSTSLOT, @@ -850,7 +856,7 @@ enum e_skill { ALL_TIMEIN, DA_ZENYRANK, DA_ACCESSORYMIX, - + NPC_EARTHQUAKE, NPC_FIREBREATH, NPC_ICEBREATH, @@ -879,7 +885,6 @@ enum e_skill { NPC_WIDESTUN, NPC_VAMPIRE_GIFT, NPC_WIDESOULDRAIN, - ALL_INCCARRY, NPC_TALK, NPC_HELLPOWER, @@ -908,7 +913,31 @@ enum e_skill { NPC_VENOMFOG, NPC_MILLENNIUMSHIELD, NPC_COMET, - +// TODO: What PACKETVER are these skills added? [Panikon] +// After this addition all skills from NPC_WIDEWEB to NPC_LEX_AETERNA +// will have their IDs changed +#if PACKETVER >= 20140205 + NPC_ICEMINE, + NPC_ICEEXPLO, + NPC_FLAMECROSS, + NPC_PULSESTRIKE2, + NPC_DANCINGBLADE, + NPC_DANCINGBLADE_ATK, + NPC_DARKPIERCING, + NPC_MAXPAIN, + NPC_MAXPAIN_ATK, + NPC_DEATHSUMMON, + NPC_HELLBURNING, + NPC_JACKFROST, +#endif + NPC_WIDEWEB, + NPC_WIDESUCK, + NPC_STORMGUST2, + NPC_FIRESTORM, + NPC_REVERBERATION, + NPC_REVERBERATION_ATK, + NPC_LEX_AETERNA, + KN_CHARGEATK = 1001, CR_SHRINK, AS_SONICACCEL, @@ -928,7 +957,7 @@ enum e_skill { SA_ELEMENTGROUND, SA_ELEMENTFIRE, SA_ELEMENTWIND, - + RK_ENCHANTBLADE = 2001, RK_SONICWAVE, RK_DEATHBOUND, @@ -949,7 +978,7 @@ enum e_skill { RK_FIGHTINGSPIRIT, RK_ABUNDANCE, RK_PHANTOMTHRUST, - + GC_VENOMIMPRESS, GC_CROSSIMPACT, GC_DARKILLUSION, @@ -967,7 +996,7 @@ enum e_skill { GC_HALLUCINATIONWALK, GC_ROLLINGCUTTER, GC_CROSSRIPPERSLASHER, - + AB_JUDEX, AB_ANCILLA, AB_ADORAMUS, @@ -988,7 +1017,7 @@ enum e_skill { AB_DUPLELIGHT_MELEE, AB_DUPLELIGHT_MAGIC, AB_SILENTIUM, - + WL_WHITEIMPRISON = 2201, WL_SOULEXPANSION, WL_FROSTMISTY, @@ -1021,7 +1050,7 @@ enum e_skill { WL_RELEASE, WL_READING_SB, WL_FREEZE_SP, - + RA_ARROWSTORM, RA_FEARBREEZE, RA_RANGERMAIN, @@ -1044,7 +1073,7 @@ enum e_skill { RA_VERDURETRAP, RA_FIRINGTRAP, RA_ICEBOUNDTRAP, - + NC_MADOLICENCE, NC_BOOSTKNUCKLE, NC_PILEBUNKER, @@ -1074,7 +1103,7 @@ enum e_skill { NC_SILVERSNIPER, NC_MAGICDECOY, NC_DISJOINT, - + SC_FATALMENACE, SC_REPRODUCE, SC_AUTOSHADOWSPELL, @@ -1096,7 +1125,7 @@ enum e_skill { SC_MAELSTROM, SC_BLOODYLUST, SC_FEINTBOMB, - + LG_CANNONSPEAR = 2307, LG_BANISHINGPOINT, LG_TRAMPLE, @@ -1116,7 +1145,7 @@ enum e_skill { LG_EARTHDRIVE, LG_HESPERUSLIT, LG_INSPIRATION, - + SR_DRAGONCOMBO, SR_SKYNETBLOW, SR_EARTHSHAKER, @@ -1140,15 +1169,15 @@ enum e_skill { SR_GENTLETOUCH_ENERGYGAIN, SR_GENTLETOUCH_CHANGE, SR_GENTLETOUCH_REVITALIZE, - + WA_SWING_DANCE = 2350, WA_SYMPHONY_OF_LOVER, WA_MOONLIT_SERENADE, - + MI_RUSH_WINDMILL = 2381, MI_ECHOSONG, MI_HARMONIZE, - + WM_LESSON = 2412, WM_METALICSOUND, WM_REVERBERATION, @@ -1172,7 +1201,7 @@ enum e_skill { WM_MELODYOFSINK, WM_BEYOND_OF_WARCRY, WM_UNLIMITED_HUMMING_VOICE, - + SO_FIREWALK = 2443, SO_ELECTRICWALK, SO_SPELLFIST, @@ -1199,7 +1228,7 @@ enum e_skill { SO_WATER_INSIGNIA, SO_WIND_INSIGNIA, SO_EARTH_INSIGNIA, - + GN_TRAINING_SWORD = 2474, GN_REMODELING_CART, GN_CART_TORNADO, @@ -1225,14 +1254,14 @@ enum e_skill { GN_MAKEBOMB, GN_S_PHARMACY, GN_SLINGITEM_RANGEMELEEATK, - + AB_SECRAMENT = 2515, WM_SEVERE_RAINSTORM_MELEE, SR_HOWLINGOFLION, SR_RIDEINLIGHTNING, LG_OVERBRAND_BRANDISH, LG_OVERBRAND_PLUSATK, - + ALL_ODINS_RECALL = 2533, RETURN_TO_ELDICASTES, ALL_BUYING_STORE, @@ -1245,7 +1274,37 @@ enum e_skill { ALL_TETANY, ALL_RAY_OF_PROTECTION, MC_CARTDECORATE, - + GM_ITEM_ATKMAX, + GM_ITEM_ATKMIN, + GM_ITEM_MATKMAX, + GM_ITEM_MATKMIN, + ALL_LIGHTGUARD, + + RL_GLITTERING_GREED = 2551, + RL_RICHS_COIN, + RL_MASS_SPIRAL, + RL_BANISHING_BUSTER, + RL_B_TRAP, + RL_FLICKER, + RL_S_STORM, + RL_E_CHAIN, + RL_QD_SHOT, + RL_C_MARKER, + RL_FIREDANCE, + RL_H_MINE, + RL_P_ALTER, + RL_FALLEN_ANGEL, + RL_R_TRIP, + RL_D_TAIL, + RL_FIRE_RAIN, + RL_HEAT_BARREL, + RL_AM_BLAST, + RL_SLUGSHOT, + RL_HAMMER_OF_GOD, + RL_R_TRIP_PLUSATK, + RL_B_FLICKER_ATK, + RL_GLITTERING_GREED_ATK, + KO_YAMIKUMO = 3001, KO_RIGHT, KO_LEFT, @@ -1275,12 +1334,17 @@ enum e_skill { OB_OBOROGENSOU, OB_OBOROGENSOU_TRANSITION_ATK, OB_AKAITSUKI, - + ECL_SNOWFLIP = 3031, ECL_PEONYMAMY, ECL_SADAGUI, ECL_SEQUOIADUST, ECLAGE_RECALL, + BA_POEMBRAGI2, + DC_FORTUNEKISS2, + ITEM_OPTION_SPLASH_ATTACK, + GM_FORCE_TRANSFER, + GM_WIDE_RESURRECTION, GC_DARKCROW = 5001, RA_UNLIMIT, @@ -1296,10 +1360,7 @@ enum e_skill { WL_TELEKINESIS_INTENSE, LG_KINGS_GRACE, ALL_FULL_THROTTLE, - SR_FLASHCOMBO_ATK_STEP1, - SR_FLASHCOMBO_ATK_STEP2, - SR_FLASHCOMBO_ATK_STEP3, - SR_FLASHCOMBO_ATK_STEP4, + NC_MAGMA_ERUPTION_DOTDAMAGE, HLIF_HEAL = 8001, HLIF_AVOID, @@ -1344,7 +1405,7 @@ enum e_skill { MH_LAVA_SLIDE, MH_PYROCLASTIC, MH_VOLCANIC_ASH, - + MS_BASH = 8201, MS_MAGNUM, MS_BOWLINGBASH, @@ -1385,7 +1446,8 @@ enum e_skill { MER_KYRIE, MER_BLESSING, MER_INCAGI, - + MER_INVINCIBLEOFF2, + EL_CIRCLE_OF_FIRE = 8401, EL_FIRE_CLOAK, EL_FIRE_MANTLE, @@ -1560,10 +1622,14 @@ enum { UNT_ZENKAI_WIND, UNT_MAKIBISHI, UNT_VENOMFOG, - UNT_ICEMINE, - UNT_FLAMECROSS, - UNT_HELLBURNING, - UNT_MAGMA_ERUPTION, + UNT_ICEMINE, + UNT_FLAMECROSS, + UNT_HELLBURNING, + UNT_MAGMA_ERUPTION, + UNT_KINGS_GRACE, + UNT_GLITTERING_GREED, + UNT_B_TRAP, + UNT_FIRE_RAIN, /** * Guild Auras @@ -1576,17 +1642,6 @@ enum { UNT_MAX = 0x190 }; -enum gx_poison { - PO_PARALYSE = 12717, - PO_LEECHESEND, - PO_OBLIVIONCURSE, - PO_DEATHHURT, - PO_TOXIN, - PO_PYREXIA, - PO_MAGICMUSHROOM, - PO_VENOMBLEED -}; - /** * Structures **/ @@ -1599,7 +1654,7 @@ struct skill_condition { // Database skills struct s_skill_db { unsigned short nameid; - char name[NAME_LENGTH]; + char name[MAX_SKILL_NAME_LENGTH]; char desc[40]; int range[MAX_SKILL_LEVEL],hit,inf,element[MAX_SKILL_LEVEL],nk,splash[MAX_SKILL_LEVEL],max; int num[MAX_SKILL_LEVEL]; @@ -1623,7 +1678,6 @@ struct s_skill_db { int unit_target; int unit_flag; }; -extern struct s_skill_db skill_db[MAX_SKILL_DB]; struct s_skill_unit_layout { int count; @@ -1650,7 +1704,7 @@ struct skill_unit_group { int map; int target_flag; //Holds BCT_* flag for battle_check_target int bl_flag; //Holds BL_* flag for map_foreachin* functions - unsigned int tick; + int64 tick; int limit,interval; uint16 skill_id,skill_lv; @@ -1679,7 +1733,7 @@ struct skill_unit { }; struct skill_unit_group_tickset { - unsigned int tick; + int64 tick; int id; }; @@ -1689,14 +1743,12 @@ struct s_skill_produce_db { int req_skill,req_skill_lv,itemlv; int mat_id[MAX_PRODUCE_RESOURCE],mat_amount[MAX_PRODUCE_RESOURCE]; }; -extern struct s_skill_produce_db skill_produce_db[MAX_SKILL_PRODUCE_DB]; // Creating database arrow struct s_skill_arrow_db { int nameid, trigger; int cre_id[MAX_ARROW_RESOURCE],cre_amount[MAX_ARROW_RESOURCE]; }; -extern struct s_skill_arrow_db skill_arrow_db[MAX_SKILL_ARROW_DB]; // Abracadabra database struct s_skill_abra_db { @@ -1704,29 +1756,101 @@ struct s_skill_abra_db { int req_lv; int per; }; -extern struct s_skill_abra_db skill_abra_db[MAX_SKILL_ABRA_DB]; //GCross magic mushroom database struct s_skill_magicmushroom_db { uint16 skill_id; }; -extern struct s_skill_magicmushroom_db skill_magicmushroom_db[MAX_SKILL_MAGICMUSHROOM_DB]; + +struct skill_cd_entry { + int duration;//milliseconds +#if PACKETVER >= 20120604 + int total;/* used for display on newer clients */ +#endif + short skidx;//the skill index entries belong to + int64 started;/* gettick() of when it started, used vs duration to measure how much left upon logout */ + int timer;/* timer id */ + uint16 skill_id;//skill id +}; + +/** + * Skill Cool Down Delay Saving + * Struct skill_cd is not a member of struct map_session_data + * to keep cooldowns in memory between player log-ins. + * All cooldowns are reset when server is restarted. + **/ +struct skill_cd { + struct skill_cd_entry *entry[MAX_SKILL_TREE]; + unsigned char cursor; +}; /** - * Vars + * Skill Unit Persistency during endack routes (mostly for songs see bugreport:4574) **/ -extern int enchant_eff[5]; -extern int deluge_eff[5]; -DBMap* skilldb_name2id; +struct skill_unit_save { + uint16 skill_id, skill_lv; +}; + +struct s_skill_improvise_db { + uint16 skill_id; + short per;//1-10000 +}; + +struct s_skill_changematerial_db { + int itemid; + short rate; + int qty[5]; + short qty_rate[5]; +}; + +struct s_skill_spellbook_db { + int nameid; + uint16 skill_id; + int point; +}; + +typedef int (*SkillFunc)(struct block_list *src, struct block_list *target, uint16 skill_id, uint16 skill_lv, int64 tick, int flag); /** * Skill.c Interface **/ struct skill_interface { - int (*init) (void); + int (*init) (bool minimal); int (*final) (void); void (*reload) (void); - void (*read_db) (void); + void (*read_db) (bool minimal); + /* */ + DBMap* cd_db; // char_id -> struct skill_cd + DBMap* name2id_db; + DBMap* unit_db; // int id -> struct skill_unit* + DBMap* usave_db; // char_id -> struct skill_unit_save + DBMap* group_db;// int group_id -> struct skill_unit_group* + DBMap* bowling_db;// int mob_id -> struct mob_data*s + /* */ + struct eri *unit_ers; //For handling skill_unit's [Skotlex] + struct eri *timer_ers; //For handling skill_timerskills [Skotlex] + struct eri *cd_ers; // ERS Storage for skill cool down managers [Ind/Hercules] + struct eri *cd_entry_ers; // ERS Storage for skill cool down entries [Ind/Hercules] + /* */ + struct s_skill_db db[MAX_SKILL_DB]; + struct s_skill_produce_db produce_db[MAX_SKILL_PRODUCE_DB]; + struct s_skill_arrow_db arrow_db[MAX_SKILL_ARROW_DB]; + struct s_skill_abra_db abra_db[MAX_SKILL_ABRA_DB]; + struct s_skill_magicmushroom_db magicmushroom_db[MAX_SKILL_MAGICMUSHROOM_DB]; + struct s_skill_improvise_db improvise_db[MAX_SKILL_IMPROVISE_DB]; + struct s_skill_changematerial_db changematerial_db[MAX_SKILL_PRODUCE_DB]; + struct s_skill_spellbook_db spellbook_db[MAX_SKILL_SPELLBOOK_DB]; + bool reproduce_db[MAX_SKILL_DB]; + struct s_skill_unit_layout unit_layout[MAX_SKILL_UNIT_LAYOUT]; + /* */ + int enchant_eff[5]; + int deluge_eff[5]; + int firewall_unit_pos; + int icewall_unit_pos; + int earthstrain_unit_pos; + int area_temp[8]; + int unit_temp[20]; // temporary storage for tracking skill unit skill ids as players move in/out of them + int unit_group_newid; /* accesssors */ int (*get_index) ( uint16 skill_id ); int (*get_type) ( uint16 skill_id ); @@ -1772,56 +1896,56 @@ struct skill_interface { const char* (*get_name) ( uint16 skill_id ); const char* (*get_desc) ( uint16 skill_id ); /* check */ - void (*chk) (int16* skill_id); + void (*chk) (uint16* skill_id); /* whether its CAST_GROUND, CAST_DAMAGE or CAST_NODAMAGE */ int (*get_casttype) (uint16 skill_id); int (*get_casttype2) (uint16 index); + bool (*is_combo) (int skill_id); int (*name2id) (const char* name); - int (*isammotype) (struct map_session_data *sd, int skill); - int (*castend_id) (int tid, unsigned int tick, int id, intptr_t data); - int (*castend_pos) (int tid, unsigned int tick, int id, intptr_t data); - int (*castend_map) ( struct map_session_data *sd,uint16 skill_id, const char *map); + int (*isammotype) (struct map_session_data *sd, int skill_id); + int (*castend_id) (int tid, int64 tick, int id, intptr_t data); + int (*castend_pos) (int tid, int64 tick, int id, intptr_t data); + int (*castend_map) ( struct map_session_data *sd,uint16 skill_id, const char *mapname); int (*cleartimerskill) (struct block_list *src); - int (*addtimerskill) (struct block_list *src,unsigned int tick,int target,int x,int y,uint16 skill_id,uint16 skill_lv,int type,int flag); - int (*additional_effect) ( struct block_list* src, struct block_list *bl,uint16 skill_id,uint16 skill_lv,int attack_type,int dmg_lv,unsigned int tick); - int (*counter_additional_effect) ( struct block_list* src, struct block_list *bl,uint16 skill_id,uint16 skill_lv,int attack_type,unsigned int tick); + int (*addtimerskill) (struct block_list *src, int64 tick, int target, int x, int y, uint16 skill_id, uint16 skill_lv, int type, int flag); + int (*additional_effect) (struct block_list* src, struct block_list *bl, uint16 skill_id, uint16 skill_lv, int attack_type, int dmg_lv, int64 tick); + int (*counter_additional_effect) (struct block_list* src, struct block_list *bl, uint16 skill_id, uint16 skill_lv, int attack_type, int64 tick); int (*blown) (struct block_list* src, struct block_list* target, int count, int8 dir, int flag); int (*break_equip) (struct block_list *bl, unsigned short where, int rate, int flag); int (*strip_equip) (struct block_list *bl, unsigned short where, int rate, int lv, int time); struct skill_unit_group* (*id2group) (int group_id); struct skill_unit_group *(*unitsetting) (struct block_list* src, uint16 skill_id, uint16 skill_lv, short x, short y, int flag); struct skill_unit *(*initunit) (struct skill_unit_group *group, int idx, int x, int y, int val1, int val2); - int (*delunit) (struct skill_unit *unit); + int (*delunit) (struct skill_unit *su); struct skill_unit_group *(*init_unitgroup) (struct block_list* src, int count, uint16 skill_id, uint16 skill_lv, int unit_id, int limit, int interval); int (*del_unitgroup) (struct skill_unit_group *group, const char* file, int line, const char* func); int (*clear_unitgroup) (struct block_list *src); int (*clear_group) (struct block_list *bl, int flag); - int (*unit_onplace) (struct skill_unit *src, struct block_list *bl, unsigned int tick); - int (*unit_ondamaged) (struct skill_unit *src,struct block_list *bl,int damage,unsigned int tick); + int (*unit_onplace) (struct skill_unit *src, struct block_list *bl, int64 tick); + int (*unit_ondamaged) (struct skill_unit *src, struct block_list *bl, int64 damage, int64 tick); int (*cast_fix) ( struct block_list *bl, uint16 skill_id, uint16 skill_lv); int (*cast_fix_sc) ( struct block_list *bl, int time); -#ifdef RENEWAL_CAST int (*vf_cast_fix) ( struct block_list *bl, double time, uint16 skill_id, uint16 skill_lv); -#endif int (*delay_fix) ( struct block_list *bl, uint16 skill_id, uint16 skill_lv); int (*check_condition_castbegin) (struct map_session_data *sd, uint16 skill_id, uint16 skill_lv); int (*check_condition_castend) (struct map_session_data *sd, uint16 skill_id, uint16 skill_lv); int (*consume_requirement) (struct map_session_data *sd, uint16 skill_id, uint16 skill_lv, short type); struct skill_condition (*get_requirement) (struct map_session_data *sd, uint16 skill_id, uint16 skill_lv); - int (*check_pc_partner) (struct map_session_data *sd, uint16 skill_id, short* skill_lv, int range, int cast_flag); - int (*unit_move) (struct block_list *bl,unsigned int tick,int flag); - int (*unit_onleft) (uint16 skill_id, struct block_list *bl,unsigned int tick); - int (*unit_onout) (struct skill_unit *src, struct block_list *bl, unsigned int tick); + int (*check_pc_partner) (struct map_session_data *sd, uint16 skill_id, uint16* skill_lv, int range, int cast_flag); + int (*unit_move) (struct block_list *bl, int64 tick, int flag); + int (*unit_onleft) (uint16 skill_id, struct block_list *bl, int64 tick); + int (*unit_onout) (struct skill_unit *src, struct block_list *bl, int64 tick); int (*unit_move_unit_group) ( struct skill_unit_group *group, int16 m,int16 dx,int16 dy); - int (*guildaura_sub) (struct map_session_data* sd, int id, int strvit, int agidex); int (*sit) (struct map_session_data *sd, int type); - void (*brandishspear) (struct block_list* src, struct block_list* bl, uint16 skill_id, uint16 skill_lv, unsigned int tick, int flag); + void (*brandishspear) (struct block_list* src, struct block_list* bl, uint16 skill_id, uint16 skill_lv, int64 tick, int flag); void (*repairweapon) (struct map_session_data *sd, int idx); void (*identify) (struct map_session_data *sd,int idx); void (*weaponrefine) (struct map_session_data *sd,int idx); int (*autospell) (struct map_session_data *md,uint16 skill_id); int (*calc_heal) (struct block_list *src, struct block_list *target, uint16 skill_id, uint16 skill_lv, bool heal); bool (*check_cloaking) (struct block_list *bl, struct status_change_entry *sce); + int (*check_cloaking_end) (struct block_list *bl, va_list ap); + bool (*can_cloak) (struct map_session_data *sd); int (*enchant_elemental_end) (struct block_list *bl, int type); int (*not_ok) (uint16 skill_id, struct map_session_data *sd); int (*not_ok_hom) (uint16 skill_id, struct homun_data *hd); @@ -1830,59 +1954,57 @@ struct skill_interface { int (*can_produce_mix) ( struct map_session_data *sd, int nameid, int trigger, int qty); int (*produce_mix) ( struct map_session_data *sd, uint16 skill_id, int nameid, int slot1, int slot2, int slot3, int qty ); int (*arrow_create) ( struct map_session_data *sd,int nameid); - int (*castend_nodamage_id) ( struct block_list *src, struct block_list *bl,uint16 skill_id,uint16 skill_lv,unsigned int tick,int flag ); - int (*castend_damage_id) ( struct block_list* src, struct block_list *bl,uint16 skill_id,uint16 skill_lv,unsigned int tick,int flag ); - int (*castend_pos2) ( struct block_list *src, int x,int y,uint16 skill_id,uint16 skill_lv,unsigned int tick,int flag); - int (*blockpc_start) (struct map_session_data*, uint16 skill_id, int, bool); - int (*blockhomun_start) (struct homun_data*,uint16 skill_id,int); - int (*blockmerc_start) (struct mercenary_data*,uint16 skill_id,int); - int (*attack) ( int attack_type, struct block_list* src, struct block_list *dsrc,struct block_list *bl,uint16 skill_id,uint16 skill_lv,unsigned int tick,int flag ); + int (*castend_nodamage_id) (struct block_list *src, struct block_list *bl, uint16 skill_id, uint16 skill_lv, int64 tick, int flag); + int (*castend_damage_id) (struct block_list* src, struct block_list *bl, uint16 skill_id, uint16 skill_lv, int64 tick,int flag); + int (*castend_pos2) (struct block_list *src, int x, int y, uint16 skill_id, uint16 skill_lv, int64 tick, int flag); + int (*blockpc_start) (struct map_session_data *sd, uint16 skill_id, int tick); + int (*blockhomun_start) (struct homun_data *hd, uint16 skill_id, int tick); + int (*blockmerc_start) (struct mercenary_data *md, uint16 skill_id, int tick); + int (*attack) (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 (*attack_area) (struct block_list *bl,va_list ap); int (*area_sub) (struct block_list *bl, va_list ap); - int (*area_sub_count) (struct block_list *src, struct block_list *target, uint16 skill_id, uint16 skill_lv, unsigned int tick, int flag); + int (*area_sub_count) (struct block_list *src, struct block_list *target, uint16 skill_id, uint16 skill_lv, int64 tick, int flag); int (*check_unit_range) (struct block_list *bl, int x, int y, uint16 skill_id, uint16 skill_lv); int (*check_unit_range_sub) (struct block_list *bl, va_list ap); int (*check_unit_range2) (struct block_list *bl, int x, int y, uint16 skill_id, uint16 skill_lv); int (*check_unit_range2_sub) (struct block_list *bl, va_list ap); void (*toggle_magicpower) (struct block_list *bl, uint16 skill_id); int (*magic_reflect) (struct block_list* src, struct block_list* bl, int type); - int (*onskillusage) (struct map_session_data *sd, struct block_list *bl, uint16 skill_id, unsigned int tick); + int (*onskillusage) (struct map_session_data *sd, struct block_list *bl, uint16 skill_id, int64 tick); int (*cell_overlap) (struct block_list *bl, va_list ap); - int (*timerskill) (int tid, unsigned int tick, int id, intptr_t data); + int (*timerskill) (int tid, int64 tick, int id, intptr_t data); int (*trap_splash) (struct block_list *bl, va_list ap); int (*check_condition_mercenary) (struct block_list *bl, int skill_id, int lv, int type); struct skill_unit_group *(*locate_element_field) (struct block_list *bl); int (*graffitiremover) (struct block_list *bl, va_list ap); int (*activate_reverberation) ( struct block_list *bl, va_list ap); int (*dance_overlap_sub) (struct block_list* bl, va_list ap); - int (*dance_overlap) (struct skill_unit* unit, int flag); + int (*dance_overlap) (struct skill_unit* su, int flag); struct s_skill_unit_layout *(*get_unit_layout) (uint16 skill_id, uint16 skill_lv, struct block_list* src, int x, int y); int (*frostjoke_scream) (struct block_list *bl, va_list ap); int (*greed) (struct block_list *bl, va_list ap); int (*destroy_trap) ( struct block_list *bl, va_list ap ); int (*icewall_block) (struct block_list *bl,va_list ap); - struct skill_unit_group_tickset *(*unitgrouptickset_search) (struct block_list *bl, struct skill_unit_group *group, int tick); - bool (*dance_switch) (struct skill_unit* unit, int flag); + struct skill_unit_group_tickset *(*unitgrouptickset_search) (struct block_list *bl, struct skill_unit_group *group, int64 tick); + bool (*dance_switch) (struct skill_unit* su, int flag); int (*check_condition_char_sub) (struct block_list *bl, va_list ap); int (*check_condition_mob_master_sub) (struct block_list *bl, va_list ap); void (*brandishspear_first) (struct square *tc, uint8 dir, int16 x, int16 y); void (*brandishspear_dir) (struct square* tc, uint8 dir, int are); -#ifdef RENEWAL_CAST - int (*get_fixed_cast) ( uint16 skill_id ,uint16 skill_lv ); -#endif + int (*get_fixed_cast) ( uint16 skill_id ,uint16 skill_lv ); int (*sit_count) (struct block_list *bl, va_list ap); int (*sit_in) (struct block_list *bl, va_list ap); int (*sit_out) (struct block_list *bl, va_list ap); void (*unitsetmapcell) (struct skill_unit *src, uint16 skill_id, uint16 skill_lv, cell_t cell, bool flag); - int (*unit_onplace_timer) (struct skill_unit *src, struct block_list *bl, unsigned int tick); + int (*unit_onplace_timer) (struct skill_unit *src, struct block_list *bl, int64 tick); int (*unit_effect) (struct block_list* bl, va_list ap); int (*unit_timer_sub_onplace) (struct block_list* bl, va_list ap); int (*unit_move_sub) (struct block_list* bl, va_list ap); - int (*blockpc_end) (int tid, unsigned int tick, int id, intptr_t data); - int (*blockhomun_end) (int tid, unsigned int tick, int id, intptr_t data); - int (*blockmerc_end) (int tid, unsigned int tick, int id, intptr_t data); + int (*blockpc_end) (int tid, int64 tick, int id, intptr_t data); + int (*blockhomun_end) (int tid, int64 tick, int id, intptr_t data); + int (*blockmerc_end) (int tid, int64 tick, int id, intptr_t data); int (*split_atoi) (char *str, int *val); - int (*unit_timer) (int tid, unsigned int tick, int id, intptr_t data); + int (*unit_timer) (int tid, int64 tick, int id, intptr_t data); int (*unit_timer_sub) (DBKey key, DBData *data, va_list ap); void (*init_unit_layout) (void); bool (*parse_row_skilldb) (char* split[], int columns, int current); @@ -1916,10 +2038,13 @@ struct skill_interface { int (*elementalanalysis) (struct map_session_data *sd, int n, uint16 skill_lv, unsigned short *item_list); int (*changematerial) (struct map_session_data *sd, int n, unsigned short *item_list); int (*get_elemental_type) (uint16 skill_id, uint16 skill_lv); -} skill_s; + void (*cooldown_save) (struct map_session_data * sd); + int (*get_new_group_id) (void); + bool (*check_shadowform) (struct block_list *bl, int64 damage, int hit); +}; struct skill_interface *skill; void skill_defaults(void); -#endif /* _SKILL_H_ */ +#endif /* MAP_SKILL_H */ diff --git a/src/map/sql/CMakeLists.txt b/src/map/sql/CMakeLists.txt deleted file mode 100644 index 1b2c19979..000000000 --- a/src/map/sql/CMakeLists.txt +++ /dev/null @@ -1,116 +0,0 @@ - -# -# map sql -# -if( BUILD_SQL_SERVERS ) -message( STATUS "Creating target map-server" ) -set( SQL_MAP_HEADERS - "${SQL_MAP_SOURCE_DIR}/atcommand.h" - "${SQL_MAP_SOURCE_DIR}/battle.h" - "${SQL_MAP_SOURCE_DIR}/battleground.h" - "${SQL_MAP_SOURCE_DIR}/buyingstore.h" - "${SQL_MAP_SOURCE_DIR}/chat.h" - "${SQL_MAP_SOURCE_DIR}/chrif.h" - "${SQL_MAP_SOURCE_DIR}/clif.h" - "${SQL_MAP_SOURCE_DIR}/date.h" - "${SQL_MAP_SOURCE_DIR}/duel.h" - "${SQL_MAP_SOURCE_DIR}/elemental.h" - "${SQL_MAP_SOURCE_DIR}/guild.h" - "${SQL_MAP_SOURCE_DIR}/homunculus.h" - "${SQL_MAP_SOURCE_DIR}/instance.h" - "${SQL_MAP_SOURCE_DIR}/intif.h" - "${SQL_MAP_SOURCE_DIR}/irc-bot.h" - "${SQL_MAP_SOURCE_DIR}/itemdb.h" - "${SQL_MAP_SOURCE_DIR}/log.h" - "${SQL_MAP_SOURCE_DIR}/mail.h" - "${SQL_MAP_SOURCE_DIR}/map.h" - "${SQL_MAP_SOURCE_DIR}/mapreg.h" - "${SQL_MAP_SOURCE_DIR}/mercenary.h" - "${SQL_MAP_SOURCE_DIR}/mob.h" - "${SQL_MAP_SOURCE_DIR}/npc.h" - "${SQL_MAP_SOURCE_DIR}/packets.h" - "${SQL_MAP_SOURCE_DIR}/packets_struct.h" - "${SQL_MAP_SOURCE_DIR}/party.h" - "${SQL_MAP_SOURCE_DIR}/path.h" - "${SQL_MAP_SOURCE_DIR}/pc.h" - "${SQL_MAP_SOURCE_DIR}/pc_groups.h" - "${SQL_MAP_SOURCE_DIR}/pet.h" - "${SQL_MAP_SOURCE_DIR}/quest.h" - "${SQL_MAP_SOURCE_DIR}/script.h" - "${SQL_MAP_SOURCE_DIR}/searchstore.h" - "${SQL_MAP_SOURCE_DIR}/skill.h" - "${SQL_MAP_SOURCE_DIR}/status.h" - "${SQL_MAP_SOURCE_DIR}/storage.h" - "${SQL_MAP_SOURCE_DIR}/trade.h" - "${SQL_MAP_SOURCE_DIR}/unit.h" - "${SQL_MAP_SOURCE_DIR}/vending.h" - ) -set( SQL_MAP_SOURCES - "${SQL_MAP_SOURCE_DIR}/atcommand.c" - "${SQL_MAP_SOURCE_DIR}/battle.c" - "${SQL_MAP_SOURCE_DIR}/battleground.c" - "${SQL_MAP_SOURCE_DIR}/buyingstore.c" - "${SQL_MAP_SOURCE_DIR}/chat.c" - "${SQL_MAP_SOURCE_DIR}/chrif.c" - "${SQL_MAP_SOURCE_DIR}/clif.c" - "${SQL_MAP_SOURCE_DIR}/date.c" - "${SQL_MAP_SOURCE_DIR}/duel.c" - "${SQL_MAP_SOURCE_DIR}/elemental.c" - "${SQL_MAP_SOURCE_DIR}/guild.c" - "${SQL_MAP_SOURCE_DIR}/homunculus.c" - "${SQL_MAP_SOURCE_DIR}/instance.c" - "${SQL_MAP_SOURCE_DIR}/intif.c" - "${SQL_MAP_SOURCE_DIR}/irc-bot.c" - "${SQL_MAP_SOURCE_DIR}/itemdb.c" - "${SQL_MAP_SOURCE_DIR}/log.c" - "${SQL_MAP_SOURCE_DIR}/mail.c" - "${SQL_MAP_SOURCE_DIR}/map.c" - "${SQL_MAP_SOURCE_DIR}/mapreg_sql.c" - "${SQL_MAP_SOURCE_DIR}/mercenary.c" - "${SQL_MAP_SOURCE_DIR}/mob.c" - "${SQL_MAP_SOURCE_DIR}/npc.c" - "${SQL_MAP_SOURCE_DIR}/npc_chat.c" - "${SQL_MAP_SOURCE_DIR}/party.c" - "${SQL_MAP_SOURCE_DIR}/path.c" - "${SQL_MAP_SOURCE_DIR}/pc.c" - "${SQL_MAP_SOURCE_DIR}/pc_groups.c" - "${SQL_MAP_SOURCE_DIR}/pet.c" - "${SQL_MAP_SOURCE_DIR}/quest.c" - "${SQL_MAP_SOURCE_DIR}/script.c" - "${SQL_MAP_SOURCE_DIR}/searchstore.c" - "${SQL_MAP_SOURCE_DIR}/skill.c" - "${SQL_MAP_SOURCE_DIR}/status.c" - "${SQL_MAP_SOURCE_DIR}/storage.c" - "${SQL_MAP_SOURCE_DIR}/trade.c" - "${SQL_MAP_SOURCE_DIR}/unit.c" - "${SQL_MAP_SOURCE_DIR}/vending.c" - ) -set( DEPENDENCIES common_sql ) -set( LIBRARIES ${GLOBAL_LIBRARIES} ) -set( INCLUDE_DIRS ${GLOBAL_INCLUDE_DIRS} ${COMMON_BASE_INCLUDE_DIRS} ) -set( DEFINITIONS "${GLOBAL_DEFINITIONS} ${COMMON_BASE_DEFINITIONS}" ) -if( WITH_PCRE ) - message( STATUS "Enabled PCRE code" ) - set( LIBRARIES ${LIBRARIES} ${PCRE_LIBRARIES} ) - set( INCLUDE_DIRS ${INCLUDE_DIRS} ${PCRE_INCLUDE_DIRS} ) - set( DEFINITIONS "${DEFINITIONS} -DPCRE_SUPPORT" ) -else() - message( STATUS "Disabled PCRE code" ) -endif() -set( SOURCE_FILES ${COMMON_BASE_HEADERS} ${COMMON_SQL_HEADERS} ${SQL_MAP_HEADERS} ${SQL_MAP_SOURCES} ) -source_group( common FILES ${COMMON_BASE_HEADERS} ${COMMON_SQL_HEADERS} ) -source_group( map FILES ${SQL_MAP_HEADERS} ${SQL_MAP_SOURCES} ) -include_directories( ${INCLUDE_DIRS} ) -add_executable( map-server ${SOURCE_FILES} ) -add_dependencies( map-server ${DEPENDENCIES} ) -target_link_libraries( map-server ${LIBRARIES} ${DEPENDENCIES} ) -set_target_properties( map-server PROPERTIES COMPILE_FLAGS "${DEFINITIONS}" ) -if( INSTALL_COMPONENT_RUNTIME ) - cpack_add_component( Runtime_mapserver_sql DESCRIPTION "map-server (sql version)" DISPLAY_NAME "map-server" GROUP Runtime ) - install( TARGETS map-server - DESTINATION "." - COMPONENT Runtime_mapserver_sql ) -endif( INSTALL_COMPONENT_RUNTIME ) -set( TARGET_LIST ${TARGET_LIST} map-server CACHE INTERNAL "" ) -message( STATUS "Creating target map-server - done" ) -endif( BUILD_SQL_SERVERS ) diff --git a/src/map/status.c b/src/map/status.c index 992cc0855..4a2a6c344 100644 --- a/src/map/status.c +++ b/src/map/status.c @@ -2,103 +2,69 @@ // See the LICENSE file // Portions Copyright (c) Athena Dev Teams -#include "../common/cbasetypes.h" -#include "../common/timer.h" -#include "../common/nullpo.h" -#include "../common/random.h" -#include "../common/showmsg.h" -#include "../common/malloc.h" -#include "../common/utils.h" -#include "../common/ers.h" -#include "../common/strlib.h" +#define HERCULES_CORE +#include "../config/core.h" // ANTI_MAYAP_CHEAT, DBPATH, DEFTYPE_MAX, DEFTYPE_MIN, DEVOTION_REFLECT_DAMAGE, RENEWAL, RENEWAL_ASPD, RENEWAL_EDP +#include "status.h" + +#include <math.h> +#include <memory.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#include "battle.h" +#include "chrif.h" +#include "clif.h" +#include "elemental.h" +#include "guild.h" +#include "homunculus.h" +#include "itemdb.h" #include "map.h" +#include "mercenary.h" +#include "mob.h" +#include "npc.h" #include "path.h" #include "pc.h" #include "pet.h" -#include "npc.h" -#include "mob.h" -#include "clif.h" -#include "guild.h" +#include "script.h" #include "skill.h" -#include "itemdb.h" -#include "battle.h" -#include "chrif.h" #include "skill.h" -#include "status.h" -#include "script.h" #include "unit.h" -#include "homunculus.h" -#include "mercenary.h" -#include "elemental.h" #include "vending.h" +#include "../common/cbasetypes.h" +#include "../common/ers.h" +#include "../common/malloc.h" +#include "../common/nullpo.h" +#include "../common/random.h" +#include "../common/showmsg.h" +#include "../common/strlib.h" +#include "../common/timer.h" +#include "../common/utils.h" -#include <time.h> -#include <stdio.h> -#include <stdlib.h> -#include <memory.h> -#include <string.h> -#include <math.h> - -//Regen related flags. -enum e_regen -{ - RGN_HP = 0x01, - RGN_SP = 0x02, - RGN_SHP = 0x04, - RGN_SSP = 0x08, -}; - -static int max_weight_base[CLASS_COUNT]; -static int hp_coefficient[CLASS_COUNT]; -static int hp_coefficient2[CLASS_COUNT]; -static int hp_sigma_val[CLASS_COUNT][MAX_LEVEL+1]; -static int sp_coefficient[CLASS_COUNT]; -#ifdef RENEWAL_ASPD - static int aspd_base[CLASS_COUNT][MAX_WEAPON_TYPE+1]; -#else - static int aspd_base[CLASS_COUNT][MAX_WEAPON_TYPE]; //[blackhole89] -#endif - -// bonus values and upgrade chances for refining equipment -static struct { - int chance[MAX_REFINE]; // success chance - int bonus[MAX_REFINE]; // cumulative fixed bonus damage - int randombonus_max[MAX_REFINE]; // cumulative maximum random bonus damage -} refine_info[REFINE_TYPE_MAX]; - -static int atkmods[3][MAX_WEAPON_TYPE]; //ATK weapon modification for size (size_fix.txt) -static char job_bonus[CLASS_COUNT][MAX_LEVEL]; -static sc_conf_type sc_conf[SC_MAX]; - -static struct eri *sc_data_ers; //For sc_data entries -static struct status_data dummy_status; - -int current_equip_item_index; //Contains inventory index of an equipped item. To pass it into the EQUP_SCRIPT [Lupus] -int current_equip_card_id; //To prevent card-stacking (from jA) [Skotlex] -//we need it for new cards 15 Feb 2005, to check if the combo cards are insrerted into the CURRENT weapon only -//to avoid cards exploits +struct status_interface status_s; /** - * Returns the status change associated with a skill. - * @param skill The skill to look up - * @return The status registered for this skill - **/ +* Returns the status change associated with a skill. +* @param skill The skill to look up +* @return The status registered for this skill +**/ sc_type status_skill2sc(int skill_id) { int idx; if( (idx = skill->get_index(skill_id)) == 0 ) { - ShowError("status_skill2sc: Unsupported skill id %d\n", skill); + ShowError("status_skill2sc: Unsupported skill id %d\n", skill_id); return SC_NONE; } - return SkillStatusChangeTable[idx]; + return status->Skill2SCTable[idx]; } /** - * Returns the FIRST skill (in order of definition in initChangeTables) to use a given status change. - * Utilized for various duration lookups. Use with caution! - * @param sc The status to look up - * @return A skill associated with the status - **/ +* Returns the FIRST skill (in order of definition in initChangeTables) to use a given status change. +* Utilized for various duration lookups. Use with caution! +* @param sc The status to look up +* @return A skill associated with the status +**/ int status_sc2skill(sc_type sc) { if( sc < 0 || sc >= SC_MAX ) { @@ -106,14 +72,14 @@ int status_sc2skill(sc_type sc) return 0; } - return StatusSkillChangeTable[sc]; + return status->SkillChangeTable[sc]; } /** - * Returns the status calculation flag associated with a given status change. - * @param sc The status to look up - * @return The scb_flag registered for this status (see enum scb_flag) - **/ +* Returns the status calculation flag associated with a given status change. +* @param sc The status to look up +* @return The scb_flag registered for this status (see enum scb_flag) +**/ unsigned int status_sc2scb_flag(sc_type sc) { if( sc < 0 || sc >= SC_MAX ) { @@ -121,28 +87,24 @@ unsigned int status_sc2scb_flag(sc_type sc) return SCB_NONE; } - return StatusChangeFlagTable[sc]; + return status->ChangeFlagTable[sc]; } /** - * Returns the bl types which require a status change packet to be sent for a given client status identifier. - * @param type The client-side status identifier to look up (see enum si_type) - * @return The bl types relevant to the type (see enum bl_type) - **/ +* Returns the bl types which require a status change packet to be sent for a given client status identifier. +* @param type The client-side status identifier to look up (see enum si_type) +* @return The bl types relevant to the type (see enum bl_type) +**/ int status_type2relevant_bl_types(int type) { if( type < 0 || type >= SI_MAX ) { ShowError("status_type2relevant_bl_types: Unsupported type %d\n", type); - return SI_BLANK; + return BL_NUL; } - return StatusRelevantBLTypes[type]; + return status->RelevantBLTypes[type]; } -#define add_sc(skill,sc) 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) set_sc((skill), (sc), (icon), (flag)); if((icon) < SI_MAX) StatusRelevantBLTypes[(icon)] |= BL_SCEFFECT - static void set_sc(uint16 skill_id, sc_type sc, int icon, unsigned int flag) { uint16 idx; if( (idx = skill->get_index(skill_id)) == 0 ) { @@ -154,31 +116,35 @@ static void set_sc(uint16 skill_id, sc_type sc, int icon, unsigned int flag) { return; } - if( StatusSkillChangeTable[sc] == 0 ) - StatusSkillChangeTable[sc] = skill_id; - if( StatusIconChangeTable[sc] == SI_BLANK ) - StatusIconChangeTable[sc] = icon; - StatusChangeFlagTable[sc] |= flag; + if( status->SkillChangeTable[sc] == 0 ) + status->SkillChangeTable[sc] = skill_id; + if( status->IconChangeTable[sc] == SI_BLANK ) + status->IconChangeTable[sc] = icon; + status->ChangeFlagTable[sc] |= flag; - if( SkillStatusChangeTable[idx] == SC_NONE ) - SkillStatusChangeTable[idx] = sc; + if( status->Skill2SCTable[idx] == SC_NONE ) + status->Skill2SCTable[idx] = sc; } void initChangeTables(void) { +#define add_sc(skill,sc) 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->RelevantBLTypes[(icon)] |= BL_SCEFFECT; } while(0) + int i; for (i = 0; i < SC_MAX; i++) - StatusIconChangeTable[i] = SI_BLANK; + status->IconChangeTable[i] = SI_BLANK; for (i = 0; i < MAX_SKILL; i++) - SkillStatusChangeTable[i] = SC_NONE; + status->Skill2SCTable[i] = SC_NONE; for (i = 0; i < SI_MAX; i++) - StatusRelevantBLTypes[i] = BL_PC; + status->RelevantBLTypes[i] = BL_PC; - memset(StatusSkillChangeTable, 0, sizeof(StatusSkillChangeTable)); - memset(StatusChangeFlagTable, 0, sizeof(StatusChangeFlagTable)); - memset(StatusDisplayType, 0, sizeof(StatusDisplayType)); + memset(status->SkillChangeTable, 0, sizeof(status->SkillChangeTable)); + memset(status->ChangeFlagTable, 0, sizeof(status->ChangeFlagTable)); + memset(status->DisplayType, 0, sizeof(status->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 ); @@ -196,7 +162,7 @@ void initChangeTables(void) { //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 ); - add_sc( SM_MAGNUM , SC_WATK_ELEMENT ); + add_sc( SM_MAGNUM , SC_SUB_WEAPONPROPERTY ); set_sc( SM_ENDURE , SC_ENDURE , SI_ENDURE , SCB_MDEF|SCB_DSPD ); add_sc( MG_SIGHT , SC_SIGHT ); add_sc( MG_SAFETYWALL , SC_SAFETYWALL ); @@ -214,7 +180,12 @@ void initChangeTables(void) { add_sc( TF_POISON , SC_POISON ); set_sc( KN_TWOHANDQUICKEN , SC_TWOHANDQUICKEN , SI_TWOHANDQUICKEN , SCB_ASPD ); add_sc( KN_AUTOCOUNTER , SC_AUTOCOUNTER ); - set_sc( PR_IMPOSITIO , SC_IMPOSITIO , SI_IMPOSITIO , SCB_WATK ); + 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 ); @@ -233,7 +204,7 @@ void initChangeTables(void) { 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 ); - add_sc( HT_LANDMINE , SC_STUN ); + add_sc( HT_LANDMINE , SC_STUN ); set_sc( HT_ANKLESNARE , SC_ANKLESNARE , SI_ANKLESNARE , SCB_NONE ); add_sc( HT_SANDMAN , SC_SLEEP ); add_sc( HT_FLASHER , SC_BLIND ); @@ -348,9 +319,9 @@ void initChangeTables(void) { set_sc( LK_AURABLADE , SC_AURABLADE , SI_AURABLADE , SCB_NONE ); set_sc( LK_PARRYING , SC_PARRYING , SI_PARRYING , SCB_NONE ); #ifndef RENEWAL - set_sc( LK_CONCENTRATION , SC_LKCONCENTRATION , SI_CONCENTRATION , SCB_BATK|SCB_WATK|SCB_HIT|SCB_DEF|SCB_DEF2); + 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_CONCENTRATION , SCB_HIT|SCB_DEF); + 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 ); @@ -427,10 +398,20 @@ void initChangeTables(void) { 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_BATK|SCB_ASPD ); + 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_BATK|SCB_FLEE|SCB_SPEED|SCB_ASPD ); + 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 ); add_sc( NJ_HYOUSYOURAKU , SC_FREEZE ); @@ -467,7 +448,7 @@ void initChangeTables(void) { 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_MATK|SCB_BATK|SCB_MDEF|SCB_DEF ); + 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 ); @@ -488,13 +469,13 @@ void initChangeTables(void) { 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 ); + 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); add_sc( MH_STEINWAND, SC_SAFETYWALL ); - add_sc(MH_ERASER_CUTTER, SC_ERASER_CUTTER); - set_sc(MH_OVERED_BOOST, SC_OVERED_BOOST, SI_BLANK, SCB_FLEE|SCB_ASPD); - add_sc(MH_LIGHT_OF_REGENE, SC_LIGHT_OF_REGENE); 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); @@ -504,14 +485,14 @@ void initChangeTables(void) { add_sc(MH_POISON_MIST, SC_BLIND); set_sc(MH_PAIN_KILLER, SC_PAIN_KILLER, SI_PAIN_KILLER, SCB_ASPD); - 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_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 ); - add_sc( MER_CRASH , SC_STUN ); set_sc( MER_PROVOKE , SC_PROVOKE , SI_PROVOKE , SCB_DEF|SCB_DEF2|SCB_BATK|SCB_WATK ); - add_sc( MS_MAGNUM , SC_WATK_ELEMENT ); + 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 ); @@ -541,13 +522,13 @@ void initChangeTables(void) { set_sc( GD_REGENERATION , SC_GDSKILL_REGENERATION , SI_BLANK , SCB_REGEN ); /** - * Rune Knight - **/ + * 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 ); - set_sc( RK_DRAGONBREATH , SC_BURNING , SI_BLANK , SCB_MDEF ); + 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 ); @@ -558,8 +539,8 @@ void initChangeTables(void) { set_sc( RK_CRUSHSTRIKE , SC_CRUSHSTRIKE , SI_CRUSHSTRIKE , SCB_NONE ); add_sc( RK_DRAGONBREATH_WATER, SC_FROSTMISTY ); /** - * GC Guillotine Cross - **/ + * 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 ); @@ -568,8 +549,8 @@ void initChangeTables(void) { set_sc( GC_ROLLINGCUTTER , SC_ROLLINGCUTTER , SI_ROLLINGCUTTER , SCB_NONE ); set_sc_with_vfx( GC_DARKCROW , SC_DARKCROW , SI_DARKCROW , SCB_NONE ); /** - * Arch Bishop - **/ + * Arch Bishop + **/ 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 ); @@ -584,17 +565,17 @@ void initChangeTables(void) { set_sc( AB_SECRAMENT , SC_SECRAMENT , SI_SECRAMENT , SCB_NONE ); set_sc( AB_OFFERTORIUM , SC_OFFERTORIUM , SI_OFFERTORIUM , SCB_NONE ); /** - * Warlock - **/ + * 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_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 ); /** - * Ranger - **/ + * 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 ); @@ -605,35 +586,33 @@ void initChangeTables(void) { 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_NONE ); + set_sc( RA_UNLIMIT , SC_UNLIMIT , SI_UNLIMIT , SCB_DEF|SCB_DEF2|SCB_MDEF|SCB_MDEF2 ); /** - * Mechanic - **/ + * 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_NONE ); + set_sc( NC_NEUTRALBARRIER , SC_NEUTRALBARRIER , SI_NEUTRALBARRIER , SCB_DEF|SCB_MDEF ); set_sc( NC_STEALTHFIELD , SC_STEALTHFIELD , SI_STEALTHFIELD , SCB_NONE ); /** - * Royal Guard - **/ + * Royal Guard + **/ set_sc( LG_REFLECTDAMAGE , SC_LG_REFLECTDAMAGE , SI_LG_REFLECTDAMAGE, SCB_NONE ); - set_sc( LG_FORCEOFVANGUARD , SC_FORCEOFVANGUARD , SI_FORCEOFVANGUARD , SCB_MAXHP|SCB_DEF ); + 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_SHIELDSPELL , SC_SHIELDSPELL_DEF , SI_SHIELDSPELL_DEF , SCB_WATK ); - set_sc( LG_SHIELDSPELL , SC_SHIELDSPELL_REF , SI_SHIELDSPELL_REF , SCB_DEF ); set_sc( LG_KINGS_GRACE , SC_KINGS_GRACE , SI_KINGS_GRACE , SCB_NONE ); /** - * Shadow Chaser - **/ + * 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 ); @@ -648,13 +627,16 @@ void initChangeTables(void) { 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 ); set_sc_with_vfx( SC_MANHOLE , SC__MANHOLE , SI_MANHOLE , SCB_NONE ); - add_sc( SC_CHAOSPANIC , SC_CONFUSION ); - set_sc_with_vfx( SC_BLOODYLUST , SC__BLOODYLUST , SI_BLOODYLUST , SCB_DEF | SCB_DEF2 | SCB_MDEF | SCB_MDEF2 | SCB_FLEE | SCB_SPEED | SCB_ASPD | SCB_MAXHP | SCB_REGEN ); + add_sc( SC_CHAOSPANIC , SC__CHAOS ); + add_sc( SC_MAELSTROM , SC__MAELSTROM ); + add_sc( SC_BLOODYLUST , SC_BERSERK ); + /** - * Sura - **/ + * Sura + **/ 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 ); set_sc_with_vfx( SR_CURSEDCIRCLE , SC_CURSEDCIRCLE_TARGET, SI_CURSEDCIRCLE_TARGET , SCB_NONE ); set_sc( SR_LIGHTNINGWALK , SC_LIGHTNINGWALK , SI_LIGHTNINGWALK , SCB_NONE ); @@ -662,16 +644,17 @@ void initChangeTables(void) { 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_REGEN ); + set_sc( SR_FLASHCOMBO , SC_FLASHCOMBO , SI_FLASHCOMBO , SCB_WATK ); /** - * Wanderer / Minstrel - **/ + * 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_BATK ); + 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 ); - set_sc_with_vfx( WM_POEMOFNETHERWORLD , SC_NETHERWORLD , SI_NETHERWORLD , SCB_NONE ); + set_sc( WM_POEMOFNETHERWORLD , SC_STOP , 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 ); @@ -680,19 +663,19 @@ void initChangeTables(void) { 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_BATK|SCB_MATK ); - set_sc( WM_BEYOND_OF_WARCRY , SC_BEYOND_OF_WARCRY , SI_WARCRYOFBEYOND , SCB_BATK|SCB_MATK ); + 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 ); - + /** - * Sorcerer - **/ + * 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 ); - set_sc_with_vfx( SO_DIAMONDDUST , SC_CRYSTALIZE , SI_COLD , SCB_NONE ); // it does show the snow icon on mobs but doesn't affect it. - add_sc( SO_CLOUD_KILL , SC_POISON ); + 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 ); set_sc( SO_WARMER , SC_WARMER , SI_WARMER , SCB_NONE ); set_sc( SO_VACUUM_EXTREME , SC_VACUUM_EXTREME , SI_VACUUM_EXTREME , SCB_NONE ); @@ -701,9 +684,10 @@ void initChangeTables(void) { 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 ); + add_sc( SO_ELEMENTAL_SHIELD , SC_SAFETYWALL ); /** - * Genetic - **/ + * Genetic + **/ set_sc( GN_CARTBOOST , SC_GN_CARTBOOST, SI_CARTSBOOST , SCB_SPEED ); 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 ); @@ -717,7 +701,7 @@ void initChangeTables(void) { 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_MDEF|SCB_WATK|SCB_MATK|SCB_FLEE ); + 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 ); @@ -734,8 +718,8 @@ void initChangeTables(void) { 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_NONE ); - set_sc( EL_UPHEAVAL , SC_UPHEAVAL_OPTION , SI_UPHEAVAL_OPTION , SCB_NONE ); + 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 ); @@ -757,302 +741,340 @@ void initChangeTables(void) { 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 ); + + add_sc( NPC_WIDEHEALTHFEAR , SC_FEAR ); + add_sc( NPC_WIDEBODYBURNNING , SC_BURNING ); + add_sc( NPC_WIDEFROSTMISTY , SC_FROSTMISTY ); + add_sc( NPC_WIDECOLD , SC_COLD ); + add_sc( NPC_WIDE_DEEP_SLEEP , SC_DEEP_SLEEP ); + add_sc( NPC_WIDESIREN , SC_SIREN ); + + set_sc_with_vfx( GN_ILLUSIONDOPING , SC_ILLUSIONDOPING , SI_ILLUSIONDOPING , SCB_HIT ); + // Storing the target job rather than simply SC_SOULLINK simplifies code later on. - SkillStatusChangeTable[SL_ALCHEMIST] = (sc_type)MAPID_ALCHEMIST, - SkillStatusChangeTable[SL_MONK] = (sc_type)MAPID_MONK, - SkillStatusChangeTable[SL_STAR] = (sc_type)MAPID_STAR_GLADIATOR, - SkillStatusChangeTable[SL_SAGE] = (sc_type)MAPID_SAGE, - SkillStatusChangeTable[SL_CRUSADER] = (sc_type)MAPID_CRUSADER, - SkillStatusChangeTable[SL_SUPERNOVICE] = (sc_type)MAPID_SUPER_NOVICE, - SkillStatusChangeTable[SL_KNIGHT] = (sc_type)MAPID_KNIGHT, - SkillStatusChangeTable[SL_WIZARD] = (sc_type)MAPID_WIZARD, - SkillStatusChangeTable[SL_PRIEST] = (sc_type)MAPID_PRIEST, - SkillStatusChangeTable[SL_BARDDANCER] = (sc_type)MAPID_BARDDANCER, - SkillStatusChangeTable[SL_ROGUE] = (sc_type)MAPID_ROGUE, - SkillStatusChangeTable[SL_ASSASIN] = (sc_type)MAPID_ASSASSIN, - SkillStatusChangeTable[SL_BLACKSMITH] = (sc_type)MAPID_BLACKSMITH, - SkillStatusChangeTable[SL_HUNTER] = (sc_type)MAPID_HUNTER, - SkillStatusChangeTable[SL_SOULLINKER] = (sc_type)MAPID_SOUL_LINKER, + status->Skill2SCTable[SL_ALCHEMIST] = (sc_type)MAPID_ALCHEMIST, + status->Skill2SCTable[SL_MONK] = (sc_type)MAPID_MONK, + status->Skill2SCTable[SL_STAR] = (sc_type)MAPID_STAR_GLADIATOR, + status->Skill2SCTable[SL_SAGE] = (sc_type)MAPID_SAGE, + status->Skill2SCTable[SL_CRUSADER] = (sc_type)MAPID_CRUSADER, + status->Skill2SCTable[SL_SUPERNOVICE] = (sc_type)MAPID_SUPER_NOVICE, + status->Skill2SCTable[SL_KNIGHT] = (sc_type)MAPID_KNIGHT, + status->Skill2SCTable[SL_WIZARD] = (sc_type)MAPID_WIZARD, + status->Skill2SCTable[SL_PRIEST] = (sc_type)MAPID_PRIEST, + status->Skill2SCTable[SL_BARDDANCER] = (sc_type)MAPID_BARDDANCER, + status->Skill2SCTable[SL_ROGUE] = (sc_type)MAPID_ROGUE, + status->Skill2SCTable[SL_ASSASIN] = (sc_type)MAPID_ASSASSIN, + status->Skill2SCTable[SL_BLACKSMITH] = (sc_type)MAPID_BLACKSMITH, + status->Skill2SCTable[SL_HUNTER] = (sc_type)MAPID_HUNTER, + status->Skill2SCTable[SL_SOULLINKER] = (sc_type)MAPID_SOUL_LINKER, //Status that don't have a skill associated. - StatusIconChangeTable[SC_WEIGHTOVER50] = SI_WEIGHTOVER50; - StatusIconChangeTable[SC_WEIGHTOVER90] = SI_WEIGHTOVER90; - StatusIconChangeTable[SC_ATTHASTE_POTION1] = SI_ATTHASTE_POTION1; - StatusIconChangeTable[SC_ATTHASTE_POTION2] = SI_ATTHASTE_POTION2; - StatusIconChangeTable[SC_ATTHASTE_POTION3] = SI_ATTHASTE_POTION3; - StatusIconChangeTable[SC_ATTHASTE_INFINITY] = SI_ATTHASTE_INFINITY; - StatusIconChangeTable[SC_MOVHASTE_HORSE] = SI_MOVHASTE_HORSE; - StatusIconChangeTable[SC_MOVHASTE_INFINITY] = SI_MOVHASTE_INFINITY; - StatusIconChangeTable[SC_CHASEWALK2] = SI_INCSTR; - StatusIconChangeTable[SC_MIRACLE] = SI_SOULLINK; - StatusIconChangeTable[SC_CLAIRVOYANCE] = SI_CLAIRVOYANCE; - StatusIconChangeTable[SC_FOOD_STR] = SI_FOOD_STR; - StatusIconChangeTable[SC_FOOD_AGI] = SI_FOOD_AGI; - StatusIconChangeTable[SC_FOOD_VIT] = SI_FOOD_VIT; - StatusIconChangeTable[SC_FOOD_INT] = SI_FOOD_INT; - StatusIconChangeTable[SC_FOOD_DEX] = SI_FOOD_DEX; - StatusIconChangeTable[SC_FOOD_LUK] = SI_FOOD_LUK; - StatusIconChangeTable[SC_FOOD_BASICAVOIDANCE]= SI_FOOD_BASICAVOIDANCE; - StatusIconChangeTable[SC_FOOD_BASICHIT] = SI_FOOD_BASICHIT; - StatusIconChangeTable[SC_MANU_ATK] = SI_MANU_ATK; - StatusIconChangeTable[SC_MANU_DEF] = SI_MANU_DEF; - StatusIconChangeTable[SC_SPL_ATK] = SI_SPL_ATK; - StatusIconChangeTable[SC_SPL_DEF] = SI_SPL_DEF; - StatusIconChangeTable[SC_MANU_MATK] = SI_MANU_MATK; - StatusIconChangeTable[SC_SPL_MATK] = SI_SPL_MATK; - StatusIconChangeTable[SC_PLUSATTACKPOWER] = SI_PLUSATTACKPOWER; - StatusIconChangeTable[SC_PLUSMAGICPOWER] = SI_PLUSMAGICPOWER; + status->IconChangeTable[SC_WEIGHTOVER50] = SI_WEIGHTOVER50; + status->IconChangeTable[SC_WEIGHTOVER90] = SI_WEIGHTOVER90; + status->IconChangeTable[SC_ATTHASTE_POTION1] = SI_ATTHASTE_POTION1; + status->IconChangeTable[SC_ATTHASTE_POTION2] = SI_ATTHASTE_POTION2; + status->IconChangeTable[SC_ATTHASTE_POTION3] = SI_ATTHASTE_POTION3; + status->IconChangeTable[SC_ATTHASTE_INFINITY] = SI_ATTHASTE_INFINITY; + status->IconChangeTable[SC_MOVHASTE_HORSE] = SI_MOVHASTE_HORSE; + status->IconChangeTable[SC_MOVHASTE_INFINITY] = SI_MOVHASTE_INFINITY; + status->IconChangeTable[SC_CHASEWALK2] = SI_INCSTR; + status->IconChangeTable[SC_MIRACLE] = SI_SOULLINK; + status->IconChangeTable[SC_CLAIRVOYANCE] = SI_CLAIRVOYANCE; + status->IconChangeTable[SC_FOOD_STR] = SI_FOOD_STR; + status->IconChangeTable[SC_FOOD_AGI] = SI_FOOD_AGI; + status->IconChangeTable[SC_FOOD_VIT] = SI_FOOD_VIT; + status->IconChangeTable[SC_FOOD_INT] = SI_FOOD_INT; + status->IconChangeTable[SC_FOOD_DEX] = SI_FOOD_DEX; + status->IconChangeTable[SC_FOOD_LUK] = SI_FOOD_LUK; + status->IconChangeTable[SC_FOOD_BASICAVOIDANCE]= SI_FOOD_BASICAVOIDANCE; + status->IconChangeTable[SC_FOOD_BASICHIT] = SI_FOOD_BASICHIT; + status->IconChangeTable[SC_MANU_ATK] = SI_MANU_ATK; + status->IconChangeTable[SC_MANU_DEF] = SI_MANU_DEF; + status->IconChangeTable[SC_SPL_ATK] = SI_SPL_ATK; + status->IconChangeTable[SC_SPL_DEF] = SI_SPL_DEF; + status->IconChangeTable[SC_MANU_MATK] = SI_MANU_MATK; + status->IconChangeTable[SC_SPL_MATK] = SI_SPL_MATK; + status->IconChangeTable[SC_PLUSATTACKPOWER] = SI_PLUSATTACKPOWER; + status->IconChangeTable[SC_PLUSMAGICPOWER] = SI_PLUSMAGICPOWER; //Cash Items - StatusIconChangeTable[SC_FOOD_STR_CASH] = SI_FOOD_STR_CASH; - StatusIconChangeTable[SC_FOOD_AGI_CASH] = SI_FOOD_AGI_CASH; - StatusIconChangeTable[SC_FOOD_VIT_CASH] = SI_FOOD_VIT_CASH; - StatusIconChangeTable[SC_FOOD_DEX_CASH] = SI_FOOD_DEX_CASH; - StatusIconChangeTable[SC_FOOD_INT_CASH] = SI_FOOD_INT_CASH; - StatusIconChangeTable[SC_FOOD_LUK_CASH] = SI_FOOD_LUK_CASH; - StatusIconChangeTable[SC_CASH_PLUSEXP] = SI_CASH_PLUSEXP; - StatusIconChangeTable[SC_CASH_RECEIVEITEM] = SI_CASH_RECEIVEITEM; - StatusIconChangeTable[SC_CASH_PLUSONLYJOBEXP] = SI_CASH_PLUSONLYJOBEXP; - StatusIconChangeTable[SC_CASH_DEATHPENALTY] = SI_CASH_DEATHPENALTY; - StatusIconChangeTable[SC_CASH_BOSS_ALARM] = SI_CASH_BOSS_ALARM; - StatusIconChangeTable[SC_PROTECT_DEF] = SI_PROTECT_DEF; - StatusIconChangeTable[SC_PROTECT_MDEF] = SI_PROTECT_MDEF; - StatusIconChangeTable[SC_CRITICALPERCENT] = SI_CRITICALPERCENT; - StatusIconChangeTable[SC_PLUSAVOIDVALUE] = SI_PLUSAVOIDVALUE; - StatusIconChangeTable[SC_HEALPLUS] = SI_HEALPLUS; - StatusIconChangeTable[SC_S_LIFEPOTION] = SI_S_LIFEPOTION; - StatusIconChangeTable[SC_L_LIFEPOTION] = SI_L_LIFEPOTION; - StatusIconChangeTable[SC_ATKER_BLOOD] = SI_ATKER_BLOOD; - StatusIconChangeTable[SC_TARGET_BLOOD] = SI_TARGET_BLOOD; + status->IconChangeTable[SC_FOOD_STR_CASH] = SI_FOOD_STR_CASH; + status->IconChangeTable[SC_FOOD_AGI_CASH] = SI_FOOD_AGI_CASH; + status->IconChangeTable[SC_FOOD_VIT_CASH] = SI_FOOD_VIT_CASH; + status->IconChangeTable[SC_FOOD_DEX_CASH] = SI_FOOD_DEX_CASH; + status->IconChangeTable[SC_FOOD_INT_CASH] = SI_FOOD_INT_CASH; + status->IconChangeTable[SC_FOOD_LUK_CASH] = SI_FOOD_LUK_CASH; + status->IconChangeTable[SC_CASH_PLUSEXP] = SI_CASH_PLUSEXP; + status->IconChangeTable[SC_CASH_RECEIVEITEM] = SI_CASH_RECEIVEITEM; + status->IconChangeTable[SC_CASH_PLUSONLYJOBEXP] = SI_CASH_PLUSONLYJOBEXP; + status->IconChangeTable[SC_CASH_DEATHPENALTY] = SI_CASH_DEATHPENALTY; + status->IconChangeTable[SC_CASH_BOSS_ALARM] = SI_CASH_BOSS_ALARM; + status->IconChangeTable[SC_PROTECT_DEF] = SI_PROTECT_DEF; + status->IconChangeTable[SC_PROTECT_MDEF] = SI_PROTECT_MDEF; + status->IconChangeTable[SC_CRITICALPERCENT] = SI_CRITICALPERCENT; + status->IconChangeTable[SC_PLUSAVOIDVALUE] = SI_PLUSAVOIDVALUE; + status->IconChangeTable[SC_HEALPLUS] = SI_HEALPLUS; + status->IconChangeTable[SC_S_LIFEPOTION] = SI_S_LIFEPOTION; + status->IconChangeTable[SC_L_LIFEPOTION] = SI_L_LIFEPOTION; + status->IconChangeTable[SC_ATKER_BLOOD] = SI_ATKER_BLOOD; + status->IconChangeTable[SC_TARGET_BLOOD] = SI_TARGET_BLOOD; // Mercenary Bonus Effects - StatusIconChangeTable[SC_MER_FLEE] = SI_MER_FLEE; - StatusIconChangeTable[SC_MER_ATK] = SI_MER_ATK; - StatusIconChangeTable[SC_MER_HP] = SI_MER_HP; - StatusIconChangeTable[SC_MER_SP] = SI_MER_SP; - StatusIconChangeTable[SC_MER_HIT] = SI_MER_HIT; + status->IconChangeTable[SC_MER_FLEE] = SI_MER_FLEE; + status->IconChangeTable[SC_MER_ATK] = SI_MER_ATK; + status->IconChangeTable[SC_MER_HP] = SI_MER_HP; + status->IconChangeTable[SC_MER_SP] = SI_MER_SP; + status->IconChangeTable[SC_MER_HIT] = SI_MER_HIT; // Warlock Spheres - StatusIconChangeTable[SC_SUMMON1] = SI_SPHERE_1; - StatusIconChangeTable[SC_SUMMON2] = SI_SPHERE_2; - StatusIconChangeTable[SC_SUMMON3] = SI_SPHERE_3; - StatusIconChangeTable[SC_SUMMON4] = SI_SPHERE_4; - StatusIconChangeTable[SC_SUMMON5] = SI_SPHERE_5; + status->IconChangeTable[SC_SUMMON1] = SI_SPHERE_1; + status->IconChangeTable[SC_SUMMON2] = SI_SPHERE_2; + status->IconChangeTable[SC_SUMMON3] = SI_SPHERE_3; + status->IconChangeTable[SC_SUMMON4] = SI_SPHERE_4; + status->IconChangeTable[SC_SUMMON5] = SI_SPHERE_5; // Warlock Preserved spells - StatusIconChangeTable[SC_SPELLBOOK1] = SI_SPELLBOOK1; - StatusIconChangeTable[SC_SPELLBOOK2] = SI_SPELLBOOK2; - StatusIconChangeTable[SC_SPELLBOOK3] = SI_SPELLBOOK3; - StatusIconChangeTable[SC_SPELLBOOK4] = SI_SPELLBOOK4; - StatusIconChangeTable[SC_SPELLBOOK5] = SI_SPELLBOOK5; - StatusIconChangeTable[SC_SPELLBOOK6] = SI_SPELLBOOK6; - StatusIconChangeTable[SC_SPELLBOOK7] = SI_SPELLBOOK7; - - StatusIconChangeTable[SC_NEUTRALBARRIER_MASTER] = SI_NEUTRALBARRIER_MASTER; - StatusIconChangeTable[SC_STEALTHFIELD_MASTER] = SI_STEALTHFIELD_MASTER; - StatusIconChangeTable[SC_OVERHEAT] = SI_OVERHEAT; - StatusIconChangeTable[SC_OVERHEAT_LIMITPOINT] = SI_OVERHEAT_LIMITPOINT; - - StatusIconChangeTable[SC_HALLUCINATIONWALK_POSTDELAY] = SI_HALLUCINATIONWALK_POSTDELAY; - StatusIconChangeTable[SC_TOXIN] = SI_TOXIN; - StatusIconChangeTable[SC_PARALYSE] = SI_PARALYSE; - StatusIconChangeTable[SC_VENOMBLEED] = SI_VENOMBLEED; - StatusIconChangeTable[SC_MAGICMUSHROOM] = SI_MAGICMUSHROOM; - StatusIconChangeTable[SC_DEATHHURT] = SI_DEATHHURT; - StatusIconChangeTable[SC_PYREXIA] = SI_PYREXIA; - StatusIconChangeTable[SC_OBLIVIONCURSE] = SI_OBLIVIONCURSE; - StatusIconChangeTable[SC_LEECHESEND] = SI_LEECHESEND; - - StatusIconChangeTable[SC_SHIELDSPELL_DEF] = SI_SHIELDSPELL_DEF; - StatusIconChangeTable[SC_SHIELDSPELL_MDEF] = SI_SHIELDSPELL_MDEF; - StatusIconChangeTable[SC_SHIELDSPELL_REF] = SI_SHIELDSPELL_REF; - StatusIconChangeTable[SC_BANDING_DEFENCE] = SI_BANDING_DEFENCE; - - StatusIconChangeTable[SC_GLOOMYDAY_SK] = SI_GLOOMYDAY; - - StatusIconChangeTable[SC_CURSEDCIRCLE_ATKER] = SI_CURSEDCIRCLE_ATKER; - - StatusIconChangeTable[SC_STOMACHACHE] = SI_STOMACHACHE; - StatusIconChangeTable[SC_MYSTERIOUS_POWDER] = SI_MYSTERIOUS_POWDER; - StatusIconChangeTable[SC_MELON_BOMB] = SI_MELON_BOMB; - StatusIconChangeTable[SC_BANANA_BOMB] = SI_BANANA_BOMB; - StatusIconChangeTable[SC_BANANA_BOMB_SITDOWN_POSTDELAY] = SI_BANANA_BOMB_SITDOWN_POSTDELAY; + status->IconChangeTable[SC_SPELLBOOK1] = SI_SPELLBOOK1; + status->IconChangeTable[SC_SPELLBOOK2] = SI_SPELLBOOK2; + status->IconChangeTable[SC_SPELLBOOK3] = SI_SPELLBOOK3; + status->IconChangeTable[SC_SPELLBOOK4] = SI_SPELLBOOK4; + status->IconChangeTable[SC_SPELLBOOK5] = SI_SPELLBOOK5; + status->IconChangeTable[SC_SPELLBOOK6] = SI_SPELLBOOK6; + status->IconChangeTable[SC_SPELLBOOK7] = SI_SPELLBOOK7; + + status->IconChangeTable[SC_NEUTRALBARRIER_MASTER] = SI_NEUTRALBARRIER_MASTER; + status->IconChangeTable[SC_STEALTHFIELD_MASTER] = SI_STEALTHFIELD_MASTER; + status->IconChangeTable[SC_OVERHEAT] = SI_OVERHEAT; + status->IconChangeTable[SC_OVERHEAT_LIMITPOINT] = SI_OVERHEAT_LIMITPOINT; + + status->IconChangeTable[SC_HALLUCINATIONWALK_POSTDELAY] = SI_HALLUCINATIONWALK_POSTDELAY; + status->IconChangeTable[SC_TOXIN] = SI_TOXIN; + status->IconChangeTable[SC_PARALYSE] = SI_PARALYSE; + status->IconChangeTable[SC_VENOMBLEED] = SI_VENOMBLEED; + status->IconChangeTable[SC_MAGICMUSHROOM] = SI_MAGICMUSHROOM; + status->IconChangeTable[SC_DEATHHURT] = SI_DEATHHURT; + status->IconChangeTable[SC_PYREXIA] = SI_PYREXIA; + status->IconChangeTable[SC_OBLIVIONCURSE] = SI_OBLIVIONCURSE; + status->IconChangeTable[SC_LEECHESEND] = SI_LEECHESEND; + + status->IconChangeTable[SC_SHIELDSPELL_DEF] = SI_SHIELDSPELL_DEF; + status->IconChangeTable[SC_SHIELDSPELL_MDEF] = SI_SHIELDSPELL_MDEF; + status->IconChangeTable[SC_SHIELDSPELL_REF] = SI_SHIELDSPELL_REF; + status->IconChangeTable[SC_BANDING_DEFENCE] = SI_BANDING_DEFENCE; + + status->IconChangeTable[SC_CURSEDCIRCLE_ATKER] = SI_CURSEDCIRCLE_ATKER; + + status->IconChangeTable[SC_STOMACHACHE] = SI_STOMACHACHE; + status->IconChangeTable[SC_MYSTERIOUS_POWDER] = SI_MYSTERIOUS_POWDER; + status->IconChangeTable[SC_MELON_BOMB] = SI_MELON_BOMB; + status->IconChangeTable[SC_BANANA_BOMB] = SI_BANANA_BOMB; + status->IconChangeTable[SC_BANANA_BOMB_SITDOWN_POSTDELAY] = SI_BANANA_BOMB_SITDOWN_POSTDELAY; //Genetics New Food Items Status Icons - StatusIconChangeTable[SC_SAVAGE_STEAK] = SI_SAVAGE_STEAK; - StatusIconChangeTable[SC_COCKTAIL_WARG_BLOOD] = SI_COCKTAIL_WARG_BLOOD; - StatusIconChangeTable[SC_MINOR_BBQ] = SI_MINOR_BBQ; - StatusIconChangeTable[SC_SIROMA_ICE_TEA] = SI_SIROMA_ICE_TEA; - StatusIconChangeTable[SC_DROCERA_HERB_STEAMED] = SI_DROCERA_HERB_STEAMED; - StatusIconChangeTable[SC_PUTTI_TAILS_NOODLES] = SI_PUTTI_TAILS_NOODLES; - - StatusIconChangeTable[SC_BOOST500] |= SI_BOOST500; - StatusIconChangeTable[SC_FULL_SWING_K] |= SI_FULL_SWING_K; - StatusIconChangeTable[SC_MANA_PLUS] |= SI_MANA_PLUS; - StatusIconChangeTable[SC_MUSTLE_M] |= SI_MUSTLE_M; - StatusIconChangeTable[SC_LIFE_FORCE_F] |= SI_LIFE_FORCE_F; - StatusIconChangeTable[SC_EXTRACT_WHITE_POTION_Z] |= SI_EXTRACT_WHITE_POTION_Z; - StatusIconChangeTable[SC_VITATA_500] |= SI_VITATA_500; - StatusIconChangeTable[SC_EXTRACT_SALAMINE_JUICE] |= SI_EXTRACT_SALAMINE_JUICE; + status->IconChangeTable[SC_SAVAGE_STEAK] = SI_SAVAGE_STEAK; + status->IconChangeTable[SC_COCKTAIL_WARG_BLOOD] = SI_COCKTAIL_WARG_BLOOD; + status->IconChangeTable[SC_MINOR_BBQ] = SI_MINOR_BBQ; + status->IconChangeTable[SC_SIROMA_ICE_TEA] = SI_SIROMA_ICE_TEA; + status->IconChangeTable[SC_DROCERA_HERB_STEAMED] = SI_DROCERA_HERB_STEAMED; + status->IconChangeTable[SC_PUTTI_TAILS_NOODLES] = SI_PUTTI_TAILS_NOODLES; + + status->IconChangeTable[SC_BOOST500] |= SI_BOOST500; + status->IconChangeTable[SC_FULL_SWING_K] |= SI_FULL_SWING_K; + status->IconChangeTable[SC_MANA_PLUS] |= SI_MANA_PLUS; + status->IconChangeTable[SC_MUSTLE_M] |= SI_MUSTLE_M; + status->IconChangeTable[SC_LIFE_FORCE_F] |= SI_LIFE_FORCE_F; + status->IconChangeTable[SC_EXTRACT_WHITE_POTION_Z] |= SI_EXTRACT_WHITE_POTION_Z; + status->IconChangeTable[SC_VITATA_500] |= SI_VITATA_500; + status->IconChangeTable[SC_EXTRACT_SALAMINE_JUICE] |= SI_EXTRACT_SALAMINE_JUICE; // Elemental Spirit's 'side' status change icons. - StatusIconChangeTable[SC_CIRCLE_OF_FIRE] = SI_CIRCLE_OF_FIRE; - StatusIconChangeTable[SC_FIRE_CLOAK] = SI_FIRE_CLOAK; - StatusIconChangeTable[SC_WATER_SCREEN] = SI_WATER_SCREEN; - StatusIconChangeTable[SC_WATER_DROP] = SI_WATER_DROP; - StatusIconChangeTable[SC_WIND_STEP] = SI_WIND_STEP; - StatusIconChangeTable[SC_WIND_CURTAIN] = SI_WIND_CURTAIN; - StatusIconChangeTable[SC_SOLID_SKIN] = SI_SOLID_SKIN; - StatusIconChangeTable[SC_STONE_SHIELD] = SI_STONE_SHIELD; - StatusIconChangeTable[SC_PYROTECHNIC] = SI_PYROTECHNIC; - StatusIconChangeTable[SC_HEATER] = SI_HEATER; - StatusIconChangeTable[SC_TROPIC] = SI_TROPIC; - StatusIconChangeTable[SC_AQUAPLAY] = SI_AQUAPLAY; - StatusIconChangeTable[SC_COOLER] = SI_COOLER; - StatusIconChangeTable[SC_CHILLY_AIR] = SI_CHILLY_AIR; - StatusIconChangeTable[SC_GUST] = SI_GUST; - StatusIconChangeTable[SC_BLAST] = SI_BLAST; - StatusIconChangeTable[SC_WILD_STORM] = SI_WILD_STORM; - StatusIconChangeTable[SC_PETROLOGY] = SI_PETROLOGY; - StatusIconChangeTable[SC_CURSED_SOIL] = SI_CURSED_SOIL; - StatusIconChangeTable[SC_UPHEAVAL] = SI_UPHEAVAL; - StatusIconChangeTable[SC_PUSH_CART] = SI_ON_PUSH_CART; - StatusIconChangeTable[SC_REBOUND] = SI_REBOUND; - StatusIconChangeTable[SC_ALL_RIDING] = SI_ALL_RIDING; - StatusIconChangeTable[SC_MONSTER_TRANSFORM] = SI_MONSTER_TRANSFORM; + status->IconChangeTable[SC_CIRCLE_OF_FIRE] = SI_CIRCLE_OF_FIRE; + status->IconChangeTable[SC_FIRE_CLOAK] = SI_FIRE_CLOAK; + status->IconChangeTable[SC_WATER_SCREEN] = SI_WATER_SCREEN; + status->IconChangeTable[SC_WATER_DROP] = SI_WATER_DROP; + status->IconChangeTable[SC_WIND_STEP] = SI_WIND_STEP; + status->IconChangeTable[SC_WIND_CURTAIN] = SI_WIND_CURTAIN; + status->IconChangeTable[SC_SOLID_SKIN] = SI_SOLID_SKIN; + status->IconChangeTable[SC_STONE_SHIELD] = SI_STONE_SHIELD; + status->IconChangeTable[SC_PYROTECHNIC] = SI_PYROTECHNIC; + status->IconChangeTable[SC_HEATER] = SI_HEATER; + status->IconChangeTable[SC_TROPIC] = SI_TROPIC; + status->IconChangeTable[SC_AQUAPLAY] = SI_AQUAPLAY; + status->IconChangeTable[SC_COOLER] = SI_COOLER; + status->IconChangeTable[SC_CHILLY_AIR] = SI_CHILLY_AIR; + status->IconChangeTable[SC_GUST] = SI_GUST; + status->IconChangeTable[SC_BLAST] = SI_BLAST; + status->IconChangeTable[SC_WILD_STORM] = SI_WILD_STORM; + status->IconChangeTable[SC_PETROLOGY] = SI_PETROLOGY; + status->IconChangeTable[SC_CURSED_SOIL] = SI_CURSED_SOIL; + status->IconChangeTable[SC_UPHEAVAL] = SI_UPHEAVAL; + status->IconChangeTable[SC_PUSH_CART] = SI_ON_PUSH_CART; + status->IconChangeTable[SC_REBOUND] = SI_REBOUND; + status->IconChangeTable[SC_ALL_RIDING] = SI_ALL_RIDING; + status->IconChangeTable[SC_MONSTER_TRANSFORM] = SI_MONSTER_TRANSFORM; + status->IconChangeTable[SC_MOONSTAR] = SI_MOONSTAR; + status->IconChangeTable[SC_SUPER_STAR] = SI_SUPER_STAR; + status->IconChangeTable[SC_STRANGELIGHTS] = SI_STRANGELIGHTS; + status->IconChangeTable[SC_DECORATION_OF_MUSIC] = SI_DECORATION_OF_MUSIC; //Other SC which are not necessarily associated to skills. - StatusChangeFlagTable[SC_ATTHASTE_POTION1] = SCB_ASPD; - StatusChangeFlagTable[SC_ATTHASTE_POTION2] = SCB_ASPD; - StatusChangeFlagTable[SC_ATTHASTE_POTION3] = SCB_ASPD; - StatusChangeFlagTable[SC_ATTHASTE_INFINITY] = SCB_ASPD; - StatusChangeFlagTable[SC_MOVHASTE_HORSE] = SCB_SPEED; - StatusChangeFlagTable[SC_MOVHASTE_INFINITY] = SCB_SPEED; - StatusChangeFlagTable[SC_PLUSATTACKPOWER] = SCB_BATK; - StatusChangeFlagTable[SC_PLUSMAGICPOWER] = SCB_MATK; - StatusChangeFlagTable[SC_INCALLSTATUS] |= SCB_STR|SCB_AGI|SCB_VIT|SCB_INT|SCB_DEX|SCB_LUK; - StatusChangeFlagTable[SC_CHASEWALK2] |= SCB_STR; - StatusChangeFlagTable[SC_INCAGI] |= SCB_AGI; - StatusChangeFlagTable[SC_INCVIT] |= SCB_VIT; - StatusChangeFlagTable[SC_INCINT] |= SCB_INT; - StatusChangeFlagTable[SC_INCDEX] |= SCB_DEX; - StatusChangeFlagTable[SC_INCLUK] |= SCB_LUK; - StatusChangeFlagTable[SC_INCHIT] |= SCB_HIT; - StatusChangeFlagTable[SC_INCHITRATE] |= SCB_HIT; - StatusChangeFlagTable[SC_INCFLEE] |= SCB_FLEE; - StatusChangeFlagTable[SC_INCFLEERATE] |= SCB_FLEE; - StatusChangeFlagTable[SC_CRITICALPERCENT] |= SCB_CRI; - StatusChangeFlagTable[SC_INCASPDRATE] |= SCB_ASPD; - StatusChangeFlagTable[SC_PLUSAVOIDVALUE] |= SCB_FLEE2; - StatusChangeFlagTable[SC_INCMHPRATE] |= SCB_MAXHP; - StatusChangeFlagTable[SC_INCMSPRATE] |= SCB_MAXSP; - StatusChangeFlagTable[SC_INCMHP] |= SCB_MAXHP; - StatusChangeFlagTable[SC_INCMSP] |= SCB_MAXSP; - StatusChangeFlagTable[SC_INCATKRATE] |= SCB_BATK|SCB_WATK; - StatusChangeFlagTable[SC_INCMATKRATE] |= SCB_MATK; - StatusChangeFlagTable[SC_INCDEFRATE] |= SCB_DEF; - StatusChangeFlagTable[SC_FOOD_STR] |= SCB_STR; - StatusChangeFlagTable[SC_FOOD_AGI] |= SCB_AGI; - StatusChangeFlagTable[SC_FOOD_VIT] |= SCB_VIT; - StatusChangeFlagTable[SC_FOOD_INT] |= SCB_INT; - StatusChangeFlagTable[SC_FOOD_DEX] |= SCB_DEX; - StatusChangeFlagTable[SC_FOOD_LUK] |= SCB_LUK; - StatusChangeFlagTable[SC_FOOD_BASICHIT] |= SCB_HIT; - StatusChangeFlagTable[SC_FOOD_BASICAVOIDANCE] |= SCB_FLEE; - StatusChangeFlagTable[SC_BATKFOOD] |= SCB_BATK; - StatusChangeFlagTable[SC_WATKFOOD] |= SCB_WATK; - StatusChangeFlagTable[SC_MATKFOOD] |= SCB_MATK; - StatusChangeFlagTable[SC_ARMORPROPERTY] |= SCB_ALL; - StatusChangeFlagTable[SC_ARMOR_RESIST] |= SCB_ALL; - StatusChangeFlagTable[SC_ATKER_BLOOD] |= SCB_ALL; - StatusChangeFlagTable[SC_WALKSPEED] |= SCB_SPEED; - StatusChangeFlagTable[SC_ITEMSCRIPT] |= SCB_ALL; + status->ChangeFlagTable[SC_ATTHASTE_POTION1] = SCB_ASPD; + status->ChangeFlagTable[SC_ATTHASTE_POTION2] = SCB_ASPD; + status->ChangeFlagTable[SC_ATTHASTE_POTION3] = SCB_ASPD; + status->ChangeFlagTable[SC_ATTHASTE_INFINITY] = SCB_ASPD; + status->ChangeFlagTable[SC_MOVHASTE_HORSE] = SCB_SPEED; + status->ChangeFlagTable[SC_MOVHASTE_INFINITY] = SCB_SPEED; + status->ChangeFlagTable[SC_PLUSATTACKPOWER] = SCB_BATK; + status->ChangeFlagTable[SC_PLUSMAGICPOWER] = SCB_MATK; + status->ChangeFlagTable[SC_INCALLSTATUS] |= SCB_STR|SCB_AGI|SCB_VIT|SCB_INT|SCB_DEX|SCB_LUK; + status->ChangeFlagTable[SC_CHASEWALK2] |= SCB_STR; + status->ChangeFlagTable[SC_INCAGI] |= SCB_AGI; + status->ChangeFlagTable[SC_INCVIT] |= SCB_VIT; + status->ChangeFlagTable[SC_INCINT] |= SCB_INT; + status->ChangeFlagTable[SC_INCDEX] |= SCB_DEX; + status->ChangeFlagTable[SC_INCLUK] |= SCB_LUK; + status->ChangeFlagTable[SC_INCHIT] |= SCB_HIT; + status->ChangeFlagTable[SC_INCHITRATE] |= SCB_HIT; + status->ChangeFlagTable[SC_INCFLEE] |= SCB_FLEE; + status->ChangeFlagTable[SC_INCFLEERATE] |= SCB_FLEE; + status->ChangeFlagTable[SC_CRITICALPERCENT] |= SCB_CRI; + status->ChangeFlagTable[SC_INCASPDRATE] |= SCB_ASPD; + status->ChangeFlagTable[SC_PLUSAVOIDVALUE] |= SCB_FLEE2; + status->ChangeFlagTable[SC_INCMHPRATE] |= SCB_MAXHP; + status->ChangeFlagTable[SC_INCMSPRATE] |= SCB_MAXSP; + status->ChangeFlagTable[SC_INCMHP] |= SCB_MAXHP; + status->ChangeFlagTable[SC_INCMSP] |= SCB_MAXSP; + status->ChangeFlagTable[SC_INCATKRATE] |= SCB_BATK|SCB_WATK; + status->ChangeFlagTable[SC_INCMATKRATE] |= SCB_MATK; + status->ChangeFlagTable[SC_INCDEFRATE] |= SCB_DEF; + status->ChangeFlagTable[SC_FOOD_STR] |= SCB_STR; + status->ChangeFlagTable[SC_FOOD_AGI] |= SCB_AGI; + status->ChangeFlagTable[SC_FOOD_VIT] |= SCB_VIT; + status->ChangeFlagTable[SC_FOOD_INT] |= SCB_INT; + status->ChangeFlagTable[SC_FOOD_DEX] |= SCB_DEX; + status->ChangeFlagTable[SC_FOOD_LUK] |= SCB_LUK; + status->ChangeFlagTable[SC_FOOD_BASICHIT] |= SCB_HIT; + status->ChangeFlagTable[SC_FOOD_BASICAVOIDANCE] |= SCB_FLEE; + status->ChangeFlagTable[SC_BATKFOOD] |= SCB_BATK; + status->ChangeFlagTable[SC_WATKFOOD] |= SCB_WATK; + status->ChangeFlagTable[SC_MATKFOOD] |= SCB_MATK; + status->ChangeFlagTable[SC_ARMORPROPERTY] |= SCB_ALL; + status->ChangeFlagTable[SC_ARMOR_RESIST] |= SCB_ALL; + status->ChangeFlagTable[SC_ATKER_BLOOD] |= SCB_ALL; + status->ChangeFlagTable[SC_WALKSPEED] |= SCB_SPEED; + status->ChangeFlagTable[SC_ITEMSCRIPT] |= SCB_ALL; // Cash Items - StatusChangeFlagTable[SC_FOOD_STR_CASH] = SCB_STR; - StatusChangeFlagTable[SC_FOOD_AGI_CASH] = SCB_AGI; - StatusChangeFlagTable[SC_FOOD_VIT_CASH] = SCB_VIT; - StatusChangeFlagTable[SC_FOOD_DEX_CASH] = SCB_DEX; - StatusChangeFlagTable[SC_FOOD_INT_CASH] = SCB_INT; - StatusChangeFlagTable[SC_FOOD_LUK_CASH] = SCB_LUK; + status->ChangeFlagTable[SC_FOOD_STR_CASH] = SCB_STR; + status->ChangeFlagTable[SC_FOOD_AGI_CASH] = SCB_AGI; + status->ChangeFlagTable[SC_FOOD_VIT_CASH] = SCB_VIT; + status->ChangeFlagTable[SC_FOOD_DEX_CASH] = SCB_DEX; + status->ChangeFlagTable[SC_FOOD_INT_CASH] = SCB_INT; + status->ChangeFlagTable[SC_FOOD_LUK_CASH] = SCB_LUK; // Mercenary Bonus Effects - StatusChangeFlagTable[SC_MER_FLEE] |= SCB_FLEE; - StatusChangeFlagTable[SC_MER_ATK] |= SCB_WATK; - StatusChangeFlagTable[SC_MER_HP] |= SCB_MAXHP; - StatusChangeFlagTable[SC_MER_SP] |= SCB_MAXSP; - StatusChangeFlagTable[SC_MER_HIT] |= SCB_HIT; + status->ChangeFlagTable[SC_MER_FLEE] |= SCB_FLEE; + status->ChangeFlagTable[SC_MER_ATK] |= SCB_WATK; + status->ChangeFlagTable[SC_MER_HP] |= SCB_MAXHP; + status->ChangeFlagTable[SC_MER_SP] |= SCB_MAXSP; + status->ChangeFlagTable[SC_MER_HIT] |= SCB_HIT; // Guillotine Cross Poison Effects - StatusChangeFlagTable[SC_PARALYSE] |= SCB_ASPD|SCB_FLEE|SCB_SPEED; - StatusChangeFlagTable[SC_DEATHHURT] |= SCB_REGEN; - StatusChangeFlagTable[SC_VENOMBLEED] |= SCB_MAXHP; - StatusChangeFlagTable[SC_OBLIVIONCURSE] |= SCB_REGEN; - - StatusChangeFlagTable[SC_SAVAGE_STEAK] |= SCB_STR; - StatusChangeFlagTable[SC_COCKTAIL_WARG_BLOOD] |= SCB_INT; - StatusChangeFlagTable[SC_MINOR_BBQ] |= SCB_VIT; - StatusChangeFlagTable[SC_SIROMA_ICE_TEA] |= SCB_DEX; - StatusChangeFlagTable[SC_DROCERA_HERB_STEAMED] |= SCB_AGI; - StatusChangeFlagTable[SC_PUTTI_TAILS_NOODLES] |= SCB_LUK; - StatusChangeFlagTable[SC_BOOST500] |= SCB_ASPD; - StatusChangeFlagTable[SC_FULL_SWING_K] |= SCB_BATK; - StatusChangeFlagTable[SC_MANA_PLUS] |= SCB_MATK; - StatusChangeFlagTable[SC_MUSTLE_M] |= SCB_MAXHP; - StatusChangeFlagTable[SC_LIFE_FORCE_F] |= SCB_MAXSP; - StatusChangeFlagTable[SC_EXTRACT_WHITE_POTION_Z] |= SCB_REGEN; - StatusChangeFlagTable[SC_VITATA_500] |= SCB_REGEN; - StatusChangeFlagTable[SC_EXTRACT_SALAMINE_JUICE] |= SCB_ASPD; - StatusChangeFlagTable[SC_REBOUND] |= SCB_SPEED|SCB_REGEN; - - StatusChangeFlagTable[SC_ALL_RIDING] = SCB_SPEED; - - /* StatusDisplayType Table [Ind/Hercules] */ - StatusDisplayType[SC_ALL_RIDING] = true; - StatusDisplayType[SC_PUSH_CART] = true; - StatusDisplayType[SC_SUMMON1] = true; - StatusDisplayType[SC_SUMMON2] = true; - StatusDisplayType[SC_SUMMON3] = true; - StatusDisplayType[SC_SUMMON4] = true; - StatusDisplayType[SC_SUMMON5] = true; - StatusDisplayType[SC_CAMOUFLAGE] = true; - StatusDisplayType[SC_DUPLELIGHT] = true; - StatusDisplayType[SC_ORATIO] = true; - StatusDisplayType[SC_FROSTMISTY] = true; - StatusDisplayType[SC_VENOMIMPRESS] = true; - StatusDisplayType[SC_HALLUCINATIONWALK] = true; - StatusDisplayType[SC_ROLLINGCUTTER] = true; - StatusDisplayType[SC_BANDING] = true; - StatusDisplayType[SC_CRYSTALIZE] = true; - StatusDisplayType[SC_DEEP_SLEEP] = true; - StatusDisplayType[SC_CURSEDCIRCLE_ATKER]= true; - StatusDisplayType[SC_CURSEDCIRCLE_TARGET]= true; - StatusDisplayType[SC_BLOOD_SUCKER] = true; - StatusDisplayType[SC__SHADOWFORM] = true; - StatusDisplayType[SC__MANHOLE] = true; - StatusDisplayType[SC_MONSTER_TRANSFORM] = true; - + status->ChangeFlagTable[SC_PARALYSE] |= SCB_FLEE|SCB_SPEED|SCB_ASPD; + status->ChangeFlagTable[SC_VENOMBLEED] |= SCB_MAXHP; + status->ChangeFlagTable[SC_MAGICMUSHROOM] |= SCB_REGEN; + status->ChangeFlagTable[SC_DEATHHURT] |= SCB_REGEN; + status->ChangeFlagTable[SC_PYREXIA] |= SCB_HIT|SCB_FLEE; + status->ChangeFlagTable[SC_OBLIVIONCURSE] |= SCB_REGEN; + // RG status + status->ChangeFlagTable[SC_SHIELDSPELL_DEF] |= SCB_WATK; + status->ChangeFlagTable[SC_SHIELDSPELL_REF] |= SCB_DEF; + // Meca status + status->ChangeFlagTable[SC_STEALTHFIELD_MASTER] |= SCB_SPEED; + + status->ChangeFlagTable[SC_SAVAGE_STEAK] |= SCB_STR; + status->ChangeFlagTable[SC_COCKTAIL_WARG_BLOOD] |= SCB_INT; + status->ChangeFlagTable[SC_MINOR_BBQ] |= SCB_VIT; + status->ChangeFlagTable[SC_SIROMA_ICE_TEA] |= SCB_DEX; + status->ChangeFlagTable[SC_DROCERA_HERB_STEAMED] |= SCB_AGI; + status->ChangeFlagTable[SC_PUTTI_TAILS_NOODLES] |= SCB_LUK; + status->ChangeFlagTable[SC_BOOST500] |= SCB_ASPD; + status->ChangeFlagTable[SC_FULL_SWING_K] |= SCB_BATK; + status->ChangeFlagTable[SC_MANA_PLUS] |= SCB_MATK; + status->ChangeFlagTable[SC_MUSTLE_M] |= SCB_MAXHP; + status->ChangeFlagTable[SC_LIFE_FORCE_F] |= SCB_MAXSP; + status->ChangeFlagTable[SC_EXTRACT_WHITE_POTION_Z] |= SCB_REGEN; + status->ChangeFlagTable[SC_VITATA_500] |= SCB_REGEN; + status->ChangeFlagTable[SC_EXTRACT_SALAMINE_JUICE] |= SCB_ASPD; + status->ChangeFlagTable[SC_REBOUND] |= SCB_SPEED|SCB_REGEN; + status->ChangeFlagTable[SC_DEFSET] |= SCB_DEF|SCB_DEF2; + status->ChangeFlagTable[SC_MDEFSET] |= SCB_MDEF|SCB_MDEF2; + + status->ChangeFlagTable[SC_ALL_RIDING] = SCB_SPEED; + status->ChangeFlagTable[SC_WEDDING] = SCB_SPEED; + + status->ChangeFlagTable[SC_MTF_ASPD] = SCB_ASPD|SCB_HIT; + status->ChangeFlagTable[SC_MTF_MATK] = SCB_MATK; + status->ChangeFlagTable[SC_MTF_MLEATKED] |= SCB_ALL; + + status->ChangeFlagTable[SC_MOONSTAR] |= SCB_NONE; + status->ChangeFlagTable[SC_SUPER_STAR] |= SCB_NONE; + status->ChangeFlagTable[SC_STRANGELIGHTS] |= SCB_NONE; + status->ChangeFlagTable[SC_DECORATION_OF_MUSIC] |= SCB_NONE; + + /* status->DisplayType Table [Ind/Hercules] */ + status->DisplayType[SC_ALL_RIDING] = true; + status->DisplayType[SC_PUSH_CART] = true; + status->DisplayType[SC_SUMMON1] = true; + status->DisplayType[SC_SUMMON2] = true; + status->DisplayType[SC_SUMMON3] = true; + status->DisplayType[SC_SUMMON4] = true; + status->DisplayType[SC_SUMMON5] = true; + status->DisplayType[SC_CAMOUFLAGE] = true; + status->DisplayType[SC_DUPLELIGHT] = true; + status->DisplayType[SC_ORATIO] = true; + status->DisplayType[SC_FROSTMISTY] = true; + status->DisplayType[SC_VENOMIMPRESS] = true; + status->DisplayType[SC_HALLUCINATIONWALK] = true; + status->DisplayType[SC_ROLLINGCUTTER] = true; + status->DisplayType[SC_BANDING] = true; + status->DisplayType[SC_COLD] = true; + status->DisplayType[SC_DEEP_SLEEP] = true; + status->DisplayType[SC_CURSEDCIRCLE_ATKER]= true; + status->DisplayType[SC_CURSEDCIRCLE_TARGET]= true; + status->DisplayType[SC_BLOOD_SUCKER] = true; + status->DisplayType[SC__SHADOWFORM] = true; + status->DisplayType[SC_MONSTER_TRANSFORM] = true; + status->DisplayType[SC_MOONSTAR] = true; + status->DisplayType[SC_SUPER_STAR] = true; + status->DisplayType[SC_STRANGELIGHTS] = true; + status->DisplayType[SC_DECORATION_OF_MUSIC] = true; + #ifdef RENEWAL_EDP // renewal EDP increases your weapon atk - StatusChangeFlagTable[SC_EDP] |= SCB_WATK; + status->ChangeFlagTable[SC_EDP] |= SCB_WATK; #endif if( !battle_config.display_hallucination ) //Disable Hallucination. - StatusIconChangeTable[SC_ILLUSION] = SI_BLANK; + status->IconChangeTable[SC_ILLUSION] = SI_BLANK; +#undef add_sc +#undef set_sc_with_vfx } -static void initDummyData(void) +void initDummyData(void) { - memset(&dummy_status, 0, sizeof(dummy_status)); - dummy_status.hp = - dummy_status.max_hp = - dummy_status.max_sp = - dummy_status.str = - dummy_status.agi = - dummy_status.vit = - dummy_status.int_ = - dummy_status.dex = - dummy_status.luk = - dummy_status.hit = 1; - dummy_status.speed = 2000; - dummy_status.adelay = 4000; - dummy_status.amotion = 2000; - dummy_status.dmotion = 2000; - dummy_status.ele_lv = 1; //Min elemental level. - dummy_status.mode = MD_CANMOVE; + memset(&status->dummy, 0, sizeof(status->dummy)); + status->dummy.hp = + status->dummy.max_hp = + status->dummy.max_sp = + status->dummy.str = + status->dummy.agi = + status->dummy.vit = + status->dummy.int_ = + status->dummy.dex = + status->dummy.luk = + status->dummy.hit = 1; + status->dummy.speed = 2000; + status->dummy.adelay = 4000; + status->dummy.amotion = 2000; + status->dummy.dmotion = 2000; + status->dummy.ele_lv = 1; //Min elemental level. + status->dummy.mode = MD_CANMOVE; } @@ -1062,107 +1084,123 @@ static inline void status_cpy(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))); } -//Sets HP to given value. Flag is the flag passed to status_heal in case +//Sets HP to given value. Flag is the flag passed to status->heal in case //final value is higher than current (use 2 to make a healing effect display //on players) It will always succeed (overrides Berserk block), but it can't kill. -int status_set_hp(struct block_list *bl, unsigned int hp, int flag) -{ - struct status_data *status; +int status_set_hp(struct block_list *bl, unsigned int hp, int flag) { + struct status_data *st; if (hp < 1) return 0; - status = status_get_status_data(bl); - if (status == &dummy_status) + st = status->get_status_data(bl); + if (st == &status->dummy) return 0; - if (hp > status->max_hp) hp = status->max_hp; - if (hp == status->hp) return 0; - if (hp > status->hp) - return status_heal(bl, hp - status->hp, 0, 1|flag); - return status_zap(bl, status->hp - hp, 0); + if (hp > st->max_hp) hp = st->max_hp; + if (hp == st->hp) return 0; + if (hp > st->hp) + return status->heal(bl, hp - st->hp, 0, 1|flag); + return status_zap(bl, st->hp - hp, 0); } -//Sets SP to given value. Flag is the flag passed to status_heal in case +//Sets SP to given value. Flag is the flag passed to status->heal in case //final value is higher than current (use 2 to make a healing effect display //on players) -int status_set_sp(struct block_list *bl, unsigned int sp, int flag) -{ - struct status_data *status; +int status_set_sp(struct block_list *bl, unsigned int sp, int flag) { + struct status_data *st; - status = status_get_status_data(bl); - if (status == &dummy_status) + st = status->get_status_data(bl); + if (st == &status->dummy) return 0; - if (sp > status->max_sp) sp = status->max_sp; - if (sp == status->sp) return 0; - if (sp > status->sp) - return status_heal(bl, 0, sp - status->sp, 1|flag); - return status_zap(bl, 0, status->sp - sp); + if (sp > st->max_sp) sp = st->max_sp; + if (sp == st->sp) return 0; + if (sp > st->sp) + return status->heal(bl, 0, sp - st->sp, 1|flag); + return status_zap(bl, 0, st->sp - sp); } -int status_charge(struct block_list* bl, int hp, int sp) -{ +int status_charge(struct block_list* bl, int64 hp, int64 sp) { if(!(bl->type&BL_CONSUME)) - return hp+sp; //Assume all was charged so there are no 'not enough' fails. - return status_damage(NULL, bl, hp, sp, 0, 3); + return (int)(hp+sp); //Assume all was charged so there are no 'not enough' fails. + return status->damage(NULL, bl, hp, sp, 0, 3); } //Inflicts damage on the target with the according walkdelay. -//If flag&1, damage is passive and does not triggers cancelling status changes. -//If flag&2, fail if target does not has enough to substract. +//If flag&1, damage is passive and does not triggers canceling status changes. +//If flag&2, fail if target does not has enough to subtract. //If flag&4, if killed, mob must not give exp/loot. //flag will be set to &8 when damaging sp of a dead character -int status_damage(struct block_list *src,struct block_list *target,int hp, int sp, int walkdelay, int flag) -{ - struct status_data *status; +int status_damage(struct block_list *src,struct block_list *target,int64 in_hp, int64 in_sp, int walkdelay, int flag) { + struct status_data *st; struct status_change *sc; + int hp,sp; + /* here onwards we consider it a 32-type, the client does not support higher and from here onwards the value doesn't get thru percentage modifiers */ + hp = (int)cap_value(in_hp,INT_MIN,INT_MAX); + sp = (int)cap_value(in_sp,INT_MIN,INT_MAX); + if(sp && !(target->type&BL_CONSUME)) sp = 0; //Not a valid SP target. if (hp < 0) { //Assume absorbed damage. - status_heal(target, -hp, 0, 1); + status->heal(target, -hp, 0, 1); hp = 0; } if (sp < 0) { - status_heal(target, 0, -sp, 1); + status->heal(target, 0, -sp, 1); sp = 0; } if (target->type == BL_SKILL) - return skill->unit_ondamaged((struct skill_unit *)target, src, hp, iTimer->gettick()); + return skill->unit_ondamaged((struct skill_unit *)target, src, hp, timer->gettick()); - status = status_get_status_data(target); - if( status == &dummy_status ) + st = status->get_status_data(target); + if( st == &status->dummy ) return 0; - if ((unsigned int)hp >= status->hp) { + if ((unsigned int)hp >= st->hp) { if (flag&2) return 0; - hp = status->hp; + hp = st->hp; } - if ((unsigned int)sp > status->sp) { + if ((unsigned int)sp > st->sp) { if (flag&2) return 0; - sp = status->sp; + sp = st->sp; } if (!hp && !sp) return 0; - if( !status->hp ) + if( !st->hp ) flag |= 8; -// Let through. battle.c/skill.c have the whole logic of when it's possible or -// not to hurt someone (and this check breaks pet catching) [Skotlex] -// if (!target->prev && !(flag&2)) -// return 0; //Cannot damage a bl not on a map, except when "charging" hp/sp + // Let through. battle.c/skill.c have the whole logic of when it's possible or + // not to hurt someone (and this check breaks pet catching) [Skotlex] + // if (!target->prev && !(flag&2)) + // return 0; //Cannot damage a bl not on a map, except when "charging" hp/sp - sc = status_get_sc(target); + sc = status->get_sc(target); if( hp && battle_config.invincible_nodamage && src && sc && sc->data[SC_INVINCIBLE] && !sc->data[SC_INVINCIBLEOFF] ) hp = 1; if( hp && !(flag&1) ) { if( sc ) { struct status_change_entry *sce; + +#ifdef DEVOTION_REFLECT_DAMAGE + if(src && (sce = sc->data[SC_DEVOTION])) { + struct block_list *d_bl = map->id2bl(sce->val1); + + if(d_bl &&((d_bl->type == BL_MER && ((TBL_MER *)d_bl)->master && ((TBL_MER *)d_bl)->master->bl.id == target->id) + || (d_bl->type == BL_PC && ((TBL_PC *)d_bl)->devotion[sce->val2] == target->id)) && check_distance_bl(target, d_bl, sce->val3)) { + clif->damage(d_bl, d_bl, 0, 0, hp, 0, 0, 0); + status_fix_damage(NULL, d_bl, hp, 0); + return 0; + } + status_change_end(target, SC_DEVOTION, INVALID_TIMER); + } +#endif + if (sc->data[SC_STONE] && sc->opt1 == OPT1_STONE) status_change_end(target, SC_STONE, INVALID_TIMER); status_change_end(target, SC_FREEZE, INVALID_TIMER); @@ -1174,12 +1212,10 @@ int status_damage(struct block_list *src,struct block_list *target,int hp, int s status_change_end(target, SC_CLOAKING, INVALID_TIMER); status_change_end(target, SC_CHASEWALK, INVALID_TIMER); status_change_end(target, SC_CAMOUFLAGE, INVALID_TIMER); - status_change_end(target, SC__INVISIBILITY, INVALID_TIMER); - status_change_end(target, SC_DEEP_SLEEP, INVALID_TIMER); if ((sce=sc->data[SC_ENDURE]) && !sce->val4 && !sc->data[SC_LKCONCENTRATION]) { //Endure count is only reduced by non-players on non-gvg maps. //val4 signals infinite endure. [Skotlex] - if (src && src->type != BL_PC && !map_flag_gvg(target->m) && !map[target->m].flag.battleground && --(sce->val2) < 0) + if (src && src->type != BL_PC && !map_flag_gvg2(target->m) && !map->list[target->m].flag.battleground && --(sce->val2) < 0) status_change_end(target, SC_ENDURE, INVALID_TIMER); } if ((sce=sc->data[SC_GRAVITATION]) && sce->val3 == BCT_SELF) { @@ -1190,82 +1226,80 @@ int status_damage(struct block_list *src,struct block_list *target,int hp, int s status_change_end(target, SC_GRAVITATION, INVALID_TIMER); } } - if(sc->data[SC_DANCING] && (unsigned int)hp > status->max_hp>>2) + if(sc->data[SC_DANCING] && (unsigned int)hp > st->max_hp>>2) status_change_end(target, SC_DANCING, INVALID_TIMER); if(sc->data[SC_CLOAKINGEXCEED] && --(sc->data[SC_CLOAKINGEXCEED]->val2) <= 0) status_change_end(target, SC_CLOAKINGEXCEED, INVALID_TIMER); if(sc->data[SC_KAGEMUSYA] && --(sc->data[SC_KAGEMUSYA]->val3) <= 0) status_change_end(target, SC_KAGEMUSYA, INVALID_TIMER); } - unit_skillcastcancel(target, 2); + unit->skillcastcancel(target, 2); } - status->hp-= hp; - status->sp-= sp; + st->hp-= hp; + st->sp-= sp; - if (sc && hp && status->hp) { + if (sc && hp && st->hp) { if (sc->data[SC_AUTOBERSERK] && (!sc->data[SC_PROVOKE] || !sc->data[SC_PROVOKE]->val2) && - status->hp < status->max_hp>>2) - sc_start4(target,SC_PROVOKE,100,10,1,0,0,0); - if (sc->data[SC_BERSERK] && status->hp <= 100) + st->hp < st->max_hp>>2) + sc_start4(src,target,SC_PROVOKE,100,10,1,0,0,0); + if (sc->data[SC_BERSERK] && st->hp <= 100) status_change_end(target, SC_BERSERK, INVALID_TIMER); - if( sc->data[SC_RAISINGDRAGON] && status->hp <= 1000 ) + if( sc->data[SC_RAISINGDRAGON] && st->hp <= 1000 ) status_change_end(target, SC_RAISINGDRAGON, INVALID_TIMER); - if (sc->data[SC_SATURDAY_NIGHT_FEVER] && status->hp <= 100) + if (sc->data[SC_SATURDAY_NIGHT_FEVER] && st->hp <= 100) status_change_end(target, SC_SATURDAY_NIGHT_FEVER, INVALID_TIMER); - if (sc->data[SC__BLOODYLUST] && status->hp <= 100) - status_change_end(target, SC__BLOODYLUST, INVALID_TIMER); } switch (target->type) { - case BL_PC: pc->damage((TBL_PC*)target,src,hp,sp); break; - case BL_MOB: mob_damage((TBL_MOB*)target, src, hp); break; - case BL_HOM: homun->damaged((TBL_HOM*)target); break; - case BL_MER: mercenary_heal((TBL_MER*)target,hp,sp); break; - case BL_ELEM: elemental_heal((TBL_ELEM*)target,hp,sp); break; + case BL_PC: pc->damage((TBL_PC*)target,src,hp,sp); break; + case BL_MOB: mob->damage((TBL_MOB*)target, src, hp); break; + case BL_HOM: homun->damaged((TBL_HOM*)target); break; + case BL_MER: mercenary->heal((TBL_MER*)target,hp,sp); break; + case BL_ELEM: elemental->heal((TBL_ELEM*)target,hp,sp); break; } - if( src && target->type == BL_PC && ((TBL_PC*)target)->disguise ) {// stop walking when attacked in disguise to prevent walk-delay bug - unit_stop_walking( target, 1 ); + if( src && target->type == BL_PC && (((TBL_PC*)target)->disguise) > 0 ) {// stop walking when attacked in disguise to prevent walk-delay bug + unit->stop_walking( target, 1 ); } - if( status->hp || (flag&8) ) - { //Still lives or has been dead before this damage. + if( st->hp || (flag&8) ) + { //Still lives or has been dead before this damage. if (walkdelay) - unit_set_walkdelay(target, iTimer->gettick(), walkdelay, 0); - return hp+sp; + unit->set_walkdelay(target, timer->gettick(), walkdelay, 0); + return (int)(hp+sp); } - status->hp = 1; //To let the dead function cast skills and all that. + st->hp = 1; //To let the dead function cast skills and all that. //NOTE: These dead functions should return: [Skotlex] - //0: Death cancelled, auto-revived. + //0: Death canceled, auto-revived. //Non-zero: Standard death. Clear status, cancel move/attack, etc //&2: Also remove object from map. //&4: Also delete object from memory. switch (target->type) { - case BL_PC: flag = pc->dead((TBL_PC*)target,src); break; - case BL_MOB: flag = mob_dead((TBL_MOB*)target, src, flag&4?3:0); break; - case BL_HOM: flag = homun->dead((TBL_HOM*)target); break; - case BL_MER: flag = mercenary_dead((TBL_MER*)target); break; - case BL_ELEM: flag = elemental_dead((TBL_ELEM*)target); break; - default: //Unhandled case, do nothing to object. - flag = 0; - break; + case BL_PC: flag = pc->dead((TBL_PC*)target,src); break; + case BL_MOB: flag = mob->dead((TBL_MOB*)target, src, flag&4?3:0); break; + case BL_HOM: flag = homun->dead((TBL_HOM*)target); break; + case BL_MER: flag = mercenary->dead((TBL_MER*)target); break; + case BL_ELEM: flag = elemental->dead((TBL_ELEM*)target); break; + default: //Unhandled case, do nothing to object. + flag = 0; + break; } - if(!flag) //Death cancelled. - return hp+sp; + if(!flag) //Death canceled. + return (int)(hp+sp); //Normal death - status->hp = 0; + st->hp = 0; if (battle_config.clear_unit_ondeath && battle_config.clear_unit_ondeath&target->type) skill->clear_unitgroup(target); - if(target->type&BL_REGEN) - { //Reset regen ticks. - struct regen_data *regen = status_get_regen_data(target); + if(target->type&BL_REGEN) { + //Reset regen ticks. + struct regen_data *regen = status->get_regen_data(target); if (regen) { memset(®en->tick, 0, sizeof(regen->tick)); if (regen->sregen) @@ -1275,129 +1309,123 @@ int status_damage(struct block_list *src,struct block_list *target,int hp, int s } } - if( sc && sc->data[SC_KAIZEL] && !map_flag_gvg(target->m) ) - { //flag&8 = disable Kaizel + if( sc && sc->data[SC_KAIZEL] && !map_flag_gvg2(target->m) ) { + //flag&8 = disable Kaizel int time = skill->get_time2(SL_KAIZEL,sc->data[SC_KAIZEL]->val1); //Look for Osiris Card's bonus effect on the character and revive 100% or revive normally if ( target->type == BL_PC && BL_CAST(BL_PC,target)->special_state.restart_full_recover ) - status_revive(target, 100, 100); + status->revive(target, 100, 100); else - status_revive(target, sc->data[SC_KAIZEL]->val2, 0); - status_change_clear(target,0); + status->revive(target, sc->data[SC_KAIZEL]->val2, 0); + status->change_clear(target,0); clif->skill_nodamage(target,target,ALL_RESURRECTION,1,1); - sc_start(target,status_skill2sc(PR_KYRIE),100,10,time); + sc_start(target,target,status->skill2sc(PR_KYRIE),100,10,time); if( target->type == BL_MOB ) ((TBL_MOB*)target)->state.rebirth = 1; - return hp+sp; - } - if(target->type == BL_PC){ - TBL_PC *sd = BL_CAST(BL_PC,target); - TBL_HOM *hd = sd->hd; - if(hd && hd->sc.data[SC_LIGHT_OF_REGENE]){ - clif->skillcasting(&hd->bl, hd->bl.id, target->id, 0,0, MH_LIGHT_OF_REGENE, skill->get_ele(MH_LIGHT_OF_REGENE, 1), 10); //just to display usage - clif->skill_nodamage(&sd->bl, target, ALL_RESURRECTION, 1, status_revive(&sd->bl,10*hd->sc.data[SC_LIGHT_OF_REGENE]->val1,0)); - status_change_end(&sd->hd->bl,SC_LIGHT_OF_REGENE,INVALID_TIMER); - return hp + sp; - } - } - if (target->type == BL_MOB && sc && sc->data[SC_REBIRTH] && !((TBL_MOB*) target)->state.rebirth) {// Ensure the monster has not already rebirthed before doing so. - status_revive(target, sc->data[SC_REBIRTH]->val2, 0); - status_change_clear(target,0); + return (int)(hp+sp); + } + + if (target->type == BL_MOB && sc && sc->data[SC_REBIRTH] && !((TBL_MOB*) target)->state.rebirth) { + // Ensure the monster has not already rebirthed before doing so. + status->revive(target, sc->data[SC_REBIRTH]->val2, 0); + status->change_clear(target,0); ((TBL_MOB*)target)->state.rebirth = 1; - return hp+sp; + return (int)(hp+sp); } - status_change_clear(target,0); + status->change_clear(target,0); if(flag&4) //Delete from memory. (also invokes map removal code) - unit_free(target,CLR_DEAD); - else - if(flag&2) //remove from map - unit_remove_map(target,CLR_DEAD); - else - { //Some death states that would normally be handled by unit_remove_map - unit_stop_attack(target); - unit_stop_walking(target,1); - unit_skillcastcancel(target,0); + unit->free(target,CLR_DEAD); + else if(flag&2) //remove from map + unit->remove_map(target,CLR_DEAD,ALC_MARK); + else { //Some death states that would normally be handled by unit_remove_map + unit->stop_attack(target); + unit->stop_walking(target,1); + unit->skillcastcancel(target,0); clif->clearunit_area(target,CLR_DEAD); - skill->unit_move(target,iTimer->gettick(),4); + skill->unit_move(target,timer->gettick(),4); skill->cleartimerskill(target); } - return hp+sp; + return (int)(hp+sp); } //Heals a character. If flag&1, this is forced healing (otherwise stuff like Berserk can block it) //If flag&2, when the player is healed, show the HP/SP heal effect. -int status_heal(struct block_list *bl,int hp,int sp, int flag) -{ - struct status_data *status; +int status_heal(struct block_list *bl,int64 in_hp,int64 in_sp, int flag) { + struct status_data *st; struct status_change *sc; + int hp,sp; - status = status_get_status_data(bl); + st = status->get_status_data(bl); - if (status == &dummy_status || !status->hp) + if (st == &status->dummy || !st->hp) return 0; - sc = status_get_sc(bl); + /* here onwards we consider it a 32-type, the client does not support higher and from here onwards the value doesn't get thru percentage modifiers */ + hp = (int)cap_value(in_hp,INT_MIN,INT_MAX); + sp = (int)cap_value(in_sp,INT_MIN,INT_MAX); + + sc = status->get_sc(bl); if (sc && !sc->count) sc = NULL; if (hp < 0) { if (hp == INT_MIN) hp++; //-INT_MIN == INT_MIN in some architectures! - status_damage(NULL, bl, -hp, 0, 0, 1); + status->damage(NULL, bl, -hp, 0, 0, 1); hp = 0; } if(hp) { - if( sc && (sc->data[SC_BERSERK] || sc->data[SC__BLOODYLUST]) ) { + if( sc && sc->data[SC_BERSERK] ) { if( flag&1 ) flag &= ~2; else hp = 0; } - if((unsigned int)hp > status->max_hp - status->hp) - hp = status->max_hp - status->hp; + if((unsigned int)hp > st->max_hp - st->hp) + hp = st->max_hp - st->hp; } if(sp < 0) { if (sp==INT_MIN) sp++; - status_damage(NULL, bl, 0, -sp, 0, 1); + status->damage(NULL, bl, 0, -sp, 0, 1); sp = 0; } if(sp) { - if((unsigned int)sp > status->max_sp - status->sp) - sp = status->max_sp - status->sp; + if((unsigned int)sp > st->max_sp - st->sp) + sp = st->max_sp - st->sp; } if(!sp && !hp) return 0; - status->hp+= hp; - status->sp+= sp; + st->hp+= hp; + st->sp+= sp; - if(hp && sc && - sc->data[SC_AUTOBERSERK] && - sc->data[SC_PROVOKE] && - sc->data[SC_PROVOKE]->val2==1 && - status->hp>=status->max_hp>>2 - ) //End auto berserk. + if( hp && sc + && sc->data[SC_AUTOBERSERK] + && sc->data[SC_PROVOKE] + && sc->data[SC_PROVOKE]->val2==1 + && st->hp>=st->max_hp>>2 + ) //End auto berserk. status_change_end(bl, SC_PROVOKE, INVALID_TIMER); // send hp update to client switch(bl->type) { case BL_PC: pc->heal((TBL_PC*)bl,hp,sp,flag&2?1:0); break; - case BL_MOB: mob_heal((TBL_MOB*)bl,hp); break; + case BL_MOB: mob->heal((TBL_MOB*)bl,hp); break; case BL_HOM: homun->healed((TBL_HOM*)bl); break; - case BL_MER: mercenary_heal((TBL_MER*)bl,hp,sp); break; - case BL_ELEM: elemental_heal((TBL_ELEM*)bl,hp,sp); break; + case BL_MER: mercenary->heal((TBL_MER*)bl,hp,sp); break; + case BL_ELEM: elemental->heal((TBL_ELEM*)bl,hp,sp); break; } - return hp+sp; + return (int)(hp+sp); } //Does percentual non-flinching damage/heal. If mob is killed this way, @@ -1405,146 +1433,174 @@ int status_heal(struct block_list *bl,int hp,int sp, int flag) //If rates are > 0, percent is of current HP/SP //If rates are < 0, percent is of max HP/SP //If !flag, this is heal, otherwise it is damage. -//Furthermore, if flag==2, then the target must not die from the substraction. -int status_percent_change(struct block_list *src,struct block_list *target,signed char hp_rate, signed char sp_rate, int flag) -{ - struct status_data *status; - unsigned int hp =0, sp = 0; - - status = status_get_status_data(target); - - - //It's safe now [MarkZD] - if (hp_rate > 99) - hp = status->hp; - else if (hp_rate > 0) - hp = status->hp>10000? - hp_rate*(status->hp/100): - ((int64)hp_rate*status->hp)/100; - else if (hp_rate < -99) - hp = status->max_hp; - else if (hp_rate < 0) - hp = status->max_hp>10000? - (-hp_rate)*(status->max_hp/100): - ((int64)-hp_rate*status->max_hp)/100; +//Furthermore, if flag==2, then the target must not die from the subtraction. +int status_percent_change(struct block_list *src,struct block_list *target,signed char hp_rate, signed char sp_rate, int flag) { + struct status_data *st; + unsigned int hp = 0, sp = 0; + + st = status->get_status_data(target); + + if (hp_rate > 100) + hp_rate = 100; + else if (hp_rate < -100) + hp_rate = -100; + if (hp_rate > 0) + hp = APPLY_RATE(st->hp, hp_rate); + else + hp = APPLY_RATE(st->max_hp, -hp_rate); if (hp_rate && !hp) hp = 1; - if (flag == 2 && hp >= status->hp) - hp = status->hp-1; //Must not kill target. - - if (sp_rate > 99) - sp = status->sp; - else if (sp_rate > 0) - sp = ((int64)sp_rate*status->sp)/100; - else if (sp_rate < -99) - sp = status->max_sp; - else if (sp_rate < 0) - sp = ((int64)-sp_rate)*status->max_sp/100; + if (flag == 2 && hp >= st->hp) + hp = st->hp-1; //Must not kill target. + + if (sp_rate > 100) + sp_rate = 100; + else if (sp_rate < -100) + sp_rate = -100; + if (sp_rate > 0) + sp = APPLY_RATE(st->sp, sp_rate); + else + sp = APPLY_RATE(st->max_sp, -sp_rate); if (sp_rate && !sp) sp = 1; //Ugly check in case damage dealt is too much for the received args of - //status_heal / status_damage. [Skotlex] + //status->heal / status->damage. [Skotlex] if (hp > INT_MAX) { - hp -= INT_MAX; + hp -= INT_MAX; if (flag) - status_damage(src, target, INT_MAX, 0, 0, (!src||src==target?5:1)); + status->damage(src, target, INT_MAX, 0, 0, (!src||src==target?5:1)); else - status_heal(target, INT_MAX, 0, 0); + status->heal(target, INT_MAX, 0, 0); } - if (sp > INT_MAX) { + if (sp > INT_MAX) { sp -= INT_MAX; if (flag) - status_damage(src, target, 0, INT_MAX, 0, (!src||src==target?5:1)); + status->damage(src, target, 0, INT_MAX, 0, (!src||src==target?5:1)); else - status_heal(target, 0, INT_MAX, 0); + status->heal(target, 0, INT_MAX, 0); } if (flag) - return status_damage(src, target, hp, sp, 0, (!src||src==target?5:1)); - return status_heal(target, hp, sp, 0); + return status->damage(src, target, hp, sp, 0, (!src||src==target?5:1)); + return status->heal(target, hp, sp, 0); } -int status_revive(struct block_list *bl, unsigned char per_hp, unsigned char per_sp) -{ - struct status_data *status; +int status_revive(struct block_list *bl, unsigned char per_hp, unsigned char per_sp) { + struct status_data *st; unsigned int hp, sp; - if (!status_isdead(bl)) return 0; + if (!status->isdead(bl)) return 0; - status = status_get_status_data(bl); - if (status == &dummy_status) + st = status->get_status_data(bl); + if (st == &status->dummy) return 0; //Invalid target. - hp = (int64)status->max_hp * per_hp/100; - sp = (int64)status->max_sp * per_sp/100; + hp = APPLY_RATE(st->max_hp, per_hp); + sp = APPLY_RATE(st->max_sp, per_sp); - if(hp > status->max_hp - status->hp) - hp = status->max_hp - status->hp; + if(hp > st->max_hp - st->hp) + hp = st->max_hp - st->hp; else if (per_hp && !hp) hp = 1; - if(sp > status->max_sp - status->sp) - sp = status->max_sp - status->sp; + if(sp > st->max_sp - st->sp) + sp = st->max_sp - st->sp; else if (per_sp && !sp) sp = 1; - status->hp += hp; - status->sp += sp; + st->hp += hp; + st->sp += sp; if (bl->prev) //Animation only if character is already on a map. clif->resurrection(bl, 1); + switch (bl->type) { case BL_PC: pc->revive((TBL_PC*)bl, hp, sp); break; - case BL_MOB: mob_revive((TBL_MOB*)bl, hp); break; + case BL_MOB: mob->revive((TBL_MOB*)bl, hp); break; + case BL_HOM: homun->revive((TBL_HOM*)bl, hp, sp); break; + } + + return 1; +} + +int status_fixed_revive(struct block_list *bl, unsigned int per_hp, unsigned int per_sp) { + struct status_data *st; + unsigned int hp, sp; + if (!status->isdead(bl)) return 0; + + st = status->get_status_data(bl); + if (st == &status->dummy) + return 0; //Invalid target. + + hp = per_hp; + sp = per_sp; + + if(hp > st->max_hp - st->hp) + hp = st->max_hp - st->hp; + else if (per_hp && !hp) + hp = 1; + + if(sp > st->max_sp - st->sp) + sp = st->max_sp - st->sp; + else if (per_sp && !sp) + sp = 1; + + st->hp += hp; + st->sp += sp; + + if (bl->prev) //Animation only if character is already on a map. + clif->resurrection(bl, 1); + switch (bl->type) { + case BL_PC: pc->revive((TBL_PC*)bl, hp, sp); break; + case BL_MOB: mob->revive((TBL_MOB*)bl, hp); break; case BL_HOM: homun->revive((TBL_HOM*)bl, hp, sp); break; } return 1; } /*========================================== - * Checks whether the src can use the skill on the target, - * taking into account status/option of both source/target. [Skotlex] - * flag: - * 0 - Trying to use skill on target. - * 1 - Cast bar is done. - * 2 - Skill already pulled off, check is due to ground-based skills or splash-damage ones. - * src MAY be null to indicate we shouldn't check it, this is a ground-based skill attack. - * target MAY Be null, in which case the checks are only to see - * whether the source can cast or not the skill on the ground. - *------------------------------------------*/ -int status_check_skilluse(struct block_list *src, struct block_list *target, uint16 skill_id, int flag) -{ - struct status_data *status; +* Checks whether the src can use the skill on the target, +* taking into account status/option of both source/target. [Skotlex] +* flag: +* 0 - Trying to use skill on target. +* 1 - Cast bar is done. +* 2 - Skill already pulled off, check is due to ground-based skills or splash-damage ones. +* src MAY be null to indicate we shouldn't check it, this is a ground-based skill attack. +* target MAY Be null, in which case the checks are only to see +* whether the source can cast or not the skill on the ground. +*------------------------------------------*/ +int status_check_skilluse(struct block_list *src, struct block_list *target, uint16 skill_id, int flag) { + struct status_data *st; struct status_change *sc=NULL, *tsc; int hide_flag; - status = src?status_get_status_data(src):&dummy_status; + st = src ? status->get_status_data(src) : &status->dummy; - if (src && src->type != BL_PC && status_isdead(src)) + if (src && src->type != BL_PC && status->isdead(src)) return 0; if (!skill_id) { //Normal attack checks. - if (!(status->mode&MD_CANATTACK)) + if (!(st->mode&MD_CANATTACK)) return 0; //This mode is only needed for melee attacking. //Dead state is not checked for skills as some skills can be used //on dead characters, said checks are left to skill.c [Skotlex] - if (target && status_isdead(target)) + if (target && status->isdead(target)) return 0; - if( src && (sc = status_get_sc(src)) && sc->data[SC_CRYSTALIZE] && src->type != BL_MOB) + if( src && (sc = status->get_sc(src)) && sc->data[SC_COLD] && src->type != BL_MOB) return 0; } if( skill_id ) { - + if( src && !(src->type == BL_PC && ((TBL_PC*)src)->skillitem)) { // Items that cast skills using 'itemskill' will not be handled by map_zone_db. int i; - - for(i = 0; i < map[src->m].zone->disabled_skills_count; i++) { - if( skill_id == map[src->m].zone->disabled_skills[i]->nameid && (map[src->m].zone->disabled_skills[i]->type&src->type) ) { + + for(i = 0; i < map->list[src->m].zone->disabled_skills_count; i++) { + if( skill_id == map->list[src->m].zone->disabled_skills[i]->nameid && (map->list[src->m].zone->disabled_skills[i]->type&src->type) ) { if( src->type == BL_PC ) clif->msg((TBL_PC*)src, SKILL_CANT_USE_AREA); // This skill cannot be used within this area - else if( src->type == BL_MOB && map[src->m].zone->disabled_skills[i]->subtype != MZS_NONE ) { - if( (status->mode&MD_BOSS) && !(map[src->m].zone->disabled_skills[i]->subtype&MZS_BOSS) ) + else if( src->type == BL_MOB && map->list[src->m].zone->disabled_skills[i]->subtype != MZS_NONE ) { + if( (st->mode&MD_BOSS) && !(map->list[src->m].zone->disabled_skills[i]->subtype&MZS_BOSS) ) break; } return 0; @@ -1556,19 +1612,19 @@ int status_check_skilluse(struct block_list *src, struct block_list *target, uin case PA_PRESSURE: if( flag && target ) { //Gloria Avoids pretty much everything.... - tsc = status_get_sc(target); + tsc = status->get_sc(target); if(tsc && tsc->option&OPTION_HIDE) return 0; } break; case GN_WALLOFTHORN: - if( target && status_isdead(target) ) + if( target && status->isdead(target) ) return 0; break; case AL_TELEPORT: //Should fail when used on top of Land Protector [Skotlex] - if (src && iMap->getcell(src->m, src->x, src->y, CELL_CHKLANDPROTECTOR) - && !(status->mode&MD_BOSS) + if (src && map->getcell(src->m, src->x, src->y, CELL_CHKLANDPROTECTOR) + && !(st->mode&MD_BOSS) && (src->type != BL_PC || ((TBL_PC*)src)->skillitem != skill_id)) return 0; break; @@ -1577,28 +1633,28 @@ int status_check_skilluse(struct block_list *src, struct block_list *target, uin } } - if ( src ) sc = status_get_sc(src); + if ( src ) sc = status->get_sc(src); if( sc && sc->count ) { - if (skill_id != RK_REFRESH && sc->opt1 >0 && !(sc->opt1 == OPT1_CRYSTALIZE && src->type == BL_MOB) && sc->opt1 != OPT1_BURNING && skill_id != SR_GENTLETOUCH_CURE) { //Stuned/Frozen/etc + if (skill_id != RK_REFRESH && sc->opt1 >0 && !(sc->opt1 == OPT1_CRYSTALIZE && src->type == BL_MOB) && sc->opt1 != OPT1_BURNING && skill_id != SR_GENTLETOUCH_CURE) { //Stunned/Frozen/etc if (flag != 1) //Can't cast, casted stuff can't damage. return 0; if (!(skill->get_inf(skill_id)&INF_GROUND_SKILL)) - return 0; //Targetted spells can't come off. + return 0; //Targeted spells can't come off. } if ( (sc->data[SC_TRICKDEAD] && skill_id != NV_TRICKDEAD) - || (sc->data[SC_AUTOCOUNTER] && !flag) + || (sc->data[SC_AUTOCOUNTER] && !flag && skill_id) || (sc->data[SC_GOSPEL] && sc->data[SC_GOSPEL]->val4 == BCT_SELF && skill_id != PA_GOSPEL) || (sc->data[SC_GRAVITATION] && sc->data[SC_GRAVITATION]->val3 == BCT_SELF && flag != 2) - ) + ) return 0; if (sc->data[SC_DC_WINKCHARM] && target && !flag) { //Prevents skill usage - if( unit_bl2ud(src) && (unit_bl2ud(src))->walktimer == INVALID_TIMER ) - unit_walktobl(src, iMap->id2bl(sc->data[SC_DC_WINKCHARM]->val2), 3, 1); + if( unit->bl2ud(src) && (unit->bl2ud(src))->walktimer == INVALID_TIMER ) + unit->walktobl(src, map->id2bl(sc->data[SC_DC_WINKCHARM]->val2), 3, 1); clif->emotion(src, E_LV); return 0; } @@ -1606,11 +1662,11 @@ int status_check_skilluse(struct block_list *src, struct block_list *target, uin if (sc->data[SC_BLADESTOP]) { switch (sc->data[SC_BLADESTOP]->val1) { - case 5: if (skill_id == MO_EXTREMITYFIST) break; - case 4: if (skill_id == MO_CHAINCOMBO) break; - case 3: if (skill_id == MO_INVESTIGATE) break; - case 2: if (skill_id == MO_FINGEROFFENSIVE) break; - default: return 0; + case 5: if (skill_id == MO_EXTREMITYFIST) break; + case 4: if (skill_id == MO_CHAINCOMBO) break; + case 3: if (skill_id == MO_INVESTIGATE) break; + case 2: if (skill_id == MO_FINGEROFFENSIVE) break; + default: return 0; } } @@ -1622,17 +1678,17 @@ int status_check_skilluse(struct block_list *src, struct block_list *target, uin } else if(sc->data[SC_LONGING]) { //Allow everything except dancing/re-dancing. [Skotlex] if (skill_id == BD_ENCORE || skill->get_inf2(skill_id)&(INF2_SONG_DANCE|INF2_ENSEMBLE_SKILL) - ) + ) return 0; } else { switch (skill_id) { - case BD_ADAPTATION: - case CG_LONGINGFREEDOM: - case BA_MUSICALSTRIKE: - case DC_THROWARROW: - break; - default: - return 0; + case BD_ADAPTATION: + case CG_LONGINGFREEDOM: + case BA_MUSICALSTRIKE: + case DC_THROWARROW: + break; + default: + return 0; } } if ((sc->data[SC_DANCING]->val1&0xFFFF) == CG_HERMODE && skill_id == BD_ADAPTATION) @@ -1641,46 +1697,44 @@ int status_check_skilluse(struct block_list *src, struct block_list *target, uin if (skill_id && //Do not block item-casted skills. (src->type != BL_PC || ((TBL_PC*)src)->skillitem != skill_id) - ) { //Skills blocked through status changes... - if (!flag && ( //Blocked only from using the skill (stuff like autospell may still go through - sc->data[SC_SILENCE] || - sc->data[SC_STEELBODY] || - sc->data[SC_BERSERK] || - sc->data[SC__BLOODYLUST] || - sc->data[SC_OBLIVIONCURSE] || - sc->data[SC_WHITEIMPRISON] || - sc->data[SC__INVISIBILITY] || - (sc->data[SC_CRYSTALIZE] && src->type != BL_MOB) || - sc->data[SC__IGNORANCE] || - sc->data[SC_DEEP_SLEEP] || - sc->data[SC_SATURDAY_NIGHT_FEVER] || - sc->data[SC_CURSEDCIRCLE_TARGET] || - (sc->data[SC_MARIONETTE_MASTER] && skill_id != CG_MARIONETTE) || //Only skill you can use is marionette again to cancel it - (sc->data[SC_MARIONETTE] && skill_id == CG_MARIONETTE) || //Cannot use marionette if you are being buffed by another - (sc->data[SC_STASIS] && skill->block_check(src, SC_STASIS, skill_id)) || - (sc->data[SC_KG_KAGEHUMI] && skill->block_check(src, SC_KG_KAGEHUMI, skill_id)) - )) - return 0; + ) { //Skills blocked through status changes... + if (!flag && ( //Blocked only from using the skill (stuff like autospell may still go through + sc->data[SC_SILENCE] || + sc->data[SC_STEELBODY] || + sc->data[SC_BERSERK] || + sc->data[SC_OBLIVIONCURSE] || + sc->data[SC_WHITEIMPRISON] || + sc->data[SC__INVISIBILITY] || + (sc->data[SC_COLD] && src->type != BL_MOB) || + sc->data[SC__IGNORANCE] || + sc->data[SC_DEEP_SLEEP] || + sc->data[SC_SATURDAY_NIGHT_FEVER] || + sc->data[SC_CURSEDCIRCLE_TARGET] || + (sc->data[SC_MARIONETTE_MASTER] && skill_id != CG_MARIONETTE) || //Only skill you can use is marionette again to cancel it + (sc->data[SC_MARIONETTE] && skill_id == CG_MARIONETTE) || //Cannot use marionette if you are being buffed by another + (sc->data[SC_STASIS] && skill->block_check(src, SC_STASIS, skill_id)) || + (sc->data[SC_KG_KAGEHUMI] && skill->block_check(src, SC_KG_KAGEHUMI, skill_id)) + )) + return 0; - //Skill blocking. - if ( - (sc->data[SC_VOLCANO] && skill_id == WZ_ICEWALL) || - (sc->data[SC_ROKISWEIL] && skill_id != BD_ADAPTATION) || - (sc->data[SC_HERMODE] && skill->get_inf(skill_id) & INF_SUPPORT_SKILL) || - (sc->data[SC_NOCHAT] && sc->data[SC_NOCHAT]->val1&MANNER_NOSKILL) - ) - return 0; + //Skill blocking. + if ( + (sc->data[SC_VOLCANO] && skill_id == WZ_ICEWALL) || + (sc->data[SC_ROKISWEIL] && skill_id != BD_ADAPTATION) || + (sc->data[SC_HERMODE] && skill->get_inf(skill_id) & INF_SUPPORT_SKILL) || + (sc->data[SC_NOCHAT] && sc->data[SC_NOCHAT]->val1&MANNER_NOSKILL) + ) + return 0; - if( sc->data[SC__MANHOLE] || ((tsc = status_get_sc(target)) && tsc->data[SC__MANHOLE]) ) { - switch(skill_id) {//##TODO## make this a flag in skill_db? - // Skills that can be used even under Man Hole effects. + if( sc->data[SC__MANHOLE] || ((tsc = status->get_sc(target)) && tsc->data[SC__MANHOLE]) ) { + switch(skill_id) {//##TODO## make this a flag in skill_db? + // Skills that can be used even under Man Hole effects. case SC_SHADOWFORM: - case SC_STRIPACCESSARY: break; default: return 0; + } } - } } } @@ -1702,8 +1756,13 @@ int status_check_skilluse(struct block_list *src, struct block_list *target, uin return 0; } } - if (sc->option&OPTION_CHASEWALK && skill_id != ST_CHASEWALK) - return 0; + if ( sc->option&OPTION_CHASEWALK ) { + if ( sc->data[SC__INVISIBILITY] ) { + if ( skill_id != 0 && skill_id != SC_INVISIBILITY ) + return 0; + } else if ( skill_id != ST_CHASEWALK ) + return 0; + } if( sc->data[SC_ALL_RIDING] ) return 0;//New mounts can't attack nor use skills in the client; this check makes it cheat-safe [Ind] } @@ -1711,7 +1770,7 @@ int status_check_skilluse(struct block_list *src, struct block_list *target, uin if (target == NULL || target == src) //No further checking needed. return 1; - tsc = status_get_sc(target); + tsc = status->get_sc(target); if(tsc && tsc->count) { /* attacks in invincible are capped to 1 damage and handled in batte.c; allow spell break and eske for sealed shrine GDB when in INVINCIBLE state. */ @@ -1724,35 +1783,46 @@ int status_check_skilluse(struct block_list *src, struct block_list *target, uin return 0; if(skill_id == PR_LEXAETERNA && (tsc->data[SC_FREEZE] || (tsc->data[SC_STONE] && tsc->opt1 == OPT1_STONE))) return 0; + if( ( tsc->data[SC_STEALTHFIELD] || tsc->data[SC_CAMOUFLAGE] ) && !(st->mode&(MD_BOSS|MD_DETECTOR)) && flag == 4 ) + return 0; } - - //If targetting, cloak+hide protect you, otherwise only hiding does. + //If targeting, cloak+hide protect you, otherwise only hiding does. hide_flag = flag?OPTION_HIDE:(OPTION_HIDE|OPTION_CLOAK|OPTION_CHASEWALK); - //You cannot hide from ground skills. + //You cannot hide from ground skills. if( skill->get_ele(skill_id,1) == ELE_EARTH ) //TODO: Need Skill Lv here :/ hide_flag &= ~OPTION_HIDE; + else { + switch ( skill_id ) { + case MO_ABSORBSPIRITS: // it works when already casted and target suddenly hides. + case SA_DISPELL: + hide_flag &= ~OPTION_HIDE; + break; + } + } switch( target->type ) { case BL_PC: { struct map_session_data *sd = (TBL_PC*) target; - bool is_boss = (status->mode&MD_BOSS); - bool is_detect = ((status->mode&MD_DETECTOR)?true:false);//god-knows-why gcc doesn't shut up until this happens + bool is_boss = (st->mode&MD_BOSS); + bool is_detect = ((st->mode&MD_DETECTOR)?true:false);//god-knows-why gcc doesn't shut up until this happens if (pc_isinvisible(sd)) return 0; - if (tsc->option&hide_flag && !is_boss && - ((sd->special_state.perfect_hiding || !is_detect) || - (tsc->data[SC_CLOAKINGEXCEED] && is_detect))) - return 0; - if( tsc->data[SC_CAMOUFLAGE] && !(is_boss || is_detect) && !skill_id ) - return 0; - if( tsc->data[SC_STEALTHFIELD] && !is_boss ) - return 0; + if( tsc ) { + if (tsc->option&hide_flag && !is_boss && + ((sd->special_state.perfect_hiding || !is_detect) || + (tsc->data[SC_CLOAKINGEXCEED] && is_detect))) + return 0; + if( tsc->data[SC_CAMOUFLAGE] && !(is_boss || is_detect) && (!skill_id || (flag == 0 && src && src->type != BL_PC)) ) + return 0; + if( tsc->data[SC_STEALTHFIELD] && !is_boss ) + return 0; + } } break; - case BL_ITEM: //Allow targetting of items to pick'em up (or in the case of mobs, to loot them). + case BL_ITEM: //Allow targeting of items to pick'em up (or in the case of mobs, to loot them). //TODO: Would be nice if this could be used to judge whether the player can or not pick up the item it targets. [Skotlex] - if (status->mode&MD_LOOTER) + if (st->mode&MD_LOOTER) return 1; return 0; case BL_HOM: @@ -1767,64 +1837,66 @@ int status_check_skilluse(struct block_list *src, struct block_list *target, uin default: //Check for chase-walk/hiding/cloaking opponents. if( tsc ) { - if( tsc->option&hide_flag && !(status->mode&(MD_BOSS|MD_DETECTOR))) + if( tsc->option&hide_flag && !(st->mode&(MD_BOSS|MD_DETECTOR))) return 0; - if( tsc->data[SC_STEALTHFIELD] && !(status->mode&MD_BOSS) ) + if( tsc->data[SC_STEALTHFIELD] && !(st->mode&MD_BOSS) ) return 0; } } + return 1; } //Checks whether the source can see and chase target. -int status_check_visibility(struct block_list *src, struct block_list *target) -{ +int status_check_visibility(struct block_list *src, struct block_list *target) { int view_range; - struct status_data* status = status_get_status_data(src); - struct status_change* tsc = status_get_sc(target); + struct status_change *tsc = NULL; + switch (src->type) { - case BL_MOB: - view_range = ((TBL_MOB*)src)->min_chase; - break; - case BL_PET: - view_range = ((TBL_PET*)src)->db->range2; - break; - default: - view_range = AREA_SIZE; + case BL_MOB: + view_range = ((TBL_MOB*)src)->min_chase; + break; + case BL_PET: + view_range = ((TBL_PET*)src)->db->range2; + break; + default: + view_range = AREA_SIZE; } if (src->m != target->m || !check_distance_bl(src, target, view_range)) return 0; - if( tsc && tsc->data[SC_STEALTHFIELD] ) - return 0; + if( src->type == BL_NPC ) /* NPCs don't care for the rest */ + return 1; + + if( ( tsc = status->get_sc(target) ) ) { + struct status_data *st = status->get_status_data(src); - switch (target->type) - { //Check for chase-walk/hiding/cloaking opponents. - case BL_PC: - if ( tsc->data[SC_CLOAKINGEXCEED] && !(status->mode&MD_BOSS) ) - return 0; - if( (tsc->option&(OPTION_HIDE|OPTION_CLOAK|OPTION_CHASEWALK) || tsc->data[SC__INVISIBILITY] || tsc->data[SC_CAMOUFLAGE]) && !(status->mode&MD_BOSS) && - ( ((TBL_PC*)target)->special_state.perfect_hiding || !(status->mode&MD_DETECTOR) ) ) - return 0; - break; - default: - if( tsc && (tsc->option&(OPTION_HIDE|OPTION_CLOAK|OPTION_CHASEWALK) || tsc->data[SC__INVISIBILITY] || tsc->data[SC_CAMOUFLAGE]) && !(status->mode&(MD_BOSS|MD_DETECTOR)) ) - return 0; + switch (target->type) { //Check for chase-walk/hiding/cloaking opponents. + case BL_PC: + if ( tsc->data[SC_CLOAKINGEXCEED] && !(st->mode&MD_BOSS) ) + return 0; + if( (tsc->option&(OPTION_HIDE|OPTION_CLOAK|OPTION_CHASEWALK) || tsc->data[SC_STEALTHFIELD] || tsc->data[SC__INVISIBILITY] || tsc->data[SC_CAMOUFLAGE]) && !(st->mode&MD_BOSS) && + ( ((TBL_PC*)target)->special_state.perfect_hiding || !(st->mode&MD_DETECTOR) ) ) + return 0; + break; + default: + if( (tsc->option&(OPTION_HIDE|OPTION_CLOAK|OPTION_CHASEWALK) || tsc->data[SC_CAMOUFLAGE]) && !(st->mode&(MD_BOSS|MD_DETECTOR)) ) + return 0; + } } return 1; } // Basic ASPD value -int status_base_amotion_pc(struct map_session_data* sd, struct status_data* status) -{ +int status_base_amotion_pc(struct map_session_data *sd, struct status_data *st) { int amotion; #ifdef RENEWAL_ASPD short mod = -1; - switch( sd->weapontype2 ){ // adjustment for dual weilding + switch( sd->weapontype2 ){ // adjustment for dual wielding case W_DAGGER: mod = 0; break; // 0, 1, 1 case W_1HSWORD: case W_1HAXE: mod = 1; @@ -1833,33 +1905,37 @@ int status_base_amotion_pc(struct map_session_data* sd, struct status_data* stat } amotion = ( sd->status.weapon < MAX_WEAPON_TYPE && mod < 0 ) - ? (aspd_base[pc->class2idx(sd->status.class_)][sd->status.weapon]) // single weapon - : ((aspd_base[pc->class2idx(sd->status.class_)][sd->weapontype2] // dual-wield - + aspd_base[pc->class2idx(sd->status.class_)][sd->weapontype2]) * 6 / 10 + 10 * mod - - aspd_base[pc->class2idx(sd->status.class_)][sd->weapontype2] - + aspd_base[pc->class2idx(sd->status.class_)][sd->weapontype1]); + ? (status->aspd_base[pc->class2idx(sd->status.class_)][sd->status.weapon]) // single weapon + : ((status->aspd_base[pc->class2idx(sd->status.class_)][sd->weapontype2] // dual-wield + + status->aspd_base[pc->class2idx(sd->status.class_)][sd->weapontype2]) * 6 / 10 + 10 * mod + - status->aspd_base[pc->class2idx(sd->status.class_)][sd->weapontype2] + + status->aspd_base[pc->class2idx(sd->status.class_)][sd->weapontype1]); if ( sd->status.shield ) - amotion += ( 2000 - aspd_base[pc->class2idx(sd->status.class_)][W_FIST] ) + - ( aspd_base[pc->class2idx(sd->status.class_)][MAX_WEAPON_TYPE] - 2000 ); + amotion += ( 2000 - status->aspd_base[pc->class2idx(sd->status.class_)][W_FIST] ) + + ( status->aspd_base[pc->class2idx(sd->status.class_)][MAX_WEAPON_TYPE] - 2000 ); #else // base weapon delay amotion = (sd->status.weapon < MAX_WEAPON_TYPE) - ? (aspd_base[pc->class2idx(sd->status.class_)][sd->status.weapon]) // single weapon - : (aspd_base[pc->class2idx(sd->status.class_)][sd->weapontype1] + aspd_base[pc->class2idx(sd->status.class_)][sd->weapontype2])*7/10; // dual-wield + ? (status->aspd_base[pc->class2idx(sd->status.class_)][sd->status.weapon]) // single weapon + : (status->aspd_base[pc->class2idx(sd->status.class_)][sd->weapontype1] + status->aspd_base[pc->class2idx(sd->status.class_)][sd->weapontype2])*7/10; // dual-wield // percentual delay reduction from stats - amotion -= amotion * (4*status->agi + status->dex)/1000; + amotion -= amotion * (4*st->agi + st->dex)/1000; #endif + // raw delay adjustment from bAspd bonus amotion += sd->bonus.aspd_add; - return amotion; + /* angra manyu disregards aspd_base and similar */ + if( sd->equip_index[EQI_HAND_R] >= 0 && sd->status.inventory[sd->equip_index[EQI_HAND_R]].nameid == ITEMID_ANGRA_MANYU ) + return 0; + + return amotion; } -static unsigned short status_base_atk(const struct block_list *bl, const struct status_data *status) -{ +unsigned short status_base_atk(const struct block_list *bl, const struct status_data *st) { int flag = 0, str, dex, #ifdef RENEWAL rstr, @@ -1871,7 +1947,7 @@ static unsigned short status_base_atk(const struct block_list *bl, const struct return 0; if (bl->type == BL_PC) - switch(((TBL_PC*)bl)->status.weapon){ + switch(((TBL_PC*)bl)->status.weapon){ case W_BOW: case W_MUSICAL: case W_WHIP: @@ -1886,14 +1962,14 @@ static unsigned short status_base_atk(const struct block_list *bl, const struct #ifdef RENEWAL rstr = #endif - str = status->dex; - dex = status->str; + str = st->dex; + dex = st->str; } else { #ifdef RENEWAL rstr = #endif - str = status->str; - dex = status->dex; + str = st->str; + dex = st->dex; } //Normally only players have base-atk, but homunc have a different batk // equation, hinting that perhaps non-players should use this for batk. @@ -1902,99 +1978,104 @@ static unsigned short status_base_atk(const struct block_list *bl, const struct str += dstr*dstr; if (bl->type == BL_PC) #ifdef RENEWAL - str = (int)(rstr + (float)dex/5 + (float)status->luk/3 + (float)((TBL_PC*)bl)->status.base_level/4); + str = (int)(rstr + (float)dex/5 + (float)st->luk/3 + (float)((TBL_PC*)bl)->status.base_level/4); else if(bl->type == BL_MOB) str = rstr + ((TBL_MOB*)bl)->level; #else - str+= dex/5 + status->luk/5; + str+= dex/5 + st->luk/5; #endif return cap_value(str, 0, USHRT_MAX); } -static inline unsigned short status_base_matk_min(const struct status_data* status){ return status->int_+(status->int_/7)*(status->int_/7); } -static inline unsigned short status_base_matk_max(const struct status_data* status){ return status->int_+(status->int_/5)*(status->int_/5); } +#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(const struct status_data *st, int level) { #ifdef RENEWAL -unsigned short status_base_matk(const struct status_data* status, int level){ return status->int_+(status->int_/2)+(status->dex/5)+(status->luk/3)+(level/4); } + return st->int_+(st->int_/2)+(st->dex/5)+(st->luk/3)+(level/4); +#else + return 0; #endif +} //Fills in the misc data that can be calculated from the other status info (except for level) -void status_calc_misc(struct block_list *bl, struct status_data *status, int level) -{ +void status_calc_misc(struct block_list *bl, struct status_data *st, int level) { //Non players get the value set, players need to stack with previous bonuses. if( bl->type != BL_PC ) - status->batk = - status->hit = status->flee = - status->def2 = status->mdef2 = - status->cri = status->flee2 = 0; + st->batk = + st->hit = st->flee = + st->def2 = st->mdef2 = + st->cri = st->flee2 = 0; #ifdef RENEWAL // renewal formulas - status->matk_min = status->matk_max = bl->type == BL_PC ? status_base_matk(status, level) : level + status->int_; - status->hit += level + status->dex + (bl->type == BL_PC ? status->luk/3 + 175 : 150); //base level + ( every 1 dex = +1 hit ) + (every 3 luk = +1 hit) + 175 - status->flee += level + status->agi + (bl->type == BL_PC ? status->luk/5 : 0) + 100; //base level + ( every 1 agi = +1 flee ) + (every 5 luk = +1 flee) + 100 - status->def2 += (int)(((float)level + status->vit)/2 + ( bl->type == BL_PC ? ((float)status->agi/5) : 0 )); //base level + (every 2 vit = +1 def) + (every 5 agi = +1 def) - status->mdef2 += (int)( bl->type == BL_PC ?(status->int_ + ((float)level/4) + ((float)(status->dex+status->vit)/5)):((float)(status->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 - status->matk_min = status_base_matk_min(status); - status->matk_max = status_base_matk_max(status); - status->hit += level + status->dex; - status->flee += level + status->agi; - status->def2 += status->vit; - status->mdef2 += status->int_ + (status->vit>>1); -#endif + st->matk_min = st->matk_max = bl->type == BL_PC ? status->base_matk(st, level) : level + st->int_; + st->hit += level + st->dex + (bl->type == BL_PC ? st->luk/3 + 175 : 150); //base level + ( every 1 dex = +1 hit ) + (every 3 luk = +1 hit) + 175 + st->flee += level + st->agi + (bl->type == BL_PC ? st->luk/5 : 0) + 100; //base level + ( every 1 agi = +1 flee ) + (every 5 luk = +1 flee) + 100 + st->def2 += (int)(((float)level + st->vit)/2 + ( bl->type == BL_PC ? ((float)st->agi/5) : 0 )); //base level + (every 2 vit = +1 def) + (every 5 agi = +1 def) + 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->hit += level + st->dex; + st->flee += level + st->agi; + st->def2 += st->vit; + st->mdef2 += st->int_ + (st->vit>>1); +#endif // RENEWAL if( bl->type&battle_config.enable_critical ) - status->cri += 10 + (status->luk*10/3); //(every 1 luk = +0.3 critical) + st->cri += 10 + (st->luk*10/3); //(every 1 luk = +0.3 critical) else - status->cri = 0; + st->cri = 0; if (bl->type&battle_config.enable_perfect_flee) - status->flee2 += status->luk + 10; //(every 10 luk = +1 perfect flee) + st->flee2 += st->luk + 10; //(every 10 luk = +1 perfect flee) else - status->flee2 = 0; + st->flee2 = 0; - if (status->batk) { - int temp = status->batk + status_base_atk(bl, status); - status->batk = cap_value(temp, 0, USHRT_MAX); + if (st->batk) { + int temp = st->batk + status->base_atk(bl, st); + st->batk = cap_value(temp, 0, USHRT_MAX); } else - status->batk = status_base_atk(bl, status); - if (status->cri) - switch (bl->type) { - case BL_MOB: - if(battle_config.mob_critical_rate != 100) - status->cri = status->cri*battle_config.mob_critical_rate/100; - if(!status->cri && battle_config.mob_critical_rate) - status->cri = 10; - break; - case BL_PC: - //Players don't have a critical adjustment setting as of yet. - break; - case BL_MER: + st->batk = status->base_atk(bl, st); + if (st->cri) + switch (bl->type) { + case BL_MOB: + if(battle_config.mob_critical_rate != 100) + st->cri = st->cri*battle_config.mob_critical_rate/100; + if(!st->cri && battle_config.mob_critical_rate) + st->cri = 10; + break; + case BL_PC: + //Players don't have a critical adjustment setting as of yet. + break; + case BL_MER: #ifdef RENEWAL - status->matk_min = status->matk_max = status_base_matk_max(status); - status->def2 = status->vit + level / 10 + status->vit / 5; - status->mdef2 = level / 10 + status->int_ / 5; + 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 - break; - default: - if(battle_config.critical_rate != 100) - status->cri = status->cri*battle_config.critical_rate/100; - if (!status->cri && battle_config.critical_rate) - status->cri = 10; + break; + default: + if(battle_config.critical_rate != 100) + st->cri = st->cri*battle_config.critical_rate/100; + if (!st->cri && battle_config.critical_rate) + st->cri = 10; } if(bl->type&BL_REGEN) - status_calc_regen(bl, status, status_get_regen_data(bl)); + status->calc_regen(bl, st, status->get_regen_data(bl)); } //Skotlex: Calculates the initial status for the given mob //first will only be false when the mob leveled up or got a GuardUp level. -int status_calc_mob_(struct mob_data* md, bool first) -{ - struct status_data *status; +int status_calc_mob_(struct mob_data* md, enum e_status_calc_opt opt) { + struct status_data *mstatus; struct block_list *mbl = NULL; int flag=0; + int guardup_lv = 0; - if(first) - { //Set basic level on respawn. + if(opt&SCO_FIRST) { //Set basic level on respawn. if (md->level > 0 && md->level <= MAX_LEVEL && md->level != md->db->lv) ; else @@ -2008,9 +2089,8 @@ int status_calc_mob_(struct mob_data* md, bool first) if (md->special_state.size) flag|=2; - if (md->guardian_data && md->guardian_data->guardup_lv) - flag|=4; - if (md->class_ == MOBID_EMPERIUM) + if( md->guardian_data && md->guardian_data->g + && (guardup_lv = guild->checkskill(md->guardian_data->g,GD_GUARDUP)) ) flag|=4; if (battle_config.slaves_inherit_speed && md->master_id) @@ -2025,142 +2105,145 @@ int status_calc_mob_(struct mob_data* md, bool first) aFree(md->base_status); md->base_status = NULL; } - if(first) + if(opt&SCO_FIRST) memcpy(&md->status, &md->db->status, sizeof(struct status_data)); return 0; } if (!md->base_status) md->base_status = (struct status_data*)aCalloc(1, sizeof(struct status_data)); - status = md->base_status; - memcpy(status, &md->db->status, sizeof(struct status_data)); + mstatus = md->base_status; + memcpy(mstatus, &md->db->status, sizeof(struct status_data)); if (flag&(8|16)) - mbl = iMap->id2bl(md->master_id); + mbl = map->id2bl(md->master_id); if (flag&8 && mbl) { - struct status_data *mstatus = status_get_base_status(mbl); - if (mstatus && - battle_config.slaves_inherit_speed&(mstatus->mode&MD_CANMOVE?1:2)) - status->speed = mstatus->speed; - if( status->speed < 2 ) /* minimum for the unit to function properly */ - status->speed = 2; + struct status_data *masterstatus = status->get_base_status(mbl); + if ( masterstatus ) { + if (battle_config.slaves_inherit_speed&(masterstatus->mode&MD_CANMOVE ? 1 : 2)) + mstatus->speed = masterstatus->speed; + if (mstatus->speed < 2) /* minimum for the unit to function properly */ + mstatus->speed = 2; + } } - if (flag&16 && mbl) - { //Max HP setting from Summon Flora/marine Sphere - struct unit_data *ud = unit_bl2ud(mbl); + if (flag&16 && mbl) { + //Max HP setting from Summon Flora/marine Sphere + struct unit_data *ud = unit->bl2ud(mbl); //Remove special AI when this is used by regular mobs. if (mbl->type == BL_MOB && !((TBL_MOB*)mbl)->special_state.ai) md->special_state.ai = 0; - if (ud) - { // different levels of HP according to skill level + if (ud) { + // different levels of HP according to skill level if (ud->skill_id == AM_SPHEREMINE) { - status->max_hp = 2000 + 400*ud->skill_lv; - } else if(ud->skill_id == KO_ZANZOU){ - status->max_hp = 3000 + 3000 * ud->skill_lv + status_get_max_sp(battle->get_master(mbl)); + mstatus->max_hp = 2000 + 400*ud->skill_lv; + } else if(ud->skill_id == KO_ZANZOU) { + mstatus->max_hp = 3000 + 3000 * ud->skill_lv + status_get_max_sp(battle->get_master(mbl)); } else { //AM_CANNIBALIZE - status->max_hp = 1500 + 200*ud->skill_lv + 10*status_get_lv(mbl); - status->mode|= MD_CANATTACK|MD_AGGRESSIVE; + mstatus->max_hp = 1500 + 200*ud->skill_lv + 10*status->get_lv(mbl); + mstatus->mode|= MD_CANATTACK|MD_AGGRESSIVE; } - status->hp = status->max_hp; + mstatus->hp = mstatus->max_hp; + if( ud->skill_id == NC_SILVERSNIPER ) + mstatus->rhw.atk = mstatus->rhw.atk2 = 200 * ud->skill_lv; } } - if (flag&1) - { // increase from mobs leveling up [Valaris] + if (flag&1) { + // increase from mobs leveling up [Valaris] int diff = md->level - md->db->lv; - status->str+= diff; - status->agi+= diff; - status->vit+= diff; - status->int_+= diff; - status->dex+= diff; - status->luk+= diff; - status->max_hp += diff*status->vit; - status->max_sp += diff*status->int_; - status->hp = status->max_hp; - status->sp = status->max_sp; - status->speed -= cap_value(diff, 0, status->speed - 10); - } - - - if (flag&2 && battle_config.mob_size_influence) - { // change for sized monsters [Valaris] - if (md->special_state.size==SZ_MEDIUM) { - status->max_hp>>=1; - status->max_sp>>=1; - if (!status->max_hp) status->max_hp = 1; - if (!status->max_sp) status->max_sp = 1; - status->hp=status->max_hp; - status->sp=status->max_sp; - status->str>>=1; - status->agi>>=1; - status->vit>>=1; - status->int_>>=1; - status->dex>>=1; - status->luk>>=1; - if (!status->str) status->str = 1; - if (!status->agi) status->agi = 1; - if (!status->vit) status->vit = 1; - if (!status->int_) status->int_ = 1; - if (!status->dex) status->dex = 1; - if (!status->luk) status->luk = 1; + mstatus->str+= diff; + mstatus->agi+= diff; + mstatus->vit+= diff; + mstatus->int_+= diff; + mstatus->dex+= diff; + mstatus->luk+= diff; + mstatus->max_hp += diff*mstatus->vit; + mstatus->max_sp += diff*mstatus->int_; + mstatus->hp = mstatus->max_hp; + mstatus->sp = mstatus->max_sp; + mstatus->speed -= cap_value(diff, 0, mstatus->speed - 10); + } + + + if (flag&2 && battle_config.mob_size_influence) { + // change for sized monsters [Valaris] + if (md->special_state.size==SZ_SMALL) { + mstatus->max_hp>>=1; + mstatus->max_sp>>=1; + if (!mstatus->max_hp) mstatus->max_hp = 1; + if (!mstatus->max_sp) mstatus->max_sp = 1; + mstatus->hp=mstatus->max_hp; + mstatus->sp=mstatus->max_sp; + mstatus->str>>=1; + mstatus->agi>>=1; + mstatus->vit>>=1; + mstatus->int_>>=1; + mstatus->dex>>=1; + mstatus->luk>>=1; + if (!mstatus->str) mstatus->str = 1; + if (!mstatus->agi) mstatus->agi = 1; + if (!mstatus->vit) mstatus->vit = 1; + if (!mstatus->int_) mstatus->int_ = 1; + if (!mstatus->dex) mstatus->dex = 1; + if (!mstatus->luk) mstatus->luk = 1; } else if (md->special_state.size==SZ_BIG) { - status->max_hp<<=1; - status->max_sp<<=1; - status->hp=status->max_hp; - status->sp=status->max_sp; - status->str<<=1; - status->agi<<=1; - status->vit<<=1; - status->int_<<=1; - status->dex<<=1; - status->luk<<=1; + mstatus->max_hp<<=1; + mstatus->max_sp<<=1; + mstatus->hp=mstatus->max_hp; + mstatus->sp=mstatus->max_sp; + mstatus->str<<=1; + mstatus->agi<<=1; + mstatus->vit<<=1; + mstatus->int_<<=1; + mstatus->dex<<=1; + mstatus->luk<<=1; } } - status_calc_misc(&md->bl, status, md->level); + status->calc_misc(&md->bl, mstatus, md->level); if(flag&4) { // Strengthen Guardians - custom value +10% / lv struct guild_castle *gc; - gc=guild->mapname2gc(map[md->bl.m].name); + gc=guild->mapname2gc(map->list[md->bl.m].name); if (!gc) - ShowError("status_calc_mob: No castle set at map %s\n", map[md->bl.m].name); + ShowError("status_calc_mob: No castle set at map %s\n", map->list[md->bl.m].name); else - if(gc->castle_id < 24 || md->class_ == MOBID_EMPERIUM) { + if(gc->castle_id < 24 || md->class_ == MOBID_EMPERIUM) { #ifdef RENEWAL - status->max_hp += 50 * gc->defense; - status->max_sp += 70 * gc->defense; + mstatus->max_hp += 50 * gc->defense; + mstatus->max_sp += 70 * gc->defense; #else - status->max_hp += 1000 * gc->defense; - status->max_sp += 200 * gc->defense; + mstatus->max_hp += 1000 * gc->defense; + mstatus->max_sp += 200 * gc->defense; #endif - status->hp = status->max_hp; - status->sp = status->max_sp; - status->def += (gc->defense+2)/3; - status->mdef += (gc->defense+2)/3; - } - if(md->class_ != MOBID_EMPERIUM) { - status->batk += status->batk * 10*md->guardian_data->guardup_lv/100; - status->rhw.atk += status->rhw.atk * 10*md->guardian_data->guardup_lv/100; - status->rhw.atk2 += status->rhw.atk2 * 10*md->guardian_data->guardup_lv/100; - status->aspd_rate -= 100*md->guardian_data->guardup_lv; - } + mstatus->hp = mstatus->max_hp; + mstatus->sp = mstatus->max_sp; + mstatus->def += (gc->defense+2)/3; + mstatus->mdef += (gc->defense+2)/3; + } + if(md->class_ != MOBID_EMPERIUM) { + mstatus->batk += mstatus->batk * 10*guardup_lv/100; + mstatus->rhw.atk += mstatus->rhw.atk * 10*guardup_lv/100; + mstatus->rhw.atk2 += mstatus->rhw.atk2 * 10*guardup_lv/100; + mstatus->aspd_rate -= 100*guardup_lv; + } } - if( first ) //Initial battle status - memcpy(&md->status, status, sizeof(struct status_data)); + if( opt&SCO_FIRST ) //Initial battle status + memcpy(&md->status, mstatus, sizeof(struct status_data)); return 1; } //Skotlex: Calculates the stats of the given pet. -int status_calc_pet_(struct pet_data *pd, bool first) +int status_calc_pet_(struct pet_data *pd, enum e_status_calc_opt opt) { nullpo_ret(pd); - if (first) { + if (opt&SCO_FIRST) { memcpy(&pd->status, &pd->db->status, sizeof(struct status_data)); pd->status.mode = MD_CANMOVE; // pets discard all modes, except walking pd->status.speed = pd->petDB->speed; @@ -2171,45 +2254,43 @@ int status_calc_pet_(struct pet_data *pd, bool first) } } - if (battle_config.pet_lv_rate && pd->msd) - { + if (battle_config.pet_lv_rate && pd->msd) { struct map_session_data *sd = pd->msd; int lv; lv =sd->status.base_level*battle_config.pet_lv_rate/100; if (lv < 0) lv = 1; - if (lv != pd->pet.level || first) - { - struct status_data *bstat = &pd->db->status, *status = &pd->status; + if (lv != pd->pet.level || opt&SCO_FIRST) { + struct status_data *bstat = &pd->db->status, *pstatus = &pd->status; pd->pet.level = lv; - if (!first) //Lv Up animation + if (! (opt&SCO_FIRST) ) //Lv Up animation clif->misceffect(&pd->bl, 0); - status->rhw.atk = (bstat->rhw.atk*lv)/pd->db->lv; - status->rhw.atk2 = (bstat->rhw.atk2*lv)/pd->db->lv; - status->str = (bstat->str*lv)/pd->db->lv; - status->agi = (bstat->agi*lv)/pd->db->lv; - status->vit = (bstat->vit*lv)/pd->db->lv; - status->int_ = (bstat->int_*lv)/pd->db->lv; - status->dex = (bstat->dex*lv)/pd->db->lv; - status->luk = (bstat->luk*lv)/pd->db->lv; - - status->rhw.atk = cap_value(status->rhw.atk, 1, battle_config.pet_max_atk1); - status->rhw.atk2 = cap_value(status->rhw.atk2, 2, battle_config.pet_max_atk2); - status->str = cap_value(status->str,1,battle_config.pet_max_stats); - status->agi = cap_value(status->agi,1,battle_config.pet_max_stats); - status->vit = cap_value(status->vit,1,battle_config.pet_max_stats); - status->int_= cap_value(status->int_,1,battle_config.pet_max_stats); - status->dex = cap_value(status->dex,1,battle_config.pet_max_stats); - status->luk = cap_value(status->luk,1,battle_config.pet_max_stats); - - status_calc_misc(&pd->bl, &pd->status, lv); - - if (!first) //Not done the first time because the pet is not visible yet + pstatus->rhw.atk = (bstat->rhw.atk*lv)/pd->db->lv; + pstatus->rhw.atk2 = (bstat->rhw.atk2*lv)/pd->db->lv; + pstatus->str = (bstat->str*lv)/pd->db->lv; + pstatus->agi = (bstat->agi*lv)/pd->db->lv; + pstatus->vit = (bstat->vit*lv)/pd->db->lv; + pstatus->int_ = (bstat->int_*lv)/pd->db->lv; + pstatus->dex = (bstat->dex*lv)/pd->db->lv; + pstatus->luk = (bstat->luk*lv)/pd->db->lv; + + pstatus->rhw.atk = cap_value(pstatus->rhw.atk, 1, battle_config.pet_max_atk1); + pstatus->rhw.atk2 = cap_value(pstatus->rhw.atk2, 2, battle_config.pet_max_atk2); + pstatus->str = cap_value(pstatus->str,1,battle_config.pet_max_stats); + pstatus->agi = cap_value(pstatus->agi,1,battle_config.pet_max_stats); + pstatus->vit = cap_value(pstatus->vit,1,battle_config.pet_max_stats); + pstatus->int_= cap_value(pstatus->int_,1,battle_config.pet_max_stats); + pstatus->dex = cap_value(pstatus->dex,1,battle_config.pet_max_stats); + pstatus->luk = cap_value(pstatus->luk,1,battle_config.pet_max_stats); + + status->calc_misc(&pd->bl, &pd->status, lv); + + if (! (opt&SCO_FIRST) ) //Not done the first time because the pet is not visible yet clif->send_petstatus(sd); } - } else if (first) { - status_calc_misc(&pd->bl, &pd->status, pd->db->lv); + } else if ( opt&SCO_FIRST ) { + status->calc_misc(&pd->bl, &pd->status, pd->db->lv); if (!battle_config.pet_lv_rate && pd->pet.level != pd->db->lv) pd->pet.level = pd->db->lv; } @@ -2223,23 +2304,23 @@ int status_calc_pet_(struct pet_data *pd, bool first) } /// Helper function for status_base_pc_maxhp(), used to pre-calculate the hp_sigma_val[] array -static void status_calc_sigma(void) +void status_calc_sigma(void) { int i,j; for(i = 0; i < CLASS_COUNT; i++) { unsigned int k = 0; - hp_sigma_val[i][0] = hp_sigma_val[i][1] = 0; + status->hp_sigma_val[i][0] = status->hp_sigma_val[i][1] = 0; for(j = 2; j <= MAX_LEVEL; j++) { - k += (hp_coefficient[i]*j + 50) / 100; - hp_sigma_val[i][j] = k; + k += (status->hp_coefficient[i]*j + 50) / 100; + status->hp_sigma_val[i][j] = k; if (k >= INT_MAX) break; //Overflow protection. [Skotlex] } for(; j <= MAX_LEVEL; j++) - hp_sigma_val[i][j] = INT_MAX; + status->hp_sigma_val[i][j] = INT_MAX; } } @@ -2248,33 +2329,31 @@ static void status_calc_sigma(void) /// f(0) = 35 | f(x+1) = f(x) + A + (x + B)*C/D /// which reduces to something close to /// f(x) = 35 + x*(A + B*C/D) + sum(i=2..x){ i*C/D } -static unsigned int status_base_pc_maxhp(struct map_session_data* sd, struct status_data* status) -{ +unsigned int status_base_pc_maxhp(struct map_session_data *sd, struct status_data *st) { uint64 val = pc->class2idx(sd->status.class_); - val = 35 + sd->status.base_level*(int64)hp_coefficient2[val]/100 + hp_sigma_val[val][sd->status.base_level]; + val = 35 + sd->status.base_level*(int64)status->hp_coefficient2[val]/100 + status->hp_sigma_val[val][sd->status.base_level]; - if((sd->class_&MAPID_UPPERMASK) == MAPID_NINJA || (sd->class_&MAPID_UPPERMASK) == MAPID_GUNSLINGER) + if((sd->class_&MAPID_UPPERMASK) == MAPID_NINJA || (sd->class_&MAPID_UPPERMASK) == MAPID_GUNSLINGER || (sd->class_&MAPID_UPPERMASK) == MAPID_REBELLION) val += 100; //Since their HP can't be approximated well enough without this. if((sd->class_&MAPID_UPPERMASK) == MAPID_TAEKWON && sd->status.base_level >= 90 && pc->famerank(sd->status.char_id, MAPID_TAEKWON)) val *= 3; //Triple max HP for top ranking Taekwons over level 90. if((sd->class_&MAPID_UPPERMASK) == MAPID_SUPER_NOVICE && sd->status.base_level >= 99) val += 2000; //Supernovice lvl99 hp bonus. - val += val * status->vit/100; // +1% per each point of VIT + val += val * st->vit/100; // +1% per each point of VIT if (sd->class_&JOBL_UPPER) val += val * 25/100; //Trans classes get a 25% hp bonus else if (sd->class_&JOBL_BABY) val -= val * 30/100; //Baby classes get a 30% hp penalty - return (unsigned int)val; + return (unsigned int)cap_value(val,0,UINT_MAX); } -static unsigned int status_base_pc_maxsp(struct map_session_data* sd, struct status_data *status) -{ +unsigned int status_base_pc_maxsp(struct map_session_data* sd, struct status_data *st) { uint64 val; - val = 10 + sd->status.base_level*(int64)sp_coefficient[pc->class2idx(sd->status.class_)]/100; - val += val * status->int_/100; + val = 10 + sd->status.base_level*(int64)status->sp_coefficient[pc->class2idx(sd->status.class_)]/100; + val += val * st->int_/100; if (sd->class_&JOBL_UPPER) val += val * 25/100; @@ -2283,19 +2362,18 @@ static unsigned int status_base_pc_maxsp(struct map_session_data* sd, struct sta if ((sd->class_&MAPID_UPPERMASK) == MAPID_TAEKWON && sd->status.base_level >= 90 && pc->famerank(sd->status.char_id, MAPID_TAEKWON)) val *= 3; //Triple max SP for top ranking Taekwons over level 90. - return (unsigned int)val; + return (unsigned int)cap_value(val,0,UINT_MAX); } //Calculates player data from scratch without counting SC adjustments. //Should be invoked whenever players raise stats, learn passive skills or change equipment. -int status_calc_pc_(struct map_session_data* sd, bool first) -{ +int status_calc_pc_(struct map_session_data* sd, enum e_status_calc_opt opt) { static int calculating = 0; //Check for recursive call preemption. [Skotlex] - struct status_data *status; // pointer to the player's base status + struct status_data *bstatus; // pointer to the player's base status const struct status_change *sc = &sd->sc; struct s_skill b_skill[MAX_SKILL]; // previous skill tree int b_weight, b_max_weight, b_cart_weight_max, // previous weight - i, k, index, skill,refinedef=0; + i, k, index, skill_lv,refinedef=0; int64 i64; if (++calculating > 10) //Too many recursive calls! @@ -2309,9 +2387,9 @@ int status_calc_pc_(struct map_session_data* sd, bool first) pc->calc_skilltree(sd); // SkillTree calculation - sd->max_weight = max_weight_base[pc->class2idx(sd->status.class_)]+sd->status.str*300; + sd->max_weight = status->max_weight_base[pc->class2idx(sd->status.class_)]+sd->status.str*300; - if(first) { + if(opt&SCO_FIRST) { //Load Hp/SP from char-received data. sd->battle_status.hp = sd->status.hp; sd->battle_status.sp = sd->status.sp; @@ -2333,7 +2411,7 @@ int status_calc_pc_(struct map_session_data* sd, bool first) } } - status = &sd->base_status; + bstatus = &sd->base_status; // these are not zeroed. [zzo] sd->hprate=100; sd->sprate=100; @@ -2371,7 +2449,6 @@ int status_calc_pc_(struct map_session_data* sd, bool first) + sizeof(sd->expaddrace) + sizeof(sd->ignore_mdef) + sizeof(sd->ignore_def) - + sizeof(sd->itemgrouphealrate) + sizeof(sd->sp_gain_race) + sizeof(sd->sp_gain_race_attack) + sizeof(sd->hp_gain_race_attack) @@ -2384,26 +2461,32 @@ int status_calc_pc_(struct map_session_data* sd, bool first) clif->sc_end(&sd->bl,sd->bl.id,SELF,SI_CLAIRVOYANCE); memset(&sd->special_state,0,sizeof(sd->special_state)); - memset(&status->max_hp, 0, sizeof(struct status_data)-(sizeof(status->hp)+sizeof(status->sp))); - + + if (!sd->state.permanent_speed) { + memset(&bstatus->max_hp, 0, sizeof(struct status_data)-(sizeof(bstatus->hp)+sizeof(bstatus->sp))); + bstatus->speed = DEFAULT_WALK_SPEED; + } else { + int pSpeed = bstatus->speed; + memset(&bstatus->max_hp, 0, sizeof(struct status_data)-(sizeof(bstatus->hp)+sizeof(bstatus->sp))); + bstatus->speed = pSpeed; + } + //FIXME: Most of these stuff should be calculated once, but how do I fix the memset above to do that? [Skotlex] - if (!sd->state.permanent_speed) - status->speed = DEFAULT_WALK_SPEED; //Give them all modes except these (useful for clones) - status->mode = MD_MASK&~(MD_BOSS|MD_PLANT|MD_DETECTOR|MD_ANGRY|MD_TARGETWEAK); + bstatus->mode = MD_MASK&~(MD_BOSS|MD_PLANT|MD_DETECTOR|MD_ANGRY|MD_TARGETWEAK); - status->size = (sd->class_&JOBL_BABY)?SZ_SMALL:SZ_MEDIUM; + bstatus->size = (sd->class_&JOBL_BABY)?SZ_MEDIUM:SZ_SMALL; if (battle_config.character_size && (pc_isriding(sd) || pc_isridingdragon(sd)) ) { //[Lupus] if (sd->class_&JOBL_BABY) { if (battle_config.character_size&SZ_BIG) - status->size++; + bstatus->size++; } else - if(battle_config.character_size&SZ_MEDIUM) - status->size++; + if(battle_config.character_size&SZ_SMALL) + bstatus->size++; } - status->aspd_rate = 1000; - status->ele_lv = 1; - status->race = RC_DEMIHUMAN; + bstatus->aspd_rate = 1000; + bstatus->ele_lv = 1; + bstatus->race = RC_DEMIHUMAN; //zero up structures... memset(&sd->autospell,0,sizeof(sd->autospell) @@ -2433,7 +2516,9 @@ int status_calc_pc_(struct map_session_data* sd, bool first) + sizeof(sd->skillfixcast) + sizeof(sd->skillvarcast) + sizeof(sd->skillfixcastrate) - ); + + sizeof(sd->def_set_race) + + sizeof(sd->mdef_set_race) + ); memset (&sd->bonus, 0,sizeof(sd->bonus)); @@ -2443,10 +2528,11 @@ int status_calc_pc_(struct map_session_data* sd, bool first) pc->delautobonus(sd,sd->autobonus3,ARRAYLENGTH(sd->autobonus3),true); // Parse equipment. - for(i=0;i<EQI_MAX-1;i++) { - current_equip_item_index = index = sd->equip_index[i]; //We pass INDEX to current_equip_item_index - for EQUIP_SCRIPT (new cards solution) [Lupus] + for(i=0;i<EQI_MAX;i++) { + status->current_equip_item_index = index = sd->equip_index[i]; //We pass INDEX to status->current_equip_item_index - for EQUIP_SCRIPT (new cards solution) [Lupus] if(index < 0) continue; + if(i == EQI_AMMO) continue;/* ammo has special handler down there */ if(i == EQI_HAND_R && sd->equip_index[EQI_HAND_L] == index) continue; if(i == EQI_HEAD_MID && sd->equip_index[EQI_HEAD_LOW] == index) @@ -2460,25 +2546,25 @@ int status_calc_pc_(struct map_session_data* sd, bool first) if(!sd->inventory_data[index]) continue; - for(k = 0; k < map[sd->bl.m].zone->disabled_items_count; k++) { - if( map[sd->bl.m].zone->disabled_items[k] == sd->inventory_data[index]->nameid ) { + for(k = 0; k < map->list[sd->bl.m].zone->disabled_items_count; k++) { + if( map->list[sd->bl.m].zone->disabled_items[k] == sd->inventory_data[index]->nameid ) { break; } } - - if( k < map[sd->bl.m].zone->disabled_items_count ) + + if( k < map->list[sd->bl.m].zone->disabled_items_count ) continue; - - status->def += sd->inventory_data[index]->def; - if(first && sd->inventory_data[index]->equip_script) - { //Execute equip-script on login - run_script(sd->inventory_data[index]->equip_script,0,sd->bl.id,0); + bstatus->def += sd->inventory_data[index]->def; + + if(opt&SCO_FIRST && sd->inventory_data[index]->equip_script) + { //Execute equip-script on login + script->run(sd->inventory_data[index]->equip_script,0,sd->bl.id,0); if (!calculating) return 1; } - // sanitize the refine level in case someone decreased the value inbetween + // sanitize the refine level in case someone decreased the value in between if (sd->status.inventory[index].refine > MAX_REFINE) sd->status.inventory[index].refine = MAX_REFINE; @@ -2490,35 +2576,35 @@ int status_calc_pc_(struct map_session_data* sd, bool first) wlv = REFINE_TYPE_MAX - 1; if(i == EQI_HAND_L && sd->status.inventory[index].equip == EQP_HAND_L) { wd = &sd->left_weapon; // Left-hand weapon - wa = &status->lhw; + wa = &bstatus->lhw; } else { wd = &sd->right_weapon; - wa = &status->rhw; + wa = &bstatus->rhw; } wa->atk += sd->inventory_data[index]->atk; if ( (r = sd->status.inventory[index].refine) ) - wa->atk2 = refine_info[wlv].bonus[r-1] / 100; + wa->atk2 = status->refine_info[wlv].bonus[r-1] / 100; #ifdef RENEWAL - wa->matk += sd->inventory_data[index]->matk; - wa->wlv = wlv; + wa->matk += sd->inventory_data[index]->matk; + wa->wlv = wlv; if( r && sd->weapontype1 != W_BOW ) // renewal magic attack refine bonus - wa->matk += refine_info[wlv].bonus[r-1] / 100; + wa->matk += status->refine_info[wlv].bonus[r-1] / 100; #endif - //Overrefine bonus. + //Overrefined bonus. if (r) - wd->overrefine = refine_info[wlv].randombonus_max[r-1] / 100; + wd->overrefine = status->refine_info[wlv].randombonus_max[r-1] / 100; wa->range += sd->inventory_data[index]->range; if(sd->inventory_data[index]->script) { if (wd == &sd->left_weapon) { sd->state.lr_flag = 1; - run_script(sd->inventory_data[index]->script,0,sd->bl.id,0); + script->run(sd->inventory_data[index]->script,0,sd->bl.id,0); sd->state.lr_flag = 0; } else - run_script(sd->inventory_data[index]->script,0,sd->bl.id,0); - if (!calculating) //Abort, run_script retriggered this. [Skotlex] + script->run(sd->inventory_data[index]->script,0,sd->bl.id,0); + if (!calculating) //Abort, script->run retriggered this. [Skotlex] return 1; } @@ -2536,14 +2622,14 @@ int status_calc_pc_(struct map_session_data* sd, bool first) else if(sd->inventory_data[index]->type == IT_ARMOR) { int r; if ( (r = sd->status.inventory[index].refine) ) - refinedef += refine_info[REFINE_TYPE_ARMOR].bonus[r-1]; + refinedef += status->refine_info[REFINE_TYPE_ARMOR].bonus[r-1]; if(sd->inventory_data[index]->script) { if( i == EQI_HAND_L ) //Shield sd->state.lr_flag = 3; - run_script(sd->inventory_data[index]->script,0,sd->bl.id,0); + script->run(sd->inventory_data[index]->script,0,sd->bl.id,0); if( i == EQI_HAND_L ) //Shield sd->state.lr_flag = 0; - if (!calculating) //Abort, run_script retriggered this. [Skotlex] + if (!calculating) //Abort, script->run retriggered this. [Skotlex] return 1; } } @@ -2555,33 +2641,51 @@ int status_calc_pc_(struct map_session_data* sd, bool first) sd->bonus.arrow_atk += sd->inventory_data[index]->atk; sd->state.lr_flag = 2; if( !itemdb_is_GNthrowable(sd->inventory_data[index]->nameid) ) //don't run scripts on throwable items - run_script(sd->inventory_data[index]->script,0,sd->bl.id,0); + script->run(sd->inventory_data[index]->script,0,sd->bl.id,0); sd->state.lr_flag = 0; - if (!calculating) //Abort, run_script retriggered status_calc_pc. [Skotlex] + if (!calculating) //Abort, script->run retriggered status_calc_pc. [Skotlex] return 1; } } /* we've got combos to process */ - if( sd->combos.count ) { - for( i = 0; i < sd->combos.count; i++ ) { - run_script(sd->combos.bonus[i],0,sd->bl.id,0); - if (!calculating) //Abort, run_script retriggered this. - return 1; + for( i = 0; i < sd->combo_count; i++ ) { + struct item_combo *combo = itemdb->id2combo(sd->combos[i].id); + unsigned char j; + + /** + * ensure combo usage is allowed at this location + **/ + for(j = 0; j < combo->count; j++) { + for(k = 0; k < map->list[sd->bl.m].zone->disabled_items_count; k++) { + if( map->list[sd->bl.m].zone->disabled_items[k] == combo->nameid[j] ) { + break; + } + } + if( k != map->list[sd->bl.m].zone->disabled_items_count ) + break; } + + if( j != combo->count ) + continue; + + script->run(sd->combos[i].bonus,0,sd->bl.id,0); + if (!calculating) //Abort, script->run retriggered this. + return 1; } //Store equipment script bonuses memcpy(sd->param_equip,sd->param_bonus,sizeof(sd->param_equip)); memset(sd->param_bonus, 0, sizeof(sd->param_bonus)); - status->def += (refinedef+50)/100; + bstatus->def += (refinedef+50)/100; //Parse Cards - for(i=0;i<EQI_MAX-1;i++) { - current_equip_item_index = index = sd->equip_index[i]; //We pass INDEX to current_equip_item_index - for EQUIP_SCRIPT (new cards solution) [Lupus] + for(i=0;i<EQI_MAX;i++) { + status->current_equip_item_index = index = sd->equip_index[i]; //We pass INDEX to status->current_equip_item_index - for EQUIP_SCRIPT (new cards solution) [Lupus] if(index < 0) continue; + if(i == EQI_AMMO) continue;/* ammo doesn't have cards */ if(i == EQI_HAND_R && sd->equip_index[EQI_HAND_L] == index) continue; if(i == EQI_HEAD_MID && sd->equip_index[EQI_HEAD_LOW] == index) @@ -2596,75 +2700,76 @@ int status_calc_pc_(struct map_session_data* sd, bool first) //Card script execution. if(itemdb_isspecial(sd->status.inventory[index].card[0])) continue; - for(j=0;j<MAX_SLOTS;j++){ // Uses MAX_SLOTS to support Soul Bound system [Inkfish] - current_equip_card_id= c= sd->status.inventory[index].card[j]; + for(j=0;j<MAX_SLOTS;j++) { + // Uses MAX_SLOTS to support Soul Bound system [Inkfish] + status->current_equip_card_id= c= sd->status.inventory[index].card[j]; if(!c) continue; - data = itemdb_exists(c); + data = itemdb->exists(c); if(!data) continue; - if(first && data->equip_script) {//Execute equip-script on login - run_script(data->equip_script,0,sd->bl.id,0); + + for(k = 0; k < map->list[sd->bl.m].zone->disabled_items_count; k++) { + if( map->list[sd->bl.m].zone->disabled_items[k] == data->nameid ) { + break; + } + } + + if( k < map->list[sd->bl.m].zone->disabled_items_count ) + continue; + + if(opt&SCO_FIRST && data->equip_script) {//Execute equip-script on login + script->run(data->equip_script,0,sd->bl.id,0); if (!calculating) return 1; } + if(!data->script) continue; - - for(k = 0; k < map[sd->bl.m].zone->disabled_items_count; k++) { - if( map[sd->bl.m].zone->disabled_items[k] == data->nameid ) { - break; - } - } - - if( k < map[sd->bl.m].zone->disabled_items_count ) - continue; - + if(i == EQI_HAND_L && sd->status.inventory[index].equip == EQP_HAND_L) { //Left hand status. sd->state.lr_flag = 1; - run_script(data->script,0,sd->bl.id,0); + script->run(data->script,0,sd->bl.id,0); sd->state.lr_flag = 0; } else - run_script(data->script,0,sd->bl.id,0); - if (!calculating) //Abort, run_script his function. [Skotlex] + script->run(data->script,0,sd->bl.id,0); + if (!calculating) //Abort, script->run his function. [Skotlex] return 1; } } } - if( sc->count && sc->data[SC_ITEMSCRIPT] ) - { - struct item_data *data = itemdb_exists(sc->data[SC_ITEMSCRIPT]->val1); + if( sc->count && sc->data[SC_ITEMSCRIPT] ) { + struct item_data *data = itemdb->exists(sc->data[SC_ITEMSCRIPT]->val1); if( data && data->script ) - run_script(data->script,0,sd->bl.id,0); + script->run(data->script,0,sd->bl.id,0); } - if( sd->pd ) - { // Pet Bonus + if( sd->pd ) { // Pet Bonus struct pet_data *pd = sd->pd; if( pd && pd->petDB && pd->petDB->equip_script && pd->pet.intimate >= battle_config.pet_equip_min_friendly ) - run_script(pd->petDB->equip_script,0,sd->bl.id,0); + script->run(pd->petDB->equip_script,0,sd->bl.id,0); if( pd && pd->pet.intimate > 0 && (!battle_config.pet_equip_required || pd->pet.equip > 0) && pd->state.skillbonus == 1 && pd->bonus ) pc->bonus(sd,pd->bonus->type, pd->bonus->val); } //param_bonus now holds card bonuses. - if(status->rhw.range < 1) status->rhw.range = 1; - if(status->lhw.range < 1) status->lhw.range = 1; - if(status->rhw.range < status->lhw.range) - status->rhw.range = status->lhw.range; + if(bstatus->rhw.range < 1) bstatus->rhw.range = 1; + if(bstatus->lhw.range < 1) bstatus->lhw.range = 1; + if(bstatus->rhw.range < bstatus->lhw.range) + bstatus->rhw.range = bstatus->lhw.range; sd->bonus.double_rate += sd->bonus.double_add_rate; sd->bonus.perfect_hit += sd->bonus.perfect_hit_add; sd->bonus.splash_range += sd->bonus.splash_add_range; // Damage modifiers from weapon type - sd->right_weapon.atkmods[0] = atkmods[0][sd->weapontype1]; - sd->right_weapon.atkmods[1] = atkmods[1][sd->weapontype1]; - sd->right_weapon.atkmods[2] = atkmods[2][sd->weapontype1]; - sd->left_weapon.atkmods[0] = atkmods[0][sd->weapontype2]; - sd->left_weapon.atkmods[1] = atkmods[1][sd->weapontype2]; - sd->left_weapon.atkmods[2] = atkmods[2][sd->weapontype2]; + sd->right_weapon.atkmods[0] = status->atkmods[0][sd->weapontype1]; + sd->right_weapon.atkmods[1] = status->atkmods[1][sd->weapontype1]; + sd->right_weapon.atkmods[2] = status->atkmods[2][sd->weapontype1]; + sd->left_weapon.atkmods[0] = status->atkmods[0][sd->weapontype2]; + sd->left_weapon.atkmods[1] = status->atkmods[1][sd->weapontype2]; + sd->left_weapon.atkmods[2] = status->atkmods[2][sd->weapontype2]; if( (pc_isriding(sd) || pc_isridingdragon(sd)) && (sd->status.weapon==W_1HSPEAR || sd->status.weapon==W_2HSPEAR)) @@ -2674,314 +2779,320 @@ int status_calc_pc_(struct map_session_data* sd, bool first) sd->left_weapon.atkmods[1] = sd->left_weapon.atkmods[2]; } -// ----- STATS CALCULATION ----- + // ----- STATS CALCULATION ----- // Job bonuses index = pc->class2idx(sd->status.class_); for(i=0;i<(int)sd->status.job_level && i<MAX_LEVEL;i++){ - if(!job_bonus[index][i]) + if(!status->job_bonus[index][i]) continue; - switch(job_bonus[index][i]) { - case 1: status->str++; break; - case 2: status->agi++; break; - case 3: status->vit++; break; - case 4: status->int_++; break; - case 5: status->dex++; break; - case 6: status->luk++; break; + switch(status->job_bonus[index][i]) { + case 1: bstatus->str++; break; + case 2: bstatus->agi++; break; + case 3: bstatus->vit++; break; + case 4: bstatus->int_++; break; + case 5: bstatus->dex++; break; + case 6: bstatus->luk++; break; } } // If a Super Novice has never died and is at least joblv 70, he gets all stats +10 - if((sd->class_&MAPID_UPPERMASK) == MAPID_SUPER_NOVICE && sd->die_counter == 0 && sd->status.job_level >= 70){ - status->str += 10; - status->agi += 10; - status->vit += 10; - status->int_+= 10; - status->dex += 10; - status->luk += 10; + if((sd->class_&MAPID_UPPERMASK) == MAPID_SUPER_NOVICE && sd->die_counter == 0 && sd->status.job_level >= 70) { + bstatus->str += 10; + bstatus->agi += 10; + bstatus->vit += 10; + bstatus->int_+= 10; + bstatus->dex += 10; + bstatus->luk += 10; } // Absolute modifiers from passive skills if(pc->checkskill(sd,BS_HILTBINDING)>0) - status->str++; - if((skill=pc->checkskill(sd,SA_DRAGONOLOGY))>0) - status->int_ += (skill+1)/2; // +1 INT / 2 lv - if((skill=pc->checkskill(sd,AC_OWL))>0) - status->dex += skill; - if((skill = pc->checkskill(sd,RA_RESEARCHTRAP))>0) - status->int_ += skill; + bstatus->str++; + if((skill_lv=pc->checkskill(sd,SA_DRAGONOLOGY))>0) + bstatus->int_ += (skill_lv+1)/2; // +1 INT / 2 lv + if((skill_lv=pc->checkskill(sd,AC_OWL))>0) + bstatus->dex += skill_lv; + if((skill_lv = pc->checkskill(sd,RA_RESEARCHTRAP))>0) + bstatus->int_ += skill_lv; // Bonuses from cards and equipment as well as base stat, remember to avoid overflows. - i = status->str + sd->status.str + sd->param_bonus[0] + sd->param_equip[0]; - status->str = cap_value(i,0,USHRT_MAX); - i = status->agi + sd->status.agi + sd->param_bonus[1] + sd->param_equip[1]; - status->agi = cap_value(i,0,USHRT_MAX); - i = status->vit + sd->status.vit + sd->param_bonus[2] + sd->param_equip[2]; - status->vit = cap_value(i,0,USHRT_MAX); - i = status->int_+ sd->status.int_+ sd->param_bonus[3] + sd->param_equip[3]; - status->int_ = cap_value(i,0,USHRT_MAX); - i = status->dex + sd->status.dex + sd->param_bonus[4] + sd->param_equip[4]; - status->dex = cap_value(i,0,USHRT_MAX); - i = status->luk + sd->status.luk + sd->param_bonus[5] + sd->param_equip[5]; - status->luk = cap_value(i,0,USHRT_MAX); - -// ------ BASE ATTACK CALCULATION ------ - - // Base batk value is set on status_calc_misc + i = bstatus->str + sd->status.str + sd->param_bonus[0] + sd->param_equip[0]; + bstatus->str = cap_value(i,0,USHRT_MAX); + i = bstatus->agi + sd->status.agi + sd->param_bonus[1] + sd->param_equip[1]; + bstatus->agi = cap_value(i,0,USHRT_MAX); + i = bstatus->vit + sd->status.vit + sd->param_bonus[2] + sd->param_equip[2]; + bstatus->vit = cap_value(i,0,USHRT_MAX); + i = bstatus->int_+ sd->status.int_+ sd->param_bonus[3] + sd->param_equip[3]; + bstatus->int_ = cap_value(i,0,USHRT_MAX); + i = bstatus->dex + sd->status.dex + sd->param_bonus[4] + sd->param_equip[4]; + bstatus->dex = cap_value(i,0,USHRT_MAX); + i = bstatus->luk + sd->status.luk + sd->param_bonus[5] + sd->param_equip[5]; + bstatus->luk = cap_value(i,0,USHRT_MAX); + + // ------ BASE ATTACK CALCULATION ------ + + // Base batk value is set on status->calc_misc // weapon-type bonus (FIXME: Why is the weapon_atk bonus applied to base attack?) if (sd->status.weapon < MAX_WEAPON_TYPE && sd->weapon_atk[sd->status.weapon]) - status->batk += sd->weapon_atk[sd->status.weapon]; + bstatus->batk += sd->weapon_atk[sd->status.weapon]; // Absolute modifiers from passive skills #ifndef RENEWAL - if((skill=pc->checkskill(sd,BS_HILTBINDING))>0) // it doesn't work in RE. - status->batk += 4; + if((skill_lv=pc->checkskill(sd,BS_HILTBINDING))>0) // it doesn't work in RE. + bstatus->batk += 4; #endif -// ----- HP MAX CALCULATION ----- + // ----- HP MAX CALCULATION ----- // Basic MaxHP value //We hold the standard Max HP here to make it faster to recalculate on vit changes. - sd->status.max_hp = status_base_pc_maxhp(sd,status); + sd->status.max_hp = status->base_pc_maxhp(sd,bstatus); //This is done to handle underflows from negative Max HP bonuses - i64 = sd->status.max_hp + (int)status->max_hp; - status->max_hp = (unsigned int)cap_value(i64, 0, INT_MAX); + i64 = sd->status.max_hp + (int)bstatus->max_hp; + bstatus->max_hp = (unsigned int)cap_value(i64, 0, INT_MAX); // Absolute modifiers from passive skills - if((skill=pc->checkskill(sd,CR_TRUST))>0) - status->max_hp += skill*200; + if((skill_lv=pc->checkskill(sd,CR_TRUST))>0) + bstatus->max_hp += skill_lv*200; // Apply relative modifiers from equipment if(sd->hprate < 0) sd->hprate = 0; if(sd->hprate!=100) - status->max_hp = (int64)status->max_hp * sd->hprate/100; + bstatus->max_hp = APPLY_RATE(bstatus->max_hp, sd->hprate); if(battle_config.hp_rate != 100) - status->max_hp = (int64)status->max_hp * battle_config.hp_rate/100; + bstatus->max_hp = APPLY_RATE(bstatus->max_hp, battle_config.hp_rate); - if(status->max_hp > (unsigned int)battle_config.max_hp) - status->max_hp = battle_config.max_hp; - else if(!status->max_hp) - status->max_hp = 1; + if(bstatus->max_hp > (unsigned int)battle_config.max_hp) + bstatus->max_hp = battle_config.max_hp; + else if(!bstatus->max_hp) + bstatus->max_hp = 1; -// ----- SP MAX CALCULATION ----- + // ----- SP MAX CALCULATION ----- // Basic MaxSP value - sd->status.max_sp = status_base_pc_maxsp(sd,status); + sd->status.max_sp = status->base_pc_maxsp(sd,bstatus); //This is done to handle underflows from negative Max SP bonuses - i64 = sd->status.max_sp + (int)status->max_sp; - status->max_sp = (unsigned int)cap_value(i64, 0, INT_MAX); + i64 = sd->status.max_sp + (int)bstatus->max_sp; + bstatus->max_sp = (unsigned int)cap_value(i64, 0, INT_MAX); // Absolute modifiers from passive skills - if((skill=pc->checkskill(sd,SL_KAINA))>0) - status->max_sp += 30*skill; - if((skill=pc->checkskill(sd,HP_MEDITATIO))>0) - status->max_sp += (int64)status->max_sp * skill/100; - if((skill=pc->checkskill(sd,HW_SOULDRAIN))>0) - status->max_sp += (int64)status->max_sp * 2*skill/100; - if( (skill = pc->checkskill(sd,RA_RESEARCHTRAP)) > 0 ) - status->max_sp += 200 + 20 * skill; - if( (skill = pc->checkskill(sd,WM_LESSON)) > 0 ) - status->max_sp += 30 * skill; + if((skill_lv=pc->checkskill(sd,SL_KAINA))>0) + bstatus->max_sp += 30*skill_lv; + if((skill_lv=pc->checkskill(sd,HP_MEDITATIO))>0) + bstatus->max_sp += (int64)bstatus->max_sp * skill_lv/100; + if((skill_lv=pc->checkskill(sd,HW_SOULDRAIN))>0) + bstatus->max_sp += (int64)bstatus->max_sp * 2*skill_lv/100; + if( (skill_lv = pc->checkskill(sd,RA_RESEARCHTRAP)) > 0 ) + bstatus->max_sp += 200 + 20 * skill_lv; + if( (skill_lv = pc->checkskill(sd,WM_LESSON)) > 0 ) + bstatus->max_sp += 30 * skill_lv; // Apply relative modifiers from equipment if(sd->sprate < 0) sd->sprate = 0; if(sd->sprate!=100) - status->max_sp = (int64)status->max_sp * sd->sprate/100; + bstatus->max_sp = APPLY_RATE(bstatus->max_sp, sd->sprate); if(battle_config.sp_rate != 100) - status->max_sp = (int64)status->max_sp * battle_config.sp_rate/100; + bstatus->max_sp = APPLY_RATE(bstatus->max_sp, battle_config.sp_rate); - if(status->max_sp > (unsigned int)battle_config.max_sp) - status->max_sp = battle_config.max_sp; - else if(!status->max_sp) - status->max_sp = 1; + if(bstatus->max_sp > (unsigned int)battle_config.max_sp) + bstatus->max_sp = battle_config.max_sp; + else if(!bstatus->max_sp) + bstatus->max_sp = 1; -// ----- RESPAWN HP/SP ----- -// + // ----- RESPAWN HP/SP ----- + // //Calc respawn hp and store it on base_status if (sd->special_state.restart_full_recover) { - status->hp = status->max_hp; - status->sp = status->max_sp; + bstatus->hp = bstatus->max_hp; + bstatus->sp = bstatus->max_sp; } else { if((sd->class_&MAPID_BASEMASK) == MAPID_NOVICE && !(sd->class_&JOBL_2) && battle_config.restart_hp_rate < 50) - status->hp = status->max_hp>>1; + bstatus->hp = bstatus->max_hp>>1; else - status->hp = (int64)status->max_hp * battle_config.restart_hp_rate/100; - if(!status->hp) - status->hp = 1; + bstatus->hp = APPLY_RATE(bstatus->max_hp, battle_config.restart_hp_rate); + if(!bstatus->hp) + bstatus->hp = 1; - status->sp = (int64)status->max_sp * battle_config.restart_sp_rate /100; + bstatus->sp = APPLY_RATE(bstatus->max_sp, battle_config.restart_sp_rate); - if( !status->sp ) /* the minimum for the respawn setting is SP:1 */ - status->sp = 1; + if( !bstatus->sp ) /* the minimum for the respawn setting is SP:1 */ + bstatus->sp = 1; } -// ----- MISC CALCULATION ----- - status_calc_misc(&sd->bl, status, sd->status.base_level); + // ----- MISC CALCULATION ----- + status->calc_misc(&sd->bl, bstatus, sd->status.base_level); //Equipment modifiers for misc settings if(sd->matk_rate < 0) sd->matk_rate = 0; if(sd->matk_rate != 100){ - status->matk_max = status->matk_max * sd->matk_rate/100; - status->matk_min = status->matk_min * sd->matk_rate/100; + bstatus->matk_max = bstatus->matk_max * sd->matk_rate/100; + bstatus->matk_min = bstatus->matk_min * sd->matk_rate/100; } if(sd->hit_rate < 0) sd->hit_rate = 0; if(sd->hit_rate != 100) - status->hit = status->hit * sd->hit_rate/100; + bstatus->hit = bstatus->hit * sd->hit_rate/100; if(sd->flee_rate < 0) sd->flee_rate = 0; if(sd->flee_rate != 100) - status->flee = status->flee * sd->flee_rate/100; + bstatus->flee = bstatus->flee * sd->flee_rate/100; if(sd->def2_rate < 0) sd->def2_rate = 0; if(sd->def2_rate != 100) - status->def2 = status->def2 * sd->def2_rate/100; + bstatus->def2 = bstatus->def2 * sd->def2_rate/100; if(sd->mdef2_rate < 0) sd->mdef2_rate = 0; if(sd->mdef2_rate != 100) - status->mdef2 = status->mdef2 * sd->mdef2_rate/100; + bstatus->mdef2 = bstatus->mdef2 * sd->mdef2_rate/100; if(sd->critical_rate < 0) sd->critical_rate = 0; if(sd->critical_rate != 100) - status->cri = status->cri * sd->critical_rate/100; + bstatus->cri = bstatus->cri * sd->critical_rate/100; if(sd->flee2_rate < 0) sd->flee2_rate = 0; if(sd->flee2_rate != 100) - status->flee2 = status->flee2 * sd->flee2_rate/100; + bstatus->flee2 = bstatus->flee2 * sd->flee2_rate/100; -// ----- HIT CALCULATION ----- + // ----- HIT CALCULATION ----- // Absolute modifiers from passive skills - if((skill=pc->checkskill(sd,BS_WEAPONRESEARCH))>0) - status->hit += skill*2; - if((skill=pc->checkskill(sd,AC_VULTURE))>0){ #ifndef RENEWAL - status->hit += skill; + if((skill_lv=pc->checkskill(sd,BS_WEAPONRESEARCH))>0) // is this correct in pre? there is already hitrate bonus in battle.c + bstatus->hit += skill_lv*2; +#endif + if((skill_lv=pc->checkskill(sd,AC_VULTURE))>0) { +#ifndef RENEWAL + bstatus->hit += skill_lv; #endif if(sd->status.weapon == W_BOW) - status->rhw.range += skill; - } - if(sd->status.weapon >= W_REVOLVER && sd->status.weapon <= W_GRENADE) - { - if((skill=pc->checkskill(sd,GS_SINGLEACTION))>0) - status->hit += 2*skill; - if((skill=pc->checkskill(sd,GS_SNAKEEYE))>0) { - status->hit += skill; - status->rhw.range += skill; + bstatus->rhw.range += skill_lv; + } + if(sd->status.weapon >= W_REVOLVER && sd->status.weapon <= W_GRENADE) { + if((skill_lv=pc->checkskill(sd,GS_SINGLEACTION))>0) + bstatus->hit += 2*skill_lv; + if((skill_lv=pc->checkskill(sd,GS_SNAKEEYE))>0) { + bstatus->hit += skill_lv; + bstatus->rhw.range += skill_lv; } } + if( (sd->status.weapon == W_1HAXE || sd->status.weapon == W_2HAXE) && (skill_lv = pc->checkskill(sd,NC_TRAININGAXE)) > 0 ) + bstatus->hit += 3*skill_lv; + if((sd->status.weapon == W_MACE || sd->status.weapon == W_2HMACE) && ((skill_lv = pc->checkskill(sd,NC_TRAININGAXE)) > 0)) + bstatus->hit += 2*skill_lv; -// ----- FLEE CALCULATION ----- + // ----- FLEE CALCULATION ----- // Absolute modifiers from passive skills - if((skill=pc->checkskill(sd,TF_MISS))>0) - status->flee += skill*(sd->class_&JOBL_2 && (sd->class_&MAPID_BASEMASK) == MAPID_THIEF? 4 : 3); - if((skill=pc->checkskill(sd,MO_DODGE))>0) - status->flee += (skill*3)>>1; -// ----- EQUIPMENT-DEF CALCULATION ----- + if((skill_lv=pc->checkskill(sd,TF_MISS))>0) + bstatus->flee += skill_lv*(sd->class_&JOBL_2 && (sd->class_&MAPID_BASEMASK) == MAPID_THIEF? 4 : 3); + if((skill_lv=pc->checkskill(sd,MO_DODGE))>0) + bstatus->flee += (skill_lv*3)>>1; + // ----- EQUIPMENT-DEF CALCULATION ----- // Apply relative modifiers from equipment if(sd->def_rate < 0) sd->def_rate = 0; if(sd->def_rate != 100) { - i = status->def * sd->def_rate/100; - status->def = cap_value(i, DEFTYPE_MIN, DEFTYPE_MAX); + i = bstatus->def * sd->def_rate/100; + bstatus->def = cap_value(i, DEFTYPE_MIN, DEFTYPE_MAX); } + if( pc_ismadogear(sd) && (skill_lv = pc->checkskill(sd,NC_MAINFRAME)) > 0 ) + bstatus->def += 20 + 20 * skill_lv; + #ifndef RENEWAL - if (!battle_config.weapon_defense_type && status->def > battle_config.max_def) - { - status->def2 += battle_config.over_def_bonus*(status->def -battle_config.max_def); - status->def = (unsigned char)battle_config.max_def; + if (!battle_config.weapon_defense_type && bstatus->def > battle_config.max_def) { + bstatus->def2 += battle_config.over_def_bonus*(bstatus->def -battle_config.max_def); + bstatus->def = (unsigned char)battle_config.max_def; } #endif -// ----- EQUIPMENT-MDEF CALCULATION ----- + // ----- EQUIPMENT-MDEF CALCULATION ----- // Apply relative modifiers from equipment if(sd->mdef_rate < 0) sd->mdef_rate = 0; if(sd->mdef_rate != 100) { - i = status->mdef * sd->mdef_rate/100; - status->mdef = cap_value(i, DEFTYPE_MIN, DEFTYPE_MAX); + i = bstatus->mdef * sd->mdef_rate/100; + bstatus->mdef = cap_value(i, DEFTYPE_MIN, DEFTYPE_MAX); } #ifndef RENEWAL - if (!battle_config.magic_defense_type && status->mdef > battle_config.max_def) - { - status->mdef2 += battle_config.over_def_bonus*(status->mdef -battle_config.max_def); - status->mdef = (signed char)battle_config.max_def; + if (!battle_config.magic_defense_type && bstatus->mdef > battle_config.max_def) { + bstatus->mdef2 += battle_config.over_def_bonus*(bstatus->mdef -battle_config.max_def); + bstatus->mdef = (signed char)battle_config.max_def; } #endif -// ----- ASPD CALCULATION ----- -// Unlike other stats, ASPD rate modifiers from skills/SCs/items/etc are first all added together, then the final modifier is applied + // ----- ASPD CALCULATION ----- + // Unlike other stats, ASPD rate modifiers from skills/SCs/items/etc are first all added together, then the final modifier is applied // Basic ASPD value - i = status_base_amotion_pc(sd,status); - status->amotion = cap_value(i,((sd->class_&JOBL_THIRD) ? battle_config.max_third_aspd : battle_config.max_aspd),2000); + i = status->base_amotion_pc(sd,bstatus); + bstatus->amotion = cap_value(i,((sd->class_&JOBL_THIRD) ? battle_config.max_third_aspd : battle_config.max_aspd),2000); // Relative modifiers from passive skills #ifndef RENEWAL_ASPD - if((skill=pc->checkskill(sd,SA_ADVANCEDBOOK))>0 && sd->status.weapon == W_BOOK) - status->aspd_rate -= 5*skill; - if((skill = pc->checkskill(sd,SG_DEVIL)) > 0 && !pc->nextjobexp(sd)) - status->aspd_rate -= 30*skill; - if((skill=pc->checkskill(sd,GS_SINGLEACTION))>0 && + if((skill_lv=pc->checkskill(sd,SA_ADVANCEDBOOK))>0 && sd->status.weapon == W_BOOK) + bstatus->aspd_rate -= 5*skill_lv; + if((skill_lv = pc->checkskill(sd,SG_DEVIL)) > 0 && !pc->nextjobexp(sd)) + bstatus->aspd_rate -= 30*skill_lv; + if((skill_lv=pc->checkskill(sd,GS_SINGLEACTION))>0 && (sd->status.weapon >= W_REVOLVER && sd->status.weapon <= W_GRENADE)) - status->aspd_rate -= ((skill+1)/2) * 10; + bstatus->aspd_rate -= ((skill_lv+1)/2) * 10; if(pc_isriding(sd)) - status->aspd_rate += 500-100*pc->checkskill(sd,KN_CAVALIERMASTERY); + bstatus->aspd_rate += 500-100*pc->checkskill(sd,KN_CAVALIERMASTERY); else if(pc_isridingdragon(sd)) - status->aspd_rate += 250-50*pc->checkskill(sd,RK_DRAGONTRAINING); + bstatus->aspd_rate += 250-50*pc->checkskill(sd,RK_DRAGONTRAINING); #else // needs more info - if((skill=pc->checkskill(sd,SA_ADVANCEDBOOK))>0 && sd->status.weapon == W_BOOK) - status->aspd_rate += 5*skill; - if((skill = pc->checkskill(sd,SG_DEVIL)) > 0 && !pc->nextjobexp(sd)) - status->aspd_rate += 30*skill; - if((skill=pc->checkskill(sd,GS_SINGLEACTION))>0 && + if((skill_lv=pc->checkskill(sd,SA_ADVANCEDBOOK))>0 && sd->status.weapon == W_BOOK) + bstatus->aspd_rate += 5*skill_lv; + if((skill_lv = pc->checkskill(sd,SG_DEVIL)) > 0 && !pc->nextjobexp(sd)) + bstatus->aspd_rate += 30*skill_lv; + if((skill_lv=pc->checkskill(sd,GS_SINGLEACTION))>0 && (sd->status.weapon >= W_REVOLVER && sd->status.weapon <= W_GRENADE)) - status->aspd_rate += ((skill+1)/2) * 10; + bstatus->aspd_rate += ((skill_lv+1)/2) * 10; if(pc_isriding(sd)) - status->aspd_rate -= 500-100*pc->checkskill(sd,KN_CAVALIERMASTERY); + bstatus->aspd_rate -= 500-100*pc->checkskill(sd,KN_CAVALIERMASTERY); else if(pc_isridingdragon(sd)) - status->aspd_rate -= 250-50*pc->checkskill(sd,RK_DRAGONTRAINING); + bstatus->aspd_rate -= 250-50*pc->checkskill(sd,RK_DRAGONTRAINING); #endif - status->adelay = 2*status->amotion; + bstatus->adelay = 2*bstatus->amotion; -// ----- DMOTION ----- -// - i = 800-status->agi*4; - status->dmotion = cap_value(i, 400, 800); + // ----- DMOTION ----- + // + i = 800-bstatus->agi*4; + bstatus->dmotion = cap_value(i, 400, 800); if(battle_config.pc_damage_delay_rate != 100) - status->dmotion = status->dmotion*battle_config.pc_damage_delay_rate/100; + bstatus->dmotion = bstatus->dmotion*battle_config.pc_damage_delay_rate/100; -// ----- MISC CALCULATIONS ----- + // ----- MISC CALCULATIONS ----- // Weight - if((skill=pc->checkskill(sd,MC_INCCARRY))>0) - sd->max_weight += 2000*skill; + if((skill_lv=pc->checkskill(sd,MC_INCCARRY))>0) + sd->max_weight += 2000*skill_lv; if(pc_isriding(sd) && pc->checkskill(sd,KN_RIDING)>0) sd->max_weight += 10000; else if(pc_isridingdragon(sd)) sd->max_weight += 5000+2000*pc->checkskill(sd,RK_DRAGONTRAINING); if(sc->data[SC_KNOWLEDGE]) sd->max_weight += sd->max_weight*sc->data[SC_KNOWLEDGE]->val1/10; - if((skill=pc->checkskill(sd,ALL_INCCARRY))>0) - sd->max_weight += 2000*skill; + if((skill_lv=pc->checkskill(sd,ALL_INCCARRY))>0) + sd->max_weight += 2000*skill_lv; sd->cart_weight_max = battle_config.max_cart_weight + (pc->checkskill(sd, GN_REMODELING_CART)*5000); @@ -2991,8 +3102,8 @@ int status_calc_pc_(struct map_session_data* sd, bool first) sd->regen.state.walk = 0; // Skill SP cost - if((skill=pc->checkskill(sd,HP_MANARECHARGE))>0 ) - sd->dsprate -= 4*skill; + if((skill_lv=pc->checkskill(sd,HP_MANARECHARGE))>0 ) + sd->dsprate -= 4*skill_lv; if(sc->data[SC_SERVICEFORYOU]) sd->dsprate -= sc->data[SC_SERVICEFORYOU]->val3; @@ -3013,30 +3124,45 @@ int status_calc_pc_(struct map_session_data* sd, bool first) sd->sprecov_rate = 0; // Anti-element and anti-race - if((skill=pc->checkskill(sd,CR_TRUST))>0) - sd->subele[ELE_HOLY] += skill*5; - if((skill=pc->checkskill(sd,BS_SKINTEMPER))>0) { - sd->subele[ELE_NEUTRAL] += skill; - sd->subele[ELE_FIRE] += skill*4; - } - if((skill=pc->checkskill(sd,NC_RESEARCHFE))>0) { - sd->subele[ELE_EARTH] += skill*10; - sd->subele[ELE_FIRE] += skill*10; - } - if((skill=pc->checkskill(sd,SA_DRAGONOLOGY))>0 ){ - skill = skill*4; - sd->right_weapon.addrace[RC_DRAGON]+=skill; - sd->left_weapon.addrace[RC_DRAGON]+=skill; - sd->magic_addrace[RC_DRAGON]+=skill; - sd->subrace[RC_DRAGON]+=skill; - } - - if(sc->count){ - if(sc->data[SC_CONCENTRATION]) { //Update the card-bonus data + if((skill_lv=pc->checkskill(sd,CR_TRUST))>0) + sd->subele[ELE_HOLY] += skill_lv*5; + if((skill_lv=pc->checkskill(sd,BS_SKINTEMPER))>0) { + sd->subele[ELE_NEUTRAL] += skill_lv; + sd->subele[ELE_FIRE] += skill_lv*4; + } + if((skill_lv=pc->checkskill(sd,NC_RESEARCHFE))>0) { + sd->subele[ELE_EARTH] += skill_lv*10; + sd->subele[ELE_FIRE] += skill_lv*10; + } + if((skill_lv=pc->checkskill(sd,SA_DRAGONOLOGY))>0 ) { +#ifdef RENEWAL + skill_lv = skill_lv*2; +#else + skill_lv = skill_lv*4; +#endif + sd->right_weapon.addrace[RC_DRAGON]+=skill_lv; + sd->left_weapon.addrace[RC_DRAGON]+=skill_lv; + sd->magic_addrace[RC_DRAGON]+=skill_lv; + sd->subrace[RC_DRAGON]+=skill_lv; + } + + if( (skill_lv = pc->checkskill(sd, AB_EUCHARISTICA)) > 0 ) { + sd->right_weapon.addrace[RC_DEMON] += skill_lv; + sd->right_weapon.addele[ELE_DARK] += skill_lv; + sd->left_weapon.addrace[RC_DEMON] += skill_lv; + sd->left_weapon.addele[ELE_DARK] += skill_lv; + sd->magic_addrace[RC_DEMON] += skill_lv; + sd->magic_addele[ELE_DARK] += skill_lv; + sd->subrace[RC_DEMON] += skill_lv; + sd->subele[ELE_DARK] += skill_lv; + } + + if(sc->count) { + if(sc->data[SC_CONCENTRATION]) { //Update the card-bonus data sc->data[SC_CONCENTRATION]->val3 = sd->param_bonus[1]; //Agi sc->data[SC_CONCENTRATION]->val4 = sd->param_bonus[4]; //Dex } - if(sc->data[SC_SIEGFRIED]){ + if(sc->data[SC_SIEGFRIED]){ i = sc->data[SC_SIEGFRIED]->val2; sd->subele[ELE_WATER] += i; sd->subele[ELE_EARTH] += i; @@ -3084,6 +3210,8 @@ int status_calc_pc_(struct map_session_data* sd, bool first) sd->subele[ELE_EARTH] += i; sd->subele[ELE_FIRE] -= i; } + if( sc->data[SC_MTF_MLEATKED] ) + sd->subele[ELE_NEUTRAL] += 2; if( sc->data[SC_FIRE_INSIGNIA] && sc->data[SC_FIRE_INSIGNIA]->val1 == 3 ) sd->magic_addele[ELE_FIRE] += 25; if( sc->data[SC_WATER_INSIGNIA] && sc->data[SC_WATER_INSIGNIA]->val1 == 3 ) @@ -3093,9 +3221,9 @@ int status_calc_pc_(struct map_session_data* sd, bool first) if( sc->data[SC_EARTH_INSIGNIA] && sc->data[SC_EARTH_INSIGNIA]->val1 == 3 ) sd->magic_addele[ELE_EARTH] += 25; } - status_cpy(&sd->battle_status, status); + status_cpy(&sd->battle_status, bstatus); -// ----- CLIENT-SIDE REFRESH ----- + // ----- CLIENT-SIDE REFRESH ----- if(!sd->bl.prev) { //Will update on LoadEndAck calculating = 0; @@ -3118,218 +3246,188 @@ int status_calc_pc_(struct map_session_data* sd, bool first) return 0; } -int status_calc_mercenary_(struct mercenary_data *md, bool first) -{ - struct status_data *status = &md->base_status; +int status_calc_mercenary_(struct mercenary_data *md, enum e_status_calc_opt opt) { + struct status_data *mstatus = &md->base_status; struct s_mercenary *merc = &md->mercenary; - if( first ) - { - memcpy(status, &md->db->status, sizeof(struct status_data)); - status->mode = MD_CANMOVE|MD_CANATTACK; - status->hp = status->max_hp; - status->sp = status->max_sp; + if( opt&SCO_FIRST ) { + memcpy(mstatus, &md->db->status, sizeof(struct status_data)); + mstatus->mode = MD_CANMOVE|MD_CANATTACK; + mstatus->hp = mstatus->max_hp; + mstatus->sp = mstatus->max_sp; md->battle_status.hp = merc->hp; md->battle_status.sp = merc->sp; } - status_calc_misc(&md->bl, status, md->db->lv); - status_cpy(&md->battle_status, status); + status->calc_misc(&md->bl, mstatus, md->db->lv); + status_cpy(&md->battle_status, mstatus); return 0; } -int status_calc_homunculus_(struct homun_data *hd, bool first) -{ - struct status_data *status = &hd->base_status; +int status_calc_homunculus_(struct homun_data *hd, enum e_status_calc_opt opt) { + struct status_data *hstatus = &hd->base_status; struct s_homunculus *hom = &hd->homunculus; - int skill; + int skill_lv; int amotion; - status->str = hom->str / 10; - status->agi = hom->agi / 10; - status->vit = hom->vit / 10; - status->dex = hom->dex / 10; - status->int_ = hom->int_ / 10; - status->luk = hom->luk / 10; + hstatus->str = hom->str / 10; + hstatus->agi = hom->agi / 10; + hstatus->vit = hom->vit / 10; + hstatus->dex = hom->dex / 10; + hstatus->int_ = hom->int_ / 10; + hstatus->luk = hom->luk / 10; - if (first) { //[orn] + if ( opt&SCO_FIRST ) { //[orn] const struct s_homunculus_db *db = hd->homunculusDB; - status->def_ele = db->element; - status->ele_lv = 1; - status->race = db->race; - status->size = (hom->class_ == db->evo_class)?db->evo_size:db->base_size; - status->rhw.range = 1 + status->size; - status->mode = MD_CANMOVE|MD_CANATTACK; - status->speed = DEFAULT_WALK_SPEED; + hstatus->def_ele = db->element; + hstatus->ele_lv = 1; + hstatus->race = db->race; + hstatus->size = (hom->class_ == db->evo_class)?db->evo_size:db->base_size; + hstatus->rhw.range = 1 + hstatus->size; + hstatus->mode = MD_CANMOVE|MD_CANATTACK; + hstatus->speed = DEFAULT_WALK_SPEED; if (battle_config.hom_setting&0x8 && hd->master) - status->speed = status_get_speed(&hd->master->bl); + hstatus->speed = status->get_speed(&hd->master->bl); - status->hp = 1; - status->sp = 1; + hstatus->hp = 1; + hstatus->sp = 1; } - skill = hom->level/10 + status->vit/5; - status->def = cap_value(skill, 0, 99); + skill_lv = hom->level/10 + hstatus->vit/5; + hstatus->def = cap_value(skill_lv, 0, 99); - skill = hom->level/10 + status->int_/5; - status->mdef = cap_value(skill, 0, 99); + skill_lv = hom->level/10 + hstatus->int_/5; + hstatus->mdef = cap_value(skill_lv, 0, 99); - status->max_hp = hom->max_hp ; - status->max_sp = hom->max_sp ; + hstatus->max_hp = hom->max_hp; + hstatus->max_sp = hom->max_sp; homun->calc_skilltree(hd, 0); - if((skill=homun->checkskill(hd,HAMI_SKIN)) > 0) - status->def += skill * 4; + if((skill_lv=homun->checkskill(hd,HAMI_SKIN)) > 0) + hstatus->def += skill_lv * 4; - if((skill = homun->checkskill(hd,HVAN_INSTRUCT)) > 0) { - status->int_ += 1 +skill/2 +skill/4 +skill/5; - status->str += 1 +skill/3 +skill/3 +skill/4; + if((skill_lv = homun->checkskill(hd,HVAN_INSTRUCT)) > 0) { + hstatus->int_ += 1 +skill_lv/2 +skill_lv/4 +skill_lv/5; + hstatus->str += 1 +skill_lv/3 +skill_lv/3 +skill_lv/4; } - if((skill=homun->checkskill(hd,HAMI_SKIN)) > 0) - status->max_hp += skill * 2 * status->max_hp / 100; + if((skill_lv=homun->checkskill(hd,HAMI_SKIN)) > 0) + hstatus->max_hp += skill_lv * 2 * hstatus->max_hp / 100; - if((skill = homun->checkskill(hd,HLIF_BRAIN)) > 0) - status->max_sp += (1 +skill/2 -skill/4 +skill/5) * status->max_sp / 100 ; + if((skill_lv = homun->checkskill(hd,HLIF_BRAIN)) > 0) + hstatus->max_sp += (1 +skill_lv/2 -skill_lv/4 +skill_lv/5) * hstatus->max_sp / 100; - if (first) { - hd->battle_status.hp = hom->hp ; - hd->battle_status.sp = hom->sp ; + if ( opt&SCO_FIRST ) { + hd->battle_status.hp = hom->hp; + hd->battle_status.sp = hom->sp; } - status->rhw.atk = status->dex; - status->rhw.atk2 = status->str + hom->level; + hstatus->rhw.atk = hstatus->dex; + hstatus->rhw.atk2 = hstatus->str + hom->level; - status->aspd_rate = 1000; + hstatus->aspd_rate = 1000; - amotion = (1000 -4*status->agi -status->dex) * hd->homunculusDB->baseASPD/1000; - status->amotion = cap_value(amotion,battle_config.max_aspd,2000); - status->adelay = status->amotion; //It seems adelay = amotion for Homunculus. + amotion = (1000 -4*hstatus->agi -hstatus->dex) * hd->homunculusDB->baseASPD/1000; + hstatus->amotion = cap_value(amotion,battle_config.max_aspd,2000); + hstatus->adelay = hstatus->amotion; //It seems adelay = amotion for Homunculus. - status_calc_misc(&hd->bl, status, hom->level); + status->calc_misc(&hd->bl, hstatus, hom->level); #ifdef RENEWAL - status->matk_max = status->matk_min; + hstatus->matk_max = hstatus->matk_min; #endif - status_cpy(&hd->battle_status, status); + status_cpy(&hd->battle_status, hstatus); return 1; } -int status_calc_elemental_(struct elemental_data *ed, bool first) { - struct status_data *status = &ed->base_status; +int status_calc_elemental_(struct elemental_data *ed, enum e_status_calc_opt opt) { + struct status_data *estatus = &ed->base_status; struct s_elemental *ele = &ed->elemental; struct map_session_data *sd = ed->master; if( !sd ) return 0; - if( first ) { - memcpy(status, &ed->db->status, sizeof(struct status_data)); + if( opt&SCO_FIRST ) { + memcpy(estatus, &ed->db->status, sizeof(struct status_data)); if( !ele->mode ) - status->mode = EL_MODE_PASSIVE; + estatus->mode = EL_MODE_PASSIVE; else - status->mode = ele->mode; + estatus->mode = ele->mode; - status_calc_misc(&ed->bl, status, 0); + status->calc_misc(&ed->bl, estatus, 0); - status->max_hp = ele->max_hp; - status->max_sp = ele->max_sp; - status->hp = ele->hp; - status->sp = ele->sp; - status->rhw.atk = ele->atk; - status->rhw.atk2 = ele->atk2; + estatus->max_hp = ele->max_hp; + estatus->max_sp = ele->max_sp; + estatus->hp = ele->hp; + estatus->sp = ele->sp; + estatus->rhw.atk = ele->atk; + estatus->rhw.atk2 = ele->atk2; - status->matk_min += ele->matk; - status->def += ele->def; - status->mdef += ele->mdef; - status->flee = ele->flee; - status->hit = ele->hit; + estatus->matk_min += ele->matk; + estatus->def += ele->def; + estatus->mdef += ele->mdef; + estatus->flee = ele->flee; + estatus->hit = ele->hit; - memcpy(&ed->battle_status,status,sizeof(struct status_data)); + memcpy(&ed->battle_status,estatus,sizeof(struct status_data)); } else { - status_calc_misc(&ed->bl, status, 0); - status_cpy(&ed->battle_status, status); + status->calc_misc(&ed->bl, estatus, 0); + status_cpy(&ed->battle_status, estatus); } return 0; } -int status_calc_npc_(struct npc_data *nd, bool first) { - struct status_data *status = &nd->status; +int status_calc_npc_(struct npc_data *nd, enum e_status_calc_opt opt) { + struct status_data *nstatus = &nd->status; if (!nd) return 0; - if (first) { - status->hp = 1; - status->sp = 1; - status->max_hp = 1; - status->max_sp = 1; + if ( opt&SCO_FIRST ) { + nstatus->hp = 1; + nstatus->sp = 1; + nstatus->max_hp = 1; + nstatus->max_sp = 1; - status->def_ele = ELE_NEUTRAL; - status->ele_lv = 1; - status->race = RC_DEMIHUMAN; - status->size = nd->size; - status->rhw.range = 1 + status->size; - status->mode = (MD_CANMOVE|MD_CANATTACK); - status->speed = nd->speed; + nstatus->def_ele = ELE_NEUTRAL; + nstatus->ele_lv = 1; + nstatus->race = RC_DEMIHUMAN; + nstatus->size = nd->size; + nstatus->rhw.range = 1 + nstatus->size; + nstatus->mode = (MD_CANMOVE|MD_CANATTACK); + nstatus->speed = nd->speed; } - status->str = nd->stat_point; - status->agi = nd->stat_point; - status->vit = nd->stat_point; - status->int_= nd->stat_point; - status->dex = nd->stat_point; - status->luk = nd->stat_point; + nstatus->str = nd->stat_point; + nstatus->agi = nd->stat_point; + nstatus->vit = nd->stat_point; + nstatus->int_= nd->stat_point; + nstatus->dex = nd->stat_point; + nstatus->luk = nd->stat_point; - status_calc_misc(&nd->bl, status, nd->level); - status_cpy(&nd->status, status); + status->calc_misc(&nd->bl, nstatus, nd->level); + status_cpy(&nd->status, nstatus); return 0; } -static unsigned short status_calc_str(struct block_list *,struct status_change *,int); -static unsigned short status_calc_agi(struct block_list *,struct status_change *,int); -static unsigned short status_calc_vit(struct block_list *,struct status_change *,int); -static unsigned short status_calc_int(struct block_list *,struct status_change *,int); -static unsigned short status_calc_dex(struct block_list *,struct status_change *,int); -static unsigned short status_calc_luk(struct block_list *,struct status_change *,int); -static unsigned short status_calc_batk(struct block_list *,struct status_change *,int,bool); -static unsigned short status_calc_watk(struct block_list *,struct status_change *,int,bool); -static unsigned short status_calc_matk(struct block_list *,struct status_change *,int,bool); -static signed short status_calc_hit(struct block_list *,struct status_change *,int,bool); -static signed short status_calc_critical(struct block_list *,struct status_change *,int,bool); -static signed short status_calc_flee(struct block_list *,struct status_change *,int,bool); -static signed short status_calc_flee2(struct block_list *,struct status_change *,int,bool); -static unsigned short status_calc_speed(struct block_list *,struct status_change *,int); -static short status_calc_aspd_rate(struct block_list *,struct status_change *,int); -static unsigned short status_calc_dmotion(struct block_list *bl, struct status_change *sc, int dmotion); -#ifdef RENEWAL_ASPD -static short status_calc_aspd(struct block_list *bl, struct status_change *sc, short flag); -#endif -static short status_calc_fix_aspd(struct block_list *bl, struct status_change *sc, int); -static unsigned int status_calc_maxhp(struct block_list *,struct status_change *, uint64); -static unsigned int status_calc_maxsp(struct block_list *,struct status_change *,unsigned int); -static unsigned char status_calc_element(struct block_list *bl, struct status_change *sc, int element); -static unsigned char status_calc_element_lv(struct block_list *bl, struct status_change *sc, int lv); -static unsigned short status_calc_mode(struct block_list *bl, struct status_change *sc, int mode); -#ifdef RENEWAL -static unsigned short status_calc_ematk(struct block_list *,struct status_change *,int); -#endif //Calculates base regen values. -void status_calc_regen(struct block_list *bl, struct status_data *status, struct regen_data *regen) -{ +void status_calc_regen(struct block_list *bl, struct status_data *st, struct regen_data *regen) { struct map_session_data *sd; - int val, skill, reg_flag; + int val, skill_lv, reg_flag; + nullpo_retv(bl); + nullpo_retv(st); if( !(bl->type&BL_REGEN) || !regen ) return; sd = BL_CAST(BL_PC,bl); - val = 1 + (status->vit/5) + (status->max_hp/200); + val = 1 + (st->vit/5) + (st->max_hp/200); if( sd && sd->hprecov_rate != 100 ) val = val*sd->hprecov_rate/100; @@ -3338,38 +3436,36 @@ void status_calc_regen(struct block_list *bl, struct status_data *status, struct regen->hp = cap_value(val, reg_flag, SHRT_MAX); - val = 1 + (status->int_/6) + (status->max_sp/100); - if( status->int_ >= 120 ) - val += ((status->int_-120)>>1) + 4; + val = 1 + (st->int_/6) + (st->max_sp/100); + if( st->int_ >= 120 ) + val += ((st->int_-120)>>1) + 4; if( sd && sd->sprecov_rate != 100 ) val = val*sd->sprecov_rate/100; regen->sp = cap_value(val, reg_flag, SHRT_MAX); - if( sd ) - { + if( sd ) { struct regen_data_sub *sregen; - if( (skill=pc->checkskill(sd,HP_MEDITATIO)) > 0 ) - { - val = regen->sp*(100+3*skill)/100; + if( (skill_lv=pc->checkskill(sd,HP_MEDITATIO)) > 0 ) { + val = regen->sp*(100+3*skill_lv)/100; regen->sp = cap_value(val, 1, SHRT_MAX); } //Only players have skill/sitting skill regen for now. sregen = regen->sregen; val = 0; - if( (skill=pc->checkskill(sd,SM_RECOVERY)) > 0 ) - val += skill*5 + skill*status->max_hp/500; + if( (skill_lv=pc->checkskill(sd,SM_RECOVERY)) > 0 ) + val += skill_lv*5 + skill_lv*st->max_hp/500; sregen->hp = cap_value(val, 0, SHRT_MAX); val = 0; - if( (skill=pc->checkskill(sd,MG_SRECOVERY)) > 0 ) - val += skill*3 + skill*status->max_sp/500; - if( (skill=pc->checkskill(sd,NJ_NINPOU)) > 0 ) - val += skill*3 + skill*status->max_sp/500; - if( (skill=pc->checkskill(sd,WM_LESSON)) > 0 ) - val += 3 + 3 * skill; + if( (skill_lv=pc->checkskill(sd,MG_SRECOVERY)) > 0 ) + val += skill_lv*3 + skill_lv*st->max_sp/500; + if( (skill_lv=pc->checkskill(sd,NJ_NINPOU)) > 0 ) + val += skill_lv*3 + skill_lv*st->max_sp/500; + if( (skill_lv=pc->checkskill(sd,WM_LESSON)) > 0 ) + val += skill_lv*3 + skill_lv*st->max_sp/500; sregen->sp = cap_value(val, 0, SHRT_MAX); @@ -3377,46 +3473,45 @@ void status_calc_regen(struct block_list *bl, struct status_data *status, struct sregen = regen->ssregen; val = 0; - if( (skill=pc->checkskill(sd,MO_SPIRITSRECOVERY)) > 0 ) - val += skill*4 + skill*status->max_hp/500; + if( (skill_lv=pc->checkskill(sd,MO_SPIRITSRECOVERY)) > 0 ) + val += skill_lv*4 + skill_lv*st->max_hp/500; - if( (skill=pc->checkskill(sd,TK_HPTIME)) > 0 && sd->state.rest ) - val += skill*30 + skill*status->max_hp/500; + if( (skill_lv=pc->checkskill(sd,TK_HPTIME)) > 0 && sd->state.rest ) + val += skill_lv*30 + skill_lv*st->max_hp/500; sregen->hp = cap_value(val, 0, SHRT_MAX); val = 0; - if( (skill=pc->checkskill(sd,TK_SPTIME)) > 0 && sd->state.rest ) - { - val += skill*3 + skill*status->max_sp/500; - if ((skill=pc->checkskill(sd,SL_KAINA)) > 0) //Power up Enjoyable Rest - val += (30+10*skill)*val/100; + if( (skill_lv=pc->checkskill(sd,TK_SPTIME)) > 0 && sd->state.rest ) { + val += skill_lv*3 + skill_lv*st->max_sp/500; + if ((skill_lv=pc->checkskill(sd,SL_KAINA)) > 0) //Power up Enjoyable Rest + val += (30+10*skill_lv)*val/100; } - if( (skill=pc->checkskill(sd,MO_SPIRITSRECOVERY)) > 0 ) - val += skill*2 + skill*status->max_sp/500; + if( (skill_lv=pc->checkskill(sd,MO_SPIRITSRECOVERY)) > 0 ) + val += skill_lv*2 + skill_lv*st->max_sp/500; sregen->sp = cap_value(val, 0, SHRT_MAX); } if( bl->type == BL_HOM ) { struct homun_data *hd = (TBL_HOM*)bl; - if( (skill = homun->checkskill(hd,HAMI_SKIN)) > 0 ) { - val = regen->hp*(100+5*skill)/100; + if( (skill_lv = homun->checkskill(hd,HAMI_SKIN)) > 0 ) { + val = regen->hp*(100+5*skill_lv)/100; regen->hp = cap_value(val, 1, SHRT_MAX); } - if( (skill = homun->checkskill(hd,HLIF_BRAIN)) > 0 ) { - val = regen->sp*(100+3*skill)/100; + if( (skill_lv = homun->checkskill(hd,HLIF_BRAIN)) > 0 ) { + val = regen->sp*(100+3*skill_lv)/100; regen->sp = cap_value(val, 1, SHRT_MAX); } } else if( bl->type == BL_MER ) { - val = (status->max_hp * status->vit / 10000 + 1) * 6; + val = (st->max_hp * st->vit / 10000 + 1) * 6; regen->hp = cap_value(val, 1, SHRT_MAX); - val = (status->max_sp * (status->int_ + 10) / 750) + 1; + val = (st->max_sp * (st->int_ + 10) / 750) + 1; regen->sp = cap_value(val, 1, SHRT_MAX); } else if( bl->type == BL_ELEM ) { - val = (status->max_hp * status->vit / 10000 + 1) * 6; + val = (st->max_hp * st->vit / 10000 + 1) * 6; regen->hp = cap_value(val, 1, SHRT_MAX); - val = (status->max_sp * (status->int_ + 10) / 750) + 1; + val = (st->max_sp * (st->int_ + 10) / 750) + 1; regen->sp = cap_value(val, 1, SHRT_MAX); } } @@ -3451,87 +3546,84 @@ void status_calc_regen_rate(struct block_list *bl, struct regen_data *regen, str if (!sc || !sc->count) return; - if ( - (sc->data[SC_POISON] && !sc->data[SC_SLOWPOISON]) - || (sc->data[SC_DPOISON] && !sc->data[SC_SLOWPOISON]) - || sc->data[SC_BERSERK] || sc->data[SC__BLOODYLUST] - || sc->data[SC_TRICKDEAD] - || sc->data[SC_BLOODING] - || sc->data[SC_MAGICMUSHROOM] - || sc->data[SC_RAISINGDRAGON] - || sc->data[SC_SATURDAY_NIGHT_FEVER] + if ((sc->data[SC_POISON] && !sc->data[SC_SLOWPOISON]) + || (sc->data[SC_DPOISON] && !sc->data[SC_SLOWPOISON]) + || sc->data[SC_BERSERK] + || sc->data[SC_TRICKDEAD] + || sc->data[SC_BLOODING] + || sc->data[SC_MAGICMUSHROOM] + || sc->data[SC_RAISINGDRAGON] + || sc->data[SC_SATURDAY_NIGHT_FEVER] ) //No regen regen->flag = 0; - if ( - sc->data[SC_DANCING] || sc->data[SC_OBLIVIONCURSE] || sc->data[SC_MAXIMIZEPOWER] || sc->data[SC_REBOUND] - || ( - (bl->type == BL_PC && ((TBL_PC*)bl)->class_&MAPID_UPPERMASK) == MAPID_MONK && - (sc->data[SC_EXTREMITYFIST] || (sc->data[SC_EXPLOSIONSPIRITS] && (!sc->data[SC_SOULLINK] || sc->data[SC_SOULLINK]->val2 != SL_MONK))) - ) - ) //No natural SP regen - regen->flag &=~RGN_SP; + if ( sc->data[SC_DANCING] || sc->data[SC_OBLIVIONCURSE] || sc->data[SC_MAXIMIZEPOWER] || sc->data[SC_REBOUND] + || ( bl->type == BL_PC && (((TBL_PC*)bl)->class_&MAPID_UPPERMASK) == MAPID_MONK + && (sc->data[SC_EXTREMITYFIST] || (sc->data[SC_EXPLOSIONSPIRITS] && (!sc->data[SC_SOULLINK] || sc->data[SC_SOULLINK]->val2 != SL_MONK))) + ) + ) { + regen->flag &=~RGN_SP; //No natural SP regen + } - if( - sc->data[SC_TENSIONRELAX] - ) { + if (sc->data[SC_TENSIONRELAX]) { regen->rate.hp += 2; if (regen->sregen) regen->sregen->rate.hp += 3; } - if (sc->data[SC_MAGNIFICAT]) - { + if (sc->data[SC_MAGNIFICAT]) { regen->rate.hp += 1; regen->rate.sp += 1; } - if (sc->data[SC_GDSKILL_REGENERATION]) - { + if (sc->data[SC_GDSKILL_REGENERATION]) { const struct status_change_entry *sce = sc->data[SC_GDSKILL_REGENERATION]; - if (!sce->val4) - { + if (!sce->val4) { regen->rate.hp += sce->val2; regen->rate.sp += sce->val3; } else regen->flag&=~sce->val4; //Remove regen as specified by val4 } - if(sc->data[SC_GENTLETOUCH_REVITALIZE]){ + if(sc->data[SC_GENTLETOUCH_REVITALIZE]) { regen->hp = cap_value(regen->hp*sc->data[SC_GENTLETOUCH_REVITALIZE]->val3/100, 1, SHRT_MAX); regen->state.walk= 1; } - if ((sc->data[SC_FIRE_INSIGNIA] && sc->data[SC_FIRE_INSIGNIA]->val1 == 1) //if insignia lvl 1 - || (sc->data[SC_WATER_INSIGNIA] && sc->data[SC_WATER_INSIGNIA]->val1 == 1) - || (sc->data[SC_EARTH_INSIGNIA] && sc->data[SC_EARTH_INSIGNIA]->val1 == 1) - || (sc->data[SC_WIND_INSIGNIA] && sc->data[SC_WIND_INSIGNIA]->val1 == 1)) - regen->rate.hp *= 2; - + if ((sc->data[SC_FIRE_INSIGNIA] && sc->data[SC_FIRE_INSIGNIA]->val1 == 1) //if insignia lvl 1 + || (sc->data[SC_WATER_INSIGNIA] && sc->data[SC_WATER_INSIGNIA]->val1 == 1) + || (sc->data[SC_EARTH_INSIGNIA] && sc->data[SC_EARTH_INSIGNIA]->val1 == 1) + || (sc->data[SC_WIND_INSIGNIA] && sc->data[SC_WIND_INSIGNIA]->val1 == 1)) + regen->rate.hp *= 2; + if( sc->data[SC_VITALITYACTIVATION] ) + regen->flag &=~RGN_SP; + if(sc->data[SC_EXTRACT_WHITE_POTION_Z]) + regen->rate.hp += regen->rate.hp * sc->data[SC_EXTRACT_WHITE_POTION_Z]->val1/100; + if(sc->data[SC_VITATA_500]) + regen->rate.sp += regen->rate.sp * sc->data[SC_VITATA_500]->val1/100; } /// Recalculates parts of an object's battle status according to the specified flags. /// @param flag bitfield of values from enum scb_flag -void status_calc_bl_main(struct block_list *bl, /*enum scb_flag*/int flag) -{ - const struct status_data *b_status = status_get_base_status(bl); - struct status_data *status = status_get_status_data(bl); - struct status_change *sc = status_get_sc(bl); +void status_calc_bl_main(struct block_list *bl, /*enum scb_flag*/int flag) { + const struct status_data *bst = status->get_base_status(bl); + struct status_data *st = status->get_status_data(bl); + struct status_change *sc = status->get_sc(bl); TBL_PC *sd = BL_CAST(BL_PC,bl); int temp; - if (!b_status || !status) + if (!bst || !st) return; if((!(bl->type&BL_REGEN)) && (!sc || !sc->count)) { //No difference. - status_cpy(status, b_status); + status_cpy(st, bst); return; } if(flag&SCB_STR) { - status->str = status_calc_str(bl, sc, b_status->str); + st->str = status->calc_str(bl, sc, bst->str); flag|=SCB_BATK; if( bl->type&BL_HOM ) flag |= SCB_WATK; } if(flag&SCB_AGI) { - status->agi = status_calc_agi(bl, sc, b_status->agi); + st->agi = status->calc_agi(bl, sc, bst->agi); flag|=SCB_FLEE #ifdef RENEWAL |SCB_DEF2 @@ -3542,7 +3634,7 @@ void status_calc_bl_main(struct block_list *bl, /*enum scb_flag*/int flag) } if(flag&SCB_VIT) { - status->vit = status_calc_vit(bl, sc, b_status->vit); + st->vit = status->calc_vit(bl, sc, bst->vit); flag|=SCB_DEF2|SCB_MDEF2; if( bl->type&(BL_PC|BL_HOM|BL_MER|BL_ELEM) ) flag |= SCB_MAXHP; @@ -3551,7 +3643,7 @@ void status_calc_bl_main(struct block_list *bl, /*enum scb_flag*/int flag) } if(flag&SCB_INT) { - status->int_ = status_calc_int(bl, sc, b_status->int_); + st->int_ = status->calc_int(bl, sc, bst->int_); flag|=SCB_MATK|SCB_MDEF2; if( bl->type&(BL_PC|BL_HOM|BL_MER|BL_ELEM) ) flag |= SCB_MAXSP; @@ -3560,7 +3652,7 @@ void status_calc_bl_main(struct block_list *bl, /*enum scb_flag*/int flag) } if(flag&SCB_DEX) { - status->dex = status_calc_dex(bl, sc, b_status->dex); + st->dex = status->calc_dex(bl, sc, bst->dex); flag|=SCB_BATK|SCB_HIT #ifdef RENEWAL |SCB_MATK|SCB_MDEF2 @@ -3573,7 +3665,7 @@ void status_calc_bl_main(struct block_list *bl, /*enum scb_flag*/int flag) } if(flag&SCB_LUK) { - status->luk = status_calc_luk(bl, sc, b_status->luk); + st->luk = status->calc_luk(bl, sc, bst->luk); flag|=SCB_BATK|SCB_CRI|SCB_FLEE2 #ifdef RENEWAL |SCB_MATK|SCB_HIT|SCB_FLEE @@ -3581,500 +3673,486 @@ void status_calc_bl_main(struct block_list *bl, /*enum scb_flag*/int flag) ; } - if(flag&SCB_BATK && b_status->batk) { - status->batk = status_base_atk(bl,status); - temp = b_status->batk - status_base_atk(bl,b_status); - if (temp) - { - temp += status->batk; - status->batk = cap_value(temp, 0, USHRT_MAX); + if(flag&SCB_BATK && bst->batk) { + st->batk = status->base_atk(bl,st); + temp = bst->batk - status->base_atk(bl,bst); + if (temp) { + temp += st->batk; + st->batk = cap_value(temp, 0, USHRT_MAX); } - status->batk = status_calc_batk(bl, sc, status->batk, true); + st->batk = status->calc_batk(bl, sc, st->batk, true); } - if(flag&SCB_WATK) { - status->rhw.atk = status_calc_watk(bl, sc, b_status->rhw.atk, true); + if(flag&SCB_WATK) { + st->rhw.atk = status->calc_watk(bl, sc, bst->rhw.atk, true); if (!sd) //Should not affect weapon refine bonus - status->rhw.atk2 = status_calc_watk(bl, sc, b_status->rhw.atk2, true); + st->rhw.atk2 = status->calc_watk(bl, sc, bst->rhw.atk2, true); - if(b_status->lhw.atk) { + if(bst->lhw.atk) { if (sd) { sd->state.lr_flag = 1; - status->lhw.atk = status_calc_watk(bl, sc, b_status->lhw.atk, true); + st->lhw.atk = status->calc_watk(bl, sc, bst->lhw.atk, true); sd->state.lr_flag = 0; } else { - status->lhw.atk = status_calc_watk(bl, sc, b_status->lhw.atk, true); - status->lhw.atk2 = status_calc_watk(bl, sc, b_status->lhw.atk2, true); + st->lhw.atk = status->calc_watk(bl, sc, bst->lhw.atk, true); + st->lhw.atk2 = status->calc_watk(bl, sc, bst->lhw.atk2, true); } } - if( bl->type&BL_HOM ) - { - status->rhw.atk += (status->dex - b_status->dex); - status->rhw.atk2 += (status->str - b_status->str); - if( status->rhw.atk2 < status->rhw.atk ) - status->rhw.atk2 = status->rhw.atk; + if( bl->type&BL_HOM ) { + st->rhw.atk += (st->dex - bst->dex); + st->rhw.atk2 += (st->str - bst->str); + if( st->rhw.atk2 < st->rhw.atk ) + st->rhw.atk2 = st->rhw.atk; } } if(flag&SCB_HIT) { - if (status->dex == b_status->dex + if (st->dex == bst->dex #ifdef RENEWAL - && status->luk == b_status->luk + && st->luk == bst->luk #endif ) - status->hit = status_calc_hit(bl, sc, b_status->hit, true); + st->hit = status->calc_hit(bl, sc, bst->hit, true); else - status->hit = status_calc_hit(bl, sc, b_status->hit + (status->dex - b_status->dex) + st->hit = status->calc_hit(bl, sc, bst->hit + (st->dex - bst->dex) #ifdef RENEWAL - + (status->luk/3 - b_status->luk/3) + + (st->luk/3 - bst->luk/3) #endif - , true); + , true); } if(flag&SCB_FLEE) { - if (status->agi == b_status->agi + if (st->agi == bst->agi #ifdef RENEWAL - && status->luk == b_status->luk + && st->luk == bst->luk #endif ) - status->flee = status_calc_flee(bl, sc, b_status->flee, true); + st->flee = status->calc_flee(bl, sc, bst->flee, true); else - status->flee = status_calc_flee(bl, sc, b_status->flee +(status->agi - b_status->agi) + st->flee = status->calc_flee(bl, sc, bst->flee +(st->agi - bst->agi) #ifdef RENEWAL - + (status->luk/5 - b_status->luk/5) + + (st->luk/5 - bst->luk/5) #endif , true); } - if(flag&SCB_DEF) - { - status->def = status_calc_def(bl, sc, b_status->def, true); + if(flag&SCB_DEF) { + st->def = status->calc_def(bl, sc, bst->def, true); if( bl->type&BL_HOM ) - status->def += (status->vit/5 - b_status->vit/5); + st->def += (st->vit/5 - bst->vit/5); } if(flag&SCB_DEF2) { - if (status->vit == b_status->vit + if (st->vit == bst->vit #ifdef RENEWAL - && status->agi == b_status->agi + && st->agi == bst->agi #endif ) - status->def2 = status_calc_def2(bl, sc, b_status->def2, true); + st->def2 = status->calc_def2(bl, sc, bst->def2, true); else - status->def2 = status_calc_def2(bl, sc, b_status->def2 + st->def2 = status->calc_def2(bl, sc, bst->def2 #ifdef RENEWAL - + (int)( ((float)status->vit/2 - (float)b_status->vit/2) + ((float)status->agi/5 - (float)b_status->agi/5) ) + + (int)( ((float)st->vit/2 - (float)bst->vit/2) + ((float)st->agi/5 - (float)bst->agi/5) ) #else - + (status->vit - b_status->vit) + + (st->vit - bst->vit) #endif - , true); + , true); } - if(flag&SCB_MDEF) - { - status->mdef = status_calc_mdef(bl, sc, b_status->mdef, true); + if(flag&SCB_MDEF) { + st->mdef = status->calc_mdef(bl, sc, bst->mdef, true); if( bl->type&BL_HOM ) - status->mdef += (status->int_/5 - b_status->int_/5); + st->mdef += (st->int_/5 - bst->int_/5); } if(flag&SCB_MDEF2) { - if (status->int_ == b_status->int_ && status->vit == b_status->vit + if (st->int_ == bst->int_ && st->vit == bst->vit #ifdef RENEWAL - && status->dex == b_status->dex + && st->dex == bst->dex #endif ) - status->mdef2 = status_calc_mdef2(bl, sc, b_status->mdef2, true); + st->mdef2 = status->calc_mdef2(bl, sc, bst->mdef2, true); else - status->mdef2 = status_calc_mdef2(bl, sc, b_status->mdef2 +(status->int_ - b_status->int_) + st->mdef2 = status->calc_mdef2(bl, sc, bst->mdef2 +(st->int_ - bst->int_) #ifdef RENEWAL - + (int)( ((float)status->dex/5 - (float)b_status->dex/5) + ((float)status->vit/5 - (float)b_status->vit/5) ) + + (int)( ((float)st->dex/5 - (float)bst->dex/5) + ((float)st->vit/5 - (float)bst->vit/5) ) #else - + ((status->vit - b_status->vit)>>1) + + ((st->vit - bst->vit)>>1) #endif , true); } if(flag&SCB_SPEED) { - struct unit_data *ud = unit_bl2ud(bl); - status->speed = status_calc_speed(bl, sc, b_status->speed); + struct unit_data *ud = unit->bl2ud(bl); + + st->speed = status->calc_speed(bl, sc, bst->speed); //Re-walk to adjust speed (we do not check if walktimer != INVALID_TIMER //because if you step on something while walking, the moment this //piece of code triggers the walk-timer is set on INVALID_TIMER) [Skotlex] - if (ud) + if (ud) ud->state.change_walk_target = ud->state.speed_changed = 1; - if( bl->type&BL_PC && status->speed < battle_config.max_walk_speed ) - status->speed = battle_config.max_walk_speed; + if( bl->type&BL_PC && !(sd && sd->state.permanent_speed) && st->speed < battle_config.max_walk_speed ) + st->speed = battle_config.max_walk_speed; if( bl->type&BL_HOM && battle_config.hom_setting&0x8 && ((TBL_HOM*)bl)->master) - status->speed = status_get_speed(&((TBL_HOM*)bl)->master->bl); - - + st->speed = status->get_speed(&((TBL_HOM*)bl)->master->bl); } - if(flag&SCB_CRI && b_status->cri) { - if (status->luk == b_status->luk) - status->cri = status_calc_critical(bl, sc, b_status->cri, true); + if(flag&SCB_CRI && bst->cri) { + if (st->luk == bst->luk) + st->cri = status->calc_critical(bl, sc, bst->cri, true); else - status->cri = status_calc_critical(bl, sc, b_status->cri + 3*(status->luk - b_status->luk), true); + st->cri = status->calc_critical(bl, sc, bst->cri + 3*(st->luk - bst->luk), true); /** - * after status_calc_critical so the bonus is applied despite if you have or not a sc bugreport:5240 - **/ + * after status_calc_critical so the bonus is applied despite if you have or not a sc bugreport:5240 + **/ if( bl->type == BL_PC && ((TBL_PC*)bl)->status.weapon == W_KATAR ) - status->cri <<= 1; + st->cri <<= 1; } - if(flag&SCB_FLEE2 && b_status->flee2) { - if (status->luk == b_status->luk) - status->flee2 = status_calc_flee2(bl, sc, b_status->flee2, true); + if(flag&SCB_FLEE2 && bst->flee2) { + if (st->luk == bst->luk) + st->flee2 = status->calc_flee2(bl, sc, bst->flee2, true); else - status->flee2 = status_calc_flee2(bl, sc, b_status->flee2 +(status->luk - b_status->luk), true); + st->flee2 = status->calc_flee2(bl, sc, bst->flee2 +(st->luk - bst->luk), true); } if(flag&SCB_ATK_ELE) { - status->rhw.ele = status_calc_attack_element(bl, sc, b_status->rhw.ele); + st->rhw.ele = status->calc_attack_element(bl, sc, bst->rhw.ele); if (sd) sd->state.lr_flag = 1; - status->lhw.ele = status_calc_attack_element(bl, sc, b_status->lhw.ele); + st->lhw.ele = status->calc_attack_element(bl, sc, bst->lhw.ele); if (sd) sd->state.lr_flag = 0; } if(flag&SCB_DEF_ELE) { - status->def_ele = status_calc_element(bl, sc, b_status->def_ele); - status->ele_lv = status_calc_element_lv(bl, sc, b_status->ele_lv); + st->def_ele = status->calc_element(bl, sc, bst->def_ele); + st->ele_lv = status->calc_element_lv(bl, sc, bst->ele_lv); } - if(flag&SCB_MODE) - { - status->mode = status_calc_mode(bl, sc, b_status->mode); + if(flag&SCB_MODE) { + st->mode = status->calc_mode(bl, sc, bst->mode); //Since mode changed, reset their state. - if (!(status->mode&MD_CANATTACK)) - unit_stop_attack(bl); - if (!(status->mode&MD_CANMOVE)) - unit_stop_walking(bl,1); + if (!(st->mode&MD_CANATTACK)) + unit->stop_attack(bl); + if (!(st->mode&MD_CANMOVE)) + unit->stop_walking(bl,1); } -// No status changes alter these yet. -// if(flag&SCB_SIZE) -// if(flag&SCB_RACE) -// if(flag&SCB_RANGE) + // No status changes alter these yet. + // if(flag&SCB_SIZE) + // if(flag&SCB_RACE) + // if(flag&SCB_RANGE) if(flag&SCB_MAXHP) { - if( bl->type&BL_PC ) - { - status->max_hp = status_base_pc_maxhp(sd,status); - status->max_hp += b_status->max_hp - sd->status.max_hp; + if( bl->type&BL_PC ) { + st->max_hp = status->base_pc_maxhp(sd,st); + st->max_hp += bst->max_hp - sd->status.max_hp; - status->max_hp = status_calc_maxhp(bl, sc, status->max_hp); + st->max_hp = status->calc_maxhp(bl, sc, st->max_hp); - if( status->max_hp > (unsigned int)battle_config.max_hp ) - status->max_hp = (unsigned int)battle_config.max_hp; - } - else - { - status->max_hp = status_calc_maxhp(bl, sc, b_status->max_hp); + if( st->max_hp > (unsigned int)battle_config.max_hp ) + st->max_hp = (unsigned int)battle_config.max_hp; + } else { + st->max_hp = status->calc_maxhp(bl, sc, bst->max_hp); } - if( status->hp > status->max_hp ) //FIXME: Should perhaps a status_zap should be issued? - { - status->hp = status->max_hp; + if( st->hp > st->max_hp ) { + //FIXME: Should perhaps a status_zap should be issued? + st->hp = st->max_hp; if( sd ) clif->updatestatus(sd,SP_HP); } } if(flag&SCB_MAXSP) { - if( bl->type&BL_PC ) - { - status->max_sp = status_base_pc_maxsp(sd,status); - status->max_sp += b_status->max_sp - sd->status.max_sp; + if( bl->type&BL_PC ) { + st->max_sp = status->base_pc_maxsp(sd,st); + st->max_sp += bst->max_sp - sd->status.max_sp; - status->max_sp = status_calc_maxsp(&sd->bl, &sd->sc, status->max_sp); + st->max_sp = status->calc_maxsp(&sd->bl, &sd->sc, st->max_sp); - if( status->max_sp > (unsigned int)battle_config.max_sp ) - status->max_sp = (unsigned int)battle_config.max_sp; - } - else - { - status->max_sp = status_calc_maxsp(bl, sc, b_status->max_sp); + if( st->max_sp > (unsigned int)battle_config.max_sp ) + st->max_sp = (unsigned int)battle_config.max_sp; + } else { + st->max_sp = status->calc_maxsp(bl, sc, bst->max_sp); } - if( status->sp > status->max_sp ) - { - status->sp = status->max_sp; + if( st->sp > st->max_sp ) { + st->sp = st->max_sp; if( sd ) clif->updatestatus(sd,SP_SP); } } - if(flag&SCB_MATK) { - status_get_matk(bl, 0); + if(flag&SCB_MATK) { + status->update_matk(bl); } if(flag&SCB_ASPD) { int amotion; - if( bl->type&BL_PC ) - { - amotion = status_base_amotion_pc(sd,status); + if( bl->type&BL_PC ) { + amotion = status->base_amotion_pc(sd,st); #ifndef RENEWAL_ASPD - status->aspd_rate = status_calc_aspd_rate(bl, sc, b_status->aspd_rate); + st->aspd_rate = status->calc_aspd_rate(bl, sc, bst->aspd_rate); - if(status->aspd_rate != 1000) - amotion = amotion*status->aspd_rate/1000; + if(st->aspd_rate != 1000) + amotion = amotion*st->aspd_rate/1000; #else // aspd = baseaspd + floor(sqrt((agi^2/2) + (dex^2/5))/4 + (potskillbonus*agi/200)) - amotion -= (int)(sqrt( (pow(status->agi, 2) / 2) + (pow(status->dex, 2) / 5) ) / 4 + ((float)status_calc_aspd(bl, sc, 1) * status->agi / 200)) * 10; + amotion -= (int)(sqrt( (pow(st->agi, 2) / 2) + (pow(st->dex, 2) / 5) ) / 4 + ((float)status->calc_aspd(bl, sc, 1) * st->agi / 200)) * 10; - if( (status_calc_aspd(bl, sc, 2) + status->aspd_rate2) != 0 ) // RE ASPD percertage modifier + if( (status->calc_aspd(bl, sc, 2) + st->aspd_rate2) != 0 ) // RE ASPD percertage modifier amotion -= (( amotion - ((sd->class_&JOBL_THIRD) ? battle_config.max_third_aspd : battle_config.max_aspd) ) - * (status_calc_aspd(bl, sc, 2) + status->aspd_rate2) / 10 + 5) / 10; + * (status->calc_aspd(bl, sc, 2) + st->aspd_rate2) / 10 + 5) / 10; - if(status->aspd_rate != 1000) // absolute percentage modifier - amotion = ( 200 - (200-amotion/10) * status->aspd_rate / 1000 ) * 10; + if(st->aspd_rate != 1000) // absolute percentage modifier + amotion = ( 200 - (200-amotion/10) * st->aspd_rate / 1000 ) * 10; #endif - amotion = status_calc_fix_aspd(bl, sc, amotion); - status->amotion = cap_value(amotion,((sd->class_&JOBL_THIRD) ? battle_config.max_third_aspd : battle_config.max_aspd),2000); + amotion = status->calc_fix_aspd(bl, sc, amotion); + st->amotion = cap_value(amotion,((sd->class_&JOBL_THIRD) ? battle_config.max_third_aspd : battle_config.max_aspd),2000); - status->adelay = 2*status->amotion; - } - else - if( bl->type&BL_HOM ) - { - amotion = (1000 -4*status->agi -status->dex) * ((TBL_HOM*)bl)->homunculusDB->baseASPD/1000; - status->aspd_rate = status_calc_aspd_rate(bl, sc, b_status->aspd_rate); + st->adelay = 2*st->amotion; + } else if( bl->type&BL_HOM ) { + amotion = (1000 - 4*st->agi - st->dex) * ((TBL_HOM*)bl)->homunculusDB->baseASPD/1000; + st->aspd_rate = status->calc_aspd_rate(bl, sc, bst->aspd_rate); - if(status->aspd_rate != 1000) - amotion = amotion*status->aspd_rate/1000; + if(st->aspd_rate != 1000) + amotion = amotion*st->aspd_rate/1000; - amotion = status_calc_fix_aspd(bl, sc, amotion); - status->amotion = cap_value(amotion,battle_config.max_aspd,2000); + amotion = status->calc_fix_aspd(bl, sc, amotion); + st->amotion = cap_value(amotion,battle_config.max_aspd,2000); - status->adelay = status->amotion; - } - else // mercenary and mobs - { - amotion = b_status->amotion; - status->aspd_rate = status_calc_aspd_rate(bl, sc, b_status->aspd_rate); + st->adelay = st->amotion; + } else { // mercenary and mobs + amotion = bst->amotion; + st->aspd_rate = status->calc_aspd_rate(bl, sc, bst->aspd_rate); - if(status->aspd_rate != 1000) - amotion = amotion*status->aspd_rate/1000; + if(st->aspd_rate != 1000) + amotion = amotion*st->aspd_rate/1000; - amotion = status_calc_fix_aspd(bl, sc, amotion); - status->amotion = cap_value(amotion, battle_config.monster_max_aspd, 2000); + amotion = status->calc_fix_aspd(bl, sc, amotion); + st->amotion = cap_value(amotion, battle_config.monster_max_aspd, 2000); - temp = b_status->adelay*status->aspd_rate/1000; - status->adelay = cap_value(temp, battle_config.monster_max_aspd*2, 4000); + temp = bst->adelay*st->aspd_rate/1000; + st->adelay = cap_value(temp, battle_config.monster_max_aspd*2, 4000); } } if(flag&SCB_DSPD) { int dmotion; - if( bl->type&BL_PC ) - { - if (b_status->agi == status->agi) - status->dmotion = status_calc_dmotion(bl, sc, b_status->dmotion); + if( bl->type&BL_PC ) { + if (bst->agi == st->agi) + st->dmotion = status->calc_dmotion(bl, sc, bst->dmotion); else { - dmotion = 800-status->agi*4; - status->dmotion = cap_value(dmotion, 400, 800); + dmotion = 800-st->agi*4; + st->dmotion = cap_value(dmotion, 400, 800); if(battle_config.pc_damage_delay_rate != 100) - status->dmotion = status->dmotion*battle_config.pc_damage_delay_rate/100; - //It's safe to ignore b_status->dmotion since no bonus affects it. - status->dmotion = status_calc_dmotion(bl, sc, status->dmotion); + st->dmotion = st->dmotion*battle_config.pc_damage_delay_rate/100; + //It's safe to ignore bst->dmotion since no bonus affects it. + st->dmotion = status->calc_dmotion(bl, sc, st->dmotion); } - } - else - if( bl->type&BL_HOM ) - { - dmotion = 800-status->agi*4; - status->dmotion = cap_value(dmotion, 400, 800); - status->dmotion = status_calc_dmotion(bl, sc, b_status->dmotion); - } - else // mercenary and mobs - { - status->dmotion = status_calc_dmotion(bl, sc, b_status->dmotion); + } else if( bl->type&BL_HOM ) { + dmotion = 800-st->agi*4; + st->dmotion = cap_value(dmotion, 400, 800); + st->dmotion = status->calc_dmotion(bl, sc, bst->dmotion); + } else { // mercenary and mobs + st->dmotion = status->calc_dmotion(bl, sc, bst->dmotion); } } if(flag&(SCB_VIT|SCB_MAXHP|SCB_INT|SCB_MAXSP) && bl->type&BL_REGEN) - status_calc_regen(bl, status, status_get_regen_data(bl)); + status->calc_regen(bl, st, status->get_regen_data(bl)); if(flag&SCB_REGEN && bl->type&BL_REGEN) - status_calc_regen_rate(bl, status_get_regen_data(bl), sc); + status->calc_regen_rate(bl, status->get_regen_data(bl), sc); } /// Recalculates parts of an object's base status and battle status according to the specified flags. /// Also sends updates to the client wherever applicable. /// @param flag bitfield of values from enum scb_flag /// @param first if true, will cause status_calc_* functions to run their base status initialization code -void status_calc_bl_(struct block_list* bl, enum scb_flag flag, bool first) -{ - struct status_data b_status; // previous battle status - struct status_data* status; // pointer to current battle status +void status_calc_bl_(struct block_list *bl, enum scb_flag flag, enum e_status_calc_opt opt) { + struct status_data bst; // previous battle status + struct status_data *st; // pointer to current battle status + if( bl->type == BL_PC && ((TBL_PC*)bl)->delayed_damage != 0 ) { + if( opt&SCO_FORCE ) + ((TBL_PC*)bl)->state.hold_recalc = 0;/* clear and move on */ + else { + ((TBL_PC*)bl)->state.hold_recalc = 1;/* flag and stop */ + return; + } + } + // remember previous values - status = status_get_status_data(bl); - memcpy(&b_status, status, sizeof(struct status_data)); + st = status->get_status_data(bl); + memcpy(&bst, st, sizeof(struct status_data)); if( flag&SCB_BASE ) {// calculate the object's base status too switch( bl->type ) { - case BL_PC: status_calc_pc_(BL_CAST(BL_PC,bl), first); break; - case BL_MOB: status_calc_mob_(BL_CAST(BL_MOB,bl), first); break; - case BL_PET: status_calc_pet_(BL_CAST(BL_PET,bl), first); break; - case BL_HOM: status_calc_homunculus_(BL_CAST(BL_HOM,bl), first); break; - case BL_MER: status_calc_mercenary_(BL_CAST(BL_MER,bl), first); break; - case BL_ELEM: status_calc_elemental_(BL_CAST(BL_ELEM,bl), first); break; - case BL_NPC: status_calc_npc_(BL_CAST(BL_NPC,bl), first); break; + case BL_PC: status->calc_pc_(BL_CAST(BL_PC,bl), opt); break; + case BL_MOB: status->calc_mob_(BL_CAST(BL_MOB,bl), opt); break; + case BL_PET: status->calc_pet_(BL_CAST(BL_PET,bl), opt); break; + case BL_HOM: status->calc_homunculus_(BL_CAST(BL_HOM,bl), opt); break; + case BL_MER: status->calc_mercenary_(BL_CAST(BL_MER,bl), opt); break; + case BL_ELEM: status->calc_elemental_(BL_CAST(BL_ELEM,bl), opt); break; + case BL_NPC: status->calc_npc_(BL_CAST(BL_NPC,bl), opt); break; } } if( bl->type == BL_PET ) return; // pets are not affected by statuses - if( first && bl->type == BL_MOB ) + if( opt&SCO_FIRST && bl->type == BL_MOB ) return; // assume there will be no statuses active - status_calc_bl_main(bl, flag); + status->calc_bl_main(bl, flag); - if( first && bl->type == BL_HOM ) + if( opt&SCO_FIRST && bl->type == BL_HOM ) return; // client update handled by caller // compare against new values and send client updates - if( bl->type == BL_PC ) - { + if( bl->type == BL_PC ) { TBL_PC* sd = BL_CAST(BL_PC, bl); - if(b_status.str != status->str) + if(bst.str != st->str) clif->updatestatus(sd,SP_STR); - if(b_status.agi != status->agi) + if(bst.agi != st->agi) clif->updatestatus(sd,SP_AGI); - if(b_status.vit != status->vit) + if(bst.vit != st->vit) clif->updatestatus(sd,SP_VIT); - if(b_status.int_ != status->int_) + if(bst.int_ != st->int_) clif->updatestatus(sd,SP_INT); - if(b_status.dex != status->dex) + if(bst.dex != st->dex) clif->updatestatus(sd,SP_DEX); - if(b_status.luk != status->luk) + if(bst.luk != st->luk) clif->updatestatus(sd,SP_LUK); - if(b_status.hit != status->hit) + if(bst.hit != st->hit) clif->updatestatus(sd,SP_HIT); - if(b_status.flee != status->flee) + if(bst.flee != st->flee) clif->updatestatus(sd,SP_FLEE1); - if(b_status.amotion != status->amotion) + if(bst.amotion != st->amotion) clif->updatestatus(sd,SP_ASPD); - if(b_status.speed != status->speed) + if(bst.speed != st->speed) clif->updatestatus(sd,SP_SPEED); - if(b_status.batk != status->batk + if(bst.batk != st->batk #ifndef RENEWAL - || b_status.rhw.atk != status->rhw.atk || b_status.lhw.atk != status->lhw.atk + || bst.rhw.atk != st->rhw.atk || bst.lhw.atk != st->lhw.atk #endif - ) + ) clif->updatestatus(sd,SP_ATK1); - if(b_status.def != status->def){ + if(bst.def != st->def) { clif->updatestatus(sd,SP_DEF1); #ifdef RENEWAL clif->updatestatus(sd,SP_DEF2); #endif } - if(b_status.rhw.atk2 != status->rhw.atk2 || b_status.lhw.atk2 != status->lhw.atk2 + if(bst.rhw.atk2 != st->rhw.atk2 || bst.lhw.atk2 != st->lhw.atk2 #ifdef RENEWAL - || b_status.rhw.atk != status->rhw.atk || b_status.lhw.atk != status->lhw.atk + || bst.rhw.atk != st->rhw.atk || bst.lhw.atk != st->lhw.atk #endif ) clif->updatestatus(sd,SP_ATK2); - if(b_status.def2 != status->def2){ + if(bst.def2 != st->def2){ clif->updatestatus(sd,SP_DEF2); #ifdef RENEWAL clif->updatestatus(sd,SP_DEF1); #endif } - if(b_status.flee2 != status->flee2) + if(bst.flee2 != st->flee2) clif->updatestatus(sd,SP_FLEE2); - if(b_status.cri != status->cri) + if(bst.cri != st->cri) clif->updatestatus(sd,SP_CRITICAL); #ifndef RENEWAL - if(b_status.matk_max != status->matk_max) + if(bst.matk_max != st->matk_max) clif->updatestatus(sd,SP_MATK1); - if(b_status.matk_min != status->matk_min) - clif->updatestatus(sd,SP_MATK2); + if(bst.matk_min != st->matk_min) + clif->updatestatus(sd,SP_MATK2); #else - if(b_status.matk_max != status->matk_max || b_status.matk_min != status->matk_min){ + if(bst.matk_max != st->matk_max || bst.matk_min != st->matk_min){ clif->updatestatus(sd,SP_MATK2); clif->updatestatus(sd,SP_MATK1); } #endif - if(b_status.mdef != status->mdef){ + if(bst.mdef != st->mdef) { clif->updatestatus(sd,SP_MDEF1); #ifdef RENEWAL clif->updatestatus(sd,SP_MDEF2); #endif } - if(b_status.mdef2 != status->mdef2){ + if(bst.mdef2 != st->mdef2) { clif->updatestatus(sd,SP_MDEF2); #ifdef RENEWAL clif->updatestatus(sd,SP_MDEF1); #endif } - if(b_status.rhw.range != status->rhw.range) + if(bst.rhw.range != st->rhw.range) clif->updatestatus(sd,SP_ATTACKRANGE); - if(b_status.max_hp != status->max_hp) + if(bst.max_hp != st->max_hp) clif->updatestatus(sd,SP_MAXHP); - if(b_status.max_sp != status->max_sp) + if(bst.max_sp != st->max_sp) clif->updatestatus(sd,SP_MAXSP); - if(b_status.hp != status->hp) + if(bst.hp != st->hp) clif->updatestatus(sd,SP_HP); - if(b_status.sp != status->sp) + if(bst.sp != st->sp) clif->updatestatus(sd,SP_SP); +#ifdef RENEWAL + if(bst.equip_atk != st->equip_atk) + clif->updatestatus(sd,SP_ATK2); +#endif } else if( bl->type == BL_HOM ) { TBL_HOM* hd = BL_CAST(BL_HOM, bl); - if( hd->master && memcmp(&b_status, status, sizeof(struct status_data)) != 0 ) + if( hd->master && memcmp(&bst, st, sizeof(struct status_data)) != 0 ) clif->hominfo(hd->master,hd,0); } else if( bl->type == BL_MER ) { TBL_MER* md = BL_CAST(BL_MER, bl); - if( b_status.rhw.atk != status->rhw.atk || b_status.rhw.atk2 != status->rhw.atk2 ) + if( bst.rhw.atk != st->rhw.atk || bst.rhw.atk2 != st->rhw.atk2 ) clif->mercenary_updatestatus(md->master, SP_ATK1); - if( b_status.matk_max != status->matk_max ) + if( bst.matk_max != st->matk_max ) clif->mercenary_updatestatus(md->master, SP_MATK1); - if( b_status.hit != status->hit ) + if( bst.hit != st->hit ) clif->mercenary_updatestatus(md->master, SP_HIT); - if( b_status.cri != status->cri ) + if( bst.cri != st->cri ) clif->mercenary_updatestatus(md->master, SP_CRITICAL); - if( b_status.def != status->def ) + if( bst.def != st->def ) clif->mercenary_updatestatus(md->master, SP_DEF1); - if( b_status.mdef != status->mdef ) + if( bst.mdef != st->mdef ) clif->mercenary_updatestatus(md->master, SP_MDEF1); - if( b_status.flee != status->flee ) + if( bst.flee != st->flee ) clif->mercenary_updatestatus(md->master, SP_MERCFLEE); - if( b_status.amotion != status->amotion ) + if( bst.amotion != st->amotion ) clif->mercenary_updatestatus(md->master, SP_ASPD); - if( b_status.max_hp != status->max_hp ) + if( bst.max_hp != st->max_hp ) clif->mercenary_updatestatus(md->master, SP_MAXHP); - if( b_status.max_sp != status->max_sp ) + if( bst.max_sp != st->max_sp ) clif->mercenary_updatestatus(md->master, SP_MAXSP); - if( b_status.hp != status->hp ) + if( bst.hp != st->hp ) clif->mercenary_updatestatus(md->master, SP_HP); - if( b_status.sp != status->sp ) + if( bst.sp != st->sp ) clif->mercenary_updatestatus(md->master, SP_SP); } else if( bl->type == BL_ELEM ) { TBL_ELEM* ed = BL_CAST(BL_ELEM, bl); - if( b_status.max_hp != status->max_hp ) + if( bst.max_hp != st->max_hp ) clif->elemental_updatestatus(ed->master, SP_MAXHP); - if( b_status.max_sp != status->max_sp ) + if( bst.max_sp != st->max_sp ) clif->elemental_updatestatus(ed->master, SP_MAXSP); - if( b_status.hp != status->hp ) + if( bst.hp != st->hp ) clif->elemental_updatestatus(ed->master, SP_HP); - if( b_status.sp != status->sp ) + if( bst.sp != st->sp ) clif->mercenary_updatestatus(ed->master, SP_SP); } } /*========================================== - * Apply shared stat mods from status changes [DracoRPG] - *------------------------------------------*/ -static unsigned short status_calc_str(struct block_list *bl, struct status_change *sc, int str) +* Apply shared stat mods from status changes [DracoRPG] +*------------------------------------------*/ +unsigned short status_calc_str(struct block_list *bl, struct status_change *sc, int str) { if(!sc || !sc->count) return cap_value(str,0,USHRT_MAX); @@ -4083,6 +4161,8 @@ static unsigned short status_calc_str(struct block_list *bl, struct status_chang str -= sc->data[SC_HARMONIZE]->val2; return (unsigned short)cap_value(str,0,USHRT_MAX); } + if(sc->data[SC_BEYOND_OF_WARCRY]) + str += sc->data[SC_BEYOND_OF_WARCRY]->val3; if(sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_HIGH && str < 50) return 50; if(sc->data[SC_INCALLSTATUS]) @@ -4131,7 +4211,7 @@ static unsigned short status_calc_str(struct block_list *bl, struct status_chang return (unsigned short)cap_value(str,0,USHRT_MAX); } -static unsigned short status_calc_agi(struct block_list *bl, struct status_change *sc, int agi) +unsigned short status_calc_agi(struct block_list *bl, struct status_change *sc, int agi) { if(!sc || !sc->count) return cap_value(agi,0,USHRT_MAX); @@ -4189,7 +4269,7 @@ static unsigned short status_calc_agi(struct block_list *bl, struct status_chang return (unsigned short)cap_value(agi,0,USHRT_MAX); } -static unsigned short status_calc_vit(struct block_list *bl, struct status_change *sc, int vit) +unsigned short status_calc_vit(struct block_list *bl, struct status_change *sc, int vit) { if(!sc || !sc->count) return cap_value(vit,0,USHRT_MAX); @@ -4237,7 +4317,7 @@ static unsigned short status_calc_vit(struct block_list *bl, struct status_chang return (unsigned short)cap_value(vit,0,USHRT_MAX); } -static unsigned short status_calc_int(struct block_list *bl, struct status_change *sc, int int_) +unsigned short status_calc_int(struct block_list *bl, struct status_change *sc, int int_) { if(!sc || !sc->count) return cap_value(int_,0,USHRT_MAX); @@ -4246,6 +4326,8 @@ static unsigned short status_calc_int(struct block_list *bl, struct status_chang int_ -= sc->data[SC_HARMONIZE]->val2; return (unsigned short)cap_value(int_,0,USHRT_MAX); } + if(sc->data[SC_MELODYOFSINK]) + int_ -= sc->data[SC_MELODYOFSINK]->val3; if(sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_HIGH && int_ < 50) return 50; if(sc->data[SC_INCALLSTATUS]) @@ -4275,7 +4357,7 @@ static unsigned short status_calc_int(struct block_list *bl, struct status_chang if(sc->data[SC_MARIONETTE]) int_ += ((sc->data[SC_MARIONETTE]->val4)>>16)&0xFF; if(sc->data[SC_MANDRAGORA]) - int_ -= 5 + 5 * sc->data[SC_MANDRAGORA]->val1; + int_ -= 4 * sc->data[SC_MANDRAGORA]->val1; if(sc->data[SC_COCKTAIL_WARG_BLOOD]) int_ += sc->data[SC_COCKTAIL_WARG_BLOOD]->val1; if(sc->data[SC_INSPIRATION]) @@ -4285,17 +4367,19 @@ static unsigned short status_calc_int(struct block_list *bl, struct status_chang if(sc->data[SC_KYOUGAKU]) int_ -= sc->data[SC_KYOUGAKU]->val2; - if(sc->data[SC_NOEQUIPHELM]) - int_ -= int_ * sc->data[SC_NOEQUIPHELM]->val2/100; - if(sc->data[SC__STRIPACCESSARY]) - int_ -= int_ * sc->data[SC__STRIPACCESSARY]->val2 / 100; + if(bl->type != BL_PC){ + if(sc->data[SC_NOEQUIPHELM]) + int_ -= int_ * sc->data[SC_NOEQUIPHELM]->val2/100; + if(sc->data[SC__STRIPACCESSARY]) + int_ -= int_ * sc->data[SC__STRIPACCESSARY]->val2 / 100; + } if(sc->data[SC_FULL_THROTTLE]) int_ += int_ * 20 / 100; return (unsigned short)cap_value(int_,0,USHRT_MAX); } -static unsigned short status_calc_dex(struct block_list *bl, struct status_change *sc, int dex) +unsigned short status_calc_dex(struct block_list *bl, struct status_change *sc, int dex) { if(!sc || !sc->count) return cap_value(dex,0,USHRT_MAX); @@ -4347,7 +4431,7 @@ static unsigned short status_calc_dex(struct block_list *bl, struct status_chang if(sc->data[SC_MARSHOFABYSS]) dex -= dex * sc->data[SC_MARSHOFABYSS]->val2 / 100; - if(sc->data[SC__STRIPACCESSARY]) + if(sc->data[SC__STRIPACCESSARY] && bl->type != BL_PC) dex -= dex * sc->data[SC__STRIPACCESSARY]->val2 / 100; if(sc->data[SC_FULL_THROTTLE]) dex += dex * 20 / 100; @@ -4355,7 +4439,7 @@ static unsigned short status_calc_dex(struct block_list *bl, struct status_chang return (unsigned short)cap_value(dex,0,USHRT_MAX); } -static unsigned short status_calc_luk(struct block_list *bl, struct status_change *sc, int luk) +unsigned short status_calc_luk(struct block_list *bl, struct status_change *sc, int luk) { if(!sc || !sc->count) return cap_value(luk,0,USHRT_MAX); @@ -4395,7 +4479,7 @@ static unsigned short status_calc_luk(struct block_list *bl, struct status_chang if(sc->data[SC_LAUDARAMUS]) luk += 4 + sc->data[SC_LAUDARAMUS]->val1; - if(sc->data[SC__STRIPACCESSARY]) + if(sc->data[SC__STRIPACCESSARY] && bl->type != BL_PC) luk -= luk * sc->data[SC__STRIPACCESSARY]->val2 / 100; if(sc->data[SC_BANANA_BOMB]) luk -= luk * sc->data[SC_BANANA_BOMB]->val1 / 100; @@ -4404,38 +4488,38 @@ static unsigned short status_calc_luk(struct block_list *bl, struct status_chang return (unsigned short)cap_value(luk,0,USHRT_MAX); } - -static unsigned short status_calc_batk(struct block_list *bl, struct status_change *sc, int batk, bool viewable) +unsigned short status_calc_batk(struct block_list *bl, struct status_change *sc, int batk, bool viewable) { if(!sc || !sc->count) return cap_value(batk,0,USHRT_MAX); - + if( !viewable ){ /* some statuses that are hidden in the status window */ + if(sc->data[SC_PLUSATTACKPOWER]) + batk += sc->data[SC_PLUSATTACKPOWER]->val1; return (unsigned short)cap_value(batk,0,USHRT_MAX); } - +#ifndef RENEWAL if(sc->data[SC_PLUSATTACKPOWER]) batk += sc->data[SC_PLUSATTACKPOWER]->val1; - if(sc->data[SC_BATKFOOD]) - batk += sc->data[SC_BATKFOOD]->val1; - if(sc->data[SC_GS_GATLINGFEVER]) - batk += sc->data[SC_GS_GATLINGFEVER]->val3; if(sc->data[SC_GS_MADNESSCANCEL]) batk += 100; + if(sc->data[SC_GS_GATLINGFEVER]) + batk += sc->data[SC_GS_GATLINGFEVER]->val3; +#endif + if(sc->data[SC_BATKFOOD]) + batk += sc->data[SC_BATKFOOD]->val1; if(sc->data[SC_FIRE_INSIGNIA] && sc->data[SC_FIRE_INSIGNIA]->val1 == 2) batk += 50; if(bl->type == BL_ELEM - && ((sc->data[SC_FIRE_INSIGNIA] && sc->data[SC_FIRE_INSIGNIA]->val1 == 1) - || (sc->data[SC_WATER_INSIGNIA] && sc->data[SC_WATER_INSIGNIA]->val1 == 1) - || (sc->data[SC_WIND_INSIGNIA] && sc->data[SC_WIND_INSIGNIA]->val1 == 1) - || (sc->data[SC_EARTH_INSIGNIA] && sc->data[SC_EARTH_INSIGNIA]->val1 == 1)) - ) + && ((sc->data[SC_FIRE_INSIGNIA] && sc->data[SC_FIRE_INSIGNIA]->val1 == 1) + || (sc->data[SC_WATER_INSIGNIA] && sc->data[SC_WATER_INSIGNIA]->val1 == 1) + || (sc->data[SC_WIND_INSIGNIA] && sc->data[SC_WIND_INSIGNIA]->val1 == 1) + || (sc->data[SC_EARTH_INSIGNIA] && sc->data[SC_EARTH_INSIGNIA]->val1 == 1)) + ) batk += batk / 5; if(sc->data[SC_FULL_SWING_K]) batk += sc->data[SC_FULL_SWING_K]->val1; - if(sc->data[SC_ODINS_POWER]) - batk += 70; if(sc->data[SC_VOLCANIC_ASH] && (bl->type==BL_MOB)){ if(status_get_element(bl) == ELE_WATER) //water type batk /= 2; @@ -4463,45 +4547,40 @@ static unsigned short status_calc_batk(struct block_list *bl, struct status_chan batk -= batk * 25/100; if( sc->data[SC_ZANGETSU] ) batk += sc->data[SC_ZANGETSU]->val2; -//Curse shouldn't effect on this? <- Curse OR Bleeding?? -// if(sc->data[SC_BLOODING]) -// batk -= batk * 25/100; + //Curse shouldn't effect on this? <- Curse OR Bleeding?? + // if(sc->data[SC_BLOODING]) + // batk -= batk * 25/100; if(sc->data[SC_HLIF_FLEET]) batk += batk * sc->data[SC_HLIF_FLEET]->val3/100; if(sc->data[SC__ENERVATION]) batk -= batk * sc->data[SC__ENERVATION]->val2 / 100; - if(sc->data[SC_RUSH_WINDMILL]) - batk += batk * sc->data[SC_RUSH_WINDMILL]->val2/100; if(sc->data[SC_SATURDAY_NIGHT_FEVER]) batk += 100 * sc->data[SC_SATURDAY_NIGHT_FEVER]->val1; - if(sc->data[SC_MELODYOFSINK]) - batk -= batk * sc->data[SC_MELODYOFSINK]->val3/100; - if(sc->data[SC_BEYOND_OF_WARCRY]) - batk += batk * sc->data[SC_BEYOND_OF_WARCRY]->val3/100; return (unsigned short)cap_value(batk,0,USHRT_MAX); } -static unsigned short status_calc_watk(struct block_list *bl, struct status_change *sc, int watk, bool viewable) +unsigned short status_calc_watk(struct block_list *bl, struct status_change *sc, int watk, bool viewable) { if(!sc || !sc->count) return cap_value(watk,0,USHRT_MAX); if( !viewable ){ /* some statuses that are hidden in the status window */ - if(sc->data[SC_STRIKING]) - watk += sc->data[SC_STRIKING]->val2; + if( sc->data[SC_WATER_BARRIER] ) + watk -= sc->data[SC_WATER_BARRIER]->val3; if(sc->data[SC_GENTLETOUCH_CHANGE] && sc->data[SC_GENTLETOUCH_CHANGE]->val2) watk += sc->data[SC_GENTLETOUCH_CHANGE]->val2; return (unsigned short)cap_value(watk,0,USHRT_MAX); } - +#ifndef RENEWAL if(sc->data[SC_IMPOSITIO]) watk += sc->data[SC_IMPOSITIO]->val2; - if(sc->data[SC_WATKFOOD]) - watk += sc->data[SC_WATKFOOD]->val1; if(sc->data[SC_DRUMBATTLE]) watk += sc->data[SC_DRUMBATTLE]->val2; +#endif + if(sc->data[SC_WATKFOOD]) + watk += sc->data[SC_WATKFOOD]->val1; if(sc->data[SC_VOLCANO]) watk += sc->data[SC_VOLCANO]->val2; if(sc->data[SC_MER_ATK]) @@ -4518,27 +4597,20 @@ static unsigned short status_calc_watk(struct block_list *bl, struct status_chan watk += sc->data[SC_TROPIC_OPTION]->val2; if( sc->data[SC_HEATER_OPTION] ) watk += sc->data[SC_HEATER_OPTION]->val2; - if( sc->data[SC_WATER_BARRIER] ) - watk -= sc->data[SC_WATER_BARRIER]->val3; if( sc->data[SC_PYROTECHNIC_OPTION] ) watk += sc->data[SC_PYROTECHNIC_OPTION]->val2; + +#ifndef RENEWAL if(sc->data[SC_NIBELUNGEN]) { if (bl->type != BL_PC) watk += sc->data[SC_NIBELUNGEN]->val2; else { - #ifndef RENEWAL TBL_PC *sd = (TBL_PC*)bl; int index = sd->equip_index[sd->state.lr_flag?EQI_HAND_L:EQI_HAND_R]; if(index >= 0 && sd->inventory_data[index] && sd->inventory_data[index]->wlv == 4) - #endif watk += sc->data[SC_NIBELUNGEN]->val2; } } -#ifndef RENEWAL - if(sc->data[SC_STRIKING]) - watk += sc->data[SC_STRIKING]->val2; - if(sc->data[SC_GENTLETOUCH_CHANGE] && sc->data[SC_GENTLETOUCH_CHANGE]->val2) - watk += sc->data[SC_GENTLETOUCH_CHANGE]->val2; if(sc->data[SC_LKCONCENTRATION]) watk += watk * sc->data[SC_LKCONCENTRATION]->val2/100; #endif @@ -4548,106 +4620,111 @@ static unsigned short status_calc_watk(struct block_list *bl, struct status_chan watk += watk * sc->data[SC_PROVOKE]->val3/100; if(sc->data[SC_SKE]) watk += watk * 3; - if(sc->data[SC__ENERVATION]) - watk -= watk * sc->data[SC__ENERVATION]->val2 / 100; if(sc->data[SC_HLIF_FLEET]) watk += watk * sc->data[SC_HLIF_FLEET]->val3/100; if(sc->data[SC_CURSE]) watk -= watk * 25/100; - if(sc->data[SC_NOEQUIPWEAPON]) + if(sc->data[SC_NOEQUIPWEAPON] && bl->type != BL_PC) watk -= watk * sc->data[SC_NOEQUIPWEAPON]->val2/100; if(sc->data[SC__ENERVATION]) watk -= watk * sc->data[SC__ENERVATION]->val2 / 100; + if(sc->data[SC_RUSH_WINDMILL]) + watk += sc->data[SC_RUSH_WINDMILL]->val2; + if (sc->data[SC_ODINS_POWER]) + watk += 40 + 30 * sc->data[SC_ODINS_POWER]->val1; + if(sc->data[SC_STRIKING]) + watk += sc->data[SC_STRIKING]->val2; if((sc->data[SC_FIRE_INSIGNIA] && sc->data[SC_FIRE_INSIGNIA]->val1 == 2) - || (sc->data[SC_WATER_INSIGNIA] && sc->data[SC_WATER_INSIGNIA]->val1 == 2) - || (sc->data[SC_WIND_INSIGNIA] && sc->data[SC_WIND_INSIGNIA]->val1 == 2) - || (sc->data[SC_EARTH_INSIGNIA] && sc->data[SC_EARTH_INSIGNIA]->val1 == 2) - ) + || (sc->data[SC_WATER_INSIGNIA] && sc->data[SC_WATER_INSIGNIA]->val1 == 2) + || (sc->data[SC_WIND_INSIGNIA] && sc->data[SC_WIND_INSIGNIA]->val1 == 2) + || (sc->data[SC_EARTH_INSIGNIA] && sc->data[SC_EARTH_INSIGNIA]->val1 == 2) + ) watk += watk / 10; if( sc && sc->data[SC_TIDAL_WEAPON] ) watk += watk * sc->data[SC_TIDAL_WEAPON]->val2 / 100; if(sc->data[SC_ANGRIFFS_MODUS]) watk += watk * sc->data[SC_ANGRIFFS_MODUS]->val2/100; + if( sc->data[SC_FLASHCOMBO] ) + watk += sc->data[SC_FLASHCOMBO]->val2; return (unsigned short)cap_value(watk,0,USHRT_MAX); } +unsigned short status_calc_ematk(struct block_list *bl, struct status_change *sc, int matk) { #ifdef RENEWAL -static unsigned short status_calc_ematk(struct block_list *bl, struct status_change *sc, int matk) -{ - if (!sc || !sc->count) - return cap_value(matk,0,USHRT_MAX); - if (sc->data[SC_PLUSMAGICPOWER]) - matk += sc->data[SC_PLUSMAGICPOWER]->val1; - if (sc->data[SC_MATKFOOD]) - matk += sc->data[SC_MATKFOOD]->val1; + if (!sc || !sc->count) + return cap_value(matk,0,USHRT_MAX); + if (sc->data[SC_PLUSMAGICPOWER]) + matk += sc->data[SC_PLUSMAGICPOWER]->val1; + if (sc->data[SC_MATKFOOD]) + matk += sc->data[SC_MATKFOOD]->val1; if(sc->data[SC_MANA_PLUS]) matk += sc->data[SC_MANA_PLUS]->val1; if(sc->data[SC_AQUAPLAY_OPTION]) matk += sc->data[SC_AQUAPLAY_OPTION]->val2; if(sc->data[SC_CHILLY_AIR_OPTION]) matk += sc->data[SC_CHILLY_AIR_OPTION]->val2; - if(sc->data[SC_WATER_BARRIER]) - matk -= sc->data[SC_WATER_BARRIER]->val3; + if(sc->data[SC_COOLER_OPTION]) + matk += sc->data[SC_COOLER_OPTION]->val2; if(sc->data[SC_FIRE_INSIGNIA] && sc->data[SC_FIRE_INSIGNIA]->val1 == 3) matk += 50; if(sc->data[SC_ODINS_POWER]) matk += 40 + 30 * sc->data[SC_ODINS_POWER]->val1; //70 lvl1, 100lvl2 if(sc->data[SC_IZAYOI]) matk += 25 * sc->data[SC_IZAYOI]->val1; - return (unsigned short)cap_value(matk,0,USHRT_MAX); -} + return (unsigned short)cap_value(matk,0,USHRT_MAX); +#else + return 0; #endif -static unsigned short status_calc_matk(struct block_list *bl, struct status_change *sc, int matk, bool viewable) +} +unsigned short status_calc_matk(struct block_list *bl, struct status_change *sc, int matk, bool viewable) { if(!sc || !sc->count) return cap_value(matk,0,USHRT_MAX); if( !viewable ){ /* some statuses that are hidden in the status window */ + if (sc->data[SC_MINDBREAKER]) + matk += matk * sc->data[SC_MINDBREAKER]->val2/100; return (unsigned short)cap_value(matk,0,USHRT_MAX); } #ifndef RENEWAL // take note fixed value first before % modifiers - if (sc->data[SC_PLUSMAGICPOWER]) - matk += sc->data[SC_PLUSMAGICPOWER]->val1; - if (sc->data[SC_MATKFOOD]) - matk += sc->data[SC_MATKFOOD]->val1; - if (sc->data[SC_MANA_PLUS]) - matk += sc->data[SC_MANA_PLUS]->val1; - if (sc->data[SC_AQUAPLAY_OPTION]) - matk += sc->data[SC_AQUAPLAY_OPTION]->val2; - if (sc->data[SC_CHILLY_AIR_OPTION]) - matk += sc->data[SC_CHILLY_AIR_OPTION]->val2; - if (sc->data[SC_WATER_BARRIER]) - matk -= sc->data[SC_WATER_BARRIER]->val3; - if (sc->data[SC_FIRE_INSIGNIA] && sc->data[SC_FIRE_INSIGNIA]->val1 == 3) - matk += 50; - if (sc->data[SC_ODINS_POWER]) - matk += 40 + 30 * sc->data[SC_ODINS_POWER]->val1; //70 lvl1, 100lvl2 - if (sc->data[SC_IZAYOI]) - matk += 25 * sc->data[SC_IZAYOI]->val1; + if (sc->data[SC_PLUSMAGICPOWER]) + matk += sc->data[SC_PLUSMAGICPOWER]->val1; + if (sc->data[SC_MATKFOOD]) + matk += sc->data[SC_MATKFOOD]->val1; + if (sc->data[SC_MANA_PLUS]) + matk += sc->data[SC_MANA_PLUS]->val1; + if (sc->data[SC_AQUAPLAY_OPTION]) + matk += sc->data[SC_AQUAPLAY_OPTION]->val2; + if (sc->data[SC_CHILLY_AIR_OPTION]) + matk += sc->data[SC_CHILLY_AIR_OPTION]->val2; + if(sc->data[SC_COOLER_OPTION]) + matk += sc->data[SC_COOLER_OPTION]->val2; + if (sc->data[SC_FIRE_INSIGNIA] && sc->data[SC_FIRE_INSIGNIA]->val1 == 3) + matk += 50; + if (sc->data[SC_ODINS_POWER]) + matk += 40 + 30 * sc->data[SC_ODINS_POWER]->val1; //70 lvl1, 100lvl2 + if (sc->data[SC_IZAYOI]) + matk += 25 * sc->data[SC_IZAYOI]->val1; #endif if( sc->data[SC_ZANGETSU] ) matk += sc->data[SC_ZANGETSU]->val3; - if (sc->data[SC_MAGICPOWER] && sc->data[SC_MAGICPOWER]->val4) - matk += matk * sc->data[SC_MAGICPOWER]->val3/100; - if (sc->data[SC_MINDBREAKER]) - matk += matk * sc->data[SC_MINDBREAKER]->val2/100; - if (sc->data[SC_INCMATKRATE]) - matk += matk * sc->data[SC_INCMATKRATE]->val1/100; - if (sc->data[SC_MOONLIT_SERENADE]) - matk += matk * sc->data[SC_MOONLIT_SERENADE]->val2/100; - if (sc->data[SC_MELODYOFSINK]) - matk += matk * sc->data[SC_MELODYOFSINK]->val3/100; - if (sc->data[SC_BEYOND_OF_WARCRY]) - matk -= matk * sc->data[SC_BEYOND_OF_WARCRY]->val3/100; + if (sc->data[SC_MAGICPOWER] && sc->data[SC_MAGICPOWER]->val4) + matk += matk * sc->data[SC_MAGICPOWER]->val3/100; + if (sc->data[SC_INCMATKRATE]) + matk += matk * sc->data[SC_INCMATKRATE]->val1/100; + if (sc->data[SC_MOONLIT_SERENADE]) + matk += matk * sc->data[SC_MOONLIT_SERENADE]->val2/100; + if (sc->data[SC_MTF_MATK]) + matk += matk * 25 / 100; return (unsigned short)cap_value(matk,0,USHRT_MAX); } -static signed short status_calc_critical(struct block_list *bl, struct status_change *sc, int critical, bool viewable) { +signed short status_calc_critical(struct block_list *bl, struct status_change *sc, int critical, bool viewable) { if(!sc || !sc->count) return cap_value(critical,10,SHRT_MAX); @@ -4675,14 +4752,16 @@ static signed short status_calc_critical(struct block_list *bl, struct status_ch #endif if(sc->data[SC__INVISIBILITY]) - critical += critical * sc->data[SC__INVISIBILITY]->val3 / 100; + critical += sc->data[SC__INVISIBILITY]->val3; if(sc->data[SC__UNLUCKY]) critical -= critical * sc->data[SC__UNLUCKY]->val2 / 100; + if(sc->data[SC_BEYOND_OF_WARCRY]) + critical += 10 * sc->data[SC_BEYOND_OF_WARCRY]->val3; return (short)cap_value(critical,10,SHRT_MAX); } -static signed short status_calc_hit(struct block_list *bl, struct status_change *sc, int hit, bool viewable) +signed short status_calc_hit(struct block_list *bl, struct status_change *sc, int hit, bool viewable) { if(!sc || !sc->count) @@ -4690,6 +4769,8 @@ static signed short status_calc_hit(struct block_list *bl, struct status_change if( !viewable ){ /* some statuses that are hidden in the status window */ + if(sc->data[SC_MTF_ASPD]) + hit += 5; return (short)cap_value(hit,1,SHRT_MAX); } @@ -4704,7 +4785,7 @@ static signed short status_calc_hit(struct block_list *bl, struct status_change if(sc->data[SC_LKCONCENTRATION]) hit += sc->data[SC_LKCONCENTRATION]->val3; if(sc->data[SC_INSPIRATION]) - hit += 5 * sc->data[SC_INSPIRATION]->val1; + hit += 5 * sc->data[SC_INSPIRATION]->val1 + 25; if(sc->data[SC_GS_ADJUSTMENT]) hit -= 30; if(sc->data[SC_GS_ACCURACY]) @@ -4722,17 +4803,17 @@ static signed short status_calc_hit(struct block_list *bl, struct status_change hit -= hit * 20 / 100; if (sc->data[SC_VOLCANIC_ASH]) hit /= 2; - + if(sc->data[SC_ILLUSIONDOPING]) + hit -= hit * (5 + sc->data[SC_ILLUSIONDOPING]->val1) / 100; //custom + return (short)cap_value(hit,1,SHRT_MAX); } -static signed short status_calc_flee(struct block_list *bl, struct status_change *sc, int flee, bool viewable) -{ - if( bl->type == BL_PC ) - { - if( map_flag_gvg(bl->m) ) +signed short status_calc_flee(struct block_list *bl, struct status_change *sc, int flee, bool viewable) { + if( bl->type == BL_PC ) { + if( map_flag_gvg2(bl->m) ) flee -= flee * battle_config.gvg_flee_penalty/100; - else if( map[bl->m].flag.battleground ) + else if( map->list[bl->m].flag.battleground ) flee -= flee * battle_config.bg_flee_penalty/100; } @@ -4760,8 +4841,6 @@ static signed short status_calc_flee(struct block_list *bl, struct status_change flee += 10; if (sc->data[SC_ANGRIFFS_MODUS]) flee -= sc->data[SC_ANGRIFFS_MODUS]->val3; - if (sc->data[SC_OVERED_BOOST]) - flee = max(flee,sc->data[SC_OVERED_BOOST]->val2); if(sc->data[SC_GS_ADJUSTMENT]) flee += 30; if(sc->data[SC_HLIF_SPEED]) @@ -4785,35 +4864,38 @@ static signed short status_calc_flee(struct block_list *bl, struct status_change flee += flee * sc->data[SC_INCFLEERATE]->val1/100; if(sc->data[SC_SPIDERWEB] && sc->data[SC_SPIDERWEB]->val1) flee -= flee * 50/100; - if (sc->data[SC_BERSERK] || sc->data[SC__BLOODYLUST]) + if (sc->data[SC_BERSERK]) flee -= flee * 50/100; if(sc->data[SC_BLIND]) flee -= flee * 25/100; if(sc->data[SC_FEAR]) flee -= flee * 20 / 100; if(sc->data[SC_PARALYSE]) - flee -= flee * 10 / 100; // 10% Flee reduction + flee -= flee / 10; // 10% Flee reduction if(sc->data[SC_INFRAREDSCAN]) flee -= flee * 30 / 100; if( sc->data[SC__LAZINESS] ) flee -= flee * sc->data[SC__LAZINESS]->val3 / 100; if( sc->data[SC_GLOOMYDAY] ) - flee -= flee * sc->data[SC_GLOOMYDAY]->val2 / 100; + flee -= flee * ( 20 + 5 * sc->data[SC_GLOOMYDAY]->val1 ) / 100; if( sc->data[SC_SATURDAY_NIGHT_FEVER] ) flee -= flee * (40 + 10 * sc->data[SC_SATURDAY_NIGHT_FEVER]->val1) / 100; if( sc->data[SC_WIND_STEP_OPTION] ) flee += flee * sc->data[SC_WIND_STEP_OPTION]->val2 / 100; if( sc->data[SC_ZEPHYR] ) - flee += flee * sc->data[SC_ZEPHYR]->val2 / 100; + flee += sc->data[SC_ZEPHYR]->val2; if(sc->data[SC_VOLCANIC_ASH] && (bl->type==BL_MOB)){ //mob if(status_get_element(bl) == ELE_WATER) //water type flee /= 2; } + + if( sc->data[SC_OVERED_BOOST] ) // should be final and unmodifiable by any means + flee = sc->data[SC_OVERED_BOOST]->val2; return (short)cap_value(flee,1,SHRT_MAX); } -static signed short status_calc_flee2(struct block_list *bl, struct status_change *sc, int flee2, bool viewable) +signed short status_calc_flee2(struct block_list *bl, struct status_change *sc, int flee2, bool viewable) { if(!sc || !sc->count) return cap_value(flee2,10,SHRT_MAX); @@ -4841,12 +4923,20 @@ defType status_calc_def(struct block_list *bl, struct status_change *sc, int def /* some statuses that are hidden in the status window */ if( sc && sc->data[SC_CAMOUFLAGE] ) def -= def * 5 * (10-sc->data[SC_CAMOUFLAGE]->val4) / 100; + if( sc->data[SC_OVERED_BOOST] && bl->type == BL_PC ) + def -= def * 50 / 100; + if( sc->data[SC_NEUTRALBARRIER] ) + def += def * (10 + 5*sc->data[SC_NEUTRALBARRIER]->val1) / 100; if( sc && sc->data[SC_GENTLETOUCH_REVITALIZE] && sc->data[SC_GENTLETOUCH_REVITALIZE]->val4 ) def += 2 * sc->data[SC_GENTLETOUCH_REVITALIZE]->val4; + if( sc->data[SC_FORCEOFVANGUARD] ) + def += def * 2 * sc->data[SC_FORCEOFVANGUARD]->val1 / 100; + if(sc->data[SC_DEFSET]) + return sc->data[SC_DEFSET]->val1; return (defType)cap_value(def,DEFTYPE_MIN,DEFTYPE_MAX); } - if (sc->data[SC_BERSERK] || sc->data[SC__BLOODYLUST]) + if (sc->data[SC_BERSERK]) return 0; if(sc->data[SC_SKA]) return sc->data[SC_SKA]->val3; @@ -4858,27 +4948,32 @@ defType status_calc_def(struct block_list *bl, struct status_change *sc, int def if(sc->data[SC_STEELBODY]) return 90; #endif + + if(sc->data[SC_STONEHARDSKIN]) + def += sc->data[SC_STONEHARDSKIN]->val1; + if(sc->data[SC_DRUMBATTLE]) + def += sc->data[SC_DRUMBATTLE]->val3; if(sc->data[SC_STONESKIN]) def += sc->data[SC_STONESKIN]->val2; - if(sc->data[SC_DRUMBATTLE]) - def += sc->data[SC_DRUMBATTLE]->val3; if(sc->data[SC_HAMI_DEFENCE]) //[orn] - def += sc->data[SC_HAMI_DEFENCE]->val2 ; - if(sc->data[SC_INCDEFRATE]) - def += def * sc->data[SC_INCDEFRATE]->val1/100; + def += sc->data[SC_HAMI_DEFENCE]->val2; + if(sc->data[SC_EARTH_INSIGNIA] && sc->data[SC_EARTH_INSIGNIA]->val1 == 2) def += 50; if(sc->data[SC_ODINS_POWER]) def -= 20; - if( sc->data[SC_ANGRIFFS_MODUS] ) - def -= 30 + 20 * sc->data[SC_ANGRIFFS_MODUS]->val1; - if(sc->data[SC_STONEHARDSKIN]) - def += sc->data[SC_STONEHARDSKIN]->val1; + +#ifndef RENEWAL if(sc->data[SC_STONE] && sc->opt1 == OPT1_STONE) def >>=1; if(sc->data[SC_FREEZE]) def >>=1; + if(sc->data[SC_INCDEFRATE]) + def += def * sc->data[SC_INCDEFRATE]->val1/100; +#endif + if( sc->data[SC_ANGRIFFS_MODUS] ) + def -= 30 + 20 * sc->data[SC_ANGRIFFS_MODUS]->val1; if(sc->data[SC_CRUCIS]) def -= def * sc->data[SC_CRUCIS]->val2/100; if(sc->data[SC_LKCONCENTRATION]) @@ -4893,24 +4988,29 @@ defType status_calc_def(struct block_list *bl, struct status_change *sc, int def def -= def * (sc->data[SC_FLING]->val2)/100; if( sc->data[SC_ANALYZE] ) def -= def * ( 14 * sc->data[SC_ANALYZE]->val1 ) / 100; - if( sc->data[SC_FORCEOFVANGUARD] ) - def += def * 2 * sc->data[SC_FORCEOFVANGUARD]->val1 / 100; if(sc->data[SC_SATURDAY_NIGHT_FEVER]) def -= def * (10 + 10 * sc->data[SC_SATURDAY_NIGHT_FEVER]->val1) / 100; if(sc->data[SC_EARTHDRIVE]) def -= def * 25 / 100; if( sc->data[SC_ROCK_CRUSHER] ) def -= def * sc->data[SC_ROCK_CRUSHER]->val2 / 100; + if( sc->data[SC_FROSTMISTY] ) + def -= def * 10 / 100; + if( sc->data[SC_OVERED_BOOST] && bl->type == BL_HOM ) + def -= def * 50 / 100; + if( sc->data[SC_POWER_OF_GAIA] ) def += def * sc->data[SC_POWER_OF_GAIA]->val2 / 100; + if( sc->data[SC_SHIELDSPELL_REF] && sc->data[SC_SHIELDSPELL_REF]->val1 == 2 ) + def += sc->data[SC_SHIELDSPELL_REF]->val2; if( sc->data[SC_PRESTIGE] ) def += def * sc->data[SC_PRESTIGE]->val1 / 100; - if( sc->data[SC_FROSTMISTY] ) - def -= def * 10 / 100; if(sc->data[SC_VOLCANIC_ASH] && (bl->type==BL_MOB)){ if(status_get_race(bl)==RC_PLANT) def /= 2; } + if(sc->data[SC_UNLIMIT]) + return 1; return (defType)cap_value(def,DEFTYPE_MIN,DEFTYPE_MAX); } @@ -4929,9 +5029,11 @@ signed short status_calc_def2(struct block_list *bl, struct status_change *sc, i #ifdef RENEWAL if( sc && sc->data[SC_ASSUMPTIO] ) def2 <<= 1; -#endif +#endif if( sc && sc->data[SC_CAMOUFLAGE] ) def2 -= def2 * 5 * (10-sc->data[SC_CAMOUFLAGE]->val4) / 100; + if(sc->data[SC_DEFSET]) + return sc->data[SC_DEFSET]->val1; #ifdef RENEWAL return (short)cap_value(def2,SHRT_MIN,SHRT_MAX); #else @@ -4939,17 +5041,14 @@ signed short status_calc_def2(struct block_list *bl, struct status_change *sc, i #endif } - if (sc->data[SC_BERSERK] || sc->data[SC__BLOODYLUST]) + if (sc->data[SC_BERSERK]) return 0; if(sc->data[SC_ETERNALCHAOS]) return 0; if(sc->data[SC_SUN_COMFORT]) def2 += sc->data[SC_SUN_COMFORT]->val2; - if( sc->data[SC_SHIELDSPELL_REF] && sc->data[SC_SHIELDSPELL_REF]->val1 == 1 ) - def2 += sc->data[SC_SHIELDSPELL_REF]->val2; if( sc->data[SC_BANDING] && sc->data[SC_BANDING]->val2 > 0 ) def2 += (5 + sc->data[SC_BANDING]->val1) * (sc->data[SC_BANDING]->val2); - if(sc->data[SC_ANGELUS]) #ifdef RENEWAL //in renewal only the VIT stat bonus is boosted by angelus def2 += status_get_vit(bl) / 2 * sc->data[SC_ANGELUS]->val2/100; @@ -4968,20 +5067,21 @@ signed short status_calc_def2(struct block_list *bl, struct status_change *sc, i def2 -= def2 * sc->data[SC_PROVOKE]->val4/100; if(sc->data[SC_JOINTBEAT]) def2 -= def2 * ( sc->data[SC_JOINTBEAT]->val2&BREAK_SHOULDER ? 50 : 0 ) / 100 - + def2 * ( sc->data[SC_JOINTBEAT]->val2&BREAK_WAIST ? 25 : 0 ) / 100; + + def2 * ( sc->data[SC_JOINTBEAT]->val2&BREAK_WAIST ? 25 : 0 ) / 100; if(sc->data[SC_FLING]) def2 -= def2 * (sc->data[SC_FLING]->val3)/100; if(sc->data[SC_ANALYZE]) def2 -= def2 * ( 14 * sc->data[SC_ANALYZE]->val1 ) / 100; if( sc->data[SC_ECHOSONG] ) - def2 += def2 * sc->data[SC_ECHOSONG]->val2/100; + def2 += def2 * sc->data[SC_ECHOSONG]->val3/100; if(sc->data[SC_VOLCANIC_ASH] && (bl->type==BL_MOB)){ if(status_get_race(bl)==RC_PLANT) def2 /= 2; } if (sc->data[SC_NEEDLE_OF_PARALYZE]) def2 -= def2 * sc->data[SC_NEEDLE_OF_PARALYZE]->val2 / 100; - + if (sc->data[SC_UNLIMIT]) + return 1; #ifdef RENEWAL return (short)cap_value(def2,SHRT_MIN,SHRT_MAX); #else @@ -4997,10 +5097,14 @@ defType status_calc_mdef(struct block_list *bl, struct status_change *sc, int md if( !viewable ){ /* some statuses that are hidden in the status window */ + if(sc->data[SC_NEUTRALBARRIER] ) + mdef += mdef * (5 * sc->data[SC_NEUTRALBARRIER]->val1 + 10) / 100; + if(sc->data[SC_MDEFSET]) + return sc->data[SC_MDEFSET]->val1; return (defType)cap_value(mdef,DEFTYPE_MIN,DEFTYPE_MAX); } - if (sc->data[SC_BERSERK] || sc->data[SC__BLOODYLUST]) + if (sc->data[SC_BERSERK]) return 0; if(sc->data[SC_BARRIER]) return 100; @@ -5018,8 +5122,6 @@ defType status_calc_mdef(struct block_list *bl, struct status_change *sc, int md mdef += (sc->data[SC_ENDURE]->val4 == 0) ? sc->data[SC_ENDURE]->val1 : 1; if(sc->data[SC_STONEHARDSKIN])// Final MDEF increase divided by 10 since were using classic (pre-renewal) mechanics. [Rytech] mdef += sc->data[SC_STONEHARDSKIN]->val1; - if(sc->data[SC_WATER_BARRIER]) - mdef += sc->data[SC_WATER_BARRIER]->val2; if(sc->data[SC_STONE] && sc->opt1 == OPT1_STONE) mdef += 25*mdef/100; if(sc->data[SC_FREEZE]) @@ -5031,9 +5133,11 @@ defType status_calc_mdef(struct block_list *bl, struct status_change *sc, int md if(sc->data[SC_GENTLETOUCH_CHANGE] && sc->data[SC_GENTLETOUCH_CHANGE]->val4) mdef -= mdef * sc->data[SC_GENTLETOUCH_CHANGE]->val4 / 100; if (sc->data[SC_ODINS_POWER]) - mdef -= 20 * sc->data[SC_ODINS_POWER]->val1; + mdef -= 20; if(sc->data[SC_BURNING]) mdef -= mdef *25 / 100; + if (sc->data[SC_UNLIMIT]) + return 1; return (defType)cap_value(mdef,DEFTYPE_MIN,DEFTYPE_MAX); } @@ -5049,6 +5153,10 @@ signed short status_calc_mdef2(struct block_list *bl, struct status_change *sc, if( !viewable ){ /* some statuses that are hidden in the status window */ + if(sc->data[SC_MDEFSET]) + return sc->data[SC_MDEFSET]->val1; + if(sc->data[SC_MINDBREAKER]) + mdef2 -= mdef2 * sc->data[SC_MINDBREAKER]->val3/100; #ifdef RENEWAL if(sc && sc->data[SC_ASSUMPTIO]) mdef2 <<= 1; @@ -5058,15 +5166,14 @@ signed short status_calc_mdef2(struct block_list *bl, struct status_change *sc, #endif } - if (sc->data[SC_BERSERK] || sc->data[SC__BLOODYLUST]) + if (sc->data[SC_BERSERK]) return 0; if(sc->data[SC_SKA]) return 90; - if(sc->data[SC_MINDBREAKER]) - mdef2 -= mdef2 * sc->data[SC_MINDBREAKER]->val3/100; if(sc->data[SC_ANALYZE]) mdef2 -= mdef2 * ( 14 * sc->data[SC_ANALYZE]->val1 ) / 100; - + if (sc->data[SC_UNLIMIT]) + return 1; #ifdef RENEWAL return (short)cap_value(mdef2,SHRT_MIN,SHRT_MAX); #else @@ -5074,21 +5181,18 @@ signed short status_calc_mdef2(struct block_list *bl, struct status_change *sc, #endif } -static unsigned short status_calc_speed(struct block_list *bl, struct status_change *sc, int speed) +unsigned short status_calc_speed(struct block_list *bl, struct status_change *sc, int speed) { TBL_PC* sd = BL_CAST(BL_PC, bl); int speed_rate; - if( sc == NULL ) - return cap_value(speed,10,USHRT_MAX); - - if (sd && sd->state.permanent_speed) - return (short)cap_value(speed,10,USHRT_MAX); + if( sc == NULL || ( sd && sd->state.permanent_speed ) ) + return (unsigned short)cap_value(speed,MIN_WALK_SPEED,MAX_WALK_SPEED); if( sd && sd->ud.skilltimer != INVALID_TIMER && (pc->checkskill(sd,SA_FREECAST) > 0 || sd->ud.skill_id == LG_EXEEDBREAK) ) { if( sd->ud.skill_id == LG_EXEEDBREAK ) - speed_rate = 100 + 60 - (sd->ud.skill_lv * 10); + speed_rate = 160 - 10 * sd->ud.skill_lv; else speed_rate = 175 - 5 * pc->checkskill(sd,SA_FREECAST); } @@ -5124,68 +5228,70 @@ static unsigned short status_calc_speed(struct block_list *bl, struct status_cha if( sd && sc->data[SC_HIDING] && pc->checkskill(sd,RG_TUNNELDRIVE) > 0 ) val = 120 - 6 * pc->checkskill(sd,RG_TUNNELDRIVE); else - if( sd && sc->data[SC_CHASEWALK] && sc->data[SC_CHASEWALK]->val3 < 0 ) - val = sc->data[SC_CHASEWALK]->val3; - else - { - // Longing for Freedom cancels song/dance penalty - if( sc->data[SC_LONGING] ) - val = max( val, 50 - 10 * sc->data[SC_LONGING]->val1 ); + if( sd && sc->data[SC_CHASEWALK] && sc->data[SC_CHASEWALK]->val3 < 0 ) + val = sc->data[SC_CHASEWALK]->val3; else - if( sd && sc->data[SC_DANCING] ) - val = max( val, 500 - (40 + 10 * (sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_BARDDANCER)) * pc->checkskill(sd,(sd->status.sex?BA_MUSICALLESSON:DC_DANCINGLESSON)) ); - - if( sc->data[SC_DEC_AGI] ) - val = max( val, 25 ); - if( sc->data[SC_QUAGMIRE] || sc->data[SC_HALLUCINATIONWALK_POSTDELAY] || (sc->data[SC_GLOOMYDAY] && sc->data[SC_GLOOMYDAY]->val4) ) - val = max( val, 50 ); - if( sc->data[SC_DONTFORGETME] ) - val = max( val, sc->data[SC_DONTFORGETME]->val3 ); - if( sc->data[SC_CURSE] ) - val = max( val, 300 ); - if( sc->data[SC_CHASEWALK] ) - val = max( val, sc->data[SC_CHASEWALK]->val3 ); - if( sc->data[SC_WEDDING] ) - val = max( val, 100 ); - if( sc->data[SC_JOINTBEAT] && sc->data[SC_JOINTBEAT]->val2&(BREAK_ANKLE|BREAK_KNEE) ) - val = max( val, (sc->data[SC_JOINTBEAT]->val2&BREAK_ANKLE ? 50 : 0) + (sc->data[SC_JOINTBEAT]->val2&BREAK_KNEE ? 30 : 0) ); - if( sc->data[SC_CLOAKING] && (sc->data[SC_CLOAKING]->val4&1) == 0 ) - val = max( val, sc->data[SC_CLOAKING]->val1 < 3 ? 300 : 30 - 3 * sc->data[SC_CLOAKING]->val1 ); - if( sc->data[SC_GOSPEL] && sc->data[SC_GOSPEL]->val4 == BCT_ENEMY ) - val = max( val, 75 ); - if( sc->data[SC_SLOWDOWN] ) // Slow Potion - val = max( val, 100 ); - if( sc->data[SC_GS_GATLINGFEVER] ) - val = max( val, 100 ); - if( sc->data[SC_NJ_SUITON] ) - val = max( val, sc->data[SC_NJ_SUITON]->val3 ); - if( sc->data[SC_SWOO] ) - val = max( val, 300 ); - if( sc->data[SC_FROSTMISTY] ) - val = max( val, 50 ); - if( sc->data[SC_CAMOUFLAGE] && (sc->data[SC_CAMOUFLAGE]->val3&1) == 0 ) - val = max( val, sc->data[SC_CAMOUFLAGE]->val1 < 3 ? 0 : 25 * (5 - sc->data[SC_CAMOUFLAGE]->val1) ); - if( sc->data[SC__GROOMY] ) - val = max( val, sc->data[SC__GROOMY]->val2); - if( sc->data[SC_STEALTHFIELD_MASTER] ) - val = max( val, 30 ); - if( sc->data[SC_BANDING_DEFENCE] ) - val = max( val, sc->data[SC_BANDING_DEFENCE]->val1 );//+90% walking speed. - if( sc->data[SC_ROCK_CRUSHER_ATK] ) - val = max( val, sc->data[SC_ROCK_CRUSHER_ATK]->val2 ); - if( sc->data[SC_POWER_OF_GAIA] ) - val = max( val, sc->data[SC_POWER_OF_GAIA]->val2 ); - if( sc->data[SC_MELON_BOMB] ) - val = max( val, sc->data[SC_MELON_BOMB]->val1 ); - - if( sc->data[SC_MARSHOFABYSS] ) // It stacks to other statuses so always put this at the end. - val = max( 50, val + 10 * sc->data[SC_MARSHOFABYSS]->val1 ); - - 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 ); - } + { + // Longing for Freedom cancels song/dance penalty + if( sc->data[SC_LONGING] ) + val = max( val, 50 - 10 * sc->data[SC_LONGING]->val1 ); + else + if( sd && sc->data[SC_DANCING] ) + val = max( val, 500 - (40 + 10 * (sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_BARDDANCER)) * pc->checkskill(sd,(sd->status.sex?BA_MUSICALLESSON:DC_DANCINGLESSON)) ); + + if( sc->data[SC_DEC_AGI] ) + val = max( val, 25 ); + if( sc->data[SC_QUAGMIRE] || sc->data[SC_HALLUCINATIONWALK_POSTDELAY] ) + val = max( val, 50 ); + if( sc->data[SC_DONTFORGETME] ) + val = max( val, sc->data[SC_DONTFORGETME]->val3 ); + if( sc->data[SC_CURSE] ) + val = max( val, 300 ); + if( sc->data[SC_CHASEWALK] ) + val = max( val, sc->data[SC_CHASEWALK]->val3 ); + if( sc->data[SC_WEDDING] ) + val = max( val, 100 ); + if( sc->data[SC_JOINTBEAT] && sc->data[SC_JOINTBEAT]->val2&(BREAK_ANKLE|BREAK_KNEE) ) + val = max( val, (sc->data[SC_JOINTBEAT]->val2&BREAK_ANKLE ? 50 : 0) + (sc->data[SC_JOINTBEAT]->val2&BREAK_KNEE ? 30 : 0) ); + if( sc->data[SC_CLOAKING] && (sc->data[SC_CLOAKING]->val4&1) == 0 ) + val = max( val, sc->data[SC_CLOAKING]->val1 < 3 ? 300 : 30 - 3 * sc->data[SC_CLOAKING]->val1 ); + if( sc->data[SC_GOSPEL] && sc->data[SC_GOSPEL]->val4 == BCT_ENEMY ) + val = max( val, 75 ); + if( sc->data[SC_SLOWDOWN] ) // Slow Potion + val = max( val, 100 ); + if( sc->data[SC_GS_GATLINGFEVER] ) + val = max( val, 100 ); + if( sc->data[SC_NJ_SUITON] ) + val = max( val, sc->data[SC_NJ_SUITON]->val3 ); + if( sc->data[SC_SWOO] ) + val = max( val, 300 ); + if( sc->data[SC_FROSTMISTY] ) + val = max( val, 50 ); + if( sc->data[SC_CAMOUFLAGE] && (sc->data[SC_CAMOUFLAGE]->val3&1) == 0 ) + val = max( val, sc->data[SC_CAMOUFLAGE]->val1 < 3 ? 0 : 25 * (5 - sc->data[SC_CAMOUFLAGE]->val1) ); + if( sc->data[SC__GROOMY] ) + val = max( val, sc->data[SC__GROOMY]->val2); + if( sc->data[SC_GLOOMYDAY] ) + val = max( val, sc->data[SC_GLOOMYDAY]->val3 ); // Should be 50 (-50% speed) + if( sc->data[SC_STEALTHFIELD_MASTER] ) + val = max( val, 30 ); + if( sc->data[SC_BANDING_DEFENCE] ) + val = max( val, sc->data[SC_BANDING_DEFENCE]->val1 );//+90% walking speed. + if( sc->data[SC_ROCK_CRUSHER_ATK] ) + val = max( val, sc->data[SC_ROCK_CRUSHER_ATK]->val2 ); + if( sc->data[SC_POWER_OF_GAIA] ) + val = max( val, sc->data[SC_POWER_OF_GAIA]->val2 ); + if( sc->data[SC_MELON_BOMB] ) + val = max( val, sc->data[SC_MELON_BOMB]->val1 ); + + if( sc->data[SC_MARSHOFABYSS] ) // It stacks to other statuses so always put this at the end. + val = max( 50, val + 10 * sc->data[SC_MARSHOFABYSS]->val1 ); + + 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() @@ -5204,7 +5310,7 @@ static unsigned short status_calc_speed(struct block_list *bl, struct status_cha val = max( val, 1 * pc->checkskill(sd,TF_MISS) ); if( sc->data[SC_CLOAKING] && (sc->data[SC_CLOAKING]->val4&1) == 1 ) val = max( val, sc->data[SC_CLOAKING]->val1 >= 10 ? 25 : 3 * sc->data[SC_CLOAKING]->val1 - 3 ); - if (sc->data[SC_BERSERK] || sc->data[SC__BLOODYLUST]) + if (sc->data[SC_BERSERK]) val = max( val, 25 ); if( sc->data[SC_RUN] ) val = max( val, 55 ); @@ -5219,7 +5325,7 @@ static unsigned short status_calc_speed(struct block_list *bl, struct status_cha if( sc->data[SC_GN_CARTBOOST] ) val = max( val, sc->data[SC_GN_CARTBOOST]->val2 ); if( sc->data[SC_SWING] ) - val = max( val, sc->data[SC_SWING]->val2 ); + val = max( val, sc->data[SC_SWING]->val3 ); if( sc->data[SC_WIND_STEP_OPTION] ) val = max( val, sc->data[SC_WIND_STEP_OPTION]->val2 ); if( sc->data[SC_FULL_THROTTLE] ) @@ -5256,14 +5362,13 @@ static unsigned short status_calc_speed(struct block_list *bl, struct status_cha } - return (short)cap_value(speed,10,USHRT_MAX); + return (unsigned short)cap_value(speed,MIN_WALK_SPEED,MAX_WALK_SPEED); } -#ifdef RENEWAL_ASPD // flag&1 - fixed value [malufett] // flag&2 - percentage value -static short status_calc_aspd(struct block_list *bl, struct status_change *sc, short flag) -{ +short status_calc_aspd(struct block_list *bl, struct status_change *sc, short flag) { +#ifdef RENEWAL_ASPD int i, pots = 0, skills1 = 0, skills2 = 0; if(!sc || !sc->count) @@ -5297,7 +5402,7 @@ static short status_calc_aspd(struct block_list *bl, struct status_change *sc, s skills1 = 5; } - if((sc->data[SC_BERSERK] || sc->data[SC__BLOODYLUST]) && skills1 < 15) + if((sc->data[SC_BERSERK]) && skills1 < 15) skills1 = 15; else if(sc->data[SC_GS_MADNESSCANCEL] && skills1 < 20) skills1 = 20; @@ -5329,20 +5434,22 @@ static short status_calc_aspd(struct block_list *bl, struct status_change *sc, s if( sc->data[SC_PARALYSE] ) skills2 -= 10; if( sc->data[SC__BODYPAINT] ) - skills2 -= 2 + 5 * sc->data[SC__BODYPAINT]->val1; + skills2 -= sc->data[SC__BODYPAINT]->val1; if( sc->data[SC__INVISIBILITY] ) skills2 -= sc->data[SC__INVISIBILITY]->val2 ; if( sc->data[SC__GROOMY] ) skills2 -= sc->data[SC__GROOMY]->val2; if( sc->data[SC_GLOOMYDAY] ) - skills2 -= sc->data[SC_GLOOMYDAY]->val3; + skills2 -= ( 15 + 5 * sc->data[SC_GLOOMYDAY]->val1 ); if( sc->data[SC_EARTHDRIVE] ) skills2 -= 25; if( sc->data[SC_MELON_BOMB] ) skills2 -= sc->data[SC_MELON_BOMB]->val1; + if( sc->data[SC_PAIN_KILLER] ) + skills2 -= sc->data[SC_PAIN_KILLER]->val2; if( sc->data[SC_SWING] ) - skills2 += sc->data[SC_SWING]->val2; + skills2 += sc->data[SC_SWING]->val3; if( sc->data[SC_DANCE_WITH_WUG] ) skills2 += sc->data[SC_DANCE_WITH_WUG]->val3; if( sc->data[SC_GENTLETOUCH_CHANGE] ) @@ -5361,7 +5468,7 @@ static short status_calc_aspd(struct block_list *bl, struct status_change *sc, s if (bl->type!=BL_PC) skills2 += sc->data[SC_ASSNCROS]->val2; else - switch(((TBL_PC*)bl)->status.weapon) + switch(((TBL_PC*)bl)->status.weapon) { case W_BOW: case W_REVOLVER: @@ -5375,30 +5482,31 @@ static short status_calc_aspd(struct block_list *bl, struct status_change *sc, s } } return ( flag&1? (skills1 + pots) : skills2 ); -} +#else + return 0; #endif +} -static short status_calc_fix_aspd(struct block_list *bl, struct status_change *sc, int aspd) { - if (!sc || !sc->count) - return cap_value(aspd, 0, 2000); - - if (!sc->data[SC_QUAGMIRE]) { - if (sc->data[SC_OVERED_BOOST]) - aspd = 2000 - sc->data[SC_OVERED_BOOST]->val3*10; - } +short status_calc_fix_aspd(struct block_list *bl, struct status_change *sc, int aspd) { + if (!sc || !sc->count) + return cap_value(aspd, 0, 2000); if ((sc->data[SC_GUST_OPTION] || sc->data[SC_BLAST_OPTION] - || sc->data[SC_WILD_STORM_OPTION])) + || sc->data[SC_WILD_STORM_OPTION])) aspd -= 50; // +5 ASPD if( sc && sc->data[SC_FIGHTINGSPIRIT] && sc->data[SC_FIGHTINGSPIRIT]->val2 ) aspd -= (bl->type==BL_PC?pc->checkskill((TBL_PC *)bl, RK_RUNEMASTERY):10) / 10 * 40; + if( sc && sc->data[SC_MTF_ASPD] ) + aspd -= 10; - return cap_value(aspd, 0, 2000); // will be recap for proper bl anyway + if (sc->data[SC_OVERED_BOOST]) // should be final and unmodifiable by any means + aspd = 2000 - sc->data[SC_OVERED_BOOST]->val3 * 10; + return cap_value(aspd, 0, 2000); // will be recap for proper bl anyway } /// Calculates an object's ASPD modifier (alters the base amotion value). /// Note that the scale of aspd_rate is 1000 = 100%. -static short status_calc_aspd_rate(struct block_list *bl, struct status_change *sc, int aspd_rate) +short status_calc_aspd_rate(struct block_list *bl, struct status_change *sc, int aspd_rate) { int i; @@ -5448,7 +5556,7 @@ static short status_calc_aspd_rate(struct block_list *bl, struct status_change * if (bl->type!=BL_PC) max = sc->data[SC_ASSNCROS]->val2; else - switch(((TBL_PC*)bl)->status.weapon) + switch(((TBL_PC*)bl)->status.weapon) { case W_BOW: case W_REVOLVER: @@ -5463,7 +5571,7 @@ static short status_calc_aspd_rate(struct block_list *bl, struct status_change * } aspd_rate -= max; - if((sc->data[SC_BERSERK] || sc->data[SC__BLOODYLUST])) + if(sc->data[SC_BERSERK]) aspd_rate -= 300; else if(sc->data[SC_GS_MADNESSCANCEL]) aspd_rate -= 200; @@ -5504,17 +5612,17 @@ static short status_calc_aspd_rate(struct block_list *bl, struct status_change * if( sc->data[SC_PARALYSE] ) aspd_rate += 100; if( sc->data[SC__BODYPAINT] ) - aspd_rate += 200 + 50 * sc->data[SC__BODYPAINT]->val1; + aspd_rate += 10 * 5 * sc->data[SC__BODYPAINT]->val1; if( sc->data[SC__INVISIBILITY] ) aspd_rate += sc->data[SC__INVISIBILITY]->val2 * 10 ; if( sc->data[SC__GROOMY] ) aspd_rate += sc->data[SC__GROOMY]->val2 * 10; if( sc->data[SC_SWING] ) - aspd_rate -= sc->data[SC_SWING]->val2 * 10; + aspd_rate -= sc->data[SC_SWING]->val3 * 10; if( sc->data[SC_DANCE_WITH_WUG] ) aspd_rate -= sc->data[SC_DANCE_WITH_WUG]->val3 * 10; if( sc->data[SC_GLOOMYDAY] ) - aspd_rate += sc->data[SC_GLOOMYDAY]->val3 * 10; + aspd_rate += ( 15 + 5 * sc->data[SC_GLOOMYDAY]->val1 ); if( sc->data[SC_EARTHDRIVE] ) aspd_rate += 250; if( sc->data[SC_GENTLETOUCH_CHANGE] ) @@ -5535,14 +5643,15 @@ static short status_calc_aspd_rate(struct block_list *bl, struct status_change * return (short)cap_value(aspd_rate,0,SHRT_MAX); } -static unsigned short status_calc_dmotion(struct block_list *bl, struct status_change *sc, int dmotion) -{ - if( !sc || !sc->count || map_flag_gvg(bl->m) || map[bl->m].flag.battleground ) +unsigned short status_calc_dmotion(struct block_list *bl, struct status_change *sc, int dmotion) { + // It has been confirmed on official servers that MvP mobs have no dmotion even without endure + if( bl->type == BL_MOB && (((TBL_MOB*)bl)->status.mode&MD_BOSS) ) + return 0; + + if( !sc || !sc->count || map_flag_gvg2(bl->m) || map->list[bl->m].flag.battleground ) return cap_value(dmotion,0,USHRT_MAX); - /** - * It has been confirmed on official servers that MvP mobs have no dmotion even without endure - **/ - if( sc->data[SC_ENDURE] || ( bl->type == BL_MOB && (((TBL_MOB*)bl)->status.mode&MD_BOSS) ) ) + + if( sc->data[SC_ENDURE] ) return 0; if( sc->data[SC_RUN] || sc->data[SC_WUGDASH] ) return 0; @@ -5550,7 +5659,7 @@ static unsigned short status_calc_dmotion(struct block_list *bl, struct status_c return (unsigned short)cap_value(dmotion,0,USHRT_MAX); } -static unsigned int status_calc_maxhp(struct block_list *bl, struct status_change *sc, uint64 maxhp) +unsigned int status_calc_maxhp(struct block_list *bl, struct status_change *sc, uint64 maxhp) { if(!sc || !sc->count) return (unsigned int)cap_value(maxhp,1,UINT_MAX); @@ -5563,7 +5672,7 @@ static unsigned int status_calc_maxhp(struct block_list *bl, struct status_chang maxhp += maxhp * sc->data[SC_APPLEIDUN]->val2/100; if(sc->data[SC_DELUGE]) maxhp += maxhp * sc->data[SC_DELUGE]->val2/100; - if (sc->data[SC_BERSERK] || sc->data[SC__BLOODYLUST]) + if(sc->data[SC_BERSERK]) maxhp += maxhp * 2; if(sc->data[SC_MARIONETTE_MASTER]) maxhp -= 1000; @@ -5584,11 +5693,13 @@ static unsigned int status_calc_maxhp(struct block_list *bl, struct status_chang if(sc->data[SC__WEAKNESS]) maxhp -= maxhp * sc->data[SC__WEAKNESS]->val2 / 100; if(sc->data[SC_LERADS_DEW]) - maxhp += maxhp * sc->data[SC_LERADS_DEW]->val3 / 100; + maxhp += sc->data[SC_LERADS_DEW]->val3; + if(sc->data[SC_BEYOND_OF_WARCRY]) + maxhp -= maxhp * sc->data[SC_BEYOND_OF_WARCRY]->val4 / 100; if(sc->data[SC_FORCEOFVANGUARD]) maxhp += maxhp * 3 * sc->data[SC_FORCEOFVANGUARD]->val1 / 100; - if(sc->data[SC_INSPIRATION]) //Custom value. - maxhp += maxhp * 3 * sc->data[SC_INSPIRATION]->val1 / 100; + if(sc->data[SC_INSPIRATION]) + maxhp += maxhp * 5 * sc->data[SC_INSPIRATION]->val1 / 100 + 600 * sc->data[SC_INSPIRATION]->val1; if(sc->data[SC_RAISINGDRAGON]) maxhp += maxhp * (2 + sc->data[SC_RAISINGDRAGON]->val1) / 100; if(sc->data[SC_GENTLETOUCH_CHANGE]) // Max HP decrease: [Skill Level x 4] % @@ -5601,6 +5712,10 @@ static unsigned int status_calc_maxhp(struct block_list *bl, struct status_chang maxhp -= sc->data[SC_MYSTERIOUS_POWDER]->val1 / 100; if(sc->data[SC_PETROLOGY_OPTION]) maxhp += maxhp * sc->data[SC_PETROLOGY_OPTION]->val2 / 100; + if(sc->data[SC_CURSED_SOIL_OPTION]) + maxhp += maxhp * sc->data[SC_CURSED_SOIL_OPTION]->val2 / 100; + if(sc->data[SC_UPHEAVAL_OPTION]) + maxhp += maxhp * sc->data[SC_UPHEAVAL_OPTION]->val3 / 100; if (sc->data[SC_ANGRIFFS_MODUS]) maxhp += maxhp * 5 * sc->data[SC_ANGRIFFS_MODUS]->val1 /100; if (sc->data[SC_GOLDENE_FERSE]) @@ -5611,7 +5726,7 @@ static unsigned int status_calc_maxhp(struct block_list *bl, struct status_chang return (unsigned int)cap_value(maxhp,1,UINT_MAX); } -static unsigned int status_calc_maxsp(struct block_list *bl, struct status_change *sc, unsigned int maxsp) +unsigned int status_calc_maxsp(struct block_list *bl, struct status_change *sc, unsigned int maxsp) { if(!sc || !sc->count) return cap_value(maxsp,1,UINT_MAX); @@ -5634,7 +5749,7 @@ static unsigned int status_calc_maxsp(struct block_list *bl, struct status_chang return cap_value(maxsp,1,UINT_MAX); } -static unsigned char status_calc_element(struct block_list *bl, struct status_change *sc, int element) +unsigned char status_calc_element(struct block_list *bl, struct status_change *sc, int element) { if(!sc || !sc->count) return element; @@ -5655,7 +5770,7 @@ static unsigned char status_calc_element(struct block_list *bl, struct status_ch return (unsigned char)cap_value(element,0,UCHAR_MAX); } -static unsigned char status_calc_element_lv(struct block_list *bl, struct status_change *sc, int lv) +unsigned char status_calc_element_lv(struct block_list *bl, struct status_change *sc, int lv) { if(!sc || !sc->count) return lv; @@ -5686,16 +5801,16 @@ unsigned char status_calc_attack_element(struct block_list *bl, struct status_ch if(sc->data[SC_ENCHANTARMS]) return sc->data[SC_ENCHANTARMS]->val2; if(sc->data[SC_PROPERTYWATER] - || (sc->data[SC_WATER_INSIGNIA] && sc->data[SC_WATER_INSIGNIA]->val1 == 2) ) + || (sc->data[SC_WATER_INSIGNIA] && sc->data[SC_WATER_INSIGNIA]->val1 == 2) ) return ELE_WATER; if(sc->data[SC_PROPERTYGROUND] - || (sc->data[SC_EARTH_INSIGNIA] && sc->data[SC_EARTH_INSIGNIA]->val1 == 2) ) + || (sc->data[SC_EARTH_INSIGNIA] && sc->data[SC_EARTH_INSIGNIA]->val1 == 2) ) return ELE_EARTH; if(sc->data[SC_PROPERTYFIRE] - || (sc->data[SC_FIRE_INSIGNIA] && sc->data[SC_FIRE_INSIGNIA]->val1 == 2) ) + || (sc->data[SC_FIRE_INSIGNIA] && sc->data[SC_FIRE_INSIGNIA]->val1 == 2) ) return ELE_FIRE; if(sc->data[SC_PROPERTYWIND] - || (sc->data[SC_WIND_INSIGNIA] && sc->data[SC_WIND_INSIGNIA]->val1 == 2) ) + || (sc->data[SC_WIND_INSIGNIA] && sc->data[SC_WIND_INSIGNIA]->val1 == 2) ) return ELE_WIND; if(sc->data[SC_ENCHANTPOISON]) return ELE_POISON; @@ -5707,12 +5822,12 @@ unsigned char status_calc_attack_element(struct block_list *bl, struct status_ch return ELE_GHOST; if(sc->data[SC_TIDAL_WEAPON_OPTION] || sc->data[SC_TIDAL_WEAPON] ) return ELE_WATER; - if(sc->data[SC_PYROCLASTIC]) - return ELE_FIRE; + if(sc->data[SC_PYROCLASTIC]) + return ELE_FIRE; return (unsigned char)cap_value(element,0,UCHAR_MAX); } -static unsigned short status_calc_mode(struct block_list *bl, struct status_change *sc, int mode) +unsigned short status_calc_mode(struct block_list *bl, struct status_change *sc, int mode) { if(!sc || !sc->count) return mode; @@ -5730,21 +5845,21 @@ static unsigned short status_calc_mode(struct block_list *bl, struct status_chan const char* status_get_name(struct block_list *bl) { nullpo_ret(bl); switch (bl->type) { - case BL_PC: return ((TBL_PC *)bl)->fakename[0] != '\0' ? ((TBL_PC*)bl)->fakename : ((TBL_PC*)bl)->status.name; - case BL_MOB: return ((TBL_MOB*)bl)->name; - case BL_PET: return ((TBL_PET*)bl)->pet.name; - case BL_HOM: return ((TBL_HOM*)bl)->homunculus.name; - case BL_NPC: return ((TBL_NPC*)bl)->name; + case BL_PC: return ((TBL_PC *)bl)->fakename[0] != '\0' ? ((TBL_PC*)bl)->fakename : ((TBL_PC*)bl)->status.name; + case BL_MOB: return ((TBL_MOB*)bl)->name; + case BL_PET: return ((TBL_PET*)bl)->pet.name; + case BL_HOM: return ((TBL_HOM*)bl)->homunculus.name; + case BL_NPC: return ((TBL_NPC*)bl)->name; } return "Unknown"; } /*========================================== - * Get the class of the current bl - * return - * 0 = fail - * class_id = success - *------------------------------------------*/ +* Get the class of the current bl +* return +* 0 = fail +* class_id = success +*------------------------------------------*/ int status_get_class(struct block_list *bl) { nullpo_ret(bl); switch( bl->type ) { @@ -5759,11 +5874,11 @@ int status_get_class(struct block_list *bl) { return 0; } /*========================================== - * Get the base level of the current bl - * return - * 1 = fail - * level = success - *------------------------------------------*/ +* Get the base level of the current bl +* return +* 1 = fail +* level = success +*------------------------------------------*/ int status_get_lv(struct block_list *bl) { nullpo_ret(bl); switch (bl->type) { @@ -5793,7 +5908,7 @@ struct regen_data *status_get_regen_data(struct block_list *bl) struct status_data *status_get_status_data(struct block_list *bl) { - nullpo_retr(&dummy_status, bl); + nullpo_retr(&status->dummy, bl); switch (bl->type) { case BL_PC: return &((TBL_PC*)bl)->battle_status; @@ -5802,9 +5917,9 @@ struct status_data *status_get_status_data(struct block_list *bl) case BL_HOM: return &((TBL_HOM*)bl)->battle_status; case BL_MER: return &((TBL_MER*)bl)->battle_status; case BL_ELEM: return &((TBL_ELEM*)bl)->battle_status; - case BL_NPC: return ((mobdb_checkid(((TBL_NPC*)bl)->class_) == 0) ? &((TBL_NPC*)bl)->status : &dummy_status); + case BL_NPC: return ((mob->db_checkid(((TBL_NPC*)bl)->class_) == 0) ? &((TBL_NPC*)bl)->status : &status->dummy); default: - return &dummy_status; + return &status->dummy; } } @@ -5818,62 +5933,61 @@ struct status_data *status_get_base_status(struct block_list *bl) case BL_HOM: return &((TBL_HOM*)bl)->base_status; case BL_MER: return &((TBL_MER*)bl)->base_status; case BL_ELEM: return &((TBL_ELEM*)bl)->base_status; - case BL_NPC: return ((mobdb_checkid(((TBL_NPC*)bl)->class_) == 0) ? &((TBL_NPC*)bl)->status : NULL); + case BL_NPC: return ((mob->db_checkid(((TBL_NPC*)bl)->class_) == 0) ? &((TBL_NPC*)bl)->status : NULL); default: return NULL; } } defType status_get_def(struct block_list *bl) { struct unit_data *ud; - struct status_data *status = status_get_status_data(bl); - int def = status?status->def:0; - ud = unit_bl2ud(bl); + struct status_data *st = status->get_status_data(bl); + int def = st ? st->def : 0; + ud = unit->bl2ud(bl); if (ud && ud->skilltimer != INVALID_TIMER) def -= def * skill->get_castdef(ud->skill_id)/100; return cap_value(def, DEFTYPE_MIN, DEFTYPE_MAX); } -unsigned short status_get_speed(struct block_list *bl) -{ - if(bl->type==BL_NPC)//Only BL with speed data but no status_data [Skotlex] - return ((struct npc_data *)bl)->speed; - return status_get_status_data(bl)->speed; +unsigned short status_get_speed(struct block_list *bl) { + if(bl->type==BL_NPC)//Only BL with speed data but no status_data [Skotlex] + return ((struct npc_data *)bl)->speed; + return status->get_status_data(bl)->speed; } int status_get_party_id(struct block_list *bl) { nullpo_ret(bl); switch (bl->type) { - case BL_PC: - return ((TBL_PC*)bl)->status.party_id; - case BL_PET: - if (((TBL_PET*)bl)->msd) - return ((TBL_PET*)bl)->msd->status.party_id; - break; - case BL_MOB: { - struct mob_data *md=(TBL_MOB*)bl; - if( md->master_id > 0 ) { - struct map_session_data *msd; - if (md->special_state.ai && (msd = iMap->id2sd(md->master_id)) != NULL) - return msd->status.party_id; - return -md->master_id; - } - } - break; - case BL_HOM: - if (((TBL_HOM*)bl)->master) - return ((TBL_HOM*)bl)->master->status.party_id; - break; - case BL_MER: - if (((TBL_MER*)bl)->master) - return ((TBL_MER*)bl)->master->status.party_id; - break; - case BL_SKILL: - return ((TBL_SKILL*)bl)->group->party_id; - case BL_ELEM: - if (((TBL_ELEM*)bl)->master) - return ((TBL_ELEM*)bl)->master->status.party_id; - break; + case BL_PC: + return ((TBL_PC*)bl)->status.party_id; + case BL_PET: + if (((TBL_PET*)bl)->msd) + return ((TBL_PET*)bl)->msd->status.party_id; + break; + case BL_MOB: { + struct mob_data *md=(TBL_MOB*)bl; + if( md->master_id > 0 ) { + struct map_session_data *msd; + if (md->special_state.ai && (msd = map->id2sd(md->master_id)) != NULL) + return msd->status.party_id; + return -md->master_id; + } + } + break; + case BL_HOM: + if (((TBL_HOM*)bl)->master) + return ((TBL_HOM*)bl)->master->status.party_id; + break; + case BL_MER: + if (((TBL_MER*)bl)->master) + return ((TBL_MER*)bl)->master->status.party_id; + break; + case BL_SKILL: + return ((TBL_SKILL*)bl)->group->party_id; + case BL_ELEM: + if (((TBL_ELEM*)bl)->master) + return ((TBL_ELEM*)bl)->master->status.party_id; + break; } return 0; } @@ -5881,39 +5995,42 @@ int status_get_party_id(struct block_list *bl) { int status_get_guild_id(struct block_list *bl) { nullpo_ret(bl); switch (bl->type) { - case BL_PC: - return ((TBL_PC*)bl)->status.guild_id; - case BL_PET: - if (((TBL_PET*)bl)->msd) - return ((TBL_PET*)bl)->msd->status.guild_id; - break; - case BL_MOB: { - struct map_session_data *msd; - struct mob_data *md = (struct mob_data *)bl; - if (md->guardian_data) //Guardian's guild [Skotlex] - return md->guardian_data->guild_id; - if (md->special_state.ai && (msd = iMap->id2sd(md->master_id)) != NULL) - return msd->status.guild_id; //Alchemist's mobs [Skotlex] - } - break; - case BL_HOM: - if (((TBL_HOM*)bl)->master) - return ((TBL_HOM*)bl)->master->status.guild_id; - break; - case BL_MER: - if (((TBL_MER*)bl)->master) - return ((TBL_MER*)bl)->master->status.guild_id; - break; - case BL_NPC: - if (((TBL_NPC*)bl)->subtype == SCRIPT) - return ((TBL_NPC*)bl)->u.scr.guild_id; - break; - case BL_SKILL: - return ((TBL_SKILL*)bl)->group->guild_id; - case BL_ELEM: - if (((TBL_ELEM*)bl)->master) - return ((TBL_ELEM*)bl)->master->status.guild_id; - break; + case BL_PC: + return ((TBL_PC*)bl)->status.guild_id; + case BL_PET: + if (((TBL_PET*)bl)->msd) + return ((TBL_PET*)bl)->msd->status.guild_id; + break; + case BL_MOB: + { + struct map_session_data *msd; + struct mob_data *md = (struct mob_data *)bl; + if( md->guardian_data ) { //Guardian's guild [Skotlex] + // Guardian guild data may not been available yet, castle data is always set + return (md->guardian_data->g)?md->guardian_data->g->guild_id:md->guardian_data->castle->guild_id; + } + if( md->special_state.ai && (msd = map->id2sd(md->master_id)) != NULL ) + return msd->status.guild_id; //Alchemist's mobs [Skotlex] + break; + } + case BL_HOM: + if (((TBL_HOM*)bl)->master) + return ((TBL_HOM*)bl)->master->status.guild_id; + break; + case BL_MER: + if (((TBL_MER*)bl)->master) + return ((TBL_MER*)bl)->master->status.guild_id; + break; + case BL_NPC: + if (((TBL_NPC*)bl)->subtype == SCRIPT) + return ((TBL_NPC*)bl)->u.scr.guild_id; + break; + case BL_SKILL: + return ((TBL_SKILL*)bl)->group->guild_id; + case BL_ELEM: + if (((TBL_ELEM*)bl)->master) + return ((TBL_ELEM*)bl)->master->status.guild_id; + break; } return 0; } @@ -5921,40 +6038,40 @@ int status_get_guild_id(struct block_list *bl) { int status_get_emblem_id(struct block_list *bl) { nullpo_ret(bl); switch (bl->type) { - case BL_PC: - return ((TBL_PC*)bl)->guild_emblem_id; - case BL_PET: - if (((TBL_PET*)bl)->msd) - return ((TBL_PET*)bl)->msd->guild_emblem_id; - break; - case BL_MOB: { - struct map_session_data *msd; - struct mob_data *md = (struct mob_data *)bl; - if (md->guardian_data) //Guardian's guild [Skotlex] - return md->guardian_data->emblem_id; - if (md->special_state.ai && (msd = iMap->id2sd(md->master_id)) != NULL) - return msd->guild_emblem_id; //Alchemist's mobs [Skotlex] - } - break; - case BL_HOM: - if (((TBL_HOM*)bl)->master) - return ((TBL_HOM*)bl)->master->guild_emblem_id; - break; - case BL_MER: - if (((TBL_MER*)bl)->master) - return ((TBL_MER*)bl)->master->guild_emblem_id; - break; - case BL_NPC: - if (((TBL_NPC*)bl)->subtype == SCRIPT && ((TBL_NPC*)bl)->u.scr.guild_id > 0) { - struct guild *g = guild->search(((TBL_NPC*)bl)->u.scr.guild_id); - if (g) - return g->emblem_id; - } - break; - case BL_ELEM: - if (((TBL_ELEM*)bl)->master) - return ((TBL_ELEM*)bl)->master->guild_emblem_id; - break; + case BL_PC: + return ((TBL_PC*)bl)->guild_emblem_id; + case BL_PET: + if (((TBL_PET*)bl)->msd) + return ((TBL_PET*)bl)->msd->guild_emblem_id; + break; + case BL_MOB: { + struct map_session_data *msd; + struct mob_data *md = (struct mob_data *)bl; + if (md->guardian_data) //Guardian's guild [Skotlex] + return (md->guardian_data->g) ? md->guardian_data->g->emblem_id:0; + if (md->special_state.ai && (msd = map->id2sd(md->master_id)) != NULL) + return msd->guild_emblem_id; //Alchemist's mobs [Skotlex] + } + break; + case BL_HOM: + if (((TBL_HOM*)bl)->master) + return ((TBL_HOM*)bl)->master->guild_emblem_id; + break; + case BL_MER: + if (((TBL_MER*)bl)->master) + return ((TBL_MER*)bl)->master->guild_emblem_id; + break; + case BL_NPC: + if (((TBL_NPC*)bl)->subtype == SCRIPT && ((TBL_NPC*)bl)->u.scr.guild_id > 0) { + struct guild *g = guild->search(((TBL_NPC*)bl)->u.scr.guild_id); + if (g) + return g->emblem_id; + } + break; + case BL_ELEM: + if (((TBL_ELEM*)bl)->master) + return ((TBL_ELEM*)bl)->master->guild_emblem_id; + break; } return 0; } @@ -5978,15 +6095,13 @@ int status_get_race2(struct block_list *bl) return 0; } -int status_isdead(struct block_list *bl) -{ +int status_isdead(struct block_list *bl) { nullpo_ret(bl); - return status_get_status_data(bl)->hp == 0; + return status->get_status_data(bl)->hp == 0; } -int status_isimmune(struct block_list *bl) -{ - struct status_change *sc =status_get_sc(bl); +int status_isimmune(struct block_list *bl) { + struct status_change *sc = status->get_sc(bl); if (sc && sc->data[SC_HERMODE]) return 100; @@ -6015,135 +6130,137 @@ void status_set_viewdata(struct block_list *bl, int class_) { struct view_data* vd; nullpo_retv(bl); - if (mobdb_checkid(class_) || mob_is_clone(class_)) - vd = mob_get_viewdata(class_); + if (mob->db_checkid(class_) || mob->is_clone(class_)) + vd = mob->get_viewdata(class_); else if (npcdb_checkid(class_) || (bl->type == BL_NPC && class_ == WARP_CLASS)) - vd = npc_get_viewdata(class_); + vd = npc->get_viewdata(class_); else if (homdb_checkid(class_)) vd = homun->get_viewdata(class_); - else if (merc_class(class_)) - vd = merc_get_viewdata(class_); - else if (elemental_class(class_)) - vd = elemental_get_viewdata(class_); + else if (mercenary->class(class_)) + vd = mercenary->get_viewdata(class_); + else if (elemental->class(class_)) + vd = elemental->get_viewdata(class_); else vd = NULL; switch (bl->type) { - case BL_PC: - { - TBL_PC* sd = (TBL_PC*)bl; - if (pcdb_checkid(class_)) { - if (sd->sc.option&OPTION_RIDING) { - switch (class_) { //Adapt class to a Mounted one. - case JOB_KNIGHT: - class_ = JOB_KNIGHT2; - break; - case JOB_CRUSADER: - class_ = JOB_CRUSADER2; - break; - case JOB_LORD_KNIGHT: - class_ = JOB_LORD_KNIGHT2; - break; - case JOB_PALADIN: - class_ = JOB_PALADIN2; - break; - case JOB_BABY_KNIGHT: - class_ = JOB_BABY_KNIGHT2; - break; - case JOB_BABY_CRUSADER: - class_ = JOB_BABY_CRUSADER2; - break; - } - } - sd->vd.class_ = class_; - clif->get_weapon_view(sd, &sd->vd.weapon, &sd->vd.shield); - sd->vd.head_top = sd->status.head_top; - sd->vd.head_mid = sd->status.head_mid; - sd->vd.head_bottom = sd->status.head_bottom; - sd->vd.hair_style = cap_value(sd->status.hair,0,battle_config.max_hair_style); - sd->vd.hair_color = cap_value(sd->status.hair_color,0,battle_config.max_hair_color); - sd->vd.cloth_color = cap_value(sd->status.clothes_color,0,battle_config.max_cloth_color); - sd->vd.robe = sd->status.robe; - sd->vd.sex = sd->status.sex; - - if ( sd->vd.cloth_color ) { - if( sd->sc.option&OPTION_WEDDING && battle_config.wedding_ignorepalette ) - sd->vd.cloth_color = 0; - if( sd->sc.option&OPTION_XMAS && battle_config.xmas_ignorepalette ) - sd->vd.cloth_color = 0; - if( sd->sc.option&OPTION_SUMMER && battle_config.summer_ignorepalette ) - sd->vd.cloth_color = 0; - if( sd->sc.option&OPTION_HANBOK && battle_config.hanbok_ignorepalette ) - sd->vd.cloth_color = 0; + case BL_PC: + { + TBL_PC* sd = (TBL_PC*)bl; + if (pcdb_checkid(class_)) { + if (sd->sc.option&OPTION_RIDING) { + switch (class_) { //Adapt class to a Mounted one. + case JOB_KNIGHT: + class_ = JOB_KNIGHT2; + break; + case JOB_CRUSADER: + class_ = JOB_CRUSADER2; + break; + case JOB_LORD_KNIGHT: + class_ = JOB_LORD_KNIGHT2; + break; + case JOB_PALADIN: + class_ = JOB_PALADIN2; + break; + case JOB_BABY_KNIGHT: + class_ = JOB_BABY_KNIGHT2; + break; + case JOB_BABY_CRUSADER: + class_ = JOB_BABY_CRUSADER2; + break; } - } else if (vd) - memcpy(&sd->vd, vd, sizeof(struct view_data)); - else - ShowError("status_set_viewdata (PC): No view data for class %d\n", class_); - } + } + sd->vd.class_ = class_; + clif->get_weapon_view(sd, &sd->vd.weapon, &sd->vd.shield); + sd->vd.head_top = sd->status.head_top; + sd->vd.head_mid = sd->status.head_mid; + sd->vd.head_bottom = sd->status.head_bottom; + sd->vd.hair_style = cap_value(sd->status.hair,0,battle_config.max_hair_style); + sd->vd.hair_color = cap_value(sd->status.hair_color,0,battle_config.max_hair_color); + sd->vd.cloth_color = cap_value(sd->status.clothes_color,0,battle_config.max_cloth_color); + sd->vd.robe = sd->status.robe; + sd->vd.sex = sd->status.sex; + + if ( sd->vd.cloth_color ) { + if( sd->sc.option&OPTION_WEDDING && battle_config.wedding_ignorepalette ) + sd->vd.cloth_color = 0; + if( sd->sc.option&OPTION_XMAS && battle_config.xmas_ignorepalette ) + sd->vd.cloth_color = 0; + if( sd->sc.option&OPTION_SUMMER && battle_config.summer_ignorepalette ) + sd->vd.cloth_color = 0; + if( sd->sc.option&OPTION_HANBOK && battle_config.hanbok_ignorepalette ) + sd->vd.cloth_color = 0; + if( sd->sc.option&OPTION_OKTOBERFEST /* TODO: config? */ ) + sd->vd.cloth_color = 0; + } + } else if (vd) + memcpy(&sd->vd, vd, sizeof(struct view_data)); + else + ShowError("status_set_viewdata (PC): No view data for class %d\n", class_); + } break; - case BL_MOB: - { - TBL_MOB* md = (TBL_MOB*)bl; - if (vd) - md->vd = vd; - else - ShowError("status_set_viewdata (MOB): No view data for class %d\n", class_); - } + case BL_MOB: + { + TBL_MOB* md = (TBL_MOB*)bl; + if (vd) + md->vd = vd; + else + ShowError("status_set_viewdata (MOB): No view data for class %d\n", class_); + } break; - case BL_PET: - { - TBL_PET* pd = (TBL_PET*)bl; - if (vd) { - memcpy(&pd->vd, vd, sizeof(struct view_data)); - if (!pcdb_checkid(vd->class_)) { - pd->vd.hair_style = battle_config.pet_hair_style; - if(pd->pet.equip) { - pd->vd.head_bottom = itemdb_viewid(pd->pet.equip); - if (!pd->vd.head_bottom) - pd->vd.head_bottom = pd->pet.equip; - } + case BL_PET: + { + TBL_PET* pd = (TBL_PET*)bl; + if (vd) { + memcpy(&pd->vd, vd, sizeof(struct view_data)); + if (!pcdb_checkid(vd->class_)) { + pd->vd.hair_style = battle_config.pet_hair_style; + if(pd->pet.equip) { + pd->vd.head_bottom = itemdb_viewid(pd->pet.equip); + if (!pd->vd.head_bottom) + pd->vd.head_bottom = pd->pet.equip; } - } else - ShowError("status_set_viewdata (PET): No view data for class %d\n", class_); - } + } + } else + ShowError("status_set_viewdata (PET): No view data for class %d\n", class_); + } break; - case BL_NPC: - { - TBL_NPC* nd = (TBL_NPC*)bl; - if (vd) - nd->vd = vd; - else - ShowError("status_set_viewdata (NPC): No view data for class %d\n", class_); - } + case BL_NPC: + { + TBL_NPC* nd = (TBL_NPC*)bl; + if (vd) + nd->vd = vd; + else + ShowError("status_set_viewdata (NPC): No view data for class %d\n", class_); + } + break; + case BL_HOM: //[blackhole89] + { + struct homun_data *hd = (struct homun_data*)bl; + if (vd) + hd->vd = vd; + else + ShowError("status_set_viewdata (HOMUNCULUS): No view data for class %d\n", class_); + } + break; + case BL_MER: + { + struct mercenary_data *md = (struct mercenary_data*)bl; + if (vd) + md->vd = vd; + else + ShowError("status_set_viewdata (MERCENARY): No view data for class %d\n", class_); + } + break; + case BL_ELEM: + { + struct elemental_data *ed = (struct elemental_data*)bl; + if (vd) + ed->vd = vd; + else + ShowError("status_set_viewdata (ELEMENTAL): No view data for class %d\n", class_); + } break; - case BL_HOM: //[blackhole89] - { - struct homun_data *hd = (struct homun_data*)bl; - if (vd) - hd->vd = vd; - else - ShowError("status_set_viewdata (HOMUNCULUS): No view data for class %d\n", class_); - } - break; - case BL_MER: - { - struct mercenary_data *md = (struct mercenary_data*)bl; - if (vd) - md->vd = vd; - else - ShowError("status_set_viewdata (MERCENARY): No view data for class %d\n", class_); - } - break; - case BL_ELEM: - { - struct elemental_data *ed = (struct elemental_data*)bl; - if (vd) - ed->vd = vd; - else - ShowError("status_set_viewdata (ELEMENTAL): No view data for class %d\n", class_); - } - break; } } @@ -6151,192 +6268,308 @@ void status_set_viewdata(struct block_list *bl, int class_) struct status_change *status_get_sc(struct block_list *bl) { if( bl ) { switch (bl->type) { - case BL_PC: return &((TBL_PC*)bl)->sc; - case BL_MOB: return &((TBL_MOB*)bl)->sc; - case BL_NPC: return NULL; - case BL_HOM: return &((TBL_HOM*)bl)->sc; - case BL_MER: return &((TBL_MER*)bl)->sc; - case BL_ELEM: return &((TBL_ELEM*)bl)->sc; + case BL_PC: return &((TBL_PC*)bl)->sc; + case BL_MOB: return &((TBL_MOB*)bl)->sc; + case BL_NPC: return NULL; + case BL_HOM: return &((TBL_HOM*)bl)->sc; + case BL_MER: return &((TBL_MER*)bl)->sc; + case BL_ELEM: return &((TBL_ELEM*)bl)->sc; } } return NULL; } -void status_change_init(struct block_list *bl) -{ - struct status_change *sc = status_get_sc(bl); +void status_change_init(struct block_list *bl) { + struct status_change *sc = status->get_sc(bl); nullpo_retv(sc); memset(sc, 0, sizeof (struct status_change)); } //Applies SC defense to a given status change. //Returns the adjusted duration based on flag values. -//the flag values are the same as in status_change_start. -int status_get_sc_def(struct block_list *bl, enum sc_type type, int rate, int tick, int flag) -{ +//the flag values are the same as in status->change_start. +int status_get_sc_def(struct block_list *src, struct block_list *bl, enum sc_type type, int rate, int tick, int flag) { //Percentual resistance: 10000 = 100% Resist //Example: 50% -> sc_def=5000 -> 25%; 5000ms -> tick_def=5000 -> 2500ms int sc_def = 0, tick_def = -1; //-1 = use sc_def //Linear resistance substracted from rate and tick after percentual resistance was applied //Example: 25% -> sc_def2=2000 -> 5%; 2500ms -> tick_def2=2000 -> 500ms - int sc_def2 = 0, tick_def2 = -1; //-1 = use sc_def2 - struct status_data* status; - struct status_change* sc; + int sc_def2 = 0, tick_def2 = -1; //-1 = use sc_def2 (pre-re only) + + struct status_data *st; + struct status_change *sc; struct map_session_data *sd; nullpo_ret(bl); + + if(!src) + return tick ? tick : 1; // If no source, it can't be resisted (NPC given) + +/// Returns the 'bl's level, capped to 'cap' +#define SCDEF_LVL_CAP(bl, cap) ( (bl) ? (status->get_lv(bl) > (cap) ? (cap) : status->get_lv(bl)) : 0 ) +/// Renewal level modifier. +/// In renewal, returns the difference between the levels of 'bl' and 'src', both capped to 'maxlv', multiplied by 'factor' +/// In pre-renewal, returns zero. +#ifdef RENEWAL +#define SCDEF_LVL_DIFF(bl, src, maxlv, factor) ( ( SCDEF_LVL_CAP((bl), (maxlv)) - SCDEF_LVL_CAP((src), (maxlv)) ) * (factor) ) +#else +#define SCDEF_LVL_DIFF(bl, src, maxlv, factor) 0 +#endif //Status that are blocked by Golden Thief Bug card or Wand of Hermod - if (status_isimmune(bl)) + if (status->isimmune(bl)) switch (type) { - case SC_DEC_AGI: - case SC_SILENCE: - case SC_COMA: - case SC_INC_AGI: - case SC_BLESSING: - case SC_SLOWPOISON: - case SC_IMPOSITIO: - case SC_LEXAETERNA: - case SC_SUFFRAGIUM: - case SC_BENEDICTIO: - case SC_PROVIDENCE: - case SC_KYRIE: - case SC_ASSUMPTIO: - case SC_ANGELUS: - case SC_MAGNIFICAT: - case SC_GLORIA: - case SC_WINDWALK: - case SC_MAGICROD: - case SC_ILLUSION: - case SC_STONE: - case SC_QUAGMIRE: - case SC_NJ_SUITON: - case SC_SWING: - case SC__ENERVATION: - case SC__GROOMY: - case SC__IGNORANCE: - case SC__LAZINESS: - case SC__UNLUCKY: - case SC__WEAKNESS: - case SC__BLOODYLUST: - return 0; + case SC_DEC_AGI: + case SC_SILENCE: + case SC_COMA: + case SC_INC_AGI: + case SC_BLESSING: + case SC_SLOWPOISON: + case SC_IMPOSITIO: + case SC_LEXAETERNA: + case SC_SUFFRAGIUM: + case SC_BENEDICTIO: + case SC_PROVIDENCE: + case SC_KYRIE: + case SC_ASSUMPTIO: + case SC_ANGELUS: + case SC_MAGNIFICAT: + case SC_GLORIA: + case SC_WINDWALK: + case SC_MAGICROD: + case SC_ILLUSION: + case SC_STONE: + case SC_QUAGMIRE: + case SC_NJ_SUITON: + case SC_SWING: + case SC__ENERVATION: + case SC__GROOMY: + case SC__IGNORANCE: + case SC__LAZINESS: + case SC__UNLUCKY: + case SC__WEAKNESS: + return 0; } sd = BL_CAST(BL_PC,bl); - status = status_get_status_data(bl); - sc = status_get_sc(bl); + st = status->get_status_data(bl); + sc = status->get_sc(bl); if( sc && !sc->count ) sc = NULL; - switch (type) { - case SC_STUN: - case SC_POISON: - if( sc && sc->data[SC__UNLUCKY] ) - return tick; - case SC_DPOISON: - case SC_SILENCE: - case SC_BLOODING: - sc_def = status->vit*100; - sc_def2 = status->luk*10; - break; - case SC_SLEEP: - sc_def = status->int_*100; - sc_def2 = status->luk*10; - break; - case SC_DEEP_SLEEP: - sc_def = status->int_*50; - tick_def = status->int_*10 + status_get_lv(bl) * 65 / 10; //Seems to be -1 sec every 10 int and -5% chance every 10 int. - break; - case SC_DEC_AGI: - case SC_ADORAMUS: //Arch Bishop - if (sd) tick>>=1; //Half duration for players. - case SC_STONE: - //Impossible to reduce duration with stats - tick_def = 0; - tick_def2 = 0; - case SC_FREEZE: - sc_def = status->mdef*100; - sc_def2 = status->luk*10; - break; - case SC_CURSE: - //Special property: inmunity when luk is greater than level or zero - if (status->luk > status_get_lv(bl) || status->luk == 0) + + if (sc && sc->data[SC_KINGS_GRACE]) { + // Protects against status effects + switch (type) { + case SC_POISON: + case SC_BLIND: + case SC_FREEZE: + case SC_STONE: + case SC_STUN: + case SC_SLEEP: + case SC_BLOODING: + case SC_CURSE: + case SC_CONFUSION: + case SC_ILLUSION: + case SC_SILENCE: + case SC_BURNING: + case SC_COLD: + case SC_FROSTMISTY: + case SC_DEEP_SLEEP: + case SC_FEAR: + case SC_MANDRAGORA: + case SC__CHAOS: return 0; - sc_def = status->luk*100; - sc_def2 = status->luk*10; - tick_def = status->vit*100; - break; - case SC_BLIND: - if( sc && sc->data[SC__UNLUCKY] ) - return tick; - sc_def = (status->vit + status->int_)*50; - sc_def2 = status->luk*10; - break; - case SC_CONFUSION: - sc_def = (status->str + status->int_)*50; - sc_def2 = status->luk*10; - break; - case SC_ANKLESNARE: - if(status->mode&MD_BOSS) // Lasts 5 times less on bosses - tick /= 5; - sc_def = status->agi*50; - break; - case SC_MAGICMIRROR: - case SC_STONESKIN: - if (sd) //Duration greatly reduced for players. - tick /= 15; - sc_def2 = status_get_lv(bl)*20 + status->vit*25 + status->agi*10; // Lineal Reduction of Rate - tick_def2 = 0; //No duration reduction - break; - case SC_MARSHOFABYSS: - //5 second (Fixed) + 25 second - {( INT + LUK ) / 20 second } - tick_def2 = (status->int_ + status->luk)*50; - break; - case SC_STASIS: - //5 second (fixed) + { Stasis Skill level * 5 - (Target's VIT + DEX) / 20 } - tick_def2 = (status->vit + status->dex)*50; + } + } + + switch (type) { + case SC_STUN: + sc_def = st->vit*100; + sc_def2 = st->luk*10 + SCDEF_LVL_DIFF(bl, src, 99, 10); +#ifdef RENEWAL + tick_def2 = st->luk*10; +#endif + break; + case SC_POISON: + case SC_DPOISON: + sc_def = st->vit*100; + sc_def2 = st->luk*10 + SCDEF_LVL_DIFF(bl, src, 99, 10); +#ifdef RENEWAL + if (sd) { + //For players: 60000 - 450*vit - 100*luk + tick_def = st->vit*75; + tick_def2 = st->luk*100; + } else { + //For monsters: 30000 - 200*vit + tick>>=1; + tick_def = (st->vit*200)/3; + } +#endif + break; + case SC_SILENCE: +#ifdef RENEWAL + sc_def = st->int_*100; + sc_def2 = (st->vit + st->luk) * 5 + SCDEF_LVL_DIFF(bl, src, 99, 10); + tick_def2 = st->luk * 10; +#else + sc_def = st->vit*100; + sc_def2 = st->luk*10 + SCDEF_LVL_DIFF(bl, src, 99, 10); +#endif + break; + case SC_BLOODING: +#ifdef RENEWAL + sc_def = st->agi*100; + tick_def2 = st->luk*10; +#else + sc_def = st->vit*100; +#endif + sc_def2 = st->luk*10 + SCDEF_LVL_DIFF(bl, src, 99, 10); + break; + case SC_SLEEP: + sc_def = st->int_*100; + sc_def2 = st->luk*10 + SCDEF_LVL_DIFF(bl, src, 99, 10); +#ifdef RENEWAL + tick_def2 = st->luk*10; +#endif + break; + case SC_DEEP_SLEEP: + sc_def = st->int_*50; + tick_def = 0; // Linear reduction instead + tick_def2 = st->int_ * 50 + SCDEF_LVL_CAP(bl, 150) * 50; // kRO balance update lists this formula + break; + case SC_DEC_AGI: + case SC_ADORAMUS: + if (sd) tick >>= 1; //Half duration for players. + sc_def = st->mdef*100; +#ifndef RENEWAL + sc_def2 = st->luk*10; + tick_def2 = 0; //No duration reduction +#endif + tick_def = 0; //No duration reduction + break; + case SC_STONE: + sc_def = st->mdef*100; + sc_def2 = st->luk*10 + SCDEF_LVL_DIFF(bl, src, 99, 10); + tick_def = 0; //No duration reduction +#ifndef RENEWAL + tick_def2 = 0; //No duration reduction +#endif + break; + case SC_FREEZE: + sc_def = st->mdef*100; + sc_def2 = st->luk*10 + SCDEF_LVL_DIFF(bl, src, 99, 10); + tick_def = 0; //No duration reduction +#ifdef RENEWAL + tick_def2 = status_get_luk(src) * -10; //Caster can increase final duration with luk +#else + tick_def2 = 0; //No duration reduction +#endif + break; + case SC_CURSE: + // Special property: immunity when luk is zero + if (st->luk == 0) + return 0; +#ifndef RENEWAL + // Special property: immunity when luk is greater than level + if (st->luk > status->get_lv(bl)) + return 0; +#endif + sc_def = st->luk*100; + sc_def2 = st->luk*10 + SCDEF_LVL_DIFF(NULL, src, 99, 10); // Curse only has a level penalty and no resistance + tick_def = st->vit*100; +#ifdef RENEWAL + tick_def2 = st->luk*10; +#endif + break; + case SC_BLIND: + sc_def = (st->vit + st->int_)*50; + sc_def2 = st->luk*10 + SCDEF_LVL_DIFF(bl, src, 99, 10); +#ifdef RENEWAL + tick_def2 = st->luk*10; +#endif + break; + case SC_CONFUSION: + sc_def = (st->str + st->int_)*50; + sc_def2 = st->luk*10 + SCDEF_LVL_DIFF(bl, src, 99, 10); +#ifdef RENEWAL + sc_def2 = -sc_def2; // Reversed sc_def2 + tick_def2 = st->luk*10; +#endif + break; + case SC_ANKLESNARE: + if(st->mode&MD_BOSS) // Lasts 5 times less on bosses + tick /= 5; + sc_def = st->agi*50; + break; + case SC_MAGICMIRROR: + case SC_STONESKIN: + if (sd) //Duration greatly reduced for players. + tick /= 15; + sc_def2 = st->vit*25 + st->agi*10 + SCDEF_LVL_CAP(bl, 99) * 20; // Linear Reduction of Rate + tick_def2 = 0; //No duration reduction + break; + case SC_MARSHOFABYSS: + //5 second (Fixed) + 25 second - {( INT + LUK ) / 20 second } + tick_def2 = (st->int_ + st->luk)*50; + break; + case SC_STASIS: + //5 second (fixed) + { Stasis Skill level * 5 - (Target's VIT + DEX) / 20 } + tick_def2 = (st->vit + st->dex)*50; + break; + case SC_WHITEIMPRISON: + if( tick == 5000 ) // 100% on caster break; - if( bl->type == BL_PC ) - tick -= (status_get_lv(bl) / 5 + status->vit / 4 + status->agi / 10)*100; + if (bl->type == BL_PC) + tick_def2 = st->vit*25 + st->agi*10 + SCDEF_LVL_CAP(bl, 150) * 20; else - tick -= (status->vit + status->luk) / 20 * 1000; + tick_def2 = (st->vit + st->luk)*50; break; case SC_BURNING: - tick -= 75 * status->luk + 125 * status->agi; - tick = max(tick,5000); // Minimum Duration 5s. + tick_def2 = 75*st->luk + 125*st->agi; break; case SC_FROSTMISTY: - tick -= 1000 * ((status->vit + status->dex) / 20); - tick = max(tick,6000); // Minimum Duration 10s. + tick_def2 = (st->vit + st->dex)*50; break; case SC_OBLIVIONCURSE: // 100% - (100 - 0.8 x INT) - sc_def = 100 - ( 100 - status->int_* 8 / 10 ); - sc_def = max(sc_def, 5); // minimum of 5% + sc_def = st->int_*80; + case SC_TOXIN: + case SC_PARALYSE: + case SC_VENOMBLEED: + case SC_MAGICMUSHROOM: + case SC_DEATHHURT: + case SC_PYREXIA: + case SC_LEECHESEND: + tick_def2 = (st->vit + st->luk) * 500; break; case SC_WUGBITE: // {(Base Success chance) - (Target's AGI / 4)} - rate -= status->agi*100/4; - rate = max(rate,5000); // minimum of 50% + sc_def2 = st->agi*25; break; case SC_ELECTRICSHOCKER: - if( bl->type == BL_MOB ) - tick -= 1000 * (status->agi/10); + tick_def2 = (st->vit + st->agi) * 70; + break; + case SC_COLD: + tick_def2 = st->vit*100 + status->get_lv(bl)*20; break; - case SC_CRYSTALIZE: - tick -= (1000*(status->vit/10))+(status_get_lv(bl)/50); + case SC_VACUUM_EXTREME: + tick_def2 = st->str*50; break; case SC_MANDRAGORA: - sc_def = (status->vit+status->luk)/5; + sc_def = (st->vit + st->luk)*20; + break; + case SC_SIREN: + tick_def2 = (status->get_lv(bl) * 100) + ((bl->type == BL_PC)?((TBL_PC*)bl)->status.job_level : 0); break; case SC_KYOUGAKU: - tick -= 1000 * status_get_int(bl) / 20; + tick_def2 = st->int_ * 50; + break; + case SC_NEEDLE_OF_PARALYZE: + tick_def2 = (st->vit + st->luk) * 50; break; - case SC_NEEDLE_OF_PARALYZE: - tick -= 50 * (status->vit + status->luk); //(1000/20); - break; default: //Effect that cannot be reduced? Likely a buff. if (!(rnd()%10000 < rate)) return 0; - return tick?tick:1; + return tick ? tick : 1; } if (sd) { @@ -6376,11 +6609,16 @@ int status_get_sc_def(struct block_list *bl, enum sc_type type, int rate, int ti sc_def += sc->data[SC_SIEGFRIED]->val3*100; //Status resistance. } - //When no tick def, reduction is the same for both. - if(tick_def < 0) + //When tick def not set, reduction is the same for both. + if(tick_def == -1) tick_def = sc_def; - if(tick_def2 < 0) + if(tick_def2 == -1) { +#ifdef RENEWAL + tick_def2 = 0; +#else tick_def2 = sc_def2; +#endif + } //Natural resistance if (!(flag&8)) { @@ -6389,9 +6627,12 @@ int status_get_sc_def(struct block_list *bl, enum sc_type type, int rate, int ti //Minimum chances switch (type) { - case SC_WUGBITE: - rate = max(rate, 5000); //Minimum of 50% - break; + case SC_OBLIVIONCURSE: + rate = max(rate,500); //Minimum of 5% + break; + case SC_WUGBITE: + rate = max(rate,5000); //Minimum of 50% + break; } //Item resistance (only applies to rate%) @@ -6402,6 +6643,9 @@ int status_get_sc_def(struct block_list *bl, enum sc_type type, int rate, int ti if( sd->sc.data[SC_TARGET_BLOOD] ) rate -= rate*sd->sc.data[SC_TARGET_BLOOD]->val1/100; } + + //Aegis accuracy + if(rate > 0 && rate%10 != 0) rate += (10 - rate%10); } if (!(rnd()%10000 < rate)) @@ -6419,61 +6663,79 @@ int status_get_sc_def(struct block_list *bl, enum sc_type type, int rate, int ti //Minimum durations switch (type) { - case SC_ANKLESNARE: - case SC_MARSHOFABYSS: - case SC_STASIS: - tick = max(tick, 5000); //Minimum duration 5s - break; - case SC_BURNING: - case SC_FROSTMISTY: - tick = max(tick, 10000); //Minimum duration 10s - break; - default: - //Skills need to trigger even if the duration is reduced below 1ms - tick = max(tick, 1); - break; + case SC_ANKLESNARE: + case SC_BURNING: + case SC_MARSHOFABYSS: + case SC_STASIS: + case SC_DEEP_SLEEP: + tick = max(tick, 5000); //Minimum duration 5s + break; + case SC_FROSTMISTY: + tick = max(tick, 6000); + break; + default: + //Skills need to trigger even if the duration is reduced below 1ms + tick = max(tick, 1); + break; } return tick; +#undef SCDEF_LVL_CAP +#undef SCDEF_LVL_DIFF } /* [Ind/Hercules] fast-checkin sc-display array */ void status_display_add(struct map_session_data *sd, enum sc_type type, int dval1, int dval2, int dval3) { - struct sc_display_entry *entry = ers_alloc(pc_sc_display_ers, struct sc_display_entry); + struct sc_display_entry *entry; + int i; + + for( i = 0; i < sd->sc_display_count; i++ ) { + if( sd->sc_display[i]->type == type ) + break; + } + if( i != sd->sc_display_count ) { + sd->sc_display[i]->val1 = dval1; + sd->sc_display[i]->val2 = dval2; + sd->sc_display[i]->val3 = dval3; + return; + } + + entry = ers_alloc(pc->sc_display_ers, struct sc_display_entry); + entry->type = type; entry->val1 = dval1; entry->val2 = dval2; entry->val3 = dval3; - + RECREATE(sd->sc_display, struct sc_display_entry *, ++sd->sc_display_count); sd->sc_display[ sd->sc_display_count - 1 ] = entry; } void status_display_remove(struct map_session_data *sd, enum sc_type type) { int i; - + for( i = 0; i < sd->sc_display_count; i++ ) { if( sd->sc_display[i]->type == type ) break; } - + if( i != sd->sc_display_count ) { int cursor; - - ers_free(pc_sc_display_ers, sd->sc_display[i]); + + ers_free(pc->sc_display_ers, sd->sc_display[i]); sd->sc_display[i] = NULL; - + /* the all-mighty compact-o-matic */ for( i = 0, cursor = 0; i < sd->sc_display_count; i++ ) { if( sd->sc_display[i] == NULL ) continue; - + if( i != cursor ) { sd->sc_display[cursor] = sd->sc_display[i]; } - + cursor++; } - + if( !(sd->sc_display_count = cursor) ) { aFree(sd->sc_display); sd->sc_display = NULL; @@ -6481,30 +6743,29 @@ void status_display_remove(struct map_session_data *sd, enum sc_type type) { } } /*========================================== - * Starts a status change. - * 'type' = type, 'val1~4' depend on the type. - * 'rate' = base success rate. 10000 = 100% - * 'tick' is base duration - * 'flag': - * &1: Cannot be avoided (it has to start) - * &2: Tick should not be reduced (by vit, luk, lv, etc) - * &4: sc_data loaded, no value has to be altered. - * &8: rate should not be reduced - *------------------------------------------*/ -int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val1,int val2,int val3,int val4,int tick,int flag) { +* Starts a status change. +* 'type' = type, 'val1~4' depend on the type. +* 'rate' = base success rate. 10000 = 100% +* 'tick' is base duration +* 'flag': +* &1: Cannot be avoided (it has to start) +* &2: Tick should not be reduced (by vit, luk, lv, etc) +* &4: sc_data loaded, no value has to be altered. +* &8: rate should not be reduced +*------------------------------------------*/ +int status_change_start(struct block_list *src, struct block_list *bl, enum sc_type type, int rate, int val1, int val2, int val3, int val4, int tick, int flag) { struct map_session_data *sd = NULL; struct status_change* sc; struct status_change_entry* sce; - struct status_data *status; + struct status_data *st; struct view_data *vd; int opt_flag, calc_flag, undead_flag, val_flag = 0, tick_time = 0; nullpo_ret(bl); - sc = status_get_sc(bl); - status = status_get_status_data(bl); + sc = status->get_sc(bl); + st = status->get_status_data(bl); - if( type <= SC_NONE || type >= SC_MAX ) - { + if( type <= SC_NONE || type >= SC_MAX ) { ShowError("status_change_start: invalid status change (%d)!\n", type); return 0; } @@ -6512,62 +6773,81 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val if( !sc ) return 0; //Unable to receive status changes - if( status_isdead(bl) && type != SC_NOCHAT ) // SC_NOCHAT should work even on dead characters + if( status->isdead(bl) && type != SC_NOCHAT ) // SC_NOCHAT should work even on dead characters return 0; - if( bl->type == BL_MOB) - { + if( bl->type == BL_MOB) { struct mob_data *md = BL_CAST(BL_MOB,bl); if(md && (md->class_ == MOBID_EMPERIUM || mob_is_battleground(md)) && type != SC_SAFETYWALL && type != SC_PNEUMA) return 0; //Emperium/BG Monsters can't be afflicted by status changes - // if(md && mob_is_gvg(md) && status_sc2scb_flag(type)&SCB_MAXHP) - // return 0; //prevent status addinh hp to gvg mob (like bloodylust=hp*3 etc... + //if(md && mob_is_gvg(md) && status->sc2scb_flag(type)&SCB_MAXHP) + // return 0; //prevent status addinh hp to gvg mob (like bloodylust=hp*3 etc... } if( sc->data[SC_REFRESH] ) { if( type >= SC_COMMON_MIN && type <= SC_COMMON_MAX) // Confirmed. return 0; // Immune to status ailements switch( type ) { - case SC_QUAGMIRE://Tester said it protects against this and decrease agi. - case SC_DEC_AGI: - case SC_BURNING: - case SC_FROSTMISTY: - //case SC_WHITEIMPRISON://Need confirm. Protected against this in the past. [Rytech] - case SC_MARSHOFABYSS: - case SC_TOXIN: - case SC_PARALYSE: - case SC_VENOMBLEED: - case SC_MAGICMUSHROOM: - case SC_DEATHHURT: - case SC_PYREXIA: - case SC_OBLIVIONCURSE: - case SC_LEECHESEND: - case SC_CRYSTALIZE: ////08/31/2011 - Class Balance Changes - case SC_DEEP_SLEEP: - case SC_MANDRAGORA: - return 0; + case SC_DEEP_SLEEP: + case SC__CHAOS: + case SC_BURNING: + case SC_STUN: + case SC_SLEEP: + case SC_CURSE: + case SC_STONE: + case SC_POISON: + case SC_BLIND: + case SC_SILENCE: + case SC_BLOODING: + case SC_FREEZE: + case SC_FROSTMISTY: + case SC_COLD: + case SC_TOXIN: + case SC_PARALYSE: + case SC_VENOMBLEED: + case SC_MAGICMUSHROOM: + case SC_DEATHHURT: + case SC_PYREXIA: + case SC_OBLIVIONCURSE: + case SC_MARSHOFABYSS: + case SC_MANDRAGORA: + return 0; } - } - else if( sc->data[SC_INSPIRATION] ) { + } else if( sc->data[SC_INSPIRATION] ) { if( type >= SC_COMMON_MIN && type <= SC_COMMON_MAX ) return 0; // Immune to status ailements switch( type ) { - case SC_DEEP_SLEEP: - case SC_SATURDAY_NIGHT_FEVER: - case SC_PYREXIA: - case SC_DEATHHURT: - case SC_MAGICMUSHROOM: - case SC_VENOMBLEED: + case SC_POISON: + case SC_BLIND: + case SC_STUN: + case SC_SILENCE: + case SC__CHAOS: + case SC_STONE: + case SC_SLEEP: + case SC_BLOODING: + case SC_CURSE: + case SC_BURNING: + case SC_FROSTMISTY: + case SC_FREEZE: + case SC_COLD: + case SC_FEAR: case SC_TOXIN: + case SC_PARALYSE: + case SC_VENOMBLEED: + case SC_MAGICMUSHROOM: + case SC_DEATHHURT: + case SC_PYREXIA: case SC_OBLIVIONCURSE: case SC_LEECHESEND: + case SC_DEEP_SLEEP: + case SC_SATURDAY_NIGHT_FEVER: + case SC__BODYPAINT: case SC__ENERVATION: case SC__GROOMY: + case SC__IGNORANCE: case SC__LAZINESS: case SC__UNLUCKY: case SC__WEAKNESS: - case SC__BODYPAINT: - case SC__IGNORANCE: return 0; } } @@ -6575,308 +6855,304 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val sd = BL_CAST(BL_PC, bl); //Adjust tick according to status resistances - if( !(flag&(1|4)) ) - { - tick = status_get_sc_def(bl, type, rate, tick, flag); + if( !(flag&(1|4)) ) { + tick = status->get_sc_def(src, bl, type, rate, tick, flag); if( !tick ) return 0; } - undead_flag = battle->check_undead(status->race,status->def_ele); + undead_flag = battle->check_undead(st->race,st->def_ele); //Check for inmunities / sc fails switch (type) { - case SC_ANGRIFFS_MODUS: - case SC_GOLDENE_FERSE: - if ((type==SC_GOLDENE_FERSE && sc->data[SC_ANGRIFFS_MODUS]) - || (type==SC_ANGRIFFS_MODUS && sc->data[SC_GOLDENE_FERSE]) - ) - return 0; - case SC_STONE: - if(sc->data[SC_POWER_OF_GAIA]) - return 0; - case SC_FREEZE: - //Undead are immune to Freeze/Stone - if (undead_flag && !(flag&1)) - return 0; - case SC_DEEP_SLEEP: - case SC_SLEEP: - case SC_STUN: - case SC_FROSTMISTY: - case SC_CRYSTALIZE: - if (sc->opt1) - return 0; //Cannot override other opt1 status changes. [Skotlex] - if((type == SC_FREEZE || type == SC_FROSTMISTY || type == SC_CRYSTALIZE) && sc->data[SC_WARMER]) - return 0; //Immune to Frozen and Freezing status if under Warmer status. [Jobbie] - break; - - //There all like berserk, do not everlap each other - case SC__BLOODYLUST: - if(!sd) return 0; //should only affect player - case SC_BERSERK: - if (((type == SC_BERSERK) && (sc->data[SC_SATURDAY_NIGHT_FEVER] || sc->data[SC__BLOODYLUST])) - || ((type == SC__BLOODYLUST) && (sc->data[SC_SATURDAY_NIGHT_FEVER] || sc->data[SC_BERSERK])) - ) - return 0; - break; + case SC_DRUMBATTLE: + case SC_NIBELUNGEN: + case SC_INTOABYSS: + case SC_SIEGFRIED: + if( sd && !sd->status.party_id ) + return 0; + break; + case SC_ANGRIFFS_MODUS: + case SC_GOLDENE_FERSE: + if ((type==SC_GOLDENE_FERSE && sc->data[SC_ANGRIFFS_MODUS]) + || (type==SC_ANGRIFFS_MODUS && sc->data[SC_GOLDENE_FERSE]) + ) + return 0; + case SC_VACUUM_EXTREME: + if(sc->data[SC_HALLUCINATIONWALK] || sc->data[SC_HOVERING]) + return 0; + break; + case SC_STONE: + if(sc->data[SC_POWER_OF_GAIA]) + return 0; + case SC_FREEZE: + //Undead are immune to Freeze/Stone + if (undead_flag && !(flag&1)) + return 0; + case SC_SLEEP: + case SC_STUN: + case SC_FROSTMISTY: + case SC_COLD: + if (sc->opt1) + return 0; //Cannot override other opt1 status changes. [Skotlex] + if((type == SC_FREEZE || type == SC_FROSTMISTY || type == SC_COLD) && sc->data[SC_WARMER]) + return 0; //Immune to Frozen and Freezing status if under Warmer status. [Jobbie] + break; - case SC_BURNING: - if(sc->opt1 || sc->data[SC_FROSTMISTY]) - return 0; - break; + //There all like berserk, do not everlap each other + case SC_BERSERK: + if( sc->data[SC__BLOODYLUST] ) + return 0; + break; - case SC_CRUCIS: - //Only affects demons and undead element (but not players) - if((!undead_flag && status->race!=RC_DEMON) || bl->type == BL_PC) - return 0; - break; - case SC_LEXAETERNA: - if( (sc->data[SC_STONE] && sc->opt1 == OPT1_STONE) || sc->data[SC_FREEZE] ) - return 0; - break; - case SC_KYRIE: - if (bl->type == BL_MOB) - return 0; - break; - case SC_OVERTHRUST: - if (sc->data[SC_OVERTHRUSTMAX]) - return 0; //Overthrust can't take effect if under Max Overthrust. [Skotlex] - case SC_OVERTHRUSTMAX: - if( sc->option&OPTION_MADOGEAR ) - return 0;//Overthrust and Overthrust Max cannot be used on Mado Gear [Ind] - break; - case SC_ADRENALINE: - if(sd && !pc_check_weapontype(sd,skill->get_weapontype(BS_ADRENALINE))) - return 0; - if (sc->data[SC_QUAGMIRE] || - sc->data[SC_DEC_AGI] || - sc->option&OPTION_MADOGEAR //Adrenaline doesn't affect Mado Gear [Ind] - ) - return 0; - break; - case SC_ADRENALINE2: - if(sd && !pc_check_weapontype(sd,skill->get_weapontype(BS_ADRENALINE2))) - return 0; - if (sc->data[SC_QUAGMIRE] || - sc->data[SC_DEC_AGI] - ) - return 0; - break; - case SC_MAGNIFICAT: - if( sc->data[SC_OFFERTORIUM] || sc->option&OPTION_MADOGEAR ) //Mado is immune to magnificat - return 0; - break; - case SC_ONEHANDQUICKEN: - case SC_MER_QUICKEN: - case SC_TWOHANDQUICKEN: - if(sc->data[SC_DEC_AGI]) - return 0; + case SC_BURNING: + if(sc->opt1 || sc->data[SC_FROSTMISTY]) + return 0; + break; - case SC_INC_AGI: - if(sd && pc_issit(sd)){ - pc->setstand(sd); - clif->standing(&sd->bl); - } - - case SC_CONCENTRATION: - case SC_SPEARQUICKEN: - case SC_TRUESIGHT: - case SC_WINDWALK: - case SC_CARTBOOST: - case SC_ASSNCROS: - if (sc->data[SC_QUAGMIRE]) - return 0; - if(sc->option&OPTION_MADOGEAR) - return 0;//Mado is immune to increase agi, wind walk, cart boost, etc (others above) [Ind] - break; - case SC_CLOAKING: - //Avoid cloaking with no wall and low skill level. [Skotlex] - //Due to the cloaking card, we have to check the wall versus to known - //skill level rather than the used one. [Skotlex] - //if (sd && val1 < 3 && skill_check_cloaking(bl,NULL)) - if( sd && pc->checkskill(sd, AS_CLOAKING) < 3 && !skill->check_cloaking(bl,NULL) ) - return 0; - break; - case SC_MODECHANGE: - { - int mode; - struct status_data *bstatus = status_get_base_status(bl); - if (!bstatus) return 0; - if (sc->data[type]) - { //Pile up with previous values. - if(!val2) val2 = sc->data[type]->val2; - val3 |= sc->data[type]->val3; - val4 |= sc->data[type]->val4; - } - mode = val2?val2:bstatus->mode; //Base mode - if (val4) mode&=~val4; //Del mode - if (val3) mode|= val3; //Add mode - if (mode == bstatus->mode) { //No change. - if (sc->data[type]) //Abort previous status - return status_change_end(bl, type, INVALID_TIMER); - return 0; - } - } - break; - //Strip skills, need to divest something or it fails. - case SC_NOEQUIPWEAPON: - if (sd && !(flag&4)) { //apply sc anyway if loading saved sc_data - int i; - opt_flag = 0; //Reuse to check success condition. - if(sd->bonus.unstripable_equip&EQP_WEAPON) + case SC_CRUCIS: + //Only affects demons and undead element (but not players) + if((!undead_flag && st->race!=RC_DEMON) || bl->type == BL_PC) + return 0; + break; + case SC_LEXAETERNA: + if( (sc->data[SC_STONE] && sc->opt1 == OPT1_STONE) || sc->data[SC_FREEZE] ) + return 0; + break; + case SC_KYRIE: + if (bl->type == BL_MOB) + return 0; + break; + case SC_OVERTHRUST: + if (sc->data[SC_OVERTHRUSTMAX]) + return 0; //Overthrust can't take effect if under Max Overthrust. [Skotlex] + case SC_OVERTHRUSTMAX: + if( sc->option&OPTION_MADOGEAR ) + return 0;//Overthrust and Overthrust Max cannot be used on Mado Gear [Ind] + break; + case SC_ADRENALINE: + if(sd && !pc_check_weapontype(sd,skill->get_weapontype(BS_ADRENALINE))) + return 0; + if (sc->data[SC_QUAGMIRE] || + sc->data[SC_DEC_AGI] || + sc->option&OPTION_MADOGEAR //Adrenaline doesn't affect Mado Gear [Ind] + ) + return 0; + break; + case SC_ADRENALINE2: + if(sd && !pc_check_weapontype(sd,skill->get_weapontype(BS_ADRENALINE2))) + return 0; + if (sc->data[SC_QUAGMIRE] || + sc->data[SC_DEC_AGI] + ) + return 0; + break; + case SC_MAGNIFICAT: + if( sc->data[SC_OFFERTORIUM] || sc->option&OPTION_MADOGEAR ) //Mado is immune to magnificat + return 0; + break; + case SC_ONEHANDQUICKEN: + case SC_MER_QUICKEN: + case SC_TWOHANDQUICKEN: + if(sc->data[SC_DEC_AGI]) return 0; - i = sd->equip_index[EQI_HAND_R]; - if (i>=0 && sd->inventory_data[i] && sd->inventory_data[i]->type == IT_WEAPON) { - opt_flag|=2; - pc->unequipitem(sd,i,3); + case SC_CONCENTRATION: + case SC_SPEARQUICKEN: + case SC_TRUESIGHT: + case SC_WINDWALK: + case SC_CARTBOOST: + case SC_ASSNCROS: + if(sc->option&OPTION_MADOGEAR) + return 0;//Mado is immune to wind walk, cart boost, etc (others above) [Ind] + case SC_INC_AGI: + if (sc->data[SC_QUAGMIRE]) + return 0; + break; + case SC_CLOAKING: + if (sd && !skill->can_cloak(sd)) + return 0; + break; + case SC_MODECHANGE: + { + int mode; + struct status_data *bst = status->get_base_status(bl); + if (!bst) return 0; + if (sc->data[type]) { + //Pile up with previous values. + if(!val2) val2 = sc->data[type]->val2; + val3 |= sc->data[type]->val3; + val4 |= sc->data[type]->val4; + } + mode = val2 ? val2 : bst->mode; //Base mode + if (val4) mode&=~val4; //Del mode + if (val3) mode|= val3; //Add mode + if (mode == bst->mode) { //No change. + if (sc->data[type]) //Abort previous status + return status_change_end(bl, type, INVALID_TIMER); + return 0; } - if (!opt_flag) return 0; } - 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 (sd && !(flag&4)) { - int i; - if(sd->bonus.unstripable_equip&EQP_SHIELD) + break; + //Strip skills, need to divest something or it fails. + case SC_NOEQUIPWEAPON: + if (sd && !(flag&4)) { //apply sc anyway if loading saved sc_data + int i; + opt_flag = 0; //Reuse to check success condition. + if(sd->bonus.unstripable_equip&EQP_WEAPON) + return 0; + + i = sd->equip_index[EQI_HAND_R]; + if (i>=0 && sd->inventory_data[i] && sd->inventory_data[i]->type == IT_WEAPON) { + opt_flag|=2; + pc->unequipitem(sd,i,3); + } + if (!opt_flag) return 0; + } + 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 (sd && !(flag&4)) { + int i; + if(sd->bonus.unstripable_equip&EQP_SHIELD) + return 0; + i = sd->equip_index[EQI_HAND_L]; + if ( i < 0 || !sd->inventory_data[i] || sd->inventory_data[i]->type != IT_ARMOR ) + return 0; + pc->unequipitem(sd,i,3); + } + if (tick == 1) return 1; //Minimal duration: Only strip without causing the SC + break; + case SC_NOEQUIPARMOR: + if (sd && !(flag&4)) { + int i; + if(sd->bonus.unstripable_equip&EQP_ARMOR) + return 0; + i = sd->equip_index[EQI_ARMOR]; + if ( i < 0 || !sd->inventory_data[i] ) + return 0; + pc->unequipitem(sd,i,3); + } + if (tick == 1) return 1; //Minimal duration: Only strip without causing the SC + break; + case SC_NOEQUIPHELM: + if (sd && !(flag&4)) { + int i; + if(sd->bonus.unstripable_equip&EQP_HELM) + return 0; + i = sd->equip_index[EQI_HEAD_TOP]; + if ( i < 0 || !sd->inventory_data[i] ) + return 0; + pc->unequipitem(sd,i,3); + } + if (tick == 1) return 1; //Minimal duration: Only strip without causing the SC + break; + case SC_MER_FLEE: + case SC_MER_ATK: + case SC_MER_HP: + case SC_MER_SP: + case SC_MER_HIT: + if( bl->type != BL_MER ) + return 0; // Stats only for Mercenaries + break; + case SC_FOOD_STR: + if (sc->data[SC_FOOD_STR_CASH] && sc->data[SC_FOOD_STR_CASH]->val1 > val1) return 0; - i = sd->equip_index[EQI_HAND_L]; - if ( i < 0 || !sd->inventory_data[i] || sd->inventory_data[i]->type != IT_ARMOR ) + break; + case SC_FOOD_AGI: + if (sc->data[SC_FOOD_AGI_CASH] && sc->data[SC_FOOD_AGI_CASH]->val1 > val1) return 0; - pc->unequipitem(sd,i,3); - } - if (tick == 1) return 1; //Minimal duration: Only strip without causing the SC - break; - case SC_NOEQUIPARMOR: - if (sd && !(flag&4)) { - int i; - if(sd->bonus.unstripable_equip&EQP_ARMOR) + break; + case SC_FOOD_VIT: + if (sc->data[SC_FOOD_VIT_CASH] && sc->data[SC_FOOD_VIT_CASH]->val1 > val1) return 0; - i = sd->equip_index[EQI_ARMOR]; - if ( i < 0 || !sd->inventory_data[i] ) + break; + case SC_FOOD_INT: + if (sc->data[SC_FOOD_INT_CASH] && sc->data[SC_FOOD_INT_CASH]->val1 > val1) return 0; - pc->unequipitem(sd,i,3); - } - if (tick == 1) return 1; //Minimal duration: Only strip without causing the SC - break; - case SC_NOEQUIPHELM: - if (sd && !(flag&4)) { - int i; - if(sd->bonus.unstripable_equip&EQP_HELM) + break; + case SC_FOOD_DEX: + if (sc->data[SC_FOOD_DEX_CASH] && sc->data[SC_FOOD_DEX_CASH]->val1 > val1) return 0; - i = sd->equip_index[EQI_HEAD_TOP]; - if ( i < 0 || !sd->inventory_data[i] ) + break; + case SC_FOOD_LUK: + if (sc->data[SC_FOOD_LUK_CASH] && sc->data[SC_FOOD_LUK_CASH]->val1 > val1) return 0; - pc->unequipitem(sd,i,3); - } - if (tick == 1) return 1; //Minimal duration: Only strip without causing the SC - break; - case SC_MER_FLEE: - case SC_MER_ATK: - case SC_MER_HP: - case SC_MER_SP: - case SC_MER_HIT: - if( bl->type != BL_MER ) - return 0; // Stats only for Mercenaries - break; - case SC_FOOD_STR: - if (sc->data[SC_FOOD_STR_CASH] && sc->data[SC_FOOD_STR_CASH]->val1 > val1) - return 0; - break; - case SC_FOOD_AGI: - if (sc->data[SC_FOOD_AGI_CASH] && sc->data[SC_FOOD_AGI_CASH]->val1 > val1) - return 0; - break; - case SC_FOOD_VIT: - if (sc->data[SC_FOOD_VIT_CASH] && sc->data[SC_FOOD_VIT_CASH]->val1 > val1) - return 0; - break; - case SC_FOOD_INT: - if (sc->data[SC_FOOD_INT_CASH] && sc->data[SC_FOOD_INT_CASH]->val1 > val1) - return 0; - break; - case SC_FOOD_DEX: - if (sc->data[SC_FOOD_DEX_CASH] && sc->data[SC_FOOD_DEX_CASH]->val1 > val1) - return 0; - break; - case SC_FOOD_LUK: - if (sc->data[SC_FOOD_LUK_CASH] && sc->data[SC_FOOD_LUK_CASH]->val1 > val1) - return 0; - break; - case SC_FOOD_STR_CASH: - if (sc->data[SC_FOOD_STR] && sc->data[SC_FOOD_STR]->val1 > val1) - return 0; - break; - case SC_FOOD_AGI_CASH: - if (sc->data[SC_FOOD_AGI] && sc->data[SC_FOOD_AGI]->val1 > val1) - return 0; - break; - case SC_FOOD_VIT_CASH: - if (sc->data[SC_FOOD_VIT] && sc->data[SC_FOOD_VIT]->val1 > val1) - return 0; - break; - case SC_FOOD_INT_CASH: - if (sc->data[SC_FOOD_INT] && sc->data[SC_FOOD_INT]->val1 > val1) - return 0; - break; - case SC_FOOD_DEX_CASH: - if (sc->data[SC_FOOD_DEX] && sc->data[SC_FOOD_DEX]->val1 > val1) - return 0; - break; - case SC_FOOD_LUK_CASH: - if (sc->data[SC_FOOD_LUK] && sc->data[SC_FOOD_LUK]->val1 > val1) - return 0; - break; - case SC_CAMOUFLAGE: - if( sd && pc->checkskill(sd, RA_CAMOUFLAGE) < 3 && !skill->check_camouflage(bl,NULL) ) - return 0; - break; - case SC__STRIPACCESSARY: - if( sd ) { - int i = -1; - if( !(sd->bonus.unstripable_equip&EQI_ACC_L) ) { - i = sd->equip_index[EQI_ACC_L]; - if( i >= 0 && sd->inventory_data[i] && sd->inventory_data[i]->type == IT_ARMOR ) - pc->unequipitem(sd,i,3); //L-Accessory - } if( !(sd->bonus.unstripable_equip&EQI_ACC_R) ) { - i = sd->equip_index[EQI_ACC_R]; - if( i >= 0 && sd->inventory_data[i] && sd->inventory_data[i]->type == IT_ARMOR ) - pc->unequipitem(sd,i,3); //R-Accessory - } - if( i < 0 ) + break; + case SC_FOOD_STR_CASH: + if (sc->data[SC_FOOD_STR] && sc->data[SC_FOOD_STR]->val1 > val1) return 0; - } - if (tick == 1) return 1; //Minimal duration: Only strip without causing the SC - break; - case SC_TOXIN: - case SC_PARALYSE: - case SC_VENOMBLEED: - case SC_MAGICMUSHROOM: - case SC_DEATHHURT: - case SC_PYREXIA: - case SC_OBLIVIONCURSE: - case SC_LEECHESEND: - { // it doesn't stack or even renewed - int i = SC_TOXIN; - for(; i<= SC_LEECHESEND; i++) - if(sc->data[i]) return 0; - } - break; - case SC_SATURDAY_NIGHT_FEVER: - if (sc->data[SC_BERSERK] || sc->data[SC_INSPIRATION] || sc->data[SC__BLOODYLUST]) - return 0; - break; - case SC_OFFERTORIUM: - if (sc->data[SC_MAGNIFICAT]) - return 0; - break; + break; + case SC_FOOD_AGI_CASH: + if (sc->data[SC_FOOD_AGI] && sc->data[SC_FOOD_AGI]->val1 > val1) + return 0; + break; + case SC_FOOD_VIT_CASH: + if (sc->data[SC_FOOD_VIT] && sc->data[SC_FOOD_VIT]->val1 > val1) + return 0; + break; + case SC_FOOD_INT_CASH: + if (sc->data[SC_FOOD_INT] && sc->data[SC_FOOD_INT]->val1 > val1) + return 0; + break; + case SC_FOOD_DEX_CASH: + if (sc->data[SC_FOOD_DEX] && sc->data[SC_FOOD_DEX]->val1 > val1) + return 0; + break; + case SC_FOOD_LUK_CASH: + if (sc->data[SC_FOOD_LUK] && sc->data[SC_FOOD_LUK]->val1 > val1) + return 0; + break; + case SC_CAMOUFLAGE: + if( sd && pc->checkskill(sd, RA_CAMOUFLAGE) < 3 && !skill->check_camouflage(bl,NULL) ) + return 0; + break; + case SC__STRIPACCESSARY: + if( sd ) { + int i = -1; + if( !(sd->bonus.unstripable_equip&EQP_ACC_L) ) { + i = sd->equip_index[EQI_ACC_L]; + if( i >= 0 && sd->inventory_data[i] && sd->inventory_data[i]->type == IT_ARMOR ) + pc->unequipitem(sd,i,3); //L-Accessory + } if( !(sd->bonus.unstripable_equip&EQP_ACC_R) ) { + i = sd->equip_index[EQI_ACC_R]; + if( i >= 0 && sd->inventory_data[i] && sd->inventory_data[i]->type == IT_ARMOR ) + pc->unequipitem(sd,i,3); //R-Accessory + } + if( i < 0 ) + return 0; + } + if (tick == 1) return 1; //Minimal duration: Only strip without causing the SC + break; + case SC_TOXIN: + case SC_PARALYSE: + case SC_VENOMBLEED: + case SC_MAGICMUSHROOM: + case SC_DEATHHURT: + case SC_PYREXIA: + case SC_OBLIVIONCURSE: + case SC_LEECHESEND: + { // it doesn't stack or even renewed + int i = SC_TOXIN; + for(; i<= SC_LEECHESEND; i++) + if(sc->data[i]) return 0; + } + break; + case SC_MAGNETICFIELD: + if(sc->data[SC_HOVERING]) + return 0; + break; + case SC_OFFERTORIUM: + if (sc->data[SC_MAGNIFICAT]) + return 0; + break; } //Check for BOSS resistances - if(status->mode&MD_BOSS && !(flag&1)) { - if (type>=SC_COMMON_MIN && type <= SC_COMMON_MAX) - return 0; - switch (type) { + if(st->mode&MD_BOSS && !(flag&1)) { + if (type>=SC_COMMON_MIN && type <= SC_COMMON_MAX) + return 0; + switch (type) { case SC_BLESSING: case SC_DEC_AGI: case SC_PROVOKE: @@ -6887,14 +7163,14 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val case SC_ROKISWEIL: case SC_FOGWALL: case SC_FROSTMISTY: - case SC_BURNING: + case SC_BURNING: case SC_MARSHOFABYSS: case SC_ADORAMUS: case SC_NEEDLE_OF_PARALYZE: case SC_DEEP_SLEEP: - case SC_CRYSTALIZE: + case SC_COLD: - // Exploit prevention - kRO Fix + // Exploit prevention - kRO Fix case SC_PYREXIA: case SC_DEATHHURT: case SC_TOXIN: @@ -6904,247 +7180,255 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val case SC_OBLIVIONCURSE: case SC_LEECHESEND: - // Ranger Effects + // Ranger Effects case SC_WUGBITE: case SC_ELECTRICSHOCKER: case SC_MAGNETICFIELD: + // Masquerades + case SC__ENERVATION: + case SC__GROOMY: + case SC__LAZINESS: + case SC__UNLUCKY: + case SC__WEAKNESS: + case SC__IGNORANCE: + + // Other Effects + case SC_VACUUM_EXTREME: + return 0; } } //Before overlapping fail, one must check for status cured. switch (type) { - case SC_BLESSING: - //TO-DO Blessing and Agi up should do 1 damage against players on Undead Status, even on PvM - //but cannot be plagiarized (this requires aegis investigation on packets and official behavior) [Brainstorm] - if ((!undead_flag && status->race!=RC_DEMON) || bl->type == BL_PC) { - status_change_end(bl, SC_CURSE, INVALID_TIMER); - if (sc->data[SC_STONE] && sc->opt1 == OPT1_STONE) - status_change_end(bl, SC_STONE, INVALID_TIMER); - } - break; - case SC_INC_AGI: - status_change_end(bl, SC_DEC_AGI, INVALID_TIMER); - break; - case SC_QUAGMIRE: - status_change_end(bl, SC_CONCENTRATION, INVALID_TIMER); - status_change_end(bl, SC_TRUESIGHT, INVALID_TIMER); - status_change_end(bl, SC_WINDWALK, INVALID_TIMER); - //Also blocks the ones below... - case SC_DEC_AGI: - status_change_end(bl, SC_CARTBOOST, INVALID_TIMER); - //Also blocks the ones below... - case SC_DONTFORGETME: - status_change_end(bl, SC_INC_AGI, INVALID_TIMER); - status_change_end(bl, SC_ADRENALINE, INVALID_TIMER); - status_change_end(bl, SC_ADRENALINE2, INVALID_TIMER); - status_change_end(bl, SC_SPEARQUICKEN, INVALID_TIMER); - status_change_end(bl, SC_TWOHANDQUICKEN, INVALID_TIMER); - status_change_end(bl, SC_ONEHANDQUICKEN, INVALID_TIMER); - status_change_end(bl, SC_MER_QUICKEN, INVALID_TIMER); - status_change_end(bl, SC_ACCELERATION, INVALID_TIMER); - break; - case SC_ONEHANDQUICKEN: - //Removes the Aspd potion effect, as reported by Vicious. [Skotlex] - status_change_end(bl, SC_ATTHASTE_POTION1, INVALID_TIMER); - status_change_end(bl, SC_ATTHASTE_POTION2, INVALID_TIMER); - status_change_end(bl, SC_ATTHASTE_POTION3, INVALID_TIMER); - status_change_end(bl, SC_ATTHASTE_INFINITY, INVALID_TIMER); - break; - case SC_OVERTHRUSTMAX: - //Cancels Normal Overthrust. [Skotlex] - status_change_end(bl, SC_OVERTHRUST, INVALID_TIMER); - break; - case SC_KYRIE: - //Cancels Assumptio - status_change_end(bl, SC_ASSUMPTIO, INVALID_TIMER); - break; - case SC_DELUGE: - if (sc->data[SC_FOGWALL] && sc->data[SC_BLIND]) - status_change_end(bl, SC_BLIND, INVALID_TIMER); - break; - case SC_SILENCE: - if (sc->data[SC_GOSPEL] && sc->data[SC_GOSPEL]->val4 == BCT_SELF) - status_change_end(bl, SC_GOSPEL, INVALID_TIMER); - break; - case SC_HIDING: - status_change_end(bl, SC_RG_CCONFINE_M, INVALID_TIMER); - status_change_end(bl, SC_RG_CCONFINE_S, INVALID_TIMER); - break; - case SC__BLOODYLUST: - case SC_BERSERK: - if(battle_config.berserk_cancels_buffs) { - status_change_end(bl, SC_ONEHANDQUICKEN, INVALID_TIMER); + case SC_BLESSING: + //TO-DO Blessing and Agi up should do 1 damage against players on Undead Status, even on PvM + //but cannot be plagiarized (this requires aegis investigation on packets and official behavior) [Brainstorm] + if ((!undead_flag && st->race!=RC_DEMON) || bl->type == BL_PC) { + status_change_end(bl, SC_CURSE, INVALID_TIMER); + if (sc->data[SC_STONE] && sc->opt1 == OPT1_STONE) + status_change_end(bl, SC_STONE, INVALID_TIMER); + } + break; + case SC_INC_AGI: + status_change_end(bl, SC_DEC_AGI, INVALID_TIMER); + break; + case SC_QUAGMIRE: + status_change_end(bl, SC_CONCENTRATION, INVALID_TIMER); + status_change_end(bl, SC_TRUESIGHT, INVALID_TIMER); + status_change_end(bl, SC_WINDWALK, INVALID_TIMER); + //Also blocks the ones below... + case SC_DEC_AGI: + case SC_ADORAMUS: + status_change_end(bl, SC_CARTBOOST, INVALID_TIMER); + //Also blocks the ones below... + case SC_DONTFORGETME: + status_change_end(bl, SC_INC_AGI, INVALID_TIMER); + status_change_end(bl, SC_ADRENALINE, INVALID_TIMER); + status_change_end(bl, SC_ADRENALINE2, INVALID_TIMER); + status_change_end(bl, SC_SPEARQUICKEN, INVALID_TIMER); status_change_end(bl, SC_TWOHANDQUICKEN, INVALID_TIMER); - status_change_end(bl, SC_LKCONCENTRATION, INVALID_TIMER); - status_change_end(bl, SC_PARRYING, INVALID_TIMER); - status_change_end(bl, SC_AURABLADE, INVALID_TIMER); + status_change_end(bl, SC_ONEHANDQUICKEN, INVALID_TIMER); status_change_end(bl, SC_MER_QUICKEN, INVALID_TIMER); - } -#ifdef RENEWAL - else { - status_change_end(bl, SC_TWOHANDQUICKEN, INVALID_TIMER); - } -#endif - break; - case SC_ASSUMPTIO: - status_change_end(bl, SC_KYRIE, INVALID_TIMER); - status_change_end(bl, SC_KAITE, INVALID_TIMER); - break; - case SC_KAITE: - status_change_end(bl, SC_ASSUMPTIO, INVALID_TIMER); - break; - case SC_CARTBOOST: - if(sc->data[SC_DEC_AGI]) - { //Cancel Decrease Agi, but take no further effect [Skotlex] - status_change_end(bl, SC_DEC_AGI, INVALID_TIMER); - return 0; - } - break; - case SC_FUSION: - status_change_end(bl, SC_SOULLINK, INVALID_TIMER); - break; - case SC_GS_ADJUSTMENT: - status_change_end(bl, SC_GS_MADNESSCANCEL, INVALID_TIMER); - break; - case SC_GS_MADNESSCANCEL: - status_change_end(bl, SC_GS_ADJUSTMENT, INVALID_TIMER); - break; - //NPC_CHANGEUNDEAD will debuff Blessing and Agi Up - case SC_PROPERTYUNDEAD: - status_change_end(bl, SC_BLESSING, INVALID_TIMER); - status_change_end(bl, SC_INC_AGI, INVALID_TIMER); - break; - case SC_FOOD_STR: - status_change_end(bl, SC_FOOD_STR_CASH, INVALID_TIMER); - break; - case SC_FOOD_AGI: - status_change_end(bl, SC_FOOD_AGI_CASH, INVALID_TIMER); - break; - case SC_FOOD_VIT: - status_change_end(bl, SC_FOOD_VIT_CASH, INVALID_TIMER); - break; - case SC_FOOD_INT: - status_change_end(bl, SC_FOOD_INT_CASH, INVALID_TIMER); - break; - case SC_FOOD_DEX: - status_change_end(bl, SC_FOOD_DEX_CASH, INVALID_TIMER); - break; - case SC_FOOD_LUK: - status_change_end(bl, SC_FOOD_LUK_CASH, INVALID_TIMER); - break; - case SC_FOOD_STR_CASH: - status_change_end(bl, SC_FOOD_STR, INVALID_TIMER); - break; - case SC_FOOD_AGI_CASH: - status_change_end(bl, SC_FOOD_AGI, INVALID_TIMER); - break; - case SC_FOOD_VIT_CASH: - status_change_end(bl, SC_FOOD_VIT, INVALID_TIMER); - break; - case SC_FOOD_INT_CASH: - status_change_end(bl, SC_FOOD_INT, INVALID_TIMER); - break; - case SC_FOOD_DEX_CASH: - status_change_end(bl, SC_FOOD_DEX, INVALID_TIMER); - break; - case SC_FOOD_LUK_CASH: - status_change_end(bl, SC_FOOD_LUK, INVALID_TIMER); - break; - case SC_ENDURE: - if( val4 ) - status_change_end(bl, SC_LKCONCENTRATION, INVALID_TIMER); - break; - case SC_FIGHTINGSPIRIT: - status_change_end(bl, type, INVALID_TIMER); // Remove previous one. - break; - case SC_MARSHOFABYSS: - status_change_end(bl, SC_INCAGI, INVALID_TIMER); - status_change_end(bl, SC_WINDWALK, INVALID_TIMER); - status_change_end(bl, SC_ATTHASTE_POTION1, INVALID_TIMER); - status_change_end(bl, SC_ATTHASTE_POTION2, INVALID_TIMER); - status_change_end(bl, SC_ATTHASTE_POTION3, INVALID_TIMER); - status_change_end(bl, SC_ATTHASTE_INFINITY, INVALID_TIMER); - break; - case SC_SWING: - case SC_SYMPHONY_LOVE: - case SC_MOONLIT_SERENADE: - case SC_RUSH_WINDMILL: - case SC_ECHOSONG: - case SC_HARMONIZE: //group A doesn't overlap - if (type != SC_SWING) status_change_end(bl, SC_SWING, INVALID_TIMER); - if (type != SC_SYMPHONY_LOVE) status_change_end(bl, SC_SYMPHONY_LOVE, INVALID_TIMER); - if (type != SC_MOONLIT_SERENADE) status_change_end(bl, SC_MOONLIT_SERENADE, INVALID_TIMER); - if (type != SC_RUSH_WINDMILL) status_change_end(bl, SC_RUSH_WINDMILL, INVALID_TIMER); - if (type != SC_ECHOSONG) status_change_end(bl, SC_ECHOSONG, INVALID_TIMER); - if (type != SC_HARMONIZE) status_change_end(bl, SC_HARMONIZE, INVALID_TIMER); - break; - case SC_SIREN: - case SC_DEEP_SLEEP: - case SC_GLOOMYDAY: - case SC_SONG_OF_MANA: - case SC_DANCE_WITH_WUG: - case SC_SATURDAY_NIGHT_FEVER: - case SC_LERADS_DEW: - case SC_MELODYOFSINK: - case SC_BEYOND_OF_WARCRY: - case SC_UNLIMITED_HUMMING_VOICE: //group B - if (type != SC_SIREN) status_change_end(bl, SC_SIREN, INVALID_TIMER); - if (type != SC_DEEP_SLEEP) status_change_end(bl, SC_DEEP_SLEEP, INVALID_TIMER); - if (type != SC_LERADS_DEW) status_change_end(bl, SC_LERADS_DEW, INVALID_TIMER); - if (type != SC_MELODYOFSINK) status_change_end(bl, SC_MELODYOFSINK, INVALID_TIMER); - if (type != SC_BEYOND_OF_WARCRY) status_change_end(bl, SC_BEYOND_OF_WARCRY, INVALID_TIMER); - if (type != SC_UNLIMITED_HUMMING_VOICE) status_change_end(bl, SC_UNLIMITED_HUMMING_VOICE, INVALID_TIMER); - if (type != SC_GLOOMYDAY) { - status_change_end(bl, SC_GLOOMYDAY, INVALID_TIMER); - status_change_end(bl, SC_GLOOMYDAY_SK, INVALID_TIMER); - } - if (type != SC_SONG_OF_MANA) status_change_end(bl, SC_SONG_OF_MANA, INVALID_TIMER); - if (type != SC_DANCE_WITH_WUG) status_change_end(bl, SC_DANCE_WITH_WUG, INVALID_TIMER); - if (type != SC_SATURDAY_NIGHT_FEVER) { - if (sc->data[SC_SATURDAY_NIGHT_FEVER]) { - sc->data[SC_SATURDAY_NIGHT_FEVER]->val2 = 0; //mark to not lose hp - status_change_end(bl, SC_SATURDAY_NIGHT_FEVER, INVALID_TIMER); - } - } - break; - case SC_REFLECTSHIELD: - status_change_end(bl, SC_LG_REFLECTDAMAGE, INVALID_TIMER); - break; - case SC_LG_REFLECTDAMAGE: - status_change_end(bl, SC_REFLECTSHIELD, INVALID_TIMER); - break; - case SC_SHIELDSPELL_DEF: - case SC_SHIELDSPELL_MDEF: - case SC_SHIELDSPELL_REF: - status_change_end(bl, SC_MAGNIFICAT, INVALID_TIMER); - if( type != SC_SHIELDSPELL_DEF ) + status_change_end(bl, SC_ACCELERATION, INVALID_TIMER); + break; + case SC_ONEHANDQUICKEN: + //Removes the Aspd potion effect, as reported by Vicious. [Skotlex] + status_change_end(bl, SC_ATTHASTE_POTION1, INVALID_TIMER); + status_change_end(bl, SC_ATTHASTE_POTION2, INVALID_TIMER); + status_change_end(bl, SC_ATTHASTE_POTION3, INVALID_TIMER); + status_change_end(bl, SC_ATTHASTE_INFINITY, INVALID_TIMER); + break; + case SC_OVERTHRUSTMAX: + //Cancels Normal Overthrust. [Skotlex] + status_change_end(bl, SC_OVERTHRUST, INVALID_TIMER); + break; + case SC_KYRIE: + //Cancels Assumptio + status_change_end(bl, SC_ASSUMPTIO, INVALID_TIMER); + break; + case SC_DELUGE: + if (sc->data[SC_FOGWALL] && sc->data[SC_BLIND]) + status_change_end(bl, SC_BLIND, INVALID_TIMER); + break; + case SC_SILENCE: + if (sc->data[SC_GOSPEL] && sc->data[SC_GOSPEL]->val4 == BCT_SELF) + status_change_end(bl, SC_GOSPEL, INVALID_TIMER); + break; + case SC_HIDING: + status_change_end(bl, SC_RG_CCONFINE_M, INVALID_TIMER); + status_change_end(bl, SC_RG_CCONFINE_S, INVALID_TIMER); + break; + case SC_BERSERK: + if( val3 == SC__BLOODYLUST ) + break; + if(battle_config.berserk_cancels_buffs) { + status_change_end(bl, SC_ONEHANDQUICKEN, INVALID_TIMER); + status_change_end(bl, SC_TWOHANDQUICKEN, INVALID_TIMER); + status_change_end(bl, SC_LKCONCENTRATION, INVALID_TIMER); + status_change_end(bl, SC_PARRYING, INVALID_TIMER); + status_change_end(bl, SC_AURABLADE, INVALID_TIMER); + status_change_end(bl, SC_MER_QUICKEN, INVALID_TIMER); + } + #ifdef RENEWAL + else { + status_change_end(bl, SC_TWOHANDQUICKEN, INVALID_TIMER); + } + #endif + break; + case SC_ASSUMPTIO: + status_change_end(bl, SC_KYRIE, INVALID_TIMER); + status_change_end(bl, SC_KAITE, INVALID_TIMER); + break; + case SC_KAITE: + status_change_end(bl, SC_ASSUMPTIO, INVALID_TIMER); + break; + case SC_CARTBOOST: + if(sc->data[SC_DEC_AGI] || sc->data[SC_ADORAMUS]) + { //Cancel Decrease Agi, but take no further effect [Skotlex] + status_change_end(bl, SC_DEC_AGI, INVALID_TIMER); + status_change_end(bl, SC_ADORAMUS, INVALID_TIMER); + return 0; + } + break; + case SC_FUSION: + status_change_end(bl, SC_SOULLINK, INVALID_TIMER); + break; + case SC_GS_ADJUSTMENT: + status_change_end(bl, SC_GS_MADNESSCANCEL, INVALID_TIMER); + break; + case SC_GS_MADNESSCANCEL: + status_change_end(bl, SC_GS_ADJUSTMENT, INVALID_TIMER); + break; + //NPC_CHANGEUNDEAD will debuff Blessing and Agi Up + case SC_PROPERTYUNDEAD: + status_change_end(bl, SC_BLESSING, INVALID_TIMER); + status_change_end(bl, SC_INC_AGI, INVALID_TIMER); + break; + case SC_FOOD_STR: + status_change_end(bl, SC_FOOD_STR_CASH, INVALID_TIMER); + break; + case SC_FOOD_AGI: + status_change_end(bl, SC_FOOD_AGI_CASH, INVALID_TIMER); + break; + case SC_FOOD_VIT: + status_change_end(bl, SC_FOOD_VIT_CASH, INVALID_TIMER); + break; + case SC_FOOD_INT: + status_change_end(bl, SC_FOOD_INT_CASH, INVALID_TIMER); + break; + case SC_FOOD_DEX: + status_change_end(bl, SC_FOOD_DEX_CASH, INVALID_TIMER); + break; + case SC_FOOD_LUK: + status_change_end(bl, SC_FOOD_LUK_CASH, INVALID_TIMER); + break; + case SC_FOOD_STR_CASH: + status_change_end(bl, SC_FOOD_STR, INVALID_TIMER); + break; + case SC_FOOD_AGI_CASH: + status_change_end(bl, SC_FOOD_AGI, INVALID_TIMER); + break; + case SC_FOOD_VIT_CASH: + status_change_end(bl, SC_FOOD_VIT, INVALID_TIMER); + break; + case SC_FOOD_INT_CASH: + status_change_end(bl, SC_FOOD_INT, INVALID_TIMER); + break; + case SC_FOOD_DEX_CASH: + status_change_end(bl, SC_FOOD_DEX, INVALID_TIMER); + break; + case SC_FOOD_LUK_CASH: + status_change_end(bl, SC_FOOD_LUK, INVALID_TIMER); + break; + case SC_ENDURE: + if( val4 ) + status_change_end(bl, SC_LKCONCENTRATION, INVALID_TIMER); + break; + case SC_FIGHTINGSPIRIT: + case SC_OVERED_BOOST: + status_change_end(bl, type, INVALID_TIMER); // Remove previous one. + break; + case SC_MARSHOFABYSS: + status_change_end(bl, SC_INCAGI, INVALID_TIMER); + status_change_end(bl, SC_WINDWALK, INVALID_TIMER); + status_change_end(bl, SC_ATTHASTE_POTION1, INVALID_TIMER); + status_change_end(bl, SC_ATTHASTE_POTION2, INVALID_TIMER); + status_change_end(bl, SC_ATTHASTE_POTION3, INVALID_TIMER); + status_change_end(bl, SC_ATTHASTE_INFINITY, INVALID_TIMER); + break; + //Group A Status (doesn't overlap) + case SC_SWING: + case SC_SYMPHONY_LOVE: + case SC_MOONLIT_SERENADE: + case SC_RUSH_WINDMILL: + case SC_ECHOSONG: + case SC_HARMONIZE: + case SC_FRIGG_SONG: + if (type != SC_SWING) status_change_end(bl, SC_SWING, INVALID_TIMER); + if (type != SC_SYMPHONY_LOVE) status_change_end(bl, SC_SYMPHONY_LOVE, INVALID_TIMER); + if (type != SC_MOONLIT_SERENADE) status_change_end(bl, SC_MOONLIT_SERENADE, INVALID_TIMER); + if (type != SC_RUSH_WINDMILL) status_change_end(bl, SC_RUSH_WINDMILL, INVALID_TIMER); + if (type != SC_ECHOSONG) status_change_end(bl, SC_ECHOSONG, INVALID_TIMER); + if (type != SC_HARMONIZE) status_change_end(bl, SC_HARMONIZE, INVALID_TIMER); + if (type != SC_FRIGG_SONG) status_change_end(bl, SC_FRIGG_SONG, INVALID_TIMER); + break; + //Group B Status + case SC_SIREN: + case SC_DEEP_SLEEP: + case SC_SIRCLEOFNATURE: + case SC_LERADS_DEW: + case SC_MELODYOFSINK: + case SC_BEYOND_OF_WARCRY: + case SC_UNLIMITED_HUMMING_VOICE: + case SC_GLOOMYDAY: + case SC_SONG_OF_MANA: + case SC_DANCE_WITH_WUG: + if (type != SC_SIREN) status_change_end(bl, SC_SIREN, INVALID_TIMER); + if (type != SC_DEEP_SLEEP) status_change_end(bl, SC_DEEP_SLEEP, INVALID_TIMER); + if (type != SC_SIRCLEOFNATURE) status_change_end(bl, SC_SIRCLEOFNATURE, INVALID_TIMER); + if (type != SC_LERADS_DEW) status_change_end(bl, SC_LERADS_DEW, INVALID_TIMER); + if (type != SC_MELODYOFSINK) status_change_end(bl, SC_MELODYOFSINK, INVALID_TIMER); + if (type != SC_BEYOND_OF_WARCRY) status_change_end(bl, SC_BEYOND_OF_WARCRY, INVALID_TIMER); + if (type != SC_UNLIMITED_HUMMING_VOICE) status_change_end(bl, SC_UNLIMITED_HUMMING_VOICE, INVALID_TIMER); + if (type != SC_GLOOMYDAY) status_change_end(bl, SC_GLOOMYDAY, INVALID_TIMER); + if (type != SC_SONG_OF_MANA) status_change_end(bl, SC_SONG_OF_MANA, INVALID_TIMER); + if (type != SC_DANCE_WITH_WUG) status_change_end(bl, SC_DANCE_WITH_WUG, INVALID_TIMER); + break; + case SC_REFLECTSHIELD: + status_change_end(bl, SC_LG_REFLECTDAMAGE, INVALID_TIMER); + break; + case SC_LG_REFLECTDAMAGE: + status_change_end(bl, SC_REFLECTSHIELD, INVALID_TIMER); + break; + case SC_SHIELDSPELL_DEF: + case SC_SHIELDSPELL_MDEF: + case SC_SHIELDSPELL_REF: + status_change_end(bl, SC_MAGNIFICAT, INVALID_TIMER); status_change_end(bl, SC_SHIELDSPELL_DEF, INVALID_TIMER); - if( type != SC_SHIELDSPELL_MDEF ) status_change_end(bl, SC_SHIELDSPELL_MDEF, INVALID_TIMER); - if( type != SC_SHIELDSPELL_REF ) status_change_end(bl, SC_SHIELDSPELL_REF, INVALID_TIMER); - break; - case SC_GENTLETOUCH_ENERGYGAIN: - case SC_GENTLETOUCH_CHANGE: - case SC_GENTLETOUCH_REVITALIZE: - if( type != SC_GENTLETOUCH_REVITALIZE ) - status_change_end(bl, SC_GENTLETOUCH_REVITALIZE, INVALID_TIMER); - if( type != SC_GENTLETOUCH_ENERGYGAIN ) - status_change_end(bl, SC_GENTLETOUCH_ENERGYGAIN, INVALID_TIMER); - if( type != SC_GENTLETOUCH_CHANGE ) - status_change_end(bl, SC_GENTLETOUCH_CHANGE, INVALID_TIMER); - break; - case SC_INVINCIBLE: - status_change_end(bl, SC_INVINCIBLEOFF, INVALID_TIMER); - break; - case SC_INVINCIBLEOFF: - status_change_end(bl, SC_INVINCIBLE, INVALID_TIMER); - break; - case SC_MAGICPOWER: - status_change_end(bl, type, INVALID_TIMER); - break; + break; + case SC_GENTLETOUCH_ENERGYGAIN: + case SC_GENTLETOUCH_CHANGE: + case SC_GENTLETOUCH_REVITALIZE: + if( type != SC_GENTLETOUCH_REVITALIZE ) + status_change_end(bl, SC_GENTLETOUCH_REVITALIZE, INVALID_TIMER); + if( type != SC_GENTLETOUCH_ENERGYGAIN ) + status_change_end(bl, SC_GENTLETOUCH_ENERGYGAIN, INVALID_TIMER); + if( type != SC_GENTLETOUCH_CHANGE ) + status_change_end(bl, SC_GENTLETOUCH_CHANGE, INVALID_TIMER); + break; + case SC_INVINCIBLE: + status_change_end(bl, SC_INVINCIBLEOFF, INVALID_TIMER); + break; + case SC_INVINCIBLEOFF: + status_change_end(bl, SC_INVINCIBLE, INVALID_TIMER); + break; + case SC_MAGICPOWER: + status_change_end(bl, type, INVALID_TIMER); + break; } //Check for overlapping fails @@ -7182,6 +7466,15 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val case SC_MARIONETTE: case SC_NOCHAT: case SC_HLIF_CHANGE: //Otherwise your Hp/Sp would get refilled while still within effect of the last invocation. + case SC_ABUNDANCE: + case SC_TOXIN: + case SC_PARALYSE: + case SC_VENOMBLEED: + case SC_MAGICMUSHROOM: + case SC_DEATHHURT: + case SC_PYREXIA: + case SC_OBLIVIONCURSE: + case SC_LEECHESEND: case SC__INVISIBILITY: case SC__ENERVATION: case SC__GROOMY: @@ -7189,6 +7482,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val case SC__LAZINESS: case SC__WEAKNESS: case SC__UNLUCKY: + case SC__CHAOS: return 0; case SC_COMBOATTACK: case SC_DANCING: @@ -7204,7 +7498,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val case SC_ARMOR_RESIST: break; case SC_GOSPEL: - //Must not override a casting gospel char. + //Must not override a casting gospel char. if(sce->val4 == BCT_SELF) return 0; if(sce->val1 > val1) @@ -7220,7 +7514,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val //Kaahi overwrites previous level regardless of existing level. //Delete timer if it exists. if (sce->val4 != INVALID_TIMER) { - iTimer->delete_timer(sce->val4,kaahi_heal_timer); + timer->delete(sce->val4,status->kaahi_heal_timer); sce->val4 = INVALID_TIMER; } break; @@ -7231,7 +7525,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val val4 = sce->val4; break; case SC_LERADS_DEW: - if (sc && (sc->data[SC_BERSERK] || sc->data[SC__BLOODYLUST])) + if (sc && sc->data[SC_BERSERK]) return 0; case SC_SHAPESHIFT: case SC_PROPERTYWALK: @@ -7251,39 +7545,38 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val } } - vd = status_get_viewdata(bl); - calc_flag = StatusChangeFlagTable[type]; + vd = status->get_viewdata(bl); + calc_flag = status->ChangeFlagTable[type]; if(!(flag&4)) { //&4 - Do not parse val settings when loading SCs switch(type) { + case SC_ADORAMUS: + sc_start(src,bl,SC_BLIND,100,val1,skill->get_time(status->sc2skill(type),val1)); + // Fall through to SC_INC_AGI case SC_DEC_AGI: case SC_INC_AGI: val2 = 2 + val1; //Agi change break; case SC_ENDURE: val2 = 7; // Hit-count [Celest] - if( !(flag&1) && (bl->type&(BL_PC|BL_MER)) && !map_flag_gvg(bl->m) && !map[bl->m].flag.battleground && !val4 ) - { + if( !(flag&1) && (bl->type&(BL_PC|BL_MER)) && !map_flag_gvg(bl->m) && !map->list[bl->m].flag.battleground && !val4 ) { struct map_session_data *tsd; - if( sd ) - { + if( sd ) { int i; - for( i = 0; i < 5; i++ ) - { - if( sd->devotion[i] && (tsd = iMap->id2sd(sd->devotion[i])) ) - status_change_start(&tsd->bl, type, 10000, val1, val2, val3, val4, tick, 1); + for( i = 0; i < 5; i++ ) { + if( sd->devotion[i] && (tsd = map->id2sd(sd->devotion[i])) ) + status->change_start(bl, &tsd->bl, type, 10000, val1, val2, val3, val4, tick, 1); } - } - else if( bl->type == BL_MER && ((TBL_MER*)bl)->devotion_flag && (tsd = ((TBL_MER*)bl)->master) ) - status_change_start(&tsd->bl, type, 10000, val1, val2, val3, val4, tick, 1); + } else if( bl->type == BL_MER && ((TBL_MER*)bl)->devotion_flag && (tsd = ((TBL_MER*)bl)->master) ) + status->change_start(bl, &tsd->bl, type, 10000, val1, val2, val3, val4, tick, 1); } //val4 signals infinite endure (if val4 == 2 it is infinite endure from Berserk) if( val4 ) tick = -1; break; case SC_AUTOBERSERK: - if (status->hp < status->max_hp>>2 && + if (st->hp < st->max_hp>>2 && (!sc->data[SC_PROVOKE] || sc->data[SC_PROVOKE]->val2==0)) - sc_start4(bl,SC_PROVOKE,100,10,1,0,0,60000); + sc_start4(src,bl,SC_PROVOKE,100,10,1,0,0,60000); tick = -1; break; case SC_CRUCIS: @@ -7297,11 +7590,9 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val break; case SC_EDP: // [Celest] val2 = val1 + 2; //Chance to Poison enemies. + val3 = 50*(val1+1); //Damage increase (+50 +50*lv%) #ifdef RENEWAL_EDP - val3 = 50*(val1+3); val4 = 100 * ((val1 + 1)/2 + 2); - #else - val3 = 50*(val1+1); //Damage increase (+50 +50*lv%) #endif if( sd )//[Ind] - iROwiki says each level increases its duration by 3 seconds tick += pc->checkskill(sd,GC_RESEARCHNEWPOISON)*3000; @@ -7314,8 +7605,17 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val val2 = val1*20; //SP gained break; case SC_KYRIE: - val2 = (int64)status->max_hp * (val1 * 2 + 10) / 100; //%Max HP to absorb - val3 = (val1 / 2 + 5); //Hits + val2 = APPLY_RATE(st->max_hp, (val1 * 2 + 10)); //%Max HP to absorb + // val4 holds current about of party memebers when casting AB_PRAEFATIO, + // as Praefatio's barrier has more health and blocks more hits than Kyrie Elesion. + if( val4 < 1 ) //== PR_KYRIE + val3 = (val1 / 2 + 5); // Hits + else { //== AB_PRAEFATIO + val2 += val4 * 2; //Increase barrier strength per party member. + val3 = 6 + val1; + } + if( sd ) + val1 = min(val1,pc->checkskill(sd,PR_KYRIE)); // use skill level to determine barrier health. break; case SC_MAGICPOWER: //val1: Skill lv @@ -7355,20 +7655,16 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val break; case SC_REFLECTSHIELD: val2=10+val1*3; // %Dmg reflected - if( !(flag&1) && (bl->type&(BL_PC|BL_MER)) ) - { + if( !(flag&1) && (bl->type&(BL_PC|BL_MER)) ) { struct map_session_data *tsd; - if( sd ) - { + if( sd ) { int i; - for( i = 0; i < 5; i++ ) - { - if( sd->devotion[i] && (tsd = iMap->id2sd(sd->devotion[i])) ) - status_change_start(&tsd->bl, type, 10000, val1, val2, 0, 0, tick, 1); + for( i = 0; i < 5; i++ ) { + if( sd->devotion[i] && (tsd = map->id2sd(sd->devotion[i])) ) + status->change_start(bl, &tsd->bl, type, 10000, val1, val2, 0, 0, tick, 1); } - } - else if( bl->type == BL_MER && ((TBL_MER*)bl)->devotion_flag && (tsd = ((TBL_MER*)bl)->master) ) - status_change_start(&tsd->bl, type, 10000, val1, val2, 0, 0, tick, 1); + } else if( bl->type == BL_MER && ((TBL_MER*)bl)->devotion_flag && (tsd = ((TBL_MER*)bl)->master) ) + status->change_start(bl, &tsd->bl, type, 10000, val1, val2, 0, 0, tick, 1); } break; case SC_NOEQUIPWEAPON: @@ -7396,21 +7692,21 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val case SC_VOLCANO: val2 = val1*10; //Watk increase #ifndef RENEWAL - if (status->def_ele != ELE_FIRE) + if (st->def_ele != ELE_FIRE) val2 = 0; #endif break; case SC_VIOLENTGALE: val2 = val1*3; //Flee increase - #ifndef RENEWAL - if (status->def_ele != ELE_WIND) + #ifndef RENEWAL + if (st->def_ele != ELE_WIND) val2 = 0; - #endif + #endif break; case SC_DELUGE: - val2 = deluge_eff[val1-1]; //HP increase + val2 = skill->deluge_eff[val1-1]; //HP increase #ifndef RENEWAL - if(status->def_ele != ELE_WATER) + if(st->def_ele != ELE_WATER) val2 = 0; #endif break; @@ -7466,18 +7762,22 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val case SC_ATTHASTE_POTION3: case SC_ATTHASTE_INFINITY: val2 = 50*(2+type-SC_ATTHASTE_POTION1); - break; + break; case SC_WEDDING: case SC_XMAS: case SC_SUMMER: case SC_HANBOK: + case SC_OKTOBERFEST: if (!vd) return 0; //Store previous values as they could be removed. - unit_stop_attack(bl); + unit->stop_attack(bl); break; case SC_NOCHAT: - // [GodLesZ] FIXME: is this correct? a hardcoded interval of 60sec? what about configuration ?_? + // A hardcoded interval of 60 seconds is expected, as the time that SC_NOCHAT uses is defined by + // mmocharstatus.manner, each negative point results in 1 minute with this status activated + // This is done this way because the message that the client displays is hardcoded, and only + // shows how many minutes are remaining. [Panikon] tick = 60000; val1 = battle_config.manner_system; //Mute filters. if (sd) @@ -7497,30 +7797,30 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val break; case SC_DPOISON: - //Lose 10/15% of your life as long as it doesn't brings life below 25% - if (status->hp > status->max_hp>>2) { - int diff = status->max_hp*(bl->type==BL_PC?10:15)/100; - if (status->hp - diff < status->max_hp>>2) - diff = status->hp - (status->max_hp>>2); - if( val2 && bl->type == BL_MOB ) { - struct block_list* src = iMap->id2bl(val2); - if( src ) - mob_log_damage((TBL_MOB*)bl,src,diff); + //Lose 10/15% of your life as long as it doesn't brings life below 25% + if (st->hp > st->max_hp>>2) { + int diff = st->max_hp*(bl->type==BL_PC?10:15)/100; + if (st->hp - diff < st->max_hp>>2) + diff = st->hp - (st->max_hp>>2); + if( val2 && bl->type == BL_MOB ) { + struct block_list* src2 = map->id2bl(val2); + if( src2 ) + mob->log_damage((TBL_MOB*)bl,src2,diff); + } + status_zap(bl, diff, 0); } - status_zap(bl, diff, 0); - } - // fall through + // fall through case SC_POISON: - val3 = tick/1000; //Damage iterations - if(val3 < 1) val3 = 1; - tick_time = 1000; // [GodLesZ] tick time - //val4: HP damage - if (bl->type == BL_PC) - val4 = (type == SC_DPOISON) ? 3 + status->max_hp/50 : 3 + status->max_hp*3/200; - else - val4 = (type == SC_DPOISON) ? 3 + status->max_hp/100 : 3 + status->max_hp/200; + val3 = tick/1000; //Damage iterations + if(val3 < 1) val3 = 1; + tick_time = 1000; // [GodLesZ] tick time + //val4: HP damage + if (bl->type == BL_PC) + val4 = (type == SC_DPOISON) ? 3 + st->max_hp/50 : 3 + st->max_hp*3/200; + else + val4 = (type == SC_DPOISON) ? 3 + st->max_hp/100 : 3 + st->max_hp/200; - break; + break; case SC_CONFUSION: clif->emotion(bl,E_WHAT); break; @@ -7541,11 +7841,10 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val tick_time = val2 * 1000; // [GodLesZ] tick time break; case SC_CASH_BOSS_ALARM: - if( sd != NULL ) - { - struct mob_data *boss_md = iMap->getmob_boss(bl->m); // Search for Boss on this Map - if( boss_md == NULL || boss_md->bl.prev == NULL ) - { // No MVP on this map - MVP is dead + if( sd != NULL ) { + struct mob_data *boss_md = map->getmob_boss(bl->m); // Search for Boss on this Map + if( boss_md == NULL || boss_md->bl.prev == NULL ) { + // No MVP on this map - MVP is dead clif->bossmapinfo(sd->fd, boss_md, 1); return 0; // No need to start SC } @@ -7567,7 +7866,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val if (sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_ROGUE) val3 -= 40; val4 = 10+val1*2; //SP cost. - if (map_flag_gvg(bl->m) || map[bl->m].flag.battleground) val4 *= 5; + if (map_flag_gvg(bl->m) || map->list[bl->m].flag.battleground) val4 *= 5; break; case SC_CLOAKING: if (!sd) //Monsters should be able to walk with no penalties. [Skotlex] @@ -7591,7 +7890,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val tick_time = 10; // [GodLesZ] tick time break; - //Permanent effects. + //Permanent effects. case SC_LEXAETERNA: case SC_MODECHANGE: case SC_WEIGHTOVER50: @@ -7604,52 +7903,44 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val case SC_TURNKICK_READY: case SC_DODGE_READY: case SC_PUSH_CART: - case SC_ALL_RIDING: tick = -1; break; case SC_AUTOGUARD: - if( !(flag&1) ) - { + if( !(flag&1) ) { struct map_session_data *tsd; int i,t; - for( i = val2 = 0; i < val1; i++) - { + for( i = val2 = 0; i < val1; i++) { t = 5-(i>>1); val2 += (t < 0)? 1:t; } - if( bl->type&(BL_PC|BL_MER) ) - { - if( sd ) - { - for( i = 0; i < 5; i++ ) - { - if( sd->devotion[i] && (tsd = iMap->id2sd(sd->devotion[i])) ) - status_change_start(&tsd->bl, type, 10000, val1, val2, 0, 0, tick, 1); + if( bl->type&(BL_PC|BL_MER) ) { + if( sd ) { + for( i = 0; i < 5; i++ ) { + if( sd->devotion[i] && (tsd = map->id2sd(sd->devotion[i])) ) + status->change_start(bl, &tsd->bl, type, 10000, val1, val2, 0, 0, tick, 1); } } else if( bl->type == BL_MER && ((TBL_MER*)bl)->devotion_flag && (tsd = ((TBL_MER*)bl)->master) ) - status_change_start(&tsd->bl, type, 10000, val1, val2, 0, 0, tick, 1); + status->change_start(bl, &tsd->bl, type, 10000, val1, val2, 0, 0, tick, 1); } } break; case SC_DEFENDER: - if (!(flag&1)) - { + if (!(flag&1)) { val2 = 5 + 15*val1; //Damage reduction val3 = 0; // unused, previously speed adjustment val4 = 250 - 50*val1; //Aspd adjustment - if (sd) - { + if (sd) { struct map_session_data *tsd; int i; - for (i = 0; i < 5; i++) - { //See if there are devoted characters, and pass the status to them. [Skotlex] - if (sd->devotion[i] && (tsd = iMap->id2sd(sd->devotion[i]))) - status_change_start(&tsd->bl,type,10000,val1,5+val1*5,val3,val4,tick,1); + for (i = 0; i < 5; i++) { + //See if there are devoted characters, and pass the status to them. [Skotlex] + if (sd->devotion[i] && (tsd = map->id2sd(sd->devotion[i]))) + status->change_start(bl, &tsd->bl,type,10000,val1,5+val1*5,val3,val4,tick,1); } } } @@ -7676,26 +7967,28 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val case SC_JOINTBEAT: if( val2&BREAK_NECK ) - sc_start2(bl,SC_BLOODING,100,val1,val3,skill->get_time2(status_sc2skill(type),val1)); + sc_start2(src,bl,SC_BLOODING,100,val1,val3,skill->get_time2(status->sc2skill(type),val1)); break; case SC_BERSERK: - if (!sc->data[SC_ENDURE] || !sc->data[SC_ENDURE]->val4) - sc_start4(bl, SC_ENDURE, 100,10,0,0,2, tick); - case SC__BLOODYLUST: + if( val3 == SC__BLOODYLUST ) + sc_start(src,bl,(sc_type)val3,100,val1,tick); + if( !val3 && !(!sc->data[SC_ENDURE] || !sc->data[SC_ENDURE]->val4) ) + sc_start4(src, bl, SC_ENDURE, 100,10,0,0,2, tick); //HP healing is performing after the calc_status call. //Val2 holds HP penalty - if (!val4) val4 = skill->get_time2(status_sc2skill(type),val1); + if (!val4) val4 = skill->get_time2(status->sc2skill(type),val1); if (!val4) val4 = 10000; //Val4 holds damage interval val3 = tick/val4; //val3 holds skill duration tick_time = val4; // [GodLesZ] tick time break; case SC_GOSPEL: - if(val4 == BCT_SELF) { // self effect + if(val4 == BCT_SELF) { + // self effect val2 = tick/10000; tick_time = 10000; // [GodLesZ] tick time - status_change_clear_buffs(bl,3); //Remove buffs/debuffs + status->change_clear_buffs(bl,3); //Remove buffs/debuffs } break; @@ -7705,23 +7998,23 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val val3 = 0; val4 = 0; - stat = ( sd ? sd->status.str : status_get_base_status(bl)->str ) / 2; val3 |= cap_value(stat,0,0xFF)<<16; - stat = ( sd ? sd->status.agi : status_get_base_status(bl)->agi ) / 2; val3 |= cap_value(stat,0,0xFF)<<8; - stat = ( sd ? sd->status.vit : status_get_base_status(bl)->vit ) / 2; val3 |= cap_value(stat,0,0xFF); - stat = ( sd ? sd->status.int_: status_get_base_status(bl)->int_) / 2; val4 |= cap_value(stat,0,0xFF)<<16; - stat = ( sd ? sd->status.dex : status_get_base_status(bl)->dex ) / 2; val4 |= cap_value(stat,0,0xFF)<<8; - stat = ( sd ? sd->status.luk : status_get_base_status(bl)->luk ) / 2; val4 |= cap_value(stat,0,0xFF); - break; + stat = ( sd ? sd->status.str : status->get_base_status(bl)->str ) / 2; val3 |= cap_value(stat,0,0xFF)<<16; + stat = ( sd ? sd->status.agi : status->get_base_status(bl)->agi ) / 2; val3 |= cap_value(stat,0,0xFF)<<8; + stat = ( sd ? sd->status.vit : status->get_base_status(bl)->vit ) / 2; val3 |= cap_value(stat,0,0xFF); + stat = ( sd ? sd->status.int_: status->get_base_status(bl)->int_) / 2; val4 |= cap_value(stat,0,0xFF)<<16; + stat = ( sd ? sd->status.dex : status->get_base_status(bl)->dex ) / 2; val4 |= cap_value(stat,0,0xFF)<<8; + stat = ( sd ? sd->status.luk : status->get_base_status(bl)->luk ) / 2; val4 |= cap_value(stat,0,0xFF); } + break; case SC_MARIONETTE: { int stat,max_stat; // fetch caster information - struct block_list *pbl = iMap->id2bl(val1); - struct status_change *psc = pbl?status_get_sc(pbl):NULL; - struct status_change_entry *psce = psc?psc->data[SC_MARIONETTE_MASTER]:NULL; + struct block_list *pbl = map->id2bl(val1); + struct status_change *psc = pbl ? status->get_sc(pbl) : NULL; + struct status_change_entry *psce = psc ? psc->data[SC_MARIONETTE_MASTER] : NULL; // fetch target's stats - struct status_data* status = status_get_status_data(bl); // battle status + struct status_data* tst = status->get_status_data(bl); // battle status if (!psce) return 0; @@ -7729,14 +8022,14 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val val3 = 0; val4 = 0; max_stat = battle_config.max_parameter; //Cap to 99 (default) - stat = (psce->val3 >>16)&0xFF; stat = min(stat, max_stat - status->str ); val3 |= cap_value(stat,0,0xFF)<<16; - stat = (psce->val3 >> 8)&0xFF; stat = min(stat, max_stat - status->agi ); val3 |= cap_value(stat,0,0xFF)<<8; - stat = (psce->val3 >> 0)&0xFF; stat = min(stat, max_stat - status->vit ); val3 |= cap_value(stat,0,0xFF); - stat = (psce->val4 >>16)&0xFF; stat = min(stat, max_stat - status->int_); val4 |= cap_value(stat,0,0xFF)<<16; - stat = (psce->val4 >> 8)&0xFF; stat = min(stat, max_stat - status->dex ); val4 |= cap_value(stat,0,0xFF)<<8; - stat = (psce->val4 >> 0)&0xFF; stat = min(stat, max_stat - status->luk ); val4 |= cap_value(stat,0,0xFF); - break; + stat = (psce->val3 >>16)&0xFF; stat = min(stat, max_stat - tst->str ); val3 |= cap_value(stat,0,0xFF)<<16; + stat = (psce->val3 >> 8)&0xFF; stat = min(stat, max_stat - tst->agi ); val3 |= cap_value(stat,0,0xFF)<<8; + stat = (psce->val3 >> 0)&0xFF; stat = min(stat, max_stat - tst->vit ); val3 |= cap_value(stat,0,0xFF); + stat = (psce->val4 >>16)&0xFF; stat = min(stat, max_stat - tst->int_); val4 |= cap_value(stat,0,0xFF)<<16; + stat = (psce->val4 >> 8)&0xFF; stat = min(stat, max_stat - tst->dex ); val4 |= cap_value(stat,0,0xFF)<<8; + stat = (psce->val4 >> 0)&0xFF; stat = min(stat, max_stat - tst->luk ); val4 |= cap_value(stat,0,0xFF); } + break; case SC_SWORDREJECT: val2 = 15*val1; //Reflect chance val3 = 3; //Reflections @@ -7766,16 +8059,15 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val struct block_list *d_bl; struct status_change *d_sc; - if( (d_bl = iMap->id2bl(val1)) && (d_sc = status_get_sc(d_bl)) && d_sc->count ) - { // Inherits Status From Source + if( (d_bl = map->id2bl(val1)) && (d_sc = status->get_sc(d_bl)) && d_sc->count ) { + // Inherits Status From Source const enum sc_type types[] = { SC_AUTOGUARD, SC_DEFENDER, SC_REFLECTSHIELD, SC_ENDURE }; enum sc_type type2; - int i = (map_flag_gvg(bl->m) || map[bl->m].flag.battleground)?2:3; - while( i >= 0 ) - { + int i = (map_flag_gvg(bl->m) || map->list[bl->m].flag.battleground)?2:3; + while( i >= 0 ) { type2 = types[i]; if( d_sc->data[type2] ) - sc_start(bl, type2, 100, d_sc->data[type2]->val1, skill->get_time(status_sc2skill(type2),d_sc->data[type2]->val1)); + sc_start(bl, bl, type2, 100, d_sc->data[type2]->val1, skill->get_time(status->sc2skill(type2),d_sc->data[type2]->val1)); i--; } } @@ -7784,25 +8076,25 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val case SC_COMA: //Coma. Sends a char to 1HP. If val2, do not zap sp if( val3 && bl->type == BL_MOB ) { - struct block_list* src = iMap->id2bl(val3); - if( src ) - mob_log_damage((TBL_MOB*)bl,src,status->hp - 1); + struct block_list* src2 = map->id2bl(val3); + if( src2 ) + mob->log_damage((TBL_MOB*)bl,src2,st->hp - 1); } - status_zap(bl, status->hp-1, val2?0:status->sp); + status_zap(bl, st->hp-1, val2 ? 0 : st->sp); return 1; break; case SC_RG_CCONFINE_S: { - struct block_list *src = val2?iMap->id2bl(val2):NULL; - struct status_change *sc2 = src?status_get_sc(src):NULL; - struct status_change_entry *sce2 = sc2?sc2->data[SC_RG_CCONFINE_M]:NULL; - if (src && sc2) { + struct block_list *src2 = val2 ? map->id2bl(val2) : NULL; + struct status_change *sc2 = src ? status->get_sc(src2) : NULL; + struct status_change_entry *sce2 = sc2 ? sc2->data[SC_RG_CCONFINE_M] : NULL; + if (src2 && sc2) { if (!sce2) //Start lock on caster. - sc_start4(src,SC_RG_CCONFINE_M,100,val1,1,0,0,tick+1000); + sc_start4(src,src2,SC_RG_CCONFINE_M,100,val1,1,0,0,tick+1000); else { //Increase count of locked enemies and refresh time. (sce2->val2)++; - iTimer->delete_timer(sce2->timer, status_change_timer); - sce2->timer = iTimer->add_timer(iTimer->gettick()+tick+1000, status_change_timer, src->id, SC_RG_CCONFINE_M); + timer->delete(sce2->timer, status->change_timer); + sce2->timer = timer->add(timer->gettick()+tick+1000, status->change_timer, src2->id, SC_RG_CCONFINE_M); } } else //Status failed. return 0; @@ -7813,41 +8105,50 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val break; case SC_KAUPE: switch (val1) { - case 3: //33*3 + 1 -> 100% - val2++; - case 1: - case 2: //33, 66% - val2 += 33*val1; - val3 = 1; //Dodge 1 attack total. - break; - default: //Custom. For high level mob usage, higher level means more blocks. [Skotlex] - val2 = 100; - val3 = val1-2; - break; + case 3: //33*3 + 1 -> 100% + val2++; + case 1: + case 2: //33, 66% + val2 += 33*val1; + val3 = 1; //Dodge 1 attack total. + break; + default: //Custom. For high level mob usage, higher level means more blocks. [Skotlex] + val2 = 100; + val3 = val1-2; + break; } break; - case SC_COMBOATTACK: { - //val1: Skill ID - //val2: When given, target (for autotargetting skills) - //val3: When set, this combo time should NOT delay attack/movement - //val3: TK: Last used kick - //val4: TK: Combo time - struct unit_data *ud = unit_bl2ud(bl); - if (ud && !val3) { - tick += 300 * battle_config.combo_delay_rate/100; - ud->attackabletime = iTimer->gettick()+tick; - unit_set_walkdelay(bl, iTimer->gettick(), tick, 1); - } - val3 = 0; - val4 = tick; + case SC_COMBOATTACK: + { + //val1: Skill ID + //val2: When given, target (for autotargetting skills) + //val3: When set, this combo time should NOT delay attack/movement + //val3: If set to 2 this combo will delay ONLY attack + //val3: TK: Last used kick + //val4: TK: Combo time + struct unit_data *ud = unit->bl2ud(bl); + if( ud && (!val3 || val3 == 2) ) { + tick += 300 * battle_config.combo_delay_rate/100; + ud->attackabletime = timer->gettick()+tick; + if( !val3 ) + unit->set_walkdelay(bl, timer->gettick(), tick, 1); } + val3 = 0; + val4 = tick; break; + } case SC_EARTHSCROLL: val2 = 11-val1; //Chance to consume: 11-skill_lv% break; case SC_RUN: - val4 = iTimer->gettick(); //Store time at which you started running. + { + //Store time at which you started running. + int64 currenttick = timer->gettick(); + // Note: this int64 value is stored in two separate int32 variables (FIXME) + val3 = (int)(currenttick&0x00000000ffffffffLL); + val4 = (int)((currenttick&0xffffffff00000000LL)>>32); + } tick = -1; break; case SC_KAAHI: @@ -7856,7 +8157,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val val4 = INVALID_TIMER; //Kaahi Timer. break; case SC_BLESSING: - if ((!undead_flag && status->race!=RC_DEMON) || bl->type == BL_PC) + if ((!undead_flag && st->race!=RC_DEMON) || bl->type == BL_PC) val2 = val1; else val2 = 0; //0 -> Half stat. @@ -7894,7 +8195,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val val2 = 5*val1; //Batk/Watk Increase val3 = 10*val1; //Hit Increase val4 = 5*val1; //Def reduction - sc_start(bl, SC_ENDURE, 100, 1, tick); //Endure effect + sc_start(src, bl, SC_ENDURE, 100, 1, tick); //Endure effect break; case SC_ANGELUS: val2 = 5*val1; //def increase @@ -7911,23 +8212,25 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val val3 = 3*val1; //Hit increase break; case SC_SUN_COMFORT: - val2 = (status_get_lv(bl) + status->dex + status->luk)/2; //def increase + val2 = (status->get_lv(bl) + st->dex + st->luk)/2; //def increase break; case SC_MOON_COMFORT: - val2 = (status_get_lv(bl) + status->dex + status->luk)/10; //flee increase + val2 = (status->get_lv(bl) + st->dex + st->luk)/10; //flee increase break; case SC_STAR_COMFORT: - val2 = (status_get_lv(bl) + status->dex + status->luk); //Aspd increase + val2 = (status->get_lv(bl) + st->dex + st->luk); //Aspd increase break; case SC_QUAGMIRE: val2 = (sd?5:10)*val1; //Agi/Dex decrease. break; - // gs_something1 [Vicious] + // gs_something1 [Vicious] case SC_GS_GATLINGFEVER: val2 = 20*val1; //Aspd increase - val3 = 20+10*val1; //Batk increase val4 = 5*val1; //Flee decrease + #ifndef RENEWAL + val3 = 20+10*val1; //Batk increase + #endif break; case SC_FLING: @@ -7967,20 +8270,30 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val tick_time = 1000; // [GodLesZ] tick time break; case SC_JAILED: - //Val1 is duration in minutes. Use INT_MAX to specify 'unlimited' time. + // val1 is duration in minutes. Use INT_MAX to specify 'unlimited' time. + // When first called: + // val2 Jail map_index + // val3 x + // val4 y + // When renewing status' information + // val3 Return map_index + // val4 return coordinates tick = val1>0?1000:250; if (sd) { if (sd->mapindex != val2) { - int pos = (bl->x&0xFFFF)|(bl->y<<16), //Current Coordinates - map = sd->mapindex; //Current Map + int pos = (bl->x&0xFFFF)|(bl->y<<16); /// Current Coordinates + int map_index = sd->mapindex; /// Current Map //1. Place in Jail (val2 -> Jail Map, val3 -> x, val4 -> y pc->setpos(sd,(unsigned short)val2,val3,val4, CLR_TELEPORT); //2. Set restore point (val3 -> return map, val4 return coords - val3 = map; + val3 = map_index; val4 = pos; - } else if (!val3 || val3 == sd->mapindex) { //Use save point. + } else if (!val3 + || val3 == sd->mapindex + || !sd->sc.data[SC_JAILED] // If player is being jailed and is already in jail (issue: 8206) + ) { //Use save point. val3 = sd->status.save_point.map; val4 = (sd->status.save_point.x&0xFFFF) |(sd->status.save_point.y<<16); @@ -7999,7 +8312,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val val3= 20*val1; //Int increase break; case SC_SWOO: - if(status->mode&MD_BOSS) + if(st->mode&MD_BOSS) tick /= 5; //TODO: Reduce skill's duration. But for how long? break; case SC_SPIDERWEB: @@ -8067,12 +8380,12 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val case SC_KAIZEL: val2 = 10*val1; //% of life to be revived with break; - // case SC_ARMORPROPERTY: - // case SC_ARMOR_RESIST: + // case SC_ARMORPROPERTY: + // case SC_ARMOR_RESIST: // Mod your resistance against elements: // val1 = water | val2 = earth | val3 = fire | val4 = wind // break; - //case ????: + //case ????: //Place here SCs that have no SCB_* data, no skill associated, no ICON //associated, and yet are not wrong/unknown. [Skotlex] //break; @@ -8100,9 +8413,9 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val case SC_SPL_MATK: val2 = 2; // Splendide group break; - /** - * General - **/ + /** + * General + **/ case SC_FEAR: val2 = 2; val4 = tick / 1000; @@ -8112,9 +8425,9 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val val4 = tick / 3000; // Total Ticks to Burn!! tick_time = 3000; // [GodLesZ] tick time break; - /** - * Rune Knight - **/ + /** + * Rune Knight + **/ case SC_DEATHBOUND: val2 = 500 + 100 * val1; break; @@ -8122,19 +8435,13 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val if( sd ) val1 = sd->status.job_level * pc->checkskill(sd, RK_RUNEMASTERY) / 4; //DEF/MDEF Increase break; - case SC_FIGHTINGSPIRIT: - val_flag |= 1|2; - break; case SC_ABUNDANCE: val4 = tick / 10000; tick_time = 10000; // [GodLesZ] tick time break; - case SC_GIANTGROWTH: - val2 = 10; // Triple damage success rate. - break; - /** - * Arch Bishop - **/ + /** + * Arch Bishop + **/ case SC_RENOVATIO: val4 = tick / 5000; tick_time = 5000; @@ -8144,16 +8451,11 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val break; case SC_VENOMIMPRESS: val2 = 10 * val1; - val_flag |= 1|2; - break; - case SC_POISONINGWEAPON: - val_flag |= 1|2|4; break; case SC_WEAPONBLOCKING: val2 = 10 + 2 * val1; // Chance - val4 = tick / 3000; - tick_time = 3000; // [GodLesZ] tick time - val_flag |= 1|2; + val4 = tick / 5000; + tick_time = 5000; // [GodLesZ] tick time break; case SC_TOXIN: val4 = tick / 10000; @@ -8164,7 +8466,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val tick_time = 4000; // [GodLesZ] tick time break; case SC_PYREXIA: - status_change_start(bl,SC_BLIND,10000,val1,0,0,0,30000,11); // Blind status that last for 30 seconds + status->change_start(src, bl,SC_BLIND,10000,val1,0,0,0,30000,11); // Blind status that last for 30 seconds val4 = tick / 3000; tick_time = 3000; // [GodLesZ] tick time break; @@ -8176,13 +8478,9 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val val4 = tick / 3000; tick_time = 3000; // [GodLesZ] tick time break; - case SC_ROLLINGCUTTER: - val_flag |= 1; - break; case SC_CLOAKINGEXCEED: val2 = ( val1 + 1 ) / 2; // Hits val3 = 90 + val1 * 10; // Walk speed - val_flag |= 1|2|4; if (bl->type == BL_PC) val4 |= battle_config.pc_cloak_check_type&7; else @@ -8192,7 +8490,6 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val case SC_HALLUCINATIONWALK: val2 = 50 * val1; // Evasion rate of physical attacks. Flee val3 = 10 * val1; // Evasion rate of magical attacks. - val_flag |= 1|2|4; break; case SC_WHITEIMPRISON: status_change_end(bl, SC_BURNING, INVALID_TIMER); @@ -8210,7 +8507,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val break; case SC_READING_SB: // val2 = sp reduction per second - tick_time = 5000; // [GodLesZ] tick time + tick_time = 10000; // [GodLesZ] tick time break; case SC_SUMMON1: case SC_SUMMON2: @@ -8221,19 +8518,22 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val if( val4 < 1 ) val4 = 1; tick_time = 1000; // [GodLesZ] tick time - val_flag |= 1; break; case SC_SHAPESHIFT: switch( val1 ) { - case 1: val2 = ELE_FIRE; break; - case 2: val2 = ELE_EARTH; break; - case 3: val2 = ELE_WIND; break; - case 4: val2 = ELE_WATER; break; + case 1: val2 = ELE_FIRE; break; + case 2: val2 = ELE_EARTH; break; + case 3: val2 = ELE_WIND; break; + case 4: val2 = ELE_WATER; break; } break; + case SC_STEALTHFIELD_MASTER: + val4 = tick / 1000; + tick_time = 2000 + (1000 * val1); + break; case SC_ELECTRICSHOCKER: - case SC_CRYSTALIZE: + case SC_COLD: case SC_MEIKYOUSISUI: val4 = tick / 1000; if( val4 < 1 ) @@ -8245,17 +8545,26 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val tick_time = 1000; // [GodLesZ] tick time break; case SC_WUGDASH: - val4 = iTimer->gettick(); //Store time at which you started running. + { + //Store time at which you started running. + int64 currenttick = timer->gettick(); + // Note: this int64 value is stored in two separate int32 variables (FIXME) + val3 = (int)(currenttick&0x00000000ffffffffLL); + val4 = (int)((currenttick&0xffffffff00000000LL)>>32); + } tick = -1; break; + case SC__REPRODUCE: + val4 = tick / 1000; + tick_time = 1000; + break; case SC__SHADOWFORM: { - struct map_session_data * s_sd = iMap->id2sd(val2); - if( s_sd ) - s_sd->shadowform_id = bl->id; - val4 = tick / 1000; - val_flag |= 1|2|4; - tick_time = 1000; // [GodLesZ] tick time - } + struct map_session_data * s_sd = map->id2sd(val2); + if( s_sd ) + s_sd->shadowform_id = bl->id; + val4 = tick / 1000; + tick_time = 1000; // [GodLesZ] tick time + } break; case SC__STRIPACCESSARY: if (!sd) @@ -8263,47 +8572,40 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val break; case SC__INVISIBILITY: val2 = 50 - 10 * val1; // ASPD - val3 = 20 * val1; // CRITICAL + val3 = 200 * val1; // CRITICAL val4 = tick / 1000; tick_time = 1000; // [GodLesZ] tick time - val_flag |= 1|2; break; case SC__ENERVATION: val2 = 20 + 10 * val1; // ATK Reduction - val_flag |= 1|2; if( sd ) pc->delspiritball(sd,sd->spiritball,0); break; case SC__GROOMY: val2 = 20 + 10 * val1; //ASPD. Need to confirm if Movement Speed reduction is the same. [Jobbie] val3 = 20 * val1; //HIT - val_flag |= 1|2|4; if( sd ) { // Removes Animals if( pc_isriding(sd) ) pc->setriding(sd, 0); if( pc_isridingdragon(sd) ) pc->setoption(sd, sd->sc.option&~OPTION_DRAGON); if( pc_iswug(sd) ) pc->setoption(sd, sd->sc.option&~OPTION_WUG); if( pc_isridingwug(sd) ) pc->setoption(sd, sd->sc.option&~OPTION_WUGRIDER); if( pc_isfalcon(sd) ) pc->setoption(sd, sd->sc.option&~OPTION_FALCON); - if( sd->status.pet_id > 0 ) pet_menu(sd, 3); - if( homun_alive(sd->hd) ) homun->vaporize(sd,1); - if( sd->md ) merc_delete(sd->md,3); + if( sd->status.pet_id > 0 ) pet->menu(sd, 3); + if( homun_alive(sd->hd) ) homun->vaporize(sd,HOM_ST_REST); + if( sd->md ) mercenary->delete(sd->md,3); } break; case SC__LAZINESS: val2 = 10 + 10 * val1; // Cast reduction val3 = 10 * val1; // Flee Reduction - val_flag |= 1|2|4; break; case SC__UNLUCKY: val2 = 10 * val1; // Crit and Flee2 Reduction - val_flag |= 1|2|4; break; case SC__WEAKNESS: val2 = 10 * val1; - val_flag |= 1|2; // bypasses coating protection and MADO - sc_start(bl,SC_NOEQUIPWEAPON,100,val1,tick); - sc_start(bl,SC_NOEQUIPSHIELD,100,val1,tick); - break; + sc_start(src, bl,SC_NOEQUIPWEAPON,100,val1,tick); + sc_start(src, bl,SC_NOEQUIPSHIELD,100,val1,tick); break; case SC_GN_CARTBOOST: if( val1 < 3 ) @@ -8314,13 +8616,12 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val val2 = 100; break; case SC_PROPERTYWALK: - val_flag |= 1|2; val3 = 0; break; case SC_WARMER: status_change_end(bl, SC_FREEZE, INVALID_TIMER); status_change_end(bl, SC_FROSTMISTY, INVALID_TIMER); - status_change_end(bl, SC_CRYSTALIZE, INVALID_TIMER); + status_change_end(bl, SC_COLD, INVALID_TIMER); break; case SC_STRIKING: val1 = 6 - val1;//spcost = 6 - level (lvl1:5 ... lvl 5: 1) @@ -8328,32 +8629,26 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val tick_time = 1000; // [GodLesZ] tick time break; case SC_BLOOD_SUCKER: - { - struct block_list *src = iMap->id2bl(sce->val2); - val3 = 1; - if(src) - val3 = 200 + 100 * sce->val1 + status_get_int(src); - val4 = tick / 1000; - tick_time = 1000; // [GodLesZ] tick time - } - break; - case SC_VACUUM_EXTREME: - tick -= (status->str / 20) * 1000; - val4 = val3 = tick / 100; - tick_time = 100; // [GodLesZ] tick time + { + struct block_list *src2 = map->id2bl(val2); + val3 = 1; + if(src2) + val3 = 200 + 100 * val1 + status_get_int(src2); + val4 = tick / 1000; + tick_time = 1000; // [GodLesZ] tick time + } break; case SC_SWING: - val2 = 4 * val1; // Walk speed and aspd reduction. + val3 = 5 * val1 + val2;//Movement Speed And ASPD Increase break; case SC_SYMPHONY_LOVE: + val2 = 12 * val1 + val2 + sd->status.job_level / 4;//MDEF Increase In % + case SC_MOONLIT_SERENADE: case SC_RUSH_WINDMILL: - case SC_ECHOSONG: - val2 = 6 * val1; - val2 += val3; //Adding 1% * Lesson Bonus - val2 += (int)(val4*2/10); //Adding 0.2% per JobLevel + val2 = 6 * val1 + val2 + sd->status.job_level / 5; break; - case SC_MOONLIT_SERENADE: - val2 = 10 * val1; + case SC_ECHOSONG: + val3 = 6 * val1 + val2 + sd->status.job_level / 4;//DEF Increase In % break; case SC_HARMONIZE: val2 = 5 + 5 * val1; @@ -8367,34 +8662,36 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val tick_time = 2000; // [GodLesZ] tick time break; case SC_SIRCLEOFNATURE: - val2 = 1 + val1; //SP consume - val3 = 40 * val1; //HP recovery + val2 = 40 * val1;//HP recovery + val3 = 4 * val1;//SP drain val4 = tick / 1000; tick_time = 1000; // [GodLesZ] tick time break; case SC_SONG_OF_MANA: - val3 = 10 + (2 * val2); - val4 = tick/3000; - tick_time = 3000; // [GodLesZ] tick time + val3 = 10 + 5 * val2; + val4 = tick/5000; + tick_time = 5000; // [GodLesZ] tick time break; case SC_SATURDAY_NIGHT_FEVER: - if (!val4) val4 = skill->get_time2(status_sc2skill(type),val1); - if (!val4) val4 = 3000; - val3 = tick/val4; - tick_time = val4; // [GodLesZ] tick time + /*val2 = 12000 - 2000 * val1;//HP/SP Drain Timer + if ( val2 < 1000 ) + val2 = 1000;//Added to prevent val3 from dividing by 0 when using level 6 or higher through commands. [Rytech] + val3 = tick/val2;*/ + val3 = tick / 3000; + tick_time = 3000;// [GodLesZ] tick time break; case SC_GLOOMYDAY: - val2 = 20 + 5 * val1; // Flee reduction. - val3 = 15 + 5 * val1; // ASPD reduction. - if( sd && rand()%100 < val1 ){ // (Skill Lv) % - val4 = 1; // reduce walk speed by half. - if( pc_isriding(sd) ) pc->setriding(sd, 0); - if( pc_isridingdragon(sd) ) pc->setoption(sd, sd->sc.option&~OPTION_DRAGON); + if ( !val2 ) { + val2 = (val4 > 0 ? max(15, rnd()%(val4*5)) : 0) + val1 * 10; + } + if ( rnd()%10000 < val1*100 ) { // 1% per SkillLv chance + if ( !val3 ) + val3 = 50; + if( sd ) { + if( pc_isriding(sd) ) pc->setriding(sd, 0); + if( pc_isridingdragon(sd) ) pc->setoption(sd, sd->sc.option&~OPTION_DRAGON); + } } - break; - case SC_GLOOMYDAY_SK: - // Random number between [15 ~ (Voice Lesson Skill Level x 5) + (Skill Level x 10)] %. - val2 = 15 + rand()%( (sd?pc->checkskill(sd, WM_LESSON)*5:0) + val1*10 ); break; case SC_SITDOWN_FORCE: case SC_BANANA_BOMB_SITDOWN_POSTDELAY: @@ -8406,119 +8703,108 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val } break; case SC_DANCE_WITH_WUG: - val3 = (5 * val1) + (1 * val2); //Still need official value. + val3 = 5 + 5 * val2;//ASPD Increase + val4 = 20 + 10 * val2;//Fixed Cast Time Reduction break; case SC_LERADS_DEW: - val3 = (5 * val1) + (1 * val2); + val3 = 200 * val1 + 300 * val2;//MaxHP Increase break; case SC_MELODYOFSINK: - val3 = (5 * val1) + (1 * val2); + val3 = val1 * (2 + val2);//INT Reduction. Formula Includes Caster And 2nd Performer. + val4 = tick/1000; + tick_time = 1000; break; case SC_BEYOND_OF_WARCRY: - val3 = (5 * val1) + (1 * val2); + val3 = val1 * (2 + val2);//STR And Crit Reduction. Formula Includes Caster And 2nd Performer. + val4 = 4 * val1 + 4 * val2;//MaxHP Reduction break; case SC_UNLIMITED_HUMMING_VOICE: { - struct unit_data *ud = unit_bl2ud(bl); + struct unit_data *ud = unit->bl2ud(bl); if( ud == NULL ) return 0; ud->state.skillcastcancel = 0; - val3 = 15 - (2 * val2); + val3 = 15 - (3 * val2);//Increased SP Cost. } break; case SC_LG_REFLECTDAMAGE: val2 = 15 + 5 * val1; - val3 = (val1==5)?20:(val1+4)*2; // SP consumption + val3 = 25 + 5 * val1; //Number of Reflects val4 = tick/10000; tick_time = 10000; // [GodLesZ] tick time break; - case SC_FORCEOFVANGUARD: // This is not the official way to handle it but I think we should use it. [pakpil] - val2 = 20 + 12 * (val1 - 1); // Chance - val3 = 5 + (2 * val1); // Max rage counters + case SC_FORCEOFVANGUARD: + val2 = 8 + 12 * val1; // Chance + val3 = 5 + 2 * val1; // Max rage counters tick = -1; //endless duration in the client - tick_time = 6000; // [GodLesZ] tick time - val_flag |= 1|2|4; break; case SC_EXEEDBREAK: - val1 *= 150; // 150 * skill_lv - if( sd && sd->inventory_data[sd->equip_index[EQI_HAND_R]] ) { // Chars. - val1 += (sd->inventory_data[sd->equip_index[EQI_HAND_R]]->weight/10 * sd->inventory_data[sd->equip_index[EQI_HAND_R]]->wlv * status_get_lv(bl) / 100); - val1 += 15 * (sd ? sd->status.job_level:50) + 100; + if( sd ){ + short index = sd->equip_index[EQI_HAND_R]; + val1 = 15 * (sd->status.job_level + val1 * 10); + if( index >= 0 && sd->inventory_data[index] && sd->inventory_data[index]->type == IT_WEAPON ) + val1 += (sd->inventory_data[index]->weight / 10 * sd->inventory_data[index]->wlv) * status->get_lv(bl) / 100; } - else // Mobs - val1 += (400 * status_get_lv(bl) / 100) + (15 * (status_get_lv(bl) / 2)); // About 1138% at mob_lvl 99. Is an aproximation to a standard weapon. [pakpil] break; - case SC_PRESTIGE: // Bassed on suggested formula in iRO Wiki and some test, still need more test. [pakpil] - val2 = ((status->int_ + status->luk) / 6) + 5; // Chance to evade magic damage. + case SC_PRESTIGE: + val2 = (st->int_ + st->luk) * val1 / 20;// Chance to evade magic damage. + val2 = val2 * status->get_lv(bl) / 200; + val2 += val1; val1 *= 15; // Defence added if( sd ) val1 += 10 * pc->checkskill(sd,CR_DEFENDER); - val_flag |= 1|2; + val1 *= status->get_lv(bl) / 100; break; case SC_BANDING: tick_time = 5000; // [GodLesZ] tick time - val_flag |= 1; - break; - case SC_SHIELDSPELL_DEF: - case SC_SHIELDSPELL_MDEF: - case SC_SHIELDSPELL_REF: - val_flag |= 1|2; break; case SC_MAGNETICFIELD: val3 = tick / 1000; tick_time = 1000; // [GodLesZ] tick time break; case SC_INSPIRATION: - if( sd ) - { - val2 = (40 * val1) + (3 * sd->status.job_level); // ATK bonus - val3 = (sd->status.job_level / 10) * 2 + 12; // All stat bonus + if( sd ) { + val2 = 40 * val1 + 3 * sd->status.job_level;// ATK bonus + val3 = sd->status.base_level / 10 + sd->status.job_level / 5;// All stat bonus } - val4 = tick / 1000; - tick_time = 1000; // [GodLesZ] tick time - status_change_clear_buffs(bl,3); //Remove buffs/debuffs - break; - case SC_SPELLFIST: - case SC_CURSEDCIRCLE_ATKER: - val_flag |= 1|2|4; + val4 = tick / 5000; + tick_time = 5000; // [GodLesZ] tick time + status->change_clear_buffs(bl,3); //Remove buffs/debuffs break; case SC_CRESCENTELBOW: - val2 = 94 + val1; - val_flag |= 1|2; + val2 = (sd ? sd->status.job_level : 2) / 2 + 50 + 5 * val1; break; case SC_LIGHTNINGWALK: // [(Job Level / 2) + (40 + 5 * Skill Level)] % val1 = (sd?sd->status.job_level:2)/2 + 40 + 5 * val1; - val_flag |= 1; break; case SC_RAISINGDRAGON: val3 = tick / 5000; tick_time = 5000; // [GodLesZ] tick time break; case SC_GENTLETOUCH_CHANGE: - {// take note there is no def increase as skill desc says. [malufett] - struct block_list * src; - val3 = status->agi * val1 / 60; // ASPD increase: [(Target AGI x Skill Level) / 60] % - if( (src = iMap->id2bl(val2)) ){ - val4 = ( 200/status_get_int(src) ) * val1;// MDEF decrease: MDEF [(200 / Caster INT) x Skill Level] - val2 = ( status_get_dex(src)/4 + status_get_str(src)/2 ) * val1 / 5; // ATK increase: ATK [{(Caster DEX / 4) + (Caster STR / 2)} x Skill Level / 5] - } + {// take note there is no def increase as skill desc says. [malufett] + struct block_list * src2; + val3 = st->agi * val1 / 60; // ASPD increase: [(Target AGI x Skill Level) / 60] % + if( (src2 = map->id2bl(val2)) ){ + val4 = ( 200/status_get_int(src2) ) * val1;// MDEF decrease: MDEF [(200 / Caster INT) x Skill Level] + val2 = ( status_get_dex(src2)/4 + status_get_str(src2)/2 ) * val1 / 5; // ATK increase: ATK [{(Caster DEX / 4) + (Caster STR / 2)} x Skill Level / 5] } + } break; case SC_GENTLETOUCH_REVITALIZE: - {// take note there is no vit,aspd,speed increase as skill desc says. [malufett] - struct block_list * src; - val3 = val1 * 30 + 150; // Natural HP recovery increase: [(Skill Level x 30) + 50] % - if( (src = iMap->id2bl(val2)) ) // the stat def is not shown in the status window and it is process differently - val4 = ( status_get_vit(src)/4 ) * val1; // STAT DEF increase: [(Caster VIT / 4) x Skill Level] - } + {// take note there is no vit,aspd,speed increase as skill desc says. [malufett] + struct block_list * src2; + val3 = val1 * 30 + 150; // Natural HP recovery increase: [(Skill Level x 30) + 50] % + if( (src2 = map->id2bl(val2)) ) // the stat def is not shown in the status window and it is process differently + val4 = ( status_get_vit(src2)/4 ) * val1; // STAT DEF increase: [(Caster VIT / 4) x Skill Level] + } break; case SC_PYROTECHNIC_OPTION: - val_flag |= 1|2|4; + val2 = 60; break; case SC_HEATER_OPTION: val2 = 120; // Watk. TODO: Renewal (Atk2) - val3 = 33; // % Increase effects. + val3 = (sd ? sd->status.job_level : 0); // % Increase damage. val4 = 3; // Change into fire element. - val_flag |= 1|2|4; break; case SC_TROPIC_OPTION: val2 = 180; // Watk. TODO: Renewal (Atk2) @@ -8526,77 +8812,85 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val break; case SC_AQUAPLAY_OPTION: val2 = 40; - val_flag |= 1|2|4; break; case SC_COOLER_OPTION: - val2 = 80; // % Freezing chance - val3 = 33; // % increased damage + val2 = 80; // Bonus Matk + val3 = (sd ? sd->status.job_level : 0); // % Freezing chance val4 = 1; // Change into water elemet - val_flag |= 1|2|4; break; case SC_CHILLY_AIR_OPTION: val2 = 120; // Matk. TODO: Renewal (Matk1) val3 = MG_COLDBOLT; - val_flag |= 1|2; - break; - case SC_GUST_OPTION: - val_flag |= 1|2; break; case SC_WIND_STEP_OPTION: val2 = 50; // % Increase speed and flee. break; case SC_BLAST_OPTION: - val2 = 20; + val2 = (sd ? sd->status.job_level : 0); // % Increase damage val3 = ELE_WIND; - val_flag |= 1|2|4; break; case SC_WILD_STORM_OPTION: val2 = MG_LIGHTNINGBOLT; - val_flag |= 1|2; break; case SC_PETROLOGY_OPTION: val2 = 5; val3 = 50; - val_flag |= 1|2|4; + break; + case SC_SOLID_SKIN_OPTION: + val2 = 33; // % Increase DEF break; case SC_CURSED_SOIL_OPTION: val2 = 10; - val3 = 33; + val3 = (sd ? sd->status.job_level : 0); // % Increase Damage val4 = 2; - val_flag |= 1|2|4; break; case SC_UPHEAVAL_OPTION: val2 = WZ_EARTHSPIKE; - val_flag |= 1|2; + val3 = 15; // Bonus MaxHP break; case SC_CIRCLE_OF_FIRE_OPTION: val2 = 300; - val_flag |= 1|2; break; case SC_FIRE_CLOAK_OPTION: case SC_WATER_DROP_OPTION: case SC_WIND_CURTAIN_OPTION: case SC_STONE_SHIELD_OPTION: - val2 = 20; // Elemental modifier. Not confirmed. - break; + val2 = 100; // Elemental modifier. + break; + case SC_TROPIC: + case SC_CHILLY_AIR: + case SC_WILD_STORM: + case SC_UPHEAVAL: + val2 += 10; + case SC_HEATER: + case SC_COOLER: + case SC_BLAST: + case SC_CURSED_SOIL: + val2 += 10; + case SC_PYROTECHNIC: + case SC_AQUAPLAY: + case SC_GUST: + case SC_PETROLOGY: + val2 += 5; + val3 += 9000; case SC_CIRCLE_OF_FIRE: + case SC_WATER_SCREEN: + case SC_WIND_STEP: + case SC_SOLID_SKIN: case SC_FIRE_CLOAK: case SC_WATER_DROP: - case SC_WATER_SCREEN: case SC_WIND_CURTAIN: - case SC_WIND_STEP: case SC_STONE_SHIELD: - case SC_SOLID_SKIN: - val2 = 10; - tick_time = 2000; // [GodLesZ] tick time + val2 += 5; + val3 += 1000; + val4 = tick; + tick_time = val3; break; case SC_WATER_BARRIER: - val2 = 40; // Increasement. Mdef1 ??? - val3 = 20; // Reductions. Atk2, Flee1, Matk1 ???? - val_flag |= 1|2|4; + val3 = 20; // Reductions. Atk2, Flee1 break; case SC_ZEPHYR: - val2 = 22; // Flee. + val2 = 25; // Flee. break; case SC_TIDAL_WEAPON: val2 = 20; // Increase Elemental's attack. @@ -8626,25 +8920,35 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val tick_time = 1000; break; case SC_ZANGETSU: - val2 = status_get_lv(bl) / 3 + 20 * val1; - val3 = status_get_lv(bl) / 2 + 30 * val1; + val2 = val4 = status->get_lv(bl) / 3 + 20 * val1; + val3 = status->get_lv(bl) / 2 + 30 * val1; val2 = (!(status_get_hp(bl)%2) ? val2 : -val3); - val3 = (!(status_get_sp(bl)%2) ? val2 : -val3); + val3 = (!(status_get_sp(bl)%2) ? val4 : -val3); break; case SC_GENSOU: - { - int hp = status_get_hp(bl), sp = status_get_sp(bl), lv = 5; - #define PER( a ) { if( a <= 15 )lv = 1;else if( a <= 30 )lv = 2;else if( a <= 50 )lv = 3;else if( a <= 75 )lv = 4;} - if( rand()%100 > (25 + 10 * val1) - status_get_int(bl) / 2) - return 0; +#define PER( a, lvl ) do { \ + int temp__ = (a); \ + if( temp__ <= 15 ) (lvl) = 1; \ + else if( temp__ <= 30 ) (lvl) = 2; \ + else if( temp__ <= 50 ) (lvl) = 3; \ + else if( temp__ <= 75 ) (lvl) = 4; \ + else (lvl) = 5; \ +} while(0) - PER( 100 / (status_get_max_hp(bl) / hp) ); - status_heal(bl, (!(hp%2) ? (6-lv) *4 / 100 : -(lv*4) / 100), 0, 1); + { + int hp = status_get_hp(bl), sp = status_get_sp(bl), lv = 5; - PER( 100 / (status_get_max_sp(bl) / sp) ); - status_heal(bl, 0,(!(sp%2) ? (6-lv) *3 / 100 : -(lv*3) / 100), 1); - } + if( rand()%100 > (25 + 10 * val1) - status_get_int(bl) / 2) + return 0; + + PER( 100 / (status_get_max_hp(bl) / hp), lv ); + status->heal(bl, (!(hp%2) ? (6-lv) *4 / 100 : -(lv*4) / 100), 0, 1); + + PER( 100 / (status_get_max_sp(bl) / sp), lv ); + status->heal(bl, 0,(!(sp%2) ? (6-lv) *3 / 100 : -(lv*3) / 100), 1); + } +#undef PER break; case SC_ANGRIFFS_MODUS: val2 = 50 + 20 * val1; //atk bonus @@ -8683,7 +8987,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val val2 = 2*val1; //aspd reduction % val3 = 2*val1; //dmg reduction % if(sc->data[SC_NEEDLE_OF_PARALYZE]) - sc_start(bl, SC_ENDURE, 100, val1, tick); //start endure for same duration + sc_start(src, bl, SC_ENDURE, 100, val1, tick); //start endure for same duration break; case SC_STYLE_CHANGE: //[Lighta] need real info tick = -1; @@ -8710,21 +9014,33 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val break; case SC_FRIGG_SONG: val2 = 5 * val1; - val3 = 1000 + 100 * val1; - tick_time = 10000; + val3 = (20 * val1) + 80; + tick_time = 1000; val4 = tick / tick_time; break; + case SC_DARKCROW: + val2 = 30 * val1; + break; case SC_MONSTER_TRANSFORM: - if( !mobdb_checkid(val1) ) + if( !mob->db_checkid(val1) ) val1 = 1002; // default poring - val_flag |= 1; break; - default: - if( calc_flag == SCB_NONE && StatusSkillChangeTable[type] == 0 && StatusIconChangeTable[type] == 0 ) - { //Status change with no calc, no icon, and no skill associated...? - ShowError("UnknownStatusChange [%d]\n", type); - return 0; - } + case SC_ALL_RIDING: + tick = -1; + break; + case SC_FLASHCOMBO: + /** + * val1 = <IN>skill_id + * val2 = <OUT>attack addition + **/ + val2 = 20+(20*val1); + break; + default: + if( calc_flag == SCB_NONE && status->SkillChangeTable[type] == 0 && status->IconChangeTable[type] == 0 ) + { //Status change with no calc, no icon, and no skill associated...? + ShowError("UnknownStatusChange [%d]\n", type); + return 0; + } } } else { //Special considerations when loading SC data. switch( type ) { @@ -8732,6 +9048,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val case SC_XMAS: case SC_SUMMER: case SC_HANBOK: + case SC_OKTOBERFEST: if( !vd ) break; clif->changelook(bl,LOOK_BASE,vd->class_); clif->changelook(bl,LOOK_WEAPON,0); @@ -8741,22 +9058,139 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val case SC_KAAHI: val4 = INVALID_TIMER; break; - case SC_SUMMON1: - case SC_SUMMON2: - case SC_SUMMON3: - case SC_SUMMON4: - case SC_SUMMON5: - case SC_MONSTER_TRANSFORM: - val_flag |= 1; - break; case SC_KYOUGAKU: clif->status_change(bl, SI_ACTIVE_MONSTER_TRANSFORM, 1, 0, 1002, 0, 0); // Poring in disguise break; } } + + /* values that must be set regardless of flag&4 e.g. val_flag */ + switch(type) { + case SC_FIGHTINGSPIRIT: + val_flag |= 1|2; + break; + case SC_VENOMIMPRESS: + val_flag |= 1|2; + break; + case SC_POISONINGWEAPON: + val_flag |= 1|2|4; + break; + case SC_WEAPONBLOCKING: + val_flag |= 1|2; + break; + case SC_ROLLINGCUTTER: + val_flag |= 1; + break; + case SC_CLOAKINGEXCEED: + val_flag |= 1|2|4; + break; + case SC_HALLUCINATIONWALK: + val_flag |= 1|2|4; + break; + case SC_SUMMON1: + case SC_SUMMON2: + case SC_SUMMON3: + case SC_SUMMON4: + case SC_SUMMON5: + val_flag |= 1; + break; + case SC__SHADOWFORM: + val_flag |= 1|2|4; + break; + case SC__INVISIBILITY: + val_flag |= 1|2; + break; + case SC__ENERVATION: + val_flag |= 1|2; + break; + case SC__GROOMY: + val_flag |= 1|2|4; + break; + case SC__LAZINESS: + val_flag |= 1|2|4; + break; + case SC__UNLUCKY: + val_flag |= 1|2|4; + break; + case SC__WEAKNESS: + val_flag |= 1|2; + break; + case SC_PROPERTYWALK: + val_flag |= 1|2; + break; + case SC_FORCEOFVANGUARD: + val_flag |= 1|2|4; + break; + case SC_PRESTIGE: + val_flag |= 1|2; + break; + case SC_BANDING: + val_flag |= 1; + break; + case SC_SHIELDSPELL_DEF: + case SC_SHIELDSPELL_MDEF: + case SC_SHIELDSPELL_REF: + val_flag |= 1|2; + break; + case SC_SPELLFIST: + case SC_CURSEDCIRCLE_ATKER: + val_flag |= 1|2|4; + break; + case SC_CRESCENTELBOW: + val_flag |= 1|2; + break; + case SC_LIGHTNINGWALK: + val_flag |= 1; + break; + case SC_PYROTECHNIC_OPTION: + val_flag |= 1|2|4; + break; + case SC_HEATER_OPTION: + val_flag |= 1|2|4; + break; + case SC_AQUAPLAY_OPTION: + val_flag |= 1|2|4; + break; + case SC_COOLER_OPTION: + val_flag |= 1|2|4; + break; + case SC_CHILLY_AIR_OPTION: + val_flag |= 1|2; + break; + case SC_GUST_OPTION: + val_flag |= 1|2; + break; + case SC_BLAST_OPTION: + val_flag |= 1|2|4; + break; + case SC_WILD_STORM_OPTION: + val_flag |= 1|2; + break; + case SC_PETROLOGY_OPTION: + val_flag |= 1|2|4; + break; + case SC_CURSED_SOIL_OPTION: + val_flag |= 1|2|4; + break; + case SC_UPHEAVAL_OPTION: + val_flag |= 1|2; + break; + case SC_CIRCLE_OF_FIRE_OPTION: + val_flag |= 1|2; + break; + case SC_WATER_BARRIER: + val_flag |= 1|2|4; + break; + case SC_CASH_PLUSEXP: + case SC_CASH_PLUSONLYJOBEXP: + case SC_MONSTER_TRANSFORM: + case SC_CASH_RECEIVEITEM: + val_flag |= 1; + break; + } /* [Ind/Hercules] */ - if( sd && StatusDisplayType[type] ) { + if( sd && status->DisplayType[type] ) { int dval1 = 0, dval2 = 0, dval3 = 0; switch( type ) { case SC_ALL_RIDING: @@ -8766,11 +9200,15 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val dval1 = val1; break; } - status_display_add(sd,type,dval1,dval2,dval3); + status->display_add(sd,type,dval1,dval2,dval3); } //Those that make you stop attacking/walking.... switch (type) { + case SC_VACUUM_EXTREME: + if(!map_flag_gvg(bl->m)) + unit->stop_walking(bl,1); + break; case SC_FREEZE: case SC_STUN: case SC_SLEEP: @@ -8782,9 +9220,10 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val status_change_end(bl, SC_DANCING, INVALID_TIMER); // Cancel cast when get status [LuzZza] if (battle_config.sc_castcancel&bl->type) - unit_skillcastcancel(bl, 0); + unit->skillcastcancel(bl, 0); + case SC_FALLENEMPIRE: case SC_WHITEIMPRISON: - unit_stop_attack(bl); + unit->stop_attack(bl); case SC_STOP: case SC_CONFUSION: case SC_RG_CCONFINE_M: @@ -8794,20 +9233,20 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val case SC_WUGBITE: case SC_THORNS_TRAP: case SC__MANHOLE: - case SC_CRYSTALIZE: + case SC__CHAOS: + case SC_COLD: case SC_CURSEDCIRCLE_ATKER: case SC_CURSEDCIRCLE_TARGET: case SC_FEAR: - case SC_NETHERWORLD: case SC_MEIKYOUSISUI: case SC_KYOUGAKU: case SC_NEEDLE_OF_PARALYZE: case SC_DEATHBOUND: - unit_stop_walking(bl,1); - break; + unit->stop_walking(bl,1); + break; case SC_ANKLESNARE: if( battle_config.skill_trap_type || !map_flag_gvg(bl->m) ) - unit_stop_walking(bl,1); + unit->stop_walking(bl,1); break; case SC_HIDING: case SC_CLOAKING: @@ -8816,12 +9255,38 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val case SC_WEIGHTOVER90: case SC_CAMOUFLAGE: case SC_SIREN: - unit_stop_attack(bl); - break; + case SC_ALL_RIDING: + unit->stop_attack(bl); + break; case SC_SILENCE: if (battle_config.sc_castcancel&bl->type) - unit_skillcastcancel(bl, 0); - break; + unit->skillcastcancel(bl, 0); + break; + /* */ + case SC_ITEMSCRIPT: + if( sd ) { + switch( val1 ) { + case ITEMID_PHREEONI_CARD: + clif->status_change(bl, SI_FOOD_BASICHIT, 1, tick, 0, 0, 0); + break; + case ITEMID_GHOSTRING_CARD: + clif->status_change(bl,SI_ARMOR_PROPERTY,1,tick,0,0,0); + break; + case ITEMID_TAO_GUNKA_CARD: + clif->status_change(bl,SI_MVPCARD_TAOGUNKA,1,tick,0,0,0); + break; + case ITEMID_MISTRESS_CARD: + clif->status_change(bl,SI_MVPCARD_MISTRESS,1,tick,0,0,0); + break; + case ITEMID_ORC_HERO_CARD: + clif->status_change(bl,SI_MVPCARD_ORCHERO,1,tick,0,0,0); + break; + case ITEMID_ORC_LOAD_CARD: + clif->status_change(bl,SI_MVPCARD_ORCLORD,1,tick,0,0,0); + break; + } + } + break; } // Set option as needed. @@ -8831,17 +9296,17 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val case SC_STONE: sc->opt1 = OPT1_STONEWAIT; break; case SC_FREEZE: sc->opt1 = OPT1_FREEZE; break; case SC_STUN: sc->opt1 = OPT1_STUN; break; - case SC_DEEP_SLEEP: opt_flag = 0; case SC_SLEEP: sc->opt1 = OPT1_SLEEP; break; case SC_BURNING: sc->opt1 = OPT1_BURNING; break; // Burning need this to be showed correctly. [pakpil] case SC_WHITEIMPRISON: sc->opt1 = OPT1_IMPRISON; break; - case SC_CRYSTALIZE: sc->opt1 = OPT1_CRYSTALIZE; break; + case SC_COLD: sc->opt1 = OPT1_CRYSTALIZE; break; //OPT2 case SC_POISON: sc->opt2 |= OPT2_POISON; break; case SC_CURSE: sc->opt2 |= OPT2_CURSE; break; case SC_SILENCE: sc->opt2 |= OPT2_SILENCE; break; case SC_CRUCIS: + case SC__CHAOS: sc->opt2 |= OPT2_SIGNUMCRUCIS; break; @@ -8894,7 +9359,6 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val break; case SC_BERSERK: opt_flag = 0; -// case SC__BLOODYLUST: sc->opt3 |= OPT3_BERSERK; break; // case ???: // doesn't seem to do anything @@ -8946,10 +9410,10 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val break; case SC_CLOAKING: case SC_CLOAKINGEXCEED: - case SC__INVISIBILITY: sc->option |= OPTION_CLOAK; opt_flag = 2; break; + case SC__INVISIBILITY: case SC_CHASEWALK: sc->option |= OPTION_CHASEWALK|OPTION_CLOAK; opt_flag = 2; @@ -8982,12 +9446,20 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val case SC_FUSION: sc->option |= OPTION_FLYING; break; + case SC_OKTOBERFEST: + sc->option |= OPTION_OKTOBERFEST; + opt_flag |= 0x4; + break; + case SC__FEINTBOMB_MASTER: + sc->option |= OPTION_INVISIBLE; + opt_flag |= 0x4; + break; default: opt_flag = 0; } //On Aegis, when turning on a status change, first goes the option packet, then the sc packet. - if(opt_flag) { + if(opt_flag) { clif->changeoption(bl); if( sd && opt_flag&0x4 ) { clif->changelook(bl,LOOK_BASE,vd->class_); @@ -9004,59 +9476,61 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val calc_flag&=~SCB_DYE; } - if( !(flag&4 && StatusDisplayType[type]) ) - clif->status_change(bl,StatusIconChangeTable[type],1,tick,(val_flag&1)?val1:1,(val_flag&2)?val2:0,(val_flag&4)?val3:0); + if( !(flag&4 && status->DisplayType[type]) ) + clif->status_change(bl,status->IconChangeTable[type],1,tick,(val_flag&1)?val1:1,(val_flag&2)?val2:0,(val_flag&4)?val3:0); /** - * used as temporary storage for scs with interval ticks, so that the actual duration is sent to the client first. - **/ + * used as temporary storage for scs with interval ticks, so that the actual duration is sent to the client first. + **/ if( tick_time ) tick = tick_time; //Don't trust the previous sce assignment, in case the SC ended somewhere between there and here. if((sce=sc->data[type])) {// reuse old sc if( sce->timer != INVALID_TIMER ) - iTimer->delete_timer(sce->timer, status_change_timer); + timer->delete(sce->timer, status->change_timer); } else {// new sc ++(sc->count); - sce = sc->data[type] = ers_alloc(sc_data_ers, struct status_change_entry); + sce = sc->data[type] = ers_alloc(status->data_ers, struct status_change_entry); } sce->val1 = val1; sce->val2 = val2; sce->val3 = val3; sce->val4 = val4; if (tick >= 0) - sce->timer = iTimer->add_timer(iTimer->gettick() + tick, status_change_timer, bl->id, type); - else + sce->timer = timer->add(timer->gettick() + tick, status->change_timer, bl->id, type); + else { sce->timer = INVALID_TIMER; //Infinite duration + if( sd ) + chrif->save_scdata_single(sd->status.account_id,sd->status.char_id,type,sce); + } if (calc_flag) status_calc_bl(bl,calc_flag); if(sd && sd->pd) - pet_sc_check(sd, type); //Skotlex: Pet Status Effect Healing + pet->sc_check(sd, type); //Skotlex: Pet Status Effect Healing - switch (type) { - case SC__BLOODYLUST: + switch (type) { case SC_BERSERK: if (!(sce->val2)) { //don't heal if already set - status_heal(bl, status->max_hp, 0, 1); //Do not use percent_heal as this healing must override BERSERK's block. - status_set_sp(bl, 0, 0); //Damage all SP + status->heal(bl, st->max_hp, 0, 1); //Do not use percent_heal as this healing must override BERSERK's block. + status->set_sp(bl, 0, 0); //Damage all SP } - sce->val2 = 5 * status->max_hp / 100; + sce->val2 = 5 * st->max_hp / 100; break; case SC_HLIF_CHANGE: status_percent_heal(bl, 100, 100); break; case SC_RUN: { - struct unit_data *ud = unit_bl2ud(bl); + struct unit_data *ud = unit->bl2ud(bl); if( ud ) - ud->state.running = unit_run(bl); + ud->state.running = unit->run(bl, NULL, SC_RUN); } break; case SC_CASH_BOSS_ALARM: - clif->bossmapinfo(sd->fd, iMap->id2boss(sce->val1), 0); // First Message + clif->bossmapinfo(sd->fd, map->id2boss(sce->val1), 0); // First Message break; case SC_MER_HP: status_percent_heal(bl, 100, 0); // Recover Full HP @@ -9064,87 +9538,86 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val case SC_MER_SP: status_percent_heal(bl, 0, 100); // Recover Full SP break; - /** - * Ranger - **/ + /** + * Ranger + **/ case SC_WUGDASH: { - struct unit_data *ud = unit_bl2ud(bl); + struct unit_data *ud = unit->bl2ud(bl); if( ud ) - ud->state.running = unit_wugdash(bl, sd); + ud->state.running = unit->run(bl, sd, SC_WUGDASH); } break; case SC_COMBOATTACK: switch (sce->val1) { - case TK_STORMKICK: - clif->skill_nodamage(bl,bl,TK_READYSTORM,1,1); - break; - case TK_DOWNKICK: - clif->skill_nodamage(bl,bl,TK_READYDOWN,1,1); - break; - case TK_TURNKICK: - clif->skill_nodamage(bl,bl,TK_READYTURN,1,1); - break; - case TK_COUNTER: - clif->skill_nodamage(bl,bl,TK_READYCOUNTER,1,1); - break; - case MO_COMBOFINISH: - case CH_TIGERFIST: - case CH_CHAINCRUSH: - if (sd) - clif->skillinfo(sd,MO_EXTREMITYFIST, INF_SELF_SKILL); - break; - case TK_JUMPKICK: - if (sd) - clif->skillinfo(sd,TK_JUMPKICK, INF_SELF_SKILL); - break; - case MO_TRIPLEATTACK: - if (sd && pc->checkskill(sd, SR_DRAGONCOMBO) > 0) - clif->skillinfo(sd,SR_DRAGONCOMBO, INF_SELF_SKILL); - break; - case SR_FALLENEMPIRE: - if (sd){ - clif->skillinfo(sd,SR_GATEOFHELL, INF_SELF_SKILL); - clif->skillinfo(sd,SR_TIGERCANNON, INF_SELF_SKILL); - } - break; + case TK_STORMKICK: + clif->skill_nodamage(bl,bl,TK_READYSTORM,1,1); + break; + case TK_DOWNKICK: + clif->skill_nodamage(bl,bl,TK_READYDOWN,1,1); + break; + case TK_TURNKICK: + clif->skill_nodamage(bl,bl,TK_READYTURN,1,1); + break; + case TK_COUNTER: + clif->skill_nodamage(bl,bl,TK_READYCOUNTER,1,1); + break; + case MO_COMBOFINISH: + case CH_TIGERFIST: + case CH_CHAINCRUSH: + if (sd) + clif->skillinfo(sd,MO_EXTREMITYFIST, INF_SELF_SKILL); + break; + case TK_JUMPKICK: + if (sd) + clif->skillinfo(sd,TK_JUMPKICK, INF_SELF_SKILL); + break; + case MO_TRIPLEATTACK: + if (sd && pc->checkskill(sd, SR_DRAGONCOMBO) > 0) + clif->skillinfo(sd,SR_DRAGONCOMBO, INF_SELF_SKILL); + break; + case SR_FALLENEMPIRE: + if (sd){ + clif->skillinfo(sd,SR_GATEOFHELL, INF_SELF_SKILL); + clif->skillinfo(sd,SR_TIGERCANNON, INF_SELF_SKILL); + } + break; } break; - case SC_RAISINGDRAGON: - sce->val2 = status->max_hp / 100;// Officially tested its 1%hp drain. [Jobbie] + case SC_RAISINGDRAGON: + sce->val2 = st->max_hp / 100;// Officially tested its 1%hp drain. [Jobbie] break; } if( opt_flag&2 && sd && sd->touching_id ) - npc_touchnext_areanpc(sd,false); // run OnTouch_ on next char in range + npc->touchnext_areanpc(sd,false); // run OnTouch_ on next char in range return 1; } - /*========================================== - * Ending all status except those listed. - * @TODO maybe usefull for dispel instead reseting a liste there. - * type: - * 0 - PC killed -> Place here statuses that do not dispel on death. - * 1 - If for some reason status_change_end decides to still keep the status when quitting. - * 2 - Do clif - * 3 - Do not remove some permanent/time-independent effects - *------------------------------------------*/ +* Ending all status except those listed. +* @TODO maybe usefull for dispel instead reseting a liste there. +* type: +* 0 - PC killed -> Place here statuses that do not dispel on death. +* 1 - If for some reason status_change_end decides to still keep the status when quitting. +* 2 - Do clif +* 3 - Do not remove some permanent/time-independent effects +*------------------------------------------*/ int status_change_clear(struct block_list* bl, int type) { struct status_change* sc; int i; - sc = status_get_sc(bl); + sc = status->get_sc(bl); if (!sc || !sc->count) return 0; for(i = 0; i < SC_MAX; i++) { if(!sc->data[i]) - continue; - + continue; + if(type == 0){ - if( status_get_sc_type(i)&SC_NO_REM_DEATH ){ + if( status->get_sc_type(i)&SC_NO_REM_DEATH ) { switch (i) { case SC_ARMOR_PROPERTY://Only when its Holy or Dark that it doesn't dispell on death if( sc->data[i]->val2 != ELE_HOLY && sc->data[i]->val2 != ELE_DARK ) @@ -9154,17 +9627,8 @@ int status_change_clear(struct block_list* bl, int type) { } } } - if( type == 3 ) { - switch (i) {// TODO: This list may be incomplete - case SC_WEIGHTOVER50: - case SC_WEIGHTOVER90: - case SC_NOCHAT: - case SC_PUSH_CART: - case SC_JAILED: - case SC_ALL_RIDING: - continue; - } - } + if( type == 3 && status->get_sc_type(i)&SC_NO_CLEAR ) + continue; status_change_end(bl, (sc_type)i, INVALID_TIMER); @@ -9172,8 +9636,8 @@ int status_change_clear(struct block_list* bl, int type) { //If for some reason status_change_end decides to still keep the status when quitting. [Skotlex] (sc->count)--; if (sc->data[i]->timer != INVALID_TIMER) - iTimer->delete_timer(sc->data[i]->timer, status_change_timer); - ers_free(sc_data_ers, sc->data[i]); + timer->delete(sc->data[i]->timer, status->change_timer); + ers_free(status->data_ers, sc->data[i]); sc->data[i] = NULL; } } @@ -9182,6 +9646,7 @@ int status_change_clear(struct block_list* bl, int type) { sc->opt2 = 0; sc->opt3 = 0; sc->bs_counter = 0; + sc->fv_counter = 0; #ifndef RENEWAL sc->sg_counter = 0; #endif @@ -9193,20 +9658,23 @@ int status_change_clear(struct block_list* bl, int type) { } /*========================================== - * Special condition we want to effectuate, check before ending a status. - *------------------------------------------*/ +* Special condition we want to effectuate, check before ending a status. +*------------------------------------------*/ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const char* file, int line) { struct map_session_data *sd; struct status_change *sc; struct status_change_entry *sce; - struct status_data *status; + struct status_data *st; struct view_data *vd; int opt_flag=0, calc_flag; - +#ifdef ANTI_MAYAP_CHEAT + bool invisible = false; +#endif + nullpo_ret(bl); - sc = status_get_sc(bl); - status = status_get_status_data(bl); + sc = status->get_sc(bl); + st = status->get_status_data(bl); if(type < 0 || type >= SC_MAX || !sc || !(sce = sc->data[type])) return 0; @@ -9216,30 +9684,33 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const if (sce->timer != tid && tid != INVALID_TIMER) return 0; + if( sd && sce->timer == INVALID_TIMER && !sd->state.loggingout ) + chrif->del_scdata_single(sd->status.account_id,sd->status.char_id,type); + if (tid == INVALID_TIMER) { if (type == SC_ENDURE && sce->val4) //Do not end infinite endure. - return 0; + return 0; if (sce->timer != INVALID_TIMER) //Could be a SC with infinite duration - iTimer->delete_timer(sce->timer,status_change_timer); + timer->delete(sce->timer,status->change_timer); if (sc->opt1) - switch (type) { - //"Ugly workaround" [Skotlex] - //delays status change ending so that a skill that sets opt1 fails to - //trigger when it also removed one - case SC_STONE: - sce->val3 = 0; //Petrify time counter. - case SC_FREEZE: - case SC_STUN: - case SC_SLEEP: - if (sce->val1) { - //Removing the 'level' shouldn't affect anything in the code - //since these SC are not affected by it, and it lets us know - //if we have already delayed this attack or not. - sce->val1 = 0; - sce->timer = iTimer->add_timer(iTimer->gettick()+10, status_change_timer, bl->id, type); - return 1; - } + switch (type) { + //"Ugly workaround" [Skotlex] + //delays status change ending so that a skill that sets opt1 fails to + //trigger when it also removed one + case SC_STONE: + sce->val3 = 0; //Petrify time counter. + case SC_FREEZE: + case SC_STUN: + case SC_SLEEP: + if (sce->val1) { + //Removing the 'level' shouldn't affect anything in the code + //since these SC are not affected by it, and it lets us know + //if we have already delayed this attack or not. + sce->val1 = 0; + sce->timer = timer->add(timer->gettick()+10, status->change_timer, bl->id, type); + return 1; + } } } @@ -9247,42 +9718,52 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const sc->data[type] = NULL; - if( sd && StatusDisplayType[type] ) { - status_display_remove(sd,type); + if( sd && status->DisplayType[type] ) { + status->display_remove(sd,type); } - - vd = status_get_viewdata(bl); - calc_flag = StatusChangeFlagTable[type]; - switch(type){ - case SC_GRANITIC_ARMOR:{ - int dammage = status->max_hp*sce->val3/100; - if(status->hp < dammage) //to not kill him - dammage = status->hp-1; - status_damage(NULL, bl, dammage,0,0,1); - break; - } - case SC_PYROCLASTIC: - if(bl->type == BL_PC) - skill->break_equip(bl,EQP_WEAPON,10000,BCT_SELF); - break; - case SC_RUN: + +#ifdef ANTI_MAYAP_CHEAT + if (sc->option&(OPTION_HIDE|OPTION_CLOAK|OPTION_INVISIBLE)) + invisible = true; +#endif + + vd = status->get_viewdata(bl); + calc_flag = status->ChangeFlagTable[type]; + switch(type) { + case SC_GRANITIC_ARMOR: { - struct unit_data *ud = unit_bl2ud(bl); - bool begin_spurt = true; - if (ud) { - if(!ud->state.running) - begin_spurt = false; - ud->state.running = 0; - if (ud->walktimer != INVALID_TIMER) - unit_stop_walking(bl,1); - } - if (begin_spurt && sce->val1 >= 7 && - DIFF_TICK(iTimer->gettick(), sce->val4) <= 1000 && - (!sd || (sd->weapontype1 == 0 && sd->weapontype2 == 0)) - ) - sc_start(bl,SC_STRUP,100,sce->val1,skill->get_time2(status_sc2skill(type), sce->val1)); + int damage = st->max_hp*sce->val3/100; + if(st->hp < damage) //to not kill him + damage = st->hp-1; + status->damage(NULL, bl, damage,0,0,1); } - break; + break; + case SC_PYROCLASTIC: + if(bl->type == BL_PC) + skill->break_equip(bl,EQP_WEAPON,10000,BCT_SELF); + break; + case SC_RUN: + { + struct unit_data *ud = unit->bl2ud(bl); + bool begin_spurt = true; + // Note: this int64 value is stored in two separate int32 variables (FIXME) + int64 starttick = (int64)sce->val3&0x00000000ffffffffLL; + starttick |= ((int64)sce->val4<<32)&0xffffffff00000000LL; + + if (ud) { + if(!ud->state.running) + begin_spurt = false; + ud->state.running = 0; + if (ud->walktimer != INVALID_TIMER) + unit->stop_walking(bl,1); + } + if (begin_spurt && sce->val1 >= 7 + && DIFF_TICK(timer->gettick(), starttick) <= 1000 + && (!sd || (sd->weapontype1 == 0 && sd->weapontype2 == 0)) + ) + sc_start(bl, bl,SC_STRUP,100,sce->val1,skill->get_time2(status->sc2skill(type), sce->val1)); + } + break; case SC_AUTOBERSERK: if (sc->data[SC_PROVOKE] && sc->data[SC_PROVOKE]->val2 == 1) status_change_end(bl, SC_PROVOKE, INVALID_TIMER); @@ -9294,17 +9775,15 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const case SC_AUTOGUARD: { struct map_session_data *tsd; - if( bl->type == BL_PC ) - { // Clear Status from others + if( bl->type == BL_PC ) { + // Clear Status from others int i; - for( i = 0; i < 5; i++ ) - { - if( sd->devotion[i] && (tsd = iMap->id2sd(sd->devotion[i])) && tsd->sc.data[type] ) + for( i = 0; i < 5; i++ ) { + if( sd->devotion[i] && (tsd = map->id2sd(sd->devotion[i])) && tsd->sc.data[type] ) status_change_end(&tsd->bl, type, INVALID_TIMER); } - } - else if( bl->type == BL_MER && ((TBL_MER*)bl)->devotion_flag ) - { // Clear Status from Master + } else if( bl->type == BL_MER && ((TBL_MER*)bl)->devotion_flag ) { + // Clear Status from Master tsd = ((TBL_MER*)bl)->master; if( tsd && tsd->sc.data[type] ) status_change_end(&tsd->bl, type, INVALID_TIMER); @@ -9313,9 +9792,8 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const break; case SC_DEVOTION: { - struct block_list *d_bl = iMap->id2bl(sce->val1); - if( d_bl ) - { + struct block_list *d_bl = map->id2bl(sce->val1); + if( d_bl ) { if( d_bl->type == BL_PC ) ((TBL_PC*)d_bl)->devotion[sce->val2] = 0; else if( d_bl->type == BL_MER ) @@ -9331,18 +9809,16 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const break; case SC_BLADESTOP: - if(sce->val4) - { - int tid = sce->val4; - struct block_list *tbl = iMap->id2bl(tid); - struct status_change *tsc = status_get_sc(tbl); + if(sce->val4) { + int target_id = sce->val4; + struct block_list *tbl = map->id2bl(target_id); + struct status_change *tsc = status->get_sc(tbl); sce->val4 = 0; - if(tbl && tsc && tsc->data[SC_BLADESTOP]) - { + if(tbl && tsc && tsc->data[SC_BLADESTOP]) { tsc->data[SC_BLADESTOP]->val4 = 0; status_change_end(tbl, SC_BLADESTOP, INVALID_TIMER); } - clif->bladestop(bl, tid, 0); + clif->bladestop(bl, target_id, 0); } break; case SC_DANCING: @@ -9368,7 +9844,7 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const sd->delunit_prevline = line; } - if(sce->val4 && sce->val4 != BCT_SELF && (dsd=iMap->id2sd(sce->val4))) + if(sce->val4 && sce->val4 != BCT_SELF && (dsd=map->id2sd(sce->val4))) {// end status on partner as well dsc = dsd->sc.data[SC_DANCING]; if(dsc) { @@ -9415,15 +9891,15 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const break; case SC_SPLASHER: { - struct block_list *src=iMap->id2bl(sce->val3); + struct block_list *src=map->id2bl(sce->val3); if(src && tid != INVALID_TIMER) - skill->castend_damage_id(src, bl, sce->val2, sce->val1, iTimer->gettick(), SD_LEVEL ); + skill->castend_damage_id(src, bl, sce->val2, sce->val1, timer->gettick(), SD_LEVEL ); } break; case SC_RG_CCONFINE_S: { - struct block_list *src = sce->val2?iMap->id2bl(sce->val2):NULL; - struct status_change *sc2 = src?status_get_sc(src):NULL; + struct block_list *src = sce->val2 ? map->id2bl(sce->val2) : NULL; + struct status_change *sc2 = src ? status->get_sc(src) : NULL; if (src && sc2 && sc2->data[SC_RG_CCONFINE_M]) { //If status was already ended, do nothing. //Decrease count @@ -9435,15 +9911,15 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const if (sce->val2 > 0) { //Caster has been unlocked... nearby chars need to be unlocked. int range = 1 - +skill->get_range2(bl, status_sc2skill(type), sce->val1) + +skill->get_range2(bl, status->sc2skill(type), sce->val1) +skill->get_range2(bl, TF_BACKSLIDING, 1); //Since most people use this to escape the hold.... - iMap->foreachinarea(status_change_timer_sub, - bl->m, bl->x-range, bl->y-range, bl->x+range,bl->y+range,BL_CHAR,bl,sce,type,iTimer->gettick()); + map->foreachinarea(status->change_timer_sub, + bl->m, bl->x-range, bl->y-range, bl->x+range,bl->y+range,BL_CHAR,bl,sce,type,timer->gettick()); } break; case SC_COMBOATTACK: if( sd ) - switch (sce->val1) { + switch (sce->val1) { case MO_COMBOFINISH: case CH_TIGERFIST: case CH_CHAINCRUSH: @@ -9464,12 +9940,12 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const break; case SC_MARIONETTE_MASTER: - case SC_MARIONETTE: /// Marionette target - if (sce->val1) - { // check for partner and end their marionette status as well + case SC_MARIONETTE: /// Marionette target + if (sce->val1) { + // check for partner and end their marionette status as well enum sc_type type2 = (type == SC_MARIONETTE_MASTER) ? SC_MARIONETTE : SC_MARIONETTE_MASTER; - struct block_list *pbl = iMap->id2bl(sce->val1); - struct status_change* sc2 = pbl?status_get_sc(pbl):NULL; + struct block_list *pbl = map->id2bl(sce->val1); + struct status_change* sc2 = pbl ? status->get_sc(pbl) : NULL; if (sc2 && sc2->data[type2]) { @@ -9480,19 +9956,18 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const break; case SC_BERSERK: - case SC_SATURDAY_NIGHT_FEVER: - //If val2 is removed, no HP penalty (dispelled?) [Skotlex] - if (status->hp > 100 && sce->val2) - status_set_hp(bl, 100, 0); - if(sc->data[SC_ENDURE] && sc->data[SC_ENDURE]->val4 == 2) - { + if(st->hp > 200 && sc && sc->data[SC__BLOODYLUST]) { + status_percent_heal(bl, 100, 0); + status_change_end(bl, SC__BLOODYLUST, INVALID_TIMER); + } else if(st->hp > 100 && sce->val2) //If val2 is removed, no HP penalty (dispelled?) [Skotlex] + status->set_hp(bl, 100, 0); + if(sc->data[SC_ENDURE] && sc->data[SC_ENDURE]->val4 == 2) { sc->data[SC_ENDURE]->val4 = 0; status_change_end(bl, SC_ENDURE, INVALID_TIMER); } - case SC__BLOODYLUST: - sc_start4(bl, SC_GDSKILL_REGENERATION, 100, 10,0,0,(RGN_HP|RGN_SP), skill->get_time(LK_BERSERK, sce->val1)); + sc_start4(bl, bl, SC_GDSKILL_REGENERATION, 100, 10,0,0,(RGN_HP|RGN_SP), skill->get_time(LK_BERSERK, sce->val1)); if( type == SC_SATURDAY_NIGHT_FEVER ) //Sit down force of Saturday Night Fever has the duration of only 3 seconds. - sc_start(bl,SC_SITDOWN_FORCE,100,sce->val1,skill->get_time2(WM_SATURDAY_NIGHT_FEVER,sce->val1)); + sc_start(bl,bl,SC_SITDOWN_FORCE,100,sce->val1,skill->get_time2(WM_SATURDAY_NIGHT_FEVER,sce->val1)); break; case SC_GOSPEL: if (sce->val3) { //Clear the group. @@ -9506,8 +9981,8 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const skill->clear_unitgroup(bl); break; case SC_BASILICA: //Clear the skill area. [Skotlex] - skill->clear_unitgroup(bl); - break; + skill->clear_unitgroup(bl); + break; case SC_TRICKDEAD: if (vd) vd->dead_sit = 0; break; @@ -9523,76 +9998,77 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const case SC_KAAHI: //Delete timer if it exists. if (sce->val4 != INVALID_TIMER) - iTimer->delete_timer(sce->val4,kaahi_heal_timer); + timer->delete(sce->val4,status->kaahi_heal_timer); break; case SC_JAILED: if(tid == INVALID_TIMER) break; - //natural expiration. + //natural expiration. if(sd && sd->mapindex == sce->val2) pc->setpos(sd,(unsigned short)sce->val3,sce->val4&0xFFFF, sce->val4>>16, CLR_TELEPORT); break; //guess hes not in jail :P case SC_HLIF_CHANGE: if (tid == INVALID_TIMER) - break; + break; // "lose almost all their HP and SP" on natural expiration. - status_set_hp(bl, 10, 0); - status_set_sp(bl, 10, 0); + status->set_hp(bl, 10, 0); + status->set_sp(bl, 10, 0); break; case SC_AUTOTRADE: if (tid == INVALID_TIMER) break; // Note: vending/buying is closed by unit_remove_map, no // need to do it here. - iMap->quit(sd); - // Because iMap->quit calls status_change_end with tid -1 + map->quit(sd); + // Because map->quit calls status_change_end with tid -1 // from here it's not neccesary to continue return 1; break; case SC_STOP: - if( sce->val2 ) - { - struct block_list* tbl = iMap->id2bl(sce->val2); + if( sce->val2 ) { + struct block_list *tbl = map->id2bl(sce->val2); + struct status_change *tsc = NULL; sce->val2 = 0; - if( tbl && (sc = status_get_sc(tbl)) && sc->data[SC_STOP] && sc->data[SC_STOP]->val2 == bl->id ) + if( tbl && (tsc = status->get_sc(tbl)) && tsc->data[SC_STOP] && tsc->data[SC_STOP]->val2 == bl->id ) status_change_end(tbl, SC_STOP, INVALID_TIMER); } break; case SC_LKCONCENTRATION: status_change_end(bl, SC_ENDURE, INVALID_TIMER); break; - /** - * 3rd Stuff - **/ + /** + * 3rd Stuff + **/ case SC_MILLENNIUMSHIELD: - clif->millenniumshield(sd,0); + clif->millenniumshield(bl,0); break; case SC_HALLUCINATIONWALK: - sc_start(bl,SC_HALLUCINATIONWALK_POSTDELAY,100,sce->val1,skill->get_time2(GC_HALLUCINATIONWALK,sce->val1)); + sc_start(bl,bl,SC_HALLUCINATIONWALK_POSTDELAY,100,sce->val1,skill->get_time2(GC_HALLUCINATIONWALK,sce->val1)); break; case SC_WHITEIMPRISON: { - struct block_list* src = iMap->id2bl(sce->val2); + struct block_list* src = map->id2bl(sce->val2); if( tid == -1 || !src) break; // Terminated by Damage - status_fix_damage(src,bl,400*sce->val1,clif->damage(bl,bl,iTimer->gettick(),0,0,400*sce->val1,0,0,0)); + status_fix_damage(src,bl,400*sce->val1,clif->damage(bl,bl,0,0,400*sce->val1,0,0,0)); } break; case SC_WUGDASH: { - struct unit_data *ud = unit_bl2ud(bl); + struct unit_data *ud = unit->bl2ud(bl); if (ud) { ud->state.running = 0; if (ud->walktimer != -1) - unit_stop_walking(bl,1); + unit->stop_walking(bl,1); } } break; case SC_ADORAMUS: status_change_end(bl, SC_BLIND, INVALID_TIMER); break; - case SC__SHADOWFORM: { - struct map_session_data *s_sd = iMap->id2sd(sce->val2); + case SC__SHADOWFORM: + { + struct map_session_data *s_sd = map->id2sd(sce->val2); if( !s_sd ) break; s_sd->shadowform_id = 0; @@ -9614,16 +10090,16 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const } break; case SC_BANDING: - if(sce->val4) { - struct skill_unit_group *group = skill->id2group(sce->val4); - sce->val4 = 0; - if( group ) /* might have been cleared before status ended, e.g. land protector */ - skill->del_unitgroup(group,ALC_MARK); - } + if(sce->val4) { + struct skill_unit_group *group = skill->id2group(sce->val4); + sce->val4 = 0; + if( group ) /* might have been cleared before status ended, e.g. land protector */ + skill->del_unitgroup(group,ALC_MARK); + } break; case SC_CURSEDCIRCLE_ATKER: if( sce->val2 ) // used the default area size cause there is a chance the caster could knock back and can't clear the target. - iMap->foreachinrange(status_change_timer_sub, bl, battle_config.area_size,BL_CHAR, bl, sce, SC_CURSEDCIRCLE_TARGET, iTimer->gettick()); + map->foreachinrange(status->change_timer_sub, bl, battle_config.area_size,BL_CHAR, bl, sce, SC_CURSEDCIRCLE_TARGET, timer->gettick()); break; case SC_RAISINGDRAGON: if( sd && sce->val2 && !pc_isdead(sd) ) { @@ -9638,21 +10114,21 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const } break; case SC_CURSEDCIRCLE_TARGET: - { - struct block_list *src = iMap->id2bl(sce->val2); - struct status_change *sc = status_get_sc(src); - if( sc && sc->data[SC_CURSEDCIRCLE_ATKER] && --(sc->data[SC_CURSEDCIRCLE_ATKER]->val2) == 0 ){ - status_change_end(src, SC_CURSEDCIRCLE_ATKER, INVALID_TIMER); - clif->bladestop(bl, sce->val2, 0); - } + { + struct block_list *src = map->id2bl(sce->val2); + struct status_change *ssc = status->get_sc(src); + if( ssc && ssc->data[SC_CURSEDCIRCLE_ATKER] && --(ssc->data[SC_CURSEDCIRCLE_ATKER]->val2) == 0 ){ + status_change_end(src, SC_CURSEDCIRCLE_ATKER, INVALID_TIMER); + clif->bladestop(bl, sce->val2, 0); } + } break; case SC_BLOOD_SUCKER: if( sce->val2 ){ - struct block_list *src = iMap->id2bl(sce->val2); - if(src){ - struct status_change *sc = status_get_sc(src); - sc->bs_counter--; + struct block_list *src = map->id2bl(sce->val2); + if(src) { + struct status_change *ssc = status->get_sc(src); + ssc->bs_counter--; } } break; @@ -9663,20 +10139,61 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const calc_flag = SCB_ALL;/* required for overlapping */ break; case SC_FULL_THROTTLE: - sc_start(bl,SC_REBOUND,100,sce->val1,skill->get_time2(ALL_FULL_THROTTLE,sce->val1)); + sc_start(bl,bl,SC_REBOUND,100,sce->val1,skill->get_time2(ALL_FULL_THROTTLE,sce->val1)); break; - } + case SC_MONSTER_TRANSFORM: + if( sce->val2 ) + status_change_end(bl, (sc_type)sce->val2, INVALID_TIMER); + break; + case SC_ITEMSCRIPT: + if( sd ) { + switch( sce->val1 ) { + case ITEMID_PHREEONI_CARD: + clif->sc_end(&sd->bl, sd->bl.id, SELF, SI_FOOD_BASICHIT); + break; + case ITEMID_GHOSTRING_CARD: + clif->sc_end(&sd->bl, sd->bl.id, SELF, SI_ARMOR_PROPERTY); + break; + case ITEMID_TAO_GUNKA_CARD: + clif->sc_end(&sd->bl, sd->bl.id, SELF, SI_MVPCARD_TAOGUNKA); + break; + case ITEMID_MISTRESS_CARD: + clif->sc_end(&sd->bl, sd->bl.id, SELF, SI_MVPCARD_MISTRESS); + break; + case ITEMID_ORC_HERO_CARD: + clif->sc_end(&sd->bl, sd->bl.id, SELF, SI_MVPCARD_ORCHERO); + break; + case ITEMID_ORC_LOAD_CARD: + clif->sc_end(&sd->bl, sd->bl.id, SELF, SI_MVPCARD_ORCLORD); + break; + } + } + break; + case SC_OVERED_BOOST: + switch( bl->type ){ + case BL_HOM: + { + struct homun_data *hd = BL_CAST(BL_HOM, bl); + if( hd ) + hd->homunculus.hunger = max(1, hd->homunculus.hunger - 50); + } + break; + case BL_PC: + status_zap(bl, 0, status_get_max_sp(bl) / 2); + break; + } + break; + } opt_flag = 1; - switch(type){ + switch(type) { case SC_STONE: case SC_FREEZE: case SC_STUN: case SC_SLEEP: - case SC_DEEP_SLEEP: case SC_BURNING: case SC_WHITEIMPRISON: - case SC_CRYSTALIZE: + case SC_COLD: sc->opt1 = 0; break; @@ -9690,6 +10207,7 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const sc->opt2 &= ~OPT2_DPOISON; break; case SC_CRUCIS: + case SC__CHAOS: sc->opt2 &= ~OPT2_SIGNUMCRUCIS; break; @@ -9699,11 +10217,11 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const break; case SC_CLOAKING: case SC_CLOAKINGEXCEED: - case SC__INVISIBILITY: sc->option &= ~OPTION_CLOAK; case SC_CAMOUFLAGE: opt_flag|= 2; break; + case SC__INVISIBILITY: case SC_CHASEWALK: sc->option &= ~(OPTION_CHASEWALK|OPTION_CLOAK); opt_flag|= 2; @@ -9727,6 +10245,14 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const sc->option &= ~OPTION_HANBOK; opt_flag |= 0x4; break; + case SC_OKTOBERFEST: + sc->option &= ~OPTION_OKTOBERFEST; + opt_flag |= 0x4; + break; + case SC__FEINTBOMB_MASTER: + sc->option &= ~OPTION_INVISIBLE; + opt_flag |= 0x4; + break; case SC_ORCISH: sc->option &= ~OPTION_ORCISH; break; @@ -9736,7 +10262,7 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const case SC_FUSION: sc->option &= ~OPTION_FLYING; break; - //opt3 + //opt3 case SC_TWOHANDQUICKEN: case SC_ONEHANDQUICKEN: case SC_SPEARQUICKEN: @@ -9784,13 +10310,12 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const break; case SC_BERSERK: opt_flag = 0; - // case SC__BLOODYLUST: sc->opt3 &= ~OPT3_BERSERK; break; - // case ???: // doesn't seem to do anything - // sc->opt3 &= ~OPT3_LIGHTBLADE; - // opt_flag = 0; - // break; + // case ???: // doesn't seem to do anything + // sc->opt3 &= ~OPT3_LIGHTBLADE; + // opt_flag = 0; + // break; case SC_DANCING: if ((sce->val1&0xFFFF) == CG_MOONLIT) sc->opt3 &= ~OPT3_MOONLIT; @@ -9825,14 +10350,20 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const sc->opt3 &= ~OPT3_UNDEAD; opt_flag = 0; break; - // case ???: // from DA_CONTRACT (looks like biolab mobs aura) - // sc->opt3 &= ~OPT3_CONTRACT; - // opt_flag = 0; - // break; + // case ???: // from DA_CONTRACT (looks like biolab mobs aura) + // sc->opt3 &= ~OPT3_CONTRACT; + // opt_flag = 0; + // break; default: opt_flag = 0; } +#ifdef ANTI_MAYAP_CHEAT + if (invisible && !(sc->option&(OPTION_HIDE|OPTION_CLOAK|OPTION_INVISIBLE))) { + clif->fixpos(bl); + } +#endif + if (calc_flag&SCB_DYE) { //Restore DYE color if (vd && !vd->cloth_color && sce->val4) clif->changelook(bl,LOOK_CLOTHES_COLOR,sce->val4); @@ -9840,14 +10371,14 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const } //On Aegis, when turning off a status change, first goes the sc packet, then the option packet. - clif->sc_end(bl,bl->id,AREA,StatusIconChangeTable[type]); + clif->sc_end(bl,bl->id,AREA,status->IconChangeTable[type]); if( opt_flag&8 ) //bugreport:681 clif->changeoption2(bl); else if(opt_flag) { clif->changeoption(bl); if( sd && opt_flag&0x4 ) { - clif->changelook(bl,LOOK_BASE,vd->class_); + clif->changelook(bl,LOOK_BASE,sd->vd.class_); clif->get_weapon_view(sd, &sd->vd.weapon, &sd->vd.shield); clif->changelook(bl,LOOK_WEAPON,sd->vd.weapon); clif->changelook(bl,LOOK_SHIELD,sd->vd.shield); @@ -9859,26 +10390,26 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const status_calc_bl(bl,calc_flag); if(opt_flag&4) //Out of hiding, invoke on place. - skill->unit_move(bl,iTimer->gettick(),1); + skill->unit_move(bl,timer->gettick(),1); - if(opt_flag&2 && sd && iMap->getcell(bl->m,bl->x,bl->y,CELL_CHKNPC)) - npc_touch_areanpc(sd,bl->m,bl->x,bl->y); //Trigger on-touch event. + if(opt_flag&2 && sd && map->getcell(bl->m,bl->x,bl->y,CELL_CHKNPC)) + npc->touch_areanpc(sd,bl->m,bl->x,bl->y); //Trigger on-touch event. - ers_free(sc_data_ers, sce); + ers_free(status->data_ers, sce); return 1; } -int kaahi_heal_timer(int tid, unsigned int tick, int id, intptr_t data) -{ +int kaahi_heal_timer(int tid, int64 tick, int id, intptr_t data) { struct block_list *bl; struct status_change *sc; struct status_change_entry *sce; - struct status_data *status; + struct status_data *st; int hp; - if(!((bl=iMap->id2bl(id))&& - (sc=status_get_sc(bl)) && - (sce = sc->data[SC_KAAHI]))) + if(!( (bl=map->id2bl(id)) + && (sc=status->get_sc(bl)) + && (sce=sc->data[SC_KAAHI]) + )) return 0; if(sce->val4 != tid) { @@ -9887,243 +10418,235 @@ int kaahi_heal_timer(int tid, unsigned int tick, int id, intptr_t data) return 0; } - status=status_get_status_data(bl); - if(!status_charge(bl, 0, sce->val3)) { + st=status->get_status_data(bl); + if(!status->charge(bl, 0, sce->val3)) { sce->val4 = INVALID_TIMER; return 0; } - hp = status->max_hp - status->hp; + hp = st->max_hp - st->hp; if (hp > sce->val2) hp = sce->val2; if (hp) - status_heal(bl, hp, 0, 2); + status->heal(bl, hp, 0, 2); sce->val4 = INVALID_TIMER; return 1; } /*========================================== - * For recusive status, like for each 5s we drop sp etc. - * Reseting the end timer. - *------------------------------------------*/ -int status_change_timer(int tid, unsigned int tick, int id, intptr_t data) -{ +* For recusive status, like for each 5s we drop sp etc. +* Reseting the end timer. +*------------------------------------------*/ +int status_change_timer(int tid, int64 tick, int id, intptr_t data) { enum sc_type type = (sc_type)data; struct block_list *bl; struct map_session_data *sd; - struct status_data *status; + struct status_data *st; struct status_change *sc; struct status_change_entry *sce; - bl = iMap->id2bl(id); - if(!bl) - { - ShowDebug("status_change_timer: Null pointer id: %d data: %d\n", id, data); + bl = map->id2bl(id); + if (!bl) { + ShowDebug("status_change_timer: Null pointer id: %d data: %"PRIdPTR"\n", id, data); return 0; } - sc = status_get_sc(bl); - status = status_get_status_data(bl); + sc = status->get_sc(bl); + st = status->get_status_data(bl); - if(!(sc && (sce = sc->data[type]))) - { - ShowDebug("status_change_timer: Null pointer id: %d data: %d bl-type: %d\n", id, data, bl->type); + if (!(sc && (sce = sc->data[type]))) { + ShowDebug("status_change_timer: Null pointer id: %d data: %"PRIdPTR" bl-type: %d\n", id, data, bl->type); return 0; } - if( sce->timer != tid ) - { + if (sce->timer != tid) { ShowError("status_change_timer: Mismatch for type %d: %d != %d (bl id %d)\n",type,tid,sce->timer, bl->id); return 0; } sd = BL_CAST(BL_PC, bl); -// set the next timer of the sce (don't assume the status still exists) -#define sc_timer_next(t,f,i,d) \ - if( (sce=sc->data[type]) ) \ - sce->timer = iTimer->add_timer(t,f,i,d); \ + // set the next timer of the sce (don't assume the status still exists) +#define sc_timer_next(t,f,i,d) do { \ + if ((sce=sc->data[type])) \ + sce->timer = timer->add((t),(f),(i),(d)); \ else \ - ShowError("status_change_timer: Unexpected NULL status change id: %d data: %d\n", id, data) + ShowError("status_change_timer: Unexpected NULL status change id: %d data: %"PRIdPTR"\n", id, data); \ +} while(0) - switch(type) - { - case SC_MAXIMIZEPOWER: - case SC_CLOAKING: - if(!status_charge(bl, 0, 1)) - break; //Not enough SP to continue. - sc_timer_next(sce->val2+tick, status_change_timer, bl->id, data); - return 0; - - case SC_CHASEWALK: - if(!status_charge(bl, 0, sce->val4)) - break; //Not enough SP to continue. + switch(type) { + case SC_MAXIMIZEPOWER: + case SC_CLOAKING: + if(!status->charge(bl, 0, 1)) + break; //Not enough SP to continue. + sc_timer_next(sce->val2+tick, status->change_timer, bl->id, data); + return 0; - if (!sc->data[SC_CHASEWALK2]) { - sc_start(bl, SC_CHASEWALK2,100,1<<(sce->val1-1), - (sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_ROGUE?10:1) //SL bonus -> x10 duration - *skill->get_time2(status_sc2skill(type),sce->val1)); - } - sc_timer_next(sce->val2+tick, status_change_timer, bl->id, data); - return 0; - break; + case SC_CHASEWALK: + if(!status->charge(bl, 0, sce->val4)) + break; //Not enough SP to continue. - case SC_SKA: - if(--(sce->val2)>0){ - sce->val3 = rnd()%100; //Random defense. - sc_timer_next(1000+tick, status_change_timer,bl->id, data); + if (!sc->data[SC_CHASEWALK2]) { + sc_start(bl,bl, SC_CHASEWALK2,100,1<<(sce->val1-1), + (sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_ROGUE?10:1) //SL bonus -> x10 duration + * skill->get_time2(status->sc2skill(type),sce->val1)); + } + sc_timer_next(sce->val2+tick, status->change_timer, bl->id, data); return 0; - } - break; - - case SC_HIDING: - if(--(sce->val2)>0){ + break; - if(sce->val2 % sce->val4 == 0 && !status_charge(bl, 0, 1)) - break; //Fail if it's time to substract SP and there isn't. + case SC_SKA: + if(--(sce->val2)>0) { + sce->val3 = rnd()%100; //Random defense. + sc_timer_next(1000+tick, status->change_timer,bl->id, data); + return 0; + } + break; - sc_timer_next(1000+tick, status_change_timer,bl->id, data); - return 0; - } - break; + case SC_HIDING: + if(--(sce->val2)>0) { + if(sce->val2 % sce->val4 == 0 && !status->charge(bl, 0, 1)) + break; //Fail if it's time to substract SP and there isn't. - case SC_SIGHT: - case SC_RUWACH: - case SC_WZ_SIGHTBLASTER: - if(type == SC_WZ_SIGHTBLASTER) - iMap->foreachinrange( status_change_timer_sub, bl, sce->val3, BL_CHAR|BL_SKILL, bl, sce, type, tick); - else - iMap->foreachinrange( status_change_timer_sub, bl, sce->val3, BL_CHAR, bl, sce, type, tick); + sc_timer_next(1000+tick, status->change_timer,bl->id, data); + return 0; + } + break; - if( --(sce->val2)>0 ){ - sce->val4 += 250; // use for Shadow Form 2 seconds checking. - sc_timer_next(250+tick, status_change_timer, bl->id, data); - return 0; - } - break; + case SC_SIGHT: + case SC_RUWACH: + case SC_WZ_SIGHTBLASTER: + if(type == SC_WZ_SIGHTBLASTER) + map->foreachinrange(status->change_timer_sub, bl, sce->val3, BL_CHAR|BL_SKILL, bl, sce, type, tick); + else + map->foreachinrange(status->change_timer_sub, bl, sce->val3, BL_CHAR, bl, sce, type, tick); - case SC_PROVOKE: - if(sce->val2) { //Auto-provoke (it is ended in status_heal) - sc_timer_next(1000*60+tick,status_change_timer, bl->id, data ); - return 0; - } - break; + if( --(sce->val2)>0 ){ + sce->val4 += 250; // use for Shadow Form 2 seconds checking. + sc_timer_next(250+tick, status->change_timer, bl->id, data); + return 0; + } + break; - case SC_STONE: - if(sc->opt1 == OPT1_STONEWAIT && sce->val3) { - sce->val4 = 0; - unit_stop_walking(bl,1); - unit_stop_attack(bl); - sc->opt1 = OPT1_STONE; - clif->changeoption(bl); - sc_timer_next(1000+tick,status_change_timer, bl->id, data ); - status_calc_bl(bl, StatusChangeFlagTable[type]); - return 0; - } - if(--(sce->val3) > 0) { - if(++(sce->val4)%5 == 0 && status->hp > status->max_hp/4) - status_percent_damage(NULL, bl, 1, 0, false); - sc_timer_next(1000+tick,status_change_timer, bl->id, data ); - return 0; - } - break; + case SC_PROVOKE: + if(sce->val2) { //Auto-provoke (it is ended in status->heal) + sc_timer_next(1000*60+tick, status->change_timer, bl->id, data ); + return 0; + } + break; - case SC_POISON: - if(status->hp <= max(status->max_hp>>2, sce->val4)) //Stop damaging after 25% HP left. + case SC_STONE: + if(sc->opt1 == OPT1_STONEWAIT && sce->val3) { + sce->val4 = 0; + unit->stop_walking(bl,1); + unit->stop_attack(bl); + sc->opt1 = OPT1_STONE; + clif->changeoption(bl); + sc_timer_next(1000+tick, status->change_timer, bl->id, data ); + status_calc_bl(bl, status->ChangeFlagTable[type]); + return 0; + } + if(--(sce->val3) > 0) { + if(++(sce->val4)%5 == 0 && st->hp > st->max_hp/4) + status_percent_damage(NULL, bl, 1, 0, false); + sc_timer_next(1000+tick, status->change_timer, bl->id, data ); + return 0; + } break; - case SC_DPOISON: - if (--(sce->val3) > 0) { - if (!sc->data[SC_SLOWPOISON]) { - if( sce->val2 && bl->type == BL_MOB ) { - struct block_list* src = iMap->id2bl(sce->val2); - if( src ) - mob_log_damage((TBL_MOB*)bl,src,sce->val4); - } - iMap->freeblock_lock(); - status_zap(bl, sce->val4, 0); - if (sc->data[type]) { // Check if the status still last ( can be dead since then ). - sc_timer_next(1000 + tick, status_change_timer, bl->id, data ); + + case SC_POISON: + if(st->hp <= max(st->max_hp>>2, sce->val4)) //Stop damaging after 25% HP left. + break; + case SC_DPOISON: + if (--(sce->val3) > 0) { + if (!sc->data[SC_SLOWPOISON]) { + if( sce->val2 && bl->type == BL_MOB ) { + struct block_list* src = map->id2bl(sce->val2); + if( src ) + mob->log_damage((TBL_MOB*)bl,src,sce->val4); + } + map->freeblock_lock(); + status_zap(bl, sce->val4, 0); + if (sc->data[type]) { // Check if the status still last ( can be dead since then ). + sc_timer_next(1000 + tick, status->change_timer, bl->id, data ); + } + map->freeblock_unlock(); } - iMap->freeblock_unlock(); + return 0; } - return 0; - } - break; + break; - case SC_TENSIONRELAX: - if(status->max_hp > status->hp && --(sce->val3) > 0){ - sc_timer_next(sce->val4+tick, status_change_timer, bl->id, data); - return 0; - } - break; + case SC_TENSIONRELAX: + if(st->max_hp > st->hp && --(sce->val3) > 0) { + sc_timer_next(sce->val4+tick, status->change_timer, bl->id, data); + return 0; + } + break; - case SC_KNOWLEDGE: - if (!sd) break; - if(bl->m == sd->feel_map[0].m || - bl->m == sd->feel_map[1].m || - bl->m == sd->feel_map[2].m) - { //Timeout will be handled by pc->setpos - sce->timer = INVALID_TIMER; - return 0; - } - break; + case SC_KNOWLEDGE: + if (!sd) break; + if(bl->m == sd->feel_map[0].m || + bl->m == sd->feel_map[1].m || + bl->m == sd->feel_map[2].m) + { //Timeout will be handled by pc->setpos + sce->timer = INVALID_TIMER; + return 0; + } + break; - case SC_BLOODING: - if (--(sce->val4) >= 0) { - int hp = rnd()%600 + 200; - struct block_list* src = iMap->id2bl(sce->val2); - if( src && bl && bl->type == BL_MOB ) { - mob_log_damage((TBL_MOB*)bl,src,sd||hp<status->hp?hp:status->hp-1); - } - iMap->freeblock_lock(); - status_fix_damage(src, bl, sd||hp<status->hp?hp:status->hp-1, 1); - if( sc->data[type] ) { - if( status->hp == 1 ) { - iMap->freeblock_unlock(); - break; + case SC_BLOODING: + if (--(sce->val4) >= 0) { + int hp = rnd()%600 + 200; + struct block_list* src = map->id2bl(sce->val2); + if( src && bl && bl->type == BL_MOB ) { + mob->log_damage((TBL_MOB*)bl,src,sd||hp<st->hp?hp:st->hp-1); + } + map->freeblock_lock(); + status_fix_damage(src, bl, sd||hp<st->hp?hp:st->hp-1, 1); + if( sc->data[type] ) { + if( st->hp == 1 ) { + map->freeblock_unlock(); + break; + } + sc_timer_next(10000 + tick, status->change_timer, bl->id, data); } - sc_timer_next(10000 + tick, status_change_timer, bl->id, data); + map->freeblock_unlock(); + return 0; } - iMap->freeblock_unlock(); - return 0; - } - break; + break; - case SC_S_LIFEPOTION: - case SC_L_LIFEPOTION: - if( sd && --(sce->val4) >= 0 ) - { - // val1 < 0 = per max% | val1 > 0 = exact amount - int hp = 0; - if( status->hp < status->max_hp ) - hp = (sce->val1 < 0) ? (int)(sd->status.max_hp * -1 * sce->val1 / 100.) : sce->val1 ; - status_heal(bl, hp, 0, 2); - sc_timer_next((sce->val2 * 1000) + tick, status_change_timer, bl->id, data); - return 0; - } - break; + case SC_S_LIFEPOTION: + case SC_L_LIFEPOTION: + if( sd && --(sce->val4) >= 0 ) { + // val1 < 0 = per max% | val1 > 0 = exact amount + int hp = 0; + if( st->hp < st->max_hp ) + hp = (sce->val1 < 0) ? (int)(sd->status.max_hp * -1 * sce->val1 / 100.) : sce->val1 ; + status->heal(bl, hp, 0, 2); + sc_timer_next((sce->val2 * 1000) + tick, status->change_timer, bl->id, data); + return 0; + } + break; - case SC_CASH_BOSS_ALARM: - if( sd && --(sce->val4) >= 0 ) - { - struct mob_data *boss_md = iMap->id2boss(sce->val1); - if( boss_md && sd->bl.m == boss_md->bl.m ) - { - clif->bossmapinfo(sd->fd, boss_md, 1); // Update X - Y on minimap - if (boss_md->bl.prev != NULL) { - sc_timer_next(5000 + tick, status_change_timer, bl->id, data); - return 0; + case SC_CASH_BOSS_ALARM: + if( sd && --(sce->val4) >= 0 ) { + struct mob_data *boss_md = map->id2boss(sce->val1); + if( boss_md && sd->bl.m == boss_md->bl.m ) { + clif->bossmapinfo(sd->fd, boss_md, 1); // Update X - Y on minimap + if (boss_md->bl.prev != NULL) { + sc_timer_next(5000 + tick, status->change_timer, bl->id, data); + return 0; + } } } - } - break; + break; - case SC_DANCING: //SP consumption by time of dancing skills - { - int s = 0; - int sp = 1; - if (--sce->val3 <= 0) - break; - switch(sce->val1&0xFFFF){ + case SC_DANCING: //SP consumption by time of dancing skills + { + int s = 0; + int sp = 1; + if (--sce->val3 <= 0) + break; + switch(sce->val1&0xFFFF){ case BD_RICHMANKIM: case BD_DRUMBATTLEFIELD: case BD_RINGNIBELUNGEN: @@ -10148,11 +10671,11 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr_t data) s=5; break; case BA_APPLEIDUN: - #ifdef RENEWAL - s=5; - #else - s=6; - #endif + #ifdef RENEWAL + s=5; + #else + s=6; + #endif break; case CG_MOONLIT: //Moonlit's cost is 4sp*skill_lv [Skotlex] @@ -10161,587 +10684,587 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr_t data) case DC_DONTFORGETME: s=10; break; + } + if( s != 0 && sce->val3 % s == 0 ) { + if (sc->data[SC_LONGING]) + sp*= 3; + if (!status->charge(bl, 0, sp)) + break; + } + sc_timer_next(1000+tick, status->change_timer, bl->id, data); + return 0; } - if( s != 0 && sce->val3 % s == 0 ) - { - if (sc->data[SC_LONGING]) - sp*= 3; - if (!status_charge(bl, 0, sp)) - break; + break; + case SC_BERSERK: + // 5% every 10 seconds [DracoRPG] + if( --( sce->val3 ) > 0 && status->charge(bl, sce->val2, 0) && st->hp > 100 ) { + sc_timer_next(sce->val4+tick, status->change_timer, bl->id, data); + return 0; } - sc_timer_next(1000+tick, status_change_timer, bl->id, data); - return 0; - } - break; - case SC__BLOODYLUST: - case SC_BERSERK: - // 5% every 10 seconds [DracoRPG] - if( --( sce->val3 ) > 0 && status_charge(bl, sce->val2, 0) && status->hp > 100 ) - { - sc_timer_next(sce->val4+tick, status_change_timer, bl->id, data); - return 0; - } - break; + break; - case SC_NOCHAT: - if(sd){ - sd->status.manner++; - clif->changestatus(sd,SP_MANNER,sd->status.manner); - clif->updatestatus(sd,SP_MANNER); - if (sd->status.manner < 0) - { //Every 60 seconds your manner goes up by 1 until it gets back to 0. - sc_timer_next(60000+tick, status_change_timer, bl->id, data); - return 0; + case SC_NOCHAT: + if(sd) { + sd->status.manner++; + clif->changestatus(sd,SP_MANNER,sd->status.manner); + clif->updatestatus(sd,SP_MANNER); + if (sd->status.manner < 0) { + //Every 60 seconds your manner goes up by 1 until it gets back to 0. + sc_timer_next(60000+tick, status->change_timer, bl->id, data); + return 0; + } } - } - break; + break; - case SC_SPLASHER: - // custom Venom Splasher countdown timer - //if (sce->val4 % 1000 == 0) { - // char timer[10]; - // snprintf (timer, 10, "%d", sce->val4/1000); - // clif->message(bl, timer); - //} - if((sce->val4 -= 500) > 0) { - sc_timer_next(500 + tick, status_change_timer, bl->id, data); - return 0; - } - break; + case SC_SPLASHER: + // custom Venom Splasher countdown timer + //if (sce->val4 % 1000 == 0) { + // char counter[10]; + // snprintf (counter, 10, "%d", sce->val4/1000); + // clif->message(bl, counter); + //} + if((sce->val4 -= 500) > 0) { + sc_timer_next(500 + tick, status->change_timer, bl->id, data); + return 0; + } + break; - case SC_MARIONETTE_MASTER: - case SC_MARIONETTE: - { - struct block_list *pbl = iMap->id2bl(sce->val1); - if( pbl && check_distance_bl(bl, pbl, 7) ) + case SC_MARIONETTE_MASTER: + case SC_MARIONETTE: { - sc_timer_next(1000 + tick, status_change_timer, bl->id, data); + struct block_list *pbl = map->id2bl(sce->val1); + if( pbl && check_distance_bl(bl, pbl, 7) ) { + sc_timer_next(1000 + tick, status->change_timer, bl->id, data); + return 0; + } + } + break; + + case SC_GOSPEL: + if(sce->val4 == BCT_SELF && --(sce->val2) > 0) { + int hp, sp; + hp = (sce->val1 > 5) ? 45 : 30; + sp = (sce->val1 > 5) ? 35 : 20; + if(!status->charge(bl, hp, sp)) + break; + sc_timer_next(10000+tick, status->change_timer, bl->id, data); return 0; } - } - break; + break; - case SC_GOSPEL: - if(sce->val4 == BCT_SELF && --(sce->val2) > 0) - { - int hp, sp; - hp = (sce->val1 > 5) ? 45 : 30; - sp = (sce->val1 > 5) ? 35 : 20; - if(!status_charge(bl, hp, sp)) - break; - sc_timer_next(10000+tick, status_change_timer, bl->id, data); - return 0; - } - break; + case SC_JAILED: + if(sce->val1 == INT_MAX || --(sce->val1) > 0) { + sc_timer_next(60000+tick, status->change_timer, bl->id,data); + return 0; + } + break; - case SC_JAILED: - if(sce->val1 == INT_MAX || --(sce->val1) > 0) - { - sc_timer_next(60000+tick, status_change_timer, bl->id,data); - return 0; - } - break; + case SC_BLIND: + if(sc->data[SC_FOGWALL]) { + //Blind lasts forever while you are standing on the fog. + sc_timer_next(5000+tick, status->change_timer, bl->id, data); + return 0; + } + break; + case SC_ABUNDANCE: + if(--(sce->val4) > 0) { + status->heal(bl,0,60,0); + sc_timer_next(10000+tick, status->change_timer, bl->id, data); + } + break; - case SC_BLIND: - if(sc->data[SC_FOGWALL]) - { //Blind lasts forever while you are standing on the fog. - sc_timer_next(5000+tick, status_change_timer, bl->id, data); - return 0; - } - break; - case SC_ABUNDANCE: - if(--(sce->val4) > 0) { - status_heal(bl,0,60,0); - sc_timer_next(10000+tick, status_change_timer, bl->id, data); - } - break; + case SC_PYREXIA: + if( --(sce->val4) > 0 ) { + map->freeblock_lock(); + clif->damage(bl,bl,status_get_amotion(bl),status_get_dmotion(bl)+500,100,0,0,0); + status_fix_damage(NULL,bl,100,0); + if( sc->data[type] ) { + sc_timer_next(3000+tick,status->change_timer,bl->id,data); + } + map->freeblock_unlock(); + return 0; + } + break; - case SC_PYREXIA: - if( --(sce->val4) > 0 ) { - iMap->freeblock_lock(); - clif->damage(bl,bl,tick,status_get_amotion(bl),status_get_dmotion(bl)+500,100,0,0,0); - status_fix_damage(NULL,bl,100,0); - if( sc->data[type] ) { - sc_timer_next(3000+tick,status_change_timer,bl->id,data); - } - iMap->freeblock_unlock(); - return 0; - } - break; + case SC_LEECHESEND: + if( --(sce->val4) > 0 ) { + int damage = st->max_hp/100; // {Target VIT x (New Poison Research Skill Level - 3)} + (Target HP/100) + damage += st->vit * (sce->val1 - 3); + unit->skillcastcancel(bl,2); + map->freeblock_lock(); + status->damage(bl, bl, damage, 0, clif->damage(bl,bl,status_get_amotion(bl),status_get_dmotion(bl)+500,damage,1,0,0), 1); + if( sc->data[type] ) { + sc_timer_next(1000 + tick, status->change_timer, bl->id, data ); + } + map->freeblock_unlock(); + return 0; + } + break; - case SC_LEECHESEND: - if( --(sce->val4) > 0 ) { - int damage = status->max_hp/100; // {Target VIT x (New Poison Research Skill Level - 3)} + (Target HP/100) - damage += status->vit * (sce->val1 - 3); - unit_skillcastcancel(bl,2); - iMap->freeblock_lock(); - status_damage(bl, bl, damage, 0, clif->damage(bl,bl,tick,status_get_amotion(bl),status_get_dmotion(bl)+500,damage,1,0,0), 1); - if( sc->data[type] ) { - sc_timer_next(1000 + tick, status_change_timer, bl->id, data ); - } - iMap->freeblock_unlock(); - return 0; - } - break; + case SC_MAGICMUSHROOM: + if( --(sce->val4) > 0 ) { + bool flag = 0; + int damage = st->max_hp * 3 / 100; + if( st->hp <= damage ) + damage = st->hp - 1; // Cannot Kill + + if( damage > 0 ) { // 3% Damage each 4 seconds + map->freeblock_lock(); + status_zap(bl,damage,0); + flag = !sc->data[type]; // Killed? Should not + map->freeblock_unlock(); + } - case SC_MAGICMUSHROOM: - if( --(sce->val4) > 0 ) { - bool flag = 0; - int damage = status->max_hp * 3 / 100; - if( status->hp <= damage ) - damage = status->hp - 1; // Cannot Kill - - if( damage > 0 ) { // 3% Damage each 4 seconds - iMap->freeblock_lock(); - status_zap(bl,damage,0); - flag = !sc->data[type]; // Killed? Should not - iMap->freeblock_unlock(); - } - - if( !flag ) { // Random Skill Cast - if (sd && !pc_issit(sd)) { //can't cast if sit - int mushroom_skill_id = 0, i; - unit_stop_attack(bl); - unit_skillcastcancel(bl,1); - do { - i = rnd() % MAX_SKILL_MAGICMUSHROOM_DB; - mushroom_skill_id = skill_magicmushroom_db[i].skill_id; - } - while( mushroom_skill_id == 0 ); + if( !flag ) { // Random Skill Cast + if (sd && !pc_issit(sd)) { //can't cast if sit + int mushroom_skill_id = 0, i; + unit->stop_attack(bl); + unit->skillcastcancel(bl,0); + do { + i = rnd() % MAX_SKILL_MAGICMUSHROOM_DB; + mushroom_skill_id = skill->magicmushroom_db[i].skill_id; + } + while( mushroom_skill_id == 0 ); - switch( skill->get_casttype(mushroom_skill_id) ) { // Magic Mushroom skills are buffs or area damage - case CAST_GROUND: - skill->castend_pos2(bl,bl->x,bl->y,mushroom_skill_id,1,tick,0); - break; - case CAST_NODAMAGE: - skill->castend_nodamage_id(bl,bl,mushroom_skill_id,1,tick,0); - break; - case CAST_DAMAGE: - skill->castend_damage_id(bl,bl,mushroom_skill_id,1,tick,0); - break; + switch( skill->get_casttype(mushroom_skill_id) ) { // Magic Mushroom skills are buffs or area damage + case CAST_GROUND: + skill->castend_pos2(bl,bl->x,bl->y,mushroom_skill_id,1,tick,0); + break; + case CAST_NODAMAGE: + skill->castend_nodamage_id(bl,bl,mushroom_skill_id,1,tick,0); + break; + case CAST_DAMAGE: + skill->castend_damage_id(bl,bl,mushroom_skill_id,1,tick,0); + break; + } } + + clif->emotion(bl,E_HEH); + sc_timer_next(4000+tick,status->change_timer,bl->id,data); } + return 0; + } + break; - clif->emotion(bl,E_HEH); - sc_timer_next(4000+tick,status_change_timer,bl->id,data); + case SC_TOXIN: + if( --(sce->val4) > 0 ) { + //Damage is every 10 seconds including 3%sp drain. + map->freeblock_lock(); + clif->damage(bl,bl,status_get_amotion(bl),1,1,0,0,0); + status->damage(NULL, bl, 1, st->max_sp * 3 / 100, 0, 0); //cancel dmg only if cancelable + if( sc->data[type] ) { + sc_timer_next(10000 + tick, status->change_timer, bl->id, data ); + } + map->freeblock_unlock(); + return 0; } - return 0; - } - break; + break; - case SC_TOXIN: - if( --(sce->val4) > 0 ) - { //Damage is every 10 seconds including 3%sp drain. - iMap->freeblock_lock(); - clif->damage(bl,bl,tick,status_get_amotion(bl),1,1,0,0,0); - status_damage(NULL, bl, 1, status->max_sp * 3 / 100, 0, 0); //cancel dmg only if cancelable - if( sc->data[type] ) { - sc_timer_next(10000 + tick, status_change_timer, bl->id, data ); - } - iMap->freeblock_unlock(); - return 0; - } - break; + case SC_OBLIVIONCURSE: + if( --(sce->val4) > 0 ) { + clif->emotion(bl,E_WHAT); + sc_timer_next(3000 + tick, status->change_timer, bl->id, data ); + return 0; + } + break; - case SC_OBLIVIONCURSE: - if( --(sce->val4) > 0 ) - { - clif->emotion(bl,E_WHAT); - sc_timer_next(3000 + tick, status_change_timer, bl->id, data ); - return 0; - } - break; + case SC_WEAPONBLOCKING: + if( --(sce->val4) > 0 ) { + if( !status->charge(bl,0,3) ) + break; + sc_timer_next(5000+tick,status->change_timer,bl->id,data); + return 0; + } + break; - case SC_WEAPONBLOCKING: - if( --(sce->val4) > 0 ) - { - if( !status_charge(bl,0,3) ) + case SC_CLOAKINGEXCEED: + if(!status->charge(bl,0,10-sce->val1)) break; - sc_timer_next(3000+tick,status_change_timer,bl->id,data); + sc_timer_next(1000 + tick, status->change_timer, bl->id, data); return 0; - } - break; - case SC_CLOAKINGEXCEED: - if(!status_charge(bl,0,10-sce->val1)) + case SC_RENOVATIO: + if( --(sce->val4) > 0 ) { + int heal = st->max_hp * 3 / 100; + if( sc && sc->data[SC_AKAITSUKI] && heal ) + heal = ~heal + 1; + status->heal(bl, heal, 0, 2); + sc_timer_next(5000 + tick, status->change_timer, bl->id, data); + return 0; + } break; - sc_timer_next(1000 + tick, status_change_timer, bl->id, data); - return 0; - case SC_RENOVATIO: - if( --(sce->val4) > 0 ) - { - int heal = status->max_hp * 3 / 100; - if( sc && sc->data[SC_AKAITSUKI] && heal ) - heal = ~heal + 1; - status_heal(bl, heal, 0, 2); - sc_timer_next(5000 + tick, status_change_timer, bl->id, data); - return 0; - } - break; + case SC_BURNING: + if( --(sce->val4) > 0 ) { + struct block_list *src = map->id2bl(sce->val3); + int damage = 1000 + 3 * status_get_max_hp(bl) / 100; // Deals fixed (1000 + 3%*MaxHP) - case SC_BURNING: - if( --(sce->val4) > 0 ) - { - struct block_list *src = iMap->id2bl(sce->val3); - int damage = 1000 + 3 * status_get_max_hp(bl) / 100; // Deals fixed (1000 + 3%*MaxHP) + map->freeblock_lock(); + clif->damage(bl,bl,0,0,damage,1,9,0); //damage is like endure effect with no walk delay + status->damage(src, bl, damage, 0, 0, 1); - iMap->freeblock_lock(); - clif->damage(bl,bl,tick,0,0,damage,1,9,0); //damage is like endure effect with no walk delay - status_damage(src, bl, damage, 0, 0, 1); + if( sc->data[type]){ // Target still lives. [LimitLine] + sc_timer_next(3000 + tick, status->change_timer, bl->id, data); + } + map->freeblock_unlock(); + return 0; + } + break; - if( sc->data[type]){ // Target still lives. [LimitLine] - sc_timer_next(3000 + tick, status_change_timer, bl->id, data); + case SC_FEAR: + if( --(sce->val4) > 0 ) { + if( sce->val2 > 0 ) + sce->val2--; + sc_timer_next(1000 + tick, status->change_timer, bl->id, data); + return 0; } - iMap->freeblock_unlock(); - return 0; - } - break; + break; - case SC_FEAR: - if( --(sce->val4) > 0 ) - { - if( sce->val2 > 0 ) - sce->val2--; - sc_timer_next(1000 + tick, status_change_timer, bl->id, data); - return 0; - } - break; + case SC_SUMMON1: + case SC_SUMMON2: + case SC_SUMMON3: + case SC_SUMMON4: + case SC_SUMMON5: + if( --(sce->val4) > 0 ) { + if( !status->charge(bl, 0, 1) ) + break; + sc_timer_next(1000 + tick, status->change_timer, bl->id, data); + return 0; + } + break; - case SC_SUMMON1: - case SC_SUMMON2: - case SC_SUMMON3: - case SC_SUMMON4: - case SC_SUMMON5: - if( --(sce->val4) > 0 ) - { - if( !status_charge(bl, 0, 1) ) + case SC_READING_SB: + if( !status->charge(bl, 0, sce->val2) ) { + int i; + for(i = SC_SPELLBOOK1; i <= SC_SPELLBOOK7; i++) // Also remove stored spell as well. + status_change_end(bl, (sc_type)i, INVALID_TIMER); break; - sc_timer_next(1000 + tick, status_change_timer, bl->id, data); + } + sc_timer_next(10000 + tick, status->change_timer, bl->id, data); return 0; - } - break; - case SC_READING_SB: - if( !status_charge(bl, 0, sce->val2) ){ - int i; - for(i = SC_SPELLBOOK1; i <= SC_SPELLBOOK7; i++) // Also remove stored spell as well. - status_change_end(bl, (sc_type)i, INVALID_TIMER); + case SC_ELECTRICSHOCKER: + if( --(sce->val4) > 0 ) { + status->charge(bl, 0, st->max_sp / 100 * sce->val1 ); + sc_timer_next(1000 + tick, status->change_timer, bl->id, data); + return 0; + } break; - } - sc_timer_next(5000 + tick, status_change_timer, bl->id, data); - return 0; - - case SC_ELECTRICSHOCKER: - if( --(sce->val4) > 0 ) - { - status_charge(bl, 0, status->max_sp / 100 * sce->val1 ); - sc_timer_next(1000 + tick, status_change_timer, bl->id, data); - return 0; - } - break; - case SC_CAMOUFLAGE: - if(--(sce->val4) > 0){ - status_charge(bl,0,7 - sce->val1); - sc_timer_next(1000 + tick, status_change_timer, bl->id, data); - return 0; - } - break; + case SC_CAMOUFLAGE: + if(--(sce->val4) > 0) { + status->charge(bl,0,7 - sce->val1); + sc_timer_next(1000 + tick, status->change_timer, bl->id, data); + return 0; + } + break; - case SC__REPRODUCE: - if(!status_charge(bl, 0, 1)) + case SC__REPRODUCE: + if( --(sce->val4) >= 0 ) { + if( !status_charge(bl, 0, 9 - (1 + sce->val1) / 2) ) + break; + sc_timer_next(1000 + tick, status->change_timer, bl->id, data); + return 0; + } break; - sc_timer_next(1000+tick, status_change_timer, bl->id, data); - return 0; - case SC__SHADOWFORM: - if( --(sce->val4) > 0 ) - { - if( !status_charge(bl, 0, sce->val1 - (sce->val1 - 1)) ) - break; - sc_timer_next(1000 + tick, status_change_timer, bl->id, data); - return 0; - } - break; + case SC__SHADOWFORM: + if( --(sce->val4) > 0 ) { + if( !status->charge(bl, 0, sce->val1 - (sce->val1 - 1)) ) + break; + sc_timer_next(1000 + tick, status->change_timer, bl->id, data); + return 0; + } + break; - case SC__INVISIBILITY: - if( --(sce->val4) > 0 ) - { - if( !status_charge(bl, 0, (status->sp * 6 - sce->val1) / 100) )// 6% - skill_lv. - break; - sc_timer_next(1000 + tick, status_change_timer, bl->id, data); - return 0; - } - break; + case SC__INVISIBILITY: + if( --(sce->val4) >= 0 ) { + if( !status->charge(bl, 0, status_get_max_sp(bl) * (12 - sce->val1*2) / 100) ) + break; + sc_timer_next(1000 + tick, status->change_timer, bl->id, data); + return 0; + } + break; - case SC_STRIKING: - if( --(sce->val4) > 0 ) - { - if( !status_charge(bl,0, sce->val1 ) ) - break; - sc_timer_next(1000 + tick, status_change_timer, bl->id, data); - return 0; - } - break; - case SC_VACUUM_EXTREME: - if( --(sce->val4) > 0 ){ - sc_timer_next(100 + tick, status_change_timer, bl->id, data); - return 0; - } - break; - case SC_BLOOD_SUCKER: - if( --(sce->val4) > 0 ) { - struct block_list *src = iMap->id2bl(sce->val2); - int damage; - if( !src || (src && (status_isdead(src) || src->m != bl->m || distance_bl(src, bl) >= 12)) ) - break; - iMap->freeblock_lock(); - damage = sce->val3; - status_damage(src, bl, damage, 0, clif->damage(bl,bl,tick,status->amotion,status->dmotion+200,damage,1,0,0), 1); - unit_skillcastcancel(bl,1); - if ( sc->data[type] ) { - sc_timer_next(1000 + tick, status_change_timer, bl->id, data); + case SC_STRIKING: + if( --(sce->val4) > 0 ) { + if( !status->charge(bl,0, sce->val1 ) ) + break; + sc_timer_next(1000 + tick, status->change_timer, bl->id, data); + return 0; } - iMap->freeblock_unlock(); - status_heal(src, damage*(5 + 5 * sce->val1)/100, 0, 0); // 5 + 5% per level - return 0; - } - break; + break; + case SC_BLOOD_SUCKER: + 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)) ) + break; + map->freeblock_lock(); + damage = sce->val3; + status->damage(src, bl, damage, 0, clif->damage(bl,bl,st->amotion,st->dmotion+200,damage,1,0,0), 1); + unit->skillcastcancel(bl,1); + if ( sc->data[type] ) { + sc_timer_next(1000 + tick, status->change_timer, bl->id, data); + } + map->freeblock_unlock(); + status->heal(src, damage*(5 + 5 * sce->val1)/100, 0, 0); // 5 + 5% per level + return 0; + } + break; - case SC_SIREN: - if( --(sce->val4) > 0 ) - { - clif->emotion(bl,E_LV); - sc_timer_next(2000 + tick, status_change_timer, bl->id, data); - return 0; - } - break; + case SC_SIREN: + if( --(sce->val4) > 0 ) { + clif->emotion(bl,E_LV); + sc_timer_next(2000 + tick, status->change_timer, bl->id, data); + return 0; + } + break; - case SC_DEEP_SLEEP: - if( --(sce->val4) > 0 ) - { // Recovers 1% HP/SP every 2 seconds. - status_heal(bl, status->max_hp / 100, status->max_sp / 100, 2); - sc_timer_next(2000 + tick, status_change_timer, bl->id, data); - return 0; - } - break; + case SC_DEEP_SLEEP: + if( --(sce->val4) >= 0 ) + {// Recovers 3% of the player's MaxHP/MaxSP every 2 seconds. + status->heal(bl, st->max_hp * 3 / 100, st->max_sp * 3 / 100, 2); + sc_timer_next(2000 + tick, status->change_timer, bl->id, data); + return 0; + } + break; - case SC_SIRCLEOFNATURE: - if( --(sce->val4) > 0 ) - { - if( !status_charge(bl,0,sce->val2) ) - break; - status_heal(bl, sce->val3, 0, 1); - sc_timer_next(1000 + tick, status_change_timer, bl->id, data); - return 0; - } - break; + case SC_SIRCLEOFNATURE: + if( --(sce->val4) >= 0 ) { + if( !status_charge(bl,0,sce->val3) ) + break; + status->heal(bl, sce->val2, 0, 1); + sc_timer_next(1000 + tick, status_change_timer, bl->id, data); + return 0; + } + break; - case SC_SONG_OF_MANA: - if( --(sce->val4) > 0 ) - { - status_heal(bl,0,sce->val3,3); - sc_timer_next(3000 + tick, status_change_timer, bl->id, data); - return 0; - } - break; + case SC_SONG_OF_MANA: + if( --(sce->val4) >= 0 ) { + status->heal(bl,0,sce->val3,3); + sc_timer_next(5000 + tick, status->change_timer, bl->id, data); + return 0; + } + break; - case SC_SATURDAY_NIGHT_FEVER: - // 1% HP/SP drain every val4 seconds [Jobbie] - if( --(sce->val3) > 0 ) - { - int hp = status->hp / 100; - int sp = status->sp / 100; - if( !status_charge(bl, hp, sp) ) + case SC_SATURDAY_NIGHT_FEVER: + if( --(sce->val3) >= 0 ) { + if( !status_charge(bl, st->max_hp * 1 / 100, st->max_sp * 1 / 100) ) break; - sc_timer_next(sce->val4+tick, status_change_timer, bl->id, data); - return 0; - } - break; - - case SC_CRYSTALIZE: - if( --(sce->val4) > 0 ) - { // Drains 2% of HP and 1% of SP every seconds. - if( bl->type != BL_MOB) // doesn't work on mobs - status_charge(bl, status->max_hp * 2 / 100, status->max_sp / 100); - sc_timer_next(1000 + tick, status_change_timer, bl->id, data); - return 0; - } - break; + sc_timer_next(3000+tick, status->change_timer, bl->id, data); + return 0; + } + break; - case SC_FORCEOFVANGUARD: - if( !status_charge(bl,0,20) ) + case SC_MELODYOFSINK: + if( --(sce->val4) >= 0 ) { + status_charge(bl, 0, st->max_sp * ( 2 * sce->val1 + 2 * sce->val2 ) / 100); + sc_timer_next(1000+tick, status->change_timer, bl->id, data); + return 0; + } break; - sc_timer_next(6000 + tick, status_change_timer, bl->id, data); - return 0; - case SC_BANDING: - if( status_charge(bl, 0, 7 - sce->val1) ) - { - if( sd ) pc->banding(sd, sce->val1); - sc_timer_next(5000 + tick, status_change_timer, bl->id, data); - return 0; - } - break; + case SC_COLD: + if( --(sce->val4) > 0 ) { + // Drains 2% of HP and 1% of SP every seconds. + if( bl->type != BL_MOB) // doesn't work on mobs + status->charge(bl, st->max_hp * 2 / 100, st->max_sp / 100); + sc_timer_next(1000 + tick, status->change_timer, bl->id, data); + return 0; + } + break; - case SC_LG_REFLECTDAMAGE: - if( --(sce->val4) > 0 ) { - if( !status_charge(bl,0,sce->val3) ) + case SC_FORCEOFVANGUARD: + if( !status->charge(bl, 0, (24 - 4 * sce->val1)) ) break; - sc_timer_next(10000 + tick, status_change_timer, bl->id, data); + sc_timer_next(10000 + tick, status->change_timer, bl->id, data); return 0; - } - break; - case SC_OVERHEAT_LIMITPOINT: - if( --(sce->val1) > 0 ) { // Cooling - sc_timer_next(30000 + tick, status_change_timer, bl->id, data); - } - break; + case SC_BANDING: + if( status->charge(bl, 0, 7 - sce->val1) ) { + if( sd ) pc->banding(sd, sce->val1); + sc_timer_next(5000 + tick, status->change_timer, bl->id, data); + return 0; + } + break; - case SC_OVERHEAT: - { - int damage = status->max_hp / 100; // Suggestion 1% each second - if( damage >= status->hp ) damage = status->hp - 1; // Do not kill, just keep you with 1 hp minimum - iMap->freeblock_lock(); - status_fix_damage(NULL,bl,damage,clif->damage(bl,bl,tick,0,0,damage,0,0,0)); - if( sc->data[type] ) { - sc_timer_next(1000 + tick, status_change_timer, bl->id, data); + case SC_LG_REFLECTDAMAGE: + if( --(sce->val4) >= 0 ) { + if( !status->charge(bl,0,10) ) + break; + sc_timer_next(1000 + tick, status->change_timer, bl->id, data); + return 0; } - iMap->freeblock_unlock(); - } - break; + break; - case SC_MAGNETICFIELD: - { - if( --(sce->val3) <= 0 ) - break; // Time out - if( sce->val2 == bl->id ) + case SC_OVERHEAT_LIMITPOINT: + if( --(sce->val1) > 0 ) { // Cooling + sc_timer_next(30000 + tick, status->change_timer, bl->id, data); + } + break; + + case SC_OVERHEAT: { - if( !status_charge(bl,0,14 + (3 * sce->val1)) ) - break; // No more SP status should end, and in the next second will end for the other affected players + int damage = st->max_hp / 100; // Suggestion 1% each second + if( damage >= st->hp ) damage = st->hp - 1; // Do not kill, just keep you with 1 hp minimum + map->freeblock_lock(); + status_fix_damage(NULL,bl,damage,clif->damage(bl,bl,0,0,damage,0,0,0)); + if( sc->data[type] ) { + sc_timer_next(1000 + tick, status->change_timer, bl->id, data); + } + map->freeblock_unlock(); } - else + break; + + case SC_MAGNETICFIELD: { - struct block_list *src = iMap->id2bl(sce->val2); - struct status_change *ssc; - if( !src || (ssc = status_get_sc(src)) == NULL || !ssc->data[SC_MAGNETICFIELD] ) - break; // Source no more under Magnetic Field + if( --(sce->val3) <= 0 ) + break; // Time out + if( sce->val2 == bl->id ) { + if( !status->charge(bl,0,50) ) + break; // No more SP status should end, and in the next second will end for the other affected players + } else { + struct block_list *src = map->id2bl(sce->val2); + struct status_change *ssc; + if( !src || (ssc = status->get_sc(src)) == NULL || !ssc->data[SC_MAGNETICFIELD] ) + break; // Source no more under Magnetic Field + } + sc_timer_next(1000 + tick, status->change_timer, bl->id, data); } - sc_timer_next(1000 + tick, status_change_timer, bl->id, data); - } - break; + break; - case SC_INSPIRATION: - if(--(sce->val4) > 0) - { - int hp = status->max_hp * (7-sce->val1) / 100; - int sp = status->max_sp * (9-sce->val1) / 100; + case SC_STEALTHFIELD_MASTER: + if(--(sce->val4) >= 0) { + // 1% SP Upkeep Cost + int sp = st->max_sp / 100; + + if( st->sp <= sp ) + status_change_end(bl,SC_STEALTHFIELD_MASTER,INVALID_TIMER); - if( !status_charge(bl,hp,sp) ) break; + if( !status_charge(bl,0,sp) ) + break; - sc_timer_next(1000+tick,status_change_timer,bl->id, data); - return 0; - } - break; + if( !sc->data[SC_STEALTHFIELD_MASTER] ) + break; - case SC_RAISINGDRAGON: - // 1% every 5 seconds [Jobbie] - if( --(sce->val3)>0 && status_charge(bl, sce->val2, 0) ) - { - if( !sc->data[type] ) return 0; - sc_timer_next(5000 + tick, status_change_timer, bl->id, data); - return 0; - } - break; + sc_timer_next((2000 + 1000 * sce->val1)+tick,status->change_timer,bl->id, data); + return 0; + } + break; + + case SC_INSPIRATION: + if(--(sce->val4) >= 0) { + int hp = st->max_hp * (35 - 5 * sce->val1) / 1000; + int sp = st->max_sp * (45 - 5 * sce->val1) / 1000; + + if( !status->charge(bl,hp,sp) ) break; - case SC_CIRCLE_OF_FIRE: - case SC_FIRE_CLOAK: - case SC_WATER_DROP: - case SC_WATER_SCREEN: - case SC_WIND_CURTAIN: - case SC_WIND_STEP: - case SC_STONE_SHIELD: - case SC_SOLID_SKIN: - if( !status_charge(bl,0,sce->val2) ){ - struct block_list *s_bl = battle->get_master(bl); - if( s_bl ) - status_change_end(s_bl,type+1,INVALID_TIMER); - status_change_end(bl,type,INVALID_TIMER); + sc_timer_next(5000+tick,status->change_timer,bl->id, data); + return 0; + } break; - } - sc_timer_next(2000 + tick, status_change_timer, bl->id, data); - return 0; - case SC_STOMACHACHE: - if( --(sce->val4) > 0 ){ - status_charge(bl,0,sce->val2); // Reduce 8 every 10 seconds. - if( sd && !pc_issit(sd) ) // Force to sit every 10 seconds. - { - pc_stop_walking(sd,1|4); - pc_stop_attack(sd); - pc_setsit(sd); - clif->sitting(bl); + case SC_RAISINGDRAGON: + // 1% every 5 seconds [Jobbie] + if( --(sce->val3)>0 && status->charge(bl, sce->val2, 0) ) { + if( !sc->data[type] ) return 0; + sc_timer_next(5000 + tick, status->change_timer, bl->id, data); + return 0; } - sc_timer_next(10000 + tick, status_change_timer, bl->id, data); - return 0; - } - break; - case SC_LEADERSHIP: - case SC_GLORYWOUNDS: - case SC_SOULCOLD: - case SC_HAWKEYES: - /* they only end by status_change_end */ - sc_timer_next(600000 + tick, status_change_timer, bl->id, data); - return 0; - case SC_MEIKYOUSISUI: - if( --(sce->val4) > 0 ){ - status_heal(bl, status->max_hp * (sce->val1+1) / 100, status->max_sp * sce->val1 / 100, 0); - sc_timer_next(1000 + tick, status_change_timer, bl->id, data); - return 0; - } - break; - case SC_IZAYOI: - case SC_KAGEMUSYA: - if( --(sce->val2) > 0 ){ - if(!status_charge(bl, 0, 1)) break; - sc_timer_next(1000+tick, status_change_timer, bl->id, data); - return 0; - } - break; - case SC_ANGRIFFS_MODUS: - if(--(sce->val4) > 0) { //drain hp/sp - if( !status_charge(bl,100,20) ) break; - sc_timer_next(1000+tick,status_change_timer,bl->id, data); - return 0; - } - break; - case SC_FULL_THROTTLE: - if( --(sce->val4) > 0 ) - { - status_percent_damage(bl, bl, sce->val2, 0, false); - sc_timer_next(1000 + tick, status_change_timer, bl->id, data); - return 0; - } - break; - case SC_KINGS_GRACE: - if( --(sce->val4) > 0 ) - { - status_percent_heal(bl, sce->val2, 0); - sc_timer_next(1000 + tick, status_change_timer, bl->id, data); + break; + + case SC_TROPIC: + case SC_CHILLY_AIR: + case SC_WILD_STORM: + case SC_UPHEAVAL: + case SC_HEATER: + case SC_COOLER: + case SC_BLAST: + case SC_CURSED_SOIL: + case SC_PYROTECHNIC: + case SC_AQUAPLAY: + case SC_GUST: + case SC_PETROLOGY: + case SC_CIRCLE_OF_FIRE: + case SC_WATER_SCREEN: + case SC_WIND_STEP: + case SC_SOLID_SKIN: + case SC_FIRE_CLOAK: + case SC_WATER_DROP: + case SC_WIND_CURTAIN: + case SC_STONE_SHIELD: + if(status->charge(bl, 0, sce->val2) && (sce->val4==-1 || (sce->val4-=sce->val3)>=0)) + sc_timer_next(sce->val3 + tick, status->change_timer, bl->id, data); + else + if (bl->type == BL_ELEM) + elemental->change_mode(BL_CAST(BL_ELEM,bl),MAX_ELESKILLTREE); return 0; - } - break; - case SC_FRIGG_SONG: - if( --(sce->val4) > 0 ) - { - status_heal(bl, sce->val3, 0, 0); - sc_timer_next(10000 + tick, status_change_timer, bl->id, data); + + case SC_STOMACHACHE: + if( --(sce->val4) > 0 ) { + status->charge(bl,0,sce->val2); // Reduce 8 every 10 seconds. + if( sd && !pc_issit(sd) ) { // Force to sit every 10 seconds. + pc_stop_walking(sd,1|4); + pc_stop_attack(sd); + pc_setsit(sd); + clif->sitting(bl); + } + sc_timer_next(10000 + tick, status->change_timer, bl->id, data); + return 0; + } + break; + case SC_LEADERSHIP: + case SC_GLORYWOUNDS: + case SC_SOULCOLD: + case SC_HAWKEYES: + /* they only end by status_change_end */ + sc_timer_next(600000 + tick, status->change_timer, bl->id, data); return 0; - } - break; + case SC_MEIKYOUSISUI: + if( --(sce->val4) > 0 ) { + status->heal(bl, st->max_hp * (sce->val1+1) / 100, st->max_sp * sce->val1 / 100, 0); + sc_timer_next(1000 + tick, status->change_timer, bl->id, data); + return 0; + } + break; + case SC_IZAYOI: + case SC_KAGEMUSYA: + if( --(sce->val2) > 0 ) { + if(!status->charge(bl, 0, 1)) break; + sc_timer_next(1000+tick, status->change_timer, bl->id, data); + return 0; + } + break; + case SC_ANGRIFFS_MODUS: + if(--(sce->val4) > 0) { //drain hp/sp + if( !status->charge(bl,100,20) ) break; + sc_timer_next(1000+tick,status->change_timer,bl->id, data); + return 0; + } + break; + case SC_FULL_THROTTLE: + if( --(sce->val4) >= 0 ) { + status_percent_damage(bl, bl, 0, sce->val2, false); + sc_timer_next(1000 + tick, status->change_timer, bl->id, data); + return 0; + } + break; + case SC_KINGS_GRACE: + if( --(sce->val4) > 0 ) { + status_percent_heal(bl, sce->val2, 0); + sc_timer_next(1000 + tick, status->change_timer, bl->id, data); + return 0; + } + break; + case SC_FRIGG_SONG: + if( --(sce->val4) > 0 ) { + status->heal(bl, sce->val3, 0, 0); + sc_timer_next(1000 + tick, status->change_timer, bl->id, data); + return 0; + } + break; } // default for all non-handled control paths is to end the status @@ -10750,96 +11273,93 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr_t data) } /*========================================== - * Foreach iteration of repetitive status - *------------------------------------------*/ -int status_change_timer_sub(struct block_list* bl, va_list ap) -{ +* Foreach iteration of repetitive status +*------------------------------------------*/ +int status_change_timer_sub(struct block_list* bl, va_list ap) { struct status_change* tsc; struct block_list* src = va_arg(ap,struct block_list*); struct status_change_entry* sce = va_arg(ap,struct status_change_entry*); enum sc_type type = (sc_type)va_arg(ap,int); //gcc: enum args get promoted to int - unsigned int tick = va_arg(ap,unsigned int); + int64 tick = va_arg(ap, int64); - if (status_isdead(bl)) + if (status->isdead(bl)) return 0; - tsc = status_get_sc(bl); + tsc = status->get_sc(bl); switch( type ) { - case SC_SIGHT: /* Reveal hidden ennemy on 3*3 range */ - if( tsc && tsc->data[SC__SHADOWFORM] && (sce && sce->val4 >0 && sce->val4%2000 == 0) && // for every 2 seconds do the checking - rnd()%100 < 100-tsc->data[SC__SHADOWFORM]->val1*10 ) // [100 - (Skill Level x 10)] % + case SC_SIGHT: /* Reveal hidden ennemy on 3*3 range */ + if( tsc && tsc->data[SC__SHADOWFORM] && (sce && sce->val4 >0 && sce->val4%2000 == 0) && // for every 2 seconds do the checking + rnd()%100 < 100-tsc->data[SC__SHADOWFORM]->val1*10 ) // [100 - (Skill Level x 10)] % status_change_end(bl, SC__SHADOWFORM, INVALID_TIMER); - case SC_CONCENTRATION: - status_change_end(bl, SC_HIDING, INVALID_TIMER); - status_change_end(bl, SC_CLOAKING, INVALID_TIMER); - status_change_end(bl, SC_CLOAKINGEXCEED, INVALID_TIMER); - status_change_end(bl, SC_CAMOUFLAGE, INVALID_TIMER); - status_change_end(bl, SC__INVISIBILITY, INVALID_TIMER); - break; - case SC_RUWACH: /* Reveal hidden target and deal little dammages if ennemy */ - if (tsc && (tsc->data[SC_HIDING] || tsc->data[SC_CLOAKING] || - tsc->data[SC_CAMOUFLAGE] || tsc->data[SC_CLOAKINGEXCEED] || - tsc->data[SC__INVISIBILITY])) { + case SC_CONCENTRATION: status_change_end(bl, SC_HIDING, INVALID_TIMER); status_change_end(bl, SC_CLOAKING, INVALID_TIMER); - status_change_end(bl, SC_CAMOUFLAGE, INVALID_TIMER); status_change_end(bl, SC_CLOAKINGEXCEED, INVALID_TIMER); - status_change_end(bl, SC__INVISIBILITY, INVALID_TIMER); - if(battle->check_target( src, bl, BCT_ENEMY ) > 0) - skill->attack(BF_MAGIC,src,src,bl,AL_RUWACH,1,tick,0); - } - if( tsc && tsc->data[SC__SHADOWFORM] && (sce && sce->val4 >0 && sce->val4%2000 == 0) && // for every 2 seconds do the checking - rnd()%100 < 100-tsc->data[SC__SHADOWFORM]->val1*10 ) // [100 - (Skill Level x 10)] % + status_change_end(bl, SC_CAMOUFLAGE, INVALID_TIMER); + break; + case SC_RUWACH: /* Reveal hidden target and deal little dammages if ennemy */ + if (tsc && (tsc->data[SC_HIDING] || tsc->data[SC_CLOAKING] || + tsc->data[SC_CAMOUFLAGE] || tsc->data[SC_CLOAKINGEXCEED])) { + status_change_end(bl, SC_HIDING, INVALID_TIMER); + status_change_end(bl, SC_CLOAKING, INVALID_TIMER); + status_change_end(bl, SC_CAMOUFLAGE, INVALID_TIMER); + status_change_end(bl, SC_CLOAKINGEXCEED, INVALID_TIMER); + if(battle->check_target( src, bl, BCT_ENEMY ) > 0) + skill->attack(BF_MAGIC,src,src,bl,AL_RUWACH,1,tick,0); + } + if( tsc && tsc->data[SC__SHADOWFORM] && (sce && sce->val4 >0 && sce->val4%2000 == 0) && // for every 2 seconds do the checking + rnd()%100 < 100-tsc->data[SC__SHADOWFORM]->val1*10 ) // [100 - (Skill Level x 10)] % status_change_end(bl, SC__SHADOWFORM, INVALID_TIMER); - break; - case SC_WZ_SIGHTBLASTER: - if (battle->check_target( src, bl, BCT_ENEMY ) > 0 && - status_check_skilluse(src, bl, WZ_SIGHTBLASTER, 2)) - { - if (sce && !(bl->type&BL_SKILL) //The hit is not counted if it's against a trap - && skill->attack(BF_MAGIC,src,src,bl,WZ_SIGHTBLASTER,1,tick,0)){ - sce->val2 = 0; //This signals it to end. + break; + case SC_WZ_SIGHTBLASTER: + if (battle->check_target( src, bl, BCT_ENEMY ) > 0 + && status->check_skilluse(src, bl, WZ_SIGHTBLASTER, 2) + ) { + if (sce && !(bl->type&BL_SKILL) //The hit is not counted if it's against a trap + && skill->attack(BF_MAGIC,src,src,bl,WZ_SIGHTBLASTER,1,tick,0) + ){ + sce->val2 = 0; //This signals it to end. + } } - } - break; - case SC_RG_CCONFINE_M: - //Lock char has released the hold on everyone... - if (tsc && tsc->data[SC_RG_CCONFINE_S] && tsc->data[SC_RG_CCONFINE_S]->val2 == src->id) { - tsc->data[SC_RG_CCONFINE_S]->val2 = 0; - status_change_end(bl, SC_RG_CCONFINE_S, INVALID_TIMER); - } - break; - case SC_CURSEDCIRCLE_TARGET: - if( tsc && tsc->data[SC_CURSEDCIRCLE_TARGET] && tsc->data[SC_CURSEDCIRCLE_TARGET]->val2 == src->id ) { - clif->bladestop(bl, tsc->data[SC_CURSEDCIRCLE_TARGET]->val2, 0); - status_change_end(bl, type, INVALID_TIMER); - } - break; + break; + case SC_RG_CCONFINE_M: + //Lock char has released the hold on everyone... + if (tsc && tsc->data[SC_RG_CCONFINE_S] && tsc->data[SC_RG_CCONFINE_S]->val2 == src->id) { + tsc->data[SC_RG_CCONFINE_S]->val2 = 0; + status_change_end(bl, SC_RG_CCONFINE_S, INVALID_TIMER); + } + break; + case SC_CURSEDCIRCLE_TARGET: + if( tsc && tsc->data[SC_CURSEDCIRCLE_TARGET] && tsc->data[SC_CURSEDCIRCLE_TARGET]->val2 == src->id ) { + clif->bladestop(bl, tsc->data[SC_CURSEDCIRCLE_TARGET]->val2, 0); + status_change_end(bl, type, INVALID_TIMER); + } + break; } return 0; } +int status_get_total_def(struct block_list *src) { return status->get_status_data(src)->def2 + (short)status->get_def(src); } +int status_get_total_mdef(struct block_list *src) { return status->get_status_data(src)->mdef2 + (short)status_get_mdef(src); } +int status_get_weapon_atk(struct block_list *bl, struct weapon_atk *watk, int flag) { #ifdef RENEWAL -int status_get_total_def(struct block_list *src){ return status_get_status_data(src)->def2 + (short)status_get_def(src); } -int status_get_total_mdef(struct block_list *src){ return status_get_status_data(src)->mdef2 + (short)status_get_mdef(src); } -int status_get_weapon_atk(struct block_list *bl, struct weapon_atk *watk, int flag){ int min = 0, max = 0, dstr; float strdex_bonus, variance; - struct status_change *sc = status_get_sc(bl); - + struct status_change *sc = status->get_sc(bl); + if ( bl->type == BL_PC && watk->atk ){ - if ( flag&16 ) + if ( flag&2 ) dstr = status_get_dex(bl); else dstr = status_get_str(bl); - + variance = 5.0f * watk->atk * watk->wlv / 100.0f; strdex_bonus = watk->atk * dstr / 200.0f; - min = (watk->atk - (int)(variance + strdex_bonus)) + watk->atk2; - max = (watk->atk + (int)(variance + strdex_bonus)) + watk->atk2; + min = (int)(watk->atk - variance + strdex_bonus) + watk->atk2; + max = (int)(watk->atk + variance + strdex_bonus) + watk->atk2; }else if( watk->atk ){ min = watk->atk * 80 / 100; max = watk->atk * 120 / 100; @@ -10851,152 +11371,218 @@ int status_get_weapon_atk(struct block_list *bl, struct weapon_atk *watk, int fl else max = min; } - - if( bl->type == BL_PC && ((TBL_PC*)bl)->right_weapon.overrefine > 0) + + if( bl->type == BL_PC && ((TBL_PC*)bl)->right_weapon.overrefine > 0 && !(flag&2) ) max += rnd()%((TBL_PC*)bl)->right_weapon.overrefine + 1; - max = status_calc_watk(bl, sc, max, false); + max = status->calc_watk(bl, sc, max, false); return max; -} +#else + return 0; #endif +} -#define GETRANDMATK(){\ - if( status->matk_max > status->matk_min )\ - return status->matk_min + rnd()%(status->matk_max - status->matk_min);\ - else\ - return status->matk_min;\ +/** + * Gets a random matk value depending on min matk and max matk + **/ +unsigned short status_get_rand_matk( unsigned short matk_max, unsigned short matk_min ) { + if( matk_max > matk_min ) + return matk_min + rnd()%(matk_max - matk_min); + else + return matk_min; } -/*========================================== - * flag [malufett] - * 0 - update matk values - * 1 - get matk w/o SC bonuses - * 2 - get modified matk - * 3 - get matk w/o eatk & SC bonuses - *------------------------------------------*/ -int status_get_matk(struct block_list *bl, int flag){ - struct status_data *status; +/** + * Get bl's matk_max and matk_min values depending on flag + * @param flag + * 0 - Get MATK + * 1 - Get MATK w/o SC bonuses + * 3 - Get MATK w/o EATK & SC bonuses + **/ +void status_get_matk_sub( struct block_list *bl, int flag, unsigned short *matk_max, unsigned short *matk_min ) { + struct status_data *st; struct status_change *sc; struct map_session_data *sd; if( bl == NULL ) - return 1; + return; - status = status_get_status_data(bl); - sc = status_get_sc(bl); - sd = BL_CAST(BL_PC, bl); + if( flag != 0 && flag != 1 && flag != 3 ) { + ShowError("status_get_matk_sub: Unknown flag %d!\n", flag); + return; + } - if( flag == 2 ) // just get matk - GETRANDMATK(); + st = status->get_status_data(bl); + sc = status->get_sc(bl); + sd = BL_CAST(BL_PC, bl); -#ifndef RENEWAL - status->matk_min = status_base_matk_min(status) + (sd?sd->bonus.ematk:0); - status->matk_max = status_base_matk_max(status) + (sd?sd->bonus.ematk:0); -#else +#ifdef RENEWAL /** * RE MATK Formula (from irowiki:http://irowiki.org/wiki/MATK) * MATK = (sMATK + wMATK + eMATK) * Multiplicative Modifiers **/ - status->matk_min = status_base_matk(status, status_get_lv(bl)); - + *matk_min = status->base_matk(st, status->get_lv(bl)); + // Any +MATK you get from skills and cards, including cards in weapon, is added here. if( sd && sd->bonus.ematk > 0 && flag != 3 ) - status->matk_min += sd->bonus.ematk; - if( flag != 3 ) - status->matk_min = status_calc_ematk(bl, sc, status->matk_min); + *matk_min += sd->bonus.ematk; + if( flag != 3 ) + *matk_min = status->calc_ematk(bl, sc, *matk_min); - status->matk_max = status->matk_min; + *matk_max = *matk_min; //This is the only portion in MATK that varies depending on the weapon level and refinement rate. - if( bl->type&BL_PC && (status->rhw.matk + status->lhw.matk) > 0 ){ - int wMatk = status->rhw.matk + status->lhw.matk; // Left and right matk stacks - int variance = wMatk * status->rhw.wlv / 10; // Only use right hand weapon level - status->matk_min += wMatk - variance; - status->matk_max += wMatk + variance; - }else if( bl->type&BL_MOB ){ - status->matk_min = status->matk_max = status_get_int(bl) + status_get_lv(bl); - status->matk_min += 70 * ((TBL_MOB*)bl)->status.rhw.atk2 / 100; - status->matk_max += 130 * ((TBL_MOB*)bl)->status.rhw.atk2 / 100; - } + if( bl->type&BL_PC && (st->rhw.matk + st->lhw.matk) > 0 ) { + int wMatk = st->rhw.matk + st->lhw.matk; // Left and right matk stacks + int variance = wMatk * st->rhw.wlv / 10; // Only use right hand weapon level + *matk_min += wMatk - variance; + *matk_max += wMatk + variance; + } else if( bl->type&BL_MOB ) { + *matk_min = *matk_max = status_get_int(bl) + status->get_lv(bl); + *matk_min += 70 * ((TBL_MOB*)bl)->status.rhw.atk2 / 100; + *matk_max += 130 * ((TBL_MOB*)bl)->status.rhw.atk2 / 100; + } +#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); #endif - if (bl->type&BL_PC && sd->matk_rate != 100) { - status->matk_max = status->matk_max * sd->matk_rate/100; - status->matk_min = status->matk_min * sd->matk_rate/100; + + if (sd && sd->matk_rate != 100) { + *matk_max = (*matk_max) * sd->matk_rate/100; + *matk_min = (*matk_min) * sd->matk_rate/100; } if ((bl->type&BL_HOM && battle_config.hom_setting&0x20) //Hom Min Matk is always the same as Max Matk || (sc && sc->data[SC_RECOGNIZEDSPELL])) - status->matk_min = status->matk_max; + *matk_min = *matk_max; #ifdef RENEWAL - if( sd && sd->right_weapon.overrefine > 0){ - status->matk_min++; - status->matk_max += sd->right_weapon.overrefine - 1; + if( sd && sd->right_weapon.overrefine > 0 ) { + (*matk_min)++; + *matk_max += sd->right_weapon.overrefine - 1; } #endif + return; +} - if( flag ) // get unmodified from sc matk - GETRANDMATK(); +/** + * Get bl's matk value depending on flag + * @param flag [malufett] + * 1 - Get MATK w/o SC bonuses + * 2 - Get modified MATK + * 3 - Get MATK w/o eATK & SC bonuses + * @retval 1 failure + * @retval MATK success + * + * Shouldn't change _any_ value! [Panikon] + **/ +int status_get_matk( struct block_list *bl, int flag ) { + struct status_data *st; + unsigned short matk_max, matk_min; - status->matk_min = status_calc_matk(bl, sc, status->matk_min, true); - status->matk_max = status_calc_matk(bl, sc, status->matk_max, true); + if( bl == NULL ) + return 1; - return 0; + if( flag < 1 || flag > 3 ) { + ShowError("status_get_matk: Unknown flag %d!\n", flag); + return 1; + } + + if( (st = status->get_status_data(bl)) == NULL ) + return 0; + + // Just get matk + if( flag == 2 ) + return status_get_rand_matk(st->matk_max, st->matk_min); + + status_get_matk_sub( bl, flag, &matk_max, &matk_min ); + + // Get unmodified from sc matk + return status_get_rand_matk(matk_max, matk_min); +} + +/** + * Updates bl's MATK values + **/ +void status_update_matk( struct block_list *bl ) { + struct status_data *st; + struct status_change *sc; + unsigned short matk_max, matk_min; + + if( bl == NULL ) + return; + + if( (st = status->get_status_data(bl)) == NULL ) + return; + + if( (sc = status->get_sc(bl)) == NULL ) + return; + + status_get_matk_sub( bl, 0, &matk_max, &matk_min ); + + // Update matk + st->matk_min = status->calc_matk(bl, sc, matk_min, true); + st->matk_max = status->calc_matk(bl, sc, matk_max, true); + + return; } /*========================================== - * Clears buffs/debuffs of a character. - * type&1 -> buffs, type&2 -> debuffs - * type&4 -> especific debuffs(implemented with refresh) - *------------------------------------------*/ -int status_change_clear_buffs (struct block_list* bl, int type) -{ +* Clears buffs/debuffs of a character. +* type&1 -> buffs, type&2 -> debuffs +* type&4 -> especific debuffs(implemented with refresh) +*------------------------------------------*/ +int status_change_clear_buffs (struct block_list* bl, int type) { int i; - struct status_change *sc= status_get_sc(bl); + struct status_change *sc= status->get_sc(bl); if (!sc || !sc->count) return 0; - if (type&6) //Debuffs - for (i = SC_COMMON_MIN; i <= SC_COMMON_MAX; i++) - status_change_end(bl, (sc_type)i, INVALID_TIMER); - - for( i = SC_COMMON_MAX+1; i < SC_MAX; i++ ) - { - if( !sc->data[i] || !status_get_sc_type(i) ) - continue; + if (type&6) //Debuffs + for (i = SC_COMMON_MIN; i <= SC_COMMON_MAX; i++) + status_change_end(bl, (sc_type)i, INVALID_TIMER); - if( type&1 && !(status_get_sc_type(i)&SC_BUFF) ) + for( i = SC_COMMON_MAX+1; i < SC_MAX; i++ ) { + if( !sc->data[i] || !status->get_sc_type(i) ) continue; - if( type&2 && !(status_get_sc_type(i)&SC_DEBUFF) ) + if( type&3 && !(status->get_sc_type(i)&SC_BUFF) && !(status->get_sc_type(i)&SC_DEBUFF) ) continue; + if( type < 3 ) { + if( type&1 && !(status->get_sc_type(i)&SC_BUFF) ) + continue; + if( type&2 && !(status->get_sc_type(i)&SC_DEBUFF) ) + continue; + } switch (i) { - case SC_DEEP_SLEEP: - case SC_FROSTMISTY: - case SC_CRYSTALIZE: - case SC_TOXIN: - case SC_PARALYSE: - case SC_VENOMBLEED: - case SC_MAGICMUSHROOM: - case SC_DEATHHURT: - case SC_PYREXIA: - case SC_OBLIVIONCURSE: - case SC_LEECHESEND: - case SC_MARSHOFABYSS: - case SC_MANDRAGORA: - if(!(type&4)) - continue; - break; - case SC__BLOODYLUST: - case SC_BERSERK: - case SC_SATURDAY_NIGHT_FEVER: - if(type&4) - continue; - sc->data[i]->val2 = 0; - break; + case SC_DEEP_SLEEP: + case SC_FROSTMISTY: + case SC_COLD: + case SC_TOXIN: + case SC_PARALYSE: + case SC_VENOMBLEED: + case SC_MAGICMUSHROOM: + case SC_DEATHHURT: + case SC_PYREXIA: + case SC_OBLIVIONCURSE: + case SC_LEECHESEND: + case SC_MARSHOFABYSS: + case SC_MANDRAGORA: + if(!(type&4)) + continue; + break; + case SC_BERSERK: + if(type&4) + continue; + sc->data[i]->val2 = 0; + break; + default: + if(type&4) + continue; + } status_change_end(bl, (sc_type)i, INVALID_TIMER); } @@ -11005,15 +11591,14 @@ int status_change_clear_buffs (struct block_list* bl, int type) int status_change_spread( struct block_list *src, struct block_list *bl ) { int i, flag = 0; - struct status_change *sc = status_get_sc(src); - const struct TimerData *timer; - unsigned int tick; + struct status_change *sc = status->get_sc(src); + int64 tick; struct status_change_data data; if( !sc || !sc->count ) return 0; - tick = iTimer->gettick(); + tick = timer->gettick(); for( i = SC_COMMON_MIN; i < SC_MAX; i++ ) { if( !sc->data[i] || i == SC_COMMON_MAX ) @@ -11022,70 +11607,69 @@ int status_change_spread( struct block_list *src, struct block_list *bl ) { switch( i ) { //Debuffs that can be spreaded. // NOTE: We'll add/delte SCs when we are able to confirm it. - case SC_CURSE: - case SC_SILENCE: - case SC_CONFUSION: - case SC_BLIND: - case SC_NOCHAT: - case SC_ILLUSION: - case SC_CRUCIS: - case SC_DEC_AGI: - case SC_SLOWDOWN: - case SC_MINDBREAKER: - case SC_DC_WINKCHARM: - case SC_STOP: - case SC_ORCISH: + case SC_CURSE: + case SC_SILENCE: + case SC_CONFUSION: + case SC_BLIND: + case SC_NOCHAT: + case SC_ILLUSION: + case SC_CRUCIS: + case SC_DEC_AGI: + case SC_SLOWDOWN: + case SC_MINDBREAKER: + case SC_DC_WINKCHARM: + case SC_STOP: + case SC_ORCISH: //case SC_NOEQUIPWEAPON://Omg I got infected and had the urge to strip myself physically. //case SC_NOEQUIPSHIELD://No this is stupid and shouldnt be spreadable at all. //case SC_NOEQUIPARMOR:// Disabled until I can confirm if it does or not. [Rytech] //case SC_NOEQUIPHELM: //case SC__STRIPACCESSARY: - case SC_WUGBITE: - case SC_FROSTMISTY: - case SC_VENOMBLEED: - case SC_DEATHHURT: - case SC_PARALYSE: - if( sc->data[i]->timer != INVALID_TIMER ) { - timer = iTimer->get_timer(sc->data[i]->timer); - if (timer == NULL || timer->func != status_change_timer || DIFF_TICK(timer->tick,tick) < 0) - continue; - data.tick = DIFF_TICK(timer->tick,tick); - } else - data.tick = INVALID_TIMER; - break; - // Special cases - case SC_POISON: - case SC_DPOISON: - data.tick = sc->data[i]->val3 * 1000; - break; - case SC_FEAR: - case SC_LEECHESEND: - data.tick = sc->data[i]->val4 * 1000; - break; - case SC_BURNING: - data.tick = sc->data[i]->val4 * 2000; - break; - case SC_PYREXIA: - case SC_OBLIVIONCURSE: - data.tick = sc->data[i]->val4 * 3000; - break; - case SC_MAGICMUSHROOM: - data.tick = sc->data[i]->val4 * 4000; - break; - case SC_TOXIN: - case SC_BLOODING: - data.tick = sc->data[i]->val4 * 10000; - break; - default: + case SC_WUGBITE: + case SC_FROSTMISTY: + case SC_VENOMBLEED: + case SC_DEATHHURT: + case SC_PARALYSE: + if( sc->data[i]->timer != INVALID_TIMER ) { + const struct TimerData *td = timer->get(sc->data[i]->timer); + if (td == NULL || td->func != status->change_timer || DIFF_TICK(td->tick,tick) < 0) continue; - break; + data.tick = DIFF_TICK32(td->tick,tick); + } else + data.tick = INVALID_TIMER; + break; + // Special cases + case SC_POISON: + case SC_DPOISON: + data.tick = sc->data[i]->val3 * 1000; + break; + case SC_FEAR: + case SC_LEECHESEND: + data.tick = sc->data[i]->val4 * 1000; + break; + case SC_BURNING: + data.tick = sc->data[i]->val4 * 2000; + break; + case SC_PYREXIA: + case SC_OBLIVIONCURSE: + data.tick = sc->data[i]->val4 * 3000; + break; + case SC_MAGICMUSHROOM: + data.tick = sc->data[i]->val4 * 4000; + break; + case SC_TOXIN: + case SC_BLOODING: + data.tick = sc->data[i]->val4 * 10000; + break; + default: + continue; } - if( i ){ + if( i ) { data.val1 = sc->data[i]->val1; data.val2 = sc->data[i]->val2; data.val3 = sc->data[i]->val3; data.val4 = sc->data[i]->val4; - status_change_start(bl,(sc_type)i,10000,data.val1,data.val2,data.val3,data.val4,data.tick,1|2|8); + status->change_start(src,bl,(sc_type)i,10000,data.val1,data.val2,data.val3,data.val4,data.tick,1|2|8); flag = 1; } } @@ -11094,11 +11678,9 @@ int status_change_spread( struct block_list *src, struct block_list *bl ) { } //Natural regen related stuff. -static unsigned int natural_heal_prev_tick,natural_heal_diff_tick; -static int status_natural_heal(struct block_list* bl, va_list args) -{ +int status_natural_heal(struct block_list* bl, va_list args) { struct regen_data *regen; - struct status_data *status; + struct status_data *st; struct status_change *sc; struct unit_data *ud; struct view_data *vd = NULL; @@ -11106,64 +11688,66 @@ static int status_natural_heal(struct block_list* bl, va_list args) struct map_session_data *sd; int val,rate,bonus = 0,flag; - regen = status_get_regen_data(bl); + regen = status->get_regen_data(bl); if (!regen) return 0; - status = status_get_status_data(bl); - sc = status_get_sc(bl); + st = status->get_status_data(bl); + sc = status->get_sc(bl); if (sc && !sc->count) sc = NULL; sd = BL_CAST(BL_PC,bl); flag = regen->flag; - if (flag&RGN_HP && (status->hp >= status->max_hp || regen->state.block&1)) + if (flag&RGN_HP && (st->hp >= st->max_hp || regen->state.block&1)) flag&=~(RGN_HP|RGN_SHP); - if (flag&RGN_SP && (status->sp >= status->max_sp || regen->state.block&2)) + if (flag&RGN_SP && (st->sp >= st->max_sp || regen->state.block&2)) flag&=~(RGN_SP|RGN_SSP); - if (flag && ( - status_isdead(bl) || - (sc && (sc->option&(OPTION_HIDE|OPTION_CLOAK|OPTION_CHASEWALK) || sc->data[SC__INVISIBILITY])) - )) + if (flag + && (status->isdead(bl) + || (sc && (sc->option&(OPTION_HIDE|OPTION_CLOAK|OPTION_CHASEWALK) || sc->data[SC__INVISIBILITY])) + ) + ) flag=0; if (sd) { if (sd->hp_loss.value || sd->sp_loss.value) - pc->bleeding(sd, natural_heal_diff_tick); + pc->bleeding(sd, status->natural_heal_diff_tick); if (sd->hp_regen.value || sd->sp_regen.value) - pc->regen(sd, natural_heal_diff_tick); + pc->regen(sd, status->natural_heal_diff_tick); } - if(flag&(RGN_SHP|RGN_SSP) && regen->ssregen && - (vd = status_get_viewdata(bl)) && vd->dead_sit == 2) - { //Apply sitting regen bonus. + if (flag&(RGN_SHP|RGN_SSP) + && regen->ssregen + && (vd = status->get_viewdata(bl)) + && vd->dead_sit == 2 + ) { + //Apply sitting regen bonus. sregen = regen->ssregen; - if(flag&(RGN_SHP)) - { //Sitting HP regen - val = natural_heal_diff_tick * sregen->rate.hp; + if(flag&(RGN_SHP)) { + //Sitting HP regen + val = status->natural_heal_diff_tick * sregen->rate.hp; if (regen->state.overweight) val>>=1; //Half as fast when overweight. sregen->tick.hp += val; - while(sregen->tick.hp >= (unsigned int)battle_config.natural_heal_skill_interval) - { + while(sregen->tick.hp >= (unsigned int)battle_config.natural_heal_skill_interval) { sregen->tick.hp -= battle_config.natural_heal_skill_interval; - if(status_heal(bl, sregen->hp, 0, 3) < sregen->hp) - { //Full + if(status->heal(bl, sregen->hp, 0, 3) < sregen->hp) { + //Full flag&=~(RGN_HP|RGN_SHP); break; } } } - if(flag&(RGN_SSP)) - { //Sitting SP regen - val = natural_heal_diff_tick * sregen->rate.sp; + if(flag&(RGN_SSP)) { + //Sitting SP regen + val = status->natural_heal_diff_tick * sregen->rate.sp; if (regen->state.overweight) val>>=1; //Half as fast when overweight. sregen->tick.sp += val; - while(sregen->tick.sp >= (unsigned int)battle_config.natural_heal_skill_interval) - { + while(sregen->tick.sp >= (unsigned int)battle_config.natural_heal_skill_interval) { sregen->tick.sp -= battle_config.natural_heal_skill_interval; - if(status_heal(bl, 0, sregen->sp, 3) < sregen->sp) - { //Full + if(status->heal(bl, 0, sregen->sp, 3) < sregen->sp) { + //Full flag&=~(RGN_SP|RGN_SSP); break; } @@ -11174,10 +11758,9 @@ static int status_natural_heal(struct block_list* bl, va_list args) if (flag && regen->state.overweight) flag=0; - ud = unit_bl2ud(bl); + ud = unit->bl2ud(bl); - if (flag&(RGN_HP|RGN_SHP|RGN_SSP) && ud && ud->walktimer != INVALID_TIMER) - { + if (flag&(RGN_HP|RGN_SHP|RGN_SSP) && ud && ud->walktimer != INVALID_TIMER) { flag&=~(RGN_SHP|RGN_SSP); if(!regen->state.walk) flag&=~RGN_HP; @@ -11186,9 +11769,8 @@ static int status_natural_heal(struct block_list* bl, va_list args) if (!flag) return 0; - if (flag&(RGN_HP|RGN_SP)) - { - if(!vd) vd = status_get_viewdata(bl); + if (flag&(RGN_HP|RGN_SP)) { + if(!vd) vd = status->get_viewdata(bl); if(vd && vd->dead_sit == 2) bonus++; if(regen->state.gc) @@ -11196,9 +11778,8 @@ static int status_natural_heal(struct block_list* bl, va_list args) } //Natural Hp regen - if (flag&RGN_HP) - { - rate = natural_heal_diff_tick*(regen->rate.hp+bonus); + if (flag&RGN_HP) { + rate = status->natural_heal_diff_tick*(regen->rate.hp+bonus); if (ud && ud->walktimer != INVALID_TIMER) rate/=2; // Homun HP regen fix (they should regen as if they were sitting (twice as fast) @@ -11206,35 +11787,32 @@ static int status_natural_heal(struct block_list* bl, va_list args) regen->tick.hp += rate; - if(regen->tick.hp >= (unsigned int)battle_config.natural_healhp_interval) - { + if(regen->tick.hp >= (unsigned int)battle_config.natural_healhp_interval) { val = 0; do { val += regen->hp; regen->tick.hp -= battle_config.natural_healhp_interval; } while(regen->tick.hp >= (unsigned int)battle_config.natural_healhp_interval); - if (status_heal(bl, val, 0, 1) < val) + if (status->heal(bl, val, 0, 1) < val) flag&=~RGN_SHP; //full. } } //Natural SP regen - if(flag&RGN_SP) - { - rate = natural_heal_diff_tick*(regen->rate.sp+bonus); + if(flag&RGN_SP) { + rate = status->natural_heal_diff_tick*(regen->rate.sp+bonus); // Homun SP regen fix (they should regen as if they were sitting (twice as fast) if(bl->type==BL_HOM) rate *=2; regen->tick.sp += rate; - if(regen->tick.sp >= (unsigned int)battle_config.natural_healsp_interval) - { + if(regen->tick.sp >= (unsigned int)battle_config.natural_healsp_interval) { val = 0; do { val += regen->sp; regen->tick.sp -= battle_config.natural_healsp_interval; } while(regen->tick.sp >= (unsigned int)battle_config.natural_healsp_interval); - if (status_heal(bl, 0, val, 1) < val) + if (status->heal(bl, 0, val, 1) < val) flag&=~RGN_SSP; //full. } } @@ -11245,40 +11823,38 @@ static int status_natural_heal(struct block_list* bl, va_list args) //Skill regen sregen = regen->sregen; - if(flag&RGN_SHP) - { //Skill HP regen - sregen->tick.hp += natural_heal_diff_tick * sregen->rate.hp; + if(flag&RGN_SHP) { + //Skill HP regen + sregen->tick.hp += status->natural_heal_diff_tick * sregen->rate.hp; - while(sregen->tick.hp >= (unsigned int)battle_config.natural_heal_skill_interval) - { + while(sregen->tick.hp >= (unsigned int)battle_config.natural_heal_skill_interval) { sregen->tick.hp -= battle_config.natural_heal_skill_interval; - if(status_heal(bl, sregen->hp, 0, 3) < sregen->hp) + if(status->heal(bl, sregen->hp, 0, 3) < sregen->hp) break; //Full } } - if(flag&RGN_SSP) - { //Skill SP regen - sregen->tick.sp += natural_heal_diff_tick * sregen->rate.sp; - while(sregen->tick.sp >= (unsigned int)battle_config.natural_heal_skill_interval) - { + if(flag&RGN_SSP) { + //Skill SP regen + sregen->tick.sp += status->natural_heal_diff_tick * sregen->rate.sp; + while(sregen->tick.sp >= (unsigned int)battle_config.natural_heal_skill_interval) { val = sregen->sp; if (sd && sd->state.doridori) { val*=2; sd->state.doridori = 0; if ((rate = pc->checkskill(sd,TK_SPTIME))) - sc_start(bl,status_skill2sc(TK_SPTIME), - 100,rate,skill->get_time(TK_SPTIME, rate)); - if ( - (sd->class_&MAPID_UPPERMASK) == MAPID_STAR_GLADIATOR && - rnd()%10000 < battle_config.sg_angel_skill_ratio - ) { //Angel of the Sun/Moon/Star + sc_start(bl,bl,status->skill2sc(TK_SPTIME), + 100,rate,skill->get_time(TK_SPTIME, rate)); + if ((sd->class_&MAPID_UPPERMASK) == MAPID_STAR_GLADIATOR + &&rnd()%10000 < battle_config.sg_angel_skill_ratio + ) { + //Angel of the Sun/Moon/Star clif->feel_hate_reset(sd); pc->resethate(sd); pc->resetfeel(sd); } } sregen->tick.sp -= battle_config.natural_heal_skill_interval; - if(status_heal(bl, 0, val, 3) < val) + if(status->heal(bl, 0, val, 3) < val) break; //Full } } @@ -11286,26 +11862,26 @@ static int status_natural_heal(struct block_list* bl, va_list args) } //Natural heal main timer. -static int status_natural_heal_timer(int tid, unsigned int tick, int id, intptr_t data) -{ - natural_heal_diff_tick = DIFF_TICK(tick,natural_heal_prev_tick); - iMap->map_foreachregen(status_natural_heal); - natural_heal_prev_tick = tick; +int status_natural_heal_timer(int tid, int64 tick, int id, intptr_t data) { + // This difference is always positive and lower than UINT_MAX (~24 days) + status->natural_heal_diff_tick = (unsigned int)cap_value(DIFF_TICK(tick,status->natural_heal_prev_tick), 0, UINT_MAX); + map->foreachregen(status->natural_heal); + status->natural_heal_prev_tick = tick; return 0; } /** - * Get the chance to upgrade a piece of equipment. - * @param wlv The weapon type of the item to refine (see see enum refine_type) - * @param refine The target refine level - * @return The chance to refine the item, in percent (0~100) - **/ +* Get the chance to upgrade a piece of equipment. +* @param wlv The weapon type of the item to refine (see see enum refine_type) +* @param refine The target refine level +* @return The chance to refine the item, in percent (0~100) +**/ int status_get_refine_chance(enum refine_type wlv, int refine) { if ( refine < 0 || refine >= MAX_REFINE) - return 0; + return 0; - return refine_info[wlv].chance[refine]; + return status->refine_info[wlv].chance[refine]; } int status_get_sc_type(sc_type type) { @@ -11313,17 +11889,17 @@ int status_get_sc_type(sc_type type) { if( type <= SC_NONE || type >= SC_MAX ) return 0; - return sc_conf[type]; + return status->sc_conf[type]; } /*------------------------------------------ - * DB reading. - * job_db1.txt - weight, hp, sp, aspd - * job_db2.txt - job level stat bonuses - * size_fix.txt - size adjustment table for weapons - * refine_db.txt - refining data table - *------------------------------------------*/ -static bool status_readdb_job1(char* fields[], int columns, int current) +* DB reading. +* job_db1.txt - weight, hp, sp, aspd +* job_db2.txt - job level stat bonuses +* size_fix.txt - size adjustment table for weapons +* refine_db.txt - refining data table +*------------------------------------------*/ +bool status_readdb_job1(char* fields[], int columns, int current) {// Job-specific values (weight, HP, SP, ASPD) int idx, class_; unsigned int i; @@ -11337,22 +11913,22 @@ static bool status_readdb_job1(char* fields[], int columns, int current) } idx = pc->class2idx(class_); - max_weight_base[idx] = atoi(fields[1]); - hp_coefficient[idx] = atoi(fields[2]); - hp_coefficient2[idx] = atoi(fields[3]); - sp_coefficient[idx] = atoi(fields[4]); + status->max_weight_base[idx] = atoi(fields[1]); + status->hp_coefficient[idx] = atoi(fields[2]); + status->hp_coefficient2[idx] = atoi(fields[3]); + status->sp_coefficient[idx] = atoi(fields[4]); #ifdef RENEWAL_ASPD for(i = 0; i <= MAX_WEAPON_TYPE; i++) #else for(i = 0; i < MAX_WEAPON_TYPE; i++) #endif { - aspd_base[idx][i] = atoi(fields[i+5]); + status->aspd_base[idx][i] = atoi(fields[i+5]); } return true; } -static bool status_readdb_job2(char* fields[], int columns, int current) +bool status_readdb_job2(char* fields[], int columns, int current) { int idx, class_, i; @@ -11367,23 +11943,23 @@ static bool status_readdb_job2(char* fields[], int columns, int current) for(i = 1; i < columns; i++) { - job_bonus[idx][i-1] = atoi(fields[i]); + status->job_bonus[idx][i-1] = atoi(fields[i]); } return true; } -static bool status_readdb_sizefix(char* fields[], int columns, int current) +bool status_readdb_sizefix(char* fields[], int columns, int current) { unsigned int i; for(i = 0; i < MAX_WEAPON_TYPE; i++) { - atkmods[current][i] = atoi(fields[i]); + status->atkmods[current][i] = atoi(fields[i]); } return true; } -static bool status_readdb_refine(char* fields[], int columns, int current) +bool status_readdb_refine(char* fields[], int columns, int current) { int i, bonus_per_level, random_bonus, random_bonus_start_level; @@ -11405,68 +11981,65 @@ static bool status_readdb_refine(char* fields[], int columns, int current) *delim = '\0'; - refine_info[current].chance[i] = atoi(fields[4+i]); + status->refine_info[current].chance[i] = atoi(fields[4+i]); if (i >= random_bonus_start_level - 1) - refine_info[current].randombonus_max[i] = random_bonus * (i - random_bonus_start_level + 2); + status->refine_info[current].randombonus_max[i] = random_bonus * (i - random_bonus_start_level + 2); - refine_info[current].bonus[i] = bonus_per_level + atoi(delim+1); + status->refine_info[current].bonus[i] = bonus_per_level + atoi(delim+1); if (i > 0) - refine_info[current].bonus[i] += refine_info[current].bonus[i-1]; + status->refine_info[current].bonus[i] += status->refine_info[current].bonus[i-1]; } return true; } -static bool status_readdb_scconfig(char* fields[], int columns, int current) -{ +bool status_readdb_scconfig(char* fields[], int columns, int current) { int val = 0; char* type = fields[0]; - if( !script_get_constant(type, &val) ){ + if( !script->get_constant(type, &val) ){ ShowWarning("status_readdb_sc_conf: Invalid status type %s specified.\n", type); return false; } - sc_conf[val] = (int)strtol(fields[1], NULL, 0); + status->sc_conf[val] = (int)strtol(fields[1], NULL, 0); return true; } -/* -* Read status db -* job1.txt -* job2.txt -* size_fixe.txt -* refine_db.txt -*/ +/** + * Read status db + * job1.txt + * job2.txt + * size_fixe.txt + * refine_db.txt + **/ int status_readdb(void) { int i, j; // initialize databases to default // - - // reset job_db1.txt data - memset(max_weight_base, 0, sizeof(max_weight_base)); - memset(hp_coefficient, 0, sizeof(hp_coefficient)); - memset(hp_coefficient2, 0, sizeof(hp_coefficient2)); - memset(sp_coefficient, 0, sizeof(sp_coefficient)); - memset(aspd_base, 0, sizeof(aspd_base)); - // reset job_db2.txt data - memset(job_bonus,0,sizeof(job_bonus)); // Job-specific stats bonus - + if( runflag == MAPSERVER_ST_RUNNING ) {//not necessary during boot + // reset job_db1.txt data + memset(status->max_weight_base, 0, sizeof(status->max_weight_base)); + memset(status->hp_coefficient, 0, sizeof(status->hp_coefficient)); + memset(status->hp_coefficient2, 0, sizeof(status->hp_coefficient2)); + memset(status->sp_coefficient, 0, sizeof(status->sp_coefficient)); + memset(status->aspd_base, 0, sizeof(status->aspd_base)); + // reset job_db2.txt data + memset(status->job_bonus,0,sizeof(status->job_bonus)); // Job-specific stats bonus + } // size_fix.txt - for(i=0;i<ARRAYLENGTH(atkmods);i++) - for(j=0;j<MAX_WEAPON_TYPE;j++) - atkmods[i][j]=100; + for(i = 0; i < ARRAYLENGTH(status->atkmods); i++) + for(j = 0; j < MAX_WEAPON_TYPE; j++) + status->atkmods[i][j] = 100; // refine_db.txt - for(i=0;i<ARRAYLENGTH(refine_info);i++) - { - for(j=0;j<MAX_REFINE; j++) - { - refine_info[i].chance[j] = 100; - refine_info[i].bonus[j] = 0; - refine_info[i].randombonus_max[j] = 0; + for(i=0;i<ARRAYLENGTH(status->refine_info);i++) { + for(j=0;j<MAX_REFINE; j++) { + status->refine_info[i].chance[j] = 100; + status->refine_info[i].bonus[j] = 0; + status->refine_info[i].randombonus_max[j] = 0; } } @@ -11475,36 +12048,202 @@ int status_readdb(void) #ifdef RENEWAL_ASPD - sv->readdb(iMap->db_path, "re/job_db1.txt", ',', 6+MAX_WEAPON_TYPE, 6+MAX_WEAPON_TYPE, -1, &status_readdb_job1); + sv->readdb(map->db_path, "re/job_db1.txt", ',', 6+MAX_WEAPON_TYPE, 6+MAX_WEAPON_TYPE, -1, status->readdb_job1); #else - sv->readdb(iMap->db_path, "pre-re/job_db1.txt", ',', 5+MAX_WEAPON_TYPE, 5+MAX_WEAPON_TYPE, -1, &status_readdb_job1); + sv->readdb(map->db_path, "pre-re/job_db1.txt", ',', 5+MAX_WEAPON_TYPE, 5+MAX_WEAPON_TYPE, -1, status->readdb_job1); #endif - sv->readdb(iMap->db_path, "job_db2.txt", ',', 1, 1+MAX_LEVEL, -1, &status_readdb_job2); - sv->readdb(iMap->db_path, "size_fix.txt", ',', MAX_WEAPON_TYPE, MAX_WEAPON_TYPE, ARRAYLENGTH(atkmods), &status_readdb_sizefix); - sv->readdb(iMap->db_path, DBPATH"refine_db.txt", ',', 4+MAX_REFINE, 4+MAX_REFINE, ARRAYLENGTH(refine_info), &status_readdb_refine); - sv->readdb(iMap->db_path, "sc_config.txt", ',', 2, 2, SC_MAX, &status_readdb_scconfig); + sv->readdb(map->db_path, "job_db2.txt", ',', 1, 1+MAX_LEVEL, -1, status->readdb_job2); + sv->readdb(map->db_path, "size_fix.txt", ',', MAX_WEAPON_TYPE, MAX_WEAPON_TYPE, ARRAYLENGTH(status->atkmods), status->readdb_sizefix); + sv->readdb(map->db_path, DBPATH"refine_db.txt", ',', 4+MAX_REFINE, 4+MAX_REFINE, ARRAYLENGTH(status->refine_info), status->readdb_refine); + sv->readdb(map->db_path, "sc_config.txt", ',', 2, 2, SC_MAX, status->readdb_scconfig); return 0; } /*========================================== - * Status db init and destroy. - *------------------------------------------*/ -int do_init_status(void) -{ - iTimer->add_timer_func_list(status_change_timer,"status_change_timer"); - iTimer->add_timer_func_list(kaahi_heal_timer,"kaahi_heal_timer"); - iTimer->add_timer_func_list(status_natural_heal_timer,"status_natural_heal_timer"); - initChangeTables(); - initDummyData(); - status_readdb(); - status_calc_sigma(); - natural_heal_prev_tick = iTimer->gettick(); - sc_data_ers = ers_new(sizeof(struct status_change_entry),"status.c::sc_data_ers",ERS_OPT_NONE); - iTimer->add_timer_interval(natural_heal_prev_tick + NATURAL_HEAL_INTERVAL, status_natural_heal_timer, 0, 0, NATURAL_HEAL_INTERVAL); +* Status db init and destroy. +*------------------------------------------*/ +int do_init_status(bool minimal) { + if (minimal) + return 0; + + timer->add_func_list(status->change_timer,"status_change_timer"); + timer->add_func_list(status->kaahi_heal_timer,"status_kaahi_heal_timer"); + timer->add_func_list(status->natural_heal_timer,"status_natural_heal_timer"); + status->initChangeTables(); + status->initDummyData(); + status->readdb(); + status->calc_sigma(); + status->natural_heal_prev_tick = timer->gettick(); + status->data_ers = ers_new(sizeof(struct status_change_entry),"status.c::data_ers",ERS_OPT_NONE); + timer->add_interval(status->natural_heal_prev_tick + NATURAL_HEAL_INTERVAL, status->natural_heal_timer, 0, 0, NATURAL_HEAL_INTERVAL); return 0; } -void do_final_status(void) -{ - ers_destroy(sc_data_ers); +void do_final_status(void) { + ers_destroy(status->data_ers); +} + +/*===================================== +* Default Functions : status.h +* Generated by HerculesInterfaceMaker +* created by Susu +*-------------------------------------*/ +void status_defaults(void) { + status = &status_s; + + /* vars */ + //we need it for new cards 15 Feb 2005, to check if the combo cards are insrerted into the CURRENT weapon only + //to avoid cards exploits + status->current_equip_item_index = 0; //Contains inventory index of an equipped item. To pass it into the EQUP_SCRIPT [Lupus] + status->current_equip_card_id = 0; //To prevent card-stacking (from jA) [Skotlex] + + memset(status->max_weight_base,0,sizeof(status->max_weight_base) + + sizeof(status->hp_coefficient) + + sizeof(status->hp_coefficient2) + + sizeof(status->hp_sigma_val) + + sizeof(status->sp_coefficient) + + sizeof(status->aspd_base) + + sizeof(status->Skill2SCTable) + + sizeof(status->IconChangeTable) + + sizeof(status->ChangeFlagTable) + + sizeof(status->SkillChangeTable) + + sizeof(status->RelevantBLTypes) + + sizeof(status->DisplayType) + + sizeof(status->refine_info) + + sizeof(status->atkmods) + + sizeof(status->job_bonus) + + sizeof(status->sc_conf) + ); + + status->data_ers = NULL; + memset(&status->dummy, 0, sizeof(status->dummy)); + status->natural_heal_prev_tick = 0; + status->natural_heal_diff_tick = 0; + /* funcs */ + status->get_refine_chance = status_get_refine_chance; + // for looking up associated data + status->skill2sc = status_skill2sc; + status->sc2skill = status_sc2skill; + status->sc2scb_flag = status_sc2scb_flag; + status->type2relevant_bl_types = status_type2relevant_bl_types; + status->get_sc_type = status_get_sc_type; + + status->damage = status_damage; + //Define for standard HP/SP skill-related cost triggers (mobs require no HP/SP to use skills) + status->charge = status_charge; + status->percent_change = status_percent_change; + //Used to set the hp/sp of an object to an absolute value (can't kill) + status->set_hp = status_set_hp; + status->set_sp = status_set_sp; + status->heal = status_heal; + status->revive = status_revive; + status->fixed_revive = status_fixed_revive; + status->get_regen_data = status_get_regen_data; + status->get_status_data = status_get_status_data; + status->get_base_status = status_get_base_status; + status->get_name = status_get_name; + status->get_class = status_get_class; + status->get_lv = status_get_lv; + status->get_def = status_get_def; + status->get_speed = status_get_speed; + status->calc_attack_element = status_calc_attack_element; + status->get_party_id = status_get_party_id; + status->get_guild_id = status_get_guild_id; + status->get_emblem_id = status_get_emblem_id; + status->get_mexp = status_get_mexp; + status->get_race2 = status_get_race2; + + status->get_viewdata = status_get_viewdata; + status->set_viewdata = status_set_viewdata; + status->change_init = status_change_init; + status->get_sc = status_get_sc; + + status->isdead = status_isdead; + status->isimmune = status_isimmune; + + status->get_sc_def = status_get_sc_def; + + status->change_start = status_change_start; + status->change_end_ = status_change_end_; + status->kaahi_heal_timer = kaahi_heal_timer; + status->change_timer = status_change_timer; + status->change_timer_sub = status_change_timer_sub; + status->change_clear = status_change_clear; + status->change_clear_buffs = status_change_clear_buffs; + + status->calc_bl_ = status_calc_bl_; + status->calc_mob_ = status_calc_mob_; + status->calc_pet_ = status_calc_pet_; + status->calc_pc_ = status_calc_pc_; + status->calc_homunculus_ = status_calc_homunculus_; + status->calc_mercenary_ = status_calc_mercenary_; + status->calc_elemental_ = status_calc_elemental_; + + status->calc_misc = status_calc_misc; + status->calc_regen = status_calc_regen; + status->calc_regen_rate = status_calc_regen_rate; + + status->check_skilluse = status_check_skilluse; // [Skotlex] + status->check_visibility = status_check_visibility; //[Skotlex] + + status->change_spread = status_change_spread; + + status->calc_def = status_calc_def; + status->calc_def2 = status_calc_def2; + status->calc_mdef = status_calc_mdef; + status->calc_mdef2 = status_calc_mdef2; + status->calc_batk = status_calc_batk; + status->base_matk = status_base_matk; + status->get_weapon_atk = status_get_weapon_atk; + status->get_total_mdef = status_get_total_mdef; + status->get_total_def = status_get_total_def; + + status->get_matk = status_get_matk; + status->update_matk = status_update_matk; + + status->readdb = status_readdb; + status->init = do_init_status; + status->final = do_final_status; + + status->initChangeTables = initChangeTables; + status->initDummyData = initDummyData; + status->base_amotion_pc = status_base_amotion_pc; + status->base_atk = status_base_atk; + status->calc_sigma = status_calc_sigma; + status->base_pc_maxhp = status_base_pc_maxhp; + status->base_pc_maxsp = status_base_pc_maxsp; + status->calc_npc_ = status_calc_npc_; + status->calc_str = status_calc_str; + status->calc_agi = status_calc_agi; + status->calc_vit = status_calc_vit; + status->calc_int = status_calc_int; + status->calc_dex = status_calc_dex; + status->calc_luk = status_calc_luk; + status->calc_watk = status_calc_watk; + status->calc_matk = status_calc_matk; + status->calc_hit = status_calc_hit; + status->calc_critical = status_calc_critical; + status->calc_flee = status_calc_flee; + status->calc_flee2 = status_calc_flee2; + status->calc_speed = status_calc_speed; + status->calc_aspd_rate = status_calc_aspd_rate; + status->calc_dmotion = status_calc_dmotion; + status->calc_aspd = status_calc_aspd; + status->calc_fix_aspd = status_calc_fix_aspd; + status->calc_maxhp = status_calc_maxhp; + status->calc_maxsp = status_calc_maxsp; + status->calc_element = status_calc_element; + status->calc_element_lv = status_calc_element_lv; + status->calc_mode = status_calc_mode; + status->calc_ematk = status_calc_ematk; + status->calc_bl_main = status_calc_bl_main; + status->display_add = status_display_add; + status->display_remove = status_display_remove; + status->natural_heal = status_natural_heal; + status->natural_heal_timer = status_natural_heal_timer; + status->readdb_job1 = status_readdb_job1; + status->readdb_job2 = status_readdb_job2; + status->readdb_sizefix = status_readdb_sizefix; + status->readdb_refine = status_readdb_refine; + status->readdb_scconfig = status_readdb_scconfig; } diff --git a/src/map/status.h b/src/map/status.h index fbce95f17..942f86d7c 100644 --- a/src/map/status.h +++ b/src/map/status.h @@ -1,15 +1,37 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder +// Copyright (c) Hercules Dev Team, licensed under GNU GPL. +// See the LICENSE file +// Portions Copyright (c) Athena Dev Teams -#ifndef _STATUS_H_ -#define _STATUS_H_ +#ifndef MAP_STATUS_H +#define MAP_STATUS_H + +#include "../config/core.h" // defType, RENEWAL, RENEWAL_ASPD + +#include "../common/cbasetypes.h" +#include "../common/mmo.h" // NEW_CARTS struct block_list; -struct mob_data; -struct pet_data; +struct elemental_data; struct homun_data; struct mercenary_data; -struct status_change; +struct mob_data; +struct npc_data; +struct pet_data; + +//Change the equation when the values are high enough to discard the +//imprecision in exchange of overflow protection [Skotlex] +//Also add 100% checks since those are the most used cases where we don't +//want approximation errors. +#define APPLY_RATE(value, rate) ( \ + (rate) == 100 ? \ + (value) \ + : ( \ + (value) > 100000 ? \ + (rate) * ( (value) / 100 ) \ + : \ + (value) * (rate) / 100 \ + ) \ +) /** * Max Refine available to your server @@ -27,26 +49,27 @@ enum refine_type { REFINE_TYPE_WEAPON2 = 2, REFINE_TYPE_WEAPON3 = 3, REFINE_TYPE_WEAPON4 = 4, - REFINE_TYPE_MAX = 5 }; +/** + * SC configuration type + * @see db/sc_config.txt for more information + **/ typedef enum sc_conf_type { - SC_NO_REM_DEATH = 0x1, - SC_NO_SAVE = 0x2, - SC_NO_DISPELL = 0x4, - SC_NO_CLEARANCE = 0x8, - SC_BUFF = 0x10, - SC_DEBUFF = 0x20, - SC_MADO_NO_RESET = 0x40 + SC_NO_REM_DEATH = 0x01, + SC_NO_SAVE = 0x02, + SC_NO_DISPELL = 0x04, + SC_NO_CLEARANCE = 0x08, + SC_BUFF = 0x10, + SC_DEBUFF = 0x20, + SC_MADO_NO_RESET = 0x40, + SC_NO_CLEAR = 0x80, } sc_conf_type; -int status_get_refine_chance(enum refine_type wlv, int refine); - -// Status changes listing. These code are for use by the server. +// Status changes listing. These code are for use by the server. typedef enum sc_type { SC_NONE = -1, - //First we enumerate common status ailments which are often used around. SC_STONE = 0, SC_COMMON_MIN = 0, // begin @@ -59,9 +82,12 @@ typedef enum sc_type { SC_CONFUSION, SC_BLIND, SC_BLOODING, - SC_DPOISON, - SC_BURNING, //11 - SC_COMMON_MAX = 11, // end + SC_DPOISON, //10 + SC_FEAR, + SC_COLD, + SC_BURNING, + SC_DEEP_SLEEP, + SC_COMMON_MAX = 14, // end //Next up, we continue on 20, to leave enough room for additional "common" ailments in the future. SC_PROVOKE = 20, @@ -147,7 +173,7 @@ typedef enum sc_type { SC_VOLCANO, //100, SC_DELUGE, SC_VIOLENTGALE, - SC_WATK_ELEMENT, + SC_SUB_WEAPONPROPERTY, SC_ARMOR, SC_ARMORPROPERTY, SC_NOCHAT, @@ -323,7 +349,6 @@ typedef enum sc_type { SC_PROTECT_DEF, //SC_SPREGEN, SC_WALKSPEED = 278, - // Mercenary Only Bonus Effects SC_MER_FLEE, SC_MER_ATK, //280 @@ -331,7 +356,6 @@ typedef enum sc_type { SC_MER_SP, SC_MER_HIT, SC_MER_QUICKEN, - SC_REBIRTH, //SC_SKILLCASTRATE, //286 //SC_DEFRATIOATK, @@ -360,8 +384,8 @@ typedef enum sc_type { /** * 3rd **/ - SC_FEAR, - SC_FROSTMISTY, + //SC_FEAR, + SC_FROSTMISTY = 311, /** * Rune Knight **/ @@ -373,20 +397,20 @@ typedef enum sc_type { SC_REUSE_REFRESH, SC_GIANTGROWTH, SC_STONEHARDSKIN, - SC_VITALITYACTIVATION, + SC_VITALITYACTIVATION, // 320 SC_STORMBLAST, SC_FIGHTINGSPIRIT, SC_ABUNDANCE, /** * Arch Bishop - **/ + **/ SC_ADORAMUS, SC_EPICLESIS, SC_ORATIO, SC_LAUDAAGNUS, SC_LAUDARAMUS, SC_RENOVATIO, - SC_EXPIATIO, + SC_EXPIATIO, // 330 SC_DUPLELIGHT, SC_SECRAMENT, /** @@ -399,7 +423,7 @@ typedef enum sc_type { SC_SUMMON1, SC_SUMMON2, SC_SUMMON3, - SC_SUMMON4, + SC_SUMMON4, // 340 SC_SUMMON5, SC_READING_SB, SC_FREEZINGSP, @@ -415,7 +439,7 @@ typedef enum sc_type { * Mechanic **/ SC_ACCELERATION, - SC_HOVERING, + SC_HOVERING, // 350 SC_SHAPESHIFT, SC_INFRAREDSCAN, SC_ANALYZE, @@ -425,7 +449,7 @@ typedef enum sc_type { SC_STEALTHFIELD, SC_STEALTHFIELD_MASTER, SC_OVERHEAT, - SC_OVERHEAT_LIMITPOINT, + SC_OVERHEAT_LIMITPOINT, // 360 /** * Guillotine Cross **/ @@ -438,7 +462,7 @@ typedef enum sc_type { SC_ROLLINGCUTTER, SC_TOXIN, SC_PARALYSE, - SC_VENOMBLEED, + SC_VENOMBLEED, // 370 SC_MAGICMUSHROOM, SC_DEATHHURT, SC_PYREXIA, @@ -451,7 +475,7 @@ typedef enum sc_type { SC_FORCEOFVANGUARD, SC_SHIELDSPELL_DEF, SC_SHIELDSPELL_MDEF, - SC_SHIELDSPELL_REF, + SC_SHIELDSPELL_REF, // 380 SC_EXEEDBREAK, SC_PRESTIGE, SC_BANDING, @@ -462,9 +486,9 @@ typedef enum sc_type { * Sorcerer **/ SC_SPELLFIST, - SC_CRYSTALIZE, - SC_STRIKING, - SC_WARMER, + //SC_COLD, + SC_STRIKING = 389, + SC_WARMER, // 390 SC_VACUUM_EXTREME, SC_PROPERTYWALK, /** @@ -477,30 +501,30 @@ typedef enum sc_type { SC_ECHOSONG, SC_HARMONIZE, SC_SIREN, - SC_DEEP_SLEEP, - SC_SIRCLEOFNATURE, + //SC_DEEP_SLEEP, // 400 + SC_SIRCLEOFNATURE = 401, SC_GLOOMYDAY, - SC_GLOOMYDAY_SK, - SC_SONG_OF_MANA, + //SC_GLOOMYDAY_SK, + SC_SONG_OF_MANA = 404, SC_DANCE_WITH_WUG, SC_SATURDAY_NIGHT_FEVER, SC_LERADS_DEW, SC_MELODYOFSINK, SC_BEYOND_OF_WARCRY, - SC_UNLIMITED_HUMMING_VOICE, + SC_UNLIMITED_HUMMING_VOICE, // 410 SC_SITDOWN_FORCE, - SC_NETHERWORLD, + //SC_NETHERWORLD, /** * Sura **/ - SC_CRESCENTELBOW, + SC_CRESCENTELBOW = 413, SC_CURSEDCIRCLE_ATKER, SC_CURSEDCIRCLE_TARGET, SC_LIGHTNINGWALK, SC_RAISINGDRAGON, SC_GENTLETOUCH_ENERGYGAIN, SC_GENTLETOUCH_CHANGE, - SC_GENTLETOUCH_REVITALIZE, + SC_GENTLETOUCH_REVITALIZE, // 420 /** * Genetic **/ @@ -513,7 +537,7 @@ typedef enum sc_type { SC_STOMACHACHE, SC_MYSTERIOUS_POWDER, SC_MELON_BOMB, - SC_BANANA_BOMB, + SC_BANANA_BOMB, // 430 SC_BANANA_BOMB_SITDOWN_POSTDELAY, SC_SAVAGE_STEAK, SC_COCKTAIL_WARG_BLOOD, @@ -523,7 +547,7 @@ typedef enum sc_type { SC_PUTTI_TAILS_NOODLES, SC_BOOST500, SC_FULL_SWING_K, - SC_MANA_PLUS, + SC_MANA_PLUS, // 440 SC_MUSTLE_M, SC_LIFE_FORCE_F, SC_EXTRACT_WHITE_POTION_Z, @@ -536,7 +560,7 @@ typedef enum sc_type { SC__AUTOSHADOWSPELL, SC__SHADOWFORM, SC__BODYPAINT, - SC__INVISIBILITY, + SC__INVISIBILITY, // 450 SC__DEADLYINFECT, SC__ENERVATION, SC__GROOMY, @@ -546,7 +570,7 @@ typedef enum sc_type { SC__WEAKNESS, SC__STRIPACCESSARY, SC__MANHOLE, - SC__BLOODYLUST, + SC__BLOODYLUST, // 460 /** * Elemental Spirits **/ @@ -559,7 +583,7 @@ typedef enum sc_type { SC_WATER_DROP, SC_WATER_DROP_OPTION, SC_WATER_BARRIER, - SC_WIND_STEP, + SC_WIND_STEP, // 470 SC_WIND_STEP_OPTION, SC_WIND_CURTAIN, SC_WIND_CURTAIN_OPTION, @@ -569,7 +593,7 @@ typedef enum sc_type { SC_STONE_SHIELD, SC_STONE_SHIELD_OPTION, SC_POWER_OF_GAIA, - SC_PYROTECHNIC, + SC_PYROTECHNIC, // 480 SC_PYROTECHNIC_OPTION, SC_HEATER, SC_HEATER_OPTION, @@ -579,7 +603,7 @@ typedef enum sc_type { SC_AQUAPLAY_OPTION, SC_COOLER, SC_COOLER_OPTION, - SC_CHILLY_AIR, + SC_CHILLY_AIR, // 490 SC_CHILLY_AIR_OPTION, SC_GUST, SC_GUST_OPTION, @@ -589,7 +613,7 @@ typedef enum sc_type { SC_WILD_STORM_OPTION, SC_PETROLOGY, SC_PETROLOGY_OPTION, - SC_CURSED_SOIL, + SC_CURSED_SOIL, // 500 SC_CURSED_SOIL_OPTION, SC_UPHEAVAL, SC_UPHEAVAL_OPTION, @@ -600,21 +624,21 @@ typedef enum sc_type { /* Guild Aura */ SC_LEADERSHIP, SC_GLORYWOUNDS, - SC_SOULCOLD, + SC_SOULCOLD, // 510 SC_HAWKEYES, /* ... */ SC_ODINS_POWER, /* Sorcerer .extra */ SC_FIRE_INSIGNIA, SC_WATER_INSIGNIA, - SC_WIND_INSIGNIA, + SC_WIND_INSIGNIA, SC_EARTH_INSIGNIA, /* new pushcart */ SC_PUSH_CART, /* Warlock Spell books */ SC_SPELLBOOK1, SC_SPELLBOOK2, - SC_SPELLBOOK3, + SC_SPELLBOOK3, // 520 SC_SPELLBOOK4, SC_SPELLBOOK5, SC_SPELLBOOK6, @@ -626,13 +650,13 @@ typedef enum sc_type { /* Max HP & SP */ SC_INCMHP, SC_INCMSP, - SC_PARTYFLEE, + SC_PARTYFLEE, /** * Kagerou & Oboro [malufett] **/ SC_MEIKYOUSISUI, SC_KO_JYUMONJIKIRI, - SC_KYOUGAKU, + SC_KYOUGAKU, // 530 SC_IZAYOI, SC_ZENKAI, SC_KG_KAGEHUMI, @@ -643,19 +667,19 @@ typedef enum sc_type { SC_AKAITSUKI, //homon S - SC_STYLE_CHANGE, - SC_GOLDENE_FERSE, - SC_ANGRIFFS_MODUS, - SC_ERASER_CUTTER, - SC_OVERED_BOOST, - SC_LIGHT_OF_REGENE, - SC_VOLCANIC_ASH, - SC_GRANITIC_ARMOR, - SC_MAGMA_FLOW, - SC_PYROCLASTIC, - SC_NEEDLE_OF_PARALYZE, - SC_PAIN_KILLER, -#ifdef RENEWAL + SC_STYLE_CHANGE, + SC_GOLDENE_FERSE, // 540 + SC_ANGRIFFS_MODUS, + SC_ERASER_CUTTER, + SC_OVERED_BOOST, + SC_LIGHT_OF_REGENE, + SC_VOLCANIC_ASH, + SC_GRANITIC_ARMOR, + SC_MAGMA_FLOW, + SC_PYROCLASTIC, + SC_NEEDLE_OF_PARALYZE, + SC_PAIN_KILLER, // 550 +#ifdef RENEWAL SC_EXTREMITYFIST2, SC_RAID, #endif @@ -666,751 +690,865 @@ typedef enum sc_type { SC_KINGS_GRACE, SC_TELEKINESIS_INTENSE, SC_OFFERTORIUM, - SC_FRIGG_SONG, + SC_FRIGG_SONG, // 560 SC_ALL_RIDING, SC_HANBOK, - SC_MONSTER_TRANSFORM, + SC_ANGEL_PROTECT, + SC_ILLUSIONDOPING, + + SC_MTF_ASPD, + SC_MTF_RANGEATK, + SC_MTF_MATK, + SC_MTF_MLEATKED, + SC_MTF_CRIDAMAGE, // 570 + + SC_MOONSTAR, + SC_SUPER_STAR, + + SC_OKTOBERFEST, + SC_STRANGELIGHTS, + SC_DECORATION_OF_MUSIC, + + SC__MAELSTROM, + SC__CHAOS, + + SC__FEINTBOMB_MASTER, + SC_FALLENEMPIRE, + SC_FLASHCOMBO, + + //Vellum Weapon reductions + SC_DEFSET, + SC_MDEFSET, + + SC_NO_SWITCH_EQUIP, SC_MAX, //Automatically updated max, used in for's to check we are within bounds. } sc_type; -// Official status change ids, used to display status icons on the client. +/// Official status change ids, used to display status icons in the client. enum si_type { - SI_BLANK = -1, - SI_PROVOKE = 0, - SI_ENDURE = 1, - SI_TWOHANDQUICKEN = 2, - SI_CONCENTRATION = 3, - SI_HIDING = 4, - SI_CLOAKING = 5, - SI_ENCHANTPOISON = 6, - SI_POISONREACT = 7, - SI_QUAGMIRE = 8, - SI_ANGELUS = 9, - SI_BLESSING = 10, - SI_CRUCIS = 11, - SI_INC_AGI = 12, - SI_DEC_AGI = 13, - SI_SLOWPOISON = 14, - SI_IMPOSITIO = 15, - SI_SUFFRAGIUM = 16, - SI_ASPERSIO = 17, - SI_BENEDICTIO = 18, - SI_KYRIE = 19, - SI_MAGNIFICAT = 20, - SI_GLORIA = 21, - SI_LEXAETERNA = 22, - SI_ADRENALINE = 23, - SI_WEAPONPERFECT = 24, - SI_OVERTHRUST = 25, - SI_MAXIMIZE = 26, - SI_RIDING = 27, - SI_FALCON = 28, - SI_TRICKDEAD = 29, - SI_SHOUT = 30, - SI_ENERGYCOAT = 31, - SI_BROKENARMOR = 32, - SI_BROKENWEAPON = 33, - SI_ILLUSION = 34, - SI_WEIGHTOVER50 = 35, - SI_WEIGHTOVER90 = 36, - SI_ATTHASTE_POTION1 = 37, - SI_ATTHASTE_POTION2 = 38, - SI_ATTHASTE_POTION3 = 39, - SI_ATTHASTE_INFINITY = 40, - SI_MOVHASTE_POTION = 41, - SI_MOVHASTE_INFINITY = 42, -// SI_AUTOCOUNTER = 43, -// SI_SPLASHER = 44, - SI_ANKLESNARE = 45, - SI_POSTDELAY = 46, -// SI_NOACTION = 47, -// SI_IMPOSSIBLEPICKUP = 48, -// SI_BARRIER = 49, - SI_NOEQUIPWEAPON = 50, - SI_NOEQUIPSHIELD = 51, - SI_NOEQUIPARMOR = 52, - SI_NOEQUIPHELM = 53, - SI_PROTECTWEAPON = 54, - SI_PROTECTSHIELD = 55, - SI_PROTECTARMOR = 56, - SI_PROTECTHELM = 57, - SI_AUTOGUARD = 58, - SI_REFLECTSHIELD = 59, -// SI_DEVOTION = 60, - SI_PROVIDENCE = 61, - SI_DEFENDER = 62, -// SI_MAGICROD = 63, -// SI_WEAPONPROPERTY = 64, - SI_AUTOSPELL = 65, -// SI_SPECIALZONE = 66, -// SI_MASK = 67, - SI_SPEARQUICKEN = 68, -// SI_BDPLAYING = 69, -// SI_WHISTLE = 70, -// SI_ASSASSINCROSS = 71, -// SI_POEMBRAGI = 72, -// SI_APPLEIDUN = 73, -// SI_HUMMING = 74, -// SI_DONTFORGETME = 75, -// SI_FORTUNEKISS = 76, -// SI_SERVICEFORYOU = 77, -// SI_RICHMANKIM = 78, -// SI_ETERNALCHAOS = 79, -// SI_DRUMBATTLEFIELD = 80, -// SI_RINGNIBELUNGEN = 81, -// SI_ROKISWEIL = 82, -// SI_INTOABYSS = 83, -// SI_SIEGFRIED = 84, -// SI_BLADESTOP = 85, - SI_EXPLOSIONSPIRITS = 86, - SI_STEELBODY = 87, - SI_EXTREMITYFIST = 88, -// SI_COMBOATTACK = 89, - SI_PROPERTYFIRE = 90, - SI_PROPERTYWATER = 91, - SI_PROPERTYWIND = 92, - SI_PROPERTYGROUND = 93, -// SI_MAGICATTACK = 94, - SI_STOP = 95, -// SI_WEAPONBRAKER = 96, - SI_PROPERTYUNDEAD = 97, -// SI_POWERUP = 98, -// SI_AGIUP = 99, -// SI_SIEGEMODE = 100, -// SI_INVISIBLE = 101, -// SI_STATUSONE = 102, - SI_AURABLADE = 103, - SI_PARRYING = 104, - SI_LKCONCENTRATION = 105, - SI_TENSIONRELAX = 106, - SI_BERSERK = 107, -// SI_SACRIFICE = 108, -// SI_GOSPEL = 109, - SI_ASSUMPTIO = 110, -// SI_BASILICA = 111, - SI_GROUNDMAGIC = 112, - SI_MAGICPOWER = 113, - SI_EDP = 114, - SI_TRUESIGHT = 115, - SI_WINDWALK = 116, - SI_MELTDOWN = 117, - SI_CARTBOOST = 118, -// SI_CHASEWALK = 119, - SI_SWORDREJECT = 120, - SI_MARIONETTE_MASTER = 121, - SI_MARIONETTE = 122, - SI_MOON = 123, - SI_BLOODING = 124, - SI_JOINTBEAT = 125, -// SI_MINDBREAKER = 126, -// SI_MEMORIZE = 127, -// SI_FOGWALL = 128, -// SI_SPIDERWEB = 129, - SI_PROTECTEXP = 130, -// SI_SUB_WEAPONPROPERTY = 131, - SI_AUTOBERSERK = 132, - SI_RUN = 133, - SI_TING = 134, - SI_STORMKICK_ON = 135, - SI_STORMKICK_READY = 136, - SI_DOWNKICK_ON = 137, - SI_DOWNKICK_READY = 138, - SI_TURNKICK_ON = 139, - SI_TURNKICK_READY = 140, - SI_COUNTER_ON = 141, - SI_COUNTER_READY = 142, - SI_DODGE_ON = 143, - SI_DODGE_READY = 144, - SI_STRUP = 145, - SI_PROPERTYDARK = 146, - SI_ADRENALINE2 = 147, - SI_PROPERTYTELEKINESIS = 148, - SI_SOULLINK = 149, - SI_PLUSATTACKPOWER = 150, - SI_PLUSMAGICPOWER = 151, - SI_DEVIL1 = 152, - SI_KAITE = 153, -// SI_SWOO = 154, -// SI_STAR2 = 155, - SI_KAIZEL = 156, - SI_KAAHI = 157, - SI_KAUPE = 158, - SI_SMA_READY = 159, - SI_SKE = 160, - SI_ONEHANDQUICKEN = 161, -// SI_FRIEND = 162, -// SI_FRIENDUP = 163, -// SI_SG_WARM = 164, - SI_SG_SUN_WARM = 165, -// 166 | The three show the exact same display: ultra red character (165, 166, 167) -// 167 | Their names would be SI_SG_SUN_WARM, SI_SG_MOON_WARM, SI_SG_STAR_WARM -// SI_EMOTION = 168, - SI_SUN_COMFORT = 169, - SI_MOON_COMFORT = 170, - SI_STAR_COMFORT = 171, -// SI_EXPUP = 172, -// SI_GDSKILL_BATTLEORDER = 173, -// SI_GDSKILL_REGENERATION = 174, -// SI_GDSKILL_POSTDELAY = 175, -// SI_RESISTHANDICAP = 176, -// SI_MAXHPPERCENT = 177, -// SI_MAXSPPERCENT = 178, -// SI_DEFENCE = 179, -// SI_SLOWDOWN = 180, - SI_PRESERVE = 181, - SI_INCSTR = 182, -// SI_NOT_EXTREMITYFIST = 183, - SI_CLAIRVOYANCE = 184, -// SI_MOVESLOW_POTION = 185, - SI_DOUBLECASTING = 186, -// SI_GRAVITATION = 187, - SI_OVERTHRUSTMAX = 188, -// SI_LONGING = 189, -// SI_HERMODE = 190, - SI_TAROTCARD = 191, // the icon allows no doubt... but what is it really used for ?? [DracoRPG] -// SI_HLIF_AVOID = 192, -// SI_HFLI_FLEET = 193, -// SI_HFLI_SPEED = 194, -// SI_HLIF_CHANGE = 195, -// SI_HAMI_BLOODLUST = 196, - SI_CR_SHRINK = 197, - SI_WZ_SIGHTBLASTER = 198, - SI_DC_WINKCHARM = 199, - SI_RG_CCONFINE_M = 200, - SI_RG_CCONFINE_S = 201, -// SI_DISABLEMOVE = 202, - SI_GS_MADNESSCANCEL = 203, //[blackhole89] - SI_GS_GATLINGFEVER = 204, - SI_EARTHSCROLL = 205, - SI_NJ_UTSUSEMI = 206, - SI_NJ_BUNSINJYUTSU = 207, - SI_NJ_NEN = 208, - SI_GS_ADJUSTMENT = 209, - SI_GS_ACCURACY = 210, - SI_NJ_SUITON = 211, -// SI_PET = 212, -// SI_MENTAL = 213, -// SI_EXPMEMORY = 214, -// SI_PERFORMANCE = 215, -// SI_GAIN = 216, -// SI_GRIFFON = 217, -// SI_DRIFT = 218, -// SI_WALLSHIFT = 219, -// SI_REINCARNATION = 220, -// SI_PATTACK = 221, -// SI_PSPEED = 222, -// SI_PDEFENSE = 223, -// SI_PCRITICAL = 224, -// SI_RANKING = 225, -// SI_PTRIPLE = 226, -// SI_DENERGY = 227, -// SI_WAVE1 = 228, -// SI_WAVE2 = 229, -// SI_WAVE3 = 230, -// SI_WAVE4 = 231, -// SI_DAURA = 232, -// SI_DFREEZER = 233, -// SI_DPUNISH = 234, -// SI_DBARRIER = 235, -// SI_DWARNING = 236, -// SI_MOUSEWHEEL = 237, -// SI_DGAUGE = 238, -// SI_DACCEL = 239, -// SI_DBLOCK = 240, - SI_FOOD_STR = 241, - SI_FOOD_AGI = 242, - SI_FOOD_VIT = 243, - SI_FOOD_DEX = 244, - SI_FOOD_INT = 245, - SI_FOOD_LUK = 246, - SI_FOOD_BASICAVOIDANCE = 247, - SI_FOOD_BASICHIT = 248, - SI_FOOD_CRITICALSUCCESSVALUE = 249, - SI_CASH_PLUSEXP = 250, - SI_CASH_DEATHPENALTY = 251, - SI_CASH_RECEIVEITEM = 252, - SI_CASH_BOSS_ALARM = 253, -// SI_DA_ENERGY = 254, -// SI_DA_FIRSTSLOT = 255, -// SI_DA_HEADDEF = 256, -// SI_DA_SPACE = 257, -// SI_DA_TRANSFORM = 258, -// SI_DA_ITEMREBUILD = 259, -// SI_DA_ILLUSION = 260, //All mobs display as Turtle General -// SI_DA_DARKPOWER = 261, -// SI_DA_EARPLUG = 262, -// SI_DA_CONTRACT = 263, //Bio Mob effect on you and SI_TRICKDEAD icon -// SI_DA_BLACK = 264, //For short time blurry screen -// SI_DA_MAGICCART = 265, -// SI_CRYSTAL = 266, -// SI_DA_REBUILD = 267, -// SI_DA_EDARKNESS = 268, -// SI_DA_EGUARDIAN = 269, -// SI_DA_TIMEOUT = 270, - SI_FOOD_STR_CASH = 271, - SI_FOOD_AGI_CASH = 272, - SI_FOOD_VIT_CASH = 273, - SI_FOOD_DEX_CASH = 274, - SI_FOOD_INT_CASH = 275, - SI_FOOD_LUK_CASH = 276, - SI_MER_FLEE = 277, - SI_MER_ATK = 278, - SI_MER_HP = 279, - SI_MER_SP = 280, - SI_MER_HIT = 281, - SI_SLOWCAST = 282, -// SI_MAGICMIRROR = 283, -// SI_STONESKIN = 284, -// SI_ANTIMAGIC = 285, - SI_CRITICALWOUND = 286, -// SI_NPC_DEFENDER = 287, -// SI_NOACTION_WAIT = 288, - SI_MOVHASTE_HORSE = 289, - SI_PROTECT_DEF = 290, - SI_PROTECT_MDEF = 291, - SI_HEALPLUS = 292, - SI_S_LIFEPOTION = 293, - SI_L_LIFEPOTION = 294, - SI_CRITICALPERCENT = 295, - SI_PLUSAVOIDVALUE = 296, -// SI_ATKER_ASPD = 297, -// SI_TARGET_ASPD = 298, -// SI_ATKER_MOVESPEED = 299, - SI_ATKER_BLOOD = 300, - SI_TARGET_BLOOD = 301, - SI_ARMOR_PROPERTY = 302, -// SI_REUSE_LIMIT_A = 303, - SI_HELLPOWER = 304, -// SI_STEAMPACK = 305, -// SI_REUSE_LIMIT_B = 306, -// SI_REUSE_LIMIT_C = 307, -// SI_REUSE_LIMIT_D = 308, -// SI_REUSE_LIMIT_E = 309, -// SI_REUSE_LIMIT_F = 310, - SI_INVINCIBLE = 311, - SI_CASH_PLUSONLYJOBEXP = 312, - SI_PARTYFLEE = 313, -// SI_ANGEL_PROTECT = 314, -// SI_ENDURE_MDEF = 315, - SI_ENCHANTBLADE = 316, - SI_DEATHBOUND = 317, - SI_REFRESH = 318, - SI_GIANTGROWTH = 319, - SI_STONEHARDSKIN = 320, - SI_VITALITYACTIVATION = 321, - SI_FIGHTINGSPIRIT = 322, - SI_ABUNDANCE = 323, - SI_REUSE_MILLENNIUMSHIELD = 324, - SI_REUSE_CRUSHSTRIKE = 325, - SI_REUSE_REFRESH = 326, - SI_REUSE_STORMBLAST = 327, - SI_VENOMIMPRESS = 328, - SI_EPICLESIS = 329, - SI_ORATIO = 330, - SI_LAUDAAGNUS = 331, - SI_LAUDARAMUS = 332, - SI_CLOAKINGEXCEED = 333, - SI_HALLUCINATIONWALK = 334, - SI_HALLUCINATIONWALK_POSTDELAY = 335, - SI_RENOVATIO = 336, - SI_WEAPONBLOCKING = 337, - SI_WEAPONBLOCKING_POSTDELAY = 338, - SI_ROLLINGCUTTER = 339, - SI_EXPIATIO = 340, - SI_POISONINGWEAPON = 341, - SI_TOXIN = 342, - SI_PARALYSE = 343, - SI_VENOMBLEED = 344, - SI_MAGICMUSHROOM = 345, - SI_DEATHHURT = 346, - SI_PYREXIA = 347, - SI_OBLIVIONCURSE = 348, - SI_LEECHESEND = 349, - SI_DUPLELIGHT = 350, - SI_FROSTMISTY = 351, - SI_FEARBREEZE = 352, - SI_ELECTRICSHOCKER = 353, - SI_MARSHOFABYSS = 354, - SI_RECOGNIZEDSPELL = 355, - SI_STASIS = 356, - SI_WUGRIDER = 357, - SI_WUGDASH = 358, - SI_WUGBITE = 359, - SI_CAMOUFLAGE = 360, - SI_ACCELERATION = 361, - SI_HOVERING = 362, - SI_SPHERE_1 = 363, - SI_SPHERE_2 = 364, - SI_SPHERE_3 = 365, - SI_SPHERE_4 = 366, - SI_SPHERE_5 = 367, - SI_MVPCARD_TAOGUNKA = 368, - SI_MVPCARD_MISTRESS = 369, - SI_MVPCARD_ORCHERO = 370, - SI_MVPCARD_ORCLORD = 371, - SI_OVERHEAT_LIMITPOINT = 372, - SI_OVERHEAT = 373, - SI_SHAPESHIFT = 374, - SI_INFRAREDSCAN = 375, - SI_MAGNETICFIELD = 376, - SI_NEUTRALBARRIER = 377, - SI_NEUTRALBARRIER_MASTER = 378, - SI_STEALTHFIELD = 379, - SI_STEALTHFIELD_MASTER = 380, - SI_MANU_ATK = 381, - SI_MANU_DEF = 382, - SI_SPL_ATK = 383, - SI_SPL_DEF = 384, - SI_REPRODUCE = 385, - SI_MANU_MATK = 386, - SI_SPL_MATK = 387, - SI_STR_SCROLL = 388, - SI_INT_SCROLL = 389, - SI_LG_REFLECTDAMAGE = 390, - SI_FORCEOFVANGUARD = 391, - SI_BUCHEDENOEL = 392, - SI_AUTOSHADOWSPELL = 393, - SI_SHADOWFORM = 394, - SI_RAID = 395, - SI_SHIELDSPELL_DEF = 396, - SI_SHIELDSPELL_MDEF = 397, - SI_SHIELDSPELL_REF = 398, - SI_BODYPAINT = 399, - SI_EXEEDBREAK = 400, - SI_ADORAMUS = 401, - SI_PRESTIGE = 402, - SI_INVISIBILITY = 403, - SI_DEADLYINFECT = 404, - SI_BANDING = 405, - SI_EARTHDRIVE = 406, - SI_INSPIRATION = 407, - SI_ENERVATION = 408, - SI_GROOMY = 409, - SI_RAISINGDRAGON = 410, - SI_IGNORANCE = 411, - SI_LAZINESS = 412, - SI_LIGHTNINGWALK = 413, - SI_ACARAJE = 414, - SI_UNLUCKY = 415, - SI_CURSEDCIRCLE_ATKER = 416, - SI_CURSEDCIRCLE_TARGET = 417, - SI_WEAKNESS = 418, - SI_CRESCENTELBOW = 419, - SI_NOEQUIPACCESSARY = 420, - SI_STRIPACCESSARY = 421, - SI_MANHOLE = 422, - SI_POPECOOKIE = 423, - SI_FALLENEMPIRE = 424, - SI_GENTLETOUCH_ENERGYGAIN = 425, - SI_GENTLETOUCH_CHANGE = 426, - SI_GENTLETOUCH_REVITALIZE = 427, - SI_BLOODYLUST = 428, - SI_SWINGDANCE = 429, - SI_SYMPHONYOFLOVERS = 430, - SI_PROPERTYWALK = 431, - SI_SPELLFIST = 432, - SI_NETHERWORLD = 433, - SI_SIREN = 434, - SI_DEEPSLEEP = 435, - SI_SIRCLEOFNATURE = 436, - SI_COLD = 437, - SI_GLOOMYDAY = 438, - SI_SONG_OF_MANA = 439, - SI_CLOUDKILL = 440, - SI_DANCEWITHWUG = 441, - SI_RUSHWINDMILL = 442, - SI_ECHOSONG = 443, - SI_HARMONIZE = 444, - SI_STRIKING = 445, - SI_WARMER = 446, - SI_MOONLITSERENADE = 447, - SI_SATURDAYNIGHTFEVER = 448, - SI_SITDOWN_FORCE = 449, - SI_ANALYZE = 450, - SI_LERADSDEW = 451, - SI_MELODYOFSINK = 452, - SI_WARCRYOFBEYOND = 453, - SI_UNLIMITEDHUMMINGVOICE = 454, - SI_SPELLBOOK1 = 455, - SI_SPELLBOOK2 = 456, - SI_SPELLBOOK3 = 457, - SI_FREEZE_SP = 458, - SI_GN_TRAINING_SWORD = 459, - SI_GN_REMODELING_CART = 460, - SI_CARTSBOOST = 461, - SI_FIXEDCASTINGTM_REDUCE = 462, - SI_THORNTRAP = 463, - SI_BLOODSUCKER = 464, - SI_SPORE_EXPLOSION = 465, - SI_DEMONIC_FIRE = 466, - SI_FIRE_EXPANSION_SMOKE_POWDER = 467, - SI_FIRE_EXPANSION_TEAR_GAS = 468, - SI_BLOCKING_PLAY = 469, - SI_MANDRAGORA = 470, - SI_ACTIVATE = 471, - SI_SECRAMENT = 472, - SI_ASSUMPTIO2 = 473, - SI_TK_SEVENWIND = 474, - SI_LIMIT_ODINS_RECALL = 475, - SI_STOMACHACHE = 476, - SI_MYSTERIOUS_POWDER = 477, - SI_MELON_BOMB = 478, - SI_BANANA_BOMB_SITDOWN_POSTDELAY = 479, - SI_PROMOTE_HEALTH_RESERCH = 480, - SI_ENERGY_DRINK_RESERCH = 481, - SI_EXTRACT_WHITE_POTION_Z = 482, - SI_VITATA_500 = 483, - SI_EXTRACT_SALAMINE_JUICE = 484, - SI_BOOST500 = 485, - SI_FULL_SWING_K = 486, - SI_MANA_PLUS = 487, - SI_MUSTLE_M = 488, - SI_LIFE_FORCE_F = 489, - SI_VACUUM_EXTREME = 490, - SI_SAVAGE_STEAK = 491, - SI_COCKTAIL_WARG_BLOOD = 492, - SI_MINOR_BBQ = 493, - SI_SIROMA_ICE_TEA = 494, - SI_DROCERA_HERB_STEAMED = 495, - SI_PUTTI_TAILS_NOODLES = 496, - SI_BANANA_BOMB = 497, - SI_SUMMON_AGNI = 498, - SI_SPELLBOOK4 = 499, - SI_SPELLBOOK5 = 500, - SI_SPELLBOOK6 = 501, - SI_SPELLBOOK7 = 502, - SI_ELEMENTAL_AGGRESSIVE = 503, - SI_RETURN_TO_ELDICASTES = 504, - SI_BANDING_DEFENCE = 505, - SI_SKELSCROLL = 506, - SI_DISTRUCTIONSCROLL = 507, - SI_ROYALSCROLL = 508, - SI_IMMUNITYSCROLL = 509, - SI_MYSTICSCROLL = 510, - SI_BATTLESCROLL = 511, - SI_ARMORSCROLL = 512, - SI_FREYJASCROLL = 513, - SI_SOULSCROLL = 514, - SI_CIRCLE_OF_FIRE = 515, - SI_CIRCLE_OF_FIRE_OPTION = 516, - SI_FIRE_CLOAK = 517, - SI_FIRE_CLOAK_OPTION = 518, - SI_WATER_SCREEN = 519, - SI_WATER_SCREEN_OPTION = 520, - SI_WATER_DROP = 521, - SI_WATER_DROP_OPTION = 522, - SI_WIND_STEP = 523, - SI_WIND_STEP_OPTION = 524, - SI_WIND_CURTAIN = 525, - SI_WIND_CURTAIN_OPTION = 526, - SI_WATER_BARRIER = 527, - SI_ZEPHYR = 528, - SI_SOLID_SKIN = 529, - SI_SOLID_SKIN_OPTION = 530, - SI_STONE_SHIELD = 531, - SI_STONE_SHIELD_OPTION = 532, - SI_POWER_OF_GAIA = 533, - // SI_EL_WAIT = 534, - // SI_EL_PASSIVE = 535, - // SI_EL_DEFENSIVE = 536, - // SI_EL_OFFENSIVE = 537, - // SI_EL_COST = 538, - SI_PYROTECHNIC = 539, - SI_PYROTECHNIC_OPTION = 540, - SI_HEATER = 541, - SI_HEATER_OPTION = 542, - SI_TROPIC = 543, - SI_TROPIC_OPTION = 544, - SI_AQUAPLAY = 545, - SI_AQUAPLAY_OPTION = 546, - SI_COOLER = 547, - SI_COOLER_OPTION = 548, - SI_CHILLY_AIR = 549, - SI_CHILLY_AIR_OPTION = 550, - SI_GUST = 551, - SI_GUST_OPTION = 552, - SI_BLAST = 553, - SI_BLAST_OPTION = 554, - SI_WILD_STORM = 555, - SI_WILD_STORM_OPTION = 556, - SI_PETROLOGY = 557, - SI_PETROLOGY_OPTION = 558, - SI_CURSED_SOIL = 559, - SI_CURSED_SOIL_OPTION = 560, - SI_UPHEAVAL = 561, - SI_UPHEAVAL_OPTION = 562, - SI_TIDAL_WEAPON = 563, - SI_TIDAL_WEAPON_OPTION = 564, - SI_ROCK_CRUSHER = 565, - SI_ROCK_CRUSHER_ATK = 566, - SI_FIRE_INSIGNIA = 567, - SI_WATER_INSIGNIA = 568, - SI_WIND_INSIGNIA = 569, - SI_EARTH_INSIGNIA = 570, - SI_EQUIPED_FLOOR = 571, - SI_GUARDIAN_RECALL = 572, - SI_MORA_BUFF = 573, - SI_REUSE_LIMIT_G = 574, - SI_REUSE_LIMIT_H = 575, - SI_NEEDLE_OF_PARALYZE = 576, - SI_PAIN_KILLER = 577, - SI_G_LIFEPOTION = 578, - SI_VITALIZE_POTION = 579, - SI_LIGHT_OF_REGENE = 580, - SI_OVERED_BOOST = 581, - SI_SILENT_BREEZE = 582, - SI_ODINS_POWER = 583, - SI_STYLE_CHANGE = 584, - SI_SONIC_CLAW_POSTDELAY = 585, + SI_BLANK = -1, + + SI_PROVOKE = 0, + SI_ENDURE = 1, + SI_TWOHANDQUICKEN = 2, + SI_CONCENTRATION = 3, + SI_HIDING = 4, + SI_CLOAKING = 5, + SI_ENCHANTPOISON = 6, + SI_POISONREACT = 7, + SI_QUAGMIRE = 8, + SI_ANGELUS = 9, + SI_BLESSING = 10, + SI_CRUCIS = 11, + SI_INC_AGI = 12, + SI_DEC_AGI = 13, + SI_SLOWPOISON = 14, + SI_IMPOSITIO = 15, + SI_SUFFRAGIUM = 16, + SI_ASPERSIO = 17, + SI_BENEDICTIO = 18, + SI_KYRIE = 19, + SI_MAGNIFICAT = 20, + SI_GLORIA = 21, + SI_LEXAETERNA = 22, + SI_ADRENALINE = 23, + SI_WEAPONPERFECT = 24, + SI_OVERTHRUST = 25, + SI_MAXIMIZE = 26, + SI_RIDING = 27, + SI_FALCON = 28, + SI_TRICKDEAD = 29, + SI_SHOUT = 30, + SI_ENERGYCOAT = 31, + SI_BROKENARMOR = 32, + SI_BROKENWEAPON = 33, + SI_ILLUSION = 34, + SI_WEIGHTOVER50 = 35, + SI_WEIGHTOVER90 = 36, + SI_ATTHASTE_POTION1 = 37, + SI_ATTHASTE_POTION2 = 38, + SI_ATTHASTE_POTION3 = 39, + SI_ATTHASTE_INFINITY = 40, + SI_MOVHASTE_POTION = 41, + SI_MOVHASTE_INFINITY = 42, + //SI_AUTOCOUNTER = 43, + //SI_SPLASHER = 44, + SI_ANKLESNARE = 45, + SI_POSTDELAY = 46, + //SI_NOACTION = 47, + //SI_IMPOSSIBLEPICKUP = 48, + //SI_BARRIER = 49, + + SI_NOEQUIPWEAPON = 50, + SI_NOEQUIPSHIELD = 51, + SI_NOEQUIPARMOR = 52, + SI_NOEQUIPHELM = 53, + SI_PROTECTWEAPON = 54, + SI_PROTECTSHIELD = 55, + SI_PROTECTARMOR = 56, + SI_PROTECTHELM = 57, + SI_AUTOGUARD = 58, + SI_REFLECTSHIELD = 59, + //SI_DEVOTION = 60, + SI_PROVIDENCE = 61, + SI_DEFENDER = 62, + //SI_MAGICROD = 63, + //SI_WEAPONPROPERTY = 64, + SI_AUTOSPELL = 65, + //SI_SPECIALZONE = 66, + //SI_MASK = 67, + SI_SPEARQUICKEN = 68, + //SI_BDPLAYING = 69, + //SI_WHISTLE = 70, + //SI_ASSASSINCROSS = 71, + //SI_POEMBRAGI = 72, + //SI_APPLEIDUN = 73, + //SI_HUMMING = 74, + //SI_DONTFORGETME = 75, + //SI_FORTUNEKISS = 76, + //SI_SERVICEFORYOU = 77, + //SI_RICHMANKIM = 78, + //SI_ETERNALCHAOS = 79, + //SI_DRUMBATTLEFIELD = 80, + //SI_RINGNIBELUNGEN = 81, + //SI_ROKISWEIL = 82, + //SI_INTOABYSS = 83, + //SI_SIEGFRIED = 84, + //SI_BLADESTOP = 85, + SI_EXPLOSIONSPIRITS = 86, + SI_STEELBODY = 87, + SI_EXTREMITYFIST = 88, + //SI_COMBOATTACK = 89, + SI_PROPERTYFIRE = 90, + SI_PROPERTYWATER = 91, + SI_PROPERTYWIND = 92, + SI_PROPERTYGROUND = 93, + //SI_MAGICATTACK = 94, + SI_STOP = 95, + //SI_WEAPONBRAKER = 96, + SI_PROPERTYUNDEAD = 97, + //SI_POWERUP = 98, + //SI_AGIUP = 99, + + //SI_SIEGEMODE = 100, + //SI_INVISIBLE = 101, + //SI_STATUSONE = 102, + SI_AURABLADE = 103, + SI_PARRYING = 104, + SI_LKCONCENTRATION = 105, + SI_TENSIONRELAX = 106, + SI_BERSERK = 107, + //SI_SACRIFICE = 108, + //SI_GOSPEL = 109, + SI_ASSUMPTIO = 110, + //SI_BASILICA = 111, + SI_GROUNDMAGIC = 112, + SI_MAGICPOWER = 113, + SI_EDP = 114, + SI_TRUESIGHT = 115, + SI_WINDWALK = 116, + SI_MELTDOWN = 117, + SI_CARTBOOST = 118, + //SI_CHASEWALK = 119, + SI_SWORDREJECT = 120, + SI_MARIONETTE_MASTER = 121, + SI_MARIONETTE = 122, + SI_MOON = 123, + SI_BLOODING = 124, + SI_JOINTBEAT = 125, + //SI_MINDBREAKER = 126, + //SI_MEMORIZE = 127, + //SI_FOGWALL = 128, + //SI_SPIDERWEB = 129, + SI_PROTECTEXP = 130, + //SI_SUB_WEAPONPROPERTY = 131, + SI_AUTOBERSERK = 132, + SI_RUN = 133, + SI_TING = 134, + SI_STORMKICK_ON = 135, + SI_STORMKICK_READY = 136, + SI_DOWNKICK_ON = 137, + SI_DOWNKICK_READY = 138, + SI_TURNKICK_ON = 139, + SI_TURNKICK_READY = 140, + SI_COUNTER_ON = 141, + SI_COUNTER_READY = 142, + SI_DODGE_ON = 143, + SI_DODGE_READY = 144, + SI_STRUP = 145, + SI_PROPERTYDARK = 146, + SI_ADRENALINE2 = 147, + SI_PROPERTYTELEKINESIS = 148, + SI_SOULLINK = 149, + + SI_PLUSATTACKPOWER = 150, + SI_PLUSMAGICPOWER = 151, + SI_DEVIL1 = 152, + SI_KAITE = 153, + //SI_SWOO = 154, + //SI_STAR2 = 155, + SI_KAIZEL = 156, + SI_KAAHI = 157, + SI_KAUPE = 158, + SI_SMA_READY = 159, + SI_SKE = 160, + SI_ONEHANDQUICKEN = 161, + //SI_FRIEND = 162, + //SI_FRIENDUP = 163, + //SI_SG_WARM = 164, + SI_SG_SUN_WARM = 165, + //SI_SG_MOON_WARM = 166 | The three show the exact same display: ultra red character (165, 166, 167) + //SI_SG_STAR_WARM = 167 | Their names would be SI_SG_SUN_WARM, SI_SG_MOON_WARM, SI_SG_STAR_WARM + //SI_EMOTION = 168, + SI_SUN_COMFORT = 169, + SI_MOON_COMFORT = 170, + SI_STAR_COMFORT = 171, + //SI_EXPUP = 172, + //SI_GDSKILL_BATTLEORDER = 173, + //SI_GDSKILL_REGENERATION = 174, + //SI_GDSKILL_POSTDELAY = 175, + //SI_RESISTHANDICAP = 176, + //SI_MAXHPPERCENT = 177, + //SI_MAXSPPERCENT = 178, + //SI_DEFENCE = 179, + //SI_SLOWDOWN = 180, + SI_PRESERVE = 181, + SI_INCSTR = 182, + //SI_NOT_EXTREMITYFIST = 183, + SI_CLAIRVOYANCE = 184, + //SI_MOVESLOW_POTION = 185, + SI_DOUBLECASTING = 186, + //SI_GRAVITATION = 187, + SI_OVERTHRUSTMAX = 188, + //SI_LONGING = 189, + //SI_HERMODE = 190, + SI_TAROTCARD = 191, // the icon allows no doubt... but what is it really used for ?? [DracoRPG] + //SI_HLIF_AVOID = 192, + //SI_HFLI_FLEET = 193, + //SI_HFLI_SPEED = 194, + //SI_HLIF_CHANGE = 195, + //SI_HAMI_BLOODLUST = 196, + SI_CR_SHRINK = 197, + SI_WZ_SIGHTBLASTER = 198, + SI_DC_WINKCHARM = 199, + + SI_RG_CCONFINE_M = 200, + SI_RG_CCONFINE_S = 201, + //SI_DISABLEMOVE = 202, + SI_GS_MADNESSCANCEL = 203, //[blackhole89] + SI_GS_GATLINGFEVER = 204, + SI_EARTHSCROLL = 205, + SI_NJ_UTSUSEMI = 206, + SI_NJ_BUNSINJYUTSU = 207, + SI_NJ_NEN = 208, + SI_GS_ADJUSTMENT = 209, + SI_GS_ACCURACY = 210, + SI_NJ_SUITON = 211, + //SI_PET = 212, + //SI_MENTAL = 213, + //SI_EXPMEMORY = 214, + //SI_PERFORMANCE = 215, + //SI_GAIN = 216, + //SI_GRIFFON = 217, + //SI_DRIFT = 218, + //SI_WALLSHIFT = 219, + //SI_REINCARNATION = 220, + //SI_PATTACK = 221, + //SI_PSPEED = 222, + //SI_PDEFENSE = 223, + //SI_PCRITICAL = 224, + //SI_RANKING = 225, + //SI_PTRIPLE = 226, + //SI_DENERGY = 227, + //SI_WAVE1 = 228, + //SI_WAVE2 = 229, + //SI_WAVE3 = 230, + //SI_WAVE4 = 231, + //SI_DAURA = 232, + //SI_DFREEZER = 233, + //SI_DPUNISH = 234, + //SI_DBARRIER = 235, + //SI_DWARNING = 236, + //SI_MOUSEWHEEL = 237, + //SI_DGAUGE = 238, + //SI_DACCEL = 239, + //SI_DBLOCK = 240, + SI_FOOD_STR = 241, + SI_FOOD_AGI = 242, + SI_FOOD_VIT = 243, + SI_FOOD_DEX = 244, + SI_FOOD_INT = 245, + SI_FOOD_LUK = 246, + SI_FOOD_BASICAVOIDANCE = 247, + SI_FOOD_BASICHIT = 248, + SI_FOOD_CRITICALSUCCESSVALUE = 249, + + SI_CASH_PLUSEXP = 250, + SI_CASH_DEATHPENALTY = 251, + SI_CASH_RECEIVEITEM = 252, + SI_CASH_BOSS_ALARM = 253, + //SI_DA_ENERGY = 254, + //SI_DA_FIRSTSLOT = 255, + //SI_DA_HEADDEF = 256, + //SI_DA_SPACE = 257, + //SI_DA_TRANSFORM = 258, + //SI_DA_ITEMREBUILD = 259, + //SI_DA_ILLUSION = 260, //All mobs display as Turtle General + //SI_DA_DARKPOWER = 261, + //SI_DA_EARPLUG = 262, + //SI_DA_CONTRACT = 263, //Bio Mob effect on you and SI_TRICKDEAD icon + //SI_DA_BLACK = 264, //For short time blurry screen + //SI_DA_MAGICCART = 265, + //SI_CRYSTAL = 266, + //SI_DA_REBUILD = 267, + //SI_DA_EDARKNESS = 268, + //SI_DA_EGUARDIAN = 269, + //SI_DA_TIMEOUT = 270, + SI_FOOD_STR_CASH = 271, + SI_FOOD_AGI_CASH = 272, + SI_FOOD_VIT_CASH = 273, + SI_FOOD_DEX_CASH = 274, + SI_FOOD_INT_CASH = 275, + SI_FOOD_LUK_CASH = 276, + SI_MER_FLEE = 277, + SI_MER_ATK = 278, + SI_MER_HP = 279, + SI_MER_SP = 280, + SI_MER_HIT = 281, + SI_SLOWCAST = 282, + //SI_MAGICMIRROR = 283, + //SI_STONESKIN = 284, + //SI_ANTIMAGIC = 285, + SI_CRITICALWOUND = 286, + //SI_NPC_DEFENDER = 287, + //SI_NOACTION_WAIT = 288, + SI_MOVHASTE_HORSE = 289, + SI_PROTECT_DEF = 290, + SI_PROTECT_MDEF = 291, + SI_HEALPLUS = 292, + SI_S_LIFEPOTION = 293, + SI_L_LIFEPOTION = 294, + SI_CRITICALPERCENT = 295, + SI_PLUSAVOIDVALUE = 296, + //SI_ATKER_ASPD = 297, + //SI_TARGET_ASPD = 298, + //SI_ATKER_MOVESPEED = 299, + + SI_ATKER_BLOOD = 300, + SI_TARGET_BLOOD = 301, + SI_ARMOR_PROPERTY = 302, + //SI_REUSE_LIMIT_A = 303, + SI_HELLPOWER = 304, + //SI_STEAMPACK = 305, + //SI_REUSE_LIMIT_B = 306, + //SI_REUSE_LIMIT_C = 307, + //SI_REUSE_LIMIT_D = 308, + //SI_REUSE_LIMIT_E = 309, + //SI_REUSE_LIMIT_F = 310, + SI_INVINCIBLE = 311, + SI_CASH_PLUSONLYJOBEXP = 312, + SI_PARTYFLEE = 313, + SI_ANGEL_PROTECT = 314, + //SI_ENDURE_MDEF = 315, + SI_ENCHANTBLADE = 316, + SI_DEATHBOUND = 317, + SI_REFRESH = 318, + SI_GIANTGROWTH = 319, + SI_STONEHARDSKIN = 320, + SI_VITALITYACTIVATION = 321, + SI_FIGHTINGSPIRIT = 322, + SI_ABUNDANCE = 323, + SI_REUSE_MILLENNIUMSHIELD = 324, + SI_REUSE_CRUSHSTRIKE = 325, + SI_REUSE_REFRESH = 326, + SI_REUSE_STORMBLAST = 327, + SI_VENOMIMPRESS = 328, + SI_EPICLESIS = 329, + SI_ORATIO = 330, + SI_LAUDAAGNUS = 331, + SI_LAUDARAMUS = 332, + SI_CLOAKINGEXCEED = 333, + SI_HALLUCINATIONWALK = 334, + SI_HALLUCINATIONWALK_POSTDELAY = 335, + SI_RENOVATIO = 336, + SI_WEAPONBLOCKING = 337, + SI_WEAPONBLOCKING_POSTDELAY = 338, + SI_ROLLINGCUTTER = 339, + SI_EXPIATIO = 340, + SI_POISONINGWEAPON = 341, + SI_TOXIN = 342, + SI_PARALYSE = 343, + SI_VENOMBLEED = 344, + SI_MAGICMUSHROOM = 345, + SI_DEATHHURT = 346, + SI_PYREXIA = 347, + SI_OBLIVIONCURSE = 348, + SI_LEECHESEND = 349, + + SI_DUPLELIGHT = 350, + SI_FROSTMISTY = 351, + SI_FEARBREEZE = 352, + SI_ELECTRICSHOCKER = 353, + SI_MARSHOFABYSS = 354, + SI_RECOGNIZEDSPELL = 355, + SI_STASIS = 356, + SI_WUGRIDER = 357, + SI_WUGDASH = 358, + SI_WUGBITE = 359, + SI_CAMOUFLAGE = 360, + SI_ACCELERATION = 361, + SI_HOVERING = 362, + SI_SPHERE_1 = 363, + SI_SPHERE_2 = 364, + SI_SPHERE_3 = 365, + SI_SPHERE_4 = 366, + SI_SPHERE_5 = 367, + SI_MVPCARD_TAOGUNKA = 368, + SI_MVPCARD_MISTRESS = 369, + SI_MVPCARD_ORCHERO = 370, + SI_MVPCARD_ORCLORD = 371, + SI_OVERHEAT_LIMITPOINT = 372, + SI_OVERHEAT = 373, + SI_SHAPESHIFT = 374, + SI_INFRAREDSCAN = 375, + SI_MAGNETICFIELD = 376, + SI_NEUTRALBARRIER = 377, + SI_NEUTRALBARRIER_MASTER = 378, + SI_STEALTHFIELD = 379, + SI_STEALTHFIELD_MASTER = 380, + SI_MANU_ATK = 381, + SI_MANU_DEF = 382, + SI_SPL_ATK = 383, + SI_SPL_DEF = 384, + SI_REPRODUCE = 385, + SI_MANU_MATK = 386, + SI_SPL_MATK = 387, + SI_STR_SCROLL = 388, + SI_INT_SCROLL = 389, + SI_LG_REFLECTDAMAGE = 390, + SI_FORCEOFVANGUARD = 391, + SI_BUCHEDENOEL = 392, + SI_AUTOSHADOWSPELL = 393, + SI_SHADOWFORM = 394, + SI_RAID = 395, + SI_SHIELDSPELL_DEF = 396, + SI_SHIELDSPELL_MDEF = 397, + SI_SHIELDSPELL_REF = 398, + SI_BODYPAINT = 399, + + SI_EXEEDBREAK = 400, + SI_ADORAMUS = 401, + SI_PRESTIGE = 402, + SI_INVISIBILITY = 403, + SI_DEADLYINFECT = 404, + SI_BANDING = 405, + SI_EARTHDRIVE = 406, + SI_INSPIRATION = 407, + SI_ENERVATION = 408, + SI_GROOMY = 409, + SI_RAISINGDRAGON = 410, + SI_IGNORANCE = 411, + SI_LAZINESS = 412, + SI_LIGHTNINGWALK = 413, + SI_ACARAJE = 414, + SI_UNLUCKY = 415, + SI_CURSEDCIRCLE_ATKER = 416, + SI_CURSEDCIRCLE_TARGET = 417, + SI_WEAKNESS = 418, + SI_CRESCENTELBOW = 419, + SI_NOEQUIPACCESSARY = 420, + SI_STRIPACCESSARY = 421, + SI_MANHOLE = 422, + SI_POPECOOKIE = 423, + SI_FALLENEMPIRE = 424, + SI_GENTLETOUCH_ENERGYGAIN = 425, + SI_GENTLETOUCH_CHANGE = 426, + SI_GENTLETOUCH_REVITALIZE = 427, + SI_BLOODYLUST = 428, + SI_SWINGDANCE = 429, + SI_SYMPHONYOFLOVERS = 430, + SI_PROPERTYWALK = 431, + SI_SPELLFIST = 432, + SI_NETHERWORLD = 433, + SI_SIREN = 434, + SI_DEEPSLEEP = 435, + SI_SIRCLEOFNATURE = 436, + SI_COLD = 437, + SI_GLOOMYDAY = 438, + SI_SONG_OF_MANA = 439, + SI_CLOUDKILL = 440, + SI_DANCEWITHWUG = 441, + SI_RUSHWINDMILL = 442, + SI_ECHOSONG = 443, + SI_HARMONIZE = 444, + SI_STRIKING = 445, + SI_WARMER = 446, + SI_MOONLITSERENADE = 447, + SI_SATURDAYNIGHTFEVER = 448, + SI_SITDOWN_FORCE = 449, + + SI_ANALYZE = 450, + SI_LERADSDEW = 451, + SI_MELODYOFSINK = 452, + SI_WARCRYOFBEYOND = 453, + SI_UNLIMITEDHUMMINGVOICE = 454, + SI_SPELLBOOK1 = 455, + SI_SPELLBOOK2 = 456, + SI_SPELLBOOK3 = 457, + SI_FREEZE_SP = 458, + SI_GN_TRAINING_SWORD = 459, + SI_GN_REMODELING_CART = 460, + SI_CARTSBOOST = 461, + SI_FIXEDCASTINGTM_REDUCE = 462, + SI_THORNTRAP = 463, + SI_BLOODSUCKER = 464, + SI_SPORE_EXPLOSION = 465, + SI_DEMONIC_FIRE = 466, + SI_FIRE_EXPANSION_SMOKE_POWDER = 467, + SI_FIRE_EXPANSION_TEAR_GAS = 468, + SI_BLOCKING_PLAY = 469, + SI_MANDRAGORA = 470, + SI_ACTIVATE = 471, + SI_SECRAMENT = 472, + SI_ASSUMPTIO2 = 473, + SI_TK_SEVENWIND = 474, + SI_LIMIT_ODINS_RECALL = 475, + SI_STOMACHACHE = 476, + SI_MYSTERIOUS_POWDER = 477, + SI_MELON_BOMB = 478, + SI_BANANA_BOMB_SITDOWN_POSTDELAY = 479, + SI_PROMOTE_HEALTH_RESERCH = 480, + SI_ENERGY_DRINK_RESERCH = 481, + SI_EXTRACT_WHITE_POTION_Z = 482, + SI_VITATA_500 = 483, + SI_EXTRACT_SALAMINE_JUICE = 484, + SI_BOOST500 = 485, + SI_FULL_SWING_K = 486, + SI_MANA_PLUS = 487, + SI_MUSTLE_M = 488, + SI_LIFE_FORCE_F = 489, + SI_VACUUM_EXTREME = 490, + SI_SAVAGE_STEAK = 491, + SI_COCKTAIL_WARG_BLOOD = 492, + SI_MINOR_BBQ = 493, + SI_SIROMA_ICE_TEA = 494, + SI_DROCERA_HERB_STEAMED = 495, + SI_PUTTI_TAILS_NOODLES = 496, + SI_BANANA_BOMB = 497, + SI_SUMMON_AGNI = 498, + SI_SPELLBOOK4 = 499, + + SI_SPELLBOOK5 = 500, + SI_SPELLBOOK6 = 501, + SI_SPELLBOOK7 = 502, + SI_ELEMENTAL_AGGRESSIVE = 503, + SI_RETURN_TO_ELDICASTES = 504, + SI_BANDING_DEFENCE = 505, + SI_SKELSCROLL = 506, + SI_DISTRUCTIONSCROLL = 507, + SI_ROYALSCROLL = 508, + SI_IMMUNITYSCROLL = 509, + SI_MYSTICSCROLL = 510, + SI_BATTLESCROLL = 511, + SI_ARMORSCROLL = 512, + SI_FREYJASCROLL = 513, + SI_SOULSCROLL = 514, + SI_CIRCLE_OF_FIRE = 515, + SI_CIRCLE_OF_FIRE_OPTION = 516, + SI_FIRE_CLOAK = 517, + SI_FIRE_CLOAK_OPTION = 518, + SI_WATER_SCREEN = 519, + SI_WATER_SCREEN_OPTION = 520, + SI_WATER_DROP = 521, + SI_WATER_DROP_OPTION = 522, + SI_WIND_STEP = 523, + SI_WIND_STEP_OPTION = 524, + SI_WIND_CURTAIN = 525, + SI_WIND_CURTAIN_OPTION = 526, + SI_WATER_BARRIER = 527, + SI_ZEPHYR = 528, + SI_SOLID_SKIN = 529, + SI_SOLID_SKIN_OPTION = 530, + SI_STONE_SHIELD = 531, + SI_STONE_SHIELD_OPTION = 532, + SI_POWER_OF_GAIA = 533, + //SI_EL_WAIT = 534, + //SI_EL_PASSIVE = 535, + //SI_EL_DEFENSIVE = 536, + //SI_EL_OFFENSIVE = 537, + //SI_EL_COST = 538, + SI_PYROTECHNIC = 539, + SI_PYROTECHNIC_OPTION = 540, + SI_HEATER = 541, + SI_HEATER_OPTION = 542, + SI_TROPIC = 543, + SI_TROPIC_OPTION = 544, + SI_AQUAPLAY = 545, + SI_AQUAPLAY_OPTION = 546, + SI_COOLER = 547, + SI_COOLER_OPTION = 548, + SI_CHILLY_AIR = 549, + + SI_CHILLY_AIR_OPTION = 550, + SI_GUST = 551, + SI_GUST_OPTION = 552, + SI_BLAST = 553, + SI_BLAST_OPTION = 554, + SI_WILD_STORM = 555, + SI_WILD_STORM_OPTION = 556, + SI_PETROLOGY = 557, + SI_PETROLOGY_OPTION = 558, + SI_CURSED_SOIL = 559, + SI_CURSED_SOIL_OPTION = 560, + SI_UPHEAVAL = 561, + SI_UPHEAVAL_OPTION = 562, + SI_TIDAL_WEAPON = 563, + SI_TIDAL_WEAPON_OPTION = 564, + SI_ROCK_CRUSHER = 565, + SI_ROCK_CRUSHER_ATK = 566, + SI_FIRE_INSIGNIA = 567, + SI_WATER_INSIGNIA = 568, + SI_WIND_INSIGNIA = 569, + SI_EARTH_INSIGNIA = 570, + SI_EQUIPED_FLOOR = 571, + SI_GUARDIAN_RECALL = 572, + SI_MORA_BUFF = 573, + SI_REUSE_LIMIT_G = 574, + SI_REUSE_LIMIT_H = 575, + SI_NEEDLE_OF_PARALYZE = 576, + SI_PAIN_KILLER = 577, + SI_G_LIFEPOTION = 578, + SI_VITALIZE_POTION = 579, + SI_LIGHT_OF_REGENE = 580, + SI_OVERED_BOOST = 581, + SI_SILENT_BREEZE = 582, + SI_ODINS_POWER = 583, + SI_STYLE_CHANGE = 584, + SI_SONIC_CLAW_POSTDELAY = 585, // ID's 586 - 595 Currently Unused - SI_SILVERVEIN_RUSH_POSTDELAY = 596, - SI_MIDNIGHT_FRENZY_POSTDELAY = 597, - SI_GOLDENE_FERSE = 598, - SI_ANGRIFFS_MODUS = 599, - SI_TINDER_BREAKER = 600, - SI_TINDER_BREAKER_POSTDELAY = 601, - SI_CBC = 602, - SI_CBC_POSTDELAY = 603, - SI_EQC = 604, - SI_MAGMA_FLOW = 605, - SI_GRANITIC_ARMOR = 606, - SI_PYROCLASTIC = 607, - SI_VOLCANIC_ASH = 608, - SI_SPIRITS_SAVEINFO1 = 609, - SI_SPIRITS_SAVEINFO2 = 610, - SI_MAGIC_CANDY = 611, - SI_SEARCH_STORE_INFO = 612, - SI_ALL_RIDING = 613, - SI_ALL_RIDING_REUSE_LIMIT = 614, - SI_MACRO = 615, - SI_MACRO_POSTDELAY = 616, - SI_BEER_BOTTLE_CAP = 617, - SI_OVERLAPEXPUP = 618, - SI_PC_IZ_DUN05 = 619, - SI_CRUSHSTRIKE = 620, - SI_MONSTER_TRANSFORM = 621, - SI_SIT = 622, - SI_ONAIR = 623, - SI_MTF_ASPD = 624, - SI_MTF_RANGEATK = 625, - SI_MTF_MATK = 626, - SI_MTF_MLEATKED = 627, - SI_MTF_CRIDAMAGE = 628, - SI_REUSE_LIMIT_MTF = 629, - SI_MACRO_PERMIT = 630, - SI_MACRO_PLAY = 631, - SI_SKF_CAST = 632, - SI_SKF_ASPD = 633, - SI_SKF_ATK = 634, - SI_SKF_MATK = 635, - SI_REWARD_PLUSONLYJOBEXP = 636, - SI_HANDICAPSTATE_NORECOVER = 637, - SI_SET_NUM_DEF = 638, - SI_SET_NUM_MDEF = 639, - SI_SET_PER_DEF = 640, - SI_SET_PER_MDEF = 641, - SI_PARTYBOOKING_SEARCH_DEALY = 642, - SI_PARTYBOOKING_REGISTER_DEALY = 643, - SI_PERIOD_TIME_CHECK_DETECT_SKILL = 644, - SI_KO_JYUMONJIKIRI = 645, - SI_MEIKYOUSISUI = 646, - SI_ATTHASTE_CASH = 647, - SI_EQUIPPED_DIVINE_ARMOR = 648, - SI_EQUIPPED_HOLY_ARMOR = 649, - SI_2011RWC = 650, - SI_KYOUGAKU = 651, - SI_IZAYOI = 652, - SI_ZENKAI = 653, - SI_KG_KAGEHUMI = 654, - SI_KYOMU = 655, - SI_KAGEMUSYA = 656, - SI_ZANGETSU = 657, - SI_PHI_DEMON = 658, - SI_GENSOU = 659, - SI_AKAITSUKI = 660, - SI_TETANY = 661, - SI_GM_BATTLE = 662, - SI_GM_BATTLE2 = 663, - SI_2011RWC_SCROLL = 664, - SI_ACTIVE_MONSTER_TRANSFORM = 665, - SI_MYSTICPOWDER = 666, - SI_ECLAGE_RECALL = 667, - SI_ENTRY_QUEUE_APPLY_DELAY = 668, - SI_REUSE_LIMIT_ECL = 669, - SI_M_LIFEPOTION = 670, + SI_SILVERVEIN_RUSH_POSTDELAY = 596, + SI_MIDNIGHT_FRENZY_POSTDELAY = 597, + SI_GOLDENE_FERSE = 598, + SI_ANGRIFFS_MODUS = 599, + + SI_TINDER_BREAKER = 600, + SI_TINDER_BREAKER_POSTDELAY = 601, + SI_CBC = 602, + SI_CBC_POSTDELAY = 603, + SI_EQC = 604, + SI_MAGMA_FLOW = 605, + SI_GRANITIC_ARMOR = 606, + SI_PYROCLASTIC = 607, + SI_VOLCANIC_ASH = 608, + SI_SPIRITS_SAVEINFO1 = 609, + SI_SPIRITS_SAVEINFO2 = 610, + SI_MAGIC_CANDY = 611, + SI_SEARCH_STORE_INFO = 612, + SI_ALL_RIDING = 613, + SI_ALL_RIDING_REUSE_LIMIT = 614, + SI_MACRO = 615, + SI_MACRO_POSTDELAY = 616, + SI_BEER_BOTTLE_CAP = 617, + SI_OVERLAPEXPUP = 618, + SI_PC_IZ_DUN05 = 619, + SI_CRUSHSTRIKE = 620, + SI_MONSTER_TRANSFORM = 621, + SI_SIT = 622, + SI_ONAIR = 623, + SI_MTF_ASPD = 624, + SI_MTF_RANGEATK = 625, + SI_MTF_MATK = 626, + SI_MTF_MLEATKED = 627, + SI_MTF_CRIDAMAGE = 628, + SI_REUSE_LIMIT_MTF = 629, + SI_MACRO_PERMIT = 630, + SI_MACRO_PLAY = 631, + SI_SKF_CAST = 632, + SI_SKF_ASPD = 633, + SI_SKF_ATK = 634, + SI_SKF_MATK = 635, + SI_REWARD_PLUSONLYJOBEXP = 636, + SI_HANDICAPSTATE_NORECOVER = 637, + SI_SET_NUM_DEF = 638, + SI_SET_NUM_MDEF = 639, + SI_SET_PER_DEF = 640, + SI_SET_PER_MDEF = 641, + SI_PARTYBOOKING_SEARCH_DEALY = 642, + SI_PARTYBOOKING_REGISTER_DEALY = 643, + SI_PERIOD_TIME_CHECK_DETECT_SKILL = 644, + SI_KO_JYUMONJIKIRI = 645, + SI_MEIKYOUSISUI = 646, + SI_ATTHASTE_CASH = 647, + SI_EQUIPPED_DIVINE_ARMOR = 648, + SI_EQUIPPED_HOLY_ARMOR = 649, + + SI_2011RWC = 650, + SI_KYOUGAKU = 651, + SI_IZAYOI = 652, + SI_ZENKAI = 653, + SI_KG_KAGEHUMI = 654, + SI_KYOMU = 655, + SI_KAGEMUSYA = 656, + SI_ZANGETSU = 657, + SI_PHI_DEMON = 658, + SI_GENSOU = 659, + SI_AKAITSUKI = 660, + SI_TETANY = 661, + SI_GM_BATTLE = 662, + SI_GM_BATTLE2 = 663, + SI_2011RWC_SCROLL = 664, + SI_ACTIVE_MONSTER_TRANSFORM = 665, + SI_MYSTICPOWDER = 666, + SI_ECLAGE_RECALL = 667, + SI_ENTRY_QUEUE_APPLY_DELAY = 668, + SI_REUSE_LIMIT_ECL = 669, + SI_M_LIFEPOTION = 670, SI_ENTRY_QUEUE_NOTIFY_ADMISSION_TIME_OUT = 671, - SI_UNKNOWN_NAME = 672, - SI_ON_PUSH_CART = 673, - SI_HAT_EFFECT = 674, - SI_FLOWER_LEAF = 675, - SI_RAY_OF_PROTECTION = 676, - SI_GLASTHEIM_ATK = 677, - SI_GLASTHEIM_DEF = 678, - SI_GLASTHEIM_HEAL = 679, - SI_GLASTHEIM_HIDDEN = 680, - SI_GLASTHEIM_STATE = 681, - SI_GLASTHEIM_ITEMDEF = 682, - SI_GLASTHEIM_HPSP = 683, - SI_HOMUN_SKILL_POSTDELAY = 684, - SI_ALMIGHTY = 685, - SI_GVG_GIANT = 686, - SI_GVG_GOLEM = 687, - SI_GVG_STUN = 688, - SI_GVG_STONE = 689, - SI_GVG_FREEZ = 690, - SI_GVG_SLEEP = 691, - SI_GVG_CURSE = 692, - SI_GVG_SILENCE = 693, - SI_GVG_BLIND = 694, - SI_CLIENT_ONLY_EQUIP_ARROW = 695, - SI_CLAN_INFO = 696, - SI_JP_EVENT01 = 697, - SI_JP_EVENT02 = 698, - SI_JP_EVENT03 = 699, - SI_JP_EVENT04 = 700, - SI_TELEPORT_FIXEDCASTINGDELAY = 701, - SI_GEFFEN_MAGIC1 = 702, - SI_GEFFEN_MAGIC2 = 703, - SI_GEFFEN_MAGIC3 = 704, - SI_QUEST_BUFF1 = 705, - SI_QUEST_BUFF2 = 706, - SI_QUEST_BUFF3 = 707, - SI_REUSE_LIMIT_RECALL = 708, - SI_SAVEPOSITION = 709, - SI_HANDICAPSTATE_ICEEXPLO = 710, - SI_FENRIR_CARD = 711, - SI_REUSE_LIMIT_ASPD_POTION = 712, - SI_MAXPAIN = 713, - SI_PC_STOP = 714, - SI_FRIGG_SONG = 715, - SI_OFFERTORIUM = 716, - SI_TELEKINESIS_INTENSE = 717, - SI_MOONSTAR = 718, - SI_STRANGELIGHTS = 719, - SI_FULL_THROTTLE = 720, - SI_REBOUND = 721, - SI_UNLIMIT = 722, - SI_KINGS_GRACE = 723, - SI_ITEM_ATKMAX = 724, - SI_ITEM_ATKMIN = 725, - SI_ITEM_MATKMAX = 726, - SI_ITEM_MATKMIN = 727, - SI_SUPER_STAR = 728, - SI_HIGH_RANKER = 729, - SI_DARKCROW = 730, - SI_2013_VALENTINE1 = 731, - SI_2013_VALENTINE2 = 732, - SI_2013_VALENTINE3 = 733, - //SI_ = 734, - //SI_ = 735, - SI_CHILL = 736, - SI_BURNT = 737, + SI_UNKNOWN_NAME = 672, + SI_ON_PUSH_CART = 673, + SI_HAT_EFFECT = 674, + SI_FLOWER_LEAF = 675, + SI_RAY_OF_PROTECTION = 676, + SI_GLASTHEIM_ATK = 677, + SI_GLASTHEIM_DEF = 678, + SI_GLASTHEIM_HEAL = 679, + SI_GLASTHEIM_HIDDEN = 680, + SI_GLASTHEIM_STATE = 681, + SI_GLASTHEIM_ITEMDEF = 682, + SI_GLASTHEIM_HPSP = 683, + SI_HOMUN_SKILL_POSTDELAY = 684, + SI_ALMIGHTY = 685, + SI_GVG_GIANT = 686, + SI_GVG_GOLEM = 687, + SI_GVG_STUN = 688, + SI_GVG_STONE = 689, + SI_GVG_FREEZ = 690, + SI_GVG_SLEEP = 691, + SI_GVG_CURSE = 692, + SI_GVG_SILENCE = 693, + SI_GVG_BLIND = 694, + SI_CLIENT_ONLY_EQUIP_ARROW = 695, + SI_CLAN_INFO = 696, + SI_JP_EVENT01 = 697, + SI_JP_EVENT02 = 698, + SI_JP_EVENT03 = 699, + + SI_JP_EVENT04 = 700, + SI_TELEPORT_FIXEDCASTINGDELAY = 701, + SI_GEFFEN_MAGIC1 = 702, + SI_GEFFEN_MAGIC2 = 703, + SI_GEFFEN_MAGIC3 = 704, + SI_QUEST_BUFF1 = 705, + SI_QUEST_BUFF2 = 706, + SI_QUEST_BUFF3 = 707, + SI_REUSE_LIMIT_RECALL = 708, + SI_SAVEPOSITION = 709, + SI_HANDICAPSTATE_ICEEXPLO = 710, + SI_FENRIR_CARD = 711, + SI_REUSE_LIMIT_ASPD_POTION = 712, + SI_MAXPAIN = 713, + SI_PC_STOP = 714, + SI_FRIGG_SONG = 715, + SI_OFFERTORIUM = 716, + SI_TELEKINESIS_INTENSE = 717, + SI_MOONSTAR = 718, + SI_STRANGELIGHTS = 719, + SI_FULL_THROTTLE = 720, + SI_REBOUND = 721, + SI_UNLIMIT = 722, + SI_KINGS_GRACE = 723, + SI_ITEM_ATKMAX = 724, + SI_ITEM_ATKMIN = 725, + SI_ITEM_MATKMAX = 726, + SI_ITEM_MATKMIN = 727, + SI_SUPER_STAR = 728, + SI_HIGH_RANKER = 729, + SI_DARKCROW = 730, + SI_2013_VALENTINE1 = 731, + SI_2013_VALENTINE2 = 732, + SI_2013_VALENTINE3 = 733, + SI_ILLUSIONDOPING = 734, + //SI_ = 735, + SI_CHILL = 736, + SI_BURNT = 737, +// SI_PCCAFE_PLAY_TIME = 738, +// SI_TWISTED_TIME = 739, + SI_FLASHCOMBO = 740, + +// SI_JITTER_BUFF1 = 741, +// SI_JITTER_BUFF2 = 742, +// SI_JITTER_BUFF3 = 743, +// SI_JITTER_BUFF4 = 744, +// SI_JITTER_BUFF5 = 745, +// SI_JITTER_BUFF6 = 746, +// SI_JITTER_BUFF7 = 747, +// SI_JITTER_BUFF8 = 748, +// SI_JITTER_BUFF9 = 749, +// SI_JITTER_BUFF10 = 750, +// SI_CUP_OF_BOZA = 751, + SI_B_TRAP = 752, + SI_E_CHAIN = 753, + SI_E_QD_SHOT_READY = 754, + SI_C_MARKER = 755, + SI_H_MINE = 756, + SI_H_MINE_SPLASH = 757, + SI_P_ALTER = 758, + SI_HEAT_BARREL = 759, + SI_ANTI_M_BLAST = 760, + SI_SLUGSHOT = 761, + SI_SWORDCLAN = 762, + SI_ARCWANDCLAN = 763, + SI_GOLDENMACECLAN = 764, + SI_CROSSBOWCLAN = 765, + SI_PACKING_ENVELOPE1 = 766, + SI_PACKING_ENVELOPE2 = 767, + SI_PACKING_ENVELOPE3 = 768, + SI_PACKING_ENVELOPE4 = 769, + SI_PACKING_ENVELOPE5 = 770, + SI_PACKING_ENVELOPE6 = 771, + SI_PACKING_ENVELOPE7 = 772, + SI_PACKING_ENVELOPE8 = 773, + SI_PACKING_ENVELOPE9 = 774, + SI_PACKING_ENVELOPE10 = 775, + SI_GLASTHEIM_TRANS = 776, +// SI_ZONGZI_POUCH_TRANS = 777, + SI_HEAT_BARREL_AFTER = 778, + SI_DECORATION_OF_MUSIC = 779, + +// SI_OVERSEAEXPUP = 780, +// SI_CLOWN_N_GYPSY_CARD = 781, +// SI_OPEN_NPC_MARKET = 782, +// SI_BEEF_RIB_STEW = 783, +// SI_PORK_RIB_STEW = 784, +// SI_CHUSEOK_MONDAY = 785, +// SI_CHUSEOK_TUESDAY = 786, +// SI_CHUSEOK_WEDNESDAY = 787, +// SI_CHUSEOK_THURSDAY = 788, +// SI_CHUSEOK_FRIDAY = 789, +// SI_CHUSEOK_WEEKEND = 790, +// SI_ALL_LIGHTGUARD = 791, +// SI_ALL_LIGHTGUARD_COOL_TIME = 792, +// SI_MTF_MHP = 793, +// SI_MTF_MSP = 794, +// SI_MTF_PUMPKIN = 795, +// SI_MTF_HITFLEE = 796, +// SI_MTF_CRIDAMAGE2 = 797, +// SI_MTF_SPDRAIN = 798, +// SI_ACUO_MINT_GUM = 799, +// ... +// SI_GUILD_STORAGE = 810, +// ... +// SI_JUMPINGCLAN = 815, +// ... +// SI_MTF_RANGEATK2 = 818, +// SI_MTF_ASPD2 = 819, +// SI_MTF_MATK2 = 820, + SI_MAX, }; - // JOINTBEAT stackable ailments enum e_joint_break { @@ -1423,8 +1561,6 @@ enum e_joint_break BREAK_FLAGS = BREAK_ANKLE | BREAK_WRIST | BREAK_KNEE | BREAK_SHOULDER | BREAK_WAIST | BREAK_NECK, }; -extern int current_equip_item_index; -extern int current_equip_card_id; //Mode definitions to clear up code reading. [Skotlex] enum e_mode @@ -1444,6 +1580,7 @@ enum e_mode MD_CHANGETARGET_MELEE = 0x1000, MD_CHANGETARGET_CHASE = 0x2000, MD_TARGETWEAK = 0x4000, + MD_RANDOMTARGET = 0x8000, MD_MASK = 0xFFFF, }; @@ -1500,30 +1637,31 @@ enum { }; enum { - OPTION_NOTHING = 0x00000000, - OPTION_SIGHT = 0x00000001, - OPTION_HIDE = 0x00000002, - OPTION_CLOAK = 0x00000004, - OPTION_FALCON = 0x00000010, - OPTION_RIDING = 0x00000020, - OPTION_INVISIBLE = 0x00000040, - OPTION_ORCISH = 0x00000800, - OPTION_WEDDING = 0x00001000, - OPTION_RUWACH = 0x00002000, - OPTION_CHASEWALK = 0x00004000, - OPTION_FLYING = 0x00008000, //Note that clientside Flying and Xmas are 0x8000 for clients prior to 2007. - OPTION_XMAS = 0x00010000, - OPTION_TRANSFORM = 0x00020000, - OPTION_SUMMER = 0x00040000, - OPTION_DRAGON1 = 0x00080000, - OPTION_WUG = 0x00100000, - OPTION_WUGRIDER = 0x00200000, - OPTION_MADOGEAR = 0x00400000, - OPTION_DRAGON2 = 0x00800000, - OPTION_DRAGON3 = 0x01000000, - OPTION_DRAGON4 = 0x02000000, - OPTION_DRAGON5 = 0x04000000, - OPTION_HANBOK = 0x08000000, + OPTION_NOTHING = 0x00000000, + OPTION_SIGHT = 0x00000001, + OPTION_HIDE = 0x00000002, + OPTION_CLOAK = 0x00000004, + OPTION_FALCON = 0x00000010, + OPTION_RIDING = 0x00000020, + OPTION_INVISIBLE = 0x00000040, + OPTION_ORCISH = 0x00000800, + OPTION_WEDDING = 0x00001000, + OPTION_RUWACH = 0x00002000, + OPTION_CHASEWALK = 0x00004000, + OPTION_FLYING = 0x00008000, //Note that clientside Flying and Xmas are 0x8000 for clients prior to 2007. + OPTION_XMAS = 0x00010000, + OPTION_TRANSFORM = 0x00020000, + OPTION_SUMMER = 0x00040000, + OPTION_DRAGON1 = 0x00080000, + OPTION_WUG = 0x00100000, + OPTION_WUGRIDER = 0x00200000, + OPTION_MADOGEAR = 0x00400000, + OPTION_DRAGON2 = 0x00800000, + OPTION_DRAGON3 = 0x01000000, + OPTION_DRAGON4 = 0x02000000, + OPTION_DRAGON5 = 0x04000000, + OPTION_HANBOK = 0x08000000, + OPTION_OKTOBERFEST = 0x10000000, #ifndef NEW_CARTS OPTION_CART1 = 0x00000008, @@ -1538,6 +1676,7 @@ enum { // compound constants OPTION_DRAGON = OPTION_DRAGON1|OPTION_DRAGON2|OPTION_DRAGON3|OPTION_DRAGON4|OPTION_DRAGON5, + OPTION_COSTUME = OPTION_WEDDING|OPTION_XMAS|OPTION_SUMMER|OPTION_HANBOK|OPTION_OKTOBERFEST, }; //Defines for the manner system [Skotlex] @@ -1590,6 +1729,20 @@ enum scb_flag SCB_ALL = 0x3FFFFFFF }; +//Regen related flags. +enum e_regen { + RGN_HP = 0x01, + RGN_SP = 0x02, + RGN_SHP = 0x04, + RGN_SSP = 0x08, +}; + +enum e_status_calc_opt { + SCO_NONE = 0x0, + SCO_FIRST = 0x1, /* trigger the calculations that should take place only onspawn/once */ + SCO_FORCE = 0x2, /* only relevant to BL_PC types, ensures call bypasses the queue caused by delayed damage */ +}; + //Define to determine who gets HP/SP consumed on doing skills/etc. [Skotlex] #define BL_CONSUME (BL_PC|BL_HOM|BL_MER|BL_ELEM) //Define to determine who has regen @@ -1608,15 +1761,7 @@ typedef struct weapon_atk { unsigned short matk; unsigned char wlv; #endif -}weapon_atk; - -sc_type SkillStatusChangeTable[MAX_SKILL]; // skill -> status -int StatusIconChangeTable[SC_MAX]; // status -> "icon" (icon is a bit of a misnomer, since there exist values with no icon associated) -unsigned int StatusChangeFlagTable[SC_MAX]; // status -> flags -int StatusSkillChangeTable[SC_MAX]; // status -> skill -int StatusRelevantBLTypes[SI_MAX]; // "icon" -> enum bl_type (for clif->status_change to identify for which bl types to send packets) -bool StatusDisplayType[SC_MAX]; - +} weapon_atk; //For holding basic status (which can be modified by status changes) struct status_data { @@ -1630,7 +1775,7 @@ struct status_data { speed, amotion, adelay, dmotion, mode; - short + short hit, flee, cri, flee2, def2, mdef2, #ifdef RENEWAL_ASPD @@ -1647,6 +1792,9 @@ struct status_data { size, race; struct weapon_atk rhw, lhw; //Right Hand/Left Hand Weapon. +#ifdef RENEWAL + int equip_atk; +#endif }; //Additional regen data that only players have. @@ -1720,151 +1868,234 @@ struct status_change { unsigned char sg_counter; //Storm gust counter (previous hits from storm gust) #endif unsigned char bs_counter; // Blood Sucker counter + unsigned char fv_counter; // Force of vanguard counter struct status_change_entry *data[SC_MAX]; }; -// for looking up associated data -sc_type status_skill2sc(int skill); -int status_sc2skill(sc_type sc); -unsigned int status_sc2scb_flag(sc_type sc); -int status_type2relevant_bl_types(int type); -int status_get_sc_type(sc_type idx); -int status_damage(struct block_list *src,struct block_list *target,int hp,int sp, int walkdelay, int flag); //Define for standard HP damage attacks. -#define status_fix_damage(src, target, hp, walkdelay) status_damage(src, target, hp, 0, walkdelay, 0) +#define status_fix_damage(src, target, hp, walkdelay) (status->damage((src), (target), (hp), 0, (walkdelay), 0)) //Define for standard HP/SP damage triggers. -#define status_zap(bl, hp, sp) status_damage(NULL, bl, hp, sp, 0, 1) -//Define for standard HP/SP skill-related cost triggers (mobs require no HP/SP to use skills) -int status_charge(struct block_list* bl, int hp, int sp); -int status_percent_change(struct block_list *src,struct block_list *target,signed char hp_rate, signed char sp_rate, int flag); -//Easier handling of status_percent_change -#define status_percent_heal(bl, hp_rate, sp_rate) status_percent_change(NULL, bl, -(hp_rate), -(sp_rate), 0) -#define status_percent_damage(src, target, hp_rate, sp_rate, kill) status_percent_change(src, target, hp_rate, sp_rate, (kill)?1:2) +#define status_zap(bl, hp, sp) (status->damage(NULL, (bl), (hp), (sp), 0, 1)) +//Easier handling of status->percent_change +#define status_percent_heal(bl, hp_rate, sp_rate) (status->percent_change(NULL, (bl), -(hp_rate), -(sp_rate), 0)) +#define status_percent_damage(src, target, hp_rate, sp_rate, kill) (status->percent_change((src), (target), (hp_rate), (sp_rate), (kill)?1:2)) //Instant kill with no drops/exp/etc -#define status_kill(bl) status_percent_damage(NULL, bl, 100, 0, true) -//Used to set the hp/sp of an object to an absolute value (can't kill) -int status_set_hp(struct block_list *bl, unsigned int hp, int flag); -int status_set_sp(struct block_list *bl, unsigned int sp, int flag); -int status_heal(struct block_list *bl,int hp,int sp, int flag); -int status_revive(struct block_list *bl, unsigned char per_hp, unsigned char per_sp); - -struct regen_data *status_get_regen_data(struct block_list *bl); -struct status_data *status_get_status_data(struct block_list *bl); -struct status_data *status_get_base_status(struct block_list *bl); -const char * status_get_name(struct block_list *bl); -int status_get_class(struct block_list *bl); -int status_get_lv(struct block_list *bl); -#define status_get_range(bl) status_get_status_data(bl)->rhw.range -#define status_get_hp(bl) status_get_status_data(bl)->hp -#define status_get_max_hp(bl) status_get_status_data(bl)->max_hp -#define status_get_sp(bl) status_get_status_data(bl)->sp -#define status_get_max_sp(bl) status_get_status_data(bl)->max_sp -#define status_get_str(bl) status_get_status_data(bl)->str -#define status_get_agi(bl) status_get_status_data(bl)->agi -#define status_get_vit(bl) status_get_status_data(bl)->vit -#define status_get_int(bl) status_get_status_data(bl)->int_ -#define status_get_dex(bl) status_get_status_data(bl)->dex -#define status_get_luk(bl) status_get_status_data(bl)->luk -#define status_get_hit(bl) status_get_status_data(bl)->hit -#define status_get_flee(bl) status_get_status_data(bl)->flee -defType status_get_def(struct block_list *bl); -#define status_get_mdef(bl) status_get_status_data(bl)->mdef -#define status_get_flee2(bl) status_get_status_data(bl)->flee2 -#define status_get_def2(bl) status_get_status_data(bl)->def2 -#define status_get_mdef2(bl) status_get_status_data(bl)->mdef2 -#define status_get_critical(bl) status_get_status_data(bl)->cri -#define status_get_batk(bl) status_get_status_data(bl)->batk -#define status_get_watk(bl) status_get_status_data(bl)->rhw.atk -#define status_get_watk2(bl) status_get_status_data(bl)->rhw.atk2 -#define status_get_matk_max(bl) status_get_status_data(bl)->matk_max -#define status_get_matk_min(bl) status_get_status_data(bl)->matk_min -#define status_get_lwatk(bl) status_get_status_data(bl)->lhw.atk -#define status_get_lwatk2(bl) status_get_status_data(bl)->lhw.atk2 -unsigned short status_get_speed(struct block_list *bl); -#define status_get_adelay(bl) status_get_status_data(bl)->adelay -#define status_get_amotion(bl) status_get_status_data(bl)->amotion -#define status_get_dmotion(bl) status_get_status_data(bl)->dmotion -#define status_get_element(bl) status_get_status_data(bl)->def_ele -#define status_get_element_level(bl) status_get_status_data(bl)->ele_lv -unsigned char status_calc_attack_element(struct block_list *bl, struct status_change *sc, int element); -#define status_get_attack_sc_element(bl, sc) status_calc_attack_element(bl, sc, 0) -#define status_get_attack_element(bl) status_get_status_data(bl)->rhw.ele -#define status_get_attack_lelement(bl) status_get_status_data(bl)->lhw.ele -#define status_get_race(bl) status_get_status_data(bl)->race -#define status_get_size(bl) status_get_status_data(bl)->size -#define status_get_mode(bl) status_get_status_data(bl)->mode -int status_get_party_id(struct block_list *bl); -int status_get_guild_id(struct block_list *bl); -int status_get_emblem_id(struct block_list *bl); -int status_get_mexp(struct block_list *bl); -int status_get_race2(struct block_list *bl); - -struct view_data *status_get_viewdata(struct block_list *bl); -void status_set_viewdata(struct block_list *bl, int class_); -void status_change_init(struct block_list *bl); -struct status_change *status_get_sc(struct block_list *bl); - -int status_isdead(struct block_list *bl); -int status_isimmune(struct block_list *bl); - -int status_get_sc_def(struct block_list *bl, enum sc_type type, int rate, int tick, int flag); +#define status_kill(bl) status_percent_damage(NULL, (bl), 100, 0, true) + +#define status_get_range(bl) (status->get_status_data(bl)->rhw.range) +#define status_get_hp(bl) (status->get_status_data(bl)->hp) +#define status_get_max_hp(bl) (status->get_status_data(bl)->max_hp) +#define status_get_sp(bl) (status->get_status_data(bl)->sp) +#define status_get_max_sp(bl) (status->get_status_data(bl)->max_sp) +#define status_get_str(bl) (status->get_status_data(bl)->str) +#define status_get_agi(bl) (status->get_status_data(bl)->agi) +#define status_get_vit(bl) (status->get_status_data(bl)->vit) +#define status_get_int(bl) (status->get_status_data(bl)->int_) +#define status_get_dex(bl) (status->get_status_data(bl)->dex) +#define status_get_luk(bl) (status->get_status_data(bl)->luk) +#define status_get_hit(bl) (status->get_status_data(bl)->hit) +#define status_get_flee(bl) (status->get_status_data(bl)->flee) +#define status_get_mdef(bl) (status->get_status_data(bl)->mdef) +#define status_get_flee2(bl) (status->get_status_data(bl)->flee2) +#define status_get_def2(bl) (status->get_status_data(bl)->def2) +#define status_get_mdef2(bl) (status->get_status_data(bl)->mdef2) +#define status_get_critical(bl) (status->get_status_data(bl)->cri) +#define status_get_batk(bl) (status->get_status_data(bl)->batk) +#define status_get_watk(bl) (status->get_status_data(bl)->rhw.atk) +#define status_get_watk2(bl) (status->get_status_data(bl)->rhw.atk2) +#define status_get_matk_max(bl) (status->get_status_data(bl)->matk_max) +#define status_get_matk_min(bl) (status->get_status_data(bl)->matk_min) +#define status_get_lwatk(bl) (status->get_status_data(bl)->lhw.atk) +#define status_get_lwatk2(bl) (status->get_status_data(bl)->lhw.atk2) +#define status_get_adelay(bl) (status->get_status_data(bl)->adelay) +#define status_get_amotion(bl) (status->get_status_data(bl)->amotion) +#define status_get_dmotion(bl) (status->get_status_data(bl)->dmotion) +#define status_get_element(bl) (status->get_status_data(bl)->def_ele) +#define status_get_element_level(bl) (status->get_status_data(bl)->ele_lv) +#define status_get_attack_sc_element(bl, sc) (status->calc_attack_element((bl), (sc), 0)) +#define status_get_attack_element(bl) (status->get_status_data(bl)->rhw.ele) +#define status_get_attack_lelement(bl) (status->get_status_data(bl)->lhw.ele) +#define status_get_race(bl) (status->get_status_data(bl)->race) +#define status_get_size(bl) (status->get_status_data(bl)->size) +#define status_get_mode(bl) (status->get_status_data(bl)->mode) + //Short version, receives rate in 1->100 range, and does not uses a flag setting. -#define sc_start(bl, type, rate, val1, tick) status_change_start(bl,type,100*(rate),val1,0,0,0,tick,0) -#define sc_start2(bl, type, rate, val1, val2, tick) status_change_start(bl,type,100*(rate),val1,val2,0,0,tick,0) -#define sc_start4(bl, type, rate, val1, val2, val3, val4, tick) status_change_start(bl,type,100*(rate),val1,val2,val3,val4,tick,0) - -int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val1,int val2,int val3,int val4,int tick,int flag); -int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const char* file, int line); -#define status_change_end(bl,type,tid) status_change_end_(bl,type,tid,__FILE__,__LINE__) -int kaahi_heal_timer(int tid, unsigned int tick, int id, intptr_t data); -int status_change_timer(int tid, unsigned int tick, int id, intptr_t data); -int status_change_timer_sub(struct block_list* bl, va_list ap); -int status_change_clear(struct block_list* bl, int type); -int status_change_clear_buffs(struct block_list* bl, int type); - -#define status_calc_bl(bl, flag) status_calc_bl_(bl, (enum scb_flag)(flag), false) -#define status_calc_mob(md, first) status_calc_bl_(&(md)->bl, SCB_ALL, first) -#define status_calc_pet(pd, first) status_calc_bl_(&(pd)->bl, SCB_ALL, first) -#define status_calc_pc(sd, first) status_calc_bl_(&(sd)->bl, SCB_ALL, first) -#define status_calc_homunculus(hd, first) status_calc_bl_(&(hd)->bl, SCB_ALL, first) -#define status_calc_mercenary(md, first) status_calc_bl_(&(md)->bl, SCB_ALL, first) -#define status_calc_elemental(ed, first) status_calc_bl_(&(ed)->bl, SCB_ALL, first) -#define status_calc_npc(nd, first) status_calc_bl_(&(nd)->bl, SCB_ALL, first) - -void status_calc_bl_(struct block_list *bl, enum scb_flag flag, bool first); -int status_calc_mob_(struct mob_data* md, bool first); -int status_calc_pet_(struct pet_data* pd, bool first); -int status_calc_pc_(struct map_session_data* sd, bool first); -int status_calc_homunculus_(struct homun_data *hd, bool first); -int status_calc_mercenary_(struct mercenary_data *md, bool first); -int status_calc_elemental_(struct elemental_data *ed, bool first); - -void status_calc_misc(struct block_list *bl, struct status_data *status, int level); -void status_calc_regen(struct block_list *bl, struct status_data *status, struct regen_data *regen); -void status_calc_regen_rate(struct block_list *bl, struct regen_data *regen, struct status_change *sc); - -int status_check_skilluse(struct block_list *src, struct block_list *target, uint16 skill_id, int flag); // [Skotlex] -int status_check_visibility(struct block_list *src, struct block_list *target); //[Skotlex] - -int status_change_spread( struct block_list *src, struct block_list *bl ); - -defType status_calc_def(struct block_list *bl, struct status_change *sc, int, bool); -signed short status_calc_def2(struct block_list *,struct status_change *, int, bool); -defType status_calc_mdef(struct block_list *bl, struct status_change *sc, int, bool); -signed short status_calc_mdef2(struct block_list *,struct status_change *, int, bool); +#define sc_start(src, bl, type, rate, val1, tick) (status->change_start((src),(bl),(type),100*(rate),(val1),0,0,0,(tick),0)) +#define sc_start2(src, bl, type, rate, val1, val2, tick) (status->change_start((src),(bl),(type),100*(rate),(val1),(val2),0,0,(tick),0)) +#define sc_start4(src, bl, type, rate, val1, val2, val3, val4, tick) (status->change_start((src),(bl),(type),100*(rate),(val1),(val2),(val3),(val4),(tick),0)) -#ifdef RENEWAL -unsigned short status_base_matk(const struct status_data* status, int level); -int status_get_weapon_atk(struct block_list *src, struct weapon_atk *watk, int flag); -int status_get_total_mdef(struct block_list *src); -int status_get_total_def(struct block_list *src); -#endif +#define status_change_end(bl,type,tid) (status->change_end_((bl),(type),(tid),__FILE__,__LINE__)) + +#define status_calc_bl(bl, flag) (status->calc_bl_((bl), (enum scb_flag)(flag), SCO_NONE)) +#define status_calc_mob(md, opt) (status->calc_bl_(&(md)->bl, SCB_ALL, (opt))) +#define status_calc_pet(pd, opt) (status->calc_bl_(&(pd)->bl, SCB_ALL, (opt))) +#define status_calc_pc(sd, opt) (status->calc_bl_(&(sd)->bl, SCB_ALL, (opt))) +#define status_calc_homunculus(hd, opt) (status->calc_bl_(&(hd)->bl, SCB_ALL, (opt))) +#define status_calc_mercenary(md, opt) (status->calc_bl_(&(md)->bl, SCB_ALL, (opt))) +#define status_calc_elemental(ed, opt) (status->calc_bl_(&(ed)->bl, SCB_ALL, (opt))) +#define status_calc_npc(nd, opt) (status->calc_bl_(&(nd)->bl, SCB_ALL, (opt))) + +// bonus values and upgrade chances for refining equipment +struct s_refine_info { + int chance[MAX_REFINE]; // success chance + int bonus[MAX_REFINE]; // cumulative fixed bonus damage + int randombonus_max[MAX_REFINE]; // cumulative maximum random bonus damage +}; + +/*===================================== +* Interface : status.h +* Generated by HerculesInterfaceMaker +* created by Susu +*-------------------------------------*/ +struct status_interface { + + /* vars */ + int current_equip_item_index; + int current_equip_card_id; + /* */ + int max_weight_base[CLASS_COUNT]; + int hp_coefficient[CLASS_COUNT]; + int hp_coefficient2[CLASS_COUNT]; + int hp_sigma_val[CLASS_COUNT][MAX_LEVEL+1]; + int sp_coefficient[CLASS_COUNT]; + int aspd_base[CLASS_COUNT][MAX_WEAPON_TYPE+1]; // +1 for RENEWAL_ASPD + sc_type Skill2SCTable[MAX_SKILL]; // skill -> status + int IconChangeTable[SC_MAX]; // status -> "icon" (icon is a bit of a misnomer, since there exist values with no icon associated) + unsigned int ChangeFlagTable[SC_MAX]; // status -> flags + int SkillChangeTable[SC_MAX]; // status -> skill + int RelevantBLTypes[SI_MAX]; // "icon" -> enum bl_type (for clif->status_change to identify for which bl types to send packets) + bool DisplayType[SC_MAX]; + /* */ + struct s_refine_info refine_info[REFINE_TYPE_MAX]; + /* */ + int atkmods[3][MAX_WEAPON_TYPE];//ATK weapon modification for size (size_fix.txt) + char job_bonus[CLASS_COUNT][MAX_LEVEL]; + sc_conf_type sc_conf[SC_MAX]; + struct eri *data_ers; //For sc_data entries + struct status_data dummy; + int64 natural_heal_prev_tick; + unsigned int natural_heal_diff_tick; + /* */ + int (*init) (bool minimal); + void (*final) (void); + /* funcs */ + int (*get_refine_chance) (enum refine_type wlv, int refine); + // for looking up associated data + sc_type (*skill2sc) (int skill_id); + int (*sc2skill) (sc_type sc); + unsigned int (*sc2scb_flag) (sc_type sc); + int (*type2relevant_bl_types) (int type); + int (*get_sc_type) (sc_type idx); + int (*damage) (struct block_list *src,struct block_list *target,int64 hp,int64 sp, int walkdelay, int flag); + //Define for standard HP/SP skill-related cost triggers (mobs require no HP/SP to use skills) + int (*charge) (struct block_list* bl, int64 hp, int64 sp); + int (*percent_change) (struct block_list *src,struct block_list *target,signed char hp_rate, signed char sp_rate, int flag); + //Used to set the hp/sp of an object to an absolute value (can't kill) + int (*set_hp) (struct block_list *bl, unsigned int hp, int flag); + int (*set_sp) (struct block_list *bl, unsigned int sp, int flag); + int (*heal) (struct block_list *bl,int64 hp,int64 sp, int flag); + int (*revive) (struct block_list *bl, unsigned char per_hp, unsigned char per_sp); + int (*fixed_revive) (struct block_list *bl, unsigned int per_hp, unsigned int per_sp); + struct regen_data * (*get_regen_data) (struct block_list *bl); + struct status_data * (*get_status_data) (struct block_list *bl); + struct status_data * (*get_base_status) (struct block_list *bl); + const char * (*get_name) (struct block_list *bl); + int (*get_class) (struct block_list *bl); + int (*get_lv) (struct block_list *bl); + defType (*get_def) (struct block_list *bl); + unsigned short (*get_speed) (struct block_list *bl); + unsigned char (*calc_attack_element) (struct block_list *bl, struct status_change *sc, int element); + int (*get_party_id) (struct block_list *bl); + int (*get_guild_id) (struct block_list *bl); + int (*get_emblem_id) (struct block_list *bl); + int (*get_mexp) (struct block_list *bl); + int (*get_race2) (struct block_list *bl); + struct view_data * (*get_viewdata) (struct block_list *bl); + void (*set_viewdata) (struct block_list *bl, int class_); + void (*change_init) (struct block_list *bl); + struct status_change * (*get_sc) (struct block_list *bl); + int (*isdead) (struct block_list *bl); + int (*isimmune) (struct block_list *bl); + int (*get_sc_def) (struct block_list *src, struct block_list *bl, enum sc_type type, int rate, int tick, int flag); + int (*change_start) (struct block_list *src, struct block_list *bl, enum sc_type type, int rate, int val1, int val2, int val3, int val4, int tick, int flag); + int (*change_end_) (struct block_list* bl, enum sc_type type, int tid, const char* file, int line); + int (*kaahi_heal_timer) (int tid, int64 tick, int id, intptr_t data); + int (*change_timer) (int tid, int64 tick, int id, intptr_t data); + int (*change_timer_sub) (struct block_list* bl, va_list ap); + int (*change_clear) (struct block_list* bl, int type); + int (*change_clear_buffs) (struct block_list* bl, int type); + void (*calc_bl_) (struct block_list *bl, enum scb_flag flag, enum e_status_calc_opt opt); + int (*calc_mob_) (struct mob_data* md, enum e_status_calc_opt opt); + int (*calc_pet_) (struct pet_data* pd, enum e_status_calc_opt opt); + int (*calc_pc_) (struct map_session_data* sd, enum e_status_calc_opt opt); + int (*calc_homunculus_) (struct homun_data *hd, enum e_status_calc_opt opt); + int (*calc_mercenary_) (struct mercenary_data *md, enum e_status_calc_opt opt); + int (*calc_elemental_) (struct elemental_data *ed, enum e_status_calc_opt opt); + void (*calc_misc) (struct block_list *bl, struct status_data *st, int level); + void (*calc_regen) (struct block_list *bl, struct status_data *st, struct regen_data *regen); + void (*calc_regen_rate) (struct block_list *bl, struct regen_data *regen, struct status_change *sc); + int (*check_skilluse) (struct block_list *src, struct block_list *target, uint16 skill_id, int flag); // [Skotlex] + int (*check_visibility) (struct block_list *src, struct block_list *target); //[Skotlex] + int (*change_spread) (struct block_list *src, struct block_list *bl); + defType (*calc_def) (struct block_list *bl, struct status_change *sc, int def, bool viewable); + short (*calc_def2) (struct block_list *bl, struct status_change *sc, int def2, bool viewable); + defType (*calc_mdef) (struct block_list *bl, struct status_change *sc, int mdef, bool viewable); + short (*calc_mdef2) (struct block_list *bl, struct status_change *sc, int mdef2, bool viewable); + unsigned short (*calc_batk)(struct block_list *bl, struct status_change *sc, int batk, bool viewable); + unsigned short (*base_matk) (const struct status_data *st, int level); + int (*get_weapon_atk) (struct block_list *src, struct weapon_atk *watk, int flag); + int (*get_total_mdef) (struct block_list *src); + int (*get_total_def) (struct block_list *src); + int (*get_matk) (struct block_list *src, int flag); + void (*update_matk) ( struct block_list *bl ); + int (*readdb) (void); + + void (*initChangeTables) (void); + void (*initDummyData) (void); + int (*base_amotion_pc) (struct map_session_data *sd, struct status_data *st); + unsigned short (*base_atk) (const struct block_list *bl, const struct status_data *st); + void (*calc_sigma) (void); + unsigned int (*base_pc_maxhp) (struct map_session_data *sd, struct status_data *st); + unsigned int (*base_pc_maxsp) (struct map_session_data *sd, struct status_data *st); + int (*calc_npc_) (struct npc_data *nd, enum e_status_calc_opt opt); + unsigned short (*calc_str) (struct block_list *bl, struct status_change *sc, int str); + unsigned short (*calc_agi) (struct block_list *bl, struct status_change *sc, int agi); + unsigned short (*calc_vit) (struct block_list *bl, struct status_change *sc, int vit); + unsigned short (*calc_int) (struct block_list *bl, struct status_change *sc, int int_); + unsigned short (*calc_dex) (struct block_list *bl, struct status_change *sc, int dex); + unsigned short (*calc_luk) (struct block_list *bl, struct status_change *sc, int luk); + unsigned short (*calc_watk) (struct block_list *bl, struct status_change *sc, int watk, bool viewable); + unsigned short (*calc_matk) (struct block_list *bl, struct status_change *sc, int matk, bool viewable); + signed short (*calc_hit) (struct block_list *bl, struct status_change *sc, int hit, bool viewable); + signed short (*calc_critical) (struct block_list *bl, struct status_change *sc, int critical, bool viewable); + signed short (*calc_flee) (struct block_list *bl, struct status_change *sc, int flee, bool viewable); + signed short (*calc_flee2) (struct block_list *bl, struct status_change *sc, int flee2, bool viewable); + unsigned short (*calc_speed) (struct block_list *bl, struct status_change *sc, int speed); + short (*calc_aspd_rate) (struct block_list *bl, struct status_change *sc, int aspd_rate); + unsigned short (*calc_dmotion) (struct block_list *bl, struct status_change *sc, int dmotion); + short (*calc_aspd) (struct block_list *bl, struct status_change *sc, short flag); + short (*calc_fix_aspd) (struct block_list *bl, struct status_change *sc, int aspd); + unsigned int (*calc_maxhp) (struct block_list *bl, struct status_change *sc, uint64 maxhp); + unsigned int (*calc_maxsp) (struct block_list *bl, struct status_change *sc, unsigned int maxsp); + unsigned char (*calc_element) (struct block_list *bl, struct status_change *sc, int element); + unsigned char (*calc_element_lv) (struct block_list *bl, struct status_change *sc, int lv); + unsigned short (*calc_mode) (struct block_list *bl, struct status_change *sc, int mode); + unsigned short (*calc_ematk) (struct block_list *bl, struct status_change *sc, int matk); + void (*calc_bl_main) (struct block_list *bl, int flag); + void (*display_add) (struct map_session_data *sd, enum sc_type type, int dval1, int dval2, int dval3); + void (*display_remove) (struct map_session_data *sd, enum sc_type type); + int (*natural_heal) (struct block_list *bl, va_list args); + int (*natural_heal_timer) (int tid, int64 tick, int id, intptr_t data); + bool (*readdb_job1) (char *fields[], int columns, int current); + bool (*readdb_job2) (char *fields[], int columns, int current); + bool (*readdb_sizefix) (char *fields[], int columns, int current); + bool (*readdb_refine) (char *fields[], int columns, int current); + bool (*readdb_scconfig) (char *fields[], int columns, int current); +}; -int status_get_matk(struct block_list *src, int flag); +struct status_interface *status; -int status_readdb(void); -int do_init_status(void); -void do_final_status(void); +void status_defaults(void); -#endif /* _STATUS_H_ */ +#endif /* MAP_STATUS_H */ diff --git a/src/map/storage.c b/src/map/storage.c index ea30f6c0f..217f14a3a 100644 --- a/src/map/storage.c +++ b/src/map/storage.c @@ -1,38 +1,40 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder +// Copyright (c) Hercules Dev Team, licensed under GNU GPL. +// See the LICENSE file +// Portions Copyright (c) Athena Dev Teams -#include "../common/cbasetypes.h" -#include "../common/db.h" -#include "../common/nullpo.h" -#include "../common/malloc.h" -#include "../common/showmsg.h" +#define HERCULES_CORE -#include "map.h" // struct map_session_data #include "storage.h" -#include "chrif.h" -#include "itemdb.h" -#include "clif.h" -#include "intif.h" -#include "pc.h" -#include "guild.h" -#include "battle.h" -#include "atcommand.h" -#include "log.h" #include <stdio.h> #include <stdlib.h> #include <string.h> +#include "atcommand.h" +#include "battle.h" +#include "chrif.h" +#include "clif.h" +#include "guild.h" +#include "intif.h" +#include "itemdb.h" +#include "log.h" +#include "map.h" // struct map_session_data +#include "pc.h" +#include "../common/cbasetypes.h" +#include "../common/db.h" +#include "../common/malloc.h" +#include "../common/nullpo.h" -static DBMap* guild_storage_db; // int guild_id -> struct guild_storage* +struct storage_interface storage_s; +struct guild_storage_interface gstorage_s; /*========================================== * Sort items in the warehouse *------------------------------------------*/ -static int storage_comp_item(const void *_i1, const void *_i2) +int storage_comp_item(const void *i1_, const void *i2_) { - struct item *i1 = (struct item *)_i1; - struct item *i2 = (struct item *)_i2; + struct item *i1 = (struct item *)i1_; + struct item *i2 = (struct item *)i2_; if (i1->nameid == i2->nameid) return 0; @@ -44,46 +46,32 @@ static int storage_comp_item(const void *_i1, const void *_i2) } //Sort item by storage_comp_item (nameid) -static void storage_sortitem(struct item* items, unsigned int size) +void storage_sortitem(struct item* items, unsigned int size) { nullpo_retv(items); if( battle_config.client_sort_storage ) { - qsort(items, size, sizeof(struct item), storage_comp_item); + qsort(items, size, sizeof(struct item), storage->comp_item); } } -/*========================================== - * Init/Terminate - *------------------------------------------*/ -int do_init_storage(void) // Called from map.c::do_init() -{ - guild_storage_db=idb_alloc(DB_OPT_RELEASE_DATA); - return 1; -} -void do_final_storage(void) // by [MC Cameri] -{ - guild_storage_db->destroy(guild_storage_db,NULL); -} - /** * Parses storage and saves 'dirty' ones upon reconnect. [Skotlex] * @see DBApply */ -static int storage_reconnect_sub(DBKey key, DBData *data, va_list ap) +int storage_reconnect_sub(DBKey key, DBData *data, va_list ap) { struct guild_storage *stor = DB->data2ptr(data); if (stor->dirty && stor->storage_status == 0) //Save closed storages. - storage_guild_storagesave(0, stor->guild_id,0); + gstorage->save(0, stor->guild_id,0); return 0; } //Function to be invoked upon server reconnection to char. To save all 'dirty' storages [Skotlex] -void do_reconnect_storage(void) -{ - guild_storage_db->foreach(guild_storage_db, storage_reconnect_sub); +void do_reconnect_storage(void) { + gstorage->db->foreach(gstorage->db, storage->reconnect_sub); } /*========================================== @@ -98,14 +86,14 @@ int storage_storageopen(struct map_session_data *sd) if(sd->state.storage_flag) return 1; //Already open? - if( !pc->can_give_items(sd) ) + if( !pc_can_give_items(sd) ) { //check is this GM level is allowed to put items to storage clif->message(sd->fd, msg_txt(246)); return 1; } sd->state.storage_flag = 1; - storage_sortitem(sd->status.storage.items, ARRAYLENGTH(sd->status.storage.items)); + storage->sortitem(sd->status.storage.items, ARRAYLENGTH(sd->status.storage.items)); clif->storagelist(sd, sd->status.storage.items, ARRAYLENGTH(sd->status.storage.items)); clif->updatestorageamount(sd, sd->status.storage.storage_amount, MAX_STORAGE); return 0; @@ -120,7 +108,8 @@ int compare_item(struct item *a, struct item *b) a->identify == b->identify && a->refine == b->refine && a->attribute == b->attribute && - a->expire_time == b->expire_time ) + a->expire_time == b->expire_time && + a->bound == b->bound ) { int i; for (i = 0; i < MAX_SLOTS && (a->card[i] == b->card[i]); i++); @@ -132,8 +121,7 @@ int compare_item(struct item *a, struct item *b) /*========================================== * Internal add-item function. *------------------------------------------*/ -static int storage_additem(struct map_session_data* sd, struct item* item_data, int amount) -{ +int storage_additem(struct map_session_data* sd, struct item* item_data, int amount) { struct storage_data* stor = &sd->status.storage; struct item_data *data; int i; @@ -141,20 +129,25 @@ static int storage_additem(struct map_session_data* sd, struct item* item_data, if( item_data->nameid <= 0 || amount <= 0 ) return 1; - data = itemdb_search(item_data->nameid); + data = itemdb->search(item_data->nameid); if( data->stack.storage && amount > data->stack.amount ) {// item stack limitation return 1; } - if( !itemdb_canstore(item_data, pc->get_group_level(sd)) ) + if( !itemdb_canstore(item_data, pc_get_group_level(sd)) ) { //Check if item is storable. [Skotlex] clif->message (sd->fd, msg_txt(264)); return 1; } - if( itemdb_isstackable2(data) ) + if( item_data->bound > IBT_ACCOUNT && !pc_can_give_bound_items(sd) ) { + clif->message(sd->fd, msg_txt(294)); + return 1; + } + + if( itemdb->isstackable2(data) ) {//Stackable for( i = 0; i < MAX_STORAGE; i++ ) { @@ -210,8 +203,7 @@ int storage_delitem(struct map_session_data* sd, int n, int amount) * 0 : fail * 1 : success *------------------------------------------*/ -int storage_storageadd(struct map_session_data* sd, int index, int amount) -{ +int storage_storageadd(struct map_session_data* sd, int index, int amount) { nullpo_ret(sd); if( sd->status.storage.storage_amount > MAX_STORAGE ) @@ -226,8 +218,10 @@ int storage_storageadd(struct map_session_data* sd, int index, int amount) if( amount < 1 || amount > sd->status.inventory[index].amount ) return 0; - if( storage_additem(sd,&sd->status.inventory[index],amount) == 0 ) + if( storage->additem(sd,&sd->status.inventory[index],amount) == 0 ) pc->delitem(sd,index,amount,0,4,LOG_TYPE_STORAGE); + else + clif->dropitem(sd, index,0); return 1; } @@ -253,7 +247,7 @@ int storage_storageget(struct map_session_data* sd, int index, int amount) return 0; if( (flag = pc->additem(sd,&sd->status.storage.items[index],amount,LOG_TYPE_STORAGE)) == 0 ) - storage_delitem(sd,index,amount); + storage->delitem(sd,index,amount); else clif->additem(sd,0,0,flag); @@ -283,7 +277,7 @@ int storage_storageaddfromcart(struct map_session_data* sd, int index, int amoun if( amount < 1 || amount > sd->status.cart[index].amount ) return 0; - if( storage_additem(sd,&sd->status.cart[index],amount) == 0 ) + if( storage->additem(sd,&sd->status.cart[index],amount) == 0 ) pc->cart_delitem(sd,index,amount,0,LOG_TYPE_STORAGE); return 1; @@ -296,8 +290,8 @@ int storage_storageaddfromcart(struct map_session_data* sd, int index, int amoun * 0 : fail * 1 : success *------------------------------------------*/ -int storage_storagegettocart(struct map_session_data* sd, int index, int amount) -{ +int storage_storagegettocart(struct map_session_data* sd, int index, int amount) { + int flag = 0; nullpo_ret(sd); if( index < 0 || index >= MAX_STORAGE ) @@ -309,8 +303,12 @@ int storage_storagegettocart(struct map_session_data* sd, int index, int amount) if( amount < 1 || amount > sd->status.storage.items[index].amount ) return 0; - if( pc->cart_additem(sd,&sd->status.storage.items[index],amount,LOG_TYPE_STORAGE) == 0 ) - storage_delitem(sd,index,amount); + if( (flag = pc->cart_additem(sd,&sd->status.storage.items[index],amount,LOG_TYPE_STORAGE)) == 0 ) + storage->delitem(sd,index,amount); + else { + clif->dropitem(sd, index,0); + clif->cart_additem_ack(sd,flag == 1?0x0:0x1); + } return 1; } @@ -319,14 +317,13 @@ int storage_storagegettocart(struct map_session_data* sd, int index, int amount) /*========================================== * Modified By Valaris to save upon closing [massdriller] *------------------------------------------*/ -void storage_storageclose(struct map_session_data* sd) -{ +void storage_storageclose(struct map_session_data* sd) { nullpo_retv(sd); clif->storageclose(sd); - if( iMap->save_settings&4 ) - chrif_save(sd,0); //Invokes the storage saving as well. + if( map->save_settings&4 ) + chrif->save(sd,0); //Invokes the storage saving as well. sd->state.storage_flag = 0; } @@ -334,12 +331,11 @@ void storage_storageclose(struct map_session_data* sd) /*========================================== * When quitting the game. *------------------------------------------*/ -void storage_storage_quit(struct map_session_data* sd, int flag) -{ +void storage_storage_quit(struct map_session_data* sd, int flag) { nullpo_retv(sd); - if (iMap->save_settings&4) - chrif_save(sd, flag); //Invokes the storage saving as well. + if (map->save_settings&4) + chrif->save(sd, flag); //Invokes the storage saving as well. sd->state.storage_flag = 0; } @@ -347,7 +343,7 @@ void storage_storage_quit(struct map_session_data* sd, int flag) /** * @see DBCreateData */ -static DBData create_guildstorage(DBKey key, va_list args) +DBData create_guildstorage(DBKey key, va_list args) { struct guild_storage *gs = NULL; gs = (struct guild_storage *) aCalloc(sizeof(struct guild_storage), 1); @@ -359,19 +355,17 @@ struct guild_storage *guild2storage(int guild_id) { struct guild_storage *gs = NULL; if(guild->search(guild_id) != NULL) - gs = idb_ensure(guild_storage_db,guild_id,create_guildstorage); + gs = idb_ensure(gstorage->db,guild_id,gstorage->create); return gs; } //For just locating a storage without creating one. [Skotlex] -struct guild_storage *guild2storage2(int guild_id) -{ - return (struct guild_storage*)idb_get(guild_storage_db,guild_id); +struct guild_storage *guild2storage2(int guild_id) { + return (struct guild_storage*)idb_get(gstorage->db,guild_id); } -int guild_storage_delete(int guild_id) -{ - idb_remove(guild_storage_db,guild_id); +int guild_storage_delete(int guild_id) { + idb_remove(gstorage->db,guild_id); return 0; } @@ -394,13 +388,13 @@ int storage_guild_storageopen(struct map_session_data* sd) if(sd->state.storage_flag) return 1; //Can't open both storages at a time. - if( !pc->can_give_items(sd) ) { //check is this GM level can open guild storage and store items [Lupus] + if( !pc_can_give_items(sd) ) { //check is this GM level can open guild storage and store items [Lupus] clif->message(sd->fd, msg_txt(246)); return 1; } - if((gstor = guild2storage2(sd->status.guild_id)) == NULL) { - intif_request_guild_storage(sd->status.account_id,sd->status.guild_id); + if((gstor = gstorage->id2storage2(sd->status.guild_id)) == NULL) { + intif->request_guild_storage(sd->status.account_id,sd->status.guild_id); return 0; } if(gstor->storage_status) @@ -411,7 +405,7 @@ int storage_guild_storageopen(struct map_session_data* sd) gstor->storage_status = 1; sd->state.storage_flag = 2; - storage_sortitem(gstor->items, ARRAYLENGTH(gstor->items)); + storage->sortitem(gstor->items, ARRAYLENGTH(gstor->items)); clif->storagelist(sd, gstor->items, ARRAYLENGTH(gstor->items)); clif->updatestorageamount(sd, gstor->storage_amount, MAX_GUILD_STORAGE); return 0; @@ -435,20 +429,25 @@ int guild_storage_additem(struct map_session_data* sd, struct guild_storage* sto if(item_data->nameid <= 0 || amount <= 0) return 1; - data = itemdb_search(item_data->nameid); + data = itemdb->search(item_data->nameid); if( data->stack.guildstorage && amount > data->stack.amount ) {// item stack limitation return 1; } - if( !itemdb_canguildstore(item_data, pc->get_group_level(sd)) || item_data->expire_time ) - { //Check if item is storable. [Skotlex] + if( !itemdb_canguildstore(item_data, pc_get_group_level(sd)) || item_data->expire_time ) + { //Check if item is storable. [Skotlex] clif->message (sd->fd, msg_txt(264)); return 1; } - if(itemdb_isstackable2(data)){ //Stackable + if( item_data->bound && item_data->bound != IBT_GUILD && !pc_can_give_bound_items(sd) ) { + clif->message(sd->fd, msg_txt(294)); + return 1; + } + + if(itemdb->isstackable2(data)){ //Stackable for(i=0;i<MAX_GUILD_STORAGE;i++){ if(compare_item(&stor->items[i], item_data)) { if( amount > MAX_AMOUNT - stor->items[i].amount || ( data->stack.guildstorage && amount > data->stack.amount - stor->items[i].amount ) ) @@ -512,7 +511,7 @@ int storage_guild_storageadd(struct map_session_data* sd, int index, int amount) struct guild_storage *stor; nullpo_ret(sd); - nullpo_ret(stor=guild2storage2(sd->status.guild_id)); + nullpo_ret(stor=gstorage->id2storage2(sd->status.guild_id)); if( !stor->storage_status || stor->storage_amount > MAX_GUILD_STORAGE ) return 0; @@ -527,12 +526,14 @@ int storage_guild_storageadd(struct map_session_data* sd, int index, int amount) return 0; if( stor->lock ) { - storage_guild_storageclose(sd); + gstorage->close(sd); return 0; } - if(guild_storage_additem(sd,stor,&sd->status.inventory[index],amount)==0) + if(gstorage->additem(sd,stor,&sd->status.inventory[index],amount)==0) pc->delitem(sd,index,amount,0,4,LOG_TYPE_GSTORAGE); + else + clif->dropitem(sd, index,0); return 1; } @@ -542,7 +543,7 @@ int storage_guild_storageadd(struct map_session_data* sd, int index, int amount) * @index : storage idx * return * 0 : fail -* 1 : succes +* 1 : success *------------------------------------------*/ int storage_guild_storageget(struct map_session_data* sd, int index, int amount) { @@ -565,12 +566,12 @@ int storage_guild_storageget(struct map_session_data* sd, int index, int amount) return 0; if( stor->lock ) { - storage_guild_storageclose(sd); + gstorage->close(sd); return 0; } if((flag = pc->additem(sd,&stor->items[index],amount,LOG_TYPE_GSTORAGE)) == 0) - guild_storage_delitem(sd,stor,index,amount); + gstorage->delitem(sd,stor,index,amount); else //inform fail clif->additem(sd,0,0,flag); // log_fromstorage(sd, index, 1); @@ -583,7 +584,7 @@ int storage_guild_storageget(struct map_session_data* sd, int index, int amount) * @index : cart inventory idx * return * 0 : fail -* 1 : succes +* 1 : success *------------------------------------------*/ int storage_guild_storageaddfromcart(struct map_session_data* sd, int index, int amount) { @@ -604,7 +605,7 @@ int storage_guild_storageaddfromcart(struct map_session_data* sd, int index, int if( amount < 1 || amount > sd->status.cart[index].amount ) return 0; - if(guild_storage_additem(sd,stor,&sd->status.cart[index],amount)==0) + if(gstorage->additem(sd,stor,&sd->status.cart[index],amount)==0) pc->cart_delitem(sd,index,amount,0,LOG_TYPE_GSTORAGE); return 1; @@ -615,7 +616,7 @@ int storage_guild_storageaddfromcart(struct map_session_data* sd, int index, int * @index : storage idx * return * 0 : fail -* 1 : succes +* 1 : success *------------------------------------------*/ int storage_guild_storagegettocart(struct map_session_data* sd, int index, int amount) { @@ -637,7 +638,7 @@ int storage_guild_storagegettocart(struct map_session_data* sd, int index, int a return 0; if(pc->cart_additem(sd,&stor->items[index],amount,LOG_TYPE_GSTORAGE)==0) - guild_storage_delitem(sd,stor,index,amount); + gstorage->delitem(sd,stor,index,amount); return 1; } @@ -646,7 +647,7 @@ int storage_guild_storagegettocart(struct map_session_data* sd, int index, int a * Request to save guild storage * return * 0 : fail (no storage) -* 1 : succes +* 1 : success *------------------------------------------*/ int storage_guild_storagesave(int account_id, int guild_id, int flag) { @@ -657,7 +658,7 @@ int storage_guild_storagesave(int account_id, int guild_id, int flag) if (flag) //Char quitting, close it. stor->storage_status = 0; if (stor->dirty) - intif_send_guild_storage(account_id,stor); + intif->send_guild_storage(account_id,stor); return 1; } return 0; @@ -667,13 +668,13 @@ int storage_guild_storagesave(int account_id, int guild_id, int flag) * ACK save of guild storage * return * 0 : fail (no storage) -* 1 : succes +* 1 : success *------------------------------------------*/ int storage_guild_storagesaved(int guild_id) { struct guild_storage *stor; - if((stor=guild2storage2(guild_id)) != NULL) { + if((stor=gstorage->id2storage2(guild_id)) != NULL) { if (stor->dirty && stor->storage_status == 0) { //Storage has been correctly saved. stor->dirty = 0; @@ -684,20 +685,18 @@ int storage_guild_storagesaved(int guild_id) } //Close storage for sd and save it -int storage_guild_storageclose(struct map_session_data* sd) -{ +int storage_guild_storageclose(struct map_session_data* sd) { struct guild_storage *stor; nullpo_ret(sd); - nullpo_ret(stor=guild2storage2(sd->status.guild_id)); + nullpo_ret(stor=gstorage->id2storage2(sd->status.guild_id)); clif->storageclose(sd); - if (stor->storage_status) - { - if (iMap->save_settings&4) - chrif_save(sd, 0); //This one also saves the storage. [Skotlex] + if (stor->storage_status) { + if (map->save_settings&4) + chrif->save(sd, 0); //This one also saves the storage. [Skotlex] else - storage_guild_storagesave(sd->status.account_id, sd->status.guild_id,0); + gstorage->save(sd->status.account_id, sd->status.guild_id,0); stor->storage_status=0; } sd->state.storage_flag = 0; @@ -705,31 +704,80 @@ int storage_guild_storageclose(struct map_session_data* sd) return 0; } -int storage_guild_storage_quit(struct map_session_data* sd, int flag) -{ +int storage_guild_storage_quit(struct map_session_data* sd, int flag) { struct guild_storage *stor; nullpo_ret(sd); - nullpo_ret(stor=guild2storage2(sd->status.guild_id)); + nullpo_ret(stor=gstorage->id2storage2(sd->status.guild_id)); - if(flag) - { //Only during a guild break flag is 1 (don't save storage) + if(flag) { + //Only during a guild break flag is 1 (don't save storage) sd->state.storage_flag = 0; stor->storage_status = 0; clif->storageclose(sd); - if (iMap->save_settings&4) - chrif_save(sd,0); + if (map->save_settings&4) + chrif->save(sd,0); return 0; } if(stor->storage_status) { - if (iMap->save_settings&4) - chrif_save(sd,0); + if (map->save_settings&4) + chrif->save(sd,0); else - storage_guild_storagesave(sd->status.account_id,sd->status.guild_id,1); + gstorage->save(sd->status.account_id,sd->status.guild_id,1); } sd->state.storage_flag = 0; stor->storage_status = 0; return 0; } +void do_init_gstorage(bool minimal) { + if (minimal) + return; + gstorage->db = idb_alloc(DB_OPT_RELEASE_DATA); +} +void do_final_gstorage(void) { + db_destroy(gstorage->db); +} +void storage_defaults(void) { + storage = &storage_s; + + /* */ + storage->reconnect = do_reconnect_storage; + /* */ + storage->delitem = storage_delitem; + storage->open = storage_storageopen; + storage->add = storage_storageadd; + storage->get = storage_storageget; + storage->additem = storage_additem; + storage->addfromcart = storage_storageaddfromcart; + storage->gettocart = storage_storagegettocart; + storage->close = storage_storageclose; + storage->pc_quit = storage_storage_quit; + storage->comp_item = storage_comp_item; + storage->sortitem = storage_sortitem; + storage->reconnect_sub = storage_reconnect_sub; +} +void gstorage_defaults(void) { + gstorage = &gstorage_s; + + /* */ + gstorage->init = do_init_gstorage; + gstorage->final = do_final_gstorage; + /* */ + gstorage->id2storage = guild2storage; + gstorage->id2storage2 = guild2storage2; + gstorage->delete = guild_storage_delete; + gstorage->open = storage_guild_storageopen; + gstorage->additem = guild_storage_additem; + gstorage->delitem = guild_storage_delitem; + gstorage->add = storage_guild_storageadd; + gstorage->get = storage_guild_storageget; + gstorage->addfromcart = storage_guild_storageaddfromcart; + gstorage->gettocart = storage_guild_storagegettocart; + gstorage->close = storage_guild_storageclose; + gstorage->pc_quit = storage_guild_storage_quit; + gstorage->save = storage_guild_storagesave; + gstorage->saved = storage_guild_storagesaved; + gstorage->create = create_guildstorage; +} diff --git a/src/map/storage.h b/src/map/storage.h index c08ec81cb..186f21263 100644 --- a/src/map/storage.h +++ b/src/map/storage.h @@ -1,41 +1,63 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder +// Copyright (c) Hercules Dev Team, licensed under GNU GPL. +// See the LICENSE file +// Portions Copyright (c) Athena Dev Teams -#ifndef _STORAGE_H_ -#define _STORAGE_H_ +#ifndef MAP_STORAGE_H +#define MAP_STORAGE_H + +#include "../common/cbasetypes.h" +#include "../common/db.h" -//#include "../common/mmo.h" -struct storage_data; struct guild_storage; struct item; -//#include "map.h" struct map_session_data; -int storage_delitem(struct map_session_data* sd, int n, int amount); -int storage_storageopen(struct map_session_data *sd); -int storage_storageadd(struct map_session_data *sd,int index,int amount); -int storage_storageget(struct map_session_data *sd,int index,int amount); -int storage_storageaddfromcart(struct map_session_data *sd,int index,int amount); -int storage_storagegettocart(struct map_session_data *sd,int index,int amount); -void storage_storageclose(struct map_session_data *sd); -int do_init_storage(void); -void do_final_storage(void); -void do_reconnect_storage(void); -void storage_storage_quit(struct map_session_data *sd, int flag); - -struct guild_storage* guild2storage(int guild_id); -struct guild_storage *guild2storage2(int guild_id); -int guild_storage_delete(int guild_id); -int storage_guild_storageopen(struct map_session_data *sd); -int guild_storage_additem(struct map_session_data *sd,struct guild_storage *stor,struct item *item_data,int amount); -int guild_storage_delitem(struct map_session_data *sd,struct guild_storage *stor,int n,int amount); -int storage_guild_storageadd(struct map_session_data *sd,int index,int amount); -int storage_guild_storageget(struct map_session_data *sd,int index,int amount); -int storage_guild_storageaddfromcart(struct map_session_data *sd,int index,int amount); -int storage_guild_storagegettocart(struct map_session_data *sd,int index,int amount); -int storage_guild_storageclose(struct map_session_data *sd); -int storage_guild_storage_quit(struct map_session_data *sd,int flag); -int storage_guild_storagesave(int account_id, int guild_id, int flag); -int storage_guild_storagesaved(int guild_id); //Ack from char server that guild store was saved. - -#endif /* _STORAGE_H_ */ +struct storage_interface { + /* */ + void (*reconnect) (void); + /* */ + int (*delitem) (struct map_session_data* sd, int n, int amount); + int (*open) (struct map_session_data *sd); + int (*add) (struct map_session_data *sd,int index,int amount); + int (*get) (struct map_session_data *sd,int index,int amount); + int (*additem) (struct map_session_data* sd, struct item* item_data, int amount); + int (*addfromcart) (struct map_session_data *sd,int index,int amount); + int (*gettocart) (struct map_session_data *sd,int index,int amount); + void (*close) (struct map_session_data *sd); + void (*pc_quit) (struct map_session_data *sd, int flag); + int (*comp_item) (const void *i1_, const void *i2_); + void (*sortitem) (struct item* items, unsigned int size); + int (*reconnect_sub) (DBKey key, DBData *data, va_list ap); +}; +struct storage_interface *storage; + +struct guild_storage_interface { + struct DBMap* db; // int guild_id -> struct guild_storage* + /* */ + struct guild_storage *(*id2storage) (int guild_id); + struct guild_storage *(*id2storage2) (int guild_id); + /* */ + void (*init) (bool minimal); + void (*final) (void); + /* */ + int (*delete) (int guild_id); + int (*open) (struct map_session_data *sd); + int (*additem) (struct map_session_data *sd,struct guild_storage *stor,struct item *item_data,int amount); + int (*delitem) (struct map_session_data *sd,struct guild_storage *stor,int n,int amount); + int (*add) (struct map_session_data *sd,int index,int amount); + int (*get) (struct map_session_data *sd,int index,int amount); + int (*addfromcart) (struct map_session_data *sd,int index,int amount); + int (*gettocart) (struct map_session_data *sd,int index,int amount); + int (*close) (struct map_session_data *sd); + int (*pc_quit) (struct map_session_data *sd,int flag); + int (*save) (int account_id, int guild_id, int flag); + int (*saved) (int guild_id); //Ack from char server that guild store was saved. + DBData (*create) (DBKey key, va_list args); +}; + +struct guild_storage_interface *gstorage; + +void storage_defaults(void); +void gstorage_defaults(void); + +#endif /* MAP_STORAGE_H */ diff --git a/src/map/trade.c b/src/map/trade.c index f469f4b28..3bbb73568 100644 --- a/src/map/trade.c +++ b/src/map/trade.c @@ -1,28 +1,30 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder +// Copyright (c) Hercules Dev Team, licensed under GNU GPL. +// See the LICENSE file +// Portions Copyright (c) Athena Dev Teams -#include "../common/nullpo.h" -#include "../common/socket.h" +#define HERCULES_CORE + +#include "trade.h" + +#include <stdio.h> +#include <string.h> + +#include "atcommand.h" +#include "battle.h" +#include "chrif.h" #include "clif.h" +#include "intif.h" #include "itemdb.h" +#include "log.h" #include "map.h" +#include "npc.h" #include "path.h" -#include "trade.h" #include "pc.h" -#include "npc.h" -#include "battle.h" -#include "chrif.h" #include "storage.h" -#include "intif.h" -#include "atcommand.h" -#include "log.h" - -#include <stdio.h> -#include <string.h> - +#include "../common/nullpo.h" +#include "../common/socket.h" -//Max distance from traders to enable a trade to take place. -#define TRADE_DISTANCE 2 +struct trade_interface trade_s; /*========================================== * Initiates a trade request. @@ -31,7 +33,7 @@ void trade_traderequest(struct map_session_data *sd, struct map_session_data *ta { nullpo_retv(sd); - if (map[sd->bl.m].flag.notrade) { + if (map->list[sd->bl.m].flag.notrade) { clif->message (sd->fd, msg_txt(272)); return; //Can't trade in notrade mapflag maps. } @@ -55,11 +57,11 @@ void trade_traderequest(struct map_session_data *sd, struct map_session_data *ta } if ( sd->trade_partner != 0 ) { // If a character tries to trade to another one then cancel the previous one - struct map_session_data *previous_sd = iMap->id2sd(sd->trade_partner); + struct map_session_data *previous_sd = map->id2sd(sd->trade_partner); if( previous_sd ){ previous_sd->trade_partner = 0; clif->tradecancelled(previous_sd); - } // Once cancelled then continue to the new one. + } // Once canceled then continue to the new one. sd->trade_partner = 0; clif->tradecancelled(sd); } @@ -69,7 +71,7 @@ void trade_traderequest(struct map_session_data *sd, struct map_session_data *ta return; } - if (!pc->can_give_items(sd) || !pc->can_give_items(target_sd)) //check if both GMs are allowed to trade + if (!pc_can_give_items(sd) || !pc_can_give_items(target_sd)) //check if both GMs are allowed to trade { clif->message(sd->fd, msg_txt(246)); clif->tradestart(sd, 2); // GM is not allowed to trade @@ -99,15 +101,14 @@ void trade_traderequest(struct map_session_data *sd, struct map_session_data *ta * Weird enough, the client should only send 3/4 * and the server is the one that can reply 0~2 *------------------------------------------*/ -void trade_tradeack(struct map_session_data *sd, int type) -{ +void trade_tradeack(struct map_session_data *sd, int type) { struct map_session_data *tsd; nullpo_retv(sd); if (sd->state.trading || !sd->trade_partner) return; //Already trading or no partner set. - if ((tsd = iMap->id2sd(sd->trade_partner)) == NULL) { + if ((tsd = map->id2sd(sd->trade_partner)) == NULL) { clif->tradestart(sd, 1); // character does not exist sd->trade_partner=0; return; @@ -165,11 +166,13 @@ void trade_tradeack(struct map_session_data *sd, int type) clif->tradestart(sd, type); } -/*========================================== - * Check here hacker for duplicate item in trade - * normal client refuse to have 2 same types of item (except equipment) in same trade window - * normal client authorise only no equiped item and only from inventory - *------------------------------------------*/ +/** + * Checks if an impossible trade will occur + * Normal clients refuse to have 2 items of the same type (except equipment) in the same trade window + * Normal clients authorize only no equipped items and only items from inventory + * @retval 0 The trade can continue + * @retval 1 Hack attempt + **/ int impossible_trade_check(struct map_session_data *sd) { struct item inventory[MAX_INVENTORY]; @@ -178,17 +181,15 @@ int impossible_trade_check(struct map_session_data *sd) nullpo_retr(1, sd); - if(sd->deal.zeny > sd->status.zeny) { - pc_setglobalreg(sd,"ZENY_HACKER",1); - return -1; - } + if( sd->deal.zeny > sd->status.zeny ) + return 1; // get inventory of player memcpy(&inventory, &sd->status.inventory, sizeof(struct item) * MAX_INVENTORY); - // remove this part: arrows can be trade and equiped + // remove this part: arrows can be trade and equipped // re-added! [celest] - // remove equiped items (they can not be trade) + // remove equipped items (they can not be trade) for (i = 0; i < MAX_INVENTORY; i++) if (inventory[i].nameid > 0 && inventory[i].equip && !(inventory[i].equip & EQP_AMMO)) memset(&inventory[i], 0, sizeof(struct item)); @@ -198,21 +199,21 @@ int impossible_trade_check(struct map_session_data *sd) if (!sd->deal.item[i].amount) continue; index = sd->deal.item[i].index; - if (inventory[index].amount < sd->deal.item[i].amount) - { // if more than the player have -> hack + if (inventory[index].amount < sd->deal.item[i].amount) { + // if more than the player have -> hack sprintf(message_to_gm, msg_txt(538), sd->status.name, sd->status.account_id); // Hack on trade: character '%s' (account: %d) try to trade more items that he has. - intif_wis_message_to_gm(iMap->wisp_server_name, PC_PERM_RECEIVE_HACK_INFO, message_to_gm); + intif->wis_message_to_gm(map->wisp_server_name, PC_PERM_RECEIVE_HACK_INFO, message_to_gm); sprintf(message_to_gm, msg_txt(539), inventory[index].amount, inventory[index].nameid, sd->deal.item[i].amount); // This player has %d of a kind of item (id: %d), and try to trade %d of them. - intif_wis_message_to_gm(iMap->wisp_server_name, PC_PERM_RECEIVE_HACK_INFO, message_to_gm); + intif->wis_message_to_gm(map->wisp_server_name, PC_PERM_RECEIVE_HACK_INFO, message_to_gm); // if we block people if (battle_config.ban_hack_trade < 0) { - chrif_char_ask_name(-1, sd->status.name, 1, 0, 0, 0, 0, 0, 0); // type: 1 - block + chrif->char_ask_name(-1, sd->status.name, 1, 0, 0, 0, 0, 0, 0); // type: 1 - block set_eof(sd->fd); // forced to disconnect because of the hack // message about the ban strcpy(message_to_gm, msg_txt(540)); // This player has been definitively blocked. // if we ban people } else if (battle_config.ban_hack_trade > 0) { - chrif_char_ask_name(-1, sd->status.name, 2, 0, 0, 0, 0, battle_config.ban_hack_trade, 0); // type: 2 - ban (year, month, day, hour, minute, second) + chrif->char_ask_name(-1, sd->status.name, 2, 0, 0, 0, 0, battle_config.ban_hack_trade, 0); // type: 2 - ban (year, month, day, hour, minute, second) set_eof(sd->fd); // forced to disconnect because of the hack // message about the ban sprintf(message_to_gm, msg_txt(507), battle_config.ban_hack_trade); // This player has been banned for %d minute(s). @@ -220,7 +221,7 @@ int impossible_trade_check(struct map_session_data *sd) // message about the ban strcpy(message_to_gm, msg_txt(508)); // This player hasn't been banned (Ban option is disabled). - intif_wis_message_to_gm(iMap->wisp_server_name, PC_PERM_RECEIVE_HACK_INFO, message_to_gm); + intif->wis_message_to_gm(map->wisp_server_name, PC_PERM_RECEIVE_HACK_INFO, message_to_gm); return 1; } inventory[index].amount -= sd->deal.item[i].amount; // remove item from inventory @@ -257,9 +258,9 @@ int trade_check(struct map_session_data *sd, struct map_session_data *tsd) if (amount > inventory[n].amount) return 0; //qty Exploit? - data = itemdb_search(inventory[n].nameid); + data = itemdb->search(inventory[n].nameid); i = MAX_INVENTORY; - if (itemdb_isstackable2(data)) { //Stackable item. + if (itemdb->isstackable2(data)) { //Stackable item. for(i = 0; i < MAX_INVENTORY; i++) if (inventory2[i].nameid == inventory[n].nameid && inventory2[i].card[0] == inventory[n].card[0] && inventory2[i].card[1] == inventory[n].card[1] && @@ -288,9 +289,9 @@ int trade_check(struct map_session_data *sd, struct map_session_data *tsd) if (amount > inventory2[n].amount) return 0; // search if it's possible to add item (for full inventory) - data = itemdb_search(inventory2[n].nameid); + data = itemdb->search(inventory2[n].nameid); i = MAX_INVENTORY; - if (itemdb_isstackable2(data)) { + if (itemdb->isstackable2(data)) { for(i = 0; i < MAX_INVENTORY; i++) if (inventory[i].nameid == inventory2[n].nameid && inventory[i].card[0] == inventory2[n].card[0] && inventory[i].card[1] == inventory2[n].card[1] && @@ -318,8 +319,7 @@ int trade_check(struct map_session_data *sd, struct map_session_data *tsd) /*========================================== * Adds an item/qty to the trade window *------------------------------------------*/ -void trade_tradeadditem(struct map_session_data *sd, short index, short amount) -{ +void trade_tradeadditem(struct map_session_data *sd, short index, short amount) { struct map_session_data *target_sd; struct item *item; int trade_i, trade_weight; @@ -329,7 +329,7 @@ void trade_tradeadditem(struct map_session_data *sd, short index, short amount) if( !sd->state.trading || sd->state.deal_locked > 0 ) return; //Can't add stuff. - if( (target_sd = iMap->id2sd(sd->trade_partner)) == NULL ) + if( (target_sd = map->id2sd(sd->trade_partner)) == NULL ) { trade->cancel(sd); return; @@ -337,7 +337,7 @@ void trade_tradeadditem(struct map_session_data *sd, short index, short amount) if( amount == 0 ) { //Why do this.. ~.~ just send an ack, the item won't display on the trade window. - clif->tradeitemok(sd, index, 0); + clif->tradeitemok(sd, index, TIO_SUCCESS); return; } @@ -350,35 +350,44 @@ void trade_tradeadditem(struct map_session_data *sd, short index, short amount) return; item = &sd->status.inventory[index]; - src_lv = pc->get_group_level(sd); - dst_lv = pc->get_group_level(target_sd); + src_lv = pc_get_group_level(sd); + dst_lv = pc_get_group_level(target_sd); if( !itemdb_cantrade(item, src_lv, dst_lv) && //Can't trade (pc->get_partner(sd) != target_sd || !itemdb_canpartnertrade(item, src_lv, dst_lv)) ) //Can't partner-trade { clif->message (sd->fd, msg_txt(260)); - clif->tradeitemok(sd, index+2, 1); + clif->tradeitemok(sd, index+2, TIO_INDROCKS); return; } if( item->expire_time ) { // Rental System clif->message (sd->fd, msg_txt(260)); - clif->tradeitemok(sd, index+2, 1); + clif->tradeitemok(sd, index+2, TIO_INDROCKS); return; } + if( item->bound && + !( item->bound == IBT_GUILD && sd->status.guild_id == target_sd->status.guild_id ) && + !( item->bound == IBT_PARTY && sd->status.party_id == target_sd->status.party_id ) + && !pc_can_give_bound_items(sd) ) { + clif->message(sd->fd, msg_txt(293)); + clif->tradeitemok(sd, index+2, TIO_INDROCKS); + return; + } + //Locate a trade position ARR_FIND( 0, 10, trade_i, sd->deal.item[trade_i].index == index || sd->deal.item[trade_i].amount == 0 ); if( trade_i == 10 ) //No space left { - clif->tradeitemok(sd, index+2, 1); + clif->tradeitemok(sd, index+2, TIO_OVERWEIGHT); return; } trade_weight = sd->inventory_data[index]->weight * amount; if( target_sd->weight + sd->deal.weight + trade_weight > target_sd->max_weight ) { //fail to add item -- the player was over weighted. - clif->tradeitemok(sd, index+2, 1); + clif->tradeitemok(sd, index+2, TIO_OVERWEIGHT); return; } @@ -398,7 +407,7 @@ void trade_tradeadditem(struct map_session_data *sd, short index, short amount) } sd->deal.weight += trade_weight; - clif->tradeitemok(sd, index+2, 0); // Return the index as it was received + clif->tradeitemok(sd, index+2, TIO_SUCCESS); // Return the index as it was received clif->tradeadditem(sd, target_sd, index+2, amount); } @@ -413,8 +422,7 @@ void trade_tradeaddzeny(struct map_session_data* sd, int amount) if( !sd->state.trading || sd->state.deal_locked > 0 ) return; //Can't add stuff. - if( (target_sd = iMap->id2sd(sd->trade_partner)) == NULL ) - { + if( (target_sd = map->id2sd(sd->trade_partner)) == NULL ) { trade->cancel(sd); return; } @@ -432,35 +440,33 @@ void trade_tradeaddzeny(struct map_session_data* sd, int amount) /*========================================== * 'Ok' button on the trade window is pressed. *------------------------------------------*/ -void trade_tradeok(struct map_session_data *sd) -{ +void trade_tradeok(struct map_session_data *sd) { struct map_session_data *target_sd; if(sd->state.deal_locked || !sd->state.trading) return; - if ((target_sd = iMap->id2sd(sd->trade_partner)) == NULL) { + if ((target_sd = map->id2sd(sd->trade_partner)) == NULL) { trade->cancel(sd); return; } sd->state.deal_locked = 1; - clif->tradeitemok(sd, 0, 0); + clif->tradeitemok(sd, 0, TIO_SUCCESS); clif->tradedeal_lock(sd, 0); clif->tradedeal_lock(target_sd, 1); } /*========================================== - * 'Cancel' is pressed. (or trade was force-cancelled by the code) + * 'Cancel' is pressed. (or trade was force-canceled by the code) *------------------------------------------*/ -void trade_tradecancel(struct map_session_data *sd) -{ +void trade_tradecancel(struct map_session_data *sd) { struct map_session_data *target_sd; int trade_i; - target_sd = iMap->id2sd(sd->trade_partner); + target_sd = map->id2sd(sd->trade_partner); if(!sd->state.trading) - { // Not trade acepted + { // Not trade accepted if( target_sd ) { target_sd->trade_partner = 0; clif->tradecancelled(target_sd); @@ -511,8 +517,7 @@ void trade_tradecancel(struct map_session_data *sd) /*========================================== * lock sd and tsd trade data, execute the trade, clear, then save players *------------------------------------------*/ -void trade_tradecommit(struct map_session_data *sd) -{ +void trade_tradecommit(struct map_session_data *sd) { struct map_session_data *tsd; int trade_i; int flag; @@ -520,8 +525,8 @@ void trade_tradecommit(struct map_session_data *sd) if (!sd->state.trading || !sd->state.deal_locked) //Locked should be 1 (pressed ok) before you can press trade. return; - if ((tsd = iMap->id2sd(sd->trade_partner)) == NULL) { - trade_tradecancel(sd); + if ((tsd = map->id2sd(sd->trade_partner)) == NULL) { + trade->cancel(sd); return; } @@ -601,10 +606,10 @@ void trade_tradecommit(struct map_session_data *sd) clif->tradecompleted(tsd, 0); // save both player to avoid crash: they always have no advantage/disadvantage between the 2 players - if (iMap->save_settings&1) + if (map->save_settings&1) { - chrif_save(sd,0); - chrif_save(tsd,0); + chrif->save(sd,0); + chrif->save(tsd,0); } } @@ -621,4 +626,4 @@ void trade_defaults(void) trade->ok = trade_tradeok; trade->cancel = trade_tradecancel; trade->commit = trade_tradecommit; -}
\ No newline at end of file +} diff --git a/src/map/trade.h b/src/map/trade.h index f66c70525..f91ccd4a2 100644 --- a/src/map/trade.h +++ b/src/map/trade.h @@ -1,10 +1,14 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder +// Copyright (c) Hercules Dev Team, licensed under GNU GPL. +// See the LICENSE file +// Portions Copyright (c) Athena Dev Teams -#ifndef _TRADE_H_ -#define _TRADE_H_ +#ifndef MAP_TRADE_H +#define MAP_TRADE_H + +//Max distance from traders to enable a trade to take place. +//TODO: battle_config candidate? +#define TRADE_DISTANCE 2 -//#include "map.h" struct map_session_data; struct trade_interface { @@ -17,9 +21,10 @@ struct trade_interface { void (*ok) (struct map_session_data *sd); void (*cancel) (struct map_session_data *sd); void (*commit) (struct map_session_data *sd); -} trade_s; +}; struct trade_interface *trade; + void trade_defaults(void); -#endif /* _TRADE_H_ */ +#endif /* MAP_TRADE_H */ diff --git a/src/map/unit.c b/src/map/unit.c index 021859bba..af0c0a948 100644 --- a/src/map/unit.c +++ b/src/map/unit.c @@ -2,50 +2,61 @@ // See the LICENSE file // Portions Copyright (c) Athena Dev Teams -#include "../common/showmsg.h" -#include "../common/timer.h" -#include "../common/nullpo.h" -#include "../common/db.h" -#include "../common/malloc.h" -#include "../common/random.h" +#define HERCULES_CORE + +#include "../config/core.h" // RENEWAL_CAST +#include "unit.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "battle.h" +#include "battleground.h" +#include "chat.h" +#include "chrif.h" +#include "clif.h" +#include "duel.h" +#include "elemental.h" +#include "guild.h" +#include "homunculus.h" +#include "instance.h" +#include "intif.h" #include "map.h" +#include "mercenary.h" +#include "mob.h" +#include "npc.h" +#include "party.h" #include "path.h" #include "pc.h" -#include "mob.h" #include "pet.h" -#include "homunculus.h" -#include "instance.h" -#include "mercenary.h" -#include "elemental.h" +#include "script.h" #include "skill.h" -#include "clif.h" -#include "duel.h" -#include "npc.h" -#include "guild.h" #include "status.h" -#include "unit.h" -#include "battle.h" -#include "battleground.h" -#include "chat.h" +#include "storage.h" #include "trade.h" #include "vending.h" -#include "party.h" -#include "intif.h" -#include "chrif.h" -#include "script.h" -#include "storage.h" - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - +#include "../common/HPM.h" +#include "../common/db.h" +#include "../common/malloc.h" +#include "../common/nullpo.h" +#include "../common/random.h" +#include "../common/showmsg.h" +#include "../common/socket.h" +#include "../common/timer.h" const short dirx[8]={0,-1,-1,-1,0,1,1,1}; const short diry[8]={1,1,0,-1,-1,-1,0,1}; -struct unit_data* unit_bl2ud(struct block_list *bl) -{ +struct unit_interface unit_s; + +/** + * Returns the unit_data for the given block_list. If the object is using + * shared unit_data (i.e. in case of BL_NPC), it returns the shared data. + * @param bl block_list to process + * @return a pointer to the given object's unit_data + **/ +struct unit_data* unit_bl2ud(struct block_list *bl) { if( bl == NULL) return NULL; if( bl->type == BL_PC) return &((struct map_session_data*)bl)->ud; if( bl->type == BL_MOB) return &((struct mob_data*)bl)->ud; @@ -57,8 +68,22 @@ struct unit_data* unit_bl2ud(struct block_list *bl) return NULL; } -static int unit_attack_timer(int tid, unsigned int tick, int id, intptr_t data); -static int unit_walktoxy_timer(int tid, unsigned int tick, int id, intptr_t data); +/** + * Returns the unit_data for the given block_list. If the object is using + * shared unit_data (i.e. in case of BL_NPC), it recreates a copy of the + * data so that it's safe to modify. + * @param bl block_list to process + * @return a pointer to the given object's unit_data + */ +struct unit_data* unit_bl2ud2(struct block_list *bl) { + if( bl && bl->type == BL_NPC && ((struct npc_data*)bl)->ud == &npc->base_ud ) { + struct npc_data *nd = (struct npc_data *)bl; + nd->ud = NULL; + CREATE(nd->ud, struct unit_data, 1); + unit->dataset(&nd->bl); + } + return unit->bl2ud(bl); +} int unit_walktoxy_sub(struct block_list *bl) { @@ -67,10 +92,10 @@ int unit_walktoxy_sub(struct block_list *bl) struct unit_data *ud = NULL; nullpo_retr(1, bl); - ud = unit_bl2ud(bl); + ud = unit->bl2ud(bl); if(ud == NULL) return 0; - if( !path_search(&wpd,bl->m,bl->x,bl->y,ud->to_x,ud->to_y,ud->state.walk_easy,CELL_CHKNOPASS) ) + if( !path->search(&wpd,bl->m,bl->x,bl->y,ud->to_x,ud->to_y,ud->state.walk_easy,CELL_CHKNOPASS) ) return 0; memcpy(&ud->walkpath,&wpd,sizeof(wpd)); @@ -85,9 +110,9 @@ int unit_walktoxy_sub(struct block_list *bl) ud->walkpath.path_len--; dir = ud->walkpath.path[ud->walkpath.path_len]; if(dir&1) - i-=14; + i -= MOVE_DIAGONAL_COST; else - i-=10; + i -= MOVE_COST; ud->to_x -= dirx[dir]; ud->to_y -= diry[dir]; } @@ -104,16 +129,15 @@ int unit_walktoxy_sub(struct block_list *bl) if(ud->walkpath.path_pos>=ud->walkpath.path_len) i = -1; else if(ud->walkpath.path[ud->walkpath.path_pos]&1) - i = status_get_speed(bl)*14/10; + i = status->get_speed(bl)*MOVE_DIAGONAL_COST/MOVE_COST; else - i = status_get_speed(bl); + i = status->get_speed(bl); if( i > 0) - ud->walktimer = iTimer->add_timer(iTimer->gettick()+i,unit_walktoxy_timer,bl->id,i); + ud->walktimer = timer->add(timer->gettick()+i,unit->walktoxy_timer,bl->id,i); return 1; } -static int unit_walktoxy_timer(int tid, unsigned int tick, int id, intptr_t data) -{ +int unit_walktoxy_timer(int tid, int64 tick, int id, intptr_t data) { int i; int x,y,dx,dy; uint8 dir; @@ -123,13 +147,13 @@ static int unit_walktoxy_timer(int tid, unsigned int tick, int id, intptr_t data struct unit_data *ud; struct mercenary_data *mrd; - bl = iMap->id2bl(id); + bl = map->id2bl(id); if(bl == NULL) return 0; sd = BL_CAST(BL_PC, bl); md = BL_CAST(BL_MOB, bl); mrd = BL_CAST(BL_MER, bl); - ud = unit_bl2ud(bl); + ud = unit->bl2ud(bl); if(ud == NULL) return 0; @@ -154,56 +178,61 @@ static int unit_walktoxy_timer(int tid, unsigned int tick, int id, intptr_t data dx = dirx[(int)dir]; dy = diry[(int)dir]; - if(iMap->getcell(bl->m,x+dx,y+dy,CELL_CHKNOPASS)) - return unit_walktoxy_sub(bl); + if(map->getcell(bl->m,x+dx,y+dy,CELL_CHKNOPASS)) + return unit->walktoxy_sub(bl); //Refresh view for all those we lose sight - iMap->foreachinmovearea(clif->outsight, bl, AREA_SIZE, dx, dy, sd?BL_ALL:BL_PC, bl); + map->foreachinmovearea(clif->outsight, bl, AREA_SIZE, dx, dy, sd?BL_ALL:BL_PC, bl); x += dx; y += dy; - iMap->moveblock(bl, x, y, tick); + map->moveblock(bl, x, y, tick); ud->walk_count++; //walked cell counter, to be used for walk-triggered skills. [Skotlex] status_change_end(bl, SC_ROLLINGCUTTER, INVALID_TIMER); //If you move, you lose your counters. [malufett] if (bl->x != x || bl->y != y || ud->walktimer != INVALID_TIMER) - return 0; //iMap->moveblock has altered the object beyond what we expected (moved/warped it) + return 0; //map->moveblock has altered the object beyond what we expected (moved/warped it) ud->walktimer = -2; // arbitrary non-INVALID_TIMER value to make the clif code send walking packets - iMap->foreachinmovearea(clif->insight, bl, AREA_SIZE, -dx, -dy, sd?BL_ALL:BL_PC, bl); + map->foreachinmovearea(clif->insight, bl, AREA_SIZE, -dx, -dy, sd?BL_ALL:BL_PC, bl); ud->walktimer = INVALID_TIMER; if(sd) { if( sd->touching_id ) - npc_touchnext_areanpc(sd,false); - if(iMap->getcell(bl->m,x,y,CELL_CHKNPC)) { - npc_touch_areanpc(sd,bl->m,x,y); + npc->touchnext_areanpc(sd,false); + if(map->getcell(bl->m,x,y,CELL_CHKNPC)) { + npc->touch_areanpc(sd,bl->m,x,y); if (bl->prev == NULL) //Script could have warped char, abort remaining of the function. return 0; } else sd->areanpc_id=0; - if( sd->md && !check_distance_bl(&sd->bl, &sd->md->bl, MAX_MER_DISTANCE) ) - { - // mercenary should be warped after being 3 seconds too far from the master [greenbox] - if (sd->md->masterteleport_timer == 0) - { - sd->md->masterteleport_timer = iTimer->gettick(); - } - else if (DIFF_TICK(iTimer->gettick(), sd->md->masterteleport_timer) > 3000) - { + if( sd->md ) { // mercenary should be warped after being 3 seconds too far from the master [greenbox] + if( !check_distance_bl(&sd->bl, &sd->md->bl, MAX_MER_DISTANCE) ) { + if (sd->md->masterteleport_timer == 0) + sd->md->masterteleport_timer = timer->gettick(); + else if (DIFF_TICK(timer->gettick(), sd->md->masterteleport_timer) > 3000) { + sd->md->masterteleport_timer = 0; + unit->warp( &sd->md->bl, sd->bl.m, sd->bl.x, sd->bl.y, CLR_TELEPORT ); + } + } else // reset the tick, he is not far anymore sd->md->masterteleport_timer = 0; - unit_warp( &sd->md->bl, sd->bl.m, sd->bl.x, sd->bl.y, CLR_TELEPORT ); - } + } - else if( sd->md ) - { - // reset the tick, he is not far anymore - sd->md->masterteleport_timer = 0; + if( sd->hd ) { + if( homun_alive(sd->hd) && !check_distance_bl(&sd->bl, &sd->hd->bl, MAX_MER_DISTANCE) ) { + if (sd->hd->masterteleport_timer == 0) + sd->hd->masterteleport_timer = timer->gettick(); + else if (DIFF_TICK(timer->gettick(), sd->hd->masterteleport_timer) > 3000) { + sd->hd->masterteleport_timer = 0; + unit->warp( &sd->hd->bl, sd->bl.m, sd->bl.x, sd->bl.y, CLR_TELEPORT ); + } + } else + sd->hd->masterteleport_timer = 0; } } else if (md) { - if( iMap->getcell(bl->m,x,y,CELL_CHKNPC) ) { - if( npc_touch_areanpc2(md) ) return 0; // Warped + if( map->getcell(bl->m,x,y,CELL_CHKNPC) ) { + if( npc->touch_areanpc2(md) ) return 0; // Warped } else md->areanpc_id = 0; if (md->min_chase > md->db->range3) md->min_chase--; @@ -211,11 +240,11 @@ static int unit_walktoxy_timer(int tid, unsigned int tick, int id, intptr_t data //But avoid triggering on stop-walk calls. if(tid != INVALID_TIMER && !(ud->walk_count%WALK_SKILL_INTERVAL) && - mobskill_use(md, tick, -1)) + mob->skill_use(md, tick, -1)) { if (!(ud->skill_id == NPC_SELFDESTRUCTION && ud->skilltimer != INVALID_TIMER)) { //Skill used, abort walking - clif->fixpos(bl); //Fix position as walk has been cancelled. + clif->fixpos(bl); //Fix position as walk has been canceled. return 0; } //Resend walk packet for proper Self Destruction display. @@ -229,12 +258,12 @@ static int unit_walktoxy_timer(int tid, unsigned int tick, int id, intptr_t data // mercenary should be warped after being 3 seconds too far from the master [greenbox] if (mrd->masterteleport_timer == 0) { - mrd->masterteleport_timer = iTimer->gettick(); + mrd->masterteleport_timer = timer->gettick(); } - else if (DIFF_TICK(iTimer->gettick(), mrd->masterteleport_timer) > 3000) + else if (DIFF_TICK(timer->gettick(), mrd->masterteleport_timer) > 3000) { mrd->masterteleport_timer = 0; - unit_warp( bl, mrd->master->bl.id, mrd->master->bl.x, mrd->master->bl.y, CLR_TELEPORT ); + unit->warp( bl, mrd->master->bl.m, mrd->master->bl.x, mrd->master->bl.y, CLR_TELEPORT ); } } else @@ -247,64 +276,63 @@ static int unit_walktoxy_timer(int tid, unsigned int tick, int id, intptr_t data return 0; if(ud->state.change_walk_target) - return unit_walktoxy_sub(bl); + return unit->walktoxy_sub(bl); ud->walkpath.path_pos++; if(ud->walkpath.path_pos>=ud->walkpath.path_len) i = -1; else if(ud->walkpath.path[ud->walkpath.path_pos]&1) - i = status_get_speed(bl)*14/10; + i = status->get_speed(bl)*14/10; else - i = status_get_speed(bl); + i = status->get_speed(bl); if(i > 0) { - ud->walktimer = iTimer->add_timer(tick+i,unit_walktoxy_timer,id,i); + ud->walktimer = timer->add(tick+i,unit->walktoxy_timer,id,i); if( md && DIFF_TICK(tick,md->dmgtick) < 3000 )//not required not damaged recently clif->move(ud); } else if(ud->state.running) { //Keep trying to run. - if ( !(unit_run(bl) || unit_wugdash(bl,sd)) ) + if ( !(unit->run(bl, NULL, SC_RUN) || unit->run(bl, sd, SC_WUGDASH)) ) ud->state.running = 0; - } - else if (ud->target_to) { + } else if (ud->target_to) { //Update target trajectory. - struct block_list *tbl = iMap->id2bl(ud->target_to); - if (!tbl || !status_check_visibility(bl, tbl)) { //Cancel chase. + struct block_list *tbl = map->id2bl(ud->target_to); + if (!tbl || !status->check_visibility(bl, tbl)) { + //Cancel chase. ud->to_x = bl->x; ud->to_y = bl->y; - if (tbl && bl->type == BL_MOB && mob_warpchase((TBL_MOB*)bl, tbl) ) + if (tbl && bl->type == BL_MOB && mob->warpchase((TBL_MOB*)bl, tbl) ) return 0; ud->target_to = 0; return 0; } - if (tbl->m == bl->m && check_distance_bl(bl, tbl, ud->chaserange)) - { //Reached destination. + if (tbl->m == bl->m && check_distance_bl(bl, tbl, ud->chaserange)) { + //Reached destination. if (ud->state.attack_continue) { //Aegis uses one before every attack, we should //only need this one for syncing purposes. [Skotlex] ud->target_to = 0; clif->fixpos(bl); - unit_attack(bl, tbl->id, ud->state.attack_continue); + unit->attack(bl, tbl->id, ud->state.attack_continue); } } else { //Update chase-path - unit_walktobl(bl, tbl, ud->chaserange, ud->state.walk_easy|(ud->state.attack_continue?2:0)); + unit->walktobl(bl, tbl, ud->chaserange, ud->state.walk_easy|(ud->state.attack_continue?2:0)); return 0; } - } - else { //Stopped walking. Update to_x and to_y to current location [Skotlex] + } else { + //Stopped walking. Update to_x and to_y to current location [Skotlex] ud->to_x = bl->x; ud->to_y = bl->y; } return 0; } -static int unit_delay_walktoxy_timer(int tid, unsigned int tick, int id, intptr_t data) -{ - struct block_list *bl = iMap->id2bl(id); +int unit_delay_walktoxy_timer(int tid, int64 tick, int id, intptr_t data) { + struct block_list *bl = map->id2bl(id); if (!bl || bl->prev == NULL) return 0; - unit_walktoxy(bl, (short)((data>>16)&0xffff), (short)(data&0xffff), 0); + unit->walktoxy(bl, (short)((data>>16)&0xffff), (short)(data&0xffff), 0); return 1; } @@ -320,52 +348,58 @@ int unit_walktoxy( struct block_list *bl, short x, short y, int flag) nullpo_ret(bl); - ud = unit_bl2ud(bl); + ud = unit->bl2ud(bl); if( ud == NULL) return 0; - path_search(&wpd, bl->m, bl->x, bl->y, x, y, flag&1, CELL_CHKNOPASS); // Count walk path cells + if (!path->search(&wpd, bl->m, bl->x, bl->y, x, y, flag&1, CELL_CHKNOPASS)) // Count walk path cells + return 0; + #ifdef OFFICIAL_WALKPATH - if( !path_search_long(NULL, bl->m, bl->x, bl->y, x, y, CELL_CHKNOPASS) // Check if there is an obstacle between + if( !path->search_long(NULL, bl->m, bl->x, bl->y, x, y, CELL_CHKNOPASS) // Check if there is an obstacle between && (wpd.path_len > (battle_config.max_walk_path/17)*14) // Official number of walkable cells is 14 if and only if there is an obstacle between. [malufett] && (bl->type != BL_NPC) ) // If type is a NPC, please disregard. return 0; #endif - if( (battle_config.max_walk_path < wpd.path_len) && (bl->type != BL_NPC) ) + if ((wpd.path_len > battle_config.max_walk_path) && (bl->type != BL_NPC)) return 0; - if (flag&4 && DIFF_TICK(ud->canmove_tick, iTimer->gettick()) > 0 && - DIFF_TICK(ud->canmove_tick, iTimer->gettick()) < 2000) - { // Delay walking command. [Skotlex] - iTimer->add_timer(ud->canmove_tick+1, unit_delay_walktoxy_timer, bl->id, (x<<16)|(y&0xFFFF)); + if (flag&4 && DIFF_TICK(ud->canmove_tick, timer->gettick()) > 0 && + DIFF_TICK(ud->canmove_tick, timer->gettick()) < 2000) { + // Delay walking command. [Skotlex] + timer->add(ud->canmove_tick+1, unit->delay_walktoxy_timer, bl->id, (x<<16)|(y&0xFFFF)); return 1; } - if(!(flag&2) && (!(status_get_mode(bl)&MD_CANMOVE) || !unit_can_move(bl))) + if(!(flag&2) && (!(status_get_mode(bl)&MD_CANMOVE) || !unit->can_move(bl))) return 0; ud->state.walk_easy = flag&1; ud->to_x = x; ud->to_y = y; - unit_set_target(ud, 0); + unit->set_target(ud, 0); - sc = status_get_sc(bl); - if (sc && sc->data[SC_CONFUSION]) //Randomize the target position - iMap->random_dir(bl, &ud->to_x, &ud->to_y); + sc = status->get_sc(bl); + if( sc ) { + if( sc->data[SC_CONFUSION] || sc->data[SC__CHAOS] ) //Randomize the target position + map->random_dir(bl, &ud->to_x, &ud->to_y); + if( sc->data[SC_COMBOATTACK] ) + status_change_end(bl, SC_COMBOATTACK, INVALID_TIMER); + } if(ud->walktimer != INVALID_TIMER) { // When you come to the center of the grid because the change of destination while you're walking right now - // Call a function from a timer unit_walktoxy_sub + // Call a function from a timer unit->walktoxy_sub ud->state.change_walk_target = 1; return 1; } if(ud->attacktimer != INVALID_TIMER) { - iTimer->delete_timer( ud->attacktimer, unit_attack_timer ); + timer->delete( ud->attacktimer, unit->attack_timer ); ud->attacktimer = INVALID_TIMER; } - return unit_walktoxy_sub(bl); + return unit->walktoxy_sub(bl); } //To set Mob's CHASE/FOLLOW states (shouldn't be done if there's no path to reach) @@ -377,18 +411,15 @@ static inline void set_mobstate(struct block_list* bl, int flag) md->state.skillstate = md->state.aggressive ? MSS_FOLLOW : MSS_RUSH; } -static int unit_walktobl_sub(int tid, unsigned int tick, int id, intptr_t data) -{ - struct block_list *bl = iMap->id2bl(id); - struct unit_data *ud = bl?unit_bl2ud(bl):NULL; +int unit_walktobl_sub(int tid, int64 tick, int id, intptr_t data) { + struct block_list *bl = map->id2bl(id); + struct unit_data *ud = bl?unit->bl2ud(bl):NULL; - if (ud && ud->walktimer == INVALID_TIMER && ud->target == data) - { + if (ud && ud->walktimer == INVALID_TIMER && ud->target == data) { if (DIFF_TICK(ud->canmove_tick, tick) > 0) //Keep waiting? - iTimer->add_timer(ud->canmove_tick+1, unit_walktobl_sub, id, data); - else if (unit_can_move(bl)) - { - if (unit_walktoxy_sub(bl)) + timer->add(ud->canmove_tick+1, unit->walktobl_sub, id, data); + else if (unit->can_move(bl)) { + if (unit->walktoxy_sub(bl)) set_mobstate(bl, ud->state.attack_continue); } } @@ -405,13 +436,13 @@ int unit_walktobl(struct block_list *bl, struct block_list *tbl, int range, int nullpo_ret(bl); nullpo_ret(tbl); - ud = unit_bl2ud(bl); + ud = unit->bl2ud(bl); if( ud == NULL) return 0; if (!(status_get_mode(bl)&MD_CANMOVE)) return 0; - if (!unit_can_reach_bl(bl, tbl, distance_bl(bl, tbl)+1, flag&1, &ud->to_x, &ud->to_y)) { + if (!unit->can_reach_bl(bl, tbl, distance_bl(bl, tbl)+1, flag&1, &ud->to_x, &ud->to_y)) { ud->to_x = bl->x; ud->to_y = bl->y; ud->target_to = 0; @@ -422,11 +453,11 @@ int unit_walktobl(struct block_list *bl, struct block_list *tbl, int range, int ud->target_to = tbl->id; ud->chaserange = range; //Note that if flag&2, this SHOULD be attack-range ud->state.attack_continue = flag&2?1:0; //Chase to attack. - unit_set_target(ud, 0); + unit->set_target(ud, 0); - sc = status_get_sc(bl); - if (sc && sc->data[SC_CONFUSION]) //Randomize the target position - iMap->random_dir(bl, &ud->to_x, &ud->to_y); + sc = status->get_sc(bl); + if (sc && (sc->data[SC_CONFUSION] || sc->data[SC__CHAOS])) //Randomize the target position + map->random_dir(bl, &ud->to_x, &ud->to_y); if(ud->walktimer != INVALID_TIMER) { ud->state.change_walk_target = 1; @@ -434,176 +465,129 @@ int unit_walktobl(struct block_list *bl, struct block_list *tbl, int range, int return 1; } - if(DIFF_TICK(ud->canmove_tick, iTimer->gettick()) > 0) + if(DIFF_TICK(ud->canmove_tick, timer->gettick()) > 0) { //Can't move, wait a bit before invoking the movement. - iTimer->add_timer(ud->canmove_tick+1, unit_walktobl_sub, bl->id, ud->target); + timer->add(ud->canmove_tick+1, unit->walktobl_sub, bl->id, ud->target); return 1; } - if(!unit_can_move(bl)) + if(!unit->can_move(bl)) return 0; if(ud->attacktimer != INVALID_TIMER) { - iTimer->delete_timer( ud->attacktimer, unit_attack_timer ); + timer->delete( ud->attacktimer, unit->attack_timer ); ud->attacktimer = INVALID_TIMER; } - if (unit_walktoxy_sub(bl)) { + if (unit->walktoxy_sub(bl)) { set_mobstate(bl, flag&2); return 1; } return 0; } -int unit_run(struct block_list *bl) -{ - struct status_change *sc = status_get_sc(bl); - short to_x,to_y,dir_x,dir_y; - int lv; - int i; - - if (!(sc && sc->data[SC_RUN])) - return 0; - - if (!unit_can_move(bl)) { - status_change_end(bl, SC_RUN, INVALID_TIMER); - return 0; - } - - lv = sc->data[SC_RUN]->val1; - dir_x = dirx[sc->data[SC_RUN]->val2]; - dir_y = diry[sc->data[SC_RUN]->val2]; - - // determine destination cell - to_x = bl->x; - to_y = bl->y; - for(i=0;i<AREA_SIZE;i++) - { - if(!iMap->getcell(bl->m,to_x+dir_x,to_y+dir_y,CELL_CHKPASS)) - break; - - //if sprinting and there's a PC/Mob/NPC, block the path [Kevin] - if(sc->data[SC_RUN] && iMap->count_oncell(bl->m, to_x+dir_x, to_y+dir_y, BL_PC|BL_MOB|BL_NPC)) - break; - to_x += dir_x; - to_y += dir_y; - } +/** + * Called by unit_run when an object was hit + * @param sd Required only when using SC_WUGDASH + **/ +void unit_run_hit( struct block_list *bl, struct status_change *sc, struct map_session_data *sd, enum sc_type type ) { + int lv = sc->data[type]->val1; - if( (to_x == bl->x && to_y == bl->y ) || (to_x == (bl->x+1) || to_y == (bl->y+1)) || (to_x == (bl->x-1) || to_y == (bl->y-1))) { - //If you can't run forward, you must be next to a wall, so bounce back. [Skotlex] + //If you can't run forward, you must be next to a wall, so bounce back. [Skotlex] + if( type == SC_RUN ) clif->sc_load(bl,bl->id,AREA,SI_TING,0,0,0); - //Set running to 0 beforehand so status_change_end knows not to enable spurt [Kevin] - unit_bl2ud(bl)->state.running = 0; - status_change_end(bl, SC_RUN, INVALID_TIMER); + //Set running to 0 beforehand so status_change_end knows not to enable spurt [Kevin] + unit->bl2ud(bl)->state.running = 0; + status_change_end(bl, type, INVALID_TIMER); - skill->blown(bl,bl,skill->get_blewcount(TK_RUN,lv),unit_getdir(bl),0); + if( type == SC_RUN ) { + skill->blown(bl,bl,skill->get_blewcount(TK_RUN,lv),unit->getdir(bl),0); clif->fixpos(bl); //Why is a clif->slide (skill->blown) AND a fixpos needed? Ask Aegis. clif->sc_end(bl,bl->id,AREA,SI_TING); - return 0; - } - if (unit_walktoxy(bl, to_x, to_y, 1)) - return 1; - //There must be an obstacle nearby. Attempt walking one cell at a time. - do { - to_x -= dir_x; - to_y -= dir_y; - } while (--i > 0 && !unit_walktoxy(bl, to_x, to_y, 1)); - if ( i == 0 ) { - // copy-paste from above - clif->sc_load(bl,bl->id,AREA,SI_TING,0,0,0); - - //Set running to 0 beforehand so status_change_end knows not to enable spurt [Kevin] - unit_bl2ud(bl)->state.running = 0; - status_change_end(bl, SC_RUN, INVALID_TIMER); - - skill->blown(bl,bl,skill->get_blewcount(TK_RUN,lv),unit_getdir(bl),0); + } else if( sd ) { clif->fixpos(bl); - clif->sc_end(bl,bl->id,AREA,SI_TING); - return 0; + skill->castend_damage_id(bl, &sd->bl, RA_WUGDASH, lv, timer->gettick(), SD_LEVEL); } - return 1; + return; } -//Exclusive function to Wug Dash state. [Jobbie/3CeAM] -int unit_wugdash(struct block_list *bl, struct map_session_data *sd) { - struct status_change *sc = status_get_sc(bl); +/** + * Makes character run, used for SC_RUN and SC_WUGDASH + * @param sd Required only when using SC_WUGDASH + * @retval true Finished running + * @retval false Hit an object/Couldn't run + **/ +bool unit_run( struct block_list *bl, struct map_session_data *sd, enum sc_type type ) { + struct status_change *sc; short to_x,to_y,dir_x,dir_y; - int lv; int i; - if (!(sc && sc->data[SC_WUGDASH])) - return 0; - nullpo_ret(sd); - nullpo_ret(bl); + nullpo_retr(false, bl); + sc = status->get_sc(bl); - if (!unit_can_move(bl)) { - status_change_end(bl,SC_WUGDASH,INVALID_TIMER); - return 0; + if( !(sc && sc->data[type]) ) + return false; + + if( !unit->can_move(bl) ) { + status_change_end(bl, type, INVALID_TIMER); + return false; } - lv = sc->data[SC_WUGDASH]->val1; - dir_x = dirx[sc->data[SC_WUGDASH]->val2]; - dir_y = diry[sc->data[SC_WUGDASH]->val2]; + dir_x = dirx[sc->data[type]->val2]; + dir_y = diry[sc->data[type]->val2]; + // determine destination cell to_x = bl->x; to_y = bl->y; - for(i=0;i<AREA_SIZE;i++) - { - if(!iMap->getcell(bl->m,to_x+dir_x,to_y+dir_y,CELL_CHKPASS)) + + // Search for available path + for(i = 0; i < AREA_SIZE; i++) { + if(!map->getcell(bl->m,to_x+dir_x,to_y+dir_y,CELL_CHKPASS)) break; - if(sc->data[SC_WUGDASH] && iMap->count_oncell(bl->m, to_x+dir_x, to_y+dir_y, BL_PC|BL_MOB|BL_NPC)) + //if sprinting and there's a PC/Mob/NPC, block the path [Kevin] + if( map->count_oncell(bl->m, to_x+dir_x, to_y+dir_y, BL_PC|BL_MOB|BL_NPC) ) break; to_x += dir_x; to_y += dir_y; } - if(to_x == bl->x && to_y == bl->y) { + // Can't run forward + if( (to_x == bl->x && to_y == bl->y ) || (to_x == (bl->x+1) || to_y == (bl->y+1)) || (to_x == (bl->x-1) || to_y == (bl->y-1))) { + unit->run_hit(bl, sc, sd, type); + return false; + } - unit_bl2ud(bl)->state.running = 0; - status_change_end(bl,SC_WUGDASH,INVALID_TIMER); + if( unit->walktoxy(bl, to_x, to_y, 1) ) + return true; - if( sd ){ - clif->fixpos(bl); - skill->castend_damage_id(bl, &sd->bl, RA_WUGDASH, lv, iTimer->gettick(), SD_LEVEL); - } - return 0; - } - if (unit_walktoxy(bl, to_x, to_y, 1)) - return 1; + //There must be an obstacle nearby. Attempt walking one cell at a time. do { to_x -= dir_x; to_y -= dir_y; - } while (--i > 0 && !unit_walktoxy(bl, to_x, to_y, 1)); - if (i==0) { + } while (--i > 0 && !unit->walktoxy(bl, to_x, to_y, 1)); - unit_bl2ud(bl)->state.running = 0; - status_change_end(bl,SC_WUGDASH,INVALID_TIMER); - - if( sd ){ - clif->fixpos(bl); - skill->castend_damage_id(bl, &sd->bl, RA_WUGDASH, lv, iTimer->gettick(), SD_LEVEL); - } - return 0; + if ( i == 0 ) { + unit->run_hit(bl, sc, sd, type); + return false; } + return 1; } //Makes bl attempt to run dist cells away from target. Uses hard-paths. -int unit_escape(struct block_list *bl, struct block_list *target, short dist) -{ - uint8 dir = iMap->calc_dir(target, bl->x, bl->y); - while( dist > 0 && iMap->getcell(bl->m, bl->x + dist*dirx[dir], bl->y + dist*diry[dir], CELL_CHKNOREACH) ) +int unit_escape(struct block_list *bl, struct block_list *target, short dist) { + uint8 dir = map->calc_dir(target, bl->x, bl->y); + while( dist > 0 && map->getcell(bl->m, bl->x + dist*dirx[dir], bl->y + dist*diry[dir], CELL_CHKNOREACH) ) dist--; - return ( dist > 0 && unit_walktoxy(bl, bl->x + dist*dirx[dir], bl->y + dist*diry[dir], 0) ); + return ( dist > 0 && unit->walktoxy(bl, bl->x + dist*dirx[dir], bl->y + dist*diry[dir], 0) ); } //Instant warp function. -int unit_movepos(struct block_list *bl, short dst_x, short dst_y, int easy, bool checkpath) -{ +int unit_movepos(struct block_list *bl, short dst_x, short dst_y, int easy, bool checkpath) { short dx,dy; uint8 dir; struct unit_data *ud = NULL; @@ -611,38 +595,38 @@ int unit_movepos(struct block_list *bl, short dst_x, short dst_y, int easy, bool nullpo_ret(bl); sd = BL_CAST(BL_PC, bl); - ud = unit_bl2ud(bl); + ud = unit->bl2ud(bl); if( ud == NULL) return 0; - unit_stop_walking(bl,1); - unit_stop_attack(bl); + unit->stop_walking(bl,1); + unit->stop_attack(bl); - if( checkpath && (iMap->getcell(bl->m,dst_x,dst_y,CELL_CHKNOPASS) || !path_search(NULL,bl->m,bl->x,bl->y,dst_x,dst_y,easy,CELL_CHKNOREACH)) ) + if( checkpath && (map->getcell(bl->m,dst_x,dst_y,CELL_CHKNOPASS) || !path->search(NULL,bl->m,bl->x,bl->y,dst_x,dst_y,easy,CELL_CHKNOREACH)) ) return 0; // unreachable ud->to_x = dst_x; ud->to_y = dst_y; - dir = iMap->calc_dir(bl, dst_x, dst_y); + dir = map->calc_dir(bl, dst_x, dst_y); ud->dir = dir; dx = dst_x - bl->x; dy = dst_y - bl->y; - iMap->foreachinmovearea(clif->outsight, bl, AREA_SIZE, dx, dy, sd?BL_ALL:BL_PC, bl); + map->foreachinmovearea(clif->outsight, bl, AREA_SIZE, dx, dy, sd?BL_ALL:BL_PC, bl); - iMap->moveblock(bl, dst_x, dst_y, iTimer->gettick()); + map->moveblock(bl, dst_x, dst_y, timer->gettick()); ud->walktimer = -2; // arbitrary non-INVALID_TIMER value to make the clif code send walking packets - iMap->foreachinmovearea(clif->insight, bl, AREA_SIZE, -dx, -dy, sd?BL_ALL:BL_PC, bl); + map->foreachinmovearea(clif->insight, bl, AREA_SIZE, -dx, -dy, sd?BL_ALL:BL_PC, bl); ud->walktimer = INVALID_TIMER; if(sd) { if( sd->touching_id ) - npc_touchnext_areanpc(sd,false); - if(iMap->getcell(bl->m,bl->x,bl->y,CELL_CHKNPC)) { - npc_touch_areanpc(sd,bl->m,bl->x,bl->y); + npc->touchnext_areanpc(sd,false); + if(map->getcell(bl->m,bl->x,bl->y,CELL_CHKNPC)) { + npc->touch_areanpc(sd,bl->m,bl->x,bl->y); if (bl->prev == NULL) //Script could have warped char, abort remaining of the function. return 0; } else @@ -651,15 +635,15 @@ int unit_movepos(struct block_list *bl, short dst_x, short dst_y, int easy, bool if( sd->status.pet_id > 0 && sd->pd && sd->pd->pet.intimate > 0 ) { // Check if pet needs to be teleported. [Skotlex] int flag = 0; - struct block_list* bl = &sd->pd->bl; - if( !checkpath && !path_search(NULL,bl->m,bl->x,bl->y,dst_x,dst_y,0,CELL_CHKNOPASS) ) + struct block_list* pbl = &sd->pd->bl; + if( !checkpath && !path->search(NULL,pbl->m,pbl->x,pbl->y,dst_x,dst_y,0,CELL_CHKNOPASS) ) flag = 1; - else if (!check_distance_bl(&sd->bl, bl, AREA_SIZE)) //Too far, teleport. + else if (!check_distance_bl(&sd->bl, pbl, AREA_SIZE)) //Too far, teleport. flag = 2; if( flag ) { - unit_movepos(bl,sd->bl.x,sd->bl.y, 0, 0); - clif->slide(bl,bl->x,bl->y); + unit->movepos(pbl,sd->bl.x,sd->bl.y, 0, 0); + clif->slide(pbl,pbl->x,pbl->y); } } } @@ -670,7 +654,7 @@ int unit_setdir(struct block_list *bl,unsigned char dir) { struct unit_data *ud; nullpo_ret(bl ); - ud = unit_bl2ud(bl); + ud = unit->bl2ud(bl); if (!ud) return 0; ud->dir = dir; if (bl->type == BL_PC) @@ -685,7 +669,7 @@ uint8 unit_getdir(struct block_list *bl) { if( bl->type == BL_NPC ) return ((TBL_NPC*)bl)->dir; - ud = unit_bl2ud(bl); + ud = unit->bl2ud(bl); if (!ud) return 0; return ud->dir; } @@ -701,16 +685,18 @@ int unit_blown(struct block_list* bl, int dx, int dy, int count, int flag) struct skill_unit* su = NULL; int nx, ny, result; + nullpo_ret(bl); + sd = BL_CAST(BL_PC, bl); su = BL_CAST(BL_SKILL, bl); - result = path_blownpos(bl->m, bl->x, bl->y, dx, dy, count); + result = path->blownpos(bl->m, bl->x, bl->y, dx, dy, count); nx = result>>16; ny = result&0xffff; if(!su) { - unit_stop_walking(bl, 0); + unit->stop_walking(bl, 0); } if( sd ) { @@ -722,15 +708,15 @@ int unit_blown(struct block_list* bl, int dx, int dy, int count, int flag) dy = ny-bl->y; if(dx || dy) { - iMap->foreachinmovearea(clif->outsight, bl, AREA_SIZE, dx, dy, bl->type == BL_PC ? BL_ALL : BL_PC, bl); + map->foreachinmovearea(clif->outsight, bl, AREA_SIZE, dx, dy, bl->type == BL_PC ? BL_ALL : BL_PC, bl); if(su) { skill->unit_move_unit_group(su->group, bl->m, dx, dy); } else { - iMap->moveblock(bl, nx, ny, iTimer->gettick()); + map->moveblock(bl, nx, ny, timer->gettick()); } - iMap->foreachinmovearea(clif->insight, bl, AREA_SIZE, -dx, -dy, bl->type == BL_PC ? BL_ALL : BL_PC, bl); + map->foreachinmovearea(clif->insight, bl, AREA_SIZE, -dx, -dy, bl->type == BL_PC ? BL_ALL : BL_PC, bl); if(!(flag&1)) { clif->blown(bl); @@ -738,17 +724,17 @@ int unit_blown(struct block_list* bl, int dx, int dy, int count, int flag) if(sd) { if(sd->touching_id) { - npc_touchnext_areanpc(sd, false); + npc->touchnext_areanpc(sd, false); } - if(iMap->getcell(bl->m, bl->x, bl->y, CELL_CHKNPC)) { - npc_touch_areanpc(sd, bl->m, bl->x, bl->y); + if(map->getcell(bl->m, bl->x, bl->y, CELL_CHKNPC)) { + npc->touch_areanpc(sd, bl->m, bl->x, bl->y); } else { sd->areanpc_id = 0; } } } - count = distance(dx, dy); + count = path->distance(dx, dy); } return count; // return amount of knocked back cells @@ -761,7 +747,7 @@ int unit_warp(struct block_list *bl,short m,short x,short y,clr_type type) { struct unit_data *ud; nullpo_ret(bl); - ud = unit_bl2ud(bl); + ud = unit->bl2ud(bl); if(bl->prev==NULL || !ud) return 1; @@ -775,31 +761,31 @@ int unit_warp(struct block_list *bl,short m,short x,short y,clr_type type) switch (bl->type) { case BL_MOB: - if (map[bl->m].flag.monster_noteleport && ((TBL_MOB*)bl)->master_id == 0) + if (map->list[bl->m].flag.monster_noteleport && ((TBL_MOB*)bl)->master_id == 0) return 1; - if (m != bl->m && map[m].flag.nobranch && battle_config.mob_warp&4 && !(((TBL_MOB *)bl)->master_id)) + if (m != bl->m && map->list[m].flag.nobranch && battle_config.mob_warp&4 && !(((TBL_MOB *)bl)->master_id)) return 1; break; case BL_PC: - if (map[bl->m].flag.noteleport) + if (map->list[bl->m].flag.noteleport) return 1; break; } - if (x<0 || y<0) - { //Random map position. - if (!iMap->search_freecell(NULL, m, &x, &y, -1, -1, 1)) { - ShowWarning("unit_warp failed. Unit Id:%d/Type:%d, target position map %d (%s) at [%d,%d]\n", bl->id, bl->type, m, map[m].name, x, y); + if (x<0 || y<0) { + //Random map position. + if (!map->search_freecell(NULL, m, &x, &y, -1, -1, 1)) { + ShowWarning("unit_warp failed. Unit Id:%d/Type:%d, target position map %d (%s) at [%d,%d]\n", bl->id, bl->type, m, map->list[m].name, x, y); return 2; } - } else if (iMap->getcell(m,x,y,CELL_CHKNOREACH)) - { //Invalid target cell - ShowWarning("unit_warp: Specified non-walkable target cell: %d (%s) at [%d,%d]\n", m, map[m].name, x,y); + } else if (map->getcell(m,x,y,CELL_CHKNOREACH)) { + //Invalid target cell + ShowWarning("unit_warp: Specified non-walkable target cell: %d (%s) at [%d,%d]\n", m, map->list[m].name, x,y); - if (!iMap->search_freecell(NULL, m, &x, &y, 4, 4, 1)) - { //Can't find a nearby cell - ShowWarning("unit_warp failed. Unit Id:%d/Type:%d, target position map %d (%s) at [%d,%d]\n", bl->id, bl->type, m, map[m].name, x, y); + if (!map->search_freecell(NULL, m, &x, &y, 4, 4, 1)) { + //Can't find a nearby cell + ShowWarning("unit_warp failed. Unit Id:%d/Type:%d, target position map %d (%s) at [%d,%d]\n", bl->id, bl->type, m, map->list[m].name, x, y); return 2; } } @@ -807,7 +793,7 @@ int unit_warp(struct block_list *bl,short m,short x,short y,clr_type type) if (bl->type == BL_PC) //Use pc_setpos return pc->setpos((TBL_PC*)bl, map_id2index(m), x, y, type); - if (!unit_remove_map(bl, type)) + if (!unit->remove_map(bl, type, ALC_MARK)) return 3; if (bl->m != m && battle_config.clear_unit_onwarp && @@ -818,9 +804,9 @@ int unit_warp(struct block_list *bl,short m,short x,short y,clr_type type) bl->y=ud->to_y=y; bl->m=m; - iMap->addblock(bl); + map->addblock(bl); clif->spawn(bl); - skill->unit_move(bl,iTimer->gettick(),1); + skill->unit_move(bl,timer->gettick(),1); return 0; } @@ -837,25 +823,25 @@ int unit_stop_walking(struct block_list *bl,int type) { struct unit_data *ud; const struct TimerData* td; - unsigned int tick; + int64 tick; nullpo_ret(bl); - ud = unit_bl2ud(bl); + ud = unit->bl2ud(bl); if(!ud || ud->walktimer == INVALID_TIMER) return 0; //NOTE: We are using timer data after deleting it because we know the - //iTimer->delete_timer function does not messes with it. If the function's - //behaviour changes in the future, this code could break! - td = iTimer->get_timer(ud->walktimer); - iTimer->delete_timer(ud->walktimer, unit_walktoxy_timer); + //timer->delete function does not messes with it. If the function's + //behavior changes in the future, this code could break! + td = timer->get(ud->walktimer); + timer->delete(ud->walktimer, unit->walktoxy_timer); ud->walktimer = INVALID_TIMER; ud->state.change_walk_target = 0; - tick = iTimer->gettick(); + tick = timer->gettick(); if( (type&0x02 && !ud->walkpath.path_pos) //Force moving at least one cell. || (type&0x04 && td && DIFF_TICK(td->tick, tick) <= td->data/2) //Enough time has passed to cover half-cell ) { ud->walkpath.path_len = ud->walkpath.path_pos+1; - unit_walktoxy_timer(INVALID_TIMER, tick, bl->id, ud->walkpath.path_pos); + unit->walktoxy_timer(INVALID_TIMER, tick, bl->id, ud->walkpath.path_pos); } if(type&0x01) @@ -866,9 +852,9 @@ int unit_stop_walking(struct block_list *bl,int type) ud->to_x = bl->x; ud->to_y = bl->y; if(bl->type == BL_PET && type&~0xff) - ud->canmove_tick = iTimer->gettick() + (type>>8); + ud->canmove_tick = timer->gettick() + (type>>8); - //Readded, the check in unit_set_walkdelay means dmg during running won't fall through to this place in code [Kevin] + //Read, the check in unit_set_walkdelay means dmg during running won't fall through to this place in code [Kevin] if (ud->state.running) { status_change_end(bl, SC_RUN, INVALID_TIMER); status_change_end(bl, SC_WUGDASH, INVALID_TIMER); @@ -878,7 +864,7 @@ int unit_stop_walking(struct block_list *bl,int type) int unit_skilluse_id(struct block_list *src, int target_id, uint16 skill_id, uint16 skill_lv) { - return unit_skilluse_id2( + return unit->skilluse_id2( src, target_id, skill_id, skill_lv, skill->cast_fix(src, skill_id, skill_lv), skill->get_castcancel(skill_id) @@ -887,7 +873,7 @@ int unit_skilluse_id(struct block_list *src, int target_id, uint16 skill_id, uin int unit_is_walking(struct block_list *bl) { - struct unit_data *ud = unit_bl2ud(bl); + struct unit_data *ud = unit->bl2ud(bl); nullpo_ret(bl); if(!ud) return 0; return (ud->walktimer != INVALID_TIMER); @@ -902,8 +888,8 @@ int unit_can_move(struct block_list *bl) { struct status_change *sc; nullpo_ret(bl); - ud = unit_bl2ud(bl); - sc = status_get_sc(bl); + ud = unit->bl2ud(bl); + sc = status->get_sc(bl); sd = BL_CAST(BL_PC, bl); if (!ud) @@ -912,7 +898,7 @@ int unit_can_move(struct block_list *bl) { if (ud->skilltimer != INVALID_TIMER && ud->skill_id != LG_EXEEDBREAK && (!sd || !pc->checkskill(sd, SA_FREECAST) || skill->get_inf2(ud->skill_id)&INF2_GUILD_SKILL)) return 0; // prevent moving while casting - if (DIFF_TICK(ud->canmove_tick, iTimer->gettick()) > 0) + if (DIFF_TICK(ud->canmove_tick, timer->gettick()) > 0) return 0; if (sd && ( @@ -923,46 +909,52 @@ int unit_can_move(struct block_list *bl) { )) return 0; //Can't move + // Status changes that block movement if (sc) { - if( sc->count && ( - sc->data[SC_ANKLESNARE] - || sc->data[SC_AUTOCOUNTER] - || sc->data[SC_TRICKDEAD] - || sc->data[SC_BLADESTOP] - || sc->data[SC_BLADESTOP_WAIT] - || (sc->data[SC_GOSPEL] && sc->data[SC_GOSPEL]->val4 == BCT_SELF) // cannot move while gospel is in effect - || (sc->data[SC_BASILICA] && sc->data[SC_BASILICA]->val4 == bl->id) // Basilica caster cannot move - || sc->data[SC_STOP] - || sc->data[SC_RG_CCONFINE_M] - || sc->data[SC_RG_CCONFINE_S] - || sc->data[SC_GS_MADNESSCANCEL] - || (sc->data[SC_GRAVITATION] && sc->data[SC_GRAVITATION]->val3 == BCT_SELF) - || sc->data[SC_WHITEIMPRISON] - || sc->data[SC_ELECTRICSHOCKER] - || sc->data[SC_WUGBITE] - || sc->data[SC_THORNS_TRAP] - || sc->data[SC_MAGNETICFIELD] - || sc->data[SC__MANHOLE] - || sc->data[SC_CURSEDCIRCLE_ATKER] - || sc->data[SC_CURSEDCIRCLE_TARGET] - || (sc->data[SC_CRYSTALIZE] && bl->type != BL_MOB) - || sc->data[SC_NETHERWORLD] - || (sc->data[SC_CAMOUFLAGE] && sc->data[SC_CAMOUFLAGE]->val1 < 3 && !(sc->data[SC_CAMOUFLAGE]->val3&1)) - || sc->data[SC_MEIKYOUSISUI] - || sc->data[SC_KG_KAGEHUMI] - || sc->data[SC_KYOUGAKU] - || sc->data[SC_NEEDLE_OF_PARALYZE] - || sc->data[SC_VACUUM_EXTREME] - || (sc->data[SC_FEAR] && sc->data[SC_FEAR]->val2 > 0) - || (sc->data[SC_SPIDERWEB] && sc->data[SC_SPIDERWEB]->val1) - || (sc->data[SC_DANCING] && sc->data[SC_DANCING]->val4 && ( - !sc->data[SC_LONGING] || - (sc->data[SC_DANCING]->val1&0xFFFF) == CG_MOONLIT || - (sc->data[SC_DANCING]->val1&0xFFFF) == CG_HERMODE - ) ) - || (sc->data[SC_CLOAKING] && //Need wall at level 1-2 - sc->data[SC_CLOAKING]->val1 < 3 && !(sc->data[SC_CLOAKING]->val4&1)) - ) ) + if( sc->count + && ( + sc->data[SC_ANKLESNARE] + || sc->data[SC_AUTOCOUNTER] + || sc->data[SC_TRICKDEAD] + || sc->data[SC_BLADESTOP] + || sc->data[SC_BLADESTOP_WAIT] + || (sc->data[SC_GOSPEL] && sc->data[SC_GOSPEL]->val4 == BCT_SELF) // cannot move while gospel is in effect + || (sc->data[SC_BASILICA] && sc->data[SC_BASILICA]->val4 == bl->id) // Basilica caster cannot move + || sc->data[SC_STOP] + || sc->data[SC_FALLENEMPIRE] + || sc->data[SC_RG_CCONFINE_M] + || sc->data[SC_RG_CCONFINE_S] + || sc->data[SC_GS_MADNESSCANCEL] + || (sc->data[SC_GRAVITATION] && sc->data[SC_GRAVITATION]->val3 == BCT_SELF) + || sc->data[SC_WHITEIMPRISON] + || sc->data[SC_ELECTRICSHOCKER] + || sc->data[SC_WUGBITE] + || sc->data[SC_THORNS_TRAP] + || sc->data[SC_MAGNETICFIELD] + || sc->data[SC__MANHOLE] + || sc->data[SC_CURSEDCIRCLE_ATKER] + || sc->data[SC_CURSEDCIRCLE_TARGET] + || (sc->data[SC_COLD] && bl->type != BL_MOB) + || sc->data[SC_DEEP_SLEEP] + || (sc->data[SC_CAMOUFLAGE] && sc->data[SC_CAMOUFLAGE]->val1 < 3 && !(sc->data[SC_CAMOUFLAGE]->val3&1)) + || sc->data[SC_MEIKYOUSISUI] + || sc->data[SC_KG_KAGEHUMI] + || sc->data[SC_KYOUGAKU] + || sc->data[SC_NEEDLE_OF_PARALYZE] + || sc->data[SC_VACUUM_EXTREME] + || (sc->data[SC_FEAR] && sc->data[SC_FEAR]->val2 > 0) + || (sc->data[SC_SPIDERWEB] && sc->data[SC_SPIDERWEB]->val1) + || (sc->data[SC_CLOAKING] && sc->data[SC_CLOAKING]->val1 < 3 && !(sc->data[SC_CLOAKING]->val4&1)) //Need wall at level 1-2 + || ( + sc->data[SC_DANCING] && sc->data[SC_DANCING]->val4 + && ( + !sc->data[SC_LONGING] + || (sc->data[SC_DANCING]->val1&0xFFFF) == CG_MOONLIT + || (sc->data[SC_DANCING]->val1&0xFFFF) == CG_HERMODE + ) + ) + ) + ) return 0; @@ -980,18 +972,17 @@ int unit_can_move(struct block_list *bl) { * Resume running after a walk delay *------------------------------------------*/ -int unit_resume_running(int tid, unsigned int tick, int id, intptr_t data) -{ +int unit_resume_running(int tid, int64 tick, int id, intptr_t data) { struct unit_data *ud = (struct unit_data *)data; - TBL_PC * sd = iMap->id2sd(id); + TBL_PC * sd = map->id2sd(id); if(sd && pc_isridingwug(sd)) clif->skill_nodamage(ud->bl,ud->bl,RA_WUGDASH,ud->skill_lv, - sc_start4(ud->bl,status_skill2sc(RA_WUGDASH),100,ud->skill_lv,unit_getdir(ud->bl),0,0,1)); + sc_start4(ud->bl,ud->bl,status->skill2sc(RA_WUGDASH),100,ud->skill_lv,unit->getdir(ud->bl),0,0,1)); else clif->skill_nodamage(ud->bl,ud->bl,TK_RUN,ud->skill_lv, - sc_start4(ud->bl,status_skill2sc(TK_RUN),100,ud->skill_lv,unit_getdir(ud->bl),0,0,0)); + sc_start4(ud->bl,ud->bl,status->skill2sc(TK_RUN),100,ud->skill_lv,unit->getdir(ud->bl),0,0,0)); if (sd) clif->walkok(sd); @@ -1005,9 +996,8 @@ int unit_resume_running(int tid, unsigned int tick, int id, intptr_t data) * if type is 0, this is a damage induced delay: if previous delay is active, do not change it. * if type is 1, this is a skill induced delay: walk-delay may only be increased, not decreased. *------------------------------------------*/ -int unit_set_walkdelay(struct block_list *bl, unsigned int tick, int delay, int type) -{ - struct unit_data *ud = unit_bl2ud(bl); +int unit_set_walkdelay(struct block_list *bl, int64 tick, int delay, int type) { + struct unit_data *ud = unit->bl2ud(bl); if (delay <= 0 || !ud) return 0; /** @@ -1021,7 +1011,7 @@ int unit_set_walkdelay(struct block_list *bl, unsigned int tick, int delay, int return 0; } else { //Don't set walk delays when already trapped. - if (!unit_can_move(bl)) + if (!unit->can_move(bl)) return 0; } ud->canmove_tick = tick + delay; @@ -1029,52 +1019,55 @@ int unit_set_walkdelay(struct block_list *bl, unsigned int tick, int delay, int { //Stop walking, if chasing, readjust timers. if (delay == 1) { //Minimal delay (walk-delay) disabled. Just stop walking. - unit_stop_walking(bl,4); + unit->stop_walking(bl,4); } else { //Resume running after can move again [Kevin] if(ud->state.running) { - iTimer->add_timer(ud->canmove_tick, unit_resume_running, bl->id, (intptr_t)ud); + timer->add(ud->canmove_tick, unit->resume_running, bl->id, (intptr_t)ud); } else { - unit_stop_walking(bl,2|4); + unit->stop_walking(bl,2|4); if(ud->target) - iTimer->add_timer(ud->canmove_tick+1, unit_walktobl_sub, bl->id, ud->target); + timer->add(ud->canmove_tick+1, unit->walktobl_sub, bl->id, ud->target); } } } return 1; } -int unit_skilluse_id2(struct block_list *src, int target_id, uint16 skill_id, uint16 skill_lv, int casttime, int castcancel) -{ +int unit_skilluse_id2(struct block_list *src, int target_id, uint16 skill_id, uint16 skill_lv, int casttime, int castcancel) { struct unit_data *ud; struct status_data *tstatus; struct status_change *sc; struct map_session_data *sd = NULL; struct block_list * target = NULL; - unsigned int tick = iTimer->gettick(); + int64 tick = timer->gettick(); int temp = 0, range; nullpo_ret(src); - if(status_isdead(src)) + if(status->isdead(src)) return 0; //Do not continue source is dead sd = BL_CAST(BL_PC, src); - ud = unit_bl2ud(src); + ud = unit->bl2ud(src); if(ud == NULL) return 0; - sc = status_get_sc(src); + sc = status->get_sc(src); if (sc && !sc->count) sc = NULL; //Unneeded //temp: used to signal combo-skills right now. - if (sc && sc->data[SC_COMBOATTACK] && (sc->data[SC_COMBOATTACK]->val1 == skill_id || - (sd?skill->check_condition_castbegin(sd,skill_id,skill_lv):0) )) { + if (sc && sc->data[SC_COMBOATTACK] + && skill->is_combo(skill_id) + && (sc->data[SC_COMBOATTACK]->val1 == skill_id + || ( sd?skill->check_condition_castbegin(sd,skill_id,skill_lv):0 ) + ) + ) { if (sc->data[SC_COMBOATTACK]->val2) target_id = sc->data[SC_COMBOATTACK]->val2; - else + else if( skill->get_inf(skill_id) != 1 ) // Only non-targetable skills should use auto target target_id = ud->target; if( skill->get_inf(skill_id)&INF_SELF_SKILL && skill->get_nk(skill_id)&NK_NO_DAMAGE )// exploit fix @@ -1095,8 +1088,8 @@ int unit_skilluse_id2(struct block_list *src, int target_id, uint16 skill_id, ui switch(skill_id) { //Check for skills that auto-select target case MO_CHAINCOMBO: - if (sc && sc->data[SC_BLADESTOP]){ - if ((target=iMap->id2bl(sc->data[SC_BLADESTOP]->val4)) == NULL) + if (sc && sc->data[SC_BLADESTOP]) { + if ((target=map->id2bl(sc->data[SC_BLADESTOP]->val4)) == NULL) return 0; } break; @@ -1104,7 +1097,7 @@ int unit_skilluse_id2(struct block_list *src, int target_id, uint16 skill_id, ui case WE_FEMALE: if (!sd->status.partner_id) return 0; - target = (struct block_list*)iMap->charid2sd(sd->status.partner_id); + target = (struct block_list*)map->charid2sd(sd->status.partner_id); if (!target) { clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); return 0; @@ -1127,12 +1120,12 @@ int unit_skilluse_id2(struct block_list *src, int target_id, uint16 skill_id, ui } if( !target ) // choose default target - target = iMap->id2bl(target_id); + target = map->id2bl(target_id); if( !target || src->m != target->m || !src->prev || !target->prev ) return 0; - if( battle_config.ksprotection && sd && mob_ksprotected(src, target) ) + if( battle_config.ksprotection && sd && mob->ksprotected(src, target) ) return 0; //Normally not needed because clif.c checks for it, but the at/char/script commands don't! [Skotlex] @@ -1142,17 +1135,17 @@ int unit_skilluse_id2(struct block_list *src, int target_id, uint16 skill_id, ui if(skill->get_inf2(skill_id)&INF2_NO_TARGET_SELF && src->id == target_id) return 0; - if(!status_check_skilluse(src, target, skill_id, 0)) + if(!status->check_skilluse(src, target, skill_id, 0)) return 0; - tstatus = status_get_status_data(target); + tstatus = status->get_status_data(target); // Record the status of the previous skill) if(sd) { if( (skill->get_inf2(skill_id)&INF2_ENSEMBLE_SKILL) && skill->check_pc_partner(sd, skill_id, &skill_lv, 1, 0) < 1 ) { clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); - return 0; - } + return 0; + } switch(skill_id){ case SA_CASTCANCEL: @@ -1209,7 +1202,7 @@ int unit_skilluse_id2(struct block_list *src, int target_id, uint16 skill_id, ui //(these are supposed to always have the same range as your attack) if( src->id != target_id && (!temp || ud->attacktimer == INVALID_TIMER) ) { if( skill->get_state(ud->skill_id) == ST_MOVE_ENABLE ) { - if( !unit_can_reach_bl(src, target, range + 1, 1, NULL, NULL) ) + if( !unit->can_reach_bl(src, target, range + 1, 1, NULL, NULL) ) return 0; // Walk-path check failed. } else if( src->type == BL_MER && skill_id == MA_REMOVETRAP ) { if( !battle->check_range(battle->get_master(src), target, range + 1) ) @@ -1220,8 +1213,8 @@ int unit_skilluse_id2(struct block_list *src, int target_id, uint16 skill_id, ui } if (!temp) //Stop attack on non-combo skills [Skotlex] - unit_stop_attack(src); - else if(ud->attacktimer != INVALID_TIMER) //Elsewise, delay current attack sequence + unit->stop_attack(src); + else if(ud->attacktimer != INVALID_TIMER) //Else-wise, delay current attack sequence ud->attackabletime = tick + status_get_adelay(src); ud->state.skillcastcancel = castcancel; @@ -1233,7 +1226,7 @@ int unit_skilluse_id2(struct block_list *src, int target_id, uint16 skill_id, ui case ALL_RESURRECTION: if(battle->check_undead(tstatus->race,tstatus->def_ele)) { temp = 1; - } else if (!status_isdead(target)) + } else if (!status->isdead(target)) return 0; //Can't cast on non-dead characters. break; case MO_FINGEROFFENSIVE: @@ -1302,6 +1295,13 @@ int unit_skilluse_id2(struct block_list *src, int target_id, uint16 skill_id, ui } } break; + case NC_DISJOINT: + if( target->type == BL_PC ){ + struct mob_data *md; + if( (md = map->id2md(target->id)) && md->master_id != src->id ) + casttime <<= 1; + } + break; } // moved here to prevent Suffragium from ending if skill fails @@ -1316,17 +1316,30 @@ int unit_skilluse_id2(struct block_list *src, int target_id, uint16 skill_id, ui casttime = 0; } + if( sc ) { + /** + * why the if else chain: these 3 status do not stack, so its efficient that way. + **/ + if( sc->data[SC_CLOAKING] && !(sc->data[SC_CLOAKING]->val4&4) && skill_id != AS_CLOAKING ) { + status_change_end(src, SC_CLOAKING, INVALID_TIMER); + if (!src->prev) return 0; //Warped away! + } else if( sc->data[SC_CLOAKINGEXCEED] && !(sc->data[SC_CLOAKINGEXCEED]->val4&4) && skill_id != GC_CLOAKINGEXCEED ) { + status_change_end(src,SC_CLOAKINGEXCEED, INVALID_TIMER); + if (!src->prev) return 0; + } + } + if(!ud->state.running) //need TK_RUN or WUGDASH handler to be done before that, see bugreport:6026 - unit_stop_walking(src,1);// eventhough this is not how official works but this will do the trick. bugreport:6829 + unit->stop_walking(src,1);// even though this is not how official works but this will do the trick. bugreport:6829 // in official this is triggered even if no cast time. clif->skillcasting(src, src->id, target_id, 0,0, skill_id, skill->get_ele(skill_id, skill_lv), casttime); if( casttime > 0 || temp ) - { + { if (sd && target->type == BL_MOB) { TBL_MOB *md = (TBL_MOB*)target; - mobskill_event(md, src, tick, -1); //Cast targetted skill event. + mob->skill_event(md, src, tick, -1); //Cast targeted skill event. if (tstatus->mode&(MD_CASTSENSOR_IDLE|MD_CASTSENSOR_CHASE) && battle->check_target(target, src, BCT_ENEMY) > 0) { @@ -1372,22 +1385,8 @@ int unit_skilluse_id2(struct block_list *src, int target_id, uint16 skill_id, ui ud->skill_id = skill_id; ud->skill_lv = skill_lv; - if( sc ) { - /** - * why the if else chain: these 3 status do not stack, so its efficient that way. - **/ - if( sc->data[SC_CLOAKING] && !(sc->data[SC_CLOAKING]->val4&4) && skill_id != AS_CLOAKING ) { - status_change_end(src, SC_CLOAKING, INVALID_TIMER); - if (!src->prev) return 0; //Warped away! - } else if( sc->data[SC_CLOAKINGEXCEED] && !(sc->data[SC_CLOAKINGEXCEED]->val4&4) && skill_id != GC_CLOAKINGEXCEED ) { - status_change_end(src,SC_CLOAKINGEXCEED, INVALID_TIMER); - if (!src->prev) return 0; - } - } - - if( casttime > 0 ) { - ud->skilltimer = iTimer->add_timer( tick+casttime, skill->castend_id, src->id, 0 ); + ud->skilltimer = timer->add( tick+casttime, skill->castend_id, src->id, 0 ); if( sd && (pc->checkskill(sd,SA_FREECAST) > 0 || skill_id == LG_EXEEDBREAK) ) status_calc_bl(&sd->bl, SCB_SPEED); } else @@ -1398,7 +1397,7 @@ int unit_skilluse_id2(struct block_list *src, int target_id, uint16 skill_id, ui int unit_skilluse_pos(struct block_list *src, short skill_x, short skill_y, uint16 skill_id, uint16 skill_lv) { - return unit_skilluse_pos2( + return unit->skilluse_pos2( src, skill_x, skill_y, skill_id, skill_lv, skill->cast_fix(src, skill_id, skill_lv), skill->get_castcancel(skill_id) @@ -1411,22 +1410,22 @@ int unit_skilluse_pos2( struct block_list *src, short skill_x, short skill_y, ui struct unit_data *ud = NULL; struct status_change *sc; struct block_list bl; - unsigned int tick = iTimer->gettick(); + int64 tick = timer->gettick(); int range; nullpo_ret(src); if (!src->prev) return 0; // not on the map - if(status_isdead(src)) return 0; + if(status->isdead(src)) return 0; sd = BL_CAST(BL_PC, src); - ud = unit_bl2ud(src); + ud = unit->bl2ud(src); if(ud == NULL) return 0; if(ud->skilltimer != INVALID_TIMER) //Normally not needed since clif.c checks for it, but at/char/script commands don't! [Skotlex] return 0; - sc = status_get_sc(src); + sc = status->get_sc(src); if (sc && !sc->count) sc = NULL; @@ -1435,20 +1434,20 @@ int unit_skilluse_pos2( struct block_list *src, short skill_x, short skill_y, ui if( skill->not_ok(skill_id, sd) || !skill->check_condition_castbegin(sd, skill_id, skill_lv) ) return 0; /** - * "WHY IS IT HEREE": pneuma cannot be cancelled past this point, the client displays the animation even, + * "WHY IS IT HEREE": pneuma cannot be canceled past this point, the client displays the animation even, * if we cancel it from nodamage_id, so it has to be here for it to not display the animation. **/ - if( skill_id == AL_PNEUMA && iMap->getcell(src->m, skill_x, skill_y, CELL_CHKLANDPROTECTOR) ) { + if( skill_id == AL_PNEUMA && map->getcell(src->m, skill_x, skill_y, CELL_CHKLANDPROTECTOR) ) { clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); return 0; } } - if (!status_check_skilluse(src, NULL, skill_id, 0)) + if (!status->check_skilluse(src, NULL, skill_id, 0)) return 0; - if( iMap->getcell(src->m, skill_x, skill_y, CELL_CHKWALL) ) - {// can't cast ground targeted spells on wall cells + if( map->getcell(src->m, skill_x, skill_y, CELL_CHKWALL) ) { + // can't cast ground targeted spells on wall cells if (sd) clif->skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); return 0; } @@ -1465,12 +1464,12 @@ int unit_skilluse_pos2( struct block_list *src, short skill_x, short skill_y, ui range = skill->get_range2(src, skill_id, skill_lv); // Skill cast distance from database if( skill->get_state(ud->skill_id) == ST_MOVE_ENABLE ) { - if( !unit_can_reach_bl(src, &bl, range + 1, 1, NULL, NULL) ) + if( !unit->can_reach_bl(src, &bl, range + 1, 1, NULL, NULL) ) return 0; //Walk-path check failed. } else if( !battle->check_range(src, &bl, range + 1) ) return 0; //Arrow-path check failed. - unit_stop_attack(src); + unit->stop_attack(src); // moved here to prevent Suffragium from ending if skill fails #ifndef RENEWAL_CAST @@ -1514,13 +1513,13 @@ int unit_skilluse_pos2( struct block_list *src, short skill_x, short skill_y, ui } } - unit_stop_walking(src,1); + unit->stop_walking(src,1); // in official this is triggered even if no cast time. clif->skillcasting(src, src->id, 0, skill_x, skill_y, skill_id, skill->get_ele(skill_id, skill_lv), casttime); if( casttime > 0 ) { - ud->skilltimer = iTimer->add_timer( tick+casttime, skill->castend_pos, src->id, 0 ); + ud->skilltimer = timer->add( tick+casttime, skill->castend_pos, src->id, 0 ); if( (sd && pc->checkskill(sd,SA_FREECAST) > 0) || skill_id == LG_EXEEDBREAK) - status_calc_bl(&sd->bl, SCB_SPEED); + status_calc_bl(&sd->bl, SCB_SPEED); } else { ud->skilltimer = INVALID_TIMER; skill->castend_pos(ud->skilltimer,tick,src->id,0); @@ -1539,9 +1538,9 @@ int unit_set_target(struct unit_data* ud, int target_id) nullpo_ret(ud); if( ud->target != target_id ) { - if( ud->target && (target = iMap->id2bl(ud->target)) && (ux = unit_bl2ud(target)) && ux->target_count > 0 ) + if( ud->target && (target = map->id2bl(ud->target)) && (ux = unit->bl2ud(target)) && ux->target_count > 0 ) ux->target_count --; - if( target_id && (target = iMap->id2bl(target_id)) && (ux = unit_bl2ud(target)) ) + if( target_id && (target = map->id2bl(target_id)) && (ux = unit->bl2ud(target)) ) ux->target_count ++; } @@ -1551,31 +1550,31 @@ int unit_set_target(struct unit_data* ud, int target_id) int unit_stop_attack(struct block_list *bl) { - struct unit_data *ud = unit_bl2ud(bl); + struct unit_data *ud = unit->bl2ud(bl); nullpo_ret(bl); if(!ud || ud->attacktimer == INVALID_TIMER) return 0; - iTimer->delete_timer( ud->attacktimer, unit_attack_timer ); + timer->delete( ud->attacktimer, unit->attack_timer ); ud->attacktimer = INVALID_TIMER; - unit_set_target(ud, 0); + unit->set_target(ud, 0); return 0; } //Means current target is unattackable. For now only unlocks mobs. int unit_unattackable(struct block_list *bl) { - struct unit_data *ud = unit_bl2ud(bl); + struct unit_data *ud = unit->bl2ud(bl); if (ud) { ud->state.attack_continue = 0; - unit_set_target(ud, 0); + unit->set_target(ud, 0); } if(bl->type == BL_MOB) - mob_unlocktarget((struct mob_data*)bl, iTimer->gettick()) ; + mob->unlocktarget((struct mob_data*)bl, timer->gettick()) ; else if(bl->type == BL_PET) - pet_unlocktarget((struct pet_data*)bl); + pet->unlocktarget((struct pet_data*)bl); return 0; } @@ -1583,38 +1582,41 @@ int unit_unattackable(struct block_list *bl) * Attack request * If type is an ongoing attack *------------------------------------------*/ -int unit_attack(struct block_list *src,int target_id,int continuous) -{ +int unit_attack(struct block_list *src,int target_id,int continuous) { struct block_list *target; struct unit_data *ud; - nullpo_ret(ud = unit_bl2ud(src)); + nullpo_ret(ud = unit->bl2ud(src)); - target = iMap->id2bl(target_id); - if( target==NULL || status_isdead(target) ) { - unit_unattackable(src); + target = map->id2bl(target_id); + if( target==NULL || status->isdead(target) ) { + unit->unattackable(src); return 1; } if( src->type == BL_PC ) { TBL_PC* sd = (TBL_PC*)src; if( target->type == BL_NPC ) { // monster npcs [Valaris] - npc_click(sd,(TBL_NPC*)target); // submitted by leinsirk10 [Celest] + npc->click(sd,(TBL_NPC*)target); // submitted by leinsirk10 [Celest] return 0; } if( pc_is90overweight(sd) || pc_isridingwug(sd) ) { // overweight or mounted on warg - stop attacking - unit_stop_attack(src); + unit->stop_attack(src); + return 0; + } + if( !pc->can_attack(sd, target_id) ) { + unit->stop_attack(src); return 0; } } - if( battle->check_target(src,target,BCT_ENEMY) <= 0 || !status_check_skilluse(src, target, 0, 0) ) { - unit_unattackable(src); + if( battle->check_target(src,target,BCT_ENEMY) <= 0 || !status->check_skilluse(src, target, 0, 0) ) { + unit->unattackable(src); return 1; } ud->state.attack_continue = continuous; - unit_set_target(ud, target_id); + unit->set_target(ud, target_id); - if (continuous) //If you're to attack continously, set to auto-case character + if (continuous) //If you're to attack continuously, set to auto-case character ud->chaserange = status_get_range(src); //Just change target/type. [Skotlex] @@ -1625,11 +1627,11 @@ int unit_attack(struct block_list *src,int target_id,int continuous) if(src->type == BL_MOB) ((TBL_MOB*)src)->state.skillstate = ((TBL_MOB*)src)->state.aggressive?MSS_ANGRY:MSS_BERSERK; - if(DIFF_TICK(ud->attackabletime, iTimer->gettick()) > 0) + if(DIFF_TICK(ud->attackabletime, timer->gettick()) > 0) //Do attack next time it is possible. [Skotlex] - ud->attacktimer=iTimer->add_timer(ud->attackabletime,unit_attack_timer,src->id,0); + ud->attacktimer=timer->add(ud->attackabletime,unit->attack_timer,src->id,0); else //Attack NOW. - unit_attack_timer(INVALID_TIMER, iTimer->gettick(), src->id, 0); + unit->attack_timer(INVALID_TIMER, timer->gettick(), src->id, 0); return 0; } @@ -1643,16 +1645,16 @@ int unit_cancel_combo(struct block_list *bl) if (!status_change_end(bl, SC_COMBOATTACK, INVALID_TIMER)) return 0; //Combo wasn't active. - ud = unit_bl2ud(bl); + ud = unit->bl2ud(bl); nullpo_ret(ud); - ud->attackabletime = iTimer->gettick() + status_get_amotion(bl); + ud->attackabletime = timer->gettick() + status_get_amotion(bl); if (ud->attacktimer == INVALID_TIMER) return 1; //Nothing more to do. - iTimer->delete_timer(ud->attacktimer, unit_attack_timer); - ud->attacktimer=iTimer->add_timer(ud->attackabletime,unit_attack_timer,bl->id,0); + timer->delete(ud->attacktimer, unit->attack_timer); + ud->attacktimer=timer->add(ud->attackabletime,unit->attack_timer,bl->id,0); return 1; } /*========================================== @@ -1665,7 +1667,7 @@ bool unit_can_reach_pos(struct block_list *bl,int x,int y, int easy) if (bl->x == x && bl->y == y) //Same place return true; - return path_search(NULL,bl->m,bl->x,bl->y,x,y,easy,CELL_CHKNOREACH); + return path->search(NULL,bl->m,bl->x,bl->y,x,y,easy,CELL_CHKNOREACH); } /*========================================== @@ -1693,9 +1695,9 @@ bool unit_can_reach_bl(struct block_list *bl,struct block_list *tbl, int range, dx=(dx>0)?1:((dx<0)?-1:0); dy=(dy>0)?1:((dy<0)?-1:0); - if (iMap->getcell(tbl->m,tbl->x-dx,tbl->y-dy,CELL_CHKNOPASS)) - { //Look for a suitable cell to place in. - for(i=0;i<9 && iMap->getcell(tbl->m,tbl->x-dirx[i],tbl->y-diry[i],CELL_CHKNOPASS);i++); + if (map->getcell(tbl->m,tbl->x-dx,tbl->y-dy,CELL_CHKNOPASS)) { + //Look for a suitable cell to place in. + for(i=0;i<9 && map->getcell(tbl->m,tbl->x-dirx[i],tbl->y-diry[i],CELL_CHKNOPASS);i++); if (i==9) return false; //No valid cells. dx = dirx[i]; dy = diry[i]; @@ -1703,7 +1705,7 @@ bool unit_can_reach_bl(struct block_list *bl,struct block_list *tbl, int range, if (x) *x = tbl->x-dx; if (y) *y = tbl->y-dy; - return path_search(NULL,bl->m,bl->x,bl->y,tbl->x-dx,tbl->y-dy,easy,CELL_CHKNOREACH); + return path->search(NULL,bl->m,bl->x,bl->y,tbl->x-dx,tbl->y-dy,easy,CELL_CHKNOREACH); } /*========================================== * Calculates position of Pet/Mercenary/Homunculus/Elemental @@ -1711,7 +1713,7 @@ bool unit_can_reach_bl(struct block_list *bl,struct block_list *tbl, int range, int unit_calc_pos(struct block_list *bl, int tx, int ty, uint8 dir) { int dx, dy, x, y, i, k; - struct unit_data *ud = unit_bl2ud(bl); + struct unit_data *ud = unit->bl2ud(bl); nullpo_ret(ud); if(dir > 7) @@ -1726,11 +1728,11 @@ int unit_calc_pos(struct block_list *bl, int tx, int ty, uint8 dir) x = tx + dx; y = ty + dy; - if( !unit_can_reach_pos(bl, x, y, 0) ) + if( !unit->can_reach_pos(bl, x, y, 0) ) { if( dx > 0 ) x--; else if( dx < 0 ) x++; if( dy > 0 ) y--; else if( dy < 0 ) y++; - if( !unit_can_reach_pos(bl, x, y, 0) ) + if( !unit->can_reach_pos(bl, x, y, 0) ) { for( i = 0; i < 12; i++ ) { @@ -1739,20 +1741,20 @@ int unit_calc_pos(struct block_list *bl, int tx, int ty, uint8 dir) dy = -diry[k] * 2; x = tx + dx; y = ty + dy; - if( unit_can_reach_pos(bl, x, y, 0) ) + if( unit->can_reach_pos(bl, x, y, 0) ) break; else { if( dx > 0 ) x--; else if( dx < 0 ) x++; if( dy > 0 ) y--; else if( dy < 0 ) y++; - if( unit_can_reach_pos(bl, x, y, 0) ) + if( unit->can_reach_pos(bl, x, y, 0) ) break; } } if( i == 12 ) { x = tx; y = tx; // Exactly Master Position - if( !unit_can_reach_pos(bl, x, y, 0) ) + if( !unit->can_reach_pos(bl, x, y, 0) ) return 1; } } @@ -1766,8 +1768,7 @@ int unit_calc_pos(struct block_list *bl, int tx, int ty, uint8 dir) /*========================================== * Continuous Attack (function timer) *------------------------------------------*/ -static int unit_attack_timer_sub(struct block_list* src, int tid, unsigned int tick) -{ +int unit_attack_timer_sub(struct block_list* src, int tid, int64 tick) { struct block_list *target; struct unit_data *ud; struct status_data *sstatus; @@ -1775,7 +1776,7 @@ static int unit_attack_timer_sub(struct block_list* src, int tid, unsigned int t struct mob_data *md = NULL; int range; - if( (ud=unit_bl2ud(src))==NULL ) + if( (ud=unit->bl2ud(src))==NULL ) return 0; if( ud->attacktimer != tid ) { @@ -1786,22 +1787,23 @@ static int unit_attack_timer_sub(struct block_list* src, int tid, unsigned int t sd = BL_CAST(BL_PC, src); md = BL_CAST(BL_MOB, src); ud->attacktimer = INVALID_TIMER; - target=iMap->id2bl(ud->target); + target=map->id2bl(ud->target); if( src == NULL || src->prev == NULL || target==NULL || target->prev == NULL ) return 0; - if( status_isdead(src) || status_isdead(target) || - battle->check_target(src,target,BCT_ENEMY) <= 0 || !status_check_skilluse(src, target, 0, 0) + if( status->isdead(src) || status->isdead(target) + || battle->check_target(src,target,BCT_ENEMY) <= 0 || !status->check_skilluse(src, target, 0, 0) #ifdef OFFICIAL_WALKPATH - || !path_search_long(NULL, src->m, src->x, src->y, target->x, target->y, CELL_CHKWALL) + || !path->search_long(NULL, src->m, src->x, src->y, target->x, target->y, CELL_CHKWALL) #endif - ) + || (sd && !pc->can_attack(sd, ud->target) ) + ) return 0; // can't attack under these conditions if( src->m != target->m ) { - if( src->type == BL_MOB && mob_warpchase((TBL_MOB*)src, target) ) + if( src->type == BL_MOB && mob->warpchase((TBL_MOB*)src, target) ) return 1; // Follow up. return 0; } @@ -1811,38 +1813,36 @@ static int unit_attack_timer_sub(struct block_list* src, int tid, unsigned int t if( !battle_config.sdelay_attack_enable && DIFF_TICK(ud->canact_tick,tick) > 0 && !(sd && pc->checkskill(sd,SA_FREECAST) > 0) ) { // attacking when under cast delay has restrictions: - if( tid == INVALID_TIMER ) - { //requested attack. + if( tid == INVALID_TIMER ) { //requested attack. if(sd) clif->skill_fail(sd,1,USESKILL_FAIL_SKILLINTERVAL,0); return 0; } //Otherwise, we are in a combo-attack, delay this until your canact time is over. [Skotlex] - if( ud->state.attack_continue ) - { + if( ud->state.attack_continue ) { if( DIFF_TICK(ud->canact_tick, ud->attackabletime) > 0 ) ud->attackabletime = ud->canact_tick; - ud->attacktimer=iTimer->add_timer(ud->attackabletime,unit_attack_timer,src->id,0); + ud->attacktimer=timer->add(ud->attackabletime,unit->attack_timer,src->id,0); } return 1; } - sstatus = status_get_status_data(src); + sstatus = status->get_status_data(src); range = sstatus->rhw.range + 1; - if( unit_is_walking(target) ) + if( unit->is_walking(target) ) range++; //Extra range when chasing if( !check_distance_bl(src,target,range) ) { //Chase if required. if(sd) clif->movetoattack(sd,target); else if(ud->state.attack_continue) - unit_walktobl(src,target,ud->chaserange,ud->state.walk_easy|2); + unit->walktobl(src,target,ud->chaserange,ud->state.walk_easy|2); return 1; } if( !battle->check_range(src,target,range) ) { - //Within range, but no direct line of attack + //Within range, but no direct line of attack if( ud->state.attack_continue ) { if(ud->chaserange > 2) ud->chaserange-=2; - unit_walktobl(src,target,ud->chaserange,ud->state.walk_easy|2); + unit->walktobl(src,target,ud->chaserange,ud->state.walk_easy|2); } return 1; } @@ -1850,31 +1850,30 @@ static int unit_attack_timer_sub(struct block_list* src, int tid, unsigned int t //Non-players use the sync packet on the walk timer. [Skotlex] if (tid == INVALID_TIMER && sd) clif->fixpos(src); - if( DIFF_TICK(ud->attackabletime,tick) <= 0 ) - { + if( DIFF_TICK(ud->attackabletime,tick) <= 0 ) { if (battle_config.attack_direction_change && (src->type&battle_config.attack_direction_change)) { - ud->dir = iMap->calc_dir(src, target->x,target->y ); + ud->dir = map->calc_dir(src, target->x,target->y ); } if(ud->walktimer != INVALID_TIMER) - unit_stop_walking(src,1); + unit->stop_walking(src,1); if(md) { - if (mobskill_use(md,tick,-1)) + if (mob->skill_use(md,tick,-1)) return 1; if (sstatus->mode&MD_ASSIST && DIFF_TICK(md->last_linktime, tick) < MIN_MOBLINKTIME) { // Link monsters nearby [Skotlex] md->last_linktime = tick; - iMap->foreachinrange(mob_linksearch, src, md->db->range2, BL_MOB, md->class_, target, tick); + map->foreachinrange(mob->linksearch, src, md->db->range2, BL_MOB, md->class_, target, tick); } } - if(src->type == BL_PET && pet_attackskill((TBL_PET*)src, target->id)) + if(src->type == BL_PET && pet->attackskill((TBL_PET*)src, target->id)) return 1; - iMap->freeblock_lock(); + map->freeblock_lock(); ud->attacktarget_lv = battle->weapon_attack(src,target,tick,0); if(sd && sd->status.pet_id > 0 && sd->pd && battle_config.pet_attack_support) - pet_target_check(sd,target,0); - iMap->freeblock_unlock(); + pet->target_check(sd,target,0); + map->freeblock_unlock(); /** * Applied when you're unable to attack (e.g. out of ammo) * We should stop here otherwise timer keeps on and this happens endlessly @@ -1885,34 +1884,36 @@ static int unit_attack_timer_sub(struct block_list* src, int tid, unsigned int t ud->attackabletime = tick + sstatus->adelay; // You can't move if you can't attack neither. if (src->type&battle_config.attack_walk_delay) - unit_set_walkdelay(src, tick, sstatus->amotion, 1); + unit->set_walkdelay(src, tick, sstatus->amotion, 1); } - if(ud->state.attack_continue) - ud->attacktimer = iTimer->add_timer(ud->attackabletime,unit_attack_timer,src->id,0); + if(ud->state.attack_continue) { + if( src->type == BL_PC && battle_config.idletime_criteria & BCIDLE_ATTACK ) + ((TBL_PC*)src)->idletime = sockt->last_tick; + ud->attacktimer = timer->add(ud->attackabletime,unit->attack_timer,src->id,0); + } return 1; } -static int unit_attack_timer(int tid, unsigned int tick, int id, intptr_t data) -{ +int unit_attack_timer(int tid, int64 tick, int id, intptr_t data) { struct block_list *bl; - bl = iMap->id2bl(id); - if(bl && unit_attack_timer_sub(bl, tid, tick) == 0) - unit_unattackable(bl); + bl = map->id2bl(id); + if(bl && unit->attack_timer_sub(bl, tid, tick) == 0) + unit->unattackable(bl); return 0; } /*========================================== * Cancels an ongoing skill cast. * flag&1: Cast-Cancel invoked. - * flag&2: Cancel only if skill is cancellable. + * flag&2: Cancel only if skill is can be cancel. *------------------------------------------*/ int unit_skillcastcancel(struct block_list *bl,int type) { struct map_session_data *sd = NULL; - struct unit_data *ud = unit_bl2ud( bl); - unsigned int tick=iTimer->gettick(); + struct unit_data *ud = unit->bl2ud( bl); + int64 tick = timer->gettick(); int ret=0, skill_id; nullpo_ret(bl); @@ -1922,12 +1923,12 @@ int unit_skillcastcancel(struct block_list *bl,int type) sd = BL_CAST(BL_PC, bl); if (type&2) { - //See if it can be cancelled. + //See if it can be canceled. if (!ud->state.skillcastcancel) return 0; if (sd && (sd->special_state.no_castcancel2 || - ((sd->sc.data[SC_UNLIMITED_HUMMING_VOICE] || sd->special_state.no_castcancel) && !map_flag_gvg(bl->m) && !map[bl->m].flag.battleground))) //fixed flags being read the wrong way around [blackhole89] + ( sd->special_state.no_castcancel && !map_flag_gvg(bl->m) && !map->list[bl->m].flag.battleground))) //fixed flags being read the wrong way around [blackhole89] return 0; } @@ -1939,11 +1940,11 @@ int unit_skillcastcancel(struct block_list *bl,int type) skill_id = ud->skill_id; if (skill->get_inf(skill_id) & INF_GROUND_SKILL) - ret = iTimer->delete_timer( ud->skilltimer, skill->castend_pos ); + ret = timer->delete( ud->skilltimer, skill->castend_pos ); else - ret = iTimer->delete_timer( ud->skilltimer, skill->castend_id ); + ret = timer->delete( ud->skilltimer, skill->castend_id ); if( ret < 0 ) - ShowError("delete timer error : skill_id : %d\n",ret); + ShowError("delete timer error %d : skill %d (%s)\n",ret,skill_id,skill->get_name(skill_id)); ud->skilltimer = INVALID_TIMER; @@ -1967,7 +1968,7 @@ 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)); + nullpo_retv(ud = unit->bl2ud(bl)); memset( ud, 0, sizeof( struct unit_data) ); ud->bl = bl; @@ -1976,7 +1977,7 @@ void unit_dataset(struct block_list *bl) { ud->attacktimer = INVALID_TIMER; ud->attackabletime = ud->canact_tick = - ud->canmove_tick = iTimer->gettick(); + ud->canmove_tick = timer->gettick(); } /*========================================== @@ -1985,7 +1986,7 @@ void unit_dataset(struct block_list *bl) { int unit_counttargeted(struct block_list* bl) { struct unit_data* ud; - if( bl && (ud = unit_bl2ud(bl)) ) + if( bl && (ud = unit->bl2ud(bl)) ) return ud->target_count; return 0; } @@ -1993,14 +1994,13 @@ int unit_counttargeted(struct block_list* bl) /*========================================== * *------------------------------------------*/ -int unit_fixdamage(struct block_list *src,struct block_list *target,unsigned int tick,int sdelay,int ddelay,int damage,int div,int type,int damage2) -{ +int unit_fixdamage(struct block_list *src, struct block_list *target, int sdelay, int ddelay, int64 damage, short div, unsigned char type, int64 damage2) { nullpo_ret(target); if(damage+damage2 <= 0) return 0; - return status_fix_damage(src,target,damage+damage2,clif->damage(target,target,tick,sdelay,ddelay,damage,div,type,damage2)); + return status_fix_damage(src,target,damage+damage2,clif->damage(target,target,sdelay,ddelay,damage,div,type,damage2)); } /*========================================== @@ -2026,32 +2026,31 @@ int unit_changeviewsize(struct block_list *bl,short size) /*========================================== * Removes a bl/ud from the map. * Returns 1 on success. 0 if it couldn't be removed or the bl was free'd - * if clrtype is 1 (death), appropiate cleanup is performed. + * if clrtype is 1 (death), appropriate cleanup is performed. * Otherwise it is assumed bl is being warped. - * On-Kill specific stuff is not performed here, look at status_damage for that. + * On-Kill specific stuff is not performed here, look at status->damage for that. *------------------------------------------*/ -int unit_remove_map_(struct block_list *bl, clr_type clrtype, const char* file, int line, const char* func) -{ - struct unit_data *ud = unit_bl2ud(bl); - struct status_change *sc = status_get_sc(bl); +int unit_remove_map(struct block_list *bl, clr_type clrtype, const char* file, int line, const char* func) { + struct unit_data *ud = unit->bl2ud(bl); + struct status_change *sc = status->get_sc(bl); nullpo_ret(ud); if(bl->prev == NULL) return 0; //Already removed? - iMap->freeblock_lock(); + map->freeblock_lock(); - unit_set_target(ud, 0); + unit->set_target(ud, 0); if (ud->walktimer != INVALID_TIMER) - unit_stop_walking(bl,0); + unit->stop_walking(bl,0); if (ud->attacktimer != INVALID_TIMER) - unit_stop_attack(bl); + unit->stop_attack(bl); if (ud->skilltimer != INVALID_TIMER) - unit_skillcastcancel(bl,0); + unit->skillcastcancel(bl,0); // Do not reset can-act delay. [Skotlex] - ud->attackabletime = ud->canmove_tick /*= ud->canact_tick*/ = iTimer->gettick(); + ud->attackabletime = ud->canmove_tick /*= ud->canact_tick*/ = timer->gettick(); if(sc && sc->count ) { //map-change/warp dispells. status_change_end(bl, SC_BLADESTOP, INVALID_TIMER); status_change_end(bl, SC_BASILICA, INVALID_TIMER); @@ -2068,8 +2067,7 @@ int unit_remove_map_(struct block_list *bl, clr_type clrtype, const char* file, status_change_end(bl, SC_RG_CCONFINE_S, INVALID_TIMER); status_change_end(bl, SC_HIDING, INVALID_TIMER); // Ensure the bl is a PC; if so, we'll handle the removal of cloaking and cloaking exceed later - if ( bl->type != BL_PC ) - { + if ( bl->type != BL_PC ) { status_change_end(bl, SC_CLOAKING, INVALID_TIMER); status_change_end(bl, SC_CLOAKINGEXCEED, INVALID_TIMER); } @@ -2080,6 +2078,11 @@ int unit_remove_map_(struct block_list *bl, clr_type clrtype, const char* file, status_change_end(bl, SC_STOP, INVALID_TIMER); status_change_end(bl, SC_WUGDASH, INVALID_TIMER); status_change_end(bl, SC_CAMOUFLAGE, INVALID_TIMER); + status_change_end(bl, SC_MAGNETICFIELD, INVALID_TIMER); + status_change_end(bl, SC_NEUTRALBARRIER_MASTER, INVALID_TIMER); + status_change_end(bl, SC_NEUTRALBARRIER, INVALID_TIMER); + status_change_end(bl, SC_STEALTHFIELD_MASTER, INVALID_TIMER); + status_change_end(bl, SC_STEALTHFIELD, INVALID_TIMER); status_change_end(bl, SC__SHADOWFORM, INVALID_TIMER); status_change_end(bl, SC__MANHOLE, INVALID_TIMER); status_change_end(bl, SC_VACUUM_EXTREME, INVALID_TIMER); @@ -2087,7 +2090,7 @@ int unit_remove_map_(struct block_list *bl, clr_type clrtype, const char* file, } if (bl->type&(BL_CHAR|BL_PET)) { - skill->unit_move(bl,iTimer->gettick(),4); + skill->unit_move(bl,timer->gettick(),4); skill->cleartimerskill(bl); } @@ -2095,23 +2098,26 @@ int unit_remove_map_(struct block_list *bl, clr_type clrtype, const char* file, case BL_PC: { struct map_session_data *sd = (struct map_session_data*)bl; - if(sd->shadowform_id){ - struct block_list *d_bl = iMap->id2bl(sd->shadowform_id); - if( d_bl ) - status_change_end(d_bl,SC__SHADOWFORM,INVALID_TIMER); + if(sd->shadowform_id) { + struct block_list *d_bl = map->id2bl(sd->shadowform_id); + if( d_bl ) + status_change_end(d_bl,SC__SHADOWFORM,INVALID_TIMER); } //Leave/reject all invitations. if(sd->chatID) - chat_leavechat(sd,0); + chat->leave(sd,0); if(sd->trade_partner) trade->cancel(sd); buyingstore->close(sd); searchstore->close(sd); - if(sd->state.storage_flag == 1) - storage_storage_quit(sd,0); - else if (sd->state.storage_flag == 2) - storage_guild_storage_quit(sd,0); - sd->state.storage_flag = 0; //Force close it when being warped. + if( sd->menuskill_id != AL_TELEPORT ) { // issue: 8027 + if(sd->state.storage_flag == 1) + storage->pc_quit(sd,0); + else if (sd->state.storage_flag == 2) + gstorage->pc_quit(sd,0); + + sd->state.storage_flag = 0; //Force close it when being warped. + } if(sd->party_invite>0) party->reply_invite(sd,sd->party_invite,0); if(sd->guild_invite>0) @@ -2121,7 +2127,7 @@ int unit_remove_map_(struct block_list *bl, clr_type clrtype, const char* file, if(sd->menuskill_id) sd->menuskill_id = sd->menuskill_val = 0; if( sd->touching_id ) - npc_touchnext_areanpc(sd,true); + npc->touchnext_areanpc(sd,true); // Check if warping and not changing the map. if ( sd->state.warping && !sd->state.changemap ) { @@ -2133,12 +2139,12 @@ int unit_remove_map_(struct block_list *bl, clr_type clrtype, const char* file, sd->adopt_invite = 0; if(sd->pvp_timer != INVALID_TIMER) { - iTimer->delete_timer(sd->pvp_timer,pc->calc_pvprank_timer); + timer->delete(sd->pvp_timer,pc->calc_pvprank_timer); sd->pvp_timer = INVALID_TIMER; sd->pvp_rank = 0; } if(sd->duel_group > 0) - duel_leave(sd->duel_group, sd); + duel->leave(sd->duel_group, sd); if(pc_issit(sd)) { pc->setstand(sd); @@ -2146,12 +2152,11 @@ int unit_remove_map_(struct block_list *bl, clr_type clrtype, const char* file, } party->send_dot_remove(sd);//minimap dot fix [Kevin] guild->send_dot_remove(sd); - bg_send_dot_remove(sd); + bg->send_dot_remove(sd); - if( map[bl->m].users <= 0 || sd->state.debug_remove_map ) - {// this is only place where map users is decreased, if the mobs were removed too soon then this function was executed too many times [FlavioJS] - if( sd->debug_file == NULL || !(sd->state.debug_remove_map) ) - { + if( map->list[bl->m].users <= 0 || sd->state.debug_remove_map ) { + // this is only place where map users is decreased, if the mobs were removed too soon then this function was executed too many times [FlavioJS] + if( sd->debug_file == NULL || !(sd->state.debug_remove_map) ) { sd->debug_file = ""; sd->debug_line = 0; sd->debug_func = ""; @@ -2163,17 +2168,21 @@ int unit_remove_map_(struct block_list *bl, clr_type clrtype, const char* file, " Please report this!!!\n", sd->status.account_id, sd->status.char_id, sd->state.active, sd->state.connect_new, sd->state.rewarp, sd->state.changemap, sd->state.debug_remove_map, - map[bl->m].name, map[bl->m].users, + map->list[bl->m].name, map->list[bl->m].users, sd->debug_file, sd->debug_line, sd->debug_func, file, line, func); - } else if (--map[bl->m].users == 0 && battle_config.dynamic_mobs) //[Skotlex] - iMap->removemobs(bl->m); - if( !(sd->sc.option&OPTION_INVISIBLE) ) - {// decrement the number of active pvp players on the map - --map[bl->m].users_pvp; + } else if (--map->list[bl->m].users == 0 && battle_config.dynamic_mobs) //[Skotlex] + map->removemobs(bl->m); + if( !(sd->sc.option&OPTION_INVISIBLE) ) { + // decrement the number of active pvp players on the map + --map->list[bl->m].users_pvp; + } + if( map->list[bl->m].instance_id >= 0 ) { + instance->list[map->list[bl->m].instance_id].users--; + instance->check_idle(map->list[bl->m].instance_id); } - if( map[bl->m].instance_id >= 0 ) { - instances[map[bl->m].instance_id].users--; - instance->check_idle(map[bl->m].instance_id); + if( sd->state.hpmeter_visible ) { + map->list[bl->m].hpmeter_visible--; + sd->state.hpmeter_visible = 0; } sd->state.debug_remove_map = 1; // temporary state to track double remove_map's [FlavioJS] sd->debug_file = file; @@ -2195,12 +2204,12 @@ int unit_remove_map_(struct block_list *bl, clr_type clrtype, const char* file, } case BL_PET: { struct pet_data *pd = (struct pet_data*)bl; - if( pd->pet.intimate <= 0 && !(pd->msd && !pd->msd->state.active) ) - { //If logging out, this is deleted on unit_free + if( pd->pet.intimate <= 0 && !(pd->msd && !pd->msd->state.active) ) { + //If logging out, this is deleted on unit->free clif->clearunit_area(bl,clrtype); - iMap->delblock(bl); - unit_free(bl,CLR_OUTSIGHT); - iMap->freeblock_unlock(); + map->delblock(bl); + unit->free(bl,CLR_OUTSIGHT); + map->freeblock_unlock(); return 0; } @@ -2208,14 +2217,13 @@ int unit_remove_map_(struct block_list *bl, clr_type clrtype, const char* file, } case BL_HOM: { struct homun_data *hd = (struct homun_data *)bl; - ud->canact_tick = ud->canmove_tick; //It appears HOM do reset the can-act tick. - if( !hd->homunculus.intimacy && !(hd->master && !hd->master->state.active) ) - { //If logging out, this is deleted on unit_free + if( !hd->homunculus.intimacy && !(hd->master && !hd->master->state.active) ) { + //If logging out, this is deleted on unit->free clif->emotion(bl, E_SOB); clif->clearunit_area(bl,clrtype); - iMap->delblock(bl); - unit_free(bl,CLR_OUTSIGHT); - iMap->freeblock_unlock(); + map->delblock(bl); + unit->free(bl,CLR_OUTSIGHT); + map->freeblock_unlock(); return 0; } break; @@ -2223,12 +2231,11 @@ int unit_remove_map_(struct block_list *bl, clr_type clrtype, const char* file, case BL_MER: { struct mercenary_data *md = (struct mercenary_data *)bl; ud->canact_tick = ud->canmove_tick; - if( mercenary_get_lifetime(md) <= 0 && !(md->master && !md->master->state.active) ) - { + if( mercenary->get_lifetime(md) <= 0 && !(md->master && !md->master->state.active) ) { clif->clearunit_area(bl,clrtype); - iMap->delblock(bl); - unit_free(bl,CLR_OUTSIGHT); - iMap->freeblock_unlock(); + map->delblock(bl); + unit->free(bl,CLR_OUTSIGHT); + map->freeblock_unlock(); return 0; } break; @@ -2236,12 +2243,11 @@ int unit_remove_map_(struct block_list *bl, clr_type clrtype, const char* file, case BL_ELEM: { struct elemental_data *ed = (struct elemental_data *)bl; ud->canact_tick = ud->canmove_tick; - if( elemental_get_lifetime(ed) <= 0 && !(ed->master && !ed->master->state.active) ) - { + if( elemental->get_lifetime(ed) <= 0 && !(ed->master && !ed->master->state.active) ) { clif->clearunit_area(bl,clrtype); - iMap->delblock(bl); - unit_free(bl,0); - iMap->freeblock_unlock(); + map->delblock(bl); + unit->free(bl,0); + map->freeblock_unlock(); return 0; } break; @@ -2251,58 +2257,61 @@ int unit_remove_map_(struct block_list *bl, clr_type clrtype, const char* file, /** * BL_MOB is handled by mob_dead unless the monster is not dead. **/ - if( bl->type != BL_MOB || !status_isdead(bl) ) + if( bl->type != BL_MOB || !status->isdead(bl) ) clif->clearunit_area(bl,clrtype); - iMap->delblock(bl); - iMap->freeblock_unlock(); + map->delblock(bl); + map->freeblock_unlock(); return 1; } void unit_remove_map_pc(struct map_session_data *sd, clr_type clrtype) { - unit_remove_map(&sd->bl,clrtype); - - if (clrtype == CLR_TELEPORT) clrtype = CLR_OUTSIGHT; //CLR_TELEPORT is the warp from logging out, but pets/homunc need to just 'vanish' instead of showing the warping out animation. - + unit->remove_map(&sd->bl,clrtype,ALC_MARK); + + //CLR_RESPAWN is the warp from logging out, CLR_TELEPORT is the warp from teleporting, but pets/homunc need to just 'vanish' instead of showing the warping animation. + if (clrtype == CLR_RESPAWN || clrtype == CLR_TELEPORT) clrtype = CLR_OUTSIGHT; + if(sd->pd) - unit_remove_map(&sd->pd->bl, clrtype); + unit->remove_map(&sd->pd->bl, clrtype, ALC_MARK); if(homun_alive(sd->hd)) - unit_remove_map(&sd->hd->bl, clrtype); + unit->remove_map(&sd->hd->bl, clrtype, ALC_MARK); if(sd->md) - unit_remove_map(&sd->md->bl, clrtype); + unit->remove_map(&sd->md->bl, clrtype, ALC_MARK); if(sd->ed) - unit_remove_map(&sd->ed->bl, clrtype); + unit->remove_map(&sd->ed->bl, clrtype, ALC_MARK); } void unit_free_pc(struct map_session_data *sd) { - if (sd->pd) unit_free(&sd->pd->bl,CLR_OUTSIGHT); - if (sd->hd) unit_free(&sd->hd->bl,CLR_OUTSIGHT); - if (sd->md) unit_free(&sd->md->bl,CLR_OUTSIGHT); - if (sd->ed) unit_free(&sd->ed->bl,CLR_OUTSIGHT); - unit_free(&sd->bl,CLR_TELEPORT); + if (sd->pd) unit->free(&sd->pd->bl,CLR_OUTSIGHT); + if (sd->hd) unit->free(&sd->hd->bl,CLR_OUTSIGHT); + if (sd->md) unit->free(&sd->md->bl,CLR_OUTSIGHT); + if (sd->ed) unit->free(&sd->ed->bl,CLR_OUTSIGHT); + unit->free(&sd->bl,CLR_TELEPORT); } /*========================================== * Function to free all related resources to the bl * if unit is on map, it is removed using the clrtype specified *------------------------------------------*/ -int unit_free(struct block_list *bl, clr_type clrtype) -{ - struct unit_data *ud = unit_bl2ud( bl ); +int unit_free(struct block_list *bl, clr_type clrtype) { + struct unit_data *ud = unit->bl2ud( bl ); nullpo_ret(ud); - iMap->freeblock_lock(); + map->freeblock_lock(); if( bl->prev ) //Players are supposed to logout with a "warp" effect. - unit_remove_map(bl, clrtype); + unit->remove_map(bl, clrtype, ALC_MARK); switch( bl->type ) { case BL_PC: { struct map_session_data *sd = (struct map_session_data*)bl; int i; + unsigned int k; - if( status_isdead(bl) ) + sd->state.loggingout = 1; + + if( status->isdead(bl) ) pc->setrestartvalue(sd,2); pc->delinvincibletimer(sd); @@ -2314,10 +2323,10 @@ int unit_free(struct block_list *bl, clr_type clrtype) pc->stop_following(sd); if( sd->duel_invite > 0 ) - duel_reject(sd->duel_invite, sd); + duel->reject(sd->duel_invite, sd); // Notify friends that this char logged out. [Skotlex] - iMap->map_foreachpc(clif->friendslist_toggle_sub, sd->status.account_id, sd->status.char_id, 0); + map->foreachpc(clif->friendslist_toggle_sub, sd->status.account_id, sd->status.char_id, 0); party->send_logout(sd); guild->send_memberinfoshort(sd,0); pc->cleareventtimer(sd); @@ -2326,33 +2335,20 @@ int unit_free(struct block_list *bl, clr_type clrtype) for(i = 1; i < 5; i++) pc->del_charm(sd, sd->charm[i], i); - if( sd->reg ) { //Double logout already freed pointer fix... [Skotlex] - aFree(sd->reg); - sd->reg = NULL; - sd->reg_num = 0; - } - if( sd->regstr ) { - for( i = 0; i < sd->regstr_num; ++i ) - if( sd->regstr[i].data ) - aFree(sd->regstr[i].data); - aFree(sd->regstr); - sd->regstr = NULL; - sd->regstr_num = 0; - } if( sd->st && sd->st->state != RUN ) {// free attached scripts that are waiting - script_free_state(sd->st); + script->free_state(sd->st); sd->st = NULL; sd->npc_id = 0; } - if( sd->combos.count ) { - aFree(sd->combos.bonus); - aFree(sd->combos.id); - sd->combos.count = 0; + if( sd->combos ) { + aFree(sd->combos); + sd->combos = NULL; } + sd->combo_count = 0; /* [Ind/Hercules] */ if( sd->sc_display_count ) { for(i = 0; i < sd->sc_display_count; i++) { - ers_free(pc_sc_display_ers, sd->sc_display[i]); + ers_free(pc->sc_display_ers, sd->sc_display[i]); } sd->sc_display_count = 0; } @@ -2368,13 +2364,27 @@ int unit_free(struct block_list *bl, clr_type clrtype) aFree(sd->queues); sd->queues = NULL; } + if( sd->quest_log != NULL ) { + aFree(sd->quest_log); + sd->quest_log = NULL; + sd->num_quests = sd->avail_quests = 0; + } + + for( k = 0; k < sd->hdatac; k++ ) { + if( sd->hdata[k]->flag.free ) { + aFree(sd->hdata[k]->data); + } + aFree(sd->hdata[k]); + } + if( sd->hdata ) + aFree(sd->hdata); break; } case BL_PET: { struct pet_data *pd = (struct pet_data*)bl; struct map_session_data *sd = pd->msd; - pet_hungry_timer_delete(pd); + pet->hungry_timer_delete(pd); if( pd->a_skill ) { aFree(pd->a_skill); @@ -2384,9 +2394,9 @@ int unit_free(struct block_list *bl, clr_type clrtype) { if (pd->s_skill->timer != INVALID_TIMER) { if (pd->s_skill->id) - iTimer->delete_timer(pd->s_skill->timer, pet_skill_support_timer); + timer->delete(pd->s_skill->timer, pet->skill_support_timer); else - iTimer->delete_timer(pd->s_skill->timer, pet_heal_timer); + timer->delete(pd->s_skill->timer, pet->heal_timer); } aFree(pd->s_skill); pd->s_skill = NULL; @@ -2394,30 +2404,30 @@ int unit_free(struct block_list *bl, clr_type clrtype) if( pd->recovery ) { if(pd->recovery->timer != INVALID_TIMER) - iTimer->delete_timer(pd->recovery->timer, pet_recovery_timer); + timer->delete(pd->recovery->timer, pet->recovery_timer); aFree(pd->recovery); pd->recovery = NULL; } if( pd->bonus ) { if (pd->bonus->timer != INVALID_TIMER) - iTimer->delete_timer(pd->bonus->timer, pet_skill_bonus_timer); + timer->delete(pd->bonus->timer, pet->skill_bonus_timer); aFree(pd->bonus); pd->bonus = NULL; } if( pd->loot ) { - pet_lootitem_drop(pd,sd); + pet->lootitem_drop(pd,sd); if (pd->loot->item) aFree(pd->loot->item); aFree (pd->loot); pd->loot = NULL; } if( pd->pet.intimate > 0 ) - intif_save_petdata(pd->pet.account_id,&pd->pet); + intif->save_petdata(pd->pet.account_id,&pd->pet); else { //Remove pet. - intif_delete_petdata(pd->pet.pet_id); + intif->delete_petdata(pd->pet.pet_id); if (sd) sd->status.pet_id = 0; } if( sd ) @@ -2429,12 +2439,12 @@ int unit_free(struct block_list *bl, clr_type clrtype) struct mob_data *md = (struct mob_data*)bl; if( md->spawn_timer != INVALID_TIMER ) { - iTimer->delete_timer(md->spawn_timer,mob_delayspawn); + timer->delete(md->spawn_timer,mob->delayspawn); md->spawn_timer = INVALID_TIMER; } if( md->deletetimer != INVALID_TIMER ) { - iTimer->delete_timer(md->deletetimer,mob_timer_delete); + timer->delete(md->deletetimer,mob->timer_delete); md->deletetimer = INVALID_TIMER; } if( md->lootitem ) @@ -2476,10 +2486,10 @@ int unit_free(struct block_list *bl, clr_type clrtype) aFree(md->base_status); md->base_status = NULL; } - if( mob_is_clone(md->class_) ) - mob_clone_delete(md); + if( mob->is_clone(md->class_) ) + mob->clone_delete(md); if( md->tomb_nid ) - mvptomb_destroy(md); + mob->mvptomb_destroy(md); break; } case BL_HOM: @@ -2490,7 +2500,7 @@ int unit_free(struct block_list *bl, clr_type clrtype) if( hd->homunculus.intimacy > 0 ) homun->save(hd); else { - intif_homunculus_requestdelete(hd->homunculus.hom_id); + intif->homunculus_requestdelete(hd->homunculus.hom_id); if( sd ) sd->status.hom_id = 0; } @@ -2502,58 +2512,111 @@ int unit_free(struct block_list *bl, clr_type clrtype) { struct mercenary_data *md = (TBL_MER*)bl; struct map_session_data *sd = md->master; - if( mercenary_get_lifetime(md) > 0 ) - mercenary_save(md); + if( mercenary->get_lifetime(md) > 0 ) + mercenary->save(md); else { - intif_mercenary_delete(md->mercenary.mercenary_id); + intif->mercenary_delete(md->mercenary.mercenary_id); if( sd ) sd->status.mer_id = 0; } if( sd ) sd->md = NULL; - merc_contract_stop(md); + mercenary->contract_stop(md); break; } case BL_ELEM: { struct elemental_data *ed = (TBL_ELEM*)bl; struct map_session_data *sd = ed->master; - if( elemental_get_lifetime(ed) > 0 ) - elemental_save(ed); + if( elemental->get_lifetime(ed) > 0 ) + elemental->save(ed); else { - intif_elemental_delete(ed->elemental.elemental_id); + intif->elemental_delete(ed->elemental.elemental_id); if( sd ) sd->status.ele_id = 0; } if( sd ) sd->ed = NULL; - elemental_summon_stop(ed); + elemental->summon_stop(ed); break; } } skill->clear_unitgroup(bl); - status_change_clear(bl,1); - iMap->deliddb(bl); + status->change_clear(bl,1); + map->deliddb(bl); if( bl->type != BL_PC ) //Players are handled by map_quit - iMap->freeblock(bl); - iMap->freeblock_unlock(); + map->freeblock(bl); + map->freeblock_unlock(); return 0; } -int do_init_unit(void) -{ - iTimer->add_timer_func_list(unit_attack_timer, "unit_attack_timer"); - iTimer->add_timer_func_list(unit_walktoxy_timer,"unit_walktoxy_timer"); - iTimer->add_timer_func_list(unit_walktobl_sub, "unit_walktobl_sub"); - iTimer->add_timer_func_list(unit_delay_walktoxy_timer,"unit_delay_walktoxy_timer"); +int do_init_unit(bool minimal) { + if (minimal) + return 0; + + timer->add_func_list(unit->attack_timer, "unit_attack_timer"); + timer->add_func_list(unit->walktoxy_timer,"unit_walktoxy_timer"); + timer->add_func_list(unit->walktobl_sub, "unit_walktobl_sub"); + timer->add_func_list(unit->delay_walktoxy_timer,"unit_delay_walktoxy_timer"); return 0; } -int do_final_unit(void) -{ +int do_final_unit(void) { // nothing to do return 0; } + +void unit_defaults(void) { + unit = &unit_s; + + unit->init = do_init_unit; + unit->final = do_final_unit; + /* */ + unit->bl2ud = unit_bl2ud; + unit->bl2ud2 = unit_bl2ud2; + unit->attack_timer = unit_attack_timer; + unit->walktoxy_timer = unit_walktoxy_timer; + unit->walktoxy_sub = unit_walktoxy_sub; + unit->delay_walktoxy_timer = unit_delay_walktoxy_timer; + unit->walktoxy = unit_walktoxy; + unit->walktobl_sub = unit_walktobl_sub; + unit->walktobl = unit_walktobl; + unit->run = unit_run; + unit->run_hit = unit_run_hit; + unit->escape = unit_escape; + unit->movepos = unit_movepos; + unit->setdir = unit_setdir; + unit->getdir = unit_getdir; + unit->blown = unit_blown; + unit->warp = unit_warp; + unit->stop_walking = unit_stop_walking; + unit->skilluse_id = unit_skilluse_id; + unit->is_walking = unit_is_walking; + unit->can_move = unit_can_move; + unit->resume_running = unit_resume_running; + unit->set_walkdelay = unit_set_walkdelay; + unit->skilluse_id2 = unit_skilluse_id2; + unit->skilluse_pos = unit_skilluse_pos; + unit->skilluse_pos2 = unit_skilluse_pos2; + unit->set_target = unit_set_target; + unit->stop_attack = unit_stop_attack; + unit->unattackable = unit_unattackable; + unit->attack = unit_attack; + unit->cancel_combo = unit_cancel_combo; + unit->can_reach_pos = unit_can_reach_pos; + unit->can_reach_bl = unit_can_reach_bl; + unit->calc_pos = unit_calc_pos; + unit->attack_timer_sub = unit_attack_timer_sub; + unit->skillcastcancel = unit_skillcastcancel; + unit->dataset = unit_dataset; + unit->counttargeted = unit_counttargeted; + unit->fixdamage = unit_fixdamage; + unit->changeviewsize = unit_changeviewsize; + unit->remove_map = unit_remove_map; + unit->remove_map_pc = unit_remove_map_pc; + unit->free_pc = unit_free_pc; + unit->free = unit_free; +} diff --git a/src/map/unit.h b/src/map/unit.h index 9d1c02a31..9b95bae41 100644 --- a/src/map/unit.h +++ b/src/map/unit.h @@ -1,18 +1,17 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder +// Copyright (c) Hercules Dev Team, licensed under GNU GPL. +// See the LICENSE file +// Portions Copyright (c) Athena Dev Teams -#ifndef _UNIT_H_ -#define _UNIT_H_ - -//#include "map.h" -struct block_list; -struct unit_data; -struct map_session_data; +#ifndef MAP_UNIT_H +#define MAP_UNIT_H #include "clif.h" // clr_type -#include "map.h" // struct block_list #include "path.h" // struct walkpath_data -#include "skill.h" // struct skill_timerskill, struct skill_unit_group, struct skill_unit_group_tickset +#include "skill.h" // 'MAX_SKILLTIMERSKILL, struct skill_timerskill, struct skill_unit_group, struct skill_unit_group_tickset +#include "../common/cbasetypes.h" + +struct map_session_data; +struct block_list; struct unit_data { struct block_list *bl; @@ -30,10 +29,10 @@ struct unit_data { int target_to; int attacktimer; int walktimer; - int chaserange; - unsigned int attackabletime; - unsigned int canact_tick; - unsigned int canmove_tick; + int chaserange; + int64 attackabletime; + int64 canact_tick; + int64 canmove_tick; uint8 dir; unsigned char walk_count; unsigned char target_count; @@ -68,78 +67,61 @@ struct view_data { unsigned dead_sit : 2; }; -// PC, MOB, PET に共通する処理を1つにまとめる計画 - -// 歩行開始 -// 戻り値は、0 ( 成功 ), 1 ( 失敗 ) -int unit_walktoxy( struct block_list *bl, short x, short y, int easy); -int unit_walktobl( struct block_list *bl, struct block_list *target, int range, int easy); -int unit_run(struct block_list *bl); -int unit_calc_pos(struct block_list *bl, int tx, int ty, uint8 dir); - -// 歩行停止 -// typeは以下の組み合わせ : -// 1: 位置情報の送信( この関数の後に位置情報を送信する場合は不要 ) -// 2: ダメージディレイ有り -// 4: 不明(MOBのみ?) -int unit_stop_walking(struct block_list *bl,int type); -int unit_can_move(struct block_list *bl); -int unit_is_walking(struct block_list *bl); -int unit_set_walkdelay(struct block_list *bl, unsigned int tick, int delay, int type); - -int unit_escape(struct block_list *bl, struct block_list *target, short dist); -// 位置の強制移動(吹き飛ばしなど) -int unit_movepos(struct block_list *bl, short dst_x, short dst_y, int easy, bool checkpath); -int unit_warp(struct block_list *bl, short map, short x, short y, clr_type type); -int unit_setdir(struct block_list *bl,unsigned char dir); -uint8 unit_getdir(struct block_list *bl); -int unit_blown(struct block_list* bl, int dx, int dy, int count, int flag); - -// そこまで歩行でたどり着けるかの判定 -bool unit_can_reach_pos(struct block_list *bl,int x,int y,int easy); -bool unit_can_reach_bl(struct block_list *bl,struct block_list *tbl, int range, int easy, short *x, short *y); - -// 攻撃関連 -int unit_stop_attack(struct block_list *bl); -int unit_attack(struct block_list *src,int target_id,int continuous); -int unit_cancel_combo(struct block_list *bl); - -// スキル使用 -int unit_skilluse_id(struct block_list *src, int target_id, uint16 skill_id, uint16 skill_lv); -int unit_skilluse_pos(struct block_list *src, short skill_x, short skill_y, uint16 skill_id, uint16 skill_lv); - -// スキル使用( 補正済みキャスト時間、キャンセル不可設定付き ) -int unit_skilluse_id2(struct block_list *src, int target_id, uint16 skill_id, uint16 skill_lv, int casttime, int castcancel); -int unit_skilluse_pos2( struct block_list *src, short skill_x, short skill_y, uint16 skill_id, uint16 skill_lv, int casttime, int castcancel); - -// 詠唱キャンセル -int unit_skillcastcancel(struct block_list *bl,int type); - -int unit_counttargeted(struct block_list *bl); -int unit_set_target(struct unit_data* ud, int target_id); - -// unit_data の初期化処理 -void unit_dataset(struct block_list *bl); +extern const short dirx[8]; +extern const short diry[8]; -int unit_fixdamage(struct block_list *src,struct block_list *target,unsigned int tick,int sdelay,int ddelay,int damage,int div,int type,int damage2); -// その他 -struct unit_data* unit_bl2ud(struct block_list *bl); -void unit_remove_map_pc(struct map_session_data *sd, clr_type clrtype); -void unit_free_pc(struct map_session_data *sd); -#define unit_remove_map(bl,clrtype) unit_remove_map_(bl,clrtype,__FILE__,__LINE__,__func__) -int unit_remove_map_(struct block_list *bl, clr_type clrtype, const char* file, int line, const char* func); -int unit_free(struct block_list *bl, clr_type clrtype); -int unit_changeviewsize(struct block_list *bl,short size); +struct unit_interface { + int (*init) (bool minimal); + int (*final) (void); + /* */ + struct unit_data* (*bl2ud) (struct block_list *bl); + struct unit_data* (*bl2ud2) (struct block_list *bl); + 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); + int (*delay_walktoxy_timer) (int tid, int64 tick, int id, intptr_t data); + int (*walktoxy) (struct block_list *bl, short x, short y, int flag); + int (*walktobl_sub) (int tid, int64 tick, int id, intptr_t data); + int (*walktobl) (struct block_list *bl, struct block_list *tbl, int range, int flag); + bool (*run) (struct block_list *bl, struct map_session_data *sd, enum sc_type type); + void (*run_hit) (struct block_list *bl, struct status_change *sc, struct map_session_data *sd, enum sc_type type); + int (*escape) (struct block_list *bl, struct block_list *target, short dist); + int (*movepos) (struct block_list *bl, short dst_x, short dst_y, int easy, bool checkpath); + int (*setdir) (struct block_list *bl, unsigned char dir); + uint8 (*getdir) (struct block_list *bl); + int (*blown) (struct block_list *bl, int dx, int dy, int count, int flag); + int (*warp) (struct block_list *bl, short m, short x, short y, clr_type type); + int (*stop_walking) (struct block_list *bl, int type); + int (*skilluse_id) (struct block_list *src, int target_id, uint16 skill_id, uint16 skill_lv); + int (*is_walking) (struct block_list *bl); + int (*can_move) (struct block_list *bl); + int (*resume_running) (int tid, int64 tick, int id, intptr_t data); + int (*set_walkdelay) (struct block_list *bl, int64 tick, int delay, int type); + int (*skilluse_id2) (struct block_list *src, int target_id, uint16 skill_id, uint16 skill_lv, int casttime, int castcancel); + int (*skilluse_pos) (struct block_list *src, short skill_x, short skill_y, uint16 skill_id, uint16 skill_lv); + int (*skilluse_pos2) (struct block_list *src, short skill_x, short skill_y, uint16 skill_id, uint16 skill_lv, int casttime, int castcancel); + int (*set_target) (struct unit_data *ud, int target_id); + int (*stop_attack) (struct block_list *bl); + int (*unattackable) (struct block_list *bl); + int (*attack) (struct block_list *src, int target_id, int continuous); + int (*cancel_combo) (struct block_list *bl); + bool (*can_reach_pos) (struct block_list *bl, int x, int y, int easy); + bool (*can_reach_bl) (struct block_list *bl, struct block_list *tbl, int range, int easy, short *x, short *y); + int (*calc_pos) (struct block_list *bl, int tx, int ty, uint8 dir); + int (*attack_timer_sub) (struct block_list *src, int tid, int64 tick); + int (*skillcastcancel) (struct block_list *bl, int type); + void (*dataset) (struct block_list *bl); + int (*counttargeted) (struct block_list *bl); + int (*fixdamage) (struct block_list *src, struct block_list *target, int sdelay, int ddelay, int64 damage, short div, unsigned char type, int64 damage2); + int (*changeviewsize) (struct block_list *bl, short size); + int (*remove_map) (struct block_list *bl, clr_type clrtype, const char *file, int line, const char *func); + void (*remove_map_pc) (struct map_session_data *sd, clr_type clrtype); + void (*free_pc) (struct map_session_data *sd); + int (*free) (struct block_list *bl, clr_type clrtype); +}; -// 初期化ルーチン -int do_init_unit(void); -int do_final_unit(void); -/** - * Ranger - **/ -int unit_wugdash(struct block_list *bl, struct map_session_data *sd); +struct unit_interface *unit; -extern const short dirx[8]; -extern const short diry[8]; +void unit_defaults(void); -#endif /* _UNIT_H_ */ +#endif /* MAP_UNIT_H */ diff --git a/src/map/vending.c b/src/map/vending.c index b9575c8dd..7e9393bf2 100644 --- a/src/map/vending.c +++ b/src/map/vending.c @@ -2,24 +2,29 @@ // See the LICENSE file // Portions Copyright (c) Athena Dev Teams -#include "../common/nullpo.h" -#include "../common/strlib.h" -#include "../common/utils.h" +#define HERCULES_CORE + +#include "vending.h" + +#include <stdio.h> +#include <string.h> + +#include "atcommand.h" +#include "battle.h" +#include "chrif.h" #include "clif.h" #include "itemdb.h" -#include "atcommand.h" +#include "log.h" #include "map.h" +#include "npc.h" #include "path.h" -#include "chrif.h" -#include "vending.h" #include "pc.h" -#include "npc.h" #include "skill.h" -#include "battle.h" -#include "log.h" +#include "../common/nullpo.h" +#include "../common/strlib.h" +#include "../common/utils.h" -#include <stdio.h> -#include <string.h> +struct vending_interface vending_s; /// Returns an unique vending shop id. static inline unsigned int getid(void) { @@ -46,16 +51,16 @@ void vending_vendinglistreq(struct map_session_data* sd, unsigned int id) { struct map_session_data* vsd; nullpo_retv(sd); - if( (vsd = iMap->id2sd(id)) == NULL ) + if( (vsd = map->id2sd(id)) == NULL ) return; if( !vsd->state.vending ) return; // not vending - if (!pc->can_give_items(sd) || !pc->can_give_items(vsd)) { //check if both GMs are allowed to trade + if (!pc_can_give_items(sd) || !pc_can_give_items(vsd)) { //check if both GMs are allowed to trade // GM is not allowed to trade clif->message(sd->fd, msg_txt(246)); return; - } + } sd->vended_id = vsd->vender_id; // register vending uid @@ -69,7 +74,7 @@ void vending_purchasereq(struct map_session_data* sd, int aid, unsigned int uid, int i, j, cursor, w, new_ = 0, blank, vend_list[MAX_VENDING]; double z; struct s_vending vend[MAX_VENDING]; // against duplicate packets - struct map_session_data* vsd = iMap->id2sd(aid); + struct map_session_data* vsd = map->id2sd(aid); nullpo_retv(sd); if( vsd == NULL || !vsd->state.vending || vsd->bl.id == sd->bl.id ) @@ -177,7 +182,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_txt(265), sd->status.name); - clif->disp_onlyself(vsd,temp,strlen(temp)); + clif_disp_onlyself(vsd,temp,strlen(temp)); } } @@ -197,9 +202,9 @@ void vending_purchasereq(struct map_session_data* sd, int aid, unsigned int uid, vsd->vend_num = cursor; //Always save BOTH: buyer and customer - if( iMap->save_settings&2 ) { - chrif_save(sd,0); - chrif_save(vsd,0); + if( map->save_settings&2 ) { + chrif->save(sd,0); + chrif->save(vsd,0); } //check for @AUTOTRADE users [durf] @@ -209,8 +214,9 @@ void vending_purchasereq(struct map_session_data* sd, int aid, unsigned int uid, if( i == vsd->vend_num ) { //Close Vending (this was automatically done by the client, we have to do it manually for autovenders) [Skotlex] vending->close(vsd); - iMap->quit(vsd); //They have no reason to stay around anymore, do they? - } + map->quit(vsd); //They have no reason to stay around anymore, do they? + } else + pc->autotrade_update(vsd,PAUC_REFRESH); } } @@ -255,7 +261,8 @@ void vending_openvending(struct map_session_data* sd, const char* message, const || !sd->status.cart[index].identify // unidentified item || sd->status.cart[index].attribute == 1 // broken item || sd->status.cart[index].expire_time // It should not be in the cart but just in case - || !itemdb_cantrade(&sd->status.cart[index], pc->get_group_level(sd), pc->get_group_level(sd)) ) // untradeable item + || (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 continue; sd->vending[i].index = index; @@ -281,7 +288,7 @@ void vending_openvending(struct map_session_data* sd, const char* message, const clif->openvending(sd,sd->bl.id,sd->vending); clif->showvendingboard(&sd->bl,message,0); - idb_put(vending->db, sd->vender_id, sd); + idb_put(vending->db, sd->status.char_id, sd); } @@ -358,7 +365,7 @@ void final(void) { db_destroy(vending->db); } -void init(void) { +void init(bool minimal) { vending->db = idb_alloc(DB_OPT_BASE); vending->next_id = 0; } diff --git a/src/map/vending.h b/src/map/vending.h index 0148deb71..63cb632a9 100644 --- a/src/map/vending.h +++ b/src/map/vending.h @@ -2,25 +2,26 @@ // See the LICENSE file // Portions Copyright (c) Athena Dev Teams -#ifndef _VENDING_H_ -#define _VENDING_H_ +#ifndef MAP_VENDING_H +#define MAP_VENDING_H #include "../common/cbasetypes.h" #include "../common/db.h" + struct map_session_data; struct s_search_store_search; struct s_vending { short index; //cart index (return item data) - short amount; //amout of the item for vending - unsigned int value; //at wich price + short amount; //amount of the item for vending + unsigned int value; //at which price }; struct vending_interface { unsigned int next_id;/* next vender id */ DBMap *db; /* */ - void (*init) (void); + void (*init) (bool minimal); void (*final) (void); /* */ void (*close) (struct map_session_data* sd); @@ -29,10 +30,10 @@ struct vending_interface { void (*purchase) (struct map_session_data* sd, int aid, unsigned int uid, const uint8* data, int count); bool (*search) (struct map_session_data* sd, unsigned short nameid); bool (*searchall) (struct map_session_data* sd, const struct s_search_store_search* s); -} vending_s; +}; -struct vending_interface * vending; +struct vending_interface *vending; void vending_defaults(void); -#endif /* _VENDING_H_ */ +#endif /* MAP_VENDING_H */ |