From 5245e666a09df5f401c1329bf5ee1fc1b09b1d16 Mon Sep 17 00:00:00 2001 From: FlavioJS Date: Thu, 20 Sep 2007 11:09:36 +0000 Subject: * Merged the tmpsql branch: - Abstraction for the sql code (sql.c/h). - New configure script and makefiles. - Restored txt zeny logging code. (r10814) - Rewrote mapserver's sql code - itemdb, mobdb, mapreg, logs. (r10814) - Fixed a precedence issue (&& and ) in char_sql/char.c. (r10833) - Improved db reading code a bit for consistency. (r11077) - Added separate atcommand for mail deletion. (r11077) - Corrected a few messages that said "new" instead of "unread". (r11077) - Broadcast (*) messages now use "*" as the target's name (not ""). (r11077) - Moved StringBuf code from utils.c/h to strlib.c/h. (r11084 r11117) - Some misc login server cleanups (reformatting etc). (r11136) - Corrected/modified some header entries. (r11141 r11147 11148) - Adjusted VS project files. (r11147) - Adjusted the way the sql charserver does item saving. (r11192) - Corrected usage of reserved keyword 'friend' in mmo.h. (r11192) git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@11245 54d463be-8e91-2dee-dedb-b68131a5f0ec --- src/char/Makefile.in | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 src/char/Makefile.in (limited to 'src/char/Makefile.in') diff --git a/src/char/Makefile.in b/src/char/Makefile.in new file mode 100644 index 000000000..78d2cb2c8 --- /dev/null +++ b/src/char/Makefile.in @@ -0,0 +1,46 @@ +COMMON_OBJ = ../common/obj/core.o ../common/obj/socket.o ../common/obj/timer.o \ + ../common/obj/db.o ../common/obj/plugins.o ../common/obj/lock.o \ + ../common/obj/malloc.o ../common/obj/showmsg.o ../common/obj/utils.o \ + ../common/obj/strlib.o ../common/obj/grfio.o \ + ../common/obj/mapindex.o ../common/obj/ers.o +COMMON_H = ../common/core.h ../common/socket.h ../common/timer.h ../common/mmo.h \ + ../common/version.h ../common/db.h ../common/plugins.h ../common/lock.h \ + ../common/malloc.h ../common/showmsg.h ../common/utils.h \ + ../common/strlib.h ../common/grfio.h \ + ../common/mapindex.h ../common/ers.h + +CHAR_OBJ = char.o inter.o int_party.o int_guild.o int_storage.o int_status.o int_pet.o int_homun.o + +##################################################################### +.PHONY : all char-server clean help + +all: char-server + +char-server: $(CHAR_OBJ) $(COMMON_OBJ) + @CC@ @LDFLAGS@ -o ../../char-server@EXEEXT@ $(CHAR_OBJ) $(COMMON_OBJ) @LIBS@ + +clean: + rm -f *.o ../../char-server@EXEEXT@ + +help: + @echo "possible targets are 'char-server' 'all' 'clean' 'help'" + @echo "'char-server' - char server (TXT version)" + @echo "'all' - builds all above targets" + @echo "'clean' - cleans builds and objects" + @echo "'help' - outputs this message" + +##################################################################### + +%.o: %.c + @CC@ @CFLAGS@ -DTXT_ONLY @CPPFLAGS@ -c $(OUTPUT_OPTION) $< + +# DO NOT DELETE + +char.o: char.c char.h inter.h int_pet.h $(COMMON_H) +inter.o: inter.c inter.h int_party.h int_guild.h int_storage.h int_pet.h char.h $(COMMON_H) +int_party.o: int_party.c int_party.h inter.h char.h $(COMMON_H) +int_guild.o: int_guild.c int_guild.h int_storage.h inter.h char.h $(COMMON_H) +int_storage.o: int_storage.c int_storage.h int_guild.h inter.h char.h $(COMMON_H) +int_status.o: int_status.c int_status.h char.h $(COMMON_H) +int_pet.o: int_pet.c int_pet.h inter.h char.h $(COMMON_H) +int_homun.o: int_homun.c int_homun.h inter.h char.h $(COMMON_H) -- cgit v1.2.3-70-g09d2 From 17222f8fdc6cb6f17efe391cbab0c357a5f93081 Mon Sep 17 00:00:00 2001 From: FlavioJS Date: Mon, 26 Nov 2007 22:36:30 +0000 Subject: * Normalized makefiles: - 3 sections: variables, public targets, private/support targets - object files always in a *_OBJ variable - header files always in a *_H variable - object files always generated to an obj* subfolder - all Makefiles can be executed individually, calling other makefiles if necessary - generic object targets when possible git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@11812 54d463be-8e91-2dee-dedb-b68131a5f0ec --- Changelog-Trunk.txt | 11 +++- src/char/Makefile.in | 29 ++++----- src/char_sql/Makefile.in | 39 ++++++++----- src/common/Makefile.in | 57 +++++++----------- src/ladmin/Makefile.in | 26 +++++++-- src/login/Makefile.in | 21 +++++-- src/login_sql/Makefile.in | 23 ++++++-- src/map/Makefile.in | 133 ++++++++++++++---------------------------- src/plugins/Makefile.in | 34 +++++------ src/tool/Makefile.in | 14 +++-- src/txt-converter/Makefile.in | 58 ++++++++++++------ 11 files changed, 230 insertions(+), 215 deletions(-) (limited to 'src/char/Makefile.in') diff --git a/Changelog-Trunk.txt b/Changelog-Trunk.txt index b0dffd272..937ea74ea 100644 --- a/Changelog-Trunk.txt +++ b/Changelog-Trunk.txt @@ -4,8 +4,15 @@ AS OF SVN REV. 5091, WE ARE NOW USING TRUNK. ALL UNTESTED BUGFIXES/FEATURES GO IF YOU HAVE A WORKING AND TESTED BUGFIX PUT IT INTO STABLE AS WELL AS TRUNK. 2007/11/26 - * Fixed buildin_query_sql using Sql_Query instead of Sql_QueryStr, making - all %f,%d,... be processed. (fixes bureport:218) [FlavioJS] + * Normalized makefiles: + - 3 sections: variables, public targets, private/support targets + - object files always in a *_OBJ variable + - header files always in a *_H variable + - object files always generated to an obj* subfolder + - all Makefiles can be executed individually, calling other makefiles if necessary + - generic object targets when possible + * Fixed buildin_query_sql using Sql_Query instead of Sql_QueryStr, + wrongly processing all %f,%d,... (fixes bureport:218) [FlavioJS] * Fixed guild expulsion not working correctly [ultramage] * Fixed a memory leak in mail_savemessage (src\char_sql\int_mail.c). [FlavioJS] 2007/11/25 diff --git a/src/char/Makefile.in b/src/char/Makefile.in index 78d2cb2c8..334265819 100644 --- a/src/char/Makefile.in +++ b/src/char/Makefile.in @@ -1,3 +1,4 @@ + COMMON_OBJ = ../common/obj/core.o ../common/obj/socket.o ../common/obj/timer.o \ ../common/obj/db.o ../common/obj/plugins.o ../common/obj/lock.o \ ../common/obj/malloc.o ../common/obj/showmsg.o ../common/obj/utils.o \ @@ -9,18 +10,22 @@ COMMON_H = ../common/core.h ../common/socket.h ../common/timer.h ../common/mmo.h ../common/strlib.h ../common/grfio.h \ ../common/mapindex.h ../common/ers.h -CHAR_OBJ = char.o inter.o int_party.o int_guild.o int_storage.o int_status.o int_pet.o int_homun.o +CHAR_OBJ = obj/char.o obj/inter.o obj/int_party.o obj/int_guild.o \ + obj/int_storage.o obj/int_status.o obj/int_pet.o obj/int_homun.o +CHAR_H = char.h inter.h int_party.h int_guild.h int_storage.h int_status.h int_pet.h int_homun.h + +@SET_MAKE@ ##################################################################### .PHONY : all char-server clean help all: char-server -char-server: $(CHAR_OBJ) $(COMMON_OBJ) +char-server: obj $(CHAR_OBJ) $(COMMON_OBJ) @CC@ @LDFLAGS@ -o ../../char-server@EXEEXT@ $(CHAR_OBJ) $(COMMON_OBJ) @LIBS@ clean: - rm -f *.o ../../char-server@EXEEXT@ + rm -rf *.o obj ../../char-server@EXEEXT@ help: @echo "possible targets are 'char-server' 'all' 'clean' 'help'" @@ -31,16 +36,12 @@ help: ##################################################################### -%.o: %.c - @CC@ @CFLAGS@ -DTXT_ONLY @CPPFLAGS@ -c $(OUTPUT_OPTION) $< +obj: + -mkdir obj -# DO NOT DELETE +obj/%.o: %.c $(CHAR_H) $(COMMON_H) + @CC@ @CFLAGS@ -DTXT_ONLY @CPPFLAGS@ -c $(OUTPUT_OPTION) $< -char.o: char.c char.h inter.h int_pet.h $(COMMON_H) -inter.o: inter.c inter.h int_party.h int_guild.h int_storage.h int_pet.h char.h $(COMMON_H) -int_party.o: int_party.c int_party.h inter.h char.h $(COMMON_H) -int_guild.o: int_guild.c int_guild.h int_storage.h inter.h char.h $(COMMON_H) -int_storage.o: int_storage.c int_storage.h int_guild.h inter.h char.h $(COMMON_H) -int_status.o: int_status.c int_status.h char.h $(COMMON_H) -int_pet.o: int_pet.c int_pet.h inter.h char.h $(COMMON_H) -int_homun.o: int_homun.c int_homun.h inter.h char.h $(COMMON_H) +# missing common object files +../common/obj/%.o: + @$(MAKE) -C ../common txt diff --git a/src/char_sql/Makefile.in b/src/char_sql/Makefile.in index 685d4286d..8162511d5 100644 --- a/src/char_sql/Makefile.in +++ b/src/char_sql/Makefile.in @@ -1,33 +1,41 @@ + COMMON_OBJ = ../common/obj/core.o ../common/obj/socket.o ../common/obj/timer.o \ ../common/obj/db.o ../common/obj/plugins.o ../common/obj/lock.o \ ../common/obj/malloc.o ../common/obj/showmsg.o ../common/obj/utils.o \ ../common/obj/strlib.o ../common/obj/grfio.o \ - ../common/obj/mapindex.o ../common/obj/ers.o ../common/obj_sql/sql.o + ../common/obj/mapindex.o ../common/obj/ers.o COMMON_H = ../common/core.h ../common/socket.h ../common/timer.h ../common/mmo.h \ ../common/version.h ../common/db.h ../common/plugins.h ../common/lock.h \ ../common/malloc.h ../common/showmsg.h ../common/utils.h \ ../common/strlib.h ../common/grfio.h \ - ../common/mapindex.h ../common/ers.h ../common/sql.h + ../common/mapindex.h ../common/ers.h + +COMMON_SQL_OBJ = ../common/obj_sql/sql.o +COMMON_H = ../common/sql.h -CHAR_OBJ = char.o inter.o int_party.o int_guild.o int_storage.o int_pet.o int_homun.o int_mail.o +CHAR_OBJ = obj/char.o obj/inter.o obj/int_party.o obj/int_guild.o \ + obj/int_storage.o obj/int_pet.o obj/int_homun.o obj/int_mail.o +CHAR_H = char.h inter.h int_party.h int_guild.h int_storage.h int_pet.h int_homun.h int_mail.h HAVE_MYSQL=@HAVE_MYSQL@ ifeq ($(HAVE_MYSQL),yes) - CHAR_SERVER_SQL_DEPENDS=$(CHAR_OBJ) $(COMMON_OBJ) + CHAR_SERVER_SQL_DEPENDS=obj $(CHAR_OBJ) $(COMMON_OBJ) $(COMMON_SQL_OBJ) else CHAR_SERVER_SQL_DEPENDS=needs_mysql endif +@SET_MAKE@ + ##################################################################### .PHONY : all char-server_sql clean help all: char-server_sql char-server_sql: $(CHAR_SERVER_SQL_DEPENDS) - @CC@ @LDFLAGS@ -o ../../char-server_sql@EXEEXT@ $(CHAR_OBJ) $(COMMON_OBJ) @LIBS@ @MYSQL_LIBS@ + @CC@ @LDFLAGS@ -o ../../char-server_sql@EXEEXT@ $(CHAR_OBJ) $(COMMON_OBJ) $(COMMON_SQL_OBJ) @LIBS@ @MYSQL_LIBS@ clean: - rm -f *.o ../../char-server_sql@EXEEXT@ + rm -rf *.o obj ../../char-server_sql@EXEEXT@ help: @echo "possible targets are 'char-server_sql' 'all' 'clean' 'help'" @@ -42,16 +50,15 @@ needs_mysql: @echo "MySQL not found or disabled by the configure script" @exit 1 -%.o: %.c +obj: + -mkdir obj + +obj/%.o: %.c $(CHAR_H) $(COMMON_H) $(COMMON_SQL_H) @CC@ @CFLAGS@ @MYSQL_CFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $< -# DO NOT DELETE +# missing common object files +../common/obj/%.o: + @$(MAKE) -C ../common sql -char.o: char.c char.h $(COMMON_H) -inter.o: inter.c inter.h int_party.h int_guild.h int_storage.h int_pet.h int_homun.h $(COMMON_H) -int_party.o: int_party.c int_party.h inter.h $(COMMON_H) -int_guild.o: int_guild.c int_guild.h inter.h $(COMMON_H) -int_storage.o: int_storage.c int_storage.h char.h $(COMMON_H) -int_pet.o: int_pet.c int_pet.h inter.h char.h $(COMMON_H) -int_homun.o: int_homun.c int_homun.h inter.h char.h $(COMMON_H) -int_mail.o: int_mail.c int_mail.h inter.h char.h $(COMMON_H) \ No newline at end of file +../common/obj_sql/%.o: + @$(MAKE) -C ../common sql diff --git a/src/common/Makefile.in b/src/common/Makefile.in index 94f42a956..89bb8a75a 100644 --- a/src/common/Makefile.in +++ b/src/common/Makefile.in @@ -1,18 +1,33 @@ + +COMMON_OBJ = obj/core.o obj/socket.o obj/timer.o obj/db.o obj/plugins.o obj/lock.o \ + obj/nullpo.o obj/malloc.o obj/showmsg.o obj/strlib.o obj/utils.o \ + obj/grfio.o obj/mapindex.o obj/ers.o obj/md5calc.o \ + obj/minicore.o obj/minisocket.o obj/minimalloc.o +COMMON_H = svnversion.h mmo.h plugin.h version.h \ + core.h socket.h timer.h db.h plugins.h lock.h \ + nullpo.h malloc.h showmsg.h strlib.h utils.h \ + grfio.h mapindex.h ers.h md5calc.h + +COMMON_SQL_OBJ = obj_sql/sql.o +COMMON_SQL_H = sql.h + HAVE_MYSQL=@HAVE_MYSQL@ ifeq ($(HAVE_MYSQL),yes) ALL_DEPENDS=txt sql - SQL_DEPENDS=txt obj_sql common_sql + SQL_DEPENDS=common common_sql else ALL_TARGET=txt SQL_DEPENDS=needs_mysql endif +@SET_MAKE@ + ##################################################################### .PHONY : all txt sql clean help all: $(ALL_DEPENDS) -txt: obj common +txt: common sql: $(SQL_DEPENDS) @@ -39,21 +54,18 @@ obj: obj_sql: -mkdir obj_sql -common: obj/core.o obj/socket.o obj/timer.o obj/db.o obj/plugins.o obj/lock.o \ - obj/nullpo.o obj/malloc.o obj/showmsg.o obj/strlib.o obj/utils.o \ - obj/grfio.o obj/minicore.o obj/minisocket.o obj/minimalloc.o \ - obj/mapindex.o obj/ers.o obj/md5calc.o +common: obj $(COMMON_OBJ) -common_sql: obj_sql/sql.o +common_sql: obj_sql $(COMMON_SQL_OBJ) -obj/%.o: %.c +obj/%.o: %.c $(COMMON_H) @CC@ @CFLAGS@ @LDFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $< -obj/mini%.o: %.c +obj/mini%.o: %.c $(COMMON_H) @CC@ @CFLAGS@ -DMINICORE @LDFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $< -obj_sql/%.o: %.c +obj_sql/%.o: %.c $(COMMON_H) $(COMMON_SQL_H) @CC@ @CFLAGS@ @MYSQL_CFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $< @@ -68,28 +80,3 @@ else svnversion.h: @printf "\n" > svnversion.h endif - -obj/minicore.o: core.c core.h -obj/minisocket.o: socket.c socket.h -obj/minimalloc.o: malloc.c malloc.h - -# DO NOT DELETE - -obj/core.o: core.c core.h showmsg.h svnversion.h -obj/db.o: db.c db.h showmsg.h ers.h -obj/ers.o: ers.c ers.h cbasetypes.h -obj/grfio.o: grfio.c grfio.h -obj/lock.o: lock.c lock.h showmsg.h -obj/malloc.o: malloc.c malloc.h showmsg.h -obj/mapindex.o: mapindex.c mapindex.h -obj/md5calc.o: md5calc.c md5calc.h -obj/nullpo.o: nullpo.c nullpo.h showmsg.h -obj/plugins.o: plugins.c plugins.h plugin.h -obj/showmsg.o: showmsg.c showmsg.h -obj/socket.o: socket.c socket.h mmo.h showmsg.h plugins.h -obj/strlib.o: strlib.c strlib.h utils.h -obj/timer.o: timer.c timer.h showmsg.h -obj/utils.o: utils.c utils.h malloc.h showmsg.h mmo.h -obj_sql/sql.o: sql.c sql.h cbasetypes.h malloc.h showmsg.h utils.h -mmo.h: cbasetypes.h - @touch mmo.h diff --git a/src/ladmin/Makefile.in b/src/ladmin/Makefile.in index f1f7bff23..87cc2ad49 100644 --- a/src/ladmin/Makefile.in +++ b/src/ladmin/Makefile.in @@ -1,20 +1,26 @@ + COMMON_OBJ = ../common/obj/minicore.o ../common/obj/minisocket.o ../common/obj/timer.o \ ../common/obj/malloc.o ../common/obj/showmsg.o ../common/obj/strlib.o \ ../common/obj/utils.o ../common/obj/md5calc.o COMMON_H = ../common/core.h ../common/socket.h ../common/timer.h ../common/mmo.h \ ../common/version.h ../common/malloc.h ../common/showmsg.h ../common/strlib.h \ - ../common/utils.h ../common/md5calc.h + ../common/utils.h ../common/md5calc.h ../common/cbasetypes.h + +LADMIN_OBJ = obj/ladmin.o +LADMIN_H = ladmin.h + +@SET_MAKE@ ##################################################################### .PHONY : all ladmin clean help all: ladmin -ladmin: ladmin.o $(COMMON_OBJ) - @CC@ @LDFLAGS@ -o ../../ladmin@EXEEXT@ ladmin.o $(COMMON_OBJ) @LIBS@ +ladmin: obj $(LADMIN_OBJ) $(COMMON_OBJ) + @CC@ @LDFLAGS@ -o ../../ladmin@EXEEXT@ $(LADMIN_OBJ) $(COMMON_OBJ) @LIBS@ clean: - rm -f *.o ../../ladmin@EXEEXT@ + rm -rf *.o obj ../../ladmin@EXEEXT@ help: @echo "possible targets are 'ladmin' 'all' 'clean' 'help'" @@ -25,7 +31,15 @@ help: ##################################################################### -# DO NOT DELETE +obj: + -mkdir obj -ladmin.o: ladmin.c ladmin.h $(COMMON_H) +obj/%.o: %.c $(LADMIN_H) $(COMMON_H) @CC@ @CFLAGS@ @LDFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $< + +# missing common object files +../common/obj/%.o: + @$(MAKE) -C ../common txt + +../common/obj/mini%.o: + @$(MAKE) -C ../common txt diff --git a/src/login/Makefile.in b/src/login/Makefile.in index c0fdcc8e3..187a3eaf0 100644 --- a/src/login/Makefile.in +++ b/src/login/Makefile.in @@ -1,3 +1,4 @@ + COMMON_OBJ = ../common/obj/core.o ../common/obj/socket.o ../common/obj/timer.o \ ../common/obj/db.o ../common/obj/plugins.o ../common/obj/lock.o \ ../common/obj/malloc.o ../common/obj/showmsg.o ../common/obj/utils.o \ @@ -9,16 +10,21 @@ COMMON_H = ../common/core.h ../common/socket.h ../common/timer.h ../common/mmo.h ../common/grfio.h ../common/mapindex.h \ ../common/ers.h ../common/md5calc.h +LOGIN_OBJ = obj/login.o +LOGIN_H = login.h + +@SET_MAKE@ + ##################################################################### .PHONY : all login-server clean help all: login-server -login-server: login.o $(COMMON_OBJ) - @CC@ @LDFLAGS@ -o ../../login-server@EXEEXT@ login.o $(COMMON_OBJ) @LIBS@ +login-server: obj $(LOGIN_OBJ) $(COMMON_OBJ) + @CC@ @LDFLAGS@ -o ../../login-server@EXEEXT@ $(LOGIN_OBJ) $(COMMON_OBJ) @LIBS@ clean: - rm -f *.o ../../login-server@EXEEXT@ + rm -rf *.o obj ../../login-server@EXEEXT@ help: @echo "possible targets are 'login-server' 'all' 'clean' 'help'" @@ -29,7 +35,12 @@ help: ##################################################################### -# DO NOT DELETE +obj: + -mkdir obj -login.o: login.c login.h $(COMMON_H) +obj/%.o: %.c $(LOGIN_H) $(COMMON_H) @CC@ @CFLAGS@ -DTXT_ONLY @CPPFLAGS@ -c $(OUTPUT_OPTION) $< + +# missing common object files +../common/obj/%.o: + @$(MAKE) -C ../common sql diff --git a/src/login_sql/Makefile.in b/src/login_sql/Makefile.in index d10b49b5f..22a1437b3 100644 --- a/src/login_sql/Makefile.in +++ b/src/login_sql/Makefile.in @@ -9,23 +9,28 @@ COMMON_H = ../common/core.h ../common/socket.h ../common/timer.h ../common/mmo.h ../common/grfio.h ../common/mapindex.h \ ../common/ers.h ../common/md5calc.h ../common/sql.h +LOGIN_OBJ = obj/login.o +LOGIN_H = login.h + HAVE_MYSQL=@HAVE_MYSQL@ ifeq ($(HAVE_MYSQL),yes) - LOGIN_SERVER_SQL_DEPENDS=login.o $(COMMON_OBJ) + LOGIN_SERVER_SQL_DEPENDS=obj $(LOGIN_OBJ) $(COMMON_OBJ) else LOGIN_SERVER_SQL_DEPENDS=needs_mysql endif +@SET_MAKE@ + ##################################################################### .PHONY : all login-server_sql clean help all: login-server_sql login-server_sql: $(LOGIN_SERVER_SQL_DEPENDS) - @CC@ @LDFLAGS@ -o ../../login-server_sql@EXEEXT@ login.o $(COMMON_OBJ) @LIBS@ @MYSQL_LIBS@ + @CC@ @LDFLAGS@ -o ../../login-server_sql@EXEEXT@ $(LOGIN_OBJ) $(COMMON_OBJ) @LIBS@ @MYSQL_LIBS@ clean: - rm -f *.o ../../login-server_sql@EXEEXT@ + rm -rf *.o obj ../../login-server_sql@EXEEXT@ help: @echo "possible targets are 'login-server_sql' 'all' 'clean' 'help'" @@ -40,7 +45,15 @@ needs_mysql: @echo "MySQL not found or disabled by the configure script" @exit 1 -# DO NOT DELETE +obj: + -mkdir obj -login.o: login.c login.h $(COMMON_H) +obj/%.o: %.c $(LOGIN_H) $(COMMON_H) @CC@ @CFLAGS@ @MYSQL_CFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $< + +# missing common object files +../common/obj/%.o: + @$(MAKE) -C ../common sql + +../common/obj_sql/%.o: + @$(MAKE) -C ../common sql diff --git a/src/map/Makefile.in b/src/map/Makefile.in index 1be112d9a..31c0fc3f1 100644 --- a/src/map/Makefile.in +++ b/src/map/Makefile.in @@ -1,8 +1,33 @@ +COMMON_OBJ = ../common/obj/core.o ../common/obj/socket.o ../common/obj/timer.o \ + ../common/obj/db.o ../common/obj/plugins.o ../common/obj/lock.o \ + ../common/obj/nullpo.o ../common/obj/malloc.o ../common/obj/showmsg.o \ + ../common/obj/utils.o ../common/obj/strlib.o ../common/obj/grfio.o \ + ../common/obj/mapindex.o ../common/obj/ers.o +COMMON_H = ../common/core.h ../common/socket.h ../common/timer.h \ + ../common/db.h ../common/plugins.h ../common/lock.h \ + ../common/nullpo.h ../common/malloc.h ../common/showmsg.h \ + ../common/utils.h ../common/strlib.h ../common/grfio.h \ + ../common/mapindex.h ../common/ers.h + +COMMON_SQL_OBJ = ../common/obj_sql/sql.o +COMMON_SQL_H = ../common/sql.h + +MAP_OBJ = obj/map.o obj/chrif.o obj/clif.o obj/pc.o obj/status.o obj/npc.o \ + obj/npc_chat.o obj/chat.o obj/path.o obj/itemdb.o obj/mob.o obj/script.o \ + obj/storage.o obj/skill.o obj/atcommand.o obj/charcommand.o obj/battle.o \ + obj/intif.o obj/trade.o obj/party.o obj/vending.o obj/guild.o obj/pet.o \ + obj/log.o obj/mail.o obj/date.o obj/irc.o obj/unit.o obj/mercenary.o +MAP_H = map.h chrif.h clif.h pc.h status.h npc.h \ + chat.h itemdb.h mob.h script.h \ + storage.h skill.h atcommand.h charcommand.h battle.h \ + intif.h trade.h party.h vending.h guild.h pet.h \ + log.h mail.h date.h irc.h unit.h mercenary.h + HAVE_MYSQL=@HAVE_MYSQL@ ifeq ($(HAVE_MYSQL),yes) ALL_DEPENDS=txt sql - SQL_DEPENDS=obj_sql map-server_sql + SQL_DEPENDS=map-server_sql else ALL_TARGET=txt SQL_DEPENDS=needs_mysql @@ -15,18 +40,19 @@ else PCRE_CFLAGS= endif +@SET_MAKE@ ##################################################################### .PHONY : all txt sql clean help all: $(ALL_DEPENDS) -txt: obj_txt map-server +txt: map-server sql: $(SQL_DEPENDS) clean: - rm -rf *.o ../../map-server@EXEEXT@ ../../map-server_sql@EXEEXT@ obj_txt obj_sql + rm -rf *.o obj_txt obj_sql ../../map-server@EXEEXT@ ../../map-server_sql@EXEEXT@ help: ifeq ($(HAVE_MYSQL),yes) @@ -46,103 +72,30 @@ needs_mysql: @echo "MySQL not found or disabled by the configure script" @exit 1 +# object directories obj_txt: -mkdir obj_txt obj_sql: -mkdir obj_sql -COMMON_OBJ = ../common/obj/core.o ../common/obj/socket.o ../common/obj/timer.o \ - ../common/obj/db.o ../common/obj/plugins.o ../common/obj/lock.o \ - ../common/obj/nullpo.o ../common/obj/malloc.o ../common/obj/showmsg.o \ - ../common/obj/utils.o ../common/obj/strlib.o ../common/obj/grfio.o \ - ../common/obj/mapindex.o ../common/obj/ers.o - -COMMON_H = ../common/core.h ../common/socket.h ../common/timer.h \ - ../common/db.h ../common/plugins.h ../common/lock.h \ - ../common/nullpo.h ../common/malloc.h ../common/showmsg.h \ - ../common/utils.h ../common/strlib.h ../common/grfio.h \ - ../common/mapindex.h ../common/ers.h - -COMMON_SQL_OBJ = $(COMMON_OBJ) ../common/obj_sql/sql.o - -COMMON_SQL_H = $(COMMON_H) ../common/sql.h - -MAP_OBJ = obj/map.o obj/chrif.o obj/clif.o obj/pc.o obj/status.o obj/npc.o \ - obj/npc_chat.o obj/chat.o obj/path.o obj/itemdb.o obj/mob.o obj/script.o \ - obj/storage.o obj/skill.o obj/atcommand.o obj/charcommand.o obj/battle.o \ - obj/intif.o obj/trade.o obj/party.o obj/vending.o obj/guild.o obj/pet.o \ - obj/log.o obj/mail.o obj/date.o obj/irc.o obj/unit.o obj/mercenary.o - -map-server: $(MAP_OBJ:obj/%=obj_txt/%) $(COMMON_OBJ) +# executables +map-server: obj_txt $(MAP_OBJ:obj/%=obj_txt/%) $(COMMON_OBJ) @CC@ @LDFLAGS@ -o ../../map-server@EXEEXT@ $(MAP_OBJ:obj/%=obj_txt/%) $(COMMON_OBJ) @LIBS@ @PCRE_LIBS@ -map-server_sql: $(MAP_OBJ:obj/%=obj_sql/%) $(COMMON_SQL_OBJ) - @CC@ @LDFLAGS@ -o ../../map-server_sql@EXEEXT@ $(MAP_OBJ:obj/%=obj_sql/%) $(COMMON_SQL_OBJ) @LIBS@ @PCRE_LIBS@ @MYSQL_LIBS@ +map-server_sql: obj_sql $(MAP_OBJ:obj/%=obj_sql/%) $(COMMON_OBJ) $(COMMON_SQL_OBJ) + @CC@ @LDFLAGS@ -o ../../map-server_sql@EXEEXT@ $(MAP_OBJ:obj/%=obj_sql/%) $(COMMON_OBJ) $(COMMON_SQL_OBJ) @LIBS@ @PCRE_LIBS@ @MYSQL_LIBS@ -obj_txt/%.o: %.c +# map object files +obj_txt/%.o: %.c $(MAP_H) $(COMMON_H) @CC@ @CFLAGS@ $(PCRE_CFLAGS) -DTXT_ONLY @CPPFLAGS@ -c $(OUTPUT_OPTION) $< -obj_sql/%.o: %.c +obj_sql/%.o: %.c $(MAP_H) $(COMMON_H) $(COMMON_SQL_H) @CC@ @CFLAGS@ $(PCRE_CFLAGS) @MYSQL_CFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $< -# DO NOT DELETE - -obj_txt/map.o: map.c map.h chrif.h clif.h npc.h pc.h mob.h chat.h skill.h itemdb.h storage.h party.h pet.h atcommand.h irc.h $(COMMON_H) -obj_txt/chrif.o: chrif.c map.h battle.h chrif.h clif.h intif.h pc.h npc.h $(COMMON_H) -obj_txt/clif.o: clif.c map.h chrif.h clif.h mob.h intif.h pc.h npc.h itemdb.h chat.h script.h storage.h party.h guild.h atcommand.h pet.h charcommand.h irc.h $(COMMON_H) -obj_txt/pc.o: pc.c map.h clif.h intif.h pc.h npc.h mob.h itemdb.h battle.h skill.h script.h party.h guild.h pet.h trade.h storage.h chat.h vending.h $(COMMON_H) -obj_txt/status.o: status.c pc.h map.h clif.h status.h mob.h itemdb.h battle.h skill.h script.h pet.h guild.h $(COMMON_H) -obj_txt/npc.o: npc.c map.h npc.h clif.h pc.h script.h mob.h itemdb.h battle.h $(COMMON_H) -obj_txt/npc_chat.o: npc_chat.c map.h npc.h clif.h pc.h script.h mob.h itemdb.h battle.h $(COMMON_H) -obj_txt/chat.o: chat.c map.h clif.h pc.h chat.h $(COMMON_H) -obj_txt/path.o: path.c map.h battle.h $(COMMON_H) -obj_txt/itemdb.o: itemdb.c map.h battle.h itemdb.h $(COMMON_H) -obj_txt/mob.o: mob.c map.h clif.h intif.h pc.h mob.h skill.h battle.h npc.h itemdb.h date.h irc.h $(COMMON_H) -obj_txt/script.o: script.c itemdb.h map.h pc.h mob.h clif.h intif.h npc.h script.h storage.h skill.h pet.h battle.h log.h irc.h $(COMMON_H) -obj_txt/storage.o: storage.c itemdb.h pc.h clif.h intif.h storage.h guild.h $(COMMON_H) -obj_txt/skill.o: skill.c skill.h map.h clif.h pc.h mob.h battle.h itemdb.h script.h date.h $(COMMON_H) -obj_txt/atcommand.o: atcommand.c atcommand.h itemdb.h pc.h map.h skill.h clif.h mob.h intif.h battle.h storage.h guild.h pet.h log.h $(COMMON_H) -obj_txt/battle.o: battle.c battle.h skill.h map.h mob.h pc.h pet.h guild.h $(COMMON_H) -obj_txt/intif.o: intif.c intif.h chrif.h clif.h party.h guild.h storage.h map.h battle.h pet.h $(COMMON_H) -obj_txt/trade.o: trade.c trade.h clif.h itemdb.h map.h pc.h npc.h $(COMMON_H) -obj_txt/party.o: party.c party.h clif.h intif.h pc.h map.h battle.h $(COMMON_H) -obj_txt/vending.o: vending.c vending.h clif.h itemdb.h map.h pc.h irc.h $(COMMON_H) -obj_txt/guild.o: guild.c guild.h storage.h battle.h clif.h intif.h pc.h npc.h map.h $(COMMON_H) -obj_txt/pet.o: pet.c pet.h map.h clif.h chrif.h intif.h pc.h itemdb.h battle.h mob.h npc.h script.h $(COMMON_H) -obj_txt/log.o: log.c log.h map.h $(COMMON_H) -obj_txt/charcommand.o: charcommand.c charcommand.h itemdb.h pc.h map.h skill.h clif.h mob.h intif.h battle.h storage.h guild.h pet.h log.h $(COMMON_H) -obj_txt/date.o: date.c date.h $(COMMON_H) -obj_txt/irc.o: irc.c irc.h map.h pc.h $(COMMON_H) -obj_txt/unit.o: unit.c unit.h $(COMMON_H) -obj_txt/mercenary.o: mercenary.c mercenary.h $(COMMON_H) - -obj_sql/map.o: map.c map.h chrif.h clif.h npc.h pc.h mob.h chat.h skill.h itemdb.h storage.h party.h pet.h atcommand.h log.h irc.h $(COMMON_SQL_H) -obj_sql/chrif.o: chrif.c map.h battle.h chrif.h clif.h intif.h pc.h npc.h $(COMMON_SQL_H) -obj_sql/clif.o: clif.c map.h chrif.h clif.h mob.h intif.h pc.h npc.h itemdb.h chat.h script.h storage.h party.h guild.h atcommand.h pet.h charcommand.h $(COMMON_SQL_H) -obj_sql/pc.o: pc.c map.h clif.h intif.h pc.h npc.h mob.h itemdb.h battle.h skill.h script.h party.h guild.h pet.h trade.h storage.h chat.h vending.h log.h $(COMMON_SQL_H) -obj_sql/status.o: status.c pc.h map.h clif.h status.h mob.h itemdb.h battle.h skill.h script.h pet.h guild.h $(COMMON_SQL_H) -obj_sql/npc.o: npc.c map.h npc.h clif.h pc.h script.h mob.h itemdb.h battle.h $(COMMON_SQL_H) -obj_sql/npc_chat.o: npc_chat.c map.h npc.h clif.h pc.h script.h mob.h itemdb.h battle.h $(COMMON_SQL_H) -obj_sql/chat.o: chat.c map.h clif.h pc.h chat.h $(COMMON_SQL_H) -obj_sql/path.o: path.c map.h battle.h $(COMMON_SQL_H) -obj_sql/itemdb.o: itemdb.c map.h battle.h itemdb.h $(COMMON_SQL_H) -obj_sql/mob.o: mob.c map.h clif.h intif.h pc.h mob.h skill.h battle.h npc.h itemdb.h log.h date.h irc.h $(COMMON_SQL_H) -obj_sql/script.o: script.c itemdb.h map.h pc.h mob.h clif.h intif.h npc.h script.h storage.h skill.h pet.h battle.h log.h irc.h $(COMMON_SQL_H) -obj_sql/storage.o: storage.c itemdb.h pc.h clif.h intif.h storage.h guild.h $(COMMON_SQL_H) -obj_sql/skill.o: skill.c skill.h map.h clif.h pc.h mob.h battle.h itemdb.h script.h log.h date.h $(COMMON_SQL_H) -obj_sql/atcommand.o: atcommand.c atcommand.h itemdb.h pc.h map.h skill.h clif.h mob.h intif.h battle.h storage.h guild.h pet.h log.h $(COMMON_SQL_H) -obj_sql/battle.o: battle.c battle.h skill.h map.h mob.h pc.h pet.h guild.h $(COMMON_SQL_H) -obj_sql/intif.o: intif.c intif.h chrif.h clif.h party.h guild.h storage.h map.h battle.h pet.h $(COMMON_SQL_H) -obj_sql/trade.o: trade.c trade.h clif.h itemdb.h map.h pc.h npc.h log.h $(COMMON_SQL_H) -obj_sql/party.o: party.c party.h clif.h intif.h pc.h map.h battle.h $(COMMON_SQL_H) -obj_sql/vending.o: vending.c vending.h clif.h itemdb.h map.h pc.h log.h irc.h $(COMMON_SQL_H) -obj_sql/guild.o: guild.c guild.h storage.h battle.h clif.h intif.h pc.h npc.h map.h irc.h $(COMMON_SQL_H) -obj_sql/pet.o: pet.c pet.h map.h clif.h chrif.h intif.h pc.h itemdb.h battle.h mob.h npc.h script.h $(COMMON_SQL_H) -obj_sql/mail.o: mail.c mail.h $(COMMON_SQL_H) -obj_sql/log.o: log.c log.h map.h $(COMMON_SQL_H) -obj_sql/charcommand.o: charcommand.c charcommand.h itemdb.h pc.h map.h skill.h clif.h mob.h intif.h battle.h storage.h guild.h pet.h log.h $(COMMON_SQL_H) -obj_sql/date.o: date.c date.h $(COMMON_SQL_H) -obj_sql/irc.o: irc.c irc.h map.h pc.h $(COMMON_SQL_H) -obj_sql/unit.o: unit.c unit.h $(COMMON_SQL_H) -obj_sql/mercenary.o: mercenary.c mercenary.h $(COMMON_SQL_H) +# missing common object files +../common/obj/%.o: + @$(MAKE) -C ../common txt + +../common/obj_sql/%.o: + @$(MAKE) -C ../common sql diff --git a/src/plugins/Makefile.in b/src/plugins/Makefile.in index 769771aca..00493a7c9 100644 --- a/src/plugins/Makefile.in +++ b/src/plugins/Makefile.in @@ -1,8 +1,13 @@ -@SET_MAKE@ + +COMMON_OBJ = ../common/obj/showmsg.o ../common/obj/utils.o ../common/obj/strlib.o \ + ../common/obj/minimalloc.o +COMMON_H = ../common/plugin.h ../common/cbasetypes.h \ + ../common/showmsg.h ../common/utils.h ../common/strlib.h \ + ../common/malloc.h PLUGINS = sample sig pid gui upnp console -COMMON_H = ../common/plugin.h ../common/cbasetypes.h +@SET_MAKE@ ##################################################################### .PHONY : all $(PLUGINS) clean help @@ -41,27 +46,18 @@ help: %@DLLEXT@: %.c @CC@ @CFLAGS@ @CPPFLAGS@ -shared -o ../../plugins/$@ $< -sig@DLLEXT@: sig.c - @$(MAKE) -C ../common txt - @CC@ @CFLAGS@ @CPPFLAGS@ -shared -o ../../plugins/$@ $< \ - ../common/obj/showmsg.o ../common/obj/utils.o ../common/obj/strlib.o \ - ../common/obj/minimalloc.o - gui@DLLEXT@: ../../plugins/gui.conf upnp@DLLEXT@: ../../plugins/upnp.conf +sig@DLLEXT@: sig.c $(COMMON_OBJ) + @CC@ @CFLAGS@ @CPPFLAGS@ -shared -o ../../plugins/$@ $< $(COMMON_OBJ) + ../../plugins/%.conf: %.txt cp -r $< $@ -../../plugins/gui.conf: gui.txt -../../plugins/upnp.conf: upnp.txt - -# DO NOT DELETE +# missing common object files +../common/obj/%.o: ../common/%.c $(COMMON_H) + @$(MAKE) -C ../common txt -sample@DLLEXT@: sample.c $(COMMON_H) -sig@DLLEXT@: sig.c $(COMMON_H) -pid@DLLEXT@: pid.c $(COMMON_H) -gui@DLLEXT@: gui.c $(COMMON_H) -#TODO where is upnp.c? [FlavioJS] -#upnp@DLLEXT@: upnp.c $(COMMON_H) -console@DLLEXT@: console.c $(COMMON_H) +../common/obj/mini%.o: ../common/%.c $(COMMON_H) + @$(MAKE) -C ../common txt diff --git a/src/tool/Makefile.in b/src/tool/Makefile.in index 7c0d1e1ee..277ff4c68 100644 --- a/src/tool/Makefile.in +++ b/src/tool/Makefile.in @@ -1,3 +1,6 @@ + +@SET_MAKE@ + ##################################################################### .PHONY : all adduser convert mapcache clean help @@ -9,12 +12,12 @@ adduser: convert: @CC@ -o ../../tools/convert@EXEEXT@ convert.c -mapcache: - @CC@ -c -o grfio.o grfio.c - @CC@ -o ../../mapcache@EXEEXT@ mapcache.c grfio.o -lz +mapcache: obj + @CC@ -c -o obj/grfio.o grfio.c + @CC@ -o ../../mapcache@EXEEXT@ mapcache.c obj/grfio.o -lz clean: - rm -rf *.o ../../tools/adduser@EXEEXT@ ../../tools/convert@EXEEXT@ ../../mapcache@EXEEXT@ + rm -rf *.o obj ../../tools/adduser@EXEEXT@ ../../tools/convert@EXEEXT@ ../../mapcache@EXEEXT@ help: @echo "possible targets are 'adduser' 'convert' 'mapcache' 'all' 'clean' 'help'" @@ -26,3 +29,6 @@ help: @echo "'help' - outputs this message" ##################################################################### + +obj: + -mkdir obj diff --git a/src/txt-converter/Makefile.in b/src/txt-converter/Makefile.in index 31d593743..59d3a6641 100644 --- a/src/txt-converter/Makefile.in +++ b/src/txt-converter/Makefile.in @@ -1,25 +1,42 @@ -LOGIN_CONVERTER_OBJ = login-converter.o ../common/obj/minicore.o \ + +LOGIN_CONVERTER_OBJ = obj_login/login-converter.o ../common/obj/minicore.o \ ../common/obj/malloc.o ../common/obj/strlib.o ../common/obj/showmsg.o \ ../common/obj/utils.o ../common/obj/ers.o ../common/obj/db.o \ ../common/obj_sql/sql.o -CHAR_CONVERTER_OBJ = char-converter.o ../common/obj/minicore.o \ +LOGIN_CONVERTER_H = ../common/cbasetypes.h ../common/mmo.h ../common/core.h \ + ../common/malloc.h ../common/strlib.h ../common/showmsg.h \ + ../common/utils.h ../common/ers.h ../common/db.h \ + ../common/sql.h + +CHAR_CONVERTER_OBJ = obj_char/char-converter.o \ + obj_char/txt-char.o obj_char/txt-int_pet.o obj_char/txt-int_storage.o obj_char/txt-inter.o \ + obj_char/txt-int_party.o obj_char/txt-int_guild.o \ + obj_char/sql-char.o obj_char/sql-int_pet.o obj_char/sql-int_storage.o \ + obj_char/sql-inter.o obj_char/sql-int_party.o obj_char/sql-int_guild.o \ + ../common/obj/minicore.o \ ../common/obj/malloc.o ../common/obj/strlib.o ../common/obj/showmsg.o \ ../common/obj/utils.o ../common/obj/ers.o ../common/obj/mapindex.o \ - ../common/obj_sql/sql.o \ - obj_txt/char.o obj_txt/int_pet.o obj_txt/int_storage.o obj_txt/inter.o \ - obj_txt/int_party.o obj_txt/int_guild.o \ - obj_sql/char.o obj_sql/int_pet.o obj_sql/int_storage.o \ - obj_sql/inter.o obj_sql/int_party.o obj_sql/int_guild.o + ../common/obj_sql/sql.o +CHAR_CONVERTER_H = ../char/char.h ../char/int_pet.h ../char/int_storage.h ../char/inter.h \ + ../char/int_party.h ../char/int_guild.h \ + ../char_sql/char.h ../char_sql/int_pet.h ../char_sql/int_storage.h \ + ../char_sql/inter.h ../char_sql/int_party.h ../char_sql/int_guild.h \ + ../common/cbasetypes.h ../common/mmo.h ../common/core.h \ + ../common/malloc.h ../common/strlib.h ../common/showmsg.h \ + ../common/utils.h ../common/ers.h ../common/mapindex.h \ + ../common/sql.h HAVE_MYSQL=@HAVE_MYSQL@ ifeq ($(HAVE_MYSQL),yes) - LOGIN_CONVERTER_DEPENDS=$(LOGIN_CONVERTER_OBJ) - CHAR_CONVERTER_DEPENDS=obj $(CHAR_CONVERTER_OBJ) + LOGIN_CONVERTER_DEPENDS=obj_login $(LOGIN_CONVERTER_OBJ) + CHAR_CONVERTER_DEPENDS=obj_char $(CHAR_CONVERTER_OBJ) else LOGIN_CONVERTER_DEPENDS=needs_mysql CHAR_CONVERTER_DEPENDS=needs_mysql endif +@SET_MAKE@ + ##################################################################### .PHONY : all login-converter char-converter clean help @@ -32,7 +49,7 @@ char-converter: $(CHAR_CONVERTER_DEPENDS) @CC@ @LDFLAGS@ -o ../../tools/char-converter@EXEEXT@ $(CHAR_CONVERTER_OBJ) @LIBS@ @MYSQL_LIBS@ clean: - rm -rf *.o obj_txt obj_sql ../../tools/login-converter@EXEEXT@ ../../tools/char-converter@EXEEXT@ + rm -rf *.o obj_login obj_char ../../tools/login-converter@EXEEXT@ ../../tools/char-converter@EXEEXT@ help: @echo "possible targets are 'login-converter' 'char-converter' 'all' 'clean' 'help'" @@ -48,21 +65,24 @@ needs_mysql: @echo "MySQL not found or disabled by the configure script" @exit 1 -obj: - -mkdir obj_txt - -mkdir obj_sql +obj_login: + -mkdir obj_login +obj_char: + -mkdir obj_char -# DO NOT DELETE +obj_login/%.o: %.c $(LOGIN_CONVERTER_H) + @CC@ @CFLAGS@ @MYSQL_CFLAGS@ @CPPFLAGS@ -DTXT_SQL_CONVERT -c $(OUTPUT_OPTION) $< -%.o: %.c +obj_char/%.o: %.c $(CHAR_CONVERTER_H) @CC@ @CFLAGS@ @MYSQL_CFLAGS@ @CPPFLAGS@ -DTXT_SQL_CONVERT -c $(OUTPUT_OPTION) $< -obj_txt/%.o: ../char/%.c +obj_char/txt-%.o: ../char/%.c $(CHAR_CONVERTER_H) @CC@ @CFLAGS@ @MYSQL_CFLAGS@ @CPPFLAGS@ -DTXT_SQL_CONVERT -c $(OUTPUT_OPTION) $< -obj_sql/%.o: ../char_sql/%.c +obj_char/sql-%.o: ../char_sql/%.c $(CHAR_CONVERTER_H) @CC@ @CFLAGS@ @MYSQL_CFLAGS@ @CPPFLAGS@ -DTXT_SQL_CONVERT -c $(OUTPUT_OPTION) $< -char-converter.o: char-converter.c -login-converter.o: login-converter.c +# missing common object files +../common/obj/%.o: + @$(MAKE) -C ../common sql -- cgit v1.2.3-70-g09d2 From d157481db8a77069628b6186b9a31ea6267854ee Mon Sep 17 00:00:00 2001 From: FlavioJS Date: Fri, 30 Nov 2007 00:17:26 +0000 Subject: * Random cleanup/documentation. * Made common/Makefile get the svn version from the src directory, not src/common. * Added a warning message to the install and uninstall targets. * Renamed all obj directories to obj_all, obj_txt or obj_sql in the makefiles (if an obj/ directory exists, BSD make enters it before reading the makefile) (run ./configure to update your makefiles, and don't forget to do 'make clean' before updating) git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@11844 54d463be-8e91-2dee-dedb-b68131a5f0ec --- Changelog-Trunk.txt | 6 ++++ Makefile.in | 2 ++ src/char/Makefile.in | 26 +++++++-------- src/char_sql/Makefile.in | 26 +++++++-------- src/common/Makefile.in | 22 ++++++------ src/ladmin/Makefile.in | 22 ++++++------ src/login/Makefile.in | 24 ++++++------- src/login_sql/Makefile.in | 27 +++++++-------- src/map/Makefile.in | 32 +++++++++--------- src/map/clif.c | 78 +++++++++++++++++++++++++++++++------------ src/map/clif.h | 6 ++-- src/map/pc.c | 12 +++---- src/plugins/Makefile.in | 8 ++--- src/tool/Makefile.in | 12 +++---- src/txt-converter/Makefile.in | 17 ++++++---- 15 files changed, 184 insertions(+), 136 deletions(-) (limited to 'src/char/Makefile.in') diff --git a/Changelog-Trunk.txt b/Changelog-Trunk.txt index 00c951714..a73ad7cb9 100644 --- a/Changelog-Trunk.txt +++ b/Changelog-Trunk.txt @@ -4,6 +4,12 @@ AS OF SVN REV. 5091, WE ARE NOW USING TRUNK. ALL UNTESTED BUGFIXES/FEATURES GO IF YOU HAVE A WORKING AND TESTED BUGFIX PUT IT INTO STABLE AS WELL AS TRUNK. 2007/11/29 + * Random cleanup/documentation. + * Made common/Makefile get the svn version from the src directory, not src/common. + * Added a warning message to the install and uninstall targets. + * Renamed all obj directories to obj_all, obj_txt or obj_sql in the + makefiles (if an obj/ directory exists, BSD make enters it before + reading the makefile) [FlavioJS] * Allowed disguising while riding a peco-peco (this does not seem to cause problems anymore). * The pvp rank packet is no longer sent to other players when disguised, as diff --git a/Makefile.in b/Makefile.in index 2c1b0a95e..aa47001a1 100644 --- a/Makefile.in +++ b/Makefile.in @@ -139,6 +139,7 @@ needs_mysql: # TODO install: conf/%.conf conf/%.txt + $(shell read -p "WARNING: This target does not work properly yet. Press Ctrl+C to cancel or Enter to continue.") $(shell mkdir -p /opt/eathena/bin/) $(shell mkdir -p /opt/eathena/etc/eathena/) $(shell mkdir -p /opt/eathena/var/log/eathena/) @@ -162,6 +163,7 @@ bin-clean: $(shell rm /opt/eathena/bin/ladmin) uninstall: + $(shell read -p "WARNING: This target does not work properly yet. Press Ctrl+C to cancel or Enter to continue.") bin-clean $(shell rm /opt/eathena/bin/save) $(shell rm /opt/eathena/bin/db) diff --git a/src/char/Makefile.in b/src/char/Makefile.in index 334265819..359e19b01 100644 --- a/src/char/Makefile.in +++ b/src/char/Makefile.in @@ -1,17 +1,17 @@ -COMMON_OBJ = ../common/obj/core.o ../common/obj/socket.o ../common/obj/timer.o \ - ../common/obj/db.o ../common/obj/plugins.o ../common/obj/lock.o \ - ../common/obj/malloc.o ../common/obj/showmsg.o ../common/obj/utils.o \ - ../common/obj/strlib.o ../common/obj/grfio.o \ - ../common/obj/mapindex.o ../common/obj/ers.o +COMMON_OBJ = ../common/obj_all/core.o ../common/obj_all/socket.o ../common/obj_all/timer.o \ + ../common/obj_all/db.o ../common/obj_all/plugins.o ../common/obj_all/lock.o \ + ../common/obj_all/malloc.o ../common/obj_all/showmsg.o ../common/obj_all/utils.o \ + ../common/obj_all/strlib.o ../common/obj_all/grfio.o \ + ../common/obj_all/mapindex.o ../common/obj_all/ers.o COMMON_H = ../common/core.h ../common/socket.h ../common/timer.h ../common/mmo.h \ ../common/version.h ../common/db.h ../common/plugins.h ../common/lock.h \ ../common/malloc.h ../common/showmsg.h ../common/utils.h \ ../common/strlib.h ../common/grfio.h \ ../common/mapindex.h ../common/ers.h -CHAR_OBJ = obj/char.o obj/inter.o obj/int_party.o obj/int_guild.o \ - obj/int_storage.o obj/int_status.o obj/int_pet.o obj/int_homun.o +CHAR_OBJ = obj_txt/char.o obj_txt/inter.o obj_txt/int_party.o obj_txt/int_guild.o \ + obj_txt/int_storage.o obj_txt/int_status.o obj_txt/int_pet.o obj_txt/int_homun.o CHAR_H = char.h inter.h int_party.h int_guild.h int_storage.h int_status.h int_pet.h int_homun.h @SET_MAKE@ @@ -21,11 +21,11 @@ CHAR_H = char.h inter.h int_party.h int_guild.h int_storage.h int_status.h int_p all: char-server -char-server: obj $(CHAR_OBJ) $(COMMON_OBJ) +char-server: obj_txt $(CHAR_OBJ) $(COMMON_OBJ) @CC@ @LDFLAGS@ -o ../../char-server@EXEEXT@ $(CHAR_OBJ) $(COMMON_OBJ) @LIBS@ clean: - rm -rf *.o obj ../../char-server@EXEEXT@ + rm -rf *.o obj_txt ../../char-server@EXEEXT@ help: @echo "possible targets are 'char-server' 'all' 'clean' 'help'" @@ -36,12 +36,12 @@ help: ##################################################################### -obj: - -mkdir obj +obj_txt: + -mkdir obj_txt -obj/%.o: %.c $(CHAR_H) $(COMMON_H) +obj_txt/%.o: %.c $(CHAR_H) $(COMMON_H) @CC@ @CFLAGS@ -DTXT_ONLY @CPPFLAGS@ -c $(OUTPUT_OPTION) $< # missing common object files -../common/obj/%.o: +../common/obj_all/%.o: @$(MAKE) -C ../common txt diff --git a/src/char_sql/Makefile.in b/src/char_sql/Makefile.in index 8162511d5..819ddec18 100644 --- a/src/char_sql/Makefile.in +++ b/src/char_sql/Makefile.in @@ -1,9 +1,9 @@ -COMMON_OBJ = ../common/obj/core.o ../common/obj/socket.o ../common/obj/timer.o \ - ../common/obj/db.o ../common/obj/plugins.o ../common/obj/lock.o \ - ../common/obj/malloc.o ../common/obj/showmsg.o ../common/obj/utils.o \ - ../common/obj/strlib.o ../common/obj/grfio.o \ - ../common/obj/mapindex.o ../common/obj/ers.o +COMMON_OBJ = ../common/obj_all/core.o ../common/obj_all/socket.o ../common/obj_all/timer.o \ + ../common/obj_all/db.o ../common/obj_all/plugins.o ../common/obj_all/lock.o \ + ../common/obj_all/malloc.o ../common/obj_all/showmsg.o ../common/obj_all/utils.o \ + ../common/obj_all/strlib.o ../common/obj_all/grfio.o \ + ../common/obj_all/mapindex.o ../common/obj_all/ers.o COMMON_H = ../common/core.h ../common/socket.h ../common/timer.h ../common/mmo.h \ ../common/version.h ../common/db.h ../common/plugins.h ../common/lock.h \ ../common/malloc.h ../common/showmsg.h ../common/utils.h \ @@ -13,13 +13,13 @@ COMMON_H = ../common/core.h ../common/socket.h ../common/timer.h ../common/mmo.h COMMON_SQL_OBJ = ../common/obj_sql/sql.o COMMON_H = ../common/sql.h -CHAR_OBJ = obj/char.o obj/inter.o obj/int_party.o obj/int_guild.o \ - obj/int_storage.o obj/int_pet.o obj/int_homun.o obj/int_mail.o +CHAR_OBJ = obj_sql/char.o obj_sql/inter.o obj_sql/int_party.o obj_sql/int_guild.o \ + obj_sql/int_storage.o obj_sql/int_pet.o obj_sql/int_homun.o obj_sql/int_mail.o CHAR_H = char.h inter.h int_party.h int_guild.h int_storage.h int_pet.h int_homun.h int_mail.h HAVE_MYSQL=@HAVE_MYSQL@ ifeq ($(HAVE_MYSQL),yes) - CHAR_SERVER_SQL_DEPENDS=obj $(CHAR_OBJ) $(COMMON_OBJ) $(COMMON_SQL_OBJ) + CHAR_SERVER_SQL_DEPENDS=obj_sql $(CHAR_OBJ) $(COMMON_OBJ) $(COMMON_SQL_OBJ) else CHAR_SERVER_SQL_DEPENDS=needs_mysql endif @@ -35,7 +35,7 @@ char-server_sql: $(CHAR_SERVER_SQL_DEPENDS) @CC@ @LDFLAGS@ -o ../../char-server_sql@EXEEXT@ $(CHAR_OBJ) $(COMMON_OBJ) $(COMMON_SQL_OBJ) @LIBS@ @MYSQL_LIBS@ clean: - rm -rf *.o obj ../../char-server_sql@EXEEXT@ + rm -rf *.o obj_sql ../../char-server_sql@EXEEXT@ help: @echo "possible targets are 'char-server_sql' 'all' 'clean' 'help'" @@ -50,14 +50,14 @@ needs_mysql: @echo "MySQL not found or disabled by the configure script" @exit 1 -obj: - -mkdir obj +obj_sql: + -mkdir obj_sql -obj/%.o: %.c $(CHAR_H) $(COMMON_H) $(COMMON_SQL_H) +obj_sql/%.o: %.c $(CHAR_H) $(COMMON_H) $(COMMON_SQL_H) @CC@ @CFLAGS@ @MYSQL_CFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $< # missing common object files -../common/obj/%.o: +../common/obj_all/%.o: @$(MAKE) -C ../common sql ../common/obj_sql/%.o: diff --git a/src/common/Makefile.in b/src/common/Makefile.in index 89bb8a75a..bda9e1911 100644 --- a/src/common/Makefile.in +++ b/src/common/Makefile.in @@ -1,8 +1,8 @@ -COMMON_OBJ = obj/core.o obj/socket.o obj/timer.o obj/db.o obj/plugins.o obj/lock.o \ - obj/nullpo.o obj/malloc.o obj/showmsg.o obj/strlib.o obj/utils.o \ - obj/grfio.o obj/mapindex.o obj/ers.o obj/md5calc.o \ - obj/minicore.o obj/minisocket.o obj/minimalloc.o +COMMON_OBJ = obj_all/core.o obj_all/socket.o obj_all/timer.o obj_all/db.o obj_all/plugins.o obj_all/lock.o \ + obj_all/nullpo.o obj_all/malloc.o obj_all/showmsg.o obj_all/strlib.o obj_all/utils.o \ + obj_all/grfio.o obj_all/mapindex.o obj_all/ers.o obj_all/md5calc.o \ + obj_all/minicore.o obj_all/minisocket.o obj_all/minimalloc.o COMMON_H = svnversion.h mmo.h plugin.h version.h \ core.h socket.h timer.h db.h plugins.h lock.h \ nullpo.h malloc.h showmsg.h strlib.h utils.h \ @@ -32,7 +32,7 @@ txt: common sql: $(SQL_DEPENDS) clean: - rm -rf *.o obj obj_sql svnversion.h + rm -rf *.o obj_all obj_sql svnversion.h help: @echo "possible targets are 'txt' 'sql' 'all' 'clean' 'help'" @@ -48,21 +48,21 @@ needs_mysql: @echo "MySQL not found or disabled by the configure script" @exit 1 -obj: - -mkdir obj +obj_all: + -mkdir obj_all obj_sql: -mkdir obj_sql -common: obj $(COMMON_OBJ) +common: obj_all $(COMMON_OBJ) common_sql: obj_sql $(COMMON_SQL_OBJ) -obj/%.o: %.c $(COMMON_H) +obj_all/%.o: %.c $(COMMON_H) @CC@ @CFLAGS@ @LDFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $< -obj/mini%.o: %.c $(COMMON_H) +obj_all/mini%.o: %.c $(COMMON_H) @CC@ @CFLAGS@ -DMINICORE @LDFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $< obj_sql/%.o: %.c $(COMMON_H) $(COMMON_SQL_H) @@ -74,7 +74,7 @@ HAVESVN = $(shell which svnversion) ifeq ($(findstring /,$(HAVESVN)), /) svnversion.h: @printf "#define SVNVERSION " > svnversion.h - @svnversion . >> svnversion.h + @svnversion .. >> svnversion.h @printf "\n" >> svnversion.h else svnversion.h: diff --git a/src/ladmin/Makefile.in b/src/ladmin/Makefile.in index 87cc2ad49..4703dded1 100644 --- a/src/ladmin/Makefile.in +++ b/src/ladmin/Makefile.in @@ -1,12 +1,12 @@ -COMMON_OBJ = ../common/obj/minicore.o ../common/obj/minisocket.o ../common/obj/timer.o \ - ../common/obj/malloc.o ../common/obj/showmsg.o ../common/obj/strlib.o \ - ../common/obj/utils.o ../common/obj/md5calc.o +COMMON_OBJ = ../common/obj_all/minicore.o ../common/obj_all/minisocket.o ../common/obj_all/timer.o \ + ../common/obj_all/malloc.o ../common/obj_all/showmsg.o ../common/obj_all/strlib.o \ + ../common/obj_all/utils.o ../common/obj_all/md5calc.o COMMON_H = ../common/core.h ../common/socket.h ../common/timer.h ../common/mmo.h \ ../common/version.h ../common/malloc.h ../common/showmsg.h ../common/strlib.h \ ../common/utils.h ../common/md5calc.h ../common/cbasetypes.h -LADMIN_OBJ = obj/ladmin.o +LADMIN_OBJ = obj_all/ladmin.o LADMIN_H = ladmin.h @SET_MAKE@ @@ -16,11 +16,11 @@ LADMIN_H = ladmin.h all: ladmin -ladmin: obj $(LADMIN_OBJ) $(COMMON_OBJ) +ladmin: obj_all $(LADMIN_OBJ) $(COMMON_OBJ) @CC@ @LDFLAGS@ -o ../../ladmin@EXEEXT@ $(LADMIN_OBJ) $(COMMON_OBJ) @LIBS@ clean: - rm -rf *.o obj ../../ladmin@EXEEXT@ + rm -rf *.o obj_all ../../ladmin@EXEEXT@ help: @echo "possible targets are 'ladmin' 'all' 'clean' 'help'" @@ -31,15 +31,15 @@ help: ##################################################################### -obj: - -mkdir obj +obj_all: + -mkdir obj_all -obj/%.o: %.c $(LADMIN_H) $(COMMON_H) +obj_all/%.o: %.c $(LADMIN_H) $(COMMON_H) @CC@ @CFLAGS@ @LDFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $< # missing common object files -../common/obj/%.o: +../common/obj_all/%.o: @$(MAKE) -C ../common txt -../common/obj/mini%.o: +../common/obj_all/mini%.o: @$(MAKE) -C ../common txt diff --git a/src/login/Makefile.in b/src/login/Makefile.in index 4bdfb5935..0c194fac4 100644 --- a/src/login/Makefile.in +++ b/src/login/Makefile.in @@ -1,16 +1,16 @@ -COMMON_OBJ = ../common/obj/core.o ../common/obj/socket.o ../common/obj/timer.o \ - ../common/obj/db.o ../common/obj/plugins.o ../common/obj/lock.o \ - ../common/obj/malloc.o ../common/obj/showmsg.o ../common/obj/utils.o \ - ../common/obj/strlib.o ../common/obj/grfio.o ../common/obj/mapindex.o \ - ../common/obj/ers.o ../common/obj/md5calc.o +COMMON_OBJ = ../common/obj_all/core.o ../common/obj_all/socket.o ../common/obj_all/timer.o \ + ../common/obj_all/db.o ../common/obj_all/plugins.o ../common/obj_all/lock.o \ + ../common/obj_all/malloc.o ../common/obj_all/showmsg.o ../common/obj_all/utils.o \ + ../common/obj_all/strlib.o ../common/obj_all/grfio.o ../common/obj_all/mapindex.o \ + ../common/obj_all/ers.o ../common/obj_all/md5calc.o COMMON_H = ../common/core.h ../common/socket.h ../common/timer.h ../common/mmo.h \ ../common/version.h ../common/db.h ../common/plugins.h ../common/lock.h \ ../common/malloc.h ../common/showmsg.h ../common/utils.h ../common/strlib.h \ ../common/grfio.h ../common/mapindex.h \ ../common/ers.h ../common/md5calc.h -LOGIN_OBJ = obj/login.o obj/admin.o +LOGIN_OBJ = obj_txt/login.o obj_txt/admin.o LOGIN_H = login.h @SET_MAKE@ @@ -20,11 +20,11 @@ LOGIN_H = login.h all: login-server -login-server: obj $(LOGIN_OBJ) $(COMMON_OBJ) +login-server: obj_txt $(LOGIN_OBJ) $(COMMON_OBJ) @CC@ @LDFLAGS@ -o ../../login-server@EXEEXT@ $(LOGIN_OBJ) $(COMMON_OBJ) @LIBS@ clean: - rm -rf *.o obj ../../login-server@EXEEXT@ + rm -rf *.o obj_txt ../../login-server@EXEEXT@ help: @echo "possible targets are 'login-server' 'all' 'clean' 'help'" @@ -35,12 +35,12 @@ help: ##################################################################### -obj: - -mkdir obj +obj_txt: + -mkdir obj_txt -obj/%.o: %.c $(LOGIN_H) $(COMMON_H) +obj_txt/%.o: %.c $(LOGIN_H) $(COMMON_H) @CC@ @CFLAGS@ -DTXT_ONLY @CPPFLAGS@ -c $(OUTPUT_OPTION) $< # missing common object files -../common/obj/%.o: +../common/obj_all/%.o: @$(MAKE) -C ../common sql diff --git a/src/login_sql/Makefile.in b/src/login_sql/Makefile.in index 22a1437b3..72d23b183 100644 --- a/src/login_sql/Makefile.in +++ b/src/login_sql/Makefile.in @@ -1,20 +1,21 @@ -COMMON_OBJ = ../common/obj/core.o ../common/obj/socket.o ../common/obj/timer.o \ - ../common/obj/db.o ../common/obj/plugins.o ../common/obj/lock.o \ - ../common/obj/malloc.o ../common/obj/showmsg.o ../common/obj/utils.o \ - ../common/obj/strlib.o ../common/obj/grfio.o ../common/obj/mapindex.o \ - ../common/obj/ers.o ../common/obj/md5calc.o ../common/obj_sql/sql.o + +COMMON_OBJ = ../common/obj_all/core.o ../common/obj_all/socket.o ../common/obj_all/timer.o \ + ../common/obj_all/db.o ../common/obj_all/plugins.o ../common/obj_all/lock.o \ + ../common/obj_all/malloc.o ../common/obj_all/showmsg.o ../common/obj_all/utils.o \ + ../common/obj_all/strlib.o ../common/obj_all/grfio.o ../common/obj_all/mapindex.o \ + ../common/obj_all/ers.o ../common/obj_all/md5calc.o ../common/obj_sql/sql.o COMMON_H = ../common/core.h ../common/socket.h ../common/timer.h ../common/mmo.h \ ../common/version.h ../common/db.h ../common/plugins.h ../common/lock.h \ ../common/malloc.h ../common/showmsg.h ../common/utils.h ../common/strlib.h \ ../common/grfio.h ../common/mapindex.h \ - ../common/ers.h ../common/md5calc.h ../common/sql.h + ../common/ers.h ../common/md5calc.h ../common/sql.h -LOGIN_OBJ = obj/login.o +LOGIN_OBJ = obj_sql/login.o LOGIN_H = login.h HAVE_MYSQL=@HAVE_MYSQL@ ifeq ($(HAVE_MYSQL),yes) - LOGIN_SERVER_SQL_DEPENDS=obj $(LOGIN_OBJ) $(COMMON_OBJ) + LOGIN_SERVER_SQL_DEPENDS=obj_sql $(LOGIN_OBJ) $(COMMON_OBJ) else LOGIN_SERVER_SQL_DEPENDS=needs_mysql endif @@ -30,7 +31,7 @@ login-server_sql: $(LOGIN_SERVER_SQL_DEPENDS) @CC@ @LDFLAGS@ -o ../../login-server_sql@EXEEXT@ $(LOGIN_OBJ) $(COMMON_OBJ) @LIBS@ @MYSQL_LIBS@ clean: - rm -rf *.o obj ../../login-server_sql@EXEEXT@ + rm -rf *.o obj_sql ../../login-server_sql@EXEEXT@ help: @echo "possible targets are 'login-server_sql' 'all' 'clean' 'help'" @@ -45,14 +46,14 @@ needs_mysql: @echo "MySQL not found or disabled by the configure script" @exit 1 -obj: - -mkdir obj +obj_sql: + -mkdir obj_sql -obj/%.o: %.c $(LOGIN_H) $(COMMON_H) +obj_sql/%.o: %.c $(LOGIN_H) $(COMMON_H) @CC@ @CFLAGS@ @MYSQL_CFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $< # missing common object files -../common/obj/%.o: +../common/obj_all/%.o: @$(MAKE) -C ../common sql ../common/obj_sql/%.o: diff --git a/src/map/Makefile.in b/src/map/Makefile.in index 31c0fc3f1..355086127 100644 --- a/src/map/Makefile.in +++ b/src/map/Makefile.in @@ -1,9 +1,9 @@ -COMMON_OBJ = ../common/obj/core.o ../common/obj/socket.o ../common/obj/timer.o \ - ../common/obj/db.o ../common/obj/plugins.o ../common/obj/lock.o \ - ../common/obj/nullpo.o ../common/obj/malloc.o ../common/obj/showmsg.o \ - ../common/obj/utils.o ../common/obj/strlib.o ../common/obj/grfio.o \ - ../common/obj/mapindex.o ../common/obj/ers.o +COMMON_OBJ = ../common/obj_all/core.o ../common/obj_all/socket.o ../common/obj_all/timer.o \ + ../common/obj_all/db.o ../common/obj_all/plugins.o ../common/obj_all/lock.o \ + ../common/obj_all/nullpo.o ../common/obj_all/malloc.o ../common/obj_all/showmsg.o \ + ../common/obj_all/utils.o ../common/obj_all/strlib.o ../common/obj_all/grfio.o \ + ../common/obj_all/mapindex.o ../common/obj_all/ers.o COMMON_H = ../common/core.h ../common/socket.h ../common/timer.h \ ../common/db.h ../common/plugins.h ../common/lock.h \ ../common/nullpo.h ../common/malloc.h ../common/showmsg.h \ @@ -13,11 +13,13 @@ COMMON_H = ../common/core.h ../common/socket.h ../common/timer.h \ COMMON_SQL_OBJ = ../common/obj_sql/sql.o COMMON_SQL_H = ../common/sql.h -MAP_OBJ = obj/map.o obj/chrif.o obj/clif.o obj/pc.o obj/status.o obj/npc.o \ - obj/npc_chat.o obj/chat.o obj/path.o obj/itemdb.o obj/mob.o obj/script.o \ - obj/storage.o obj/skill.o obj/atcommand.o obj/charcommand.o obj/battle.o \ - obj/intif.o obj/trade.o obj/party.o obj/vending.o obj/guild.o obj/pet.o \ - obj/log.o obj/mail.o obj/date.o obj/irc.o obj/unit.o obj/mercenary.o +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 charcommand.o battle.o \ + intif.o trade.o party.o vending.o guild.o pet.o \ + log.o mail.o date.o irc.o unit.o mercenary.o +MAP_TXT_OBJ = $(MAP_OBJ:%=obj_txt/%) +MAP_SQL_OBJ = $(MAP_OBJ:%=obj_sql/%) MAP_H = map.h chrif.h clif.h pc.h status.h npc.h \ chat.h itemdb.h mob.h script.h \ storage.h skill.h atcommand.h charcommand.h battle.h \ @@ -80,11 +82,11 @@ obj_sql: -mkdir obj_sql # executables -map-server: obj_txt $(MAP_OBJ:obj/%=obj_txt/%) $(COMMON_OBJ) - @CC@ @LDFLAGS@ -o ../../map-server@EXEEXT@ $(MAP_OBJ:obj/%=obj_txt/%) $(COMMON_OBJ) @LIBS@ @PCRE_LIBS@ +map-server: obj_txt $(MAP_TXT_OBJ) $(COMMON_OBJ) + @CC@ @LDFLAGS@ -o ../../map-server@EXEEXT@ $(MAP_TXT_OBJ) $(COMMON_OBJ) @LIBS@ @PCRE_LIBS@ -map-server_sql: obj_sql $(MAP_OBJ:obj/%=obj_sql/%) $(COMMON_OBJ) $(COMMON_SQL_OBJ) - @CC@ @LDFLAGS@ -o ../../map-server_sql@EXEEXT@ $(MAP_OBJ:obj/%=obj_sql/%) $(COMMON_OBJ) $(COMMON_SQL_OBJ) @LIBS@ @PCRE_LIBS@ @MYSQL_LIBS@ +map-server_sql: obj_sql $(MAP_SQL_OBJ) $(COMMON_OBJ) $(COMMON_SQL_OBJ) + @CC@ @LDFLAGS@ -o ../../map-server_sql@EXEEXT@ $(MAP_SQL_OBJ) $(COMMON_OBJ) $(COMMON_SQL_OBJ) @LIBS@ @PCRE_LIBS@ @MYSQL_LIBS@ # map object files obj_txt/%.o: %.c $(MAP_H) $(COMMON_H) @@ -94,7 +96,7 @@ obj_sql/%.o: %.c $(MAP_H) $(COMMON_H) $(COMMON_SQL_H) @CC@ @CFLAGS@ $(PCRE_CFLAGS) @MYSQL_CFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $< # missing common object files -../common/obj/%.o: +../common/obj_all/%.o: @$(MAKE) -C ../common txt ../common/obj_sql/%.o: diff --git a/src/map/clif.c b/src/map/clif.c index 5f59bda74..2a45b1b79 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -4396,35 +4396,44 @@ void clif_skill_warppoint(struct map_session_data* sd, short skill_num, short sk else sd->menuskill_val = skill_lv; } -/*========================================== - * メモ応答 - *------------------------------------------*/ -int clif_skill_memo(struct map_session_data *sd,int flag) + +/// Memo message. +/// type=0 : "Saved location as a Memo Point for Warp skill." in color 0xFFFF00 (cyan) +/// type=1 : "Skill Level is not high enough." in color 0x0000FF (red) +/// type=2 : "You haven't learned Warp." in color 0x0000FF (red) +/// +/// @param sd Who receives the message +/// @param type What message +void clif_skill_memomessage(struct map_session_data* sd, int type) { int fd; - nullpo_retr(0, sd); + nullpo_retv(sd); fd=sd->fd; - WFIFOHEAD(fd,packet_len(0x11e)); WFIFOW(fd,0)=0x11e; - WFIFOB(fd,2)=flag; + WFIFOB(fd,2)=type; WFIFOSET(fd,packet_len(0x11e)); - return 0; } -int clif_skill_teleportmessage(struct map_session_data *sd,int flag) + +/// Teleport message. +/// type=0 : "Unable to Teleport in this area" in color 0xFFFF00 (cyan) +/// type=1 : "Saved point cannot be memorized." in color 0x0000FF (red) +/// +/// @param sd Who receives the message +/// @param type What message +void clif_skill_teleportmessage(struct map_session_data *sd, int type) { int fd; - nullpo_retr(0, sd); + nullpo_retv(sd); fd=sd->fd; WFIFOHEAD(fd,packet_len(0x189)); WFIFOW(fd,0)=0x189; - WFIFOW(fd,2)=flag; + WFIFOW(fd,2)=type; WFIFOSET(fd,packet_len(0x189)); - return 0; } /*========================================== @@ -4700,18 +4709,43 @@ int clif_resurrection(struct block_list *bl,int type) return 0; } -/*========================================== - * PVP実装?(仮) - *------------------------------------------*/ -int clif_set0199(int fd,int type) +/// Sets the map mode. +/// +/// mode=1 : pvp mode +/// mode=2 : unknown mode (pk?) +/// mode=3 : gvg mode +/// mode=4 : message "You are in a PK area. Please beware of sudden attacks." in color 0x9B9BFF (light red) +/// mode=5 : pvp mode +/// mode=other : ? +void clif_set0199(struct map_session_data* sd, int mode) { + int fd; + + nullpo_retv(sd); + + fd=sd->fd; WFIFOHEAD(fd,packet_len(0x199)); WFIFOW(fd,0)=0x199; - WFIFOW(fd,2)=type; + WFIFOW(fd,2)=mode; WFIFOSET(fd,packet_len(0x199)); +} - return 0; +#if 0 +/// Set the map mode? +/// Differs from the behaviour of clif_set0199 with unknown consequences. +void clif_set01D6(struct map_session_data* sd, int mode) +{ + int fd; + + nullpo_retv(sd); + + fd=sd->fd; + WFIFOHEAD(fd,packet_len(0x1D6)); + WFIFOW(fd,0)=0x1D6; + WFIFOW(fd,2)=mode; + WFIFOSET(fd,packet_len(0x1D6)); } +#endif /*========================================== * PVP実装?(仮) @@ -7762,15 +7796,15 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd) sd->pvp_won = 0; sd->pvp_lost = 0; } - clif_set0199(fd,1); + clif_set0199(sd,1); } else // set flag, if it's a duel [LuzZza] if(sd->duel_group) - clif_set0199(fd,1); + clif_set0199(sd,1); if (map[sd->bl.m].flag.gvg_dungeon) { - clif_set0199(fd,1); //TODO: Figure out the real packet to send here. + clif_set0199(sd,1); //TODO: Figure out the real packet to send here. if (!sd->pvp_point) { sd->pvp_point = 5; //Need to die twice to be warped out. @@ -7780,7 +7814,7 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd) } if(map_flag_gvg(sd->bl.m)) - clif_set0199(fd,3); + clif_set0199(sd,3); // info about nearby objects // must use foreachinarea (CIRCULAR_AREA interferes with foreachinrange) diff --git a/src/map/clif.h b/src/map/clif.h index a1246f97a..b68645da9 100644 --- a/src/map/clif.h +++ b/src/map/clif.h @@ -213,8 +213,8 @@ int clif_skill_nodamage(struct block_list *src,struct block_list *dst,int skill_ int clif_skill_poseffect(struct block_list *src,int skill_id,int val,int x,int y,int tick); int clif_skill_estimation(struct map_session_data *sd,struct block_list *dst); void clif_skill_warppoint(struct map_session_data* sd, short skill_num, short skill_lv, unsigned short map1, unsigned short map2, unsigned short map3, unsigned short map4); -int clif_skill_memo(struct map_session_data *sd,int flag); -int clif_skill_teleportmessage(struct map_session_data *sd,int flag); +void clif_skill_memomessage(struct map_session_data* sd, int type); +void clif_skill_teleportmessage(struct map_session_data* sd, int type); int clif_skill_produce_mix_list(struct map_session_data *sd, int trigger); int clif_produceeffect(struct map_session_data* sd,int flag,int nameid); @@ -331,7 +331,7 @@ void clif_MainChatMessage(const char* message); //luzza int clif_announce(struct block_list *bl, const char* mes, int len, unsigned long color, int flag); int clif_heal(int fd,int type,int val); int clif_resurrection(struct block_list *bl,int type); -int clif_set0199(int fd,int type); +void clif_set0199(struct map_session_data* sd, int mode); int clif_pvpset(struct map_session_data *sd, int pvprank, int pvpnum,int type); int clif_send0199(int map,int type); void clif_refine(int fd, int fail, int index, int val); diff --git a/src/map/pc.c b/src/map/pc.c index fc39ea88d..852d06e5e 100644 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -3603,11 +3603,11 @@ int pc_memo(struct map_session_data* sd, int pos) // check required skill level skill = pc_checkskill(sd, AL_WARP); if( skill < 1 ) { - clif_skill_memo(sd,2); // "You haven't learned Warp." + clif_skill_memomessage(sd,2); // "You haven't learned Warp." return 0; } if( skill < 2 || skill - 2 < pos ) { - clif_skill_memo(sd,1); // "Skill Level is not high enough." + clif_skill_memomessage(sd,1); // "Skill Level is not high enough." return 0; } @@ -3624,7 +3624,7 @@ int pc_memo(struct map_session_data* sd, int pos) sd->status.memo_point[pos].x = sd->bl.x; sd->status.memo_point[pos].y = sd->bl.y; - clif_skill_memo(sd, 0); + clif_skill_memomessage(sd, 0); return 1; } @@ -7173,7 +7173,7 @@ int duel_create(struct map_session_data* sd, const unsigned int maxpl) strcpy(output, msg_txt(372)); // " -- Duel has been created (@invite/@leave) --" clif_disp_onlyself(sd, output, strlen(output)); - clif_set0199(sd->fd, 1); + clif_set0199(sd, 1); //clif_misceffect2(&sd->bl, 159); return i; } @@ -7220,7 +7220,7 @@ int duel_leave(const unsigned int did, struct map_session_data* sd) sd->duel_group = 0; duel_savetime(sd); - clif_set0199(sd->fd, 0); + clif_set0199(sd, 0); return 0; } @@ -7237,7 +7237,7 @@ int duel_accept(const unsigned int did, struct map_session_data* sd) sprintf(output, msg_txt(376), sd->status.name); clif_disp_message(&sd->bl, output, strlen(output), DUEL_WOS); - clif_set0199(sd->fd, 1); + clif_set0199(sd, 1); //clif_misceffect2(&sd->bl, 159); return 0; } diff --git a/src/plugins/Makefile.in b/src/plugins/Makefile.in index 00493a7c9..7019fadd8 100644 --- a/src/plugins/Makefile.in +++ b/src/plugins/Makefile.in @@ -1,6 +1,6 @@ -COMMON_OBJ = ../common/obj/showmsg.o ../common/obj/utils.o ../common/obj/strlib.o \ - ../common/obj/minimalloc.o +COMMON_OBJ = ../common/obj_all/showmsg.o ../common/obj_all/utils.o ../common/obj_all/strlib.o \ + ../common/obj_all/minimalloc.o COMMON_H = ../common/plugin.h ../common/cbasetypes.h \ ../common/showmsg.h ../common/utils.h ../common/strlib.h \ ../common/malloc.h @@ -56,8 +56,8 @@ sig@DLLEXT@: sig.c $(COMMON_OBJ) cp -r $< $@ # missing common object files -../common/obj/%.o: ../common/%.c $(COMMON_H) +../common/obj_all/%.o: ../common/%.c $(COMMON_H) @$(MAKE) -C ../common txt -../common/obj/mini%.o: ../common/%.c $(COMMON_H) +../common/obj_all/mini%.o: ../common/%.c $(COMMON_H) @$(MAKE) -C ../common txt diff --git a/src/tool/Makefile.in b/src/tool/Makefile.in index 277ff4c68..f1d688a7d 100644 --- a/src/tool/Makefile.in +++ b/src/tool/Makefile.in @@ -12,12 +12,12 @@ adduser: convert: @CC@ -o ../../tools/convert@EXEEXT@ convert.c -mapcache: obj - @CC@ -c -o obj/grfio.o grfio.c - @CC@ -o ../../mapcache@EXEEXT@ mapcache.c obj/grfio.o -lz +mapcache: obj_mapcache + @CC@ -c -o obj_mapcache/grfio.o grfio.c + @CC@ -o ../../mapcache@EXEEXT@ mapcache.c obj_mapcache/grfio.o -lz clean: - rm -rf *.o obj ../../tools/adduser@EXEEXT@ ../../tools/convert@EXEEXT@ ../../mapcache@EXEEXT@ + rm -rf *.o obj_mapcache ../../tools/adduser@EXEEXT@ ../../tools/convert@EXEEXT@ ../../mapcache@EXEEXT@ help: @echo "possible targets are 'adduser' 'convert' 'mapcache' 'all' 'clean' 'help'" @@ -30,5 +30,5 @@ help: ##################################################################### -obj: - -mkdir obj +obj_mapcache: + -mkdir obj_mapcache diff --git a/src/txt-converter/Makefile.in b/src/txt-converter/Makefile.in index 59d3a6641..c90a6a4b2 100644 --- a/src/txt-converter/Makefile.in +++ b/src/txt-converter/Makefile.in @@ -1,7 +1,7 @@ -LOGIN_CONVERTER_OBJ = obj_login/login-converter.o ../common/obj/minicore.o \ - ../common/obj/malloc.o ../common/obj/strlib.o ../common/obj/showmsg.o \ - ../common/obj/utils.o ../common/obj/ers.o ../common/obj/db.o \ +LOGIN_CONVERTER_OBJ = obj_login/login-converter.o ../common/obj_all/minicore.o \ + ../common/obj_all/malloc.o ../common/obj_all/strlib.o ../common/obj_all/showmsg.o \ + ../common/obj_all/utils.o ../common/obj_all/ers.o ../common/obj_all/db.o \ ../common/obj_sql/sql.o LOGIN_CONVERTER_H = ../common/cbasetypes.h ../common/mmo.h ../common/core.h \ ../common/malloc.h ../common/strlib.h ../common/showmsg.h \ @@ -13,9 +13,9 @@ CHAR_CONVERTER_OBJ = obj_char/char-converter.o \ obj_char/txt-int_party.o obj_char/txt-int_guild.o \ obj_char/sql-char.o obj_char/sql-int_pet.o obj_char/sql-int_storage.o \ obj_char/sql-inter.o obj_char/sql-int_party.o obj_char/sql-int_guild.o \ - ../common/obj/minicore.o \ - ../common/obj/malloc.o ../common/obj/strlib.o ../common/obj/showmsg.o \ - ../common/obj/utils.o ../common/obj/ers.o ../common/obj/mapindex.o \ + ../common/obj_all/minicore.o \ + ../common/obj_all/malloc.o ../common/obj_all/strlib.o ../common/obj_all/showmsg.o \ + ../common/obj_all/utils.o ../common/obj_all/ers.o ../common/obj_all/mapindex.o \ ../common/obj_sql/sql.o CHAR_CONVERTER_H = ../char/char.h ../char/int_pet.h ../char/int_storage.h ../char/inter.h \ ../char/int_party.h ../char/int_guild.h \ @@ -84,5 +84,8 @@ obj_char/sql-%.o: ../char_sql/%.c $(CHAR_CONVERTER_H) @CC@ @CFLAGS@ @MYSQL_CFLAGS@ @CPPFLAGS@ -DTXT_SQL_CONVERT -c $(OUTPUT_OPTION) $< # missing common object files -../common/obj/%.o: +../common/obj_all/%.o: + @$(MAKE) -C ../common sql + +../common/obj_sql/%.o: @$(MAKE) -C ../common sql -- cgit v1.2.3-70-g09d2 From 7b595ae429f84872a3004e24ee74ffe905500f22 Mon Sep 17 00:00:00 2001 From: Lupus Date: Fri, 22 Feb 2008 17:00:59 +0000 Subject: Added $(CUSTOM_CFLAGS) into all Makefile.in to provide any custom defs directly to all sub make files git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@12230 54d463be-8e91-2dee-dedb-b68131a5f0ec --- Changelog-Trunk.txt | 4 ++++ src/char/Makefile.in | 2 +- src/char_sql/Makefile.in | 2 +- src/common/Makefile.in | 6 +++--- src/ladmin/Makefile.in | 2 +- src/login/Makefile.in | 2 +- src/login_sql/Makefile.in | 2 +- src/map/Makefile.in | 4 ++-- src/plugins/Makefile.in | 2 +- 9 files changed, 15 insertions(+), 11 deletions(-) (limited to 'src/char/Makefile.in') diff --git a/Changelog-Trunk.txt b/Changelog-Trunk.txt index c928ed2fd..9bf6640bc 100644 --- a/Changelog-Trunk.txt +++ b/Changelog-Trunk.txt @@ -3,6 +3,10 @@ Date Added AS OF SVN REV. 5091, WE ARE NOW USING TRUNK. ALL UNTESTED BUGFIXES/FEATURES GO INTO TRUNK. IF YOU HAVE A WORKING AND TESTED BUGFIX PUT IT INTO STABLE AS WELL AS TRUNK. +2007/02/22 + * Added $(CUSTOM_CFLAGS) into all Makefile.in to provide any custom defs + directly to all sub make files. How to use: + make CUSTOM_CFLAGS='-DSOME_DEF' sql [Lupus] 2007/02/21 * Added status_calc_life to properly calculate hp/max_hp as a ratio taking into accounts overflows (and for now also avoids divisions by 0). Applied diff --git a/src/char/Makefile.in b/src/char/Makefile.in index 359e19b01..37b464991 100644 --- a/src/char/Makefile.in +++ b/src/char/Makefile.in @@ -40,7 +40,7 @@ obj_txt: -mkdir obj_txt obj_txt/%.o: %.c $(CHAR_H) $(COMMON_H) - @CC@ @CFLAGS@ -DTXT_ONLY @CPPFLAGS@ -c $(OUTPUT_OPTION) $< + @CC@ @CFLAGS@ $(CUSTOM_CFLAGS) -DTXT_ONLY @CPPFLAGS@ -c $(OUTPUT_OPTION) $< # missing common object files ../common/obj_all/%.o: diff --git a/src/char_sql/Makefile.in b/src/char_sql/Makefile.in index 819ddec18..8a422dcf7 100644 --- a/src/char_sql/Makefile.in +++ b/src/char_sql/Makefile.in @@ -54,7 +54,7 @@ obj_sql: -mkdir obj_sql obj_sql/%.o: %.c $(CHAR_H) $(COMMON_H) $(COMMON_SQL_H) - @CC@ @CFLAGS@ @MYSQL_CFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $< + @CC@ @CFLAGS@ $(CUSTOM_CFLAGS) @MYSQL_CFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $< # missing common object files ../common/obj_all/%.o: diff --git a/src/common/Makefile.in b/src/common/Makefile.in index bda9e1911..75450f46a 100644 --- a/src/common/Makefile.in +++ b/src/common/Makefile.in @@ -60,13 +60,13 @@ common_sql: obj_sql $(COMMON_SQL_OBJ) obj_all/%.o: %.c $(COMMON_H) - @CC@ @CFLAGS@ @LDFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $< + @CC@ @CFLAGS@ $(CUSTOM_CFLAGS) @LDFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $< obj_all/mini%.o: %.c $(COMMON_H) - @CC@ @CFLAGS@ -DMINICORE @LDFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $< + @CC@ @CFLAGS@ $(CUSTOM_CFLAGS) -DMINICORE @LDFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $< obj_sql/%.o: %.c $(COMMON_H) $(COMMON_SQL_H) - @CC@ @CFLAGS@ @MYSQL_CFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $< + @CC@ @CFLAGS@ $(CUSTOM_CFLAGS) @MYSQL_CFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $< HAVESVN = $(shell which svnversion) diff --git a/src/ladmin/Makefile.in b/src/ladmin/Makefile.in index 4703dded1..365252f63 100644 --- a/src/ladmin/Makefile.in +++ b/src/ladmin/Makefile.in @@ -35,7 +35,7 @@ obj_all: -mkdir obj_all obj_all/%.o: %.c $(LADMIN_H) $(COMMON_H) - @CC@ @CFLAGS@ @LDFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $< + @CC@ @CFLAGS@ $(CUSTOM_CFLAGS) @LDFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $< # missing common object files ../common/obj_all/%.o: diff --git a/src/login/Makefile.in b/src/login/Makefile.in index 0c194fac4..aeb41b667 100644 --- a/src/login/Makefile.in +++ b/src/login/Makefile.in @@ -39,7 +39,7 @@ obj_txt: -mkdir obj_txt obj_txt/%.o: %.c $(LOGIN_H) $(COMMON_H) - @CC@ @CFLAGS@ -DTXT_ONLY @CPPFLAGS@ -c $(OUTPUT_OPTION) $< + @CC@ @CFLAGS@ $(CUSTOM_CFLAGS) -DTXT_ONLY @CPPFLAGS@ -c $(OUTPUT_OPTION) $< # missing common object files ../common/obj_all/%.o: diff --git a/src/login_sql/Makefile.in b/src/login_sql/Makefile.in index 72d23b183..05bd9262e 100644 --- a/src/login_sql/Makefile.in +++ b/src/login_sql/Makefile.in @@ -50,7 +50,7 @@ obj_sql: -mkdir obj_sql obj_sql/%.o: %.c $(LOGIN_H) $(COMMON_H) - @CC@ @CFLAGS@ @MYSQL_CFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $< + @CC@ @CFLAGS@ $(CUSTOM_CFLAGS) @MYSQL_CFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $< # missing common object files ../common/obj_all/%.o: diff --git a/src/map/Makefile.in b/src/map/Makefile.in index 4276b976a..7799b43ce 100644 --- a/src/map/Makefile.in +++ b/src/map/Makefile.in @@ -90,10 +90,10 @@ map-server_sql: obj_sql $(MAP_SQL_OBJ) $(COMMON_OBJ) $(COMMON_SQL_OBJ) # map object files obj_txt/%.o: %.c $(MAP_H) $(COMMON_H) - @CC@ @CFLAGS@ $(PCRE_CFLAGS) -DTXT_ONLY @CPPFLAGS@ -c $(OUTPUT_OPTION) $< + @CC@ @CFLAGS@ $(PCRE_CFLAGS) $(CUSTOM_CFLAGS) -DTXT_ONLY @CPPFLAGS@ -c $(OUTPUT_OPTION) $< obj_sql/%.o: %.c $(MAP_H) $(COMMON_H) $(COMMON_SQL_H) - @CC@ @CFLAGS@ $(PCRE_CFLAGS) @MYSQL_CFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $< + @CC@ @CFLAGS@ $(PCRE_CFLAGS) $(CUSTOM_CFLAGS) @MYSQL_CFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $< # missing common object files ../common/obj_all/%.o: diff --git a/src/plugins/Makefile.in b/src/plugins/Makefile.in index c21bcd7d9..6a902e1d7 100644 --- a/src/plugins/Makefile.in +++ b/src/plugins/Makefile.in @@ -50,7 +50,7 @@ gui@DLLEXT@: ../../plugins/gui.conf upnp@DLLEXT@: ../../plugins/upnp.conf sig@DLLEXT@: sig.c $(COMMON_OBJ) - @CC@ @CFLAGS@ @CPPFLAGS@ @LDFLAGS@ -shared -o ../../plugins/$@ $< $(COMMON_OBJ) + @CC@ @CFLAGS@ $(CUSTOM_CFLAGS) @CPPFLAGS@ @LDFLAGS@ -shared -o ../../plugins/$@ $< $(COMMON_OBJ) ../../plugins/%.conf: %.txt cp -r $< $@ -- cgit v1.2.3-70-g09d2 From aede64e8f9fd60c0e1aa91b420280bf423b14e57 Mon Sep 17 00:00:00 2001 From: Kevin Date: Sat, 12 Apr 2008 07:59:42 +0000 Subject: I live in a giant bucket. git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@12570 54d463be-8e91-2dee-dedb-b68131a5f0ec --- src/char/Makefile.in | 47 - src/char/char.c | 4290 ------------------------------------------------ src/char/char.h | 54 - src/char/int_guild.c | 1579 ------------------ src/char/int_guild.h | 26 - src/char/int_homun.c | 365 ---- src/char/int_homun.h | 15 - src/char/int_party.c | 732 --------- src/char/int_party.h | 20 - src/char/int_pet.c | 380 ----- src/char/int_pet.h | 21 - src/char/int_status.c | 183 --- src/char/int_status.h | 23 - src/char/int_storage.c | 481 ------ src/char/int_storage.h | 25 - src/char/inter.c | 711 -------- src/char/inter.h | 30 - src/login/Makefile.in | 46 - src/login/admin.c | 879 ---------- src/login/login.c | 2362 -------------------------- src/login/login.h | 94 -- 21 files changed, 12363 deletions(-) delete mode 100644 src/char/Makefile.in delete mode 100644 src/char/char.c delete mode 100644 src/char/char.h delete mode 100644 src/char/int_guild.c delete mode 100644 src/char/int_guild.h delete mode 100644 src/char/int_homun.c delete mode 100644 src/char/int_homun.h delete mode 100644 src/char/int_party.c delete mode 100644 src/char/int_party.h delete mode 100644 src/char/int_pet.c delete mode 100644 src/char/int_pet.h delete mode 100644 src/char/int_status.c delete mode 100644 src/char/int_status.h delete mode 100644 src/char/int_storage.c delete mode 100644 src/char/int_storage.h delete mode 100644 src/char/inter.c delete mode 100644 src/char/inter.h delete mode 100644 src/login/Makefile.in delete mode 100644 src/login/admin.c delete mode 100644 src/login/login.c delete mode 100644 src/login/login.h (limited to 'src/char/Makefile.in') diff --git a/src/char/Makefile.in b/src/char/Makefile.in deleted file mode 100644 index 37b464991..000000000 --- a/src/char/Makefile.in +++ /dev/null @@ -1,47 +0,0 @@ - -COMMON_OBJ = ../common/obj_all/core.o ../common/obj_all/socket.o ../common/obj_all/timer.o \ - ../common/obj_all/db.o ../common/obj_all/plugins.o ../common/obj_all/lock.o \ - ../common/obj_all/malloc.o ../common/obj_all/showmsg.o ../common/obj_all/utils.o \ - ../common/obj_all/strlib.o ../common/obj_all/grfio.o \ - ../common/obj_all/mapindex.o ../common/obj_all/ers.o -COMMON_H = ../common/core.h ../common/socket.h ../common/timer.h ../common/mmo.h \ - ../common/version.h ../common/db.h ../common/plugins.h ../common/lock.h \ - ../common/malloc.h ../common/showmsg.h ../common/utils.h \ - ../common/strlib.h ../common/grfio.h \ - ../common/mapindex.h ../common/ers.h - -CHAR_OBJ = obj_txt/char.o obj_txt/inter.o obj_txt/int_party.o obj_txt/int_guild.o \ - obj_txt/int_storage.o obj_txt/int_status.o obj_txt/int_pet.o obj_txt/int_homun.o -CHAR_H = char.h inter.h int_party.h int_guild.h int_storage.h int_status.h int_pet.h int_homun.h - -@SET_MAKE@ - -##################################################################### -.PHONY : all char-server clean help - -all: char-server - -char-server: obj_txt $(CHAR_OBJ) $(COMMON_OBJ) - @CC@ @LDFLAGS@ -o ../../char-server@EXEEXT@ $(CHAR_OBJ) $(COMMON_OBJ) @LIBS@ - -clean: - rm -rf *.o obj_txt ../../char-server@EXEEXT@ - -help: - @echo "possible targets are 'char-server' 'all' 'clean' 'help'" - @echo "'char-server' - char server (TXT version)" - @echo "'all' - builds all above targets" - @echo "'clean' - cleans builds and objects" - @echo "'help' - outputs this message" - -##################################################################### - -obj_txt: - -mkdir obj_txt - -obj_txt/%.o: %.c $(CHAR_H) $(COMMON_H) - @CC@ @CFLAGS@ $(CUSTOM_CFLAGS) -DTXT_ONLY @CPPFLAGS@ -c $(OUTPUT_OPTION) $< - -# missing common object files -../common/obj_all/%.o: - @$(MAKE) -C ../common txt diff --git a/src/char/char.c b/src/char/char.c deleted file mode 100644 index 13da079ab..000000000 --- a/src/char/char.c +++ /dev/null @@ -1,4290 +0,0 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder - -#include "../common/cbasetypes.h" -#include "../common/mmo.h" -#include "../common/db.h" -#include "../common/lock.h" -#include "../common/malloc.h" -#include "../common/core.h" -#include "../common/socket.h" -#include "../common/strlib.h" -#include "../common/showmsg.h" -#include "../common/timer.h" -#include "../common/lock.h" -#include "../common/malloc.h" -#include "../common/mapindex.h" -#include "../common/showmsg.h" -#include "../common/utils.h" -#include "../common/version.h" -#include "inter.h" -#include "int_guild.h" -#include "int_homun.h" -#include "int_pet.h" -#include "int_party.h" -#include "int_storage.h" -#include "int_status.h" -#include "char.h" - -#include -#ifdef WIN32 -#include -#else -#include -#include -#include -#endif -#include -#include -#include -#include -#include -#include -#include - -// private declarations -#define CHAR_CONF_NAME "conf/char_athena.conf" -#define LAN_CONF_NAME "conf/subnet_athena.conf" - -char char_txt[1024] = "save/athena.txt"; -char friends_txt[1024] = "save/friends.txt"; -char hotkeys_txt[1024] = "save/hotkeys.txt"; -char char_log_filename[1024] = "log/char.log"; - -int save_log = 1; // show loading/saving messages - -#ifndef TXT_SQL_CONVERT -char db_path[1024] = "db"; - -struct mmo_map_server { - int fd; - uint32 ip; - uint16 port; - int users; - unsigned short map[MAX_MAP_PER_SERVER]; -} server[MAX_MAP_SERVERS]; - -int login_fd=-1, char_fd=-1; -char userid[24]; -char passwd[24]; -char server_name[20]; -char wisp_server_name[NAME_LENGTH] = "Server"; -char login_ip_str[128]; -uint32 login_ip = 0; -uint16 login_port = 6900; -char char_ip_str[128]; -uint32 char_ip = 0; -char bind_ip_str[128]; -uint32 bind_ip = INADDR_ANY; -uint16 char_port = 6121; -int char_maintenance = 0; -bool char_new = true; -int char_new_display = 0; - -int email_creation = 0; // disabled by default - -bool name_ignoring_case = false; // Allow or not identical name for characters but with a different case by [Yor] -int char_name_option = 0; // Option to know which letters/symbols are authorised in the name of a character (0: all, 1: only those in char_name_letters, 2: all EXCEPT those in char_name_letters) by [Yor] -char unknown_char_name[1024] = "Unknown"; // Name to use when the requested name cannot be determined -#define TRIM_CHARS "\032\t\x0A\x0D " //The following characters are trimmed regardless because they cause confusion and problems on the servers. [Skotlex] -char char_name_letters[1024] = ""; // list of letters/symbols authorised (or not) in a character name. by [Yor] -bool char_rename = true; - -int log_char = 1; // loggin char or not [devil] -int log_inter = 1; // loggin inter or not [devil] - -static int online_check = 1; //If one, it won't let players connect when their account is already registered online and will send the relevant map server a kick user request. [Skotlex] - -// Advanced subnet check [LuzZza] -struct s_subnet { - uint32 mask; - uint32 char_ip; - uint32 map_ip; -} subnet[16]; -int subnet_count = 0; - -struct char_session_data { - bool auth; // whether the session is authed or not - int account_id, login_id1, login_id2, sex; - int found_char[MAX_CHARS]; // ids of chars on this account - char email[40]; // e-mail (default: a@a.com) by [Yor] - time_t expiration_time; // # of seconds 1/1/1970 (timestamp): Validity limit of the account (0 = unlimited) -}; - -int char_id_count = START_CHAR_NUM; -struct character_data *char_dat; - -int char_num, char_max; -int max_connect_user = 0; -int gm_allow_level = 99; -int autosave_interval = DEFAULT_AUTOSAVE_INTERVAL; -int start_zeny = 500; -int start_weapon = 1201; -int start_armor = 2301; -int guild_exp_rate = 100; - -//Custom limits for the fame lists. [Skotlex] -int fame_list_size_chemist = MAX_FAME_LIST; -int fame_list_size_smith = MAX_FAME_LIST; -int fame_list_size_taekwon = MAX_FAME_LIST; - -// Char-server-side stored fame lists [DracoRPG] -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]; - -// Initial position (it's possible to set it in conf file) -struct point start_point = { 0, 53, 111 }; - -struct gm_account *gm_account = NULL; -int GM_num = 0; - -// online players by [Yor] -char online_txt_filename[1024] = "online.txt"; -char online_html_filename[1024] = "online.html"; -int online_sorting_option = 0; // sorting option to display online players in online files -int online_display_option = 1; // display options: to know which columns must be displayed -int online_refresh_html = 20; // refresh time (in sec) of the html file in the explorer -int online_gm_display_min_level = 20; // minimum GM level to display 'GM' when we want to display it - -int console = 0; - -//----------------------------------------------------- -// Auth database -//----------------------------------------------------- -#define AUTH_TIMEOUT 30000 - -struct auth_node { - int account_id; - int char_id; - uint32 login_id1; - uint32 login_id2; - uint32 ip; - int sex; - time_t expiration_time; // # of seconds 1/1/1970 (timestamp): Validity limit of the account (0 = unlimited) -}; - -static DBMap* auth_db; // int account_id -> struct auth_node* - -//----------------------------------------------------- -// Online User Database -//----------------------------------------------------- - -struct online_char_data { - int account_id; - int char_id; - int fd; - int waiting_disconnect; - short server; -}; - -static DBMap* online_char_db; // int account_id -> struct online_char_data* -static int chardb_waiting_disconnect(int tid, unsigned int tick, int id, int data); - -static void* create_online_char_data(DBKey key, va_list args) -{ - struct online_char_data* character; - CREATE(character, struct online_char_data, 1); - character->account_id = key.i; - character->char_id = -1; - character->server = -1; - character->fd = -1; - character->waiting_disconnect = -1; - return character; -} - -void set_char_online(int map_id, int char_id, int account_id) -{ - struct online_char_data* character; - - character = (struct online_char_data*)idb_ensure(online_char_db, account_id, create_online_char_data); - if (online_check && character->char_id != -1 && character->server > -1 && character->server != map_id && map_id != -3) - { - //char == 99 <- Character logging in, so someone has logged in while one - //char is still on map-server, so kick him out, but don't print "error" - //as this is normal behaviour. [Skotlex] - if (char_id != 99) - ShowNotice("set_char_online: Character %d:%d marked in map server %d, but map server %d claims to have (%d:%d) online!\n", - character->account_id, character->char_id, character->server, map_id, account_id, char_id); - mapif_disconnectplayer(server[character->server].fd, character->account_id, character->char_id, 2); - } - - if( character->server > -1 ) - server[character->server].users++; - - if(character->waiting_disconnect != -1) { - delete_timer(character->waiting_disconnect, chardb_waiting_disconnect); - character->waiting_disconnect = -1; - } - - //If user is NOT at char screen, delete entry [Kevin] - if(character->char_id != -1) - { - idb_remove(online_char_db, account_id); - } - - if (login_fd > 0 && !session[login_fd]->flag.eof) - { - WFIFOHEAD(login_fd,6); - WFIFOW(login_fd,0) = 0x272b; - WFIFOL(login_fd,2) = account_id; - WFIFOSET(login_fd,6); - } -} - -void set_char_offline(int char_id, int account_id) -{ - struct online_char_data* character; - - if ((character = (struct online_char_data*)idb_get(online_char_db, account_id)) != NULL) - { //We don't free yet to avoid aCalloc/aFree spamming during char change. [Skotlex] - if( character->server > -1 ) - server[character->server].users--; - - character->char_id = -1; - character->server = -1; - if(character->waiting_disconnect != -1){ - delete_timer(character->waiting_disconnect, chardb_waiting_disconnect); - character->waiting_disconnect = -1; - } - } - - if (login_fd > 0 && !session[login_fd]->flag.eof) - { - WFIFOHEAD(login_fd,6); - WFIFOW(login_fd,0) = 0x272c; - WFIFOL(login_fd,2) = account_id; - WFIFOSET(login_fd,6); - } -} - -static int char_db_setoffline(DBKey key, void* data, va_list ap) -{ - struct online_char_data* character = (struct online_char_data*)data; - int server = va_arg(ap, int); - if (server == -1) { - character->char_id = -1; - character->server = -1; - if(character->waiting_disconnect != -1){ - delete_timer(character->waiting_disconnect, chardb_waiting_disconnect); - character->waiting_disconnect = -1; - } - } else if (character->server == server) - character->server = -2; //In some map server that we aren't connected to. - return 0; -} - -static int char_db_kickoffline(DBKey key, void* data, va_list ap) -{ - struct online_char_data* character = (struct online_char_data*)data; - int server_id = va_arg(ap, int); - - if (server_id > -1 && character->server != server_id) - return 0; - - //Kick out any connected characters, and set them offline as appropiate. - if (character->server > -1) - mapif_disconnectplayer(server[character->server].fd, character->account_id, character->char_id, 1); - else if (character->waiting_disconnect == -1) - set_char_offline(character->char_id, character->account_id); - else - return 0; // fail - - return 1; -} - -void set_all_offline(int id) -{ - if (id < 0) - ShowNotice("Sending all users offline.\n"); - else - ShowNotice("Sending users of map-server %d offline.\n",id); - online_char_db->foreach(online_char_db,char_db_kickoffline,id); - - if (id >= 0 || login_fd <= 0 || session[login_fd]->flag.eof) - return; - //Tell login-server to also mark all our characters as offline. - WFIFOHEAD(login_fd,2); - WFIFOW(login_fd,0) = 0x2737; - WFIFOSET(login_fd,2); -} - -//------------------------------ -// Writing function of logs file -//------------------------------ -int char_log(char *fmt, ...) -{ - if(log_char) - { - FILE *logfp; - va_list ap; - time_t raw_time; - char tmpstr[2048]; - - va_start(ap, fmt); - - logfp = fopen(char_log_filename, "a"); - if (logfp) { - if (fmt[0] == '\0') // jump a line if no message - fprintf(logfp, "\n"); - else { - time(&raw_time); - strftime(tmpstr, 24, "%d-%m-%Y %H:%M:%S", localtime(&raw_time)); - sprintf(tmpstr + 19, ": %s", fmt); - vfprintf(logfp, tmpstr, ap); - } - fclose(logfp); - } - va_end(ap); - } - return 0; -} - -//---------------------------------------------------------------------- -// Determine if an account (id) is a GM account -// and returns its level (or 0 if it isn't a GM account or if not found) -//---------------------------------------------------------------------- -int isGM(int account_id) -{ - int i; - - for(i = 0; i < GM_num; i++) - if (gm_account[i].account_id == account_id) - return gm_account[i].level; - return 0; -} - -//Search character data from the aid/cid givem -struct mmo_charstatus* search_character(int aid, int cid) -{ - int i; - for (i = 0; i < char_num; i++) { - if (char_dat[i].status.char_id == cid && char_dat[i].status.account_id == aid) - return &char_dat[i].status; - } - return NULL; -} - -struct mmo_charstatus* search_character_byname(char* character_name) -{ - int i = search_character_index(character_name); - if (i == -1) return NULL; - return &char_dat[i].status; -} - -// Searches if the given character is online, and returns the fd of the -// map-server it is connected to. -int search_character_online(int aid, int cid) -{ - //Look for online character. - struct online_char_data* character; - character = idb_get(online_char_db, aid); - if(character && - character->char_id == cid && - character->server > -1) - return server[character->server].fd; - return -1; -} - -//---------------------------------------------- -// Search an character id -// (return character index or -1 (if not found)) -// If exact character name is not found, -// the function checks without case sensitive -// and returns index if only 1 character is found -// and similar to the searched name. -//---------------------------------------------- -int search_character_index(char* character_name) -{ - int i, quantity, index; - - quantity = 0; - index = -1; - for(i = 0; i < char_num; i++) { - // Without case sensitive check (increase the number of similar character names found) - if (stricmp(char_dat[i].status.name, character_name) == 0) { - // Strict comparison (if found, we finish the function immediatly with correct value) - if (strcmp(char_dat[i].status.name, character_name) == 0) - return i; - quantity++; - index = i; - } - } - // Here, the exact character name is not found - // We return the found index of a similar account ONLY if there is 1 similar character - if (quantity == 1) - return index; - - // Exact character name is not found and 0 or more than 1 similar characters have been found ==> we say not found - return -1; -} - -/*--------------------------------------------------- - Make a data line for friends list - --------------------------------------------------*/ -int mmo_friends_list_data_str(char *str, struct mmo_charstatus *p) -{ - int i; - char *str_p = str; - str_p += sprintf(str_p, "%d", p->char_id); - - for (i=0;ifriends[i].account_id > 0 && p->friends[i].char_id > 0 && p->friends[i].name[0]) - str_p += sprintf(str_p, ",%d,%d,%s", p->friends[i].account_id, p->friends[i].char_id, p->friends[i].name); - } - - str_p += '\0'; - - return 0; -} - -/*--------------------------------------------------- - Make a data line for hotkeys list - --------------------------------------------------*/ -int mmo_hotkeys_tostr(char *str, struct mmo_charstatus *p) -{ -#ifdef HOTKEY_SAVING - int i; - char *str_p = str; - str_p += sprintf(str_p, "%d", p->char_id); - for (i=0;ihotkeys[i].type, p->hotkeys[i].id, p->hotkeys[i].lv); - str_p += '\0'; -#endif - - return 0; -} - -//------------------------------------------------- -// Function to create the character line (for save) -//------------------------------------------------- -int mmo_char_tostr(char *str, struct mmo_charstatus *p, struct global_reg *reg, int reg_num) -{ - int i,j; - char *str_p = str; - - str_p += sprintf(str_p, - "%d\t%d,%d\t%s\t%d,%d,%d\t%u,%u,%d" //Up to Zeny field - "\t%d,%d,%d,%d\t%d,%d,%d,%d,%d,%d\t%d,%d" //Up to Skill Point - "\t%d,%d,%d\t%d,%d,%d,%d" //Up to hom id - "\t%d,%d,%d\t%d,%d,%d,%d,%d" //Up to head bottom - "\t%d,%d,%d\t%d,%d,%d" //last point + save point - ",%d,%d,%d,%d,%d\t", //Family info - p->char_id, p->account_id, p->slot, p->name, // - p->class_, p->base_level, p->job_level, - p->base_exp, p->job_exp, p->zeny, - p->hp, p->max_hp, p->sp, p->max_sp, - p->str, p->agi, p->vit, p->int_, p->dex, p->luk, - p->status_point, p->skill_point, - p->option, p->karma, p->manner, // - p->party_id, p->guild_id, p->pet_id, p->hom_id, - p->hair, p->hair_color, p->clothes_color, - p->weapon, p->shield, p->head_top, p->head_mid, p->head_bottom, - p->last_point.map, p->last_point.x, p->last_point.y, // - p->save_point.map, p->save_point.x, p->save_point.y, - p->partner_id,p->father,p->mother,p->child,p->fame); - for(i = 0; i < MAX_MEMOPOINTS; i++) - if (p->memo_point[i].map) { - str_p += sprintf(str_p, "%d,%d,%d ", p->memo_point[i].map, p->memo_point[i].x, p->memo_point[i].y); - } - *(str_p++) = '\t'; - - for(i = 0; i < MAX_INVENTORY; i++) - if (p->inventory[i].nameid) { - str_p += sprintf(str_p,"%d,%d,%d,%d,%d,%d,%d", - p->inventory[i].id,p->inventory[i].nameid,p->inventory[i].amount,p->inventory[i].equip, - p->inventory[i].identify,p->inventory[i].refine,p->inventory[i].attribute); - for(j=0; jinventory[i].card[j]); - str_p += sprintf(str_p," "); - } - *(str_p++) = '\t'; - - for(i = 0; i < MAX_CART; i++) - if (p->cart[i].nameid) { - str_p += sprintf(str_p,"%d,%d,%d,%d,%d,%d,%d", - p->cart[i].id,p->cart[i].nameid,p->cart[i].amount,p->cart[i].equip, - p->cart[i].identify,p->cart[i].refine,p->cart[i].attribute); - for(j=0; jcart[i].card[j]); - str_p += sprintf(str_p," "); - } - *(str_p++) = '\t'; - - for(i = 0; i < MAX_SKILL; i++) - if (p->skill[i].id && p->skill[i].flag != 1) { - str_p += sprintf(str_p, "%d,%d ", p->skill[i].id, (p->skill[i].flag == 0) ? p->skill[i].lv : p->skill[i].flag-2); - } - *(str_p++) = '\t'; - - for(i = 0; i < reg_num; i++) - if (reg[i].str[0]) - str_p += sprintf(str_p, "%s,%s ", reg[i].str, reg[i].value); - *(str_p++) = '\t'; - - *str_p = '\0'; - return 0; -} -#endif //TXT_SQL_CONVERT -//------------------------------------------------------------------------- -// Function to set the character from the line (at read of characters file) -//------------------------------------------------------------------------- -int mmo_char_fromstr(char *str, struct mmo_charstatus *p, struct global_reg *reg, int *reg_num) -{ - char tmp_str[3][128]; //To avoid deleting chars with too long names. - int tmp_int[256]; - unsigned int tmp_uint[2]; //To read exp.... - int next, len, i, j; - - // initilialise character - memset(p, '\0', sizeof(struct mmo_charstatus)); - -// Char structure of version 1500 (homun + mapindex maps) - if (sscanf(str, "%d\t%d,%d\t%127[^\t]\t%d,%d,%d\t%u,%u,%d\t%d,%d,%d,%d\t%d,%d,%d,%d,%d,%d\t%d,%d" - "\t%d,%d,%d\t%d,%d,%d,%d\t%d,%d,%d\t%d,%d,%d,%d,%d" - "\t%d,%d,%d\t%d,%d,%d,%d,%d,%d,%d,%d%n", - &tmp_int[0], &tmp_int[1], &tmp_int[2], tmp_str[0], - &tmp_int[3], &tmp_int[4], &tmp_int[5], - &tmp_uint[0], &tmp_uint[1], &tmp_int[8], - &tmp_int[9], &tmp_int[10], &tmp_int[11], &tmp_int[12], - &tmp_int[13], &tmp_int[14], &tmp_int[15], &tmp_int[16], &tmp_int[17], &tmp_int[18], - &tmp_int[19], &tmp_int[20], - &tmp_int[21], &tmp_int[22], &tmp_int[23], // - &tmp_int[24], &tmp_int[25], &tmp_int[26], &tmp_int[44], - &tmp_int[27], &tmp_int[28], &tmp_int[29], - &tmp_int[30], &tmp_int[31], &tmp_int[32], &tmp_int[33], &tmp_int[34], - &tmp_int[45], &tmp_int[35], &tmp_int[36], - &tmp_int[46], &tmp_int[37], &tmp_int[38], &tmp_int[39], - &tmp_int[40], &tmp_int[41], &tmp_int[42], &tmp_int[43], &next) != 48) - { - tmp_int[44] = 0; //Hom ID. -// Char structure of version 1488 (fame field addition) - if (sscanf(str, "%d\t%d,%d\t%127[^\t]\t%d,%d,%d\t%u,%u,%d\t%d,%d,%d,%d\t%d,%d,%d,%d,%d,%d\t%d,%d" - "\t%d,%d,%d\t%d,%d,%d\t%d,%d,%d\t%d,%d,%d,%d,%d" - "\t%127[^,],%d,%d\t%127[^,],%d,%d,%d,%d,%d,%d,%d%n", - &tmp_int[0], &tmp_int[1], &tmp_int[2], tmp_str[0], - &tmp_int[3], &tmp_int[4], &tmp_int[5], - &tmp_uint[0], &tmp_uint[1], &tmp_int[8], - &tmp_int[9], &tmp_int[10], &tmp_int[11], &tmp_int[12], - &tmp_int[13], &tmp_int[14], &tmp_int[15], &tmp_int[16], &tmp_int[17], &tmp_int[18], - &tmp_int[19], &tmp_int[20], - &tmp_int[21], &tmp_int[22], &tmp_int[23], // - &tmp_int[24], &tmp_int[25], &tmp_int[26], - &tmp_int[27], &tmp_int[28], &tmp_int[29], - &tmp_int[30], &tmp_int[31], &tmp_int[32], &tmp_int[33], &tmp_int[34], - tmp_str[1], &tmp_int[35], &tmp_int[36], - tmp_str[2], &tmp_int[37], &tmp_int[38], &tmp_int[39], - &tmp_int[40], &tmp_int[41], &tmp_int[42], &tmp_int[43], &next) != 47) - { - tmp_int[43] = 0; //Fame -// Char structure of version 1363 (family data addition) - if (sscanf(str, "%d\t%d,%d\t%127[^\t]\t%d,%d,%d\t%u,%u,%d\t%d,%d,%d,%d\t%d,%d,%d,%d,%d,%d\t%d,%d" - "\t%d,%d,%d\t%d,%d,%d\t%d,%d,%d\t%d,%d,%d,%d,%d" - "\t%127[^,],%d,%d\t%127[^,],%d,%d,%d,%d,%d,%d%n", - &tmp_int[0], &tmp_int[1], &tmp_int[2], tmp_str[0], // - &tmp_int[3], &tmp_int[4], &tmp_int[5], - &tmp_uint[0], &tmp_uint[1], &tmp_int[8], - &tmp_int[9], &tmp_int[10], &tmp_int[11], &tmp_int[12], - &tmp_int[13], &tmp_int[14], &tmp_int[15], &tmp_int[16], &tmp_int[17], &tmp_int[18], - &tmp_int[19], &tmp_int[20], - &tmp_int[21], &tmp_int[22], &tmp_int[23], // - &tmp_int[24], &tmp_int[25], &tmp_int[26], - &tmp_int[27], &tmp_int[28], &tmp_int[29], - &tmp_int[30], &tmp_int[31], &tmp_int[32], &tmp_int[33], &tmp_int[34], - tmp_str[1], &tmp_int[35], &tmp_int[36], // - tmp_str[2], &tmp_int[37], &tmp_int[38], &tmp_int[39], - &tmp_int[40], &tmp_int[41], &tmp_int[42], &next) != 46) - { - tmp_int[40] = 0; // father - tmp_int[41] = 0; // mother - tmp_int[42] = 0; // child -// Char structure version 1008 (marriage partner addition) - if (sscanf(str, "%d\t%d,%d\t%127[^\t]\t%d,%d,%d\t%u,%u,%d\t%d,%d,%d,%d\t%d,%d,%d,%d,%d,%d\t%d,%d" - "\t%d,%d,%d\t%d,%d,%d\t%d,%d,%d\t%d,%d,%d,%d,%d" - "\t%127[^,],%d,%d\t%127[^,],%d,%d,%d%n", - &tmp_int[0], &tmp_int[1], &tmp_int[2], tmp_str[0], // - &tmp_int[3], &tmp_int[4], &tmp_int[5], - &tmp_uint[0], &tmp_uint[1], &tmp_int[8], - &tmp_int[9], &tmp_int[10], &tmp_int[11], &tmp_int[12], - &tmp_int[13], &tmp_int[14], &tmp_int[15], &tmp_int[16], &tmp_int[17], &tmp_int[18], - &tmp_int[19], &tmp_int[20], - &tmp_int[21], &tmp_int[22], &tmp_int[23], // - &tmp_int[24], &tmp_int[25], &tmp_int[26], - &tmp_int[27], &tmp_int[28], &tmp_int[29], - &tmp_int[30], &tmp_int[31], &tmp_int[32], &tmp_int[33], &tmp_int[34], - tmp_str[1], &tmp_int[35], &tmp_int[36], // - tmp_str[2], &tmp_int[37], &tmp_int[38], &tmp_int[39], &next) != 43) - { - tmp_int[39] = 0; // partner id -// Char structure version 384 (pet addition) - if (sscanf(str, "%d\t%d,%d\t%127[^\t]\t%d,%d,%d\t%u,%u,%d\t%d,%d,%d,%d\t%d,%d,%d,%d,%d,%d\t%d,%d" - "\t%d,%d,%d\t%d,%d,%d\t%d,%d,%d\t%d,%d,%d,%d,%d" - "\t%127[^,],%d,%d\t%127[^,],%d,%d%n", - &tmp_int[0], &tmp_int[1], &tmp_int[2], tmp_str[0], // - &tmp_int[3], &tmp_int[4], &tmp_int[5], - &tmp_uint[0], &tmp_uint[1], &tmp_int[8], - &tmp_int[9], &tmp_int[10], &tmp_int[11], &tmp_int[12], - &tmp_int[13], &tmp_int[14], &tmp_int[15], &tmp_int[16], &tmp_int[17], &tmp_int[18], - &tmp_int[19], &tmp_int[20], - &tmp_int[21], &tmp_int[22], &tmp_int[23], // - &tmp_int[24], &tmp_int[25], &tmp_int[26], - &tmp_int[27], &tmp_int[28], &tmp_int[29], - &tmp_int[30], &tmp_int[31], &tmp_int[32], &tmp_int[33], &tmp_int[34], - tmp_str[1], &tmp_int[35], &tmp_int[36], // - tmp_str[2], &tmp_int[37], &tmp_int[38], &next) != 42) - { - tmp_int[26] = 0; // pet id -// Char structure of a version 1 (original data structure) - if (sscanf(str, "%d\t%d,%d\t%127[^\t]\t%d,%d,%d\t%u,%u,%d\t%d,%d,%d,%d\t%d,%d,%d,%d,%d,%d\t%d,%d" - "\t%d,%d,%d\t%d,%d\t%d,%d,%d\t%d,%d,%d,%d,%d" - "\t%127[^,],%d,%d\t%127[^,],%d,%d%n", - &tmp_int[0], &tmp_int[1], &tmp_int[2], tmp_str[0], // - &tmp_int[3], &tmp_int[4], &tmp_int[5], - &tmp_uint[0], &tmp_uint[1], &tmp_int[8], - &tmp_int[9], &tmp_int[10], &tmp_int[11], &tmp_int[12], - &tmp_int[13], &tmp_int[14], &tmp_int[15], &tmp_int[16], &tmp_int[17], &tmp_int[18], - &tmp_int[19], &tmp_int[20], - &tmp_int[21], &tmp_int[22], &tmp_int[23], // - &tmp_int[24], &tmp_int[25], // - &tmp_int[27], &tmp_int[28], &tmp_int[29], - &tmp_int[30], &tmp_int[31], &tmp_int[32], &tmp_int[33], &tmp_int[34], - tmp_str[1], &tmp_int[35], &tmp_int[36], // - tmp_str[2], &tmp_int[37], &tmp_int[38], &next) != 41) - { - ShowError("Char-loading: Unrecognized character data version, info lost!\n"); - ShowDebug("Character info: %s\n", str); - return 0; - } - } // Char structure version 384 (pet addition) - } // Char structure version 1008 (marriage partner addition) - } // Char structure of version 1363 (family data addition) - } // Char structure of version 1488 (fame field addition) - //Convert save data from string to integer for older formats - tmp_int[45] = mapindex_name2id(tmp_str[1]); - tmp_int[46] = mapindex_name2id(tmp_str[2]); - } // Char structure of version 1500 (homun + mapindex maps) - - memcpy(p->name, tmp_str[0], NAME_LENGTH); //Overflow protection [Skotlex] - p->char_id = tmp_int[0]; - p->account_id = tmp_int[1]; - p->slot = tmp_int[2]; - p->class_ = tmp_int[3]; - p->base_level = tmp_int[4]; - p->job_level = tmp_int[5]; - p->base_exp = tmp_uint[0]; - p->job_exp = tmp_uint[1]; - p->zeny = tmp_int[8]; - p->hp = tmp_int[9]; - p->max_hp = tmp_int[10]; - p->sp = tmp_int[11]; - p->max_sp = tmp_int[12]; - p->str = tmp_int[13]; - p->agi = tmp_int[14]; - p->vit = tmp_int[15]; - p->int_ = tmp_int[16]; - p->dex = tmp_int[17]; - p->luk = tmp_int[18]; - p->status_point = min(tmp_int[19], USHRT_MAX); - p->skill_point = min(tmp_int[20], USHRT_MAX); - p->option = tmp_int[21]; - p->karma = tmp_int[22]; - p->manner = tmp_int[23]; - p->party_id = tmp_int[24]; - p->guild_id = tmp_int[25]; - p->pet_id = tmp_int[26]; - p->hair = tmp_int[27]; - p->hair_color = tmp_int[28]; - p->clothes_color = tmp_int[29]; - p->weapon = tmp_int[30]; - p->shield = tmp_int[31]; - p->head_top = tmp_int[32]; - p->head_mid = tmp_int[33]; - p->head_bottom = tmp_int[34]; - p->last_point.x = tmp_int[35]; - p->last_point.y = tmp_int[36]; - p->save_point.x = tmp_int[37]; - p->save_point.y = tmp_int[38]; - p->partner_id = tmp_int[39]; - p->father = tmp_int[40]; - p->mother = tmp_int[41]; - p->child = tmp_int[42]; - p->fame = tmp_int[43]; - p->hom_id = tmp_int[44]; - p->last_point.map = tmp_int[45]; - p->save_point.map = tmp_int[46]; - -#ifndef TXT_SQL_CONVERT - // Some checks - for(i = 0; i < char_num; i++) { - if (char_dat[i].status.char_id == p->char_id) { - ShowError(CL_RED"mmmo_auth_init: a character has an identical id to another.\n"); - ShowError(" character id #%d -> new character not readed.\n", p->char_id); - ShowError(" Character saved in log file."CL_RESET"\n"); - return -1; - } else if (strcmp(char_dat[i].status.name, p->name) == 0) { - ShowError(CL_RED"mmmo_auth_init: a character name already exists.\n"); - ShowError(" character name '%s' -> new character not read.\n", p->name); - ShowError(" Character saved in log file."CL_RESET"\n"); - return -2; - } - } - - if (strcmpi(wisp_server_name, p->name) == 0) { - ShowWarning("mmo_auth_init: ******WARNING: character name has wisp server name.\n"); - ShowWarning(" Character name '%s' = wisp server name '%s'.\n", p->name, wisp_server_name); - ShowWarning(" Character readed. Suggestion: change the wisp server name.\n"); - char_log("mmo_auth_init: ******WARNING: character name has wisp server name: Character name '%s' = wisp server name '%s'.\n", - p->name, wisp_server_name); - } -#endif //TXT_SQL_CONVERT - if (str[next] == '\n' || str[next] == '\r') - return 1; // 新規データ - - next++; - - for(i = 0; str[next] && str[next] != '\t'; i++) { - //mapindex memo format - if (sscanf(str+next, "%d,%d,%d%n", &tmp_int[2], &tmp_int[0], &tmp_int[1], &len) != 3) - { //Old string-based memo format. - if (sscanf(str+next, "%[^,],%d,%d%n", tmp_str[0], &tmp_int[0], &tmp_int[1], &len) != 3) - return -3; - tmp_int[2] = mapindex_name2id(tmp_str[0]); - } - if (i < MAX_MEMOPOINTS) - { //Avoid overflowing (but we must also read through all saved memos) - p->memo_point[i].x = tmp_int[0]; - p->memo_point[i].y = tmp_int[1]; - p->memo_point[i].map = tmp_int[2]; - } - next += len; - if (str[next] == ' ') - next++; - } - - next++; - - for(i = 0; str[next] && str[next] != '\t'; i++) { - if(sscanf(str + next, "%d,%d,%d,%d,%d,%d,%d%[0-9,-]%n", - &tmp_int[0], &tmp_int[1], &tmp_int[2], &tmp_int[3], - &tmp_int[4], &tmp_int[5], &tmp_int[6], tmp_str[0], &len) == 8) - { - p->inventory[i].id = tmp_int[0]; - p->inventory[i].nameid = tmp_int[1]; - p->inventory[i].amount = tmp_int[2]; - p->inventory[i].equip = tmp_int[3]; - p->inventory[i].identify = tmp_int[4]; - p->inventory[i].refine = tmp_int[5]; - p->inventory[i].attribute = tmp_int[6]; - - for(j = 0; j < MAX_SLOTS && tmp_str[0] && sscanf(tmp_str[0], ",%d%[0-9,-]",&tmp_int[0], tmp_str[0]) > 0; j++) - p->inventory[i].card[j] = tmp_int[0]; - - next += len; - if (str[next] == ' ') - next++; - } else // invalid structure - return -4; - } - next++; - - for(i = 0; str[next] && str[next] != '\t'; i++) { - if(sscanf(str + next, "%d,%d,%d,%d,%d,%d,%d%[0-9,-]%n", - &tmp_int[0], &tmp_int[1], &tmp_int[2], &tmp_int[3], - &tmp_int[4], &tmp_int[5], &tmp_int[6], tmp_str[0], &len) == 8) - { - p->cart[i].id = tmp_int[0]; - p->cart[i].nameid = tmp_int[1]; - p->cart[i].amount = tmp_int[2]; - p->cart[i].equip = tmp_int[3]; - p->cart[i].identify = tmp_int[4]; - p->cart[i].refine = tmp_int[5]; - p->cart[i].attribute = tmp_int[6]; - - for(j = 0; j < MAX_SLOTS && tmp_str && sscanf(tmp_str[0], ",%d%[0-9,-]",&tmp_int[0], tmp_str[0]) > 0; j++) - p->cart[i].card[j] = tmp_int[0]; - - next += len; - if (str[next] == ' ') - next++; - } else // invalid structure - return -5; - } - - next++; - - for(i = 0; str[next] && str[next] != '\t'; i++) { - if (sscanf(str + next, "%d,%d%n", &tmp_int[0], &tmp_int[1], &len) != 2) - return -6; - p->skill[tmp_int[0]].id = tmp_int[0]; - p->skill[tmp_int[0]].lv = tmp_int[1]; - next += len; - if (str[next] == ' ') - next++; - } - - next++; - - for(i = 0; str[next] && str[next] != '\t' && str[next] != '\n' && str[next] != '\r'; i++) { // global_reg実装以前のathena.txt互換のため一応'\n'チェック - if (sscanf(str + next, "%[^,],%[^ ] %n", reg[i].str, reg[i].value, &len) != 2) { - // because some scripts are not correct, the str can be "". So, we must check that. - // If it's, we must not refuse the character, but just this REG value. - // Character line will have something like: nov_2nd_cos,9 ,9 nov_1_2_cos_c,1 (here, ,9 is not good) - if (str[next] == ',' && sscanf(str + next, ",%[^ ] %n", reg[i].value, &len) == 1) - i--; - else - return -7; - } - next += len; - if (str[next] == ' ') - next++; - } - *reg_num = i; - - return 1; -} - -//--------------------------------- -// Function to read friend list -//--------------------------------- -int parse_friend_txt(struct mmo_charstatus *p) -{ - char line[1024], temp[1024]; - int pos = 0, count = 0, next; - int i,len; - FILE *fp; - - // Open the file and look for the ID - fp = fopen(friends_txt, "r"); - - if(fp == NULL) - return -1; - - while(fgets(line, sizeof(line), fp)) - { - if(line[0] == '/' && line[1] == '/') - continue; - if (sscanf(line, "%d%n",&i, &pos) < 1 || i != p->char_id) - continue; //Not this line... - //Read friends - len = strlen(line); - next = pos; - for (count = 0; next < len && count < MAX_FRIENDS; count++) - { //Read friends. - if (sscanf(line+next, ",%d,%d,%23[^,^\n]%n",&p->friends[count].account_id,&p->friends[count].char_id, p->friends[count].name, &pos) < 3) - { //Invalid friend? - memset(&p->friends[count], 0, sizeof(p->friends[count])); - break; - } - next+=pos; - //What IF the name contains a comma? while the next field is not a - //number, we assume it belongs to the current name. [Skotlex] - //NOTE: Of course, this will fail if someone sets their name to something like - //Bob,2005 but... meh, it's the problem of parsing a text file (encasing it in " - //won't do as quotes are also valid name chars!) - while(next < len && sscanf(line+next, ",%23[^,^\n]%n", temp, &pos) > 0) - { - if (atoi(temp)) //We read the next friend, just continue. - break; - //Append the name. - next+=pos; - i = strlen(p->friends[count].name); - if (i + strlen(temp) +1 < NAME_LENGTH) - { - p->friends[count].name[i] = ','; - strcpy(p->friends[count].name+i+1, temp); - } - } //End Guess Block - } //Friend's for. - break; //Found friends. - } - fclose(fp); - return count; -} - -//--------------------------------- -// Function to read hotkey list -//--------------------------------- -int parse_hotkey_txt(struct mmo_charstatus *p) -{ -#ifdef HOTKEY_SAVING - char line[1024]; - int pos = 0, count = 0, next; - int i,len; - int type, id, lv; - FILE *fp; - - // Open the file and look for the ID - fp = fopen(hotkeys_txt, "r"); - if(fp == NULL) - return -1; - - while(fgets(line, sizeof(line), fp)) - { - if(line[0] == '/' && line[1] == '/') - continue; - if (sscanf(line, "%d%n",&i, &pos) < 1 || i != p->char_id) - continue; //Not this line... - //Read hotkeys - len = strlen(line); - next = pos; - for (count = 0; next < len && count < MAX_HOTKEYS; count++) - { - if (sscanf(line+next, ",%d,%d,%d%n",&type,&id,&lv, &pos) < 3) - //Invalid entry? - break; - p->hotkeys[count].type = type; - p->hotkeys[count].id = id; - p->hotkeys[count].lv = lv; - next+=pos; - } - break; //Found hotkeys. - } - fclose(fp); - return count; -#else - return 0; -#endif -} - - - -#ifndef TXT_SQL_CONVERT -//--------------------------------- -// Function to read characters file -//--------------------------------- -int mmo_char_init(void) -{ - char line[65536]; - int ret, line_count; - FILE* fp; - - char_num = 0; - char_max = 0; - char_dat = NULL; - - fp = fopen(char_txt, "r"); - - if (fp == NULL) { - ShowError("Characters file not found: %s.\n", char_txt); - char_log("Characters file not found: %s.\n", char_txt); - char_log("Id for the next created character: %d.\n", char_id_count); - return 0; - } - - line_count = 0; - while(fgets(line, sizeof(line), fp)) - { - int i, j; - line_count++; - - if (line[0] == '/' && line[1] == '/') - continue; - - j = 0; - if (sscanf(line, "%d\t%%newid%%%n", &i, &j) == 1 && j > 0) { - if (char_id_count < i) - char_id_count = i; - continue; - } - - if (char_num >= char_max) { - char_max += 256; - char_dat = (struct character_data*)aRealloc(char_dat, sizeof(struct character_data) * char_max); - if (!char_dat) { - ShowFatalError("Out of memory: mmo_char_init (realloc of char_dat).\n"); - char_log("Out of memory: mmo_char_init (realloc of char_dat).\n"); - exit(EXIT_FAILURE); - } - } - - ret = mmo_char_fromstr(line, &char_dat[char_num].status, char_dat[char_num].global, &char_dat[char_num].global_num); - - // Initialize friends list - parse_friend_txt(&char_dat[char_num].status); // Grab friends for the character - // Initialize hotkey list - parse_hotkey_txt(&char_dat[char_num].status); // Grab hotkeys for the character - - if (ret > 0) { // negative value or zero for errors - if (char_dat[char_num].status.char_id >= char_id_count) - char_id_count = char_dat[char_num].status.char_id + 1; - char_num++; - } else { - ShowError("mmo_char_init: in characters file, unable to read the line #%d.\n", line_count); - ShowError(" -> Character saved in log file.\n"); - switch (ret) { - case -1: - char_log("Duplicate character id in the next character line (character not readed):\n"); - break; - case -2: - char_log("Duplicate character name in the next character line (character not readed):\n"); - break; - case -3: - char_log("Invalid memo point structure in the next character line (character not readed):\n"); - break; - case -4: - char_log("Invalid inventory item structure in the next character line (character not readed):\n"); - break; - case -5: - char_log("Invalid cart item structure in the next character line (character not readed):\n"); - break; - case -6: - char_log("Invalid skill structure in the next character line (character not readed):\n"); - break; - case -7: - char_log("Invalid register structure in the next character line (character not readed):\n"); - break; - default: // 0 - char_log("Unabled to get a character in the next line - Basic structure of line (before inventory) is incorrect (character not readed):\n"); - break; - } - char_log("%s", line); - } - } - fclose(fp); - - if (char_num == 0) { - ShowNotice("mmo_char_init: No character found in %s.\n", char_txt); - char_log("mmo_char_init: No character found in %s.\n", char_txt); - } else if (char_num == 1) { - ShowStatus("mmo_char_init: 1 character read in %s.\n", char_txt); - char_log("mmo_char_init: 1 character read in %s.\n", char_txt); - } else { - ShowStatus("mmo_char_init: %d characters read in %s.\n", char_num, char_txt); - char_log("mmo_char_init: %d characters read in %s.\n", char_num, char_txt); - } - - char_log("Id for the next created character: %d.\n", char_id_count); - - return 0; -} - -//--------------------------------------------------------- -// Function to save characters in files (speed up by [Yor]) -//--------------------------------------------------------- -void mmo_char_sync(void) -{ - char line[65536],f_line[1024]; - int i, j, k; - int lock; - FILE *fp,*f_fp; - CREATE_BUFFER(id, int, char_num); - - // Sorting before save (by [Yor]) - for(i = 0; i < char_num; i++) { - id[i] = i; - for(j = 0; j < i; j++) { - if ((char_dat[i].status.account_id < char_dat[id[j]].status.account_id) || - // if same account id, we sort by slot. - (char_dat[i].status.account_id == char_dat[id[j]].status.account_id && - char_dat[i].status.slot < char_dat[id[j]].status.slot)) { - for(k = i; k > j; k--) - id[k] = id[k-1]; - id[j] = i; // id[i] - break; - } - } - } - - // Data save - fp = lock_fopen(char_txt, &lock); - if (fp == NULL) { - ShowWarning("Server cannot save characters.\n"); - char_log("WARNING: Server cannot save characters.\n"); - } else { - for(i = 0; i < char_num; i++) { - mmo_char_tostr(line, &char_dat[id[i]].status, char_dat[id[i]].global, char_dat[id[i]].global_num); // use of sorted index - fprintf(fp, "%s\n", line); - } - fprintf(fp, "%d\t%%newid%%\n", char_id_count); - lock_fclose(fp, char_txt, &lock); - } - - // Friends List data save (davidsiaw) - f_fp = lock_fopen(friends_txt, &lock); - for(i = 0; i < char_num; i++) { - mmo_friends_list_data_str(f_line, &char_dat[id[i]].status); - fprintf(f_fp, "%s\n", f_line); - } - - lock_fclose(f_fp, friends_txt, &lock); - -#ifdef HOTKEY_SAVING - // Hotkey List data save (Skotlex) - f_fp = lock_fopen(hotkeys_txt, &lock); - for(i = 0; i < char_num; i++) { - mmo_hotkeys_tostr(f_line, &char_dat[id[i]].status); - fprintf(f_fp, "%s\n", f_line); - } - - lock_fclose(f_fp, hotkeys_txt, &lock); -#endif - - DELETE_BUFFER(id); - - return; -} - -//---------------------------------------------------- -// Function to save (in a periodic way) datas in files -//---------------------------------------------------- -int mmo_char_sync_timer(int tid, unsigned int tick, int id, int data) -{ - if (save_log) - ShowInfo("Saving all files...\n"); - mmo_char_sync(); - inter_save(); - return 0; -} - -//----------------------------------- -// Function to create a new character -//----------------------------------- -int make_new_char(struct char_session_data* sd, char* name_, int str, int agi, int vit, int int_, int dex, int luk, int slot, int hair_color, int hair_style) -{ - char name[NAME_LENGTH]; - int i; - - safestrncpy(name, name_, NAME_LENGTH); - normalize_name(name,TRIM_CHARS); - - // check length of character name - if( name[0] == '\0' ) - return -2; // empty character name - - // check content of character name - if( remove_control_chars(name) ) - return -2; // control chars in name - - // check for reserved names - if( strcmpi(name, main_chat_nick) == 0 || strcmpi(name, wisp_server_name) == 0 ) - return -1; // nick reserved for internal server messages - - // Check Authorised letters/symbols in the name of the character - if( char_name_option == 1 ) { // only letters/symbols in char_name_letters are authorised - for( i = 0; i < NAME_LENGTH && name[i]; i++ ) - if( strchr(char_name_letters, name[i]) == NULL ) - return -2; - } else - if( char_name_option == 2 ) { // letters/symbols in char_name_letters are forbidden - for( i = 0; i < NAME_LENGTH && name[i]; i++ ) - if( strchr(char_name_letters, name[i]) != NULL ) - return -2; - } // else, all letters/symbols are authorised (except control char removed before) - - // check name (already in use?) - ARR_FIND( 0, char_num, i, - (name_ignoring_case && strncmp(char_dat[i].status.name, name, NAME_LENGTH) == 0) || - (!name_ignoring_case && strncmpi(char_dat[i].status.name, name, NAME_LENGTH) == 0) ); - if( i < char_num ) - return -1; // name already exists - - //check other inputs - if((slot >= MAX_CHARS) // slots - || (hair_style >= 24) // hair style - || (hair_color >= 9) // hair color - || (str + agi + vit + int_ + dex + luk != 6*5 ) // stats - || (str < 1 || str > 9 || agi < 1 || agi > 9 || vit < 1 || vit > 9 || int_ < 1 || int_ > 9 || dex < 1 || dex > 9 || luk < 1 || luk > 9) // individual stat values - || (str + int_ != 10 || agi + luk != 10 || vit + dex != 10) ) // pairs - return -2; // invalid input - - // check char slot - ARR_FIND( 0, char_num, i, char_dat[i].status.account_id == sd->account_id && char_dat[i].status.slot == slot ); - if( i < char_num ) - return -2; // slot already in use - - if (char_num >= char_max) { - char_max += 256; - RECREATE(char_dat, struct character_data, char_max); - if (!char_dat) { - ShowFatalError("Out of memory: make_new_char (realloc of char_dat).\n"); - char_log("Out of memory: make_new_char (realloc of char_dat).\n"); - exit(EXIT_FAILURE); - } - } - - // validation success, log result - char_log("make new char: account: %d, slot %d, name: %s, stats: %d/%d/%d/%d/%d/%d, hair: %d, hair color: %d.\n", - sd->account_id, slot, name, str, agi, vit, int_, dex, luk, hair_style, hair_color); - - i = char_num; - memset(&char_dat[i], 0, sizeof(struct character_data)); - - char_dat[i].status.char_id = char_id_count++; - char_dat[i].status.account_id = sd->account_id; - char_dat[i].status.slot = slot; - safestrncpy(char_dat[i].status.name,name,NAME_LENGTH); - char_dat[i].status.class_ = 0; - char_dat[i].status.base_level = 1; - char_dat[i].status.job_level = 1; - char_dat[i].status.base_exp = 0; - char_dat[i].status.job_exp = 0; - char_dat[i].status.zeny = start_zeny; - char_dat[i].status.str = str; - char_dat[i].status.agi = agi; - char_dat[i].status.vit = vit; - char_dat[i].status.int_ = int_; - char_dat[i].status.dex = dex; - char_dat[i].status.luk = luk; - char_dat[i].status.max_hp = 40 * (100 + char_dat[i].status.vit) / 100; - char_dat[i].status.max_sp = 11 * (100 + char_dat[i].status.int_) / 100; - char_dat[i].status.hp = char_dat[i].status.max_hp; - char_dat[i].status.sp = char_dat[i].status.max_sp; - char_dat[i].status.status_point = 0; - char_dat[i].status.skill_point = 0; - char_dat[i].status.option = 0; - char_dat[i].status.karma = 0; - char_dat[i].status.manner = 0; - char_dat[i].status.party_id = 0; - char_dat[i].status.guild_id = 0; - char_dat[i].status.hair = hair_style; - char_dat[i].status.hair_color = hair_color; - char_dat[i].status.clothes_color = 0; - char_dat[i].status.inventory[0].nameid = start_weapon; // Knife - char_dat[i].status.inventory[0].amount = 1; - char_dat[i].status.inventory[0].identify = 1; - char_dat[i].status.inventory[1].nameid = start_armor; // Cotton Shirt - char_dat[i].status.inventory[1].amount = 1; - char_dat[i].status.inventory[1].identify = 1; - char_dat[i].status.weapon = 0; // W_FIST - char_dat[i].status.shield = 0; - char_dat[i].status.head_top = 0; - char_dat[i].status.head_mid = 0; - char_dat[i].status.head_bottom = 0; - memcpy(&char_dat[i].status.last_point, &start_point, sizeof(start_point)); - memcpy(&char_dat[i].status.save_point, &start_point, sizeof(start_point)); - char_num++; - - ShowInfo("Created char: account: %d, char: %d, slot: %d, name: %s\n", sd->account_id, i, slot, name); - mmo_char_sync(); - return i; -} - -//---------------------------------------------------- -// This function return the name of the job (by [Yor]) -//---------------------------------------------------- -char * job_name(int class_) -{ - switch (class_) { - case JOB_NOVICE: return "Novice"; - case JOB_SWORDMAN: return "Swordsman"; - case JOB_MAGE: return "Mage"; - case JOB_ARCHER: return "Archer"; - case JOB_ACOLYTE: return "Acolyte"; - case JOB_MERCHANT: return "Merchant"; - case JOB_THIEF: return "Thief"; - case JOB_KNIGHT: return "Knight"; - case JOB_PRIEST: return "Priest"; - case JOB_WIZARD: return "Wizard"; - case JOB_BLACKSMITH: return "Blacksmith"; - case JOB_HUNTER: return "Hunter"; - case JOB_ASSASSIN: return "Assassin"; - case JOB_KNIGHT2: return "Peco-Knight"; - case JOB_CRUSADER: return "Crusader"; - case JOB_MONK: return "Monk"; - case JOB_SAGE: return "Sage"; - case JOB_ROGUE: return "Rogue"; - case JOB_ALCHEMIST: return "Alchemist"; - case JOB_BARD: return "Bard"; - case JOB_DANCER: return "Dancer"; - case JOB_CRUSADER2: return "Peco-Crusader"; - case JOB_WEDDING: return "Wedding"; - case JOB_SUPER_NOVICE: return "Super Novice"; - case JOB_GUNSLINGER: return "Gunslinger"; - case JOB_NINJA: return "Ninja"; - case JOB_XMAS: return "Christmas"; - case JOB_NOVICE_HIGH: return "Novice High"; - case JOB_SWORDMAN_HIGH: return "Swordsman High"; - case JOB_MAGE_HIGH: return "Mage High"; - case JOB_ARCHER_HIGH: return "Archer High"; - case JOB_ACOLYTE_HIGH: return "Acolyte High"; - case JOB_MERCHANT_HIGH: return "Merchant High"; - case JOB_THIEF_HIGH: return "Thief High"; - case JOB_LORD_KNIGHT: return "Lord Knight"; - case JOB_HIGH_PRIEST: return "High Priest"; - case JOB_HIGH_WIZARD: return "High Wizard"; - case JOB_WHITESMITH: return "Whitesmith"; - case JOB_SNIPER: return "Sniper"; - case JOB_ASSASSIN_CROSS: return "Assassin Cross"; - case JOB_LORD_KNIGHT2: return "Peko Knight"; - case JOB_PALADIN: return "Paladin"; - case JOB_CHAMPION: return "Champion"; - case JOB_PROFESSOR: return "Professor"; - case JOB_STALKER: return "Stalker"; - case JOB_CREATOR: return "Creator"; - case JOB_CLOWN: return "Clown"; - case JOB_GYPSY: return "Gypsy"; - case JOB_PALADIN2: return "Peko Paladin"; - case JOB_BABY: return "Baby Novice"; - case JOB_BABY_SWORDMAN: return "Baby Swordsman"; - case JOB_BABY_MAGE: return "Baby Mage"; - case JOB_BABY_ARCHER: return "Baby Archer"; - case JOB_BABY_ACOLYTE: return "Baby Acolyte"; - case JOB_BABY_MERCHANT: return "Baby Merchant"; - case JOB_BABY_THIEF: return "Baby Thief"; - case JOB_BABY_KNIGHT: return "Baby Knight"; - case JOB_BABY_PRIEST: return "Baby Priest"; - case JOB_BABY_WIZARD: return "Baby Wizard"; - case JOB_BABY_BLACKSMITH: return "Baby Blacksmith"; - case JOB_BABY_HUNTER: return "Baby Hunter"; - case JOB_BABY_ASSASSIN: return "Baby Assassin"; - case JOB_BABY_KNIGHT2: return "Baby Peco Knight"; - case JOB_BABY_CRUSADER: return "Baby Crusader"; - case JOB_BABY_MONK: return "Baby Monk"; - case JOB_BABY_SAGE: return "Baby Sage"; - case JOB_BABY_ROGUE: return "Baby Rogue"; - case JOB_BABY_ALCHEMIST: return "Baby Alchemist"; - case JOB_BABY_BARD: return "Baby Bard"; - case JOB_BABY_DANCER: return "Baby Dancer"; - case JOB_BABY_CRUSADER2: return "Baby Peco Crusader"; - case JOB_SUPER_BABY: return "Super Baby"; - case JOB_TAEKWON: return "Taekwon"; - case JOB_STAR_GLADIATOR: return "Star Gladiator"; - case JOB_STAR_GLADIATOR2: return "Flying Star Gladiator"; - case JOB_SOUL_LINKER: return "Soul Linker"; - } - return "Unknown Job"; -} - -static int create_online_files_sub(DBKey key, void* data, va_list va) -{ - struct online_char_data *character; - int* players; - int *id; - int j,k,l; - character = (struct online_char_data*) data; - players = va_arg(va, int*); - id = va_arg(va, int*); - - // check if map-server is online - if (character->server == -1 || character->char_id == -1) { //Character not currently online. - return -1; - } - - j = character->server; - if (server[j].fd < 0) { - server[j].users = 0; - return -1; - } - // search position of character in char_dat and sort online characters. - for(j = 0; j < char_num; j++) { - if (char_dat[j].status.char_id != character->char_id) - continue; - id[*players] = j; - // use sorting option - switch (online_sorting_option) { - case 1: // by name (without case sensitive) - for(k = 0; k < *players; k++) - if (stricmp(char_dat[j].status.name, char_dat[id[k]].status.name) < 0 || - // if same name, we sort with case sensitive. - (stricmp(char_dat[j].status.name, char_dat[id[k]].status.name) == 0 && - strcmp(char_dat[j].status.name, char_dat[id[k]].status.name) < 0)) { - for(l = *players; l > k; l--) - id[l] = id[l-1]; - id[k] = j; // id[*players] - break; - } - break; - case 2: // by zeny - for(k = 0; k < *players; k++) - if (char_dat[j].status.zeny < char_dat[id[k]].status.zeny || - // if same number of zenys, we sort by name. - (char_dat[j].status.zeny == char_dat[id[k]].status.zeny && - stricmp(char_dat[j].status.name, char_dat[id[k]].status.name) < 0)) { - for(l = *players; l > k; l--) - id[l] = id[l-1]; - id[k] = j; // id[*players] - break; - } - break; - case 3: // by base level - for(k = 0; k < *players; k++) - if (char_dat[j].status.base_level < char_dat[id[k]].status.base_level || - // if same base level, we sort by base exp. - (char_dat[j].status.base_level == char_dat[id[k]].status.base_level && - char_dat[j].status.base_exp < char_dat[id[k]].status.base_exp)) { - for(l = *players; l > k; l--) - id[l] = id[l-1]; - id[k] = j; // id[*players] - break; - } - break; - case 4: // by job (and job level) - for(k = 0; k < *players; k++) - if (char_dat[j].status.class_ < char_dat[id[k]].status.class_ || - // if same job, we sort by job level. - (char_dat[j].status.class_ == char_dat[id[k]].status.class_ && - char_dat[j].status.job_level < char_dat[id[k]].status.job_level) || - // if same job and job level, we sort by job exp. - (char_dat[j].status.class_ == char_dat[id[k]].status.class_ && - char_dat[j].status.job_level == char_dat[id[k]].status.job_level && - char_dat[j].status.job_exp < char_dat[id[k]].status.job_exp)) { - for(l = *players; l > k; l--) - id[l] = id[l-1]; - id[k] = j; // id[*players] - break; - } - break; - case 5: // by location map name - { - const char *map1, *map2; - map1 = mapindex_id2name(char_dat[j].status.last_point.map); - - for(k = 0; k < *players; k++) { - map2 = mapindex_id2name(char_dat[id[k]].status.last_point.map); - if (!map1 || !map2 || //Avoid sorting if either one failed to resolve. - stricmp(map1, map2) < 0 || - // if same map name, we sort by name. - (stricmp(map1, map2) == 0 && - stricmp(char_dat[j].status.name, char_dat[id[k]].status.name) < 0)) { - for(l = *players; l > k; l--) - id[l] = id[l-1]; - id[k] = j; // id[*players] - break; - } - } - } - break; - default: // 0 or invalid value: no sorting - break; - } - (*players)++; - break; - } - return 0; -} -//------------------------------------------------------------- -// Function to create the online files (txt and html). by [Yor] -//------------------------------------------------------------- -void create_online_files(void) -{ - unsigned int k, j; // for loop with strlen comparing - int i, l; // for loops - int players; // count the number of players - FILE *fp; // for the txt file - FILE *fp2; // for the html file - char temp[256]; // to prepare what we must display - time_t time_server; // for number of seconds - struct tm *datetime; // variable for time in structure ->tm_mday, ->tm_sec, ... - int id[4096]; - - if (online_display_option == 0) // we display nothing, so return - return; - - // Get number of online players, id of each online players, and verify if a server is offline - players = 0; - online_char_db->foreach(online_char_db, create_online_files_sub, &players, &id); - - // write files - fp = fopen(online_txt_filename, "w"); - if (fp != NULL) { - fp2 = fopen(online_html_filename, "w"); - if (fp2 != NULL) { - // get time - time(&time_server); // get time in seconds since 1/1/1970 - datetime = localtime(&time_server); // convert seconds in structure - strftime(temp, sizeof(temp), "%d %b %Y %X", datetime); // like sprintf, but only for date/time (05 dec 2003 15:12:52) - // write heading - fprintf(fp2, "\n"); - fprintf(fp2, " \n", online_refresh_html); // update on client explorer every x seconds - fprintf(fp2, " \n"); - fprintf(fp2, " Online Players on %s\n", server_name); - fprintf(fp2, " \n"); - fprintf(fp2, " \n"); - fprintf(fp2, "

Online Players on %s (%s):

\n", server_name, temp); - fprintf(fp, "Online Players on %s (%s):\n", server_name, temp); - fprintf(fp, "\n"); - - for (i = 0; i < players; i++) { - // if it's the first player - if (i == 0) { - j = 0; // count the number of characters for the txt version and to set the separate line - fprintf(fp2, " \n"); - fprintf(fp2, " \n"); - if ((online_display_option & 1) || (online_display_option & 64)) { - fprintf(fp2, " \n"); - if (online_display_option & 64) { - fprintf(fp, "Name "); // 30 - j += 30; - } else { - fprintf(fp, "Name "); // 25 - j += 25; - } - } - if ((online_display_option & 6) == 6) { - fprintf(fp2, " \n"); - fprintf(fp, "Job Levels "); // 27 - j += 27; - } else if (online_display_option & 2) { - fprintf(fp2, " \n"); - fprintf(fp, "Job "); // 19 - j += 19; - } else if (online_display_option & 4) { - fprintf(fp2, " \n"); - fprintf(fp, " Levels "); // 8 - j += 8; - } - if (online_display_option & 24) { // 8 or 16 - fprintf(fp2, " \n"); - if (online_display_option & 16) { - fprintf(fp, "Location ( x , y ) "); // 23 - j += 23; - } else { - fprintf(fp, "Location "); // 13 - j += 13; - } - } - if (online_display_option & 32) { - fprintf(fp2, " \n"); - fprintf(fp, " Zenys "); // 16 - j += 16; - } - fprintf(fp2, " \n"); - fprintf(fp, "\n"); - for (k = 0; k < j; k++) - fprintf(fp, "-"); - fprintf(fp, "\n"); - } - fprintf(fp2, " \n"); - // get id of the character (more speed) - j = id[i]; - // displaying the character name - if ((online_display_option & 1) || (online_display_option & 64)) { // without/with 'GM' display - strcpy(temp, char_dat[j].status.name); - l = isGM(char_dat[j].status.account_id); - if (online_display_option & 64) { - if (l >= online_gm_display_min_level) - fprintf(fp, "%-24s (GM) ", temp); - else - fprintf(fp, "%-24s ", temp); - } else - fprintf(fp, "%-24s ", temp); - // name of the character in the html (no < >, because that create problem in html code) - fprintf(fp2, " \n"); - } - // displaying of the job - if (online_display_option & 6) { - char * jobname = job_name(char_dat[j].status.class_); - if ((online_display_option & 6) == 6) { - fprintf(fp2, " \n", jobname, char_dat[j].status.base_level, char_dat[j].status.job_level); - fprintf(fp, "%-18s %3d/%3d ", jobname, char_dat[j].status.base_level, char_dat[j].status.job_level); - } else if (online_display_option & 2) { - fprintf(fp2, " \n", jobname); - fprintf(fp, "%-18s ", jobname); - } else if (online_display_option & 4) { - fprintf(fp2, " \n", char_dat[j].status.base_level, char_dat[j].status.job_level); - fprintf(fp, "%3d/%3d ", char_dat[j].status.base_level, char_dat[j].status.job_level); - } - } - // displaying of the map - if (online_display_option & 24) { // 8 or 16 - // prepare map name - memcpy(temp, mapindex_id2name(char_dat[j].status.last_point.map), MAP_NAME_LENGTH); - // write map name - if (online_display_option & 16) { // map-name AND coordinates - fprintf(fp2, " \n", temp, char_dat[j].status.last_point.x, char_dat[j].status.last_point.y); - fprintf(fp, "%-12s (%3d,%3d) ", temp, char_dat[j].status.last_point.x, char_dat[j].status.last_point.y); - } else { - fprintf(fp2, " \n", temp); - fprintf(fp, "%-12s ", temp); - } - } - // displaying nimber of zenys - if (online_display_option & 32) { - // write number of zenys - if (char_dat[j].status.zeny == 0) { // if no zeny - fprintf(fp2, " \n"); - fprintf(fp, " no zeny "); - } else { - fprintf(fp2, " \n", char_dat[j].status.zeny); - fprintf(fp, "%13d z ", char_dat[j].status.zeny); - } - } - fprintf(fp, "\n"); - fprintf(fp2, " \n"); - } - // If we display at least 1 player - if (players > 0) { - fprintf(fp2, "
NameJob (levels)JobLevelsLocationzenys
"); - if ((online_display_option & 64) && l >= online_gm_display_min_level) - fprintf(fp2, ""); - for (k = 0; k < strlen(temp); k++) { - switch(temp[k]) { - case '<': // < - fprintf(fp2, "<"); - break; - case '>': // > - fprintf(fp2, ">"); - break; - default: - fprintf(fp2, "%c", temp[k]); - break; - }; - } - if ((online_display_option & 64) && l >= online_gm_display_min_level) - fprintf(fp2, " (GM)"); - fprintf(fp2, "%s %d/%d%s%d/%d%s (%d, %d)%sno zeny%d z
\n"); - fprintf(fp, "\n"); - } - - // Displaying number of online players - if (players == 0) { - fprintf(fp2, "

No user is online.

\n"); - fprintf(fp, "No user is online.\n"); - } else if (players == 1) { - fprintf(fp2, "

%d user is online.

\n", players); - fprintf(fp, "%d user is online.\n", players); - } else { - fprintf(fp2, "

%d users are online.

\n", players); - fprintf(fp, "%d users are online.\n", players); - } - fprintf(fp2, " \n"); - fprintf(fp2, "\n"); - fclose(fp2); - } - fclose(fp); - } - - return; -} - -//--------------------------------------------------------------------- -// This function return the number of online players in all map-servers -//--------------------------------------------------------------------- -int count_users(void) -{ - int i, users; - - users = 0; - for(i = 0; i < MAX_MAP_SERVERS; i++) - if (server[i].fd >= 0) - users += server[i].users; - - return users; -} - -/// Writes char data to the buffer in the format used by the client. -/// Used in packets 0x6b (chars info) and 0x6d (new char info) -/// Returns the size (106 or 108) -int mmo_char_tobuf(uint8* buf, struct mmo_charstatus* p) -{ - if( buf == NULL || p == NULL ) - return 0; - - WBUFL(buf,0) = p->char_id; - WBUFL(buf,4) = min(p->base_exp, LONG_MAX); - WBUFL(buf,8) = p->zeny; - WBUFL(buf,12) = min(p->job_exp, LONG_MAX); - WBUFL(buf,16) = p->job_level; - WBUFL(buf,20) = 0; // probably opt1 - WBUFL(buf,24) = 0; // probably opt2 - WBUFL(buf,28) = p->option; - WBUFL(buf,32) = p->karma; - WBUFL(buf,36) = p->manner; - WBUFW(buf,40) = min(p->status_point, SHRT_MAX); - WBUFW(buf,42) = min(p->hp, SHRT_MAX); - WBUFW(buf,44) = min(p->max_hp, SHRT_MAX); - WBUFW(buf,46) = min(p->sp, SHRT_MAX); - WBUFW(buf,48) = min(p->max_sp, SHRT_MAX); - WBUFW(buf,50) = DEFAULT_WALK_SPEED; // p->speed; - WBUFW(buf,52) = p->class_; - WBUFW(buf,54) = p->hair; - WBUFW(buf,56) = p->option&0x20 ? 0 : p->weapon; //When the weapon is sent and your option is riding, the client crashes on login!? - WBUFW(buf,58) = p->base_level; - WBUFW(buf,60) = min(p->skill_point, SHRT_MAX); - WBUFW(buf,62) = p->head_bottom; - WBUFW(buf,64) = p->shield; - WBUFW(buf,66) = p->head_top; - WBUFW(buf,68) = p->head_mid; - WBUFW(buf,70) = p->hair_color; - WBUFW(buf,72) = p->clothes_color; - memcpy(WBUFP(buf,74), p->name, NAME_LENGTH); - WBUFB(buf,98) = min(p->str, UCHAR_MAX); - WBUFB(buf,99) = min(p->agi, UCHAR_MAX); - WBUFB(buf,100) = min(p->vit, UCHAR_MAX); - WBUFB(buf,101) = min(p->int_, UCHAR_MAX); - WBUFB(buf,102) = min(p->dex, UCHAR_MAX); - WBUFB(buf,103) = min(p->luk, UCHAR_MAX); - WBUFW(buf,104) = p->slot; - if (char_rename) { - WBUFW(buf,106) = 1;// Rename bit (0=rename,1=no rename) - return 108; - } else { - return 106; - } -} - -//---------------------------------------- -// Function to send characters to a player -//---------------------------------------- -int mmo_char_send006b(int fd, struct char_session_data* sd) -{ - int i, j, found_num; - - found_num = 0; - for(i = 0; i < char_num; i++) { - if (char_dat[i].status.account_id == sd->account_id) { - sd->found_char[found_num] = i; - if( ++found_num == MAX_CHARS ) - break; - } - } - for(i = found_num; i < MAX_CHARS; i++) - sd->found_char[i] = -1; - - j = 24; // offset - WFIFOHEAD(fd,j + found_num*108); // or 106(!) - WFIFOW(fd,0) = 0x6b; - memset(WFIFOP(fd,4), 0, 20); // unknown bytes - for(i = 0; i < found_num; i++) - j += mmo_char_tobuf(WFIFOP(fd,j), &char_dat[sd->found_char[i]].status); - WFIFOW(fd,2) = j; // packet len - WFIFOSET(fd,j); - - return 0; -} - -// 離婚(char削除時に使用) -int char_divorce(struct mmo_charstatus *cs) -{ - if (cs == NULL) - return 0; - - if (cs->partner_id > 0){ - int i, j; - for(i = 0; i < char_num; i++) { - if (char_dat[i].status.char_id == cs->partner_id && char_dat[i].status.partner_id == cs->char_id) { - cs->partner_id = 0; - char_dat[i].status.partner_id = 0; - for(j = 0; j < MAX_INVENTORY; j++) - if (char_dat[i].status.inventory[j].nameid == WEDDING_RING_M || char_dat[i].status.inventory[j].nameid == WEDDING_RING_F) - memset(&char_dat[i].status.inventory[j], 0, sizeof(char_dat[i].status.inventory[0])); - if (cs->inventory[j].nameid == WEDDING_RING_M || cs->inventory[j].nameid == WEDDING_RING_F) - memset(&cs->inventory[j], 0, sizeof(cs->inventory[0])); - return 0; - } - } - } - return 0; -} - -int char_married(int pl1,int pl2) -{ - return (char_dat[pl1].status.char_id == char_dat[pl2].status.partner_id && char_dat[pl2].status.char_id == char_dat[pl1].status.partner_id); -} - -int char_child(int parent_id, int child_id) -{ - return (char_dat[parent_id].status.child == char_dat[child_id].status.char_id && - ((char_dat[parent_id].status.char_id == char_dat[child_id].status.father) || - (char_dat[parent_id].status.char_id == char_dat[child_id].status.mother))); -} - -int char_family(int cid1, int cid2, int cid3) -{ - int i, idx1 = -1, idx2 =-1;//, idx3 =-1; - for(i = 0; i < char_num && (idx1 == -1 || idx2 == -1/* || idx3 == 1*/); i++) - { - if (char_dat[i].status.char_id == cid1) - idx1 = i; - if (char_dat[i].status.char_id == cid2) - idx2 = i; -// if (char_dat[i].status.char_id == cid2) -// idx3 = i; - } - if (idx1 == -1 || idx2 == -1/* || idx3 == -1*/) - return 0; //Some character not found?? - - //Unless the dbs are corrupted, these 3 checks should suffice, even though - //we could do a lot more checks and force cross-reference integrity. - if(char_dat[idx1].status.partner_id == cid2 && - char_dat[idx1].status.child == cid3) - return cid3; //cid1/cid2 parents. cid3 child. - - if(char_dat[idx1].status.partner_id == cid3 && - char_dat[idx1].status.child == cid2) - return cid2; //cid1/cid3 parents. cid2 child. - - if(char_dat[idx2].status.partner_id == cid3 && - char_dat[idx2].status.child == cid1) - return cid1; //cid2/cid3 parents. cid1 child. - return 0; -} - -//Clears the given party id from all characters. -//Since sometimes the party format changes and parties must be wiped, this -//method is required to prevent stress during the "party not found!" stages. -void char_clearparty(int party_id) -{ - int i; - for(i = 0; i < char_num; i++) - { - if (char_dat[i].status.party_id == party_id) - char_dat[i].status.party_id = 0; - } -} - -//---------------------------------------------------------------------- -// Force disconnection of an online player (with account value) by [Yor] -//---------------------------------------------------------------------- -int disconnect_player(int account_id) -{ - int i; - struct char_session_data *sd; - - // disconnect player if online on char-server - for(i = 0; i < fd_max; i++) { - if (session[i] && (sd = (struct char_session_data*)session[i]->session_data)) { - if (sd->account_id == account_id) { - set_eof(i); - return 1; - } - } - } - - return 0; -} - -// キャラ削除に伴うデータ削除 -static int char_delete(struct mmo_charstatus *cs) -{ - int j; - - // ペット削除 - if (cs->pet_id) - inter_pet_delete(cs->pet_id); - if (cs->hom_id) - inter_homun_delete(cs->hom_id); - for (j = 0; j < MAX_INVENTORY; j++) - if (cs->inventory[j].card[0] == (short)0xff00) - inter_pet_delete(MakeDWord(cs->inventory[j].card[1],cs->inventory[j].card[2])); - for (j = 0; j < MAX_CART; j++) - if (cs->cart[j].card[0] == (short)0xff00) - inter_pet_delete( MakeDWord(cs->cart[j].card[1],cs->cart[j].card[2]) ); - // ギルド脱退 - if (cs->guild_id) - inter_guild_leave(cs->guild_id, cs->account_id, cs->char_id); - // パーティー脱退 - if (cs->party_id) - inter_party_leave(cs->party_id, cs->account_id, cs->char_id); - // 離婚 - if (cs->partner_id){ - // 離婚情報をmapに通知 - unsigned char buf[10]; - WBUFW(buf,0) = 0x2b12; - WBUFL(buf,2) = cs->char_id; - WBUFL(buf,6) = cs->partner_id; - mapif_sendall(buf,10); - // 離婚 - char_divorce(cs); - } -#ifdef ENABLE_SC_SAVING - status_delete_scdata(cs->account_id, cs->char_id); -#endif - return 0; -} - -static void char_auth_ok(int fd, struct char_session_data *sd) -{ - struct online_char_data* character; - if (max_connect_user && count_users() >= max_connect_user && isGM(sd->account_id) < gm_allow_level) - { - // refuse connection (over populated) - WFIFOW(fd,0) = 0x6c; - WFIFOW(fd,2) = 0; - WFIFOSET(fd,3); - return; - } - - if( online_check && (character = (struct online_char_data*)idb_get(online_char_db, sd->account_id)) != NULL ) - { // check if character is not online already. [Skotlex] - if (character->server > -1) - { //Character already online. KICK KICK KICK - mapif_disconnectplayer(server[character->server].fd, character->account_id, character->char_id, 2); - if (character->waiting_disconnect == -1) - character->waiting_disconnect = add_timer(gettick()+20000, chardb_waiting_disconnect, character->account_id, 0); - WFIFOW(fd,0) = 0x81; - WFIFOB(fd,2) = 8; - WFIFOSET(fd,3); - return; - } - if (character->fd >= 0 && character->fd != fd) - { //There's already a connection from this account that hasn't picked a char yet. - WFIFOW(fd,0) = 0x81; - WFIFOB(fd,2) = 8; - WFIFOSET(fd,3); - return; - } - character->fd = fd; - } - - if (login_fd > 0) { - // request to login-server to obtain e-mail/time limit - //FIXME: isn't this part of the auth_ok packet? [ultramage] - WFIFOHEAD(login_fd,6); - WFIFOW(login_fd,0) = 0x2716; - WFIFOL(login_fd,2) = sd->account_id; - WFIFOSET(login_fd,6); - } - - // mark session as 'authed' - sd->auth = true; - - // set char online on charserver - set_char_online(-1, 99, sd->account_id); - - // send characters to player - mmo_char_send006b(fd, sd); -} - -int send_accounts_tologin(int tid, unsigned int tick, int id, int data); - -int parse_fromlogin(int fd) -{ - int i; - struct char_session_data *sd; - - // only login-server can have an access to here. - // so, if it isn't the login-server, we disconnect the session. - if( fd != login_fd ) - set_eof(fd); - - if(session[fd]->flag.eof) { - if (fd == login_fd) { - ShowWarning("Connection to login-server lost (connection #%d).\n", fd); - login_fd = -1; - } - do_close(fd); - return 0; - } - - sd = (struct char_session_data*)session[fd]->session_data; - - while(RFIFOREST(fd) >= 2) - { - uint16 command = RFIFOW(fd,0); - - switch( command ) - { - - // acknowledgement of connect-to-loginserver request - case 0x2711: - if (RFIFOREST(fd) < 3) - return 0; - - if (RFIFOB(fd,2)) { - //printf("connect login server error : %d\n", RFIFOB(fd,2)); - ShowError("Can not connect to login-server.\n"); - ShowError("The server communication passwords (default s1/p1) are probably invalid.\n"); - ShowInfo("Also, please make sure your accounts file (default: accounts.txt) has those values present.\n"); - ShowInfo("The communication passwords can be changed in map_athena.conf and char_athena.conf\n"); - } else { - ShowStatus("Connected to login-server (connection #%d).\n", fd); - - //Send online accounts to login server. - send_accounts_tologin(-1, gettick(), 0, 0); - - // if no map-server already connected, display a message... - ARR_FIND( 0, MAX_MAP_SERVERS, i, server[i].fd > 0 && server[i].map[0] ); - if( i == MAX_MAP_SERVERS ) - ShowStatus("Awaiting maps from map-server.\n"); - } - RFIFOSKIP(fd,3); - break; - - // acknowledgement of account authentication request - case 0x2713: - if (RFIFOREST(fd) < 59) - return 0; - { - int account_id = RFIFOL(fd,2); - int login_id1 = RFIFOL(fd,6); - int login_id2 = RFIFOL(fd,10); - bool result = RFIFOB(fd,14); - const char* email = (const char*)RFIFOP(fd,15); - time_t expiration_time = (time_t)RFIFOL(fd,55); - - // find the session with this account id - ARR_FIND( 0, fd_max, i, session[i] && (sd = (struct char_session_data*)session[i]->session_data) && - sd->account_id == account_id && sd->login_id1 == login_id1 && sd->login_id2 == login_id2 ); - if( i < fd_max ) - { - if( result ) { // failure - WFIFOHEAD(i,3); - WFIFOW(i,0) = 0x6c; - WFIFOB(i,2) = 0x42; - WFIFOSET(i,3); - } else { // success - memcpy(sd->email, email, 40); - if (e_mail_check(sd->email) == 0) - strncpy(sd->email, "a@a.com", 40); // default e-mail - sd->expiration_time = expiration_time; - char_auth_ok(i, sd); - } - } - } - RFIFOSKIP(fd,59); - break; - - // Receiving of an e-mail/time limit from the login-server (answer of a request because a player comes back from map-server to char-server) by [Yor] - case 0x2717: - if (RFIFOREST(fd) < 50) - return 0; - for(i = 0; i < fd_max; i++) { - if (session[i] && (sd = (struct char_session_data*)session[i]->session_data)) { - if (sd->account_id == RFIFOL(fd,2)) { - memcpy(sd->email, RFIFOP(fd,6), 40); - if (e_mail_check(sd->email) == 0) - strncpy(sd->email, "a@a.com", 40); // default e-mail - sd->expiration_time = (time_t)RFIFOL(fd,46); - break; - } - } - } - RFIFOSKIP(fd,50); - break; - - // login-server alive packet - case 0x2718: - if (RFIFOREST(fd) < 2) - return 0; - RFIFOSKIP(fd,2); - break; - - // changesex reply - case 0x2723: - if (RFIFOREST(fd) < 7) - return 0; - { - int i, j; - unsigned char buf[7]; - - int acc = RFIFOL(fd,2); - int sex = RFIFOB(fd,6); - RFIFOSKIP(fd,7); - - if( acc > 0 ) - { - struct auth_node* node = (struct auth_node*)idb_get(auth_db, acc); - if( node != NULL ) - node->sex = sex; - - ARR_FIND( 0, char_num, i, char_dat[i].status.account_id == acc ); - if( i < char_num ) - { - int jobclass = char_dat[i].status.class_; - char_dat[i].status.sex = sex; - if (jobclass == JOB_BARD || jobclass == JOB_DANCER || - jobclass == JOB_CLOWN || jobclass == JOB_GYPSY || - jobclass == JOB_BABY_BARD || jobclass == JOB_BABY_DANCER) { - // job modification - if (jobclass == JOB_BARD || jobclass == JOB_DANCER) { - char_dat[i].status.class_ = (sex) ? JOB_BARD : JOB_DANCER; - } else if (jobclass == JOB_CLOWN || jobclass == JOB_GYPSY) { - char_dat[i].status.class_ = (sex) ? JOB_CLOWN : JOB_GYPSY; - } else if (jobclass == JOB_BABY_BARD || jobclass == JOB_BABY_DANCER) { - char_dat[i].status.class_ = (sex) ? JOB_BABY_BARD : JOB_BABY_DANCER; - } - // remove specifical skills of classes 19, 4020 and 4042 - for(j = 315; j <= 322; j++) { - if (char_dat[i].status.skill[j].id > 0 && !char_dat[i].status.skill[j].flag) { - if (char_dat[i].status.skill_point > USHRT_MAX - char_dat[i].status.skill[j].lv) - char_dat[i].status.skill_point = USHRT_MAX; - else - char_dat[i].status.skill_point += char_dat[i].status.skill[j].lv; - char_dat[i].status.skill[j].id = 0; - char_dat[i].status.skill[j].lv = 0; - } - } - // remove specifical skills of classes 20, 4021 and 4043 - for(j = 323; j <= 330; j++) { - if (char_dat[i].status.skill[j].id > 0 && !char_dat[i].status.skill[j].flag) { - if (char_dat[i].status.skill_point > USHRT_MAX - char_dat[i].status.skill[j].lv) - char_dat[i].status.skill_point = USHRT_MAX; - else - char_dat[i].status.skill_point += char_dat[i].status.skill[j].lv; - - char_dat[i].status.skill[j].id = 0; - char_dat[i].status.skill[j].lv = 0; - } - } - } - // to avoid any problem with equipment and invalid sex, equipment is unequiped. - for (j = 0; j < MAX_INVENTORY; j++) { - if (char_dat[i].status.inventory[j].nameid && char_dat[i].status.inventory[j].equip) - char_dat[i].status.inventory[j].equip = 0; - } - char_dat[i].status.weapon = 0; - char_dat[i].status.shield = 0; - char_dat[i].status.head_top = 0; - char_dat[i].status.head_mid = 0; - char_dat[i].status.head_bottom = 0; - - if (char_dat[i].status.guild_id) //If there is a guild, update the guild_member data [Skotlex] - inter_guild_sex_changed(char_dat[i].status.guild_id, acc, char_dat[i].status.char_id, sex); - } - // disconnect player if online on char-server - disconnect_player(acc); - } - WBUFW(buf,0) = 0x2b0d; - WBUFL(buf,2) = acc; - WBUFB(buf,6) = sex; - mapif_sendall(buf, 7); - } - break; - - case 0x2726: // Request to send a broadcast message (no answer) - if (RFIFOREST(fd) < 8 || RFIFOREST(fd) < (8 + RFIFOL(fd,4))) - return 0; - if (RFIFOL(fd,4) < 1) - char_log("Receiving a message for broadcast, but message is void.\n"); - else - { - // at least 1 map-server - ARR_FIND( 0, MAX_MAP_SERVERS, i, server[i].fd >= 0 ); - if (i == MAX_MAP_SERVERS) - char_log("'ladmin': Receiving a message for broadcast, but no map-server is online.\n"); - else { - unsigned char buf[128]; - char message[4096]; // +1 to add a null terminated if not exist in the packet - int lp; - char *p; - memset(message, '\0', sizeof(message)); - memcpy(message, RFIFOP(fd,8), RFIFOL(fd,4)); - message[sizeof(message)-1] = '\0'; - remove_control_chars(message); - // remove all first spaces - p = message; - while(p[0] == ' ') - p++; - // if message is only composed of spaces - if (p[0] == '\0') - char_log("Receiving a message for broadcast, but message is only a lot of spaces.\n"); - // else send message to all map-servers - else { - if (RFIFOW(fd,2) == 0) { - char_log("'ladmin': Receiving a message for broadcast (message (in yellow): %s)\n", - message); - lp = 4; - } else { - char_log("'ladmin': Receiving a message for broadcast (message (in blue): %s)\n", - message); - lp = 8; - } - // split message to max 80 char - while(p[0] != '\0') { // if not finish - if (p[0] == ' ') // jump if first char is a space - p++; - else { - char split[80]; - char* last_space; - sscanf(p, "%79[^\t]", split); // max 79 char, any char (\t is control char and control char was removed before) - split[sizeof(split)-1] = '\0'; // last char always \0 - if ((last_space = strrchr(split, ' ')) != NULL) { // searching space from end of the string - last_space[0] = '\0'; // replace it by NULL to have correct length of split - p++; // to jump the new NULL - } - p += strlen(split); - // send broadcast to all map-servers - WBUFW(buf,0) = 0x3800; - WBUFW(buf,2) = lp + strlen(split) + 1; - WBUFL(buf,4) = 0x65756c62; // only write if in blue (lp = 8) - memcpy(WBUFP(buf,lp), split, strlen(split) + 1); - mapif_sendall(buf, WBUFW(buf,2)); - } - } - } - } - } - RFIFOSKIP(fd,8 + RFIFOL(fd,4)); - break; - - // account_reg2変更通知 - case 0x2729: - if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2)) - return 0; - { //Receive account_reg2 registry, forward to map servers. - unsigned char buf[ACCOUNT_REG2_NUM*(256+32+2)+16]; - memcpy(buf,RFIFOP(fd,0), RFIFOW(fd,2)); -// WBUFW(buf,0) = 0x2b11; - WBUFW(buf,0) = 0x3804; //Map server can now receive all kinds of reg values with the same packet. [Skotlex] - mapif_sendall(buf, WBUFW(buf,2)); - RFIFOSKIP(fd, RFIFOW(fd,2)); - } - break; - - // Account deletion notification (from login-server) - case 0x2730: - if (RFIFOREST(fd) < 6) - return 0; - // Deletion of all characters of the account - for(i = 0; i < char_num; i++) { - if (char_dat[i].status.account_id == RFIFOL(fd,2)) { - char_delete(&char_dat[i].status); - if (i < char_num - 1) { - memcpy(&char_dat[i], &char_dat[char_num-1], sizeof(struct character_data)); - // if moved character owns to deleted account, check again it's character - if (char_dat[i].status.account_id == RFIFOL(fd,2)) { - i--; - // Correct moved character reference in the character's owner by [Yor] - } else { - int j, k; - struct char_session_data *sd2; - for (j = 0; j < fd_max; j++) { - if (session[j] && (sd2 = (struct char_session_data*)session[j]->session_data) && - sd2->account_id == char_dat[char_num-1].status.account_id) { - for (k = 0; k < MAX_CHARS; k++) { - if (sd2->found_char[k] == char_num-1) { - sd2->found_char[k] = i; - break; - } - } - break; - } - } - } - } - char_num--; - } - } - // Deletion of the storage - inter_storage_delete(RFIFOL(fd,2)); - // send to all map-servers to disconnect the player - { - unsigned char buf[6]; - WBUFW(buf,0) = 0x2b13; - WBUFL(buf,2) = RFIFOL(fd,2); - mapif_sendall(buf, 6); - } - // disconnect player if online on char-server - disconnect_player(RFIFOL(fd,2)); - RFIFOSKIP(fd,6); - break; - - // State change of account/ban notification (from login-server) by [Yor] - case 0x2731: - if (RFIFOREST(fd) < 11) - return 0; - // send to all map-servers to disconnect the player - { - unsigned char buf[11]; - WBUFW(buf,0) = 0x2b14; - WBUFL(buf,2) = RFIFOL(fd,2); - WBUFB(buf,6) = RFIFOB(fd,6); // 0: change of statut, 1: ban - WBUFL(buf,7) = RFIFOL(fd,7); // status or final date of a banishment - mapif_sendall(buf, 11); - } - // disconnect player if online on char-server - disconnect_player(RFIFOL(fd,2)); - RFIFOSKIP(fd,11); - break; - - // Receiving GM acounts info from login-server (by [Yor]) - case 0x2732: - if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2)) - return 0; - { - unsigned char buf[32000]; //FIXME: this will crash - if (gm_account != NULL) - aFree(gm_account); - CREATE(gm_account, struct gm_account, (RFIFOW(fd,2) - 4)/5); - GM_num = 0; - for (i = 4; i < RFIFOW(fd,2); i = i + 5) { - gm_account[GM_num].account_id = RFIFOL(fd,i); - gm_account[GM_num].level = (int)RFIFOB(fd,i+4); - //printf("GM account: %d -> level %d\n", gm_account[GM_num].account_id, gm_account[GM_num].level); - GM_num++; - } - ShowStatus("From login-server: receiving information of %d GM accounts.\n", GM_num); - char_log("From login-server: receiving information of %d GM accounts.\n", GM_num); - // send new gm acccounts level to map-servers - memcpy(buf, RFIFOP(fd,0), RFIFOW(fd,2)); - WBUFW(buf,0) = 0x2b15; - mapif_sendall(buf, RFIFOW(fd,2)); - - RFIFOSKIP(fd,RFIFOW(fd,2)); - } - break; - - // Login server request to kick a character out. [Skotlex] - case 0x2734: - if (RFIFOREST(fd) < 6) - return 0; - { - int aid = RFIFOL(fd,2); - struct online_char_data* character = (struct online_char_data*)idb_get(online_char_db, aid); - RFIFOSKIP(fd,6); - if( character != NULL ) - {// account is already marked as online! - if( character->server > -1 ) - { //Kick it from the map server it is on. - mapif_disconnectplayer(server[character->server].fd, character->account_id, character->char_id, 2); - if (character->waiting_disconnect == -1) - character->waiting_disconnect = add_timer(gettick()+AUTH_TIMEOUT, chardb_waiting_disconnect, character->account_id, 0); - } - else - {// Manual kick from char server. - struct char_session_data *tsd; - int i; - ARR_FIND( 0, fd_max, i, session[i] && (tsd = (struct char_session_data*)session[i]->session_data) && tsd->account_id == aid ); - if( i < fd_max ) - { - WFIFOHEAD(i,3); - WFIFOW(i,0) = 0x81; - WFIFOB(i,2) = 2; // "Someone has already logged in with this id" - WFIFOSET(i,3); - set_eof(i); - } - else //Shouldn't happen, but just in case. - set_char_offline(99, aid); - } - } - } - break; - - case 0x2735: - { - unsigned char buf[2]; - uint32 new_ip = 0; - - WBUFW(buf,0) = 0x2b1e; - mapif_sendall(buf, 2); - - new_ip = host2ip(login_ip_str); - if (new_ip && new_ip != login_ip) - login_ip = new_ip; //Update login up. - - new_ip = host2ip(char_ip_str); - if (new_ip && new_ip != char_ip) - { //Update ip. - char_ip = new_ip; - ShowInfo("Updating IP for [%s].\n", char_ip_str); - WFIFOHEAD(fd,6); - WFIFOW(fd,0) = 0x2736; - WFIFOL(fd,2) = htonl(char_ip); - WFIFOSET(fd,6); - } - - RFIFOSKIP(fd,2); - } - break; - - default: - ShowError("Unknown packet 0x%04x received from login-server, disconnecting.\n", RFIFOW(fd,0)); - set_eof(fd); - return 0; - } - } - - RFIFOFLUSH(fd); - return 0; -} - -int request_accreg2(int account_id, int char_id) -{ - if (login_fd > 0) { - WFIFOHEAD(login_fd,10); - WFIFOW(login_fd,0) = 0x272e; - WFIFOL(login_fd,2) = account_id; - WFIFOL(login_fd,6) = char_id; - WFIFOSET(login_fd,10); - return 1; - } - return 0; -} - -//Send packet forward to login-server for account saving -int save_accreg2(unsigned char* buf, int len) -{ - if (login_fd > 0) { - WFIFOHEAD(login_fd,len+4); - memcpy(WFIFOP(login_fd,4), buf, len); - WFIFOW(login_fd,0) = 0x2728; - WFIFOW(login_fd,2) = len+4; - WFIFOSET(login_fd,len+4); - return 1; - } - return 0; -} - -//Receive Registry information for a character. -int char_parse_Registry(int account_id, int char_id, unsigned char *buf, int buf_len) -{ - int i,j,p,len; - for (i = 0; i < char_num; i++) { - if (char_dat[i].status.account_id == account_id && char_dat[i].status.char_id == char_id) - break; - } - if(i >= char_num) //Character not found? - return 1; - for(j=0,p=0;j= char_num){ //Character not found? Sent empty packet. - WFIFOW(fd,2)=13; - }else{ - for (p=13,j = 0; j < char_dat[i].global_num; j++) { - if (char_dat[i].global[j].str[0]) { - p+= sprintf((char*)WFIFOP(fd,p), "%s", char_dat[i].global[j].str)+1; //We add 1 to consider the '\0' in place. - p+= sprintf((char*)WFIFOP(fd,p), "%s", char_dat[i].global[j].value)+1; - } - } - WFIFOW(fd,2)=p; - } - WFIFOSET(fd,WFIFOW(fd,2)); - return 0; -} - -void char_read_fame_list(void) -{ - int i, j, k; - struct fame_list fame_item; - CREATE_BUFFER(id, int, char_num); - - for(i = 0; i < char_num; i++) { - id[i] = i; - for(j = 0; j < i; j++) { - if (char_dat[i].status.fame > char_dat[id[j]].status.fame) { - for(k = i; k > j; k--) - id[k] = id[k-1]; - id[j] = i; // id[i] - break; - } - } - } - - // Empty ranking lists - 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)); - // Build Blacksmith ranking list - for (i = 0, j = 0; i < char_num && j < fame_list_size_smith; i++) { - if (char_dat[id[i]].status.fame && ( - char_dat[id[i]].status.class_ == JOB_BLACKSMITH || - char_dat[id[i]].status.class_ == JOB_WHITESMITH || - char_dat[id[i]].status.class_ == JOB_BABY_BLACKSMITH)) - { - fame_item.id = char_dat[id[i]].status.char_id; - fame_item.fame = char_dat[id[i]].status.fame; - strncpy(fame_item.name, char_dat[id[i]].status.name, NAME_LENGTH); - - memcpy(&smith_fame_list[j],&fame_item,sizeof(struct fame_list)); - j++; - } - } - // Build Alchemist ranking list - for (i = 0, j = 0; i < char_num && j < fame_list_size_chemist; i++) { - if (char_dat[id[i]].status.fame && ( - char_dat[id[i]].status.class_ == JOB_ALCHEMIST || - char_dat[id[i]].status.class_ == JOB_CREATOR || - char_dat[id[i]].status.class_ == JOB_BABY_ALCHEMIST)) - { - fame_item.id = char_dat[id[i]].status.char_id; - fame_item.fame = char_dat[id[i]].status.fame; - strncpy(fame_item.name, char_dat[id[i]].status.name, NAME_LENGTH); - - memcpy(&chemist_fame_list[j],&fame_item,sizeof(struct fame_list)); - - j++; - } - } - // Build Taekwon ranking list - for (i = 0, j = 0; i < char_num && j < fame_list_size_taekwon; i++) { - if (char_dat[id[i]].status.fame && - char_dat[id[i]].status.class_ == JOB_TAEKWON) - { - fame_item.id = char_dat[id[i]].status.char_id; - fame_item.fame = char_dat[id[i]].status.fame; - strncpy(fame_item.name, char_dat[id[i]].status.name, NAME_LENGTH); - - memcpy(&taekwon_fame_list[j],&fame_item,sizeof(struct fame_list)); - - j++; - } - } - DELETE_BUFFER(id); -} -// Send map-servers the fame ranking lists -int char_send_fame_list(int fd) -{ - int i, len = 8; - unsigned char buf[32000]; - - WBUFW(buf,0) = 0x2b1b; - - for(i = 0; i < fame_list_size_smith && smith_fame_list[i].id; i++) { - memcpy(WBUFP(buf, len), &smith_fame_list[i], sizeof(struct fame_list)); - len += sizeof(struct fame_list); - } - // add blacksmith's block length - WBUFW(buf, 6) = len; - - for(i = 0; i < fame_list_size_chemist && chemist_fame_list[i].id; i++) { - memcpy(WBUFP(buf, len), &chemist_fame_list[i], sizeof(struct fame_list)); - len += sizeof(struct fame_list); - } - // add alchemist's block length - WBUFW(buf, 4) = len; - - for(i = 0; i < fame_list_size_taekwon && taekwon_fame_list[i].id; i++) { - memcpy(WBUFP(buf, len), &taekwon_fame_list[i], sizeof(struct fame_list)); - len += sizeof(struct fame_list); - } - // add total packet length - WBUFW(buf, 2) = len; - - if(fd!=-1) - mapif_send(fd, buf, len); - else - mapif_sendall(buf, len); - - return 0; -} - -void char_update_fame_list(int type, int index, int fame) -{ - unsigned char buf[9]; - WBUFW(buf,0) = 0x2b22; - WBUFB(buf,2) = type; - WBUFB(buf,3) = index; - WBUFL(buf,4) = fame; - mapif_sendall(buf, 8); -} - -//Loads a character's name and stores it in the buffer given (must be NAME_LENGTH in size) -//Returns 1 on found, 0 on not found (buffer is filled with Unknown char name) -int char_loadName(int char_id, char* name) -{ - int j; - for( j = 0; j < char_num && char_dat[j].status.char_id != char_id; ++j ) - ;// find char - if( j < char_num ) - strncpy(name, char_dat[j].status.name, NAME_LENGTH); - else - strncpy(name, unknown_char_name, NAME_LENGTH); - - return (j < char_num) ? 1 : 0; -} - -int search_mapserver(unsigned short map, uint32 ip, uint16 port); - -int parse_frommap(int fd) -{ - int i, j; - int id; - - ARR_FIND( 0, MAX_MAP_SERVERS, id, server[id].fd == fd ); - if(id == MAX_MAP_SERVERS) - set_eof(fd); - if(session[fd]->flag.eof) { - if (id < MAX_MAP_SERVERS) { - unsigned char buf[16384]; - ShowStatus("Map-server %d (session #%d) has disconnected.\n", id, fd); - //Notify other map servers that this one is gone. [Skotlex] - WBUFW(buf,0) = 0x2b20; - WBUFL(buf,4) = htonl(server[id].ip); - WBUFW(buf,8) = htons(server[id].port); - j = 0; - for(i = 0; i < MAX_MAP_PER_SERVER; i++) - if (server[id].map[i]) - WBUFW(buf,10+(j++)*4) = server[id].map[i]; - if (j > 0) { - WBUFW(buf,2) = j * 4 + 10; - mapif_sendallwos(fd, buf, WBUFW(buf,2)); - } - server[id].fd = -1; - online_char_db->foreach(online_char_db,char_db_setoffline,i); //Tag relevant chars as 'in disconnected' server. - } - do_close(fd); - create_online_files(); - return 0; - } - - while(RFIFOREST(fd) >= 2) - { - //ShowDebug("Received packet 0x%4x (%d bytes) from map-server (connection %d)\n", RFIFOW(fd, 0), RFIFOREST(fd), fd); - - switch(RFIFOW(fd,0)) - { - - case 0x2af7: // request from map-server to reload GM accounts. Transmission to login-server - if (login_fd > 0) { // don't send request if no login-server - WFIFOHEAD(login_fd,2); - WFIFOW(login_fd,0) = 0x2709; - WFIFOSET(login_fd,2); - } - RFIFOSKIP(fd,2); - break; - - case 0x2afa: // Receiving map names list from the map-server - if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2)) - return 0; - - memset(server[id].map, 0, sizeof(server[id].map)); - j = 0; - for(i = 4; i < RFIFOW(fd,2); i += 4) { - server[id].map[j] = RFIFOW(fd,i); - j++; - } - - ShowStatus("Map-Server %d connected: %d maps, from IP %d.%d.%d.%d port %d.\n", - id, j, CONVIP(server[id].ip), server[id].port); - ShowStatus("Map-server %d loading complete.\n", id); - char_log("Map-Server %d connected: %d maps, from IP %d.%d.%d.%d port %d. Map-server %d loading complete.\n", - id, j, CONVIP(server[id].ip), server[id].port, id); - - // send name for wisp to player - WFIFOHEAD(fd, 3 + NAME_LENGTH); - WFIFOW(fd,0) = 0x2afb; - WFIFOB(fd,2) = 0; - memcpy(WFIFOP(fd,3), wisp_server_name, NAME_LENGTH); - WFIFOSET(fd,3+NAME_LENGTH); - - char_send_fame_list(fd); //Send fame list. - - { - unsigned char buf[16384]; - int x; - if (j == 0) { - ShowWarning("Map-server %d has NO maps.\n", id); - char_log("WARNING: Map-server %d has NO maps.\n", id); - } else { - // Transmitting maps information to the other map-servers - WBUFW(buf,0) = 0x2b04; - WBUFW(buf,2) = j * 4 + 10; - WBUFL(buf,4) = htonl(server[id].ip); - WBUFW(buf,8) = htons(server[id].port); - memcpy(WBUFP(buf,10), RFIFOP(fd,4), j * 4); - mapif_sendallwos(fd, buf, WBUFW(buf,2)); - } - // Transmitting the maps of the other map-servers to the new map-server - for(x = 0; x < MAX_MAP_SERVERS; x++) { - if (server[x].fd > 0 && x != id) { - WFIFOHEAD(fd,10 +4*MAX_MAP_PER_SERVER); - WFIFOW(fd,0) = 0x2b04; - WFIFOL(fd,4) = htonl(server[x].ip); - WFIFOW(fd,8) = htons(server[x].port); - j = 0; - for(i = 0; i < MAX_MAP_PER_SERVER; i++) - if (server[x].map[i]) - WFIFOW(fd,10+(j++)*4) = server[x].map[i]; - if (j > 0) { - WFIFOW(fd,2) = j * 4 + 10; - WFIFOSET(fd,WFIFOW(fd,2)); - } - } - } - } - RFIFOSKIP(fd,RFIFOW(fd,2)); - break; - - case 0x2afc: //Packet command is now used for sc_data request. [Skotlex] - if (RFIFOREST(fd) < 10) - return 0; - { -#ifdef ENABLE_SC_SAVING - int aid, cid; - struct scdata *data; - aid = RFIFOL(fd,2); - cid = RFIFOL(fd,6); - data = status_search_scdata(aid, cid); - if (data->count > 0) - { //Deliver status change data. - WFIFOW(fd,0) = 0x2b1d; - WFIFOW(fd,2) = 14 + data->count*sizeof(struct status_change_data); - WFIFOL(fd,4) = aid; - WFIFOL(fd,8) = cid; - WFIFOW(fd,12) = data->count; - for (i = 0; i < data->count; i++) - memcpy(WFIFOP(fd,14+i*sizeof(struct status_change_data)), &data->data[i], sizeof(struct status_change_data)); - WFIFOSET(fd, WFIFOW(fd,2)); - status_delete_scdata(aid, cid); //Data sent, so it needs be discarded now. - } -#endif - RFIFOSKIP(fd, 10); - } - break; - - case 0x2afe: //set MAP user count - if (RFIFOREST(fd) < 4) - return 0; - if (RFIFOW(fd,2) != server[id].users) { - server[id].users = RFIFOW(fd,2); - ShowInfo("User Count: %d (Server: %d)\n", server[id].users, id); - } - RFIFOSKIP(fd, 4); - break; - - case 0x2aff: //set MAP users - if (RFIFOREST(fd) < 6 || RFIFOREST(fd) < RFIFOW(fd,2)) - return 0; - //TODO: When data mismatches memory, update guild/party online/offline states. - server[id].users = RFIFOW(fd,4); - online_char_db->foreach(online_char_db,char_db_setoffline,id); //Set all chars from this server as 'unknown' - for(i = 0; i < server[id].users; i++) { - int aid, cid; - struct online_char_data* character; - aid = RFIFOL(fd,6+i*8); - cid = RFIFOL(fd,6+i*8+4); - character = (struct online_char_data*)idb_ensure(online_char_db, aid, create_online_char_data); - if (online_check && character->server > -1 && character->server != id) - { - ShowNotice("Set map user: Character (%d:%d) marked on map server %d, but map server %d claims to have (%d:%d) online!\n", - character->account_id, character->char_id, character->server, id, aid, cid); - mapif_disconnectplayer(server[character->server].fd, character->account_id, character->char_id, 2); - } - character->char_id = cid; - character->server = id; - } - //If any chars remain in -2, they will be cleaned in the cleanup timer. - RFIFOSKIP(fd,6+i*8); - break; - - case 0x2b01: // Receive character data from map-server for saving - if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2)) - return 0; - for(i = 0; i < char_num; i++) { - if (char_dat[i].status.account_id == RFIFOL(fd,4) && - char_dat[i].status.char_id == RFIFOL(fd,8)) - break; - } - if (i != char_num) - memcpy(&char_dat[i].status, RFIFOP(fd,13), sizeof(struct mmo_charstatus)); - if (RFIFOB(fd,12)) - { //Flag, set character offline. [Skotlex] - set_char_offline(RFIFOL(fd,8),RFIFOL(fd,4)); - WFIFOW(fd,0) = 0x2b21; //Save ack only needed on final save. - WFIFOL(fd,2) = RFIFOL(fd,4); - WFIFOL(fd,6) = RFIFOL(fd,8); - WFIFOSET(fd,10); - } - RFIFOSKIP(fd,RFIFOW(fd,2)); - break; - - case 0x2b02: // req char selection - if( RFIFOREST(fd) < 18 ) - return 0; - { - struct auth_node* node; - - int account_id = RFIFOL(fd,2); - uint32 login_id1 = RFIFOL(fd,6); - uint32 login_id2 = RFIFOL(fd,10); - uint32 ip = RFIFOL(fd,14); - RFIFOSKIP(fd,18); - - // create temporary auth entry - CREATE(node, struct auth_node, 1); - node->account_id = account_id; - node->char_id = 0; - node->login_id1 = login_id1; - node->login_id2 = login_id2; - //node->sex = 0; - node->ip = ntohl(ip); - node->expiration_time = 0; // unlimited/unknown time by default (not display in map-server) - idb_put(auth_db, account_id, node); - - //Set char to "@ char select" in online db [Kevin] - set_char_online(-3, 99, account_id); - - WFIFOHEAD(fd,7); - WFIFOW(fd,0) = 0x2b03; - WFIFOL(fd,2) = account_id; - WFIFOB(fd,6) = 0; - WFIFOSET(fd,7); - } - break; - - case 0x2b05: // request "change map server" - if (RFIFOREST(fd) < 35) - return 0; - { - unsigned short name; - int map_id, map_fd = -1; - struct online_char_data* data; - struct mmo_charstatus* char_data; - - name = RFIFOW(fd,18); - map_id = search_mapserver(name, ntohl(RFIFOL(fd,24)), ntohs(RFIFOW(fd,28))); //Locate mapserver by ip and port. - if (map_id >= 0) - map_fd = server[map_id].fd; - for(i = 0; i < char_num; i++) { - if (char_dat[i].status.account_id == RFIFOL(fd,2) && - char_dat[i].status.char_id == RFIFOL(fd,14)) - break; - } - char_data = i < char_num ? &char_dat[i].status : NULL; - //Tell the new map server about this player using Kevin's new auth packet. [Skotlex] - if (map_fd >= 0 && session[map_fd] && char_data) - { //Send the map server the auth of this player. - //Update the "last map" as this is where the player must be spawned on the new map server. - char_data->last_point.map = RFIFOW(fd,18); - char_data->last_point.x = RFIFOW(fd,20); - char_data->last_point.y = RFIFOW(fd,22); - char_data->sex = RFIFOB(fd,30); - - WFIFOHEAD(map_fd, 20 + sizeof(struct mmo_charstatus)); - WFIFOW(map_fd,0) = 0x2afd; - WFIFOW(map_fd,2) = 20 + sizeof(struct mmo_charstatus); - WFIFOL(map_fd,4) = RFIFOL(fd,2); //Account ID - WFIFOL(map_fd,8) = RFIFOL(fd,6); //Login1 - WFIFOL(map_fd,16) = RFIFOL(fd,10); //Login2 - WFIFOL(map_fd,12) = (unsigned long)0; //TODO: expiration_time, how do I figure it out right now? - memcpy(WFIFOP(map_fd,20), char_data, sizeof(struct mmo_charstatus)); - WFIFOSET(map_fd, WFIFOW(map_fd,2)); - - data = (struct online_char_data*)idb_ensure(online_char_db, RFIFOL(fd,2), create_online_char_data); - data->char_id = char_data->char_id; - data->server = map_id; //Update server where char is. - - //Reply with an ack. - WFIFOHEAD(fd,30); - WFIFOW(fd,0) = 0x2b06; - memcpy(WFIFOP(fd,2), RFIFOP(fd,2), 28); - WFIFOSET(fd,30); - } else { //Reply with nak - WFIFOHEAD(fd,30); - WFIFOW(fd,0) = 0x2b06; - memcpy(WFIFOP(fd,2), RFIFOP(fd,2), 28); - WFIFOL(fd,6) = 0; //Set login1 to 0. - WFIFOSET(fd,30); - } - RFIFOSKIP(fd,35); - } - break; - - case 0x2b08: // char name request - if (RFIFOREST(fd) < 6) - return 0; - - WFIFOHEAD(fd,30); - WFIFOW(fd,0) = 0x2b09; - WFIFOL(fd,2) = RFIFOL(fd,2); - char_loadName((int)RFIFOL(fd,2), (char*)WFIFOP(fd,6)); - WFIFOSET(fd,30); - - RFIFOSKIP(fd,6); - break; - - case 0x2b0c: // Map server send information to change an email of an account -> login-server - if (RFIFOREST(fd) < 86) - return 0; - if (login_fd > 0) { // don't send request if no login-server - WFIFOHEAD(login_fd,86); - memcpy(WFIFOP(login_fd,0), RFIFOP(fd,0),86); // 0x2722 .L .40B .40B - WFIFOW(login_fd,0) = 0x2722; - WFIFOSET(login_fd,86); - } - RFIFOSKIP(fd, 86); - break; - - case 0x2b0e: // Request from map-server to change an account's status (will just be forwarded to login server) - if (RFIFOREST(fd) < 44) - return 0; - { - int result = 0; // 0-login-server request done, 1-player not found, 2-gm level too low, 3-login-server offline - char character_name[NAME_LENGTH]; - - int acc = RFIFOL(fd,2); // account_id of who ask (-1 if server itself made this request) - const char* name = (char*)RFIFOP(fd,6); // name of the target character - int type = RFIFOW(fd,30); // type of operation: 1-block, 2-ban, 3-unblock, 4-unban - short year = RFIFOW(fd,32); - short month = RFIFOW(fd,34); - short day = RFIFOW(fd,36); - short hour = RFIFOW(fd,38); - short minute = RFIFOW(fd,40); - short second = RFIFOW(fd,42); - RFIFOSKIP(fd,44); - - safestrncpy(character_name, name, NAME_LENGTH); - i = search_character_index(character_name); - if( i < 0 ) - { - result = 1; // 1-player not found - } - else - { - char name[NAME_LENGTH]; - int account_id; - - account_id = char_dat[i].status.account_id; - safestrncpy(name, char_dat[i].status.name, NAME_LENGTH); - - if( login_fd <= 0 ) - result = 3; // 3-login-server offline - else - if( acc != -1 && isGM(acc) < isGM(account_id) ) - result = 2; // 2-gm level too low - else - switch( type ) { - case 1: // block - WFIFOHEAD(login_fd,10); - WFIFOW(login_fd,0) = 0x2724; - WFIFOL(login_fd,2) = account_id; - WFIFOL(login_fd,6) = 5; // new account status - WFIFOSET(login_fd,10); - break; - case 2: // ban - WFIFOHEAD(login_fd,18); - WFIFOW(login_fd, 0) = 0x2725; - WFIFOL(login_fd, 2) = account_id; - WFIFOW(login_fd, 6) = year; - WFIFOW(login_fd, 8) = month; - WFIFOW(login_fd,10) = day; - WFIFOW(login_fd,12) = hour; - WFIFOW(login_fd,14) = minute; - WFIFOW(login_fd,16) = second; - WFIFOSET(login_fd,18); - break; - case 3: // unblock - WFIFOHEAD(login_fd,10); - WFIFOW(login_fd,0) = 0x2724; - WFIFOL(login_fd,2) = account_id; - WFIFOL(login_fd,6) = 0; // new account status - WFIFOSET(login_fd,10); - break; - case 4: // unban - WFIFOHEAD(login_fd,6); - WFIFOW(login_fd,0) = 0x272a; - WFIFOL(login_fd,2) = account_id; - WFIFOSET(login_fd,6); - break; - case 5: // changesex - WFIFOHEAD(login_fd,6); - WFIFOW(login_fd,0) = 0x2727; - WFIFOL(login_fd,2) = account_id; - WFIFOSET(login_fd,6); - break; - } - } - - // send answer if a player ask, not if the server ask - if( acc != -1 ) { - WFIFOHEAD(fd,34); - WFIFOW(fd, 0) = 0x2b0f; - WFIFOL(fd, 2) = acc; - safestrncpy((char*)WFIFOP(fd,6), name, NAME_LENGTH); - WFIFOW(fd,30) = type; - WFIFOW(fd,32) = result; - WFIFOSET(fd,34); - } - } - break; - - case 0x2b10: // Update and send fame ranking list - if (RFIFOREST(fd) < 11) - return 0; - { - int cid = RFIFOL(fd, 2); - int fame = RFIFOL(fd, 6); - char type = RFIFOB(fd, 10); - int size; - struct fame_list* list; - int player_pos; - int fame_pos; - - switch(type) - { - case 1: size = fame_list_size_smith; list = smith_fame_list; break; - case 2: size = fame_list_size_chemist; list = chemist_fame_list; break; - case 3: size = fame_list_size_taekwon; list = taekwon_fame_list; break; - default: size = 0; list = NULL; break; - } - - ARR_FIND(0, size, player_pos, list[player_pos].id == cid);// position of the player - ARR_FIND(0, size, fame_pos, list[fame_pos].fame <= fame);// where the player should be - - if( player_pos == size && fame_pos == size ) - ;// not on list and not enough fame to get on it - else if( fame_pos == player_pos ) - {// same position - list[player_pos].fame = fame; - char_update_fame_list(type, player_pos, fame); - } - else - {// move in the list - if( player_pos == size ) - {// new ranker - not in the list - ARR_MOVE(size - 1, fame_pos, list, struct fame_list); - list[fame_pos].id = cid; - list[fame_pos].fame = fame; - char_loadName(cid, list[fame_pos].name); - } - else - {// already in the list - if( fame_pos == size ) - --fame_pos;// move to the end of the list - ARR_MOVE(player_pos, fame_pos, list, struct fame_list); - list[fame_pos].fame = fame; - } - char_send_fame_list(-1); - } - - RFIFOSKIP(fd,11); - } - break; - - case 0x2b16: // Receive rates [Wizputer] - if (RFIFOREST(fd) < 6 || RFIFOREST(fd) < RFIFOW(fd,8)) - return 0; - // Txt doesn't need this packet, so just skip it - RFIFOSKIP(fd,RFIFOW(fd,8)); - break; - - case 0x2b17: // Character disconnected set online 0 [Wizputer] - if (RFIFOREST(fd) < 6) - return 0; - set_char_offline(RFIFOL(fd,2),RFIFOL(fd,6)); - RFIFOSKIP(fd,10); - break; - - case 0x2b18: // Reset all chars to offline [Wizputer] - set_all_offline(id); - RFIFOSKIP(fd,2); - break; - - case 0x2b19: // Character set online [Wizputer] - if (RFIFOREST(fd) < 10) - return 0; - set_char_online(id, RFIFOL(fd,2),RFIFOL(fd,6)); - RFIFOSKIP(fd,10); - break; - - case 0x2b1a: // Build and send fame ranking lists [DracoRPG] - if (RFIFOREST(fd) < 2) - return 0; - char_read_fame_list(); - char_send_fame_list(-1); - RFIFOSKIP(fd,2); - break; - - case 0x2b1c: //Request to save status change data. [Skotlex] - if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2)) - return 0; - { -#ifdef ENABLE_SC_SAVING - int count, aid, cid; - struct scdata *data; - - aid = RFIFOL(fd, 4); - cid = RFIFOL(fd, 8); - count = RFIFOW(fd, 12); - - data = status_search_scdata(aid, cid); - if (data->count != count) - { - data->count = count; - data->data = (struct status_change_data*)aRealloc(data->data, count*sizeof(struct status_change_data)); - } - for (i = 0; i < count; i++) - memcpy (&data->data[i], RFIFOP(fd, 14+i*sizeof(struct status_change_data)), sizeof(struct status_change_data)); -#endif - RFIFOSKIP(fd, RFIFOW(fd, 2)); - } - break; - - case 0x2b23: // map-server alive packet - WFIFOHEAD(fd,2); - WFIFOW(fd,0) = 0x2b24; - WFIFOSET(fd,2); - RFIFOSKIP(fd,2); - break; - - case 0x2736: // ip address update - if (RFIFOREST(fd) < 6) return 0; - server[id].ip = ntohl(RFIFOL(fd, 2)); - ShowInfo("Updated IP address of map-server #%d to %d.%d.%d.%d.\n", id, CONVIP(server[id].ip)); - RFIFOSKIP(fd,6); - break; - - default: - { - // inter server - packet - int r = inter_parse_frommap(fd); - if (r == 1) break; // processed - if (r == 2) return 0; // need more packet - - // no inter server packet. no char server packet -> disconnect - ShowError("Unknown packet 0x%04x from map server, disconnecting.\n", RFIFOW(fd,0)); - set_eof(fd); - return 0; - } - } // switch - } // while - - return 0; -} - -// Searches for the mapserver that has a given map (and optionally ip/port, if not -1). -// If found, returns the server's index in the 'server' array (otherwise returns -1). -int search_mapserver(unsigned short map, uint32 ip, uint16 port) -{ - int i, j; - - for(i = 0; i < MAX_MAP_SERVERS; i++) - { - if (server[i].fd > 0 - && (ip == (uint32)-1 || server[i].ip == ip) - && (port == (uint16)-1 || server[i].port == port)) - { - for (j = 0; server[i].map[j]; j++) - if (server[i].map[j] == map) - return i; - } - } - - return -1; -} - -// char_mapifの初期化処理(現在はinter_mapif初期化のみ) -static int char_mapif_init(int fd) -{ - return inter_mapif_init(fd); -} - -//-------------------------------------------- -// Test to know if an IP come from LAN or WAN. -//-------------------------------------------- -int lan_subnetcheck(uint32 ip) -{ - int i; - ARR_FIND( 0, subnet_count, i, (subnet[i].char_ip & subnet[i].mask) == (ip & subnet[i].mask) ); - if ( i < subnet_count ) { - ShowInfo("Subnet check [%u.%u.%u.%u]: Matches "CL_CYAN"%u.%u.%u.%u/%u.%u.%u.%u"CL_RESET"\n", CONVIP(ip), CONVIP(subnet[i].char_ip & subnet[i].mask), CONVIP(subnet[i].mask)); - return subnet[i].char_ip; - } else { - ShowInfo("Subnet check [%u.%u.%u.%u]: "CL_CYAN"WAN"CL_RESET"\n", CONVIP(ip)); - return 0; - } -} - -int parse_char(int fd) -{ - int i, ch; - char email[40]; - unsigned short cmd; - int map_fd; - struct char_session_data* sd; - uint32 ipl = session[fd]->client_addr; - - sd = (struct char_session_data*)session[fd]->session_data; - - // disconnect any player if no login-server. - if(login_fd < 0) - set_eof(fd); - - if(session[fd]->flag.eof) - { - if( sd != NULL && sd->auth ) - { - struct online_char_data* data = (struct online_char_data*)idb_get(online_char_db, sd->account_id); - if( data == NULL || data->server == -1) //If it is not in any server, send it offline. [Skotlex] - set_char_offline(-1,sd->account_id); - if( data != NULL && data->fd == fd) - data->fd = -1; - } - do_close(fd); - return 0; - } - - while( RFIFOREST(fd) >= 2 ) - { - //For use in packets that depend on an sd being present [Skotlex] - #define FIFOSD_CHECK(rest) { if(RFIFOREST(fd) < rest) return 0; if (sd==NULL || !sd->auth) { RFIFOSKIP(fd,rest); return 0; } } - - cmd = RFIFOW(fd,0); - switch( cmd ) - { - - // request to connect - // 0065 .L .L .L .W .B - case 0x65: - if( RFIFOREST(fd) < 17 ) - return 0; - { - struct auth_node* node; - int GM_value; - - int account_id = RFIFOL(fd,2); - uint32 login_id1 = RFIFOL(fd,6); - uint32 login_id2 = RFIFOL(fd,10); - int sex = RFIFOB(fd,16); - RFIFOSKIP(fd,17); - - ShowInfo("request connect - account_id:%d/login_id1:%d/login_id2:%d\n", account_id, login_id1, login_id2); - - if (sd) { - //Received again auth packet for already authentified account?? Discard it. - //TODO: Perhaps log this as a hack attempt? - //TODO: and perhaps send back a reply? - break; - } - - if( (GM_value = isGM(account_id)) != 0 ) - ShowInfo("Account Logged On; Account ID: %d (GM level %d).\n", account_id, GM_value); - else - ShowInfo("Account Logged On; Account ID: %d.\n", account_id); - - CREATE(session[fd]->session_data, struct char_session_data, 1); - sd = (struct char_session_data*)session[fd]->session_data; - strncpy(sd->email, "no mail", 40); // put here a mail without '@' to refuse deletion if we don't receive the e-mail - sd->expiration_time = 0; // unknown or unlimited (not displaying on map-server) - sd->account_id = account_id; - sd->login_id1 = login_id1; - sd->login_id2 = login_id2; - sd->sex = sex; - sd->auth = false; // not authed yet - - // send back account_id - WFIFOHEAD(fd,4); - WFIFOL(fd,0) = account_id; - WFIFOSET(fd,4); - - // search authentification - node = (struct auth_node*)idb_get(auth_db, account_id); - if( node != NULL && - node->account_id == account_id && - node->login_id1 == login_id1 && - node->login_id2 == login_id2 && - node->ip == ipl ) - {// authentication found (coming from map server) - idb_remove(auth_db, account_id); - char_auth_ok(fd, sd); - } - else - {// authentication not found (coming from login server) - if (login_fd > 0) { // don't send request if no login-server - WFIFOHEAD(login_fd,19); - WFIFOW(login_fd,0) = 0x2712; // ask login-server to authentify an account - WFIFOL(login_fd,2) = sd->account_id; - WFIFOL(login_fd,6) = sd->login_id1; - WFIFOL(login_fd,10) = sd->login_id2; - WFIFOB(login_fd,14) = sd->sex; - WFIFOL(login_fd,15) = htonl(ipl); - WFIFOSET(login_fd,19); - } else { // if no login-server, we must refuse connection - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x6c; - WFIFOB(fd,2) = 0; - WFIFOSET(fd,3); - } - } - } - break; - - // char select - case 0x66: - FIFOSD_CHECK(3); - { - struct mmo_charstatus *cd; - uint32 subnet_map_ip; - struct auth_node* node; - - int slot = RFIFOB(fd,2); - RFIFOSKIP(fd,3); - - // if we activated email creation and email is default email - if (email_creation != 0 && strcmp(sd->email, "a@a.com") == 0 && login_fd > 0) { // to modify an e-mail, login-server must be online - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x70; - WFIFOB(fd,2) = 0; // 00 = Incorrect Email address - WFIFOSET(fd,3); - break; - } - // otherwise, load the character - ARR_FIND( 0, MAX_CHARS, ch, sd->found_char[ch] >= 0 && char_dat[sd->found_char[ch]].status.slot == slot ); - if (ch == MAX_CHARS) - { //Not found?? May be forged packet. - break; - } - cd = &char_dat[sd->found_char[ch]].status; - char_log("Character Selected, Account ID: %d, Character Slot: %d, Character Name: %s.\n", sd->account_id, slot, cd->name); - - cd->sex = sd->sex; - - // searching map server - i = search_mapserver(cd->last_point.map,-1,-1); - - // if map is not found, we check major cities - if (i < 0) { - unsigned short j; - //First check that there's actually a map server online. - ARR_FIND( 0, MAX_MAP_SERVERS, j, server[j].fd >= 0 && server[j].map[0] ); - if (j == MAX_MAP_SERVERS) { - ShowInfo("Connection Closed. No map servers available.\n"); - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x81; - WFIFOB(fd,2) = 1; // 01 = Server closed - WFIFOSET(fd,3); - break; - } - if ((i = search_mapserver((j=mapindex_name2id(MAP_PRONTERA)),-1,-1)) >= 0) { - cd->last_point.x = 273; - cd->last_point.y = 354; - } else if ((i = search_mapserver((j=mapindex_name2id(MAP_GEFFEN)),-1,-1)) >= 0) { - cd->last_point.x = 120; - cd->last_point.y = 100; - } else if ((i = search_mapserver((j=mapindex_name2id(MAP_MORROC)),-1,-1)) >= 0) { - cd->last_point.x = 160; - cd->last_point.y = 94; - } else if ((i = search_mapserver((j=mapindex_name2id(MAP_ALBERTA)),-1,-1)) >= 0) { - cd->last_point.x = 116; - cd->last_point.y = 57; - } else if ((i = search_mapserver((j=mapindex_name2id(MAP_PAYON)),-1,-1)) >= 0) { - cd->last_point.x = 87; - cd->last_point.y = 117; - } else if ((i = search_mapserver((j=mapindex_name2id(MAP_IZLUDE)),-1,-1)) >= 0) { - cd->last_point.x = 94; - cd->last_point.y = 103; - } else { - ShowInfo("Connection Closed. No map server available that has a major city, and unable to find map-server for '%s'.\n", mapindex_id2name(cd->last_point.map)); - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x81; - WFIFOB(fd,2) = 1; // 01 = Server closed - WFIFOSET(fd,3); - break; - } - ShowWarning("Unable to find map-server for '%s', sending to major city '%s'.\n", mapindex_id2name(cd->last_point.map), mapindex_id2name(j)); - cd->last_point.map = j; - } - - //Send NEW auth packet [Kevin] - //FIXME: is this case even possible? [ultramage] - if ((map_fd = server[i].fd) < 1 || session[map_fd] == NULL) - { - ShowError("parse_char: Attempting to write to invalid session %d! Map Server #%d disconnected.\n", map_fd, i); - server[i].fd = -1; - memset(&server[i], 0, sizeof(struct mmo_map_server)); - //Send server closed. - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x81; - WFIFOB(fd,2) = 1; // 01 = Server closed - WFIFOSET(fd,3); - break; - } - - //Send player to map - WFIFOHEAD(fd,28); - WFIFOW(fd,0) = 0x71; - WFIFOL(fd,2) = cd->char_id; - mapindex_getmapname_ext(mapindex_id2name(cd->last_point.map), (char*)WFIFOP(fd,6)); - - // Advanced subnet check [LuzZza] - subnet_map_ip = lan_subnetcheck(ipl); - WFIFOL(fd,22) = htonl((subnet_map_ip) ? subnet_map_ip : server[i].ip); - WFIFOW(fd,26) = ntows(htons(server[i].port)); // [!] LE byte order here [!] - WFIFOSET(fd,28); - - ShowInfo("Character selection '%s' (account: %d, slot: %d).\n", cd->name, sd->account_id, ch); - - //Send auth ok to map server - WFIFOHEAD(map_fd,20 + sizeof(struct mmo_charstatus)); - WFIFOW(map_fd,0) = 0x2afd; - WFIFOW(map_fd,2) = 20 + sizeof(struct mmo_charstatus); - WFIFOL(map_fd,4) = sd->account_id; - WFIFOL(map_fd,8) = sd->login_id1; - WFIFOL(map_fd,16) = sd->login_id2; - WFIFOL(map_fd,12) = (unsigned long)sd->expiration_time; - memcpy(WFIFOP(map_fd,20), cd, sizeof(struct mmo_charstatus)); - WFIFOSET(map_fd, WFIFOW(map_fd,2)); - - // create temporary auth entry - CREATE(node, struct auth_node, 1); - node->account_id = sd->account_id; - node->char_id = cd->char_id; - node->login_id1 = sd->login_id1; - node->login_id2 = sd->login_id2; - node->sex = sd->sex; - node->expiration_time = sd->expiration_time; - node->ip = ipl; - idb_put(auth_db, sd->account_id, node); - } - break; - - // create new char - // S 0067 .24B .B .B .B .B .B .B .B .W .W - case 0x67: - FIFOSD_CHECK(37); - - if( !char_new ) //turn character creation on/off [Kevin] - i = -2; - else - i = make_new_char(sd, (char*)RFIFOP(fd,2),RFIFOB(fd,26),RFIFOB(fd,27),RFIFOB(fd,28),RFIFOB(fd,29),RFIFOB(fd,30),RFIFOB(fd,31),RFIFOB(fd,32),RFIFOW(fd,33),RFIFOW(fd,35)); - - //'Charname already exists' (-1), 'Char creation denied' (-2) and 'You are underaged' (-3) - if (i < 0) - { - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x6e; - switch (i) { - case -1: WFIFOB(fd,2) = 0x00; break; - case -2: WFIFOB(fd,2) = 0x02; break; - case -3: WFIFOB(fd,2) = 0x01; break; - } - WFIFOSET(fd,3); - } - else - { - int len; - // send to player - WFIFOHEAD(fd,110); - WFIFOW(fd,0) = 0x6d; - len = 2 + mmo_char_tobuf(WFIFOP(fd,2), &char_dat[i].status); - WFIFOSET(fd,len); - - // add new entry to the chars list - ARR_FIND( 0, MAX_CHARS, ch, sd->found_char[ch] == -1 ); - if( ch < MAX_CHARS ) - sd->found_char[ch] = i; // position of the new char in the char_dat[] array - } - - RFIFOSKIP(fd,37); - break; - - // delete char - case 0x68: - // 2004-04-19aSakexe+ langtype 12 char deletion packet - case 0x1fb: - if (cmd == 0x68) FIFOSD_CHECK(46); - if (cmd == 0x1fb) FIFOSD_CHECK(56); - { - int cid = RFIFOL(fd,2); - struct mmo_charstatus* cs = NULL; - ShowInfo(CL_RED"Request Char Deletion: "CL_GREEN"%d (%d)"CL_RESET"\n", sd->account_id, cid); - memcpy(email, RFIFOP(fd,6), 40); - RFIFOSKIP(fd,RFIFOREST(fd)); // hack to make the other deletion packet work - - if (e_mail_check(email) == 0) - strncpy(email, "a@a.com", 40); // default e-mail - - // BEGIN HACK: "change email using the char deletion 'confirm email' menu" - // if we activated email creation and email is default email - if (email_creation != 0 && strcmp(sd->email, "a@a.com") == 0 && login_fd > 0) { // to modify an e-mail, login-server must be online - // if sended email is incorrect e-mail - if (strcmp(email, "a@a.com") == 0) { - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x70; - WFIFOB(fd,2) = 0; // 00 = Incorrect Email address - WFIFOSET(fd,3); - break; - } - // we change the packet to set it like selection. - ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] != -1 && char_dat[sd->found_char[i]].status.char_id == cid ); - if( i < MAX_CHARS ) - { - // we save new e-mail - memcpy(sd->email, email, 40); - // we send new e-mail to login-server ('online' login-server is checked before) - WFIFOHEAD(login_fd,46); - WFIFOW(login_fd,0) = 0x2715; - WFIFOL(login_fd,2) = sd->account_id; - memcpy(WFIFOP(login_fd, 6), email, 40); - WFIFOSET(login_fd,46); - - // change value to put new packet (char selection) - RFIFOSKIP(fd,-3); //FIXME: Will this work? Messing with the received buffer is ugly anyway... - RFIFOW(fd,0) = 0x66; - RFIFOB(fd,2) = char_dat[sd->found_char[i]].status.slot; - // not send packet, it's modify of actual packet - } else { - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x70; - WFIFOB(fd,2) = 0; // 00 = Incorrect Email address - WFIFOSET(fd,3); - } - break; - } - // END HACK - - // otherwise, we delete the character - if (strcmpi(email, sd->email) != 0) { // if it's an invalid email - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x70; - WFIFOB(fd,2) = 0; // 00 = Incorrect Email address - WFIFOSET(fd,3); - break; - } - - // check if this char exists - ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] != -1 && char_dat[sd->found_char[i]].status.char_id == cid ); - if( i == MAX_CHARS ) - { // Such a character does not exist in the account - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x70; - WFIFOB(fd,2) = 0; - WFIFOSET(fd,3); - break; - } - - // deletion process - cs = &char_dat[sd->found_char[i]].status; - char_delete(cs); - if (sd->found_char[i] != char_num - 1) { - int j, k; - struct char_session_data *sd2; - memcpy(&char_dat[sd->found_char[i]], &char_dat[char_num-1], sizeof(struct mmo_charstatus)); - // Correct moved character reference in the character's owner - for (j = 0; j < fd_max; j++) { - if (session[j] && (sd2 = (struct char_session_data*)session[j]->session_data) && - sd2->account_id == char_dat[char_num-1].status.account_id) { - for (k = 0; k < MAX_CHARS; k++) { - if (sd2->found_char[k] == char_num-1) { - sd2->found_char[k] = sd->found_char[i]; - break; - } - } - break; - } - } - } - char_num--; - - // remove char from list and compact it - for(ch = i; ch < MAX_CHARS-1; ch++) - sd->found_char[ch] = sd->found_char[ch+1]; - sd->found_char[MAX_CHARS-1] = -1; - - /* Char successfully deleted.*/ - WFIFOHEAD(fd,2); - WFIFOW(fd,0) = 0x6f; - WFIFOSET(fd,2); - } - break; - - // client keep-alive packet (every 12 seconds) - // R 0187 .l - case 0x187: - if (RFIFOREST(fd) < 6) - return 0; - RFIFOSKIP(fd,6); - break; - - // char rename request - // R 028d .l .l .24B - case 0x28d: - FIFOSD_CHECK(34); - //not implemented - RFIFOSKIP(fd,34); - break; - - // login as map-server - case 0x2af8: - if (RFIFOREST(fd) < 60) - return 0; - { - char* l_user = (char*)RFIFOP(fd,2); - char* l_pass = (char*)RFIFOP(fd,26); - l_user[23] = '\0'; - l_pass[23] = '\0'; - ARR_FIND( 0, MAX_MAP_SERVERS, i, server[i].fd <= 0 ); - if (i == MAX_MAP_SERVERS || strcmp(l_user, userid) || strcmp(l_pass, passwd)) { - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x2af9; - WFIFOB(fd,2) = 3; - WFIFOSET(fd,3); - } else { - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x2af9; - WFIFOB(fd,2) = 0; - WFIFOSET(fd,3); - - server[i].fd = fd; - server[i].ip = ntohl(RFIFOL(fd,54)); - server[i].port = ntohs(RFIFOW(fd,58)); - server[i].users = 0; - memset(server[i].map, 0, sizeof(server[i].map)); - session[fd]->func_parse = parse_frommap; - session[fd]->flag.server = 1; - realloc_fifo(fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK); - char_mapif_init(fd); - // send gm acccounts level to map-servers - WFIFOHEAD(fd,4+5*GM_num); - WFIFOW(fd,0) = 0x2b15; - for(i = 0; i < GM_num; i++) { - WFIFOL(fd,4+5*i) = gm_account[i].account_id; - WFIFOB(fd,4+5*i+4) = (unsigned char)gm_account[i].level; - } - WFIFOW(fd,2) = 4+5*GM_num; - WFIFOSET(fd,WFIFOW(fd,2)); - } - - RFIFOSKIP(fd,60); - } - return 0; // avoid processing of followup packets here - - // Athena info get - case 0x7530: - WFIFOHEAD(fd,10); - WFIFOW(fd,0) = 0x7531; - WFIFOB(fd,2) = ATHENA_MAJOR_VERSION; - WFIFOB(fd,3) = ATHENA_MINOR_VERSION; - WFIFOB(fd,4) = ATHENA_REVISION; - WFIFOB(fd,5) = ATHENA_RELEASE_FLAG; - WFIFOB(fd,6) = ATHENA_OFFICIAL_FLAG; - WFIFOB(fd,7) = ATHENA_SERVER_INTER | ATHENA_SERVER_CHAR; - WFIFOW(fd,8) = ATHENA_MOD_VERSION; - WFIFOSET(fd,10); - - RFIFOSKIP(fd,2); - break; - - // unknown packet received - default: - ShowError("parse_char: Received unknown packet "CL_WHITE"0x%x"CL_RESET" from ip '"CL_WHITE"%s"CL_RESET"'! Disconnecting!\n", RFIFOW(fd,0), ip2str(ipl, NULL)); - set_eof(fd); - return 0; - } - } - - RFIFOFLUSH(fd); - return 0; -} - -// Console Command Parser [Wizputer] -int parse_console(char* buf) -{ - char command[256]; - - memset(command, 0, sizeof(command)); - - sscanf(buf, "%[^\n]", command); - - //login_log("Console command :%s\n", command); - - if( strcmpi("shutdown", command) == 0 || - strcmpi("exit", command) == 0 || - strcmpi("quit", command) == 0 || - strcmpi("end", command) == 0 ) - runflag = 0; - else if( strcmpi("alive", command) == 0 || - strcmpi("status", command) == 0 ) - ShowInfo(CL_CYAN"Console: "CL_BOLD"I'm Alive."CL_RESET"\n"); - else if( strcmpi("help", command) == 0 ){ - ShowInfo(CL_BOLD"Help of commands:"CL_RESET"\n"); - ShowInfo(" To shutdown the server:\n"); - ShowInfo(" 'shutdown|exit|qui|end'\n"); - ShowInfo(" To know if server is alive:\n"); - ShowInfo(" 'alive|status'\n"); - } - - return 0; -} - -// 全てのMAPサーバーにデータ送信(送信したmap鯖の数を返す) -int mapif_sendall(unsigned char *buf, unsigned int len) -{ - int i, c; - - c = 0; - for(i = 0; i < MAX_MAP_SERVERS; i++) { - int fd; - if ((fd = server[i].fd) > 0) { - WFIFOHEAD(fd,len); - memcpy(WFIFOP(fd,0), buf, len); - WFIFOSET(fd,len); - c++; - } - } - - return c; -} - -// 自分以外の全てのMAPサーバーにデータ送信(送信したmap鯖の数を返す) -int mapif_sendallwos(int sfd, unsigned char *buf, unsigned int len) -{ - int i, c; - - c = 0; - for(i = 0; i < MAX_MAP_SERVERS; i++) { - int fd; - if ((fd = server[i].fd) > 0 && fd != sfd) { - WFIFOHEAD(fd,len); - memcpy(WFIFOP(fd,0), buf, len); - WFIFOSET(fd,len); - c++; - } - } - - return c; -} -// MAPサーバーにデータ送信(map鯖生存確認有り) -int mapif_send(int fd, unsigned char *buf, unsigned int len) -{ - int i; - - if (fd >= 0) { - for(i = 0; i < MAX_MAP_SERVERS; i++) { - if (fd == server[i].fd) { - WFIFOHEAD(fd,len); - memcpy(WFIFOP(fd,0), buf, len); - WFIFOSET(fd,len); - return 1; - } - } - } - return 0; -} - -int broadcast_user_count(int tid, unsigned int tick, int id, int data) -{ - uint8 buf[6]; - int users = count_users(); - - // only send an update when needed - static int prev_users = 0; - if( prev_users == users ) - return 0; - prev_users = users; - - if( login_fd > 0 && session[login_fd] ) - { - // send number of user to login server - WFIFOHEAD(login_fd,6); - WFIFOW(login_fd,0) = 0x2714; - WFIFOL(login_fd,2) = users; - WFIFOSET(login_fd,6); - } - - // send number of players to all map-servers - WBUFW(buf,0) = 0x2b00; - WBUFL(buf,2) = users; - mapif_sendall(buf,6); - - // refresh online files (txt and html) - create_online_files(); - - return 0; -} - -/// load this char's account id into the 'online accounts' packet -static int send_accounts_tologin_sub(DBKey key, void* data, va_list ap) -{ - struct online_char_data* character = (struct online_char_data*)data; - int* i = va_arg(ap, int*); - - if(character->server > -1) - { - WFIFOL(login_fd,8+(*i)*4) = character->account_id; - (*i)++; - return 1; - } - return 0; -} - -int send_accounts_tologin(int tid, unsigned int tick, int id, int data) -{ - if (login_fd > 0 && session[login_fd]) - { - // send account list to login server - int users = online_char_db->size(online_char_db); - int i = 0; - - WFIFOHEAD(login_fd,8+users*4); - WFIFOW(login_fd,0) = 0x272d; - online_char_db->foreach(online_char_db, send_accounts_tologin_sub, &i, users); - WFIFOW(login_fd,2) = 8+ i*4; - WFIFOL(login_fd,4) = i; - WFIFOSET(login_fd,WFIFOW(login_fd,2)); - } - return 0; -} - -int check_connect_login_server(int tid, unsigned int tick, int id, int data) -{ - if (login_fd > 0 && session[login_fd] != NULL) - return 0; - - ShowInfo("Attempt to connect to login-server...\n"); - login_fd = make_connection(login_ip, login_port); - if (login_fd == -1) - { //Try again later. [Skotlex] - login_fd = 0; - return 0; - } - session[login_fd]->func_parse = parse_fromlogin; - session[login_fd]->flag.server = 1; - realloc_fifo(login_fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK); - - WFIFOHEAD(login_fd,86); - WFIFOW(login_fd,0) = 0x2710; - memcpy(WFIFOP(login_fd,2), userid, 24); - memcpy(WFIFOP(login_fd,26), passwd, 24); - WFIFOL(login_fd,50) = 0; - WFIFOL(login_fd,54) = htonl(char_ip); - WFIFOL(login_fd,58) = htons(char_port); - memcpy(WFIFOP(login_fd,60), server_name, 20); - WFIFOW(login_fd,80) = 0; - WFIFOW(login_fd,82) = char_maintenance; - WFIFOW(login_fd,84) = char_new_display; //only display (New) if they want to [Kevin] - WFIFOSET(login_fd,86); - - return 1; -} - -// sends a ping packet to login server (will receive pong 0x2718) -int ping_login_server(int tid, unsigned int tick, int id, int data) -{ - if (login_fd > 0 && session[login_fd] != NULL) - { - WFIFOHEAD(login_fd,2); - WFIFOW(login_fd,0) = 0x2719; - WFIFOSET(login_fd,2); - } - return 0; -} - -//------------------------------------------------ -//Invoked 15 seconds after mapif_disconnectplayer in case the map server doesn't -//replies/disconnect the player we tried to kick. [Skotlex] -//------------------------------------------------ -static int chardb_waiting_disconnect(int tid, unsigned int tick, int id, int data) -{ - struct online_char_data* character; - if ((character = (struct online_char_data*)idb_get(online_char_db, id)) != NULL && character->waiting_disconnect == tid) - { //Mark it offline due to timeout. - character->waiting_disconnect = -1; - set_char_offline(character->char_id, character->account_id); - } - return 0; -} - -static int online_data_cleanup_sub(DBKey key, void *data, va_list ap) -{ - struct online_char_data *character= (struct online_char_data*)data; - if (character->fd != -1) - return 0; //Character still connected - if (character->server == -2) //Unknown server.. set them offline - set_char_offline(character->char_id, character->account_id); - if (character->server < 0) - //Free data from players that have not been online for a while. - db_remove(online_char_db, key); - return 0; -} - -static int online_data_cleanup(int tid, unsigned int tick, int id, int data) -{ - online_char_db->foreach(online_char_db, online_data_cleanup_sub); - return 0; -} - -//---------------------------------- -// Reading Lan Support configuration -// Rewrote: Anvanced subnet check [LuzZza] -//---------------------------------- -int char_lan_config_read(const char *lancfgName) -{ - FILE *fp; - int line_num = 0; - char line[1024], w1[64], w2[64], w3[64], w4[64]; - - if((fp = fopen(lancfgName, "r")) == NULL) { - ShowWarning("LAN Support configuration file is not found: %s\n", lancfgName); - return 1; - } - - ShowInfo("Reading the configuration file %s...\n", lancfgName); - - while(fgets(line, sizeof(line), fp)) - { - line_num++; - if ((line[0] == '/' && line[1] == '/') || line[0] == '\n' || line[1] == '\n') - continue; - - if(sscanf(line,"%[^:]: %[^:]:%[^:]:%[^\r\n]", w1, w2, w3, w4) != 4) { - - ShowWarning("Error syntax of configuration file %s in line %d.\n", lancfgName, line_num); - continue; - } - - remove_control_chars(w1); - remove_control_chars(w2); - remove_control_chars(w3); - remove_control_chars(w4); - - if( strcmpi(w1, "subnet") == 0 ) - { - subnet[subnet_count].mask = str2ip(w2); - subnet[subnet_count].char_ip = str2ip(w3); - subnet[subnet_count].map_ip = str2ip(w4); - - if( (subnet[subnet_count].char_ip & subnet[subnet_count].mask) != (subnet[subnet_count].map_ip & subnet[subnet_count].mask) ) - { - ShowError("%s: Configuration Error: The char server (%s) and map server (%s) belong to different subnetworks!\n", lancfgName, w3, w4); - continue; - } - - subnet_count++; - } - } - - ShowStatus("Read information about %d subnetworks.\n", subnet_count); - - fclose(fp); - return 0; -} -#endif //TXT_SQL_CONVERT - -int char_config_read(const char *cfgName) -{ - char line[1024], w1[1024], w2[1024]; - FILE* fp = fopen(cfgName, "r"); - - if (fp == NULL) { - ShowError("Configuration file not found: %s.\n", cfgName); - return 1; - } - - ShowInfo("Reading configuration file %s...\n", cfgName); - while(fgets(line, sizeof(line), fp)) - { - if (line[0] == '/' && line[1] == '/') - continue; - - if (sscanf(line, "%[^:]: %[^\r\n]", w1, w2) != 2) - continue; - - remove_control_chars(w1); - remove_control_chars(w2); - if(strcmpi(w1,"timestamp_format") == 0) { - strncpy(timestamp_format, w2, 20); - } else if(strcmpi(w1,"console_silent")==0){ - ShowInfo("Console Silent Setting: %d\n", atoi(w2)); - msg_silent = atoi(w2); -#ifndef TXT_SQL_CONVERT - } else if(strcmpi(w1,"stdout_with_ansisequence")==0){ - stdout_with_ansisequence = config_switch(w2); - } else if (strcmpi(w1, "userid") == 0) { - strncpy(userid, w2, 24); - } else if (strcmpi(w1, "passwd") == 0) { - strncpy(passwd, w2, 24); - } else if (strcmpi(w1, "server_name") == 0) { - strncpy(server_name, w2, 20); - server_name[sizeof(server_name) - 1] = '\0'; - ShowStatus("%s server has been initialized\n", w2); - } else if (strcmpi(w1, "wisp_server_name") == 0) { - if (strlen(w2) >= 4) { - memcpy(wisp_server_name, w2, sizeof(wisp_server_name)); - wisp_server_name[sizeof(wisp_server_name) - 1] = '\0'; - } - } else if (strcmpi(w1, "login_ip") == 0) { - char ip_str[16]; - login_ip = host2ip(w2); - if (login_ip) { - strncpy(login_ip_str, w2, sizeof(login_ip_str)); - ShowStatus("Login server IP address : %s -> %s\n", w2, ip2str(login_ip, ip_str)); - } - } else if (strcmpi(w1, "login_port") == 0) { - login_port = atoi(w2); - } else if (strcmpi(w1, "char_ip") == 0) { - char ip_str[16]; - char_ip = host2ip(w2); - if (char_ip){ - strncpy(char_ip_str, w2, sizeof(char_ip_str)); - ShowStatus("Character server IP address : %s -> %s\n", w2, ip2str(char_ip, ip_str)); - } - } else if (strcmpi(w1, "bind_ip") == 0) { - char ip_str[16]; - bind_ip = host2ip(w2); - if (bind_ip) { - strncpy(bind_ip_str, w2, sizeof(bind_ip_str)); - ShowStatus("Character server binding IP address : %s -> %s\n", w2, ip2str(bind_ip, ip_str)); - } - } else if (strcmpi(w1, "char_port") == 0) { - char_port = atoi(w2); - } else if (strcmpi(w1, "char_maintenance") == 0) { - char_maintenance = atoi(w2); - } else if (strcmpi(w1, "char_new") == 0) { - char_new = (bool)atoi(w2); - } else if (strcmpi(w1, "char_new_display") == 0) { - char_new_display = atoi(w2); - } else if (strcmpi(w1, "email_creation") == 0) { - email_creation = config_switch(w2); - } else if (strcmpi(w1, "scdata_txt") == 0) { //By Skotlex - strcpy(scdata_txt, w2); -#endif - } else if (strcmpi(w1, "char_txt") == 0) { - strcpy(char_txt, w2); - } else if (strcmpi(w1, "friends_txt") == 0) { //By davidsiaw - strcpy(friends_txt, w2); - } else if (strcmpi(w1, "hotkeys_txt") == 0) { //By davidsiaw - strcpy(hotkeys_txt, w2); -#ifndef TXT_SQL_CONVERT - } else if (strcmpi(w1, "max_connect_user") == 0) { - max_connect_user = atoi(w2); - if (max_connect_user < 0) - max_connect_user = 0; // unlimited online players - } else if(strcmpi(w1, "gm_allow_level") == 0) { - gm_allow_level = atoi(w2); - if(gm_allow_level < 0) - gm_allow_level = 99; - } else if (strcmpi(w1, "online_check") == 0) { - online_check = config_switch(w2); - } else if (strcmpi(w1, "autosave_time") == 0) { - autosave_interval = atoi(w2)*1000; - if (autosave_interval <= 0) - autosave_interval = DEFAULT_AUTOSAVE_INTERVAL; - } else if (strcmpi(w1, "save_log") == 0) { - save_log = config_switch(w2); - } else if (strcmpi(w1, "start_point") == 0) { - char map[MAP_NAME_LENGTH_EXT]; - int x, y; - if (sscanf(w2, "%15[^,],%d,%d", map, &x, &y) < 3) - continue; - start_point.map = mapindex_name2id(map); - if (!start_point.map) { - ShowError("Specified start_point %s not found in map-index cache.\n", map); - start_point.map = 0; - } - start_point.x = x; - start_point.y = y; - } else if (strcmpi(w1, "start_zeny") == 0) { - start_zeny = atoi(w2); - if (start_zeny < 0) - start_zeny = 0; - } else if (strcmpi(w1, "start_weapon") == 0) { - start_weapon = atoi(w2); - if (start_weapon < 0) - start_weapon = 0; - } else if (strcmpi(w1, "start_armor") == 0) { - start_armor = atoi(w2); - if (start_armor < 0) - start_armor = 0; - } else if(strcmpi(w1,"log_char")==0) { //log char or not [devil] - log_char = atoi(w2); - } else if (strcmpi(w1, "unknown_char_name") == 0) { - strcpy(unknown_char_name, w2); - unknown_char_name[NAME_LENGTH-1] = '\0'; - } else if (strcmpi(w1, "char_log_filename") == 0) { - strcpy(char_log_filename, w2); - } else if (strcmpi(w1, "name_ignoring_case") == 0) { - name_ignoring_case = (bool)config_switch(w2); - } else if (strcmpi(w1, "char_name_option") == 0) { - char_name_option = atoi(w2); - } else if (strcmpi(w1, "char_name_letters") == 0) { - strcpy(char_name_letters, w2); - } else if (strcmpi(w1, "char_rename") == 0) { - char_rename = config_switch(w2); -// online files options - } else if (strcmpi(w1, "online_txt_filename") == 0) { - strcpy(online_txt_filename, w2); - } else if (strcmpi(w1, "online_html_filename") == 0) { - strcpy(online_html_filename, w2); - } else if (strcmpi(w1, "online_sorting_option") == 0) { - online_sorting_option = atoi(w2); - } else if (strcmpi(w1, "online_display_option") == 0) { - online_display_option = atoi(w2); - } else if (strcmpi(w1, "online_gm_display_min_level") == 0) { // minimum GM level to display 'GM' when we want to display it - online_gm_display_min_level = atoi(w2); - if (online_gm_display_min_level < 5) // send online file every 5 seconds to player is enough - online_gm_display_min_level = 5; - } else if (strcmpi(w1, "online_refresh_html") == 0) { - online_refresh_html = atoi(w2); - if (online_refresh_html < 1) - online_refresh_html = 1; - } else if(strcmpi(w1,"db_path")==0) { - strcpy(db_path,w2); - } else if (strcmpi(w1, "console") == 0) { - console = config_switch(w2); - } else if (strcmpi(w1, "fame_list_alchemist") == 0) { - fame_list_size_chemist = atoi(w2); - if (fame_list_size_chemist > MAX_FAME_LIST) { - ShowWarning("Max fame list size is %d (fame_list_alchemist)\n", MAX_FAME_LIST); - fame_list_size_chemist = MAX_FAME_LIST; - } - } else if (strcmpi(w1, "fame_list_blacksmith") == 0) { - fame_list_size_smith = atoi(w2); - if (fame_list_size_smith > MAX_FAME_LIST) { - ShowWarning("Max fame list size is %d (fame_list_blacksmith)\n", MAX_FAME_LIST); - fame_list_size_smith = MAX_FAME_LIST; - } - } else if (strcmpi(w1, "fame_list_taekwon") == 0) { - fame_list_size_taekwon = atoi(w2); - if (fame_list_size_taekwon > MAX_FAME_LIST) { - ShowWarning("Max fame list size is %d (fame_list_taekwon)\n", MAX_FAME_LIST); - fame_list_size_taekwon = MAX_FAME_LIST; - } - } else if (strcmpi(w1, "guild_exp_rate") == 0) { - guild_exp_rate = atoi(w2); -#endif //TXT_SQL_CONVERT - } else if (strcmpi(w1, "import") == 0) { - char_config_read(w2); - } - } - fclose(fp); - - ShowInfo("Done reading %s.\n", cfgName); - return 0; -} - -#ifndef TXT_SQL_CONVERT -int chardb_final(int key, void* data, va_list va) -{ - aFree(data); - return 0; -} -void do_final(void) -{ - ShowStatus("Terminating server.\n"); - - mmo_char_sync(); - inter_save(); - set_all_offline(-1); - flush_fifos(); - // write online players files with no player - online_char_db->clear(online_char_db, NULL); //clean the db... - create_online_files(); - online_char_db->destroy(online_char_db, NULL); //dispose the db... - auth_db->destroy(auth_db, NULL); - - if(gm_account) aFree(gm_account); - if(char_dat) aFree(char_dat); - - if (login_fd > 0) - do_close(login_fd); - if (char_fd > 0) - do_close(char_fd); - -#ifdef ENABLE_SC_SAVING - status_final(); -#endif - inter_final(); - mapindex_final(); - - char_log("----End of char-server (normal end with closing of all files).\n"); -} - -//------------------------------ -// Function called when the server -// has received a crash signal. -//------------------------------ -void do_abort(void) -{ -} - -void set_server_type(void) -{ - SERVER_TYPE = ATHENA_SERVER_CHAR; -} - -int do_init(int argc, char **argv) -{ - int i; - - for(i = 0; i < MAX_MAP_SERVERS; i++) { - memset(&server[i], 0, sizeof(struct mmo_map_server)); - server[i].fd = -1; - } - - //Read map indexes - mapindex_init(); - start_point.map = mapindex_name2id("new_zone01"); - - char_config_read((argc < 2) ? CHAR_CONF_NAME : argv[1]); - char_lan_config_read((argc > 3) ? argv[3] : LAN_CONF_NAME); - - if (strcmp(userid, "s1")==0 && strcmp(passwd, "p1")==0) { - ShowError("Using the default user/password s1/p1 is NOT RECOMMENDED.\n"); - ShowNotice("Please edit your save/account.txt file to create a proper inter-server user/password (gender 'S')\n"); - ShowNotice("And then change the user/password to use in conf/char_athena.conf (or conf/import/char_conf.txt)\n"); - } - - ShowInfo("Finished reading the char-server configuration.\n"); - - // a newline in the log... - char_log(""); - // moved behind char_config_read in case we changed the filename [celest] - char_log("The char-server starting...\n"); - - ShowInfo("Initializing char server.\n"); - auth_db = idb_alloc(DB_OPT_RELEASE_DATA); - online_char_db = idb_alloc(DB_OPT_RELEASE_DATA); - mmo_char_init(); - char_read_fame_list(); //Read fame lists. -#ifdef ENABLE_SC_SAVING - status_init(); -#endif - inter_init_txt((argc > 2) ? argv[2] : inter_cfgName); // inter server 初期化 - ShowInfo("char server initialized.\n"); - - set_defaultparse(parse_char); - - if ((naddr_ != 0) && (!login_ip || !char_ip)) - { - char ip_str[16]; - ip2str(addr_[0], ip_str); - - if (naddr_ > 1) - ShowStatus("Multiple interfaces detected.. using %s as our IP address\n", ip_str); - else - ShowStatus("Defaulting to %s as our IP address\n", ip_str); - if (!login_ip) { - strcpy(login_ip_str, ip_str); - login_ip = str2ip(login_ip_str); - } - if (!char_ip) { - strcpy(char_ip_str, ip_str); - char_ip = str2ip(char_ip_str); - } - } - - // establish char-login connection if not present - add_timer_func_list(check_connect_login_server, "check_connect_login_server"); - add_timer_interval(gettick() + 1000, check_connect_login_server, 0, 0, 10 * 1000); - - // keep the char-login connection alive - add_timer_func_list(ping_login_server, "ping_login_server"); - add_timer_interval(gettick() + 1000, ping_login_server, 0, 0, ((int)stall_time-2) * 1000); - - // periodically update the overall user count on all mapservers + login server - add_timer_func_list(broadcast_user_count, "broadcast_user_count"); - add_timer_interval(gettick() + 1000, broadcast_user_count, 0, 0, 5 * 1000); - - // send a list of all online account IDs to login server - add_timer_func_list(send_accounts_tologin, "send_accounts_tologin"); - add_timer_interval(gettick() + 1000, send_accounts_tologin, 0, 0, 3600 * 1000); //Sync online accounts every hour - - // ??? - add_timer_func_list(chardb_waiting_disconnect, "chardb_waiting_disconnect"); - - // ??? - add_timer_func_list(online_data_cleanup, "online_data_cleanup"); - add_timer_interval(gettick() + 1000, online_data_cleanup, 0, 0, 600 * 1000); - - // periodic flush of all saved data to disk - add_timer_func_list(mmo_char_sync_timer, "mmo_char_sync_timer"); - add_timer_interval(gettick() + 1000, mmo_char_sync_timer, 0, 0, autosave_interval); - - if( console ) - { - //##TODO invoke a CONSOLE_START plugin event - } - - char_fd = make_listen_bind(bind_ip, char_port); - char_log("The char-server is ready (Server is listening on the port %d).\n", char_port); - ShowStatus("The char-server is "CL_GREEN"ready"CL_RESET" (Server is listening on the port %d).\n\n", char_port); - - return 0; -} - -#endif //TXT_SQL_CONVERT diff --git a/src/char/char.h b/src/char/char.h deleted file mode 100644 index 72077ac09..000000000 --- a/src/char/char.h +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder - -#ifndef _CHAR_H_ -#define _CHAR_H_ - -#include "../common/mmo.h" - -#define START_CHAR_NUM 150000 -#define MAX_MAP_SERVERS 30 - -#define DEFAULT_AUTOSAVE_INTERVAL 300*1000 - -struct character_data { - struct mmo_charstatus status; - int global_num; - struct global_reg global[GLOBAL_REG_NUM]; -}; - -struct mmo_charstatus* search_character(int aid, int cid); -struct mmo_charstatus* search_character_byname(char* character_name); -int search_character_index(char* character_name); -char* search_character_name(int index); -int search_character_online(int aid, int cid); - -int mapif_sendall(unsigned char *buf, unsigned int len); -int mapif_sendallwos(int fd,unsigned char *buf, unsigned int len); -int mapif_send(int fd,unsigned char *buf, unsigned int len); - -int char_married(int pl1,int pl2); -int char_child(int parent_id, int child_id); -int char_family(int cid1, int cid2, int cid3); -void char_clearparty(int party_id); - -int char_log(char *fmt, ...); - -int request_accreg2(int account_id, int char_id); -int char_parse_Registry(int account_id, int char_id, unsigned char *buf, int len); -int save_accreg2(unsigned char *buf, int len); -int char_account_reg_reply(int fd,int account_id,int char_id); - -extern int char_name_option; -extern char char_name_letters[]; -extern int autosave_interval; -extern char db_path[]; -extern int guild_exp_rate; -extern int log_inter; -//Exported for use in the TXT-SQL converter. -extern char char_txt[]; -int char_config_read(const char *cfgName); -int mmo_char_fromstr(char *str, struct mmo_charstatus *p, struct global_reg *reg, int *reg_num); -int parse_friend_txt(struct mmo_charstatus *p); - -#endif /* _CHAR_H_ */ diff --git a/src/char/int_guild.c b/src/char/int_guild.c deleted file mode 100644 index e8379c130..000000000 --- a/src/char/int_guild.c +++ /dev/null @@ -1,1579 +0,0 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder - -#include "../common/cbasetypes.h" -#include "../common/mmo.h" -#include "../common/malloc.h" -#include "../common/socket.h" -#include "../common/db.h" -#include "../common/lock.h" -#include "../common/showmsg.h" -#include "../common/strlib.h" -#include "char.h" -#include "inter.h" -#include "int_storage.h" -#include "int_guild.h" - -#include -#include -#include - -char guild_txt[1024] = "save/guild.txt"; -char castle_txt[1024] = "save/castle.txt"; - -#ifndef TXT_SQL_CONVERT -static DBMap* guild_db; // int guild_id -> struct guild* -static DBMap* castle_db; // int castle_id -> struct guild_castle* - -static int guild_newid = 10000; - -static unsigned int guild_exp[100]; - -int mapif_guild_broken(int guild_id, int flag); -static bool guild_check_empty(struct guild *g); -int guild_calcinfo(struct guild *g); -int mapif_guild_basicinfochanged(int guild_id, int type, const void *data, int len); -int mapif_guild_info(int fd, struct guild *g); -int guild_break_sub(DBKey key, void *data, va_list ap); - -/// serializes the guild data structure into the provided string -int inter_guild_tostr(char* str, struct guild* g) -{ - int i, c, len; - - // save guild base info - len = sprintf(str, "%d\t%s\t%s\t%d,%d,%u,%d,%d\t%s#\t%s#\t", - g->guild_id, g->name, g->master, g->guild_lv, g->max_member, g->exp, g->skill_point, 0, g->mes1, g->mes2); - - // save guild member info - for(i = 0; i < g->max_member; i++) - { - struct guild_member *m = &g->member[i]; - len += sprintf(str + len, "%d,%d,%d,%d,%d,%d,%d,%u,%d,%d\t%s\t", - m->account_id, m->char_id, - m->hair, m->hair_color, m->gender, - m->class_, m->lv, m->exp, m->exp_payper, m->position, - ((m->account_id > 0) ? m->name : "-")); - } - - // save guild position info - for(i = 0; i < MAX_GUILDPOSITION; i++) { - struct guild_position *p = &g->position[i]; - len += sprintf(str + len, "%d,%d\t%s#\t", p->mode, p->exp_mode, p->name); - } - - // save guild emblem - len += sprintf(str + len, "%d,%d,", g->emblem_len, g->emblem_id); - for(i = 0; i < g->emblem_len; i++) { - len += sprintf(str + len, "%02x", (unsigned char)(g->emblem_data[i])); - } - len += sprintf(str + len, "$\t"); - - // save guild alliance info - c = 0; - for(i = 0; i < MAX_GUILDALLIANCE; i++) - if (g->alliance[i].guild_id > 0) - c++; - len += sprintf(str + len, "%d\t", c); - for(i = 0; i < MAX_GUILDALLIANCE; i++) { - struct guild_alliance *a = &g->alliance[i]; - if (a->guild_id > 0) - len += sprintf(str + len, "%d,%d\t%s\t", a->guild_id, a->opposition, a->name); - } - - // save guild expulsion info - c = 0; - for(i = 0; i < MAX_GUILDEXPULSION; i++) - if (g->expulsion[i].account_id > 0) - c++; - len += sprintf(str + len, "%d\t", c); - for(i = 0; i < MAX_GUILDEXPULSION; i++) { - struct guild_expulsion *e = &g->expulsion[i]; - if (e->account_id > 0) - len += sprintf(str + len, "%d,%d,%d,%d\t%s\t%s\t%s#\t", - e->account_id, 0, 0, 0, e->name, "#", e->mes ); - } - - // save guild skill info - for(i = 0; i < MAX_GUILDSKILL; i++) { - len += sprintf(str + len, "%d,%d ", g->skill[i].id, g->skill[i].lv); - } - len += sprintf(str + len, "\t"); - - return 0; -} -#endif //TXT_SQL_CONVERT - -/// parses the guild data string into a guild data structure -int inter_guild_fromstr(char* str, struct guild* g) -{ - int i, c; - char *pstr; - - memset(g, 0, sizeof(struct guild)); - - {// load guild base info - int guildid; - char name[256]; // only 24 used - char master[256]; // only 24 used - int guildlv; - int max_member; - unsigned int exp; - int skpoint; - char mes1[256]; // only 60 used - char mes2[256]; // only 120 used - int len; - - if( sscanf(str, "%d\t%[^\t]\t%[^\t]\t%d,%d,%u,%d,%*d\t%[^\t]\t%[^\t]\t%n", - &guildid, name, master, &guildlv, &max_member, &exp, &skpoint, mes1, mes2, &len) < 9 ) - return 1; - - // remove '#' - mes1[strlen(mes1)-1] = '\0'; - mes2[strlen(mes2)-1] = '\0'; - - g->guild_id = guildid; - g->guild_lv = guildlv; - g->max_member = max_member; - g->exp = exp; - g->skill_point = skpoint; - safestrncpy(g->name, name, sizeof(g->name)); - safestrncpy(g->master, master, sizeof(g->master)); - safestrncpy(g->mes1, mes1, sizeof(g->mes1)); - safestrncpy(g->mes2, mes2, sizeof(g->mes2)); - - str+= len; - } - - {// load guild member info - int accountid; - int charid; - int hair, hair_color, gender; - int class_, lv; - unsigned int exp; - int exp_payper; - int position; - char name[256]; // only 24 used - int len; - int i; - - for( i = 0; i < g->max_member; i++ ) - { - struct guild_member* m = &g->member[i]; - if (sscanf(str, "%d,%d,%d,%d,%d,%d,%d,%u,%d,%d\t%[^\t]\t%n", - &accountid, &charid, &hair, &hair_color, &gender, - &class_, &lv, &exp, &exp_payper, &position, - name, &len) < 11) - return 1; - - m->account_id = accountid; - m->char_id = charid; - m->hair = hair; - m->hair_color = hair_color; - m->gender = gender; - m->class_ = class_; - m->lv = lv; - m->exp = exp; - m->exp_payper = exp_payper; - m->position = position; - safestrncpy(m->name, name, NAME_LENGTH); - - str+= len; - } - } - - {// load guild position info - int mode, exp_mode; - char name[256]; // only 24 used - int len; - int i = 0; - int j; - - while (sscanf(str, "%d,%d%n", &mode, &exp_mode, &j) == 2 && str[j] == '\t') - { - struct guild_position *p = &g->position[i]; - if (sscanf(str, "%d,%d\t%[^\t]\t%n", &mode, &exp_mode, name, &len) < 3) - return 1; - - p->mode = mode; - p->exp_mode = exp_mode; - name[strlen(name)-1] = 0; - safestrncpy(p->name, name, NAME_LENGTH); - - i++; - str+= len; - } - } - - {// load guild emblem - int emblemlen; - int emblemid; - char emblem[4096]; - int len; - - emblemid = 0; - if( sscanf(str, "%d,%d,%[^\t]\t%n", &emblemlen, &emblemid, emblem, &len) < 3 ) - if( sscanf(str, "%d,%[^\t]\t%n", &emblemlen, emblem, &len) < 2 ) //! pre-svn format - return 1; - - g->emblem_len = emblemlen; - g->emblem_id = emblemid; - for(i = 0, pstr = emblem; i < g->emblem_len; i++, pstr += 2) { - int c1 = pstr[0], c2 = pstr[1], x1 = 0, x2 = 0; - if (c1 >= '0' && c1 <= '9') x1 = c1 - '0'; - if (c1 >= 'a' && c1 <= 'f') x1 = c1 - 'a' + 10; - if (c1 >= 'A' && c1 <= 'F') x1 = c1 - 'A' + 10; - if (c2 >= '0' && c2 <= '9') x2 = c2 - '0'; - if (c2 >= 'a' && c2 <= 'f') x2 = c2 - 'a' + 10; - if (c2 >= 'A' && c2 <= 'F') x2 = c2 - 'A' + 10; - g->emblem_data[i] = (x1<<4) | x2; - } - - str+= len; - } - - {// load guild alliance info - int guildid; - int opposition; - char name[256]; // only 24 used - int len; - - if (sscanf(str, "%d\t%n", &c, &len) < 1) - return 1; - str+= len; - - for(i = 0; i < c; i++) - { - struct guild_alliance* a = &g->alliance[i]; - if (sscanf(str, "%d,%d\t%[^\t]\t%n", &guildid, &opposition, name, &len) < 3) - return 1; - - a->guild_id = guildid; - a->opposition = opposition; - safestrncpy(a->name, name, NAME_LENGTH); - - str+= len; - } - } - - {// load guild expulsion info - int accountid; - char name[256]; // only 24 used - char message[256]; // only 40 used - int len; - int i; - - if (sscanf(str, "%d\t%n", &c, &len) < 1) - return 1; - str+= len; - - for(i = 0; i < c; i++) - { - struct guild_expulsion *e = &g->expulsion[i]; - if (sscanf(str, "%d,%*d,%*d,%*d\t%[^\t]\t%*[^\t]\t%[^\t]\t%n", &accountid, name, message, &len) < 3) - return 1; - - e->account_id = accountid; - safestrncpy(e->name, name, sizeof(e->name)); - message[strlen(message)-1] = 0; // remove '#' - safestrncpy(e->mes, message, sizeof(e->mes)); - - str+= len; - } - } - - {// load guild skill info - int skillid; - int skilllv; - int len; - int i; - - for(i = 0; i < MAX_GUILDSKILL; i++) - { - if (sscanf(str, "%d,%d %n", &skillid, &skilllv, &len) < 2) - break; - g->skill[i].id = skillid; - g->skill[i].lv = skilllv; - - str+= len; - } - str = strchr(str, '\t'); - } - - return 0; -} - -#ifndef TXT_SQL_CONVERT -// ギルド城データの文字列への変換 -int inter_guildcastle_tostr(char *str, struct guild_castle *gc) -{ - int len; - - len = sprintf(str, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d", - gc->castle_id, gc->guild_id, gc->economy, gc->defense, gc->triggerE, - gc->triggerD, gc->nextTime, gc->payTime, gc->createTime, gc->visibleC, - gc->guardian[0].visible, gc->guardian[1].visible, gc->guardian[2].visible, gc->guardian[3].visible, - gc->guardian[4].visible, gc->guardian[5].visible, gc->guardian[6].visible, gc->guardian[7].visible); - - return 0; -} -#endif ///TXT_SQL_CONVERT - -// ギルド城データの文字列からの変換 -int inter_guildcastle_fromstr(char *str, struct guild_castle *gc) -{ - int castleid, guildid, economy, defense, triggerE, triggerD, nextTime, payTime, createTime, visibleC; - int guardian[8]; - int dummy; - - memset(gc, 0, sizeof(struct guild_castle)); - // structure of guild castle with the guardian hp included - if( sscanf(str, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d", - &castleid, &guildid, &economy, &defense, &triggerE, &triggerD, &nextTime, &payTime, &createTime, &visibleC, - &guardian[0], &guardian[1], &guardian[2], &guardian[3], &guardian[4], &guardian[5], &guardian[6], &guardian[7], - &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy) != 26 ) - // structure of guild castle without the hps (current one) - if( sscanf(str, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d", - &castleid, &guildid, &economy, &defense, &triggerE, &triggerD, &nextTime, &payTime, &createTime, &visibleC, - &guardian[0], &guardian[1], &guardian[2], &guardian[3], &guardian[4], &guardian[5], &guardian[6], &guardian[7]) != 18 ) - return 1; - - gc->castle_id = castleid; - gc->guild_id = guildid; - gc->economy = economy; - gc->defense = defense; - gc->triggerE = triggerE; - gc->triggerD = triggerD; - gc->nextTime = nextTime; - gc->payTime = payTime; - gc->createTime = createTime; - gc->visibleC = visibleC; - gc->guardian[0].visible = guardian[0]; - gc->guardian[1].visible = guardian[1]; - gc->guardian[2].visible = guardian[2]; - gc->guardian[3].visible = guardian[3]; - gc->guardian[4].visible = guardian[4]; - gc->guardian[5].visible = guardian[5]; - gc->guardian[6].visible = guardian[6]; - gc->guardian[7].visible = guardian[7]; - - return 0; -} - -#ifndef TXT_SQL_CONVERT -// ギルド関連データベース読み込み -int inter_guild_readdb(void) -{ - int i; - FILE *fp; - char line[1024]; - char path[1024]; - - sprintf(path, "%s%s", db_path, "/exp_guild.txt"); - fp = fopen(path, "r"); - if (fp == NULL) { - ShowError("can't read db/exp_guild.txt\n"); - return 1; - } - i = 0; - while(fgets(line, sizeof(line), fp) && i < 100) - { - if (line[0] == '/' && line[1] == '/') - continue; - guild_exp[i] = (unsigned int)atof(line); - i++; - } - fclose(fp); - - return 0; -} - -// ギルドデータの読み込み -int inter_guild_init() -{ - char line[16384]; - struct guild *g; - struct guild_castle *gc; - FILE *fp; - int i, j, c = 0; - - inter_guild_readdb(); - - guild_db = idb_alloc(DB_OPT_RELEASE_DATA); - castle_db = idb_alloc(DB_OPT_RELEASE_DATA); - - if ((fp = fopen(guild_txt,"r")) == NULL) - return 1; - while(fgets(line, sizeof(line), fp)) - { - j = 0; - if (sscanf(line, "%d\t%%newid%%\n%n", &i, &j) == 1 && j > 0 && guild_newid <= i) { - guild_newid = i; - continue; - } - - g = (struct guild *) aCalloc(sizeof(struct guild), 1); - if(g == NULL){ - ShowFatalError("int_guild: out of memory!\n"); - exit(EXIT_FAILURE); - } -// memset(g, 0, sizeof(struct guild)); not needed... - if (inter_guild_fromstr(line, g) == 0 && g->guild_id > 0) { - if (g->guild_id >= guild_newid) - guild_newid = g->guild_id + 1; - idb_put(guild_db, g->guild_id, g); - guild_check_empty(g); - guild_calcinfo(g); - } else { - ShowError("int_guild: broken data [%s] line %d\n", guild_txt, c); - aFree(g); - } - c++; - } - fclose(fp); - - c = 0;//カウンタ初期化 - - if ((fp = fopen(castle_txt, "r")) == NULL) { - return 1; - } - - while(fgets(line, sizeof(line), fp)) - { - gc = (struct guild_castle *) aCalloc(sizeof(struct guild_castle), 1); - if(gc == NULL){ - ShowFatalError("int_guild: out of memory!\n"); - exit(EXIT_FAILURE); - } -// memset(gc, 0, sizeof(struct guild_castle)); No need... - if (inter_guildcastle_fromstr(line, gc) == 0) { - idb_put(castle_db, gc->castle_id, gc); - } else { - ShowError("int_guild: broken data [%s] line %d\n", castle_txt, c); - aFree(gc); - } - c++; - } - - fclose(fp); - - if (!c) { - ShowStatus(" %s - making Default Data...\n", castle_txt); - //デフォルトデータを作成 - for(i = 0; i < MAX_GUILDCASTLE; i++) { - gc = (struct guild_castle *) aCalloc(sizeof(struct guild_castle), 1); - if (gc == NULL) { - ShowFatalError("int_guild: out of memory!\n"); - exit(EXIT_FAILURE); - } - gc->castle_id = i; - idb_put(castle_db, gc->castle_id, gc); - } - ShowStatus(" %s - making done\n",castle_txt); - return 0; - } - - return 0; -} - -void inter_guild_final() -{ - castle_db->destroy(castle_db, NULL); - guild_db->destroy(guild_db, NULL); - return; -} - -struct guild *inter_guild_search(int guild_id) -{ - return (struct guild*)idb_get(guild_db, guild_id); -} - -// ギルドデータのセーブ -int inter_guild_save() -{ - FILE *fp; - int lock; - DBIterator* iter; - struct guild* g; - struct guild_castle* gc; - - // save guild data - if ((fp = lock_fopen(guild_txt, &lock)) == NULL) { - ShowError("int_guild: can't write [%s] !!! data is lost !!!\n", guild_txt); - return 1; - } - - iter = guild_db->iterator(guild_db); - for( g = (struct guild*)iter->first(iter,NULL); iter->exists(iter); g = (struct guild*)iter->next(iter,NULL) ) - { - char line[16384]; - inter_guild_tostr(line, g); - fprintf(fp, "%s\n", line); - } - iter->destroy(iter); - -// fprintf(fp, "%d\t%%newid%%\n", guild_newid); - lock_fclose(fp, guild_txt, &lock); - - // save castle data - if ((fp = lock_fopen(castle_txt,&lock)) == NULL) { - ShowError("int_guild: can't write [%s] !!! data is lost !!!\n", castle_txt); - return 1; - } - - iter = castle_db->iterator(castle_db); - for( gc = (struct guild_castle*)iter->first(iter,NULL); iter->exists(iter); gc = (struct guild_castle*)iter->next(iter,NULL) ) - { - char line[16384]; - inter_guildcastle_tostr(line, gc); - fprintf(fp, "%s\n", line); - } - iter->destroy(iter); - - lock_fclose(fp, castle_txt, &lock); - - return 0; -} - -// ギルド名検索 -struct guild* search_guildname(char *str) -{ - DBIterator* iter; - struct guild* g; - - iter = guild_db->iterator(guild_db); - for( g = (struct guild*)iter->first(iter,NULL); iter->exists(iter); g = (struct guild*)iter->next(iter,NULL) ) - { - if (strcmpi(g->name, str) == 0) - break; - } - iter->destroy(iter); - - return g; -} - -// ギルドが空かどうかチェック -static bool guild_check_empty(struct guild *g) -{ - int i; - ARR_FIND( 0, g->max_member, i, g->member[i].account_id > 0 ); - if( i < g->max_member) - return false; // not empty - - // 誰もいないので解散 - guild_db->foreach(guild_db, guild_break_sub, g->guild_id); - inter_guild_storage_delete(g->guild_id); - mapif_guild_broken(g->guild_id, 0); - idb_remove(guild_db, g->guild_id); - return true; -} - -unsigned int guild_nextexp(int level) -{ - if (level == 0) - return 1; - if (level > 0 && level < 100) - return guild_exp[level-1]; - - return 0; -} - -// ギルドスキルがあるか確認 -int guild_checkskill(struct guild *g, int id) -{ - int idx = id - GD_SKILLBASE; - - - if(idx < 0 || idx >= MAX_GUILDSKILL) - - return 0; - - return g->skill[idx].lv; -} - -// ギルドの情報の再計算 -int guild_calcinfo(struct guild *g) -{ - int i, c; - unsigned int nextexp; - struct guild before = *g; - - // スキルIDの設定 - for(i = 0; i < MAX_GUILDSKILL; i++) - g->skill[i].id=i+GD_SKILLBASE; - - // ギルドレベル - if (g->guild_lv <= 0) - g->guild_lv = 1; - nextexp = guild_nextexp(g->guild_lv); - if (nextexp > 0) { - while(g->exp >= nextexp && nextexp > 0) { //fixed guild exp overflow [Kevin] - g->exp -= nextexp; - g->guild_lv++; - g->skill_point++; - nextexp = guild_nextexp(g->guild_lv); - } - } - - // ギルドの次の経験値 - g->next_exp = guild_nextexp(g->guild_lv); - - // メンバ上限(ギルド拡張適用) - g->max_member = 16 + guild_checkskill(g, GD_EXTENSION) * 6; //Guild Extention skill - currently adds 6 to max per skill lv. - if(g->max_member > MAX_GUILD) - { - ShowError("Guild %d:%s has capacity for too many guild members (%d), max supported is %d\n", g->guild_id, g->name, g->max_member, MAX_GUILD); - g->max_member = MAX_GUILD; - } - - // 平均レベルとオンライン人数 - g->average_lv = 0; - g->connect_member = 0; - c = 0; - for(i = 0; i < g->max_member; i++) { - if (g->member[i].account_id > 0) { - g->average_lv += g->member[i].lv; - c++; - if (g->member[i].online > 0) - g->connect_member++; - } - } - if(c) g->average_lv /= c; - - // 全データを送る必要がありそう - if (g->max_member != before.max_member || - g->guild_lv != before.guild_lv || - g->skill_point != before.skill_point) { - mapif_guild_info(-1, g); - return 1; - } - - return 0; -} - -//------------------------------------------------------------------- -// map serverへの通信 - -// ギルド作成可否 -int mapif_guild_created(int fd, int account_id, struct guild *g) -{ - WFIFOHEAD(fd, 10); - WFIFOW(fd,0) = 0x3830; - WFIFOL(fd,2) = account_id; - if (g != NULL) { - WFIFOL(fd,6) = g->guild_id; - ShowInfo("Created Guild (%d %s)\n", g->guild_id, g->name); - }else{ - WFIFOL(fd,6) = 0; - } - WFIFOSET(fd,10); - return 0; -} - -// ギルド情報見つからず -int mapif_guild_noinfo(int fd, int guild_id) -{ - WFIFOHEAD(fd, 8); - WFIFOW(fd,0) = 0x3831; - WFIFOW(fd,2) = 8; - WFIFOL(fd,4) = guild_id; - WFIFOSET(fd,8); - ShowNotice("int_guild: info not found %d\n", guild_id); - - return 0; -} - -// ギルド情報まとめ送り -int mapif_guild_info(int fd, struct guild *g) -{ - unsigned char buf[8+sizeof(struct guild)]; - - WBUFW(buf,0) = 0x3831; - memcpy(buf + 4, g, sizeof(struct guild)); - WBUFW(buf,2) = 4 + sizeof(struct guild); - if (fd < 0) - mapif_sendall(buf, WBUFW(buf,2)); - else - mapif_send(fd, buf, WBUFW(buf,2)); - - return 0; -} - -// メンバ追加可否 -int mapif_guild_memberadded(int fd, int guild_id, int account_id, int char_id, int flag) -{ - WFIFOHEAD(fd, 15); - WFIFOW(fd,0) = 0x3832; - WFIFOL(fd,2) = guild_id; - WFIFOL(fd,6) = account_id; - WFIFOL(fd,10) = char_id; - WFIFOB(fd,14) = flag; - WFIFOSET(fd, 15); - - return 0; -} - -// 脱退/追放通知 -int mapif_guild_leaved(int guild_id, int account_id, int char_id, int flag, const char *name, const char *mes) -{ - unsigned char buf[79]; - - WBUFW(buf, 0) = 0x3834; - WBUFL(buf, 2) = guild_id; - WBUFL(buf, 6) = account_id; - WBUFL(buf,10) = char_id; - WBUFB(buf,14) = flag; - memcpy(WBUFP(buf,15), mes, 40); - memcpy(WBUFP(buf,55), name, NAME_LENGTH); - mapif_sendall(buf, 55+NAME_LENGTH); -// mapif_sendall(buf, 79); - ShowInfo("Character left guild (Guild %d, %d - %s: %s)\n", guild_id, account_id, name, mes); - - return 0; -} - -// オンライン状態とLv更新通知 -int mapif_guild_memberinfoshort(struct guild *g, int idx) -{ - unsigned char buf[19]; - - WBUFW(buf, 0) = 0x3835; - WBUFL(buf, 2) = g->guild_id; - WBUFL(buf, 6) = g->member[idx].account_id; - WBUFL(buf,10) = g->member[idx].char_id; - WBUFB(buf,14) = (unsigned char)g->member[idx].online; - WBUFW(buf,15) = g->member[idx].lv; - WBUFW(buf,17) = g->member[idx].class_; - mapif_sendall(buf, 19); - return 0; -} - -// 解散通知 -int mapif_guild_broken(int guild_id, int flag) -{ - unsigned char buf[7]; - - WBUFW(buf,0) = 0x3836; - WBUFL(buf,2) = guild_id; - WBUFB(buf,6) = flag; - mapif_sendall(buf, 7); - ShowInfo("Guild Break (%d)\n", guild_id); - - return 0; -} - -// ギルド内発言 -int mapif_guild_message(int guild_id, int account_id, char *mes, int len, int sfd) -{ - unsigned char buf[2048]; - - WBUFW(buf,0) = 0x3837; - WBUFW(buf,2) = len + 12; - WBUFL(buf,4) = guild_id; - WBUFL(buf,8) = account_id; - memcpy(WBUFP(buf,12), mes, len); - mapif_sendallwos(sfd, buf, len + 12); - - return 0; -} - -// ギルド基本情報変更通知 -int mapif_guild_basicinfochanged(int guild_id, int type, const void *data, int len) -{ - unsigned char buf[2048]; - - WBUFW(buf,0) = 0x3839; - WBUFW(buf,2) = len+10; - WBUFL(buf,4) = guild_id; - WBUFW(buf,8) = type; - memcpy(WBUFP(buf,10),data,len); - mapif_sendall(buf,len+10); - return 0; -} - -// ギルドメンバ情報変更通知 -int mapif_guild_memberinfochanged(int guild_id, int account_id, int char_id, int type, const void *data, int len) -{ - unsigned char buf[4096]; - - WBUFW(buf, 0) = 0x383a; - WBUFW(buf, 2) = len + 18; - WBUFL(buf, 4) = guild_id; - WBUFL(buf, 8) = account_id; - WBUFL(buf,12) = char_id; - WBUFW(buf,16) = type; - memcpy(WBUFP(buf,18), data, len); - mapif_sendall(buf,len+18); - - return 0; -} - -// ギルドスキルアップ通知 -int mapif_guild_skillupack(int guild_id, int skill_num, int account_id) -{ - unsigned char buf[14]; - - WBUFW(buf, 0) = 0x383c; - WBUFL(buf, 2) = guild_id; - WBUFL(buf, 6) = skill_num; - WBUFL(buf,10) = account_id; - mapif_sendall(buf, 14); - - return 0; -} - -// ギルド同盟/敵対通知 -int mapif_guild_alliance(int guild_id1, int guild_id2, int account_id1, int account_id2, int flag, const char *name1, const char *name2) -{ - unsigned char buf[67]; - - WBUFW(buf, 0) = 0x383d; - WBUFL(buf, 2) = guild_id1; - WBUFL(buf, 6) = guild_id2; - WBUFL(buf,10) = account_id1; - WBUFL(buf,14) = account_id2; - WBUFB(buf,18) = flag; - memcpy(WBUFP(buf,19), name1, NAME_LENGTH); - memcpy(WBUFP(buf,19+NAME_LENGTH), name2, NAME_LENGTH); - mapif_sendall(buf,19+2*NAME_LENGTH); -/* - memcpy(WBUFP(buf,43), name2, NAME_LENGTH); - mapif_sendall(buf, 67); -*/ - return 0; -} - -// ギルド役職変更通知 -int mapif_guild_position(struct guild *g, int idx) -{ - unsigned char buf[2048]; - - WBUFW(buf,0) = 0x383b; - WBUFW(buf,2) = sizeof(struct guild_position) + 12; - WBUFL(buf,4) = g->guild_id; - WBUFL(buf,8) = idx; - memcpy(WBUFP(buf,12), &g->position[idx], sizeof(struct guild_position)); - mapif_sendall(buf, WBUFW(buf,2)); - - return 0; -} - -// ギルド告知変更通知 -int mapif_guild_notice(struct guild *g) -{ - unsigned char buf[186]; - - WBUFW(buf,0) = 0x383e; - WBUFL(buf,2) = g->guild_id; - memcpy(WBUFP(buf,6), g->mes1, 60); - memcpy(WBUFP(buf,66), g->mes2, 120); - mapif_sendall(buf, 186); - - return 0; -} - -// ギルドエンブレム変更通知 -int mapif_guild_emblem(struct guild *g) -{ - unsigned char buf[2048]; - - WBUFW(buf,0) = 0x383f; - WBUFW(buf,2) = g->emblem_len + 12; - WBUFL(buf,4) = g->guild_id; - WBUFL(buf,8) = g->emblem_id; - memcpy(WBUFP(buf,12), g->emblem_data, g->emblem_len); - mapif_sendall(buf, WBUFW(buf,2)); - - return 0; -} - -int mapif_guild_master_changed(struct guild *g, int aid, int cid) -{ - unsigned char buf[14]; - WBUFW(buf,0)=0x3843; - WBUFL(buf,2)=g->guild_id; - WBUFL(buf,6)=aid; - WBUFL(buf,10)=cid; - mapif_sendall(buf,14); - return 0; -} - -int mapif_guild_castle_dataload(int castle_id, int index, int value) -{ - unsigned char buf[9]; - - WBUFW(buf,0) = 0x3840; - WBUFW(buf,2) = castle_id; - WBUFB(buf,4) = index; - WBUFL(buf,5) = value; - mapif_sendall(buf,9); - - return 0; -} - -int mapif_guild_castle_datasave(int castle_id, int index, int value) -{ - unsigned char buf[9]; - - WBUFW(buf,0) = 0x3841; - WBUFW(buf,2) = castle_id; - WBUFB(buf,4) = index; - WBUFL(buf,5) = value; - mapif_sendall(buf,9); - - return 0; -} - -int mapif_guild_castle_alldataload(int fd) -{ - DBIterator* iter; - struct guild_castle* gc; - int len = 4; - - WFIFOHEAD(fd, 4 + MAX_GUILDCASTLE*sizeof(struct guild_castle)); - WFIFOW(fd,0) = 0x3842; - iter = castle_db->iterator(castle_db); - for( gc = (struct guild_castle*)iter->first(iter,NULL); iter->exists(iter); gc = (struct guild_castle*)iter->next(iter,NULL) ) - { - memcpy(WFIFOP(fd,len), gc, sizeof(struct guild_castle)); - len += sizeof(struct guild_castle); - } - iter->destroy(iter); - WFIFOW(fd,2) = len; - WFIFOSET(fd, len); - - return 0; -} - -//------------------------------------------------------------------- -// map serverからの通信 - -// ギルド作成要求 -int mapif_parse_CreateGuild(int fd, int account_id, char *name, struct guild_member *master) -{ - struct guild *g; - int i; - - for(i = 0; i < NAME_LENGTH && name[i]; i++) { - if (!(name[i] & 0xe0) || name[i] == 0x7f) { - ShowInfo("Create Guild: illegal guild name [%s]\n", name); - mapif_guild_created(fd, account_id, NULL); - return 0; - } - } - - if ((g = search_guildname(name)) != NULL) { - ShowInfo("Create Guild: same name guild exists [%s]\n", name); - mapif_guild_created(fd, account_id, NULL); - return 0; - } - - // Check Authorised letters/symbols in the name of the character - if (char_name_option == 1) { // only letters/symbols in char_name_letters are authorised - for (i = 0; i < NAME_LENGTH && name[i]; i++) - if (strchr(char_name_letters, name[i]) == NULL) { - mapif_guild_created(fd,account_id,NULL); - return 0; - } - } else if (char_name_option == 2) { // letters/symbols in char_name_letters are forbidden - for (i = 0; i < NAME_LENGTH && name[i]; i++) - if (strchr(char_name_letters, name[i]) != NULL) { - mapif_guild_created(fd,account_id,NULL); - return 0; - } - } - - g = (struct guild *) aCalloc(sizeof(struct guild), 1); - if (g == NULL) { - ShowFatalError("int_guild: CreateGuild: out of memory !\n"); - mapif_guild_created(fd, account_id, NULL); - exit(EXIT_FAILURE); - } -// memset(g, 0, sizeof(struct guild)); Meh... - g->guild_id = guild_newid++; - memcpy(g->name, name, NAME_LENGTH); - memcpy(g->master, master->name, NAME_LENGTH); - memcpy(&g->member[0], master, sizeof(struct guild_member)); - - g->position[0].mode = 0x11; - strcpy(g->position[ 0].name, "GuildMaster"); - strcpy(g->position[MAX_GUILDPOSITION-1].name, "Newbie"); - for(i = 1; i < MAX_GUILDPOSITION-1; i++) - sprintf(g->position[i].name, "Position %d", i + 1); - - // ここでギルド情報計算が必要と思われる - g->max_member = 16; - g->average_lv = master->lv; - g->connect_member = 1; - for(i = 0; i < MAX_GUILDSKILL; i++) - g->skill[i].id=i + GD_SKILLBASE; - - idb_put(guild_db, g->guild_id, g); - - mapif_guild_created(fd, account_id, g); - mapif_guild_info(fd, g); - - if(log_inter) - inter_log("guild %s (id=%d) created by master %s (id=%d)\n", - name, g->guild_id, master->name, master->account_id); - - return 0; -} - -// ギルド情報要求 -int mapif_parse_GuildInfo(int fd, int guild_id) -{ - struct guild *g; - - g = (struct guild*)idb_get(guild_db, guild_id); - if (g != NULL){ - guild_calcinfo(g); - mapif_guild_info(fd, g); - } else - mapif_guild_noinfo(fd, guild_id); - - return 0; -} - -// ギルドメンバ追加要求 -int mapif_parse_GuildAddMember(int fd, int guild_id, struct guild_member *m) -{ - struct guild *g; - int i; - - g = (struct guild*)idb_get(guild_db, guild_id); - if (g == NULL) { - mapif_guild_memberadded(fd, guild_id, m->account_id, m->char_id, 1); - return 0; - } - - ARR_FIND( 0, g->max_member, i, g->member[i].account_id == 0 ); - if( i < g->max_member ) - { - memcpy(&g->member[i], m, sizeof(struct guild_member)); - mapif_guild_memberadded(fd, guild_id, m->account_id, m->char_id, 0); - guild_calcinfo(g); - mapif_guild_info(-1, g); - } - else - mapif_guild_memberadded(fd, guild_id, m->account_id, m->char_id, 1); - - return 0; -} - -// Delete member from guild -int mapif_parse_GuildLeave(int fd, int guild_id, int account_id, int char_id, int flag, const char *mes) -{ - int i, j; - - struct guild* g = (struct guild*)idb_get(guild_db, guild_id); - if( g == NULL ) - { - //TODO - return 0; - } - - // Find the member - ARR_FIND( 0, g->max_member, i, g->member[i].account_id == account_id && g->member[i].char_id == char_id ); - if( i == g->max_member ) - { - //TODO - return 0; - } - - if( flag ) - { // 追放の場合追放リストに入れる - ARR_FIND( 0, MAX_GUILDEXPULSION, j, g->expulsion[j].account_id == 0 ); - if (j == MAX_GUILDEXPULSION) - { // 一杯なので古いのを消す - for(j = 0; j < MAX_GUILDEXPULSION - 1; j++) - g->expulsion[j] = g->expulsion[j+1]; - j = MAX_GUILDEXPULSION - 1; - } - // Save the expulsion entry - g->expulsion[j].account_id = account_id; - safestrncpy(g->expulsion[j].name, g->member[i].name, NAME_LENGTH); - safestrncpy(g->expulsion[j].mes, mes, 40); - } - - mapif_guild_leaved(guild_id, account_id, char_id, flag, g->member[i].name, mes); - - memset(&g->member[i], 0, sizeof(struct guild_member)); - - if (guild_check_empty(g) == 0) - mapif_guild_info(-1,g);// まだ人がいるのでデータ送信 - - return 0; -} - -// オンライン/Lv更新 -int mapif_parse_GuildChangeMemberInfoShort(int fd, int guild_id, int account_id, int char_id, int online, int lv, int class_) -{ - struct guild *g; - int i, sum, c; - - g = (struct guild*)idb_get(guild_db, guild_id); - if (g == NULL) - return 0; - - ARR_FIND( 0, g->max_member, i, g->member[i].account_id == account_id && g->member[i].char_id == char_id ); - if( i < g->max_member ) - { - g->member[i].online = online; - g->member[i].lv = lv; - g->member[i].class_ = class_; - mapif_guild_memberinfoshort(g, i); - } - - g->average_lv = 0; - g->connect_member = 0; - c = 0; // member count - sum = 0; // total sum of base levels - - for(i = 0; i < g->max_member; i++) - { - if( g->member[i].account_id > 0 ) - { - sum += g->member[i].lv; - c++; - } - if( g->member[i].online ) - g->connect_member++; - } - - if( c ) // this check should always succeed... - g->average_lv = sum / c; - - //FIXME: how about sending a mapif_guild_info() update to the mapserver? [ultramage] - - return 0; -} - -// ギルド解散処理用(同盟/敵対を解除) -int guild_break_sub(DBKey key, void *data, va_list ap) -{ - struct guild *g = (struct guild *)data; - int guild_id = va_arg(ap, int); - int i; - - for(i = 0; i < MAX_GUILDALLIANCE; i++) { - if (g->alliance[i].guild_id == guild_id) - g->alliance[i].guild_id = 0; - } - return 0; -} - -// ギルド解散要求 -int mapif_parse_BreakGuild(int fd, int guild_id) -{ - struct guild *g; - - g = (struct guild*)idb_get(guild_db, guild_id); - if(g == NULL) - return 0; - - guild_db->foreach(guild_db, guild_break_sub, guild_id); - inter_guild_storage_delete(guild_id); - mapif_guild_broken(guild_id, 0); - - if(log_inter) - inter_log("guild %s (id=%d) broken\n", g->name, guild_id); - - idb_remove(guild_db, guild_id); - return 0; -} - -// ギルドメッセージ送信 -int mapif_parse_GuildMessage(int fd, int guild_id, int account_id, char *mes, int len) -{ - return mapif_guild_message(guild_id, account_id, mes, len, fd); -} - -// ギルド基本データ変更要求 -int mapif_parse_GuildBasicInfoChange(int fd, int guild_id, int type, const char *data, int len) -{ - struct guild *g; - short dw = *((short *)data); - - g = (struct guild*)idb_get(guild_db, guild_id); - if (g == NULL) - return 0; - - switch(type) { - case GBI_GUILDLV: - if (dw > 0 && g->guild_lv + dw <= 50) { - g->guild_lv+=dw; - g->skill_point+=dw; - } else if (dw < 0 && g->guild_lv + dw >= 1) - g->guild_lv += dw; - mapif_guild_info(-1, g); - return 0; - default: - ShowError("int_guild: GuildBasicInfoChange: Unknown type %d\n", type); - break; - } - mapif_guild_basicinfochanged(guild_id, type, data, len); - - return 0; -} - -// ギルドメンバデータ変更要求 -int mapif_parse_GuildMemberInfoChange(int fd, int guild_id, int account_id, int char_id, int type, const char *data, int len) -{ - int i; - struct guild *g; - - g = (struct guild*)idb_get(guild_db, guild_id); - if(g == NULL) - return 0; - - for(i = 0; i < g->max_member; i++) - if (g->member[i].account_id == account_id && g->member[i].char_id == char_id) - break; - if (i == g->max_member) { - ShowWarning("int_guild: GuildMemberChange: Not found %d,%d in %d[%s]\n", account_id, char_id, guild_id, g->name); - return 0; - } - switch(type) { - case GMI_POSITION: // 役職 - g->member[i].position = *((int *)data); - break; - case GMI_EXP: // EXP - { - unsigned int exp, old_exp=g->member[i].exp; - g->member[i].exp=*((unsigned int *)data); - if (g->member[i].exp > old_exp) - { - exp = g->member[i].exp - old_exp; - if (guild_exp_rate != 100) - exp = exp*guild_exp_rate/100; - if (exp > UINT_MAX - g->exp) - g->exp = UINT_MAX; - else - g->exp+=exp; - guild_calcinfo(g); - mapif_guild_basicinfochanged(guild_id,GBI_EXP,&g->exp,4); - } - break; - } - case GMI_HAIR: - { - g->member[i].hair=*((int *)data); - mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len); - break; - } - case GMI_HAIR_COLOR: - { - g->member[i].hair_color=*((int *)data); - mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len); - break; - } - case GMI_GENDER: - { - g->member[i].gender=*((int *)data); - mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len); - break; - } - case GMI_CLASS: - { - g->member[i].class_=*((int *)data); - mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len); - break; - } - case GMI_LEVEL: - { - g->member[i].lv=*((int *)data); - mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len); - break; - } - - default: - ShowError("int_guild: GuildMemberInfoChange: Unknown type %d\n", type); - break; - } - mapif_guild_memberinfochanged(guild_id, account_id, char_id, type, data, len); - - return 0; -} - -int inter_guild_sex_changed(int guild_id,int account_id,int char_id, int gender) -{ - return mapif_parse_GuildMemberInfoChange(0, guild_id, account_id, char_id, GMI_GENDER, (const char*)&gender, sizeof(gender)); -} - -// ギルド役職名変更要求 -int mapif_parse_GuildPosition(int fd, int guild_id, int idx, struct guild_position *p) -{ - struct guild *g = (struct guild*)idb_get(guild_db, guild_id); - - if (g == NULL || idx < 0 || idx >= MAX_GUILDPOSITION) { - return 0; - } - memcpy(&g->position[idx], p, sizeof(struct guild_position)); - mapif_guild_position(g, idx); - ShowInfo("int_guild: position [%d] changed\n", idx); - - return 0; -} - -// ギルドスキルアップ要求 -int mapif_parse_GuildSkillUp(int fd, int guild_id, int skill_num, int account_id) -{ - struct guild *g = (struct guild*)idb_get(guild_db, guild_id); - int idx = skill_num - GD_SKILLBASE; - - if (g == NULL || idx < 0 || idx >= MAX_GUILDSKILL) - return 0; - - if (g->skill_point > 0 && g->skill[idx].id > 0 && g->skill[idx].lv < 10) { - g->skill[idx].lv++; - g->skill_point--; - if (guild_calcinfo(g) == 0) - mapif_guild_info(-1, g); - mapif_guild_skillupack(guild_id, skill_num, account_id); - } - - return 0; -} - -//Manual deletion of an alliance when partnering guild does not exists. [Skotlex] -static int mapif_parse_GuildDeleteAlliance(struct guild *g, int guild_id, int account_id1, int account_id2, int flag) -{ - int i; - char name[NAME_LENGTH]; - for(i=0;ialliance[i].guild_id == guild_id) - { - strcpy(name, g->alliance[i].name); - g->alliance[i].guild_id=0; - break; - } - if (i == MAX_GUILDALLIANCE) - return -1; - - mapif_guild_alliance(g->guild_id,guild_id,account_id1,account_id2,flag,g->name,name); - return 0; -} - -// ギルド同盟要求 -int mapif_parse_GuildAlliance(int fd, int guild_id1, int guild_id2, int account_id1, int account_id2, int flag) -{ - struct guild *g[2]; - int j, i; - - g[0] = (struct guild*)idb_get(guild_db, guild_id1); - g[1] = (struct guild*)idb_get(guild_db, guild_id2); - - if(g[0] && g[1]==NULL && (flag&0x8)) //Requested to remove an alliance with a not found guild. - return mapif_parse_GuildDeleteAlliance(g[0], guild_id2, - account_id1, account_id2, flag); //Try to do a manual removal of said guild. - - if (g[0] == NULL || g[1] == NULL) - return 0; - - if (!(flag & 0x8)) { - for(i = 0; i < 2 - (flag & 1); i++) { - for(j = 0; j < MAX_GUILDALLIANCE; j++) - if (g[i]->alliance[j].guild_id == 0) { - g[i]->alliance[j].guild_id = g[1-i]->guild_id; - memcpy(g[i]->alliance[j].name, g[1-i]->name, NAME_LENGTH); - g[i]->alliance[j].opposition = flag & 1; - break; - } - } - } else { // 関係解消 - for(i = 0; i < 2 - (flag & 1); i++) { - for(j = 0; j < MAX_GUILDALLIANCE; j++) - if (g[i]->alliance[j].guild_id == g[1-i]->guild_id && g[i]->alliance[j].opposition == (flag & 1)) { - g[i]->alliance[j].guild_id = 0; - break; - } - } - } - mapif_guild_alliance(guild_id1, guild_id2, account_id1, account_id2, flag, g[0]->name, g[1]->name); - - return 0; -} - -// ギルド告知変更要求 -int mapif_parse_GuildNotice(int fd, int guild_id, const char *mes1, const char *mes2) -{ - struct guild *g; - - g = (struct guild*)idb_get(guild_db, guild_id); - if (g == NULL) - return 0; - memcpy(g->mes1, mes1, 60); - memcpy(g->mes2, mes2, 120); - - return mapif_guild_notice(g); -} - -// ギルドエンブレム変更要求 -int mapif_parse_GuildEmblem(int fd, int len, int guild_id, int dummy, const char *data) -{ - struct guild *g; - - g = (struct guild*)idb_get(guild_db, guild_id); - if (g == NULL) - return 0; - memcpy(g->emblem_data, data, len); - g->emblem_len = len; - g->emblem_id++; - - return mapif_guild_emblem(g); -} - -int mapif_parse_GuildCastleDataLoad(int fd, int castle_id, int index) -{ - struct guild_castle *gc = (struct guild_castle*)idb_get(castle_db, castle_id); - - if (gc == NULL) { - return mapif_guild_castle_dataload(castle_id, 0, 0); - } - switch(index) { - case 1: return mapif_guild_castle_dataload(gc->castle_id, index, gc->guild_id); - case 2: return mapif_guild_castle_dataload(gc->castle_id, index, gc->economy); - case 3: return mapif_guild_castle_dataload(gc->castle_id, index, gc->defense); - case 4: return mapif_guild_castle_dataload(gc->castle_id, index, gc->triggerE); - case 5: return mapif_guild_castle_dataload(gc->castle_id, index, gc->triggerD); - case 6: return mapif_guild_castle_dataload(gc->castle_id, index, gc->nextTime); - case 7: return mapif_guild_castle_dataload(gc->castle_id, index, gc->payTime); - case 8: return mapif_guild_castle_dataload(gc->castle_id, index, gc->createTime); - case 9: return mapif_guild_castle_dataload(gc->castle_id, index, gc->visibleC); - case 10: - case 11: - case 12: - case 13: - case 14: - case 15: - case 16: - case 17: - return mapif_guild_castle_dataload(gc->castle_id, index, gc->guardian[index-10].visible); - default: - ShowError("mapif_parse_GuildCastleDataLoad ERROR!! (Not found index=%d)\n", index); - return 0; - } - - return 0; -} - -int mapif_parse_GuildCastleDataSave(int fd, int castle_id, int index, int value) -{ - struct guild_castle *gc = (struct guild_castle*)idb_get(castle_db, castle_id); - - if (gc == NULL) - return mapif_guild_castle_datasave(castle_id, index, value); - - switch(index) { - case 1: - if (gc->guild_id != value) { - int gid = (value) ? value : gc->guild_id; - struct guild *g = (struct guild*)idb_get(guild_db, gid); - if(log_inter) - inter_log("guild %s (id=%d) %s castle id=%d\n", - (g) ? g->name : "??", gid, (value) ? "occupy" : "abandon", castle_id); - } - gc->guild_id = value; - if(gc->guild_id == 0) { - //Delete guardians. - memset(&gc->guardian, 0, sizeof(gc->guardian)); - } - break; - case 2: gc->economy = value; break; - case 3: gc->defense = value; break; - case 4: gc->triggerE = value; break; - case 5: gc->triggerD = value; break; - case 6: gc->nextTime = value; break; - case 7: gc->payTime = value; break; - case 8: gc->createTime = value; break; - case 9: gc->visibleC = value; break; - case 10: - case 11: - case 12: - case 13: - case 14: - case 15: - case 16: - case 17: - gc->guardian[index-10].visible = value; break; - default: - ShowError("mapif_parse_GuildCastleDataSave ERROR!! (Not found index=%d)\n", index); - return 0; - } - - return mapif_guild_castle_datasave(gc->castle_id, index, value); -} - -int mapif_parse_GuildMasterChange(int fd, int guild_id, const char* name, int len) -{ - struct guild *g = (struct guild*)idb_get(guild_db, guild_id); - struct guild_member gm; - int pos; - - if(g==NULL || g->guild_id<=0 || len > NAME_LENGTH) - return 0; - - for (pos = 0; pos < g->max_member && strncmp(g->member[pos].name, name, len); pos++); - - if (pos == g->max_member) - return 0; //Character not found?? - - memcpy(&gm, &g->member[pos], sizeof (struct guild_member)); - memcpy(&g->member[pos], &g->member[0], sizeof(struct guild_member)); - memcpy(&g->member[0], &gm, sizeof(struct guild_member)); - - g->member[pos].position = g->member[0].position; - g->member[0].position = 0; //Position 0: guild Master. - safestrncpy(g->master, name, NAME_LENGTH); - - ShowInfo("int_guild: Guildmaster Changed to %s (Guild %d - %s)\n",name, guild_id, g->name); - return mapif_guild_master_changed(g, g->member[0].account_id, g->member[0].char_id); -} - -// map server からの通信 -// ・1パケットのみ解析すること -// ・パケット長データはinter.cにセットしておくこと -// ・パケット長チェックや、RFIFOSKIPは呼び出し元で行われるので行ってはならない -// ・エラーなら0(false)、そうでないなら1(true)をかえさなければならない -int inter_guild_parse_frommap(int fd) -{ - RFIFOHEAD(fd); - switch(RFIFOW(fd,0)) { - case 0x3030: mapif_parse_CreateGuild(fd, RFIFOL(fd,4), (char*)RFIFOP(fd,8), (struct guild_member *)RFIFOP(fd,32)); break; - case 0x3031: mapif_parse_GuildInfo(fd, RFIFOL(fd,2)); break; - case 0x3032: mapif_parse_GuildAddMember(fd, RFIFOL(fd,4), (struct guild_member *)RFIFOP(fd,8)); break; - case 0x3033: mapif_parse_GuildMasterChange(fd,RFIFOL(fd,4),(const char*)RFIFOP(fd,8),RFIFOW(fd,2)-8); break; - case 0x3034: mapif_parse_GuildLeave(fd, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10), RFIFOB(fd,14), (const char*)RFIFOP(fd,15)); break; - case 0x3035: mapif_parse_GuildChangeMemberInfoShort(fd, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10), RFIFOB(fd,14), RFIFOW(fd,15), RFIFOW(fd,17)); break; - case 0x3036: mapif_parse_BreakGuild(fd, RFIFOL(fd,2)); break; - case 0x3037: mapif_parse_GuildMessage(fd, RFIFOL(fd,4), RFIFOL(fd,8), (char*)RFIFOP(fd,12), RFIFOW(fd,2)-12); break; - case 0x3039: mapif_parse_GuildBasicInfoChange(fd, RFIFOL(fd,4), RFIFOW(fd,8), (const char*)RFIFOP(fd,10), RFIFOW(fd,2)-10); break; - case 0x303A: mapif_parse_GuildMemberInfoChange(fd, RFIFOL(fd,4), RFIFOL(fd,8), RFIFOL(fd,12), RFIFOW(fd,16), (const char*)RFIFOP(fd,18), RFIFOW(fd,2)-18); break; - case 0x303B: mapif_parse_GuildPosition(fd, RFIFOL(fd,4), RFIFOL(fd,8), (struct guild_position *)RFIFOP(fd,12)); break; - case 0x303C: mapif_parse_GuildSkillUp(fd, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10)); break; - case 0x303D: mapif_parse_GuildAlliance(fd, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10), RFIFOL(fd,14), RFIFOB(fd,18)); break; - case 0x303E: mapif_parse_GuildNotice(fd, RFIFOL(fd,2), (const char*)RFIFOP(fd,6), (const char*)RFIFOP(fd,66)); break; - case 0x303F: mapif_parse_GuildEmblem(fd, RFIFOW(fd,2)-12, RFIFOL(fd,4), RFIFOL(fd,8), (const char*)RFIFOP(fd,12)); break; - case 0x3040: mapif_parse_GuildCastleDataLoad(fd, RFIFOW(fd,2), RFIFOB(fd,4)); break; - case 0x3041: mapif_parse_GuildCastleDataSave(fd, RFIFOW(fd,2), RFIFOB(fd,4), RFIFOL(fd,5)); break; - - default: - return 0; - } - - return 1; -} - -// processes a mapserver connection event -int inter_guild_mapif_init(int fd) -{ - return mapif_guild_castle_alldataload(fd); -} - -// サーバーから脱退要求(キャラ削除用) -int inter_guild_leave(int guild_id, int account_id, int char_id) -{ - return mapif_parse_GuildLeave(-1, guild_id, account_id, char_id, 0, "** Character Deleted **"); -} -#endif //TXT_SQL_CONVERT diff --git a/src/char/int_guild.h b/src/char/int_guild.h deleted file mode 100644 index 06293eb0f..000000000 --- a/src/char/int_guild.h +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder - -#ifndef _INT_GUILD_H_ -#define _INT_GUILD_H_ - -struct guild; -struct guild_castle; - -int inter_guild_init(void); -void inter_guild_final(void); -int inter_guild_save(void); -int inter_guild_parse_frommap(int fd); -struct guild *inter_guild_search(int guild_id); -int inter_guild_mapif_init(int fd); -int inter_guild_leave(int guild_id,int account_id,int char_id); -int inter_guild_sex_changed(int guild_id,int account_id,int char_id, int gender); - -extern char guild_txt[1024]; -extern char castle_txt[1024]; - -//For the TXT->SQL converter -int inter_guild_fromstr(char *str, struct guild *g); -int inter_guildcastle_fromstr(char *str, struct guild_castle *gc); - -#endif /* _INT_GUILD_H_ */ diff --git a/src/char/int_homun.c b/src/char/int_homun.c deleted file mode 100644 index d547b60f7..000000000 --- a/src/char/int_homun.c +++ /dev/null @@ -1,365 +0,0 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder - -#include "../common/mmo.h" -#include "../common/malloc.h" -#include "../common/socket.h" -#include "../common/db.h" -#include "../common/lock.h" -#include "../common/showmsg.h" -#include "char.h" -#include "inter.h" -#include "int_homun.h" - -#include -#include -#include - -char homun_txt[1024]="save/homun.txt"; - -static DBMap* homun_db; // int hom_id -> struct s_homunculus* -static int homun_newid = 100; - -int inter_homun_tostr(char *str,struct s_homunculus *p) -{ - int i; - - str+=sprintf(str,"%d,%d\t%s\t%d,%d,%d,%d,%d," - "%u,%d,%d,%d," - "%u,%d,%d," - "%d,%d,%d,%d,%d,%d\t", - p->hom_id, p->class_, p->name, - p->char_id, p->hp, p->max_hp, p->sp, p->max_sp, - p->intimacy, p->hunger, p->skillpts, p->level, - p->exp, p->rename_flag, p->vaporize, - p->str, p->agi, p->vit, p->int_, p->dex, p->luk); - - for (i = 0; i < MAX_HOMUNSKILL; i++) - { - if (p->hskill[i].id && !p->hskill[i].flag) - str+=sprintf(str,"%d,%d,", p->hskill[i].id, p->hskill[i].lv); - } - - return 0; -} - -int inter_homun_fromstr(char *str,struct s_homunculus *p) -{ - int i, next, len; - int tmp_int[25]; - unsigned int tmp_uint[5]; - char tmp_str[256]; - - memset(p,0,sizeof(struct s_homunculus)); - - i=sscanf(str,"%d,%d\t%127[^\t]\t%d,%d,%d,%d,%d," - "%u,%d,%d,%d," - "%u,%d,%d," - "%d,%d,%d,%d,%d,%d\t%n", - &tmp_int[0],&tmp_int[1],tmp_str, - &tmp_int[2],&tmp_int[3],&tmp_int[4],&tmp_int[5],&tmp_int[6], - &tmp_uint[0],&tmp_int[7],&tmp_int[8],&tmp_int[9], - &tmp_uint[1],&tmp_int[10],&tmp_int[11], - &tmp_int[12],&tmp_int[13],&tmp_int[14],&tmp_int[15],&tmp_int[16],&tmp_int[17], - &next); - - if(i!=21) - return 1; - - p->hom_id = tmp_int[0]; - p->class_ = tmp_int[1]; - memcpy(p->name, tmp_str, NAME_LENGTH); - - p->char_id = tmp_int[2]; - p->hp = tmp_int[3]; - p->max_hp = tmp_int[4]; - p->sp = tmp_int[5]; - p->max_sp = tmp_int[6]; - - p->intimacy = tmp_uint[0]; - p->hunger = tmp_int[7]; - p->skillpts = tmp_int[8]; - p->level = tmp_int[9]; - - p->exp = tmp_uint[1]; - p->rename_flag = tmp_int[10]; - p->vaporize = tmp_int[11]; - - p->str = tmp_int[12]; - p->agi = tmp_int[13]; - p->vit = tmp_int[14]; - p->int_= tmp_int[15]; - p->dex = tmp_int[16]; - p->luk = tmp_int[17]; - - //Read skills. - while(str[next] && str[next] != '\n' && str[next] != '\r') { - if (sscanf(str+next, "%d,%d,%n", &tmp_int[0], &tmp_int[1], &len) != 2) - return 2; - - if (tmp_int[0] >= HM_SKILLBASE && tmp_int[0] < HM_SKILLBASE+MAX_HOMUNSKILL) - { - i = tmp_int[0] - HM_SKILLBASE; - p->hskill[i].id = tmp_int[0]; - p->hskill[i].lv = tmp_int[1]; - } else - ShowError("Read Homun: Unsupported Skill ID %d for homunculus (Homun ID=%d)\n", tmp_int[0], p->hom_id); - next += len; - if (str[next] == ' ') - next++; - } - return 0; -} - -int inter_homun_init() -{ - char line[8192]; - struct s_homunculus *p; - FILE *fp; - int c=0; - - homun_db= idb_alloc(DB_OPT_RELEASE_DATA); - - if( (fp=fopen(homun_txt,"r"))==NULL ) - return 1; - while(fgets(line, sizeof(line), fp)) - { - p = (struct s_homunculus*)aCalloc(sizeof(struct s_homunculus), 1); - if(p==NULL){ - ShowFatalError("int_homun: out of memory!\n"); - exit(EXIT_FAILURE); - } - if(inter_homun_fromstr(line,p)==0 && p->hom_id>0){ - if( p->hom_id >= homun_newid) - homun_newid=p->hom_id+1; - idb_put(homun_db,p->hom_id,p); - }else{ - ShowError("int_homun: broken data [%s] line %d\n",homun_txt,c); - aFree(p); - } - c++; - } - fclose(fp); - return 0; -} - -void inter_homun_final() -{ - homun_db->destroy(homun_db, NULL); - return; -} - -int inter_homun_save_sub(DBKey key,void *data,va_list ap) -{ - char line[8192]; - FILE *fp; - inter_homun_tostr(line,(struct s_homunculus *)data); - fp=va_arg(ap,FILE *); - fprintf(fp,"%s\n",line); - return 0; -} - -int inter_homun_save() -{ - FILE *fp; - int lock; - if( (fp=lock_fopen(homun_txt,&lock))==NULL ){ - ShowError("int_homun: can't write [%s] !!! data is lost !!!\n",homun_txt); - return 1; - } - homun_db->foreach(homun_db,inter_homun_save_sub,fp); - lock_fclose(fp,homun_txt,&lock); - return 0; -} - -int inter_homun_delete(int hom_id) -{ - struct s_homunculus *p; - p = (struct s_homunculus*)idb_get(homun_db,hom_id); - if( p == NULL) - return 0; - idb_remove(homun_db,hom_id); - ShowInfo("Deleted homun (hom_id: %d)\n",hom_id); - return 1; -} - -int mapif_homun_created(int fd,int account_id, struct s_homunculus *p) -{ - WFIFOHEAD(fd, sizeof(struct s_homunculus)+9); - WFIFOW(fd, 0) =0x3890; - WFIFOW(fd,2) = sizeof(struct s_homunculus)+9; - WFIFOL(fd,4) = account_id; - WFIFOB(fd,8)= p->hom_id?1:0; - memcpy(WFIFOP(fd,9), p, sizeof(struct s_homunculus)); - WFIFOSET(fd, WFIFOW(fd,2)); - return 0; -} - -int mapif_homun_info(int fd,int account_id,struct s_homunculus *p) -{ - WFIFOHEAD(fd, sizeof(struct s_homunculus)+9); - WFIFOW(fd,0) = 0x3891; - WFIFOW(fd,2) = sizeof(struct s_homunculus)+9; - WFIFOL(fd,4) = account_id; - WFIFOB(fd,8) = 1; // account loaded with success - - memcpy(WFIFOP(fd,9), p, sizeof(struct s_homunculus)); - WFIFOSET(fd,WFIFOW(fd,2)); - return 0; -} - -int mapif_homun_noinfo(int fd,int account_id) -{ - WFIFOHEAD(fd,sizeof(struct s_homunculus) + 9); - WFIFOW(fd,0)=0x3891; - WFIFOW(fd,2)=sizeof(struct s_homunculus) + 9; - WFIFOL(fd,4)=account_id; - WFIFOB(fd,8)=0; - memset(WFIFOP(fd,9),0,sizeof(struct s_homunculus)); - WFIFOSET(fd,WFIFOW(fd,2)); - - return 0; -} - -int mapif_save_homun_ack(int fd,int account_id,int flag) -{ - WFIFOHEAD(fd, 7); - WFIFOW(fd,0)=0x3892; - WFIFOL(fd,2)=account_id; - WFIFOB(fd,6)=flag; - WFIFOSET(fd,7); - return 0; -} - -int mapif_delete_homun_ack(int fd,int flag) -{ - WFIFOHEAD(fd, 3); - WFIFOW(fd,0)=0x3893; - WFIFOB(fd,2)=flag; - WFIFOSET(fd,3); - return 0; -} - -int mapif_rename_homun_ack(int fd, int account_id, int char_id, int flag, char *name){ - WFIFOHEAD(fd, NAME_LENGTH+12); - WFIFOW(fd, 0) =0x3894; - WFIFOL(fd, 2) =account_id; - WFIFOL(fd, 6) =char_id; - WFIFOB(fd, 10) =flag; - memcpy(WFIFOP(fd, 11), name, NAME_LENGTH); - WFIFOSET(fd, NAME_LENGTH+12); - - return 0; -} - -int mapif_create_homun(int fd) -{ - struct s_homunculus *p; - p= (struct s_homunculus *) aCalloc(sizeof(struct s_homunculus), 1); - if(p==NULL){ - ShowFatalError("int_homun: out of memory !\n"); - //Sending the received data will pass hom_id == 0 <- fail. - mapif_homun_created(fd,RFIFOL(fd,4),(struct s_homunculus*)RFIFOP(fd,8)); - return 0; - } - memcpy(p, RFIFOP(fd,8), sizeof(struct s_homunculus)); - p->hom_id = homun_newid++; //New ID - idb_put(homun_db,p->hom_id,p); - mapif_homun_created(fd,RFIFOL(fd,4),p); - return 0; -} - -int mapif_load_homun(int fd) -{ - struct s_homunculus *p; - int account_id; - account_id = RFIFOL(fd,2); - - p = (struct s_homunculus*)idb_get(homun_db,RFIFOL(fd,6)); - if(p==NULL) { - mapif_homun_noinfo(fd,account_id); - return 0; - } - mapif_homun_info(fd,account_id,p); - return 0; -} - -static void* create_homun(DBKey key, va_list args) { - struct s_homunculus *p; - p=(struct s_homunculus *)aCalloc(sizeof(struct s_homunculus),1); - p->hom_id = key.i; - return p; -} -int mapif_save_homun(int fd,int account_id,struct s_homunculus *data) -{ - struct s_homunculus *p; - int hom_id; - - if (data->hom_id == 0) - data->hom_id = homun_newid++; - hom_id = data->hom_id; - p = (struct s_homunculus*)idb_ensure(homun_db,hom_id,create_homun); - memcpy(p,data,sizeof(struct s_homunculus)); - mapif_save_homun_ack(fd,account_id,1); - return 0; -} - -int mapif_delete_homun(int fd,int hom_id) -{ - mapif_delete_homun_ack(fd,inter_homun_delete(hom_id)); - return 0; -} - -int mapif_rename_homun(int fd, int account_id, int char_id, char *name){ - int i; - - // Check Authorised letters/symbols in the name of the homun - if (char_name_option == 1) { // only letters/symbols in char_name_letters are authorised - for (i = 0; i < NAME_LENGTH && name[i]; i++) - if (strchr(char_name_letters, name[i]) == NULL) { - mapif_rename_homun_ack(fd, account_id, char_id, 0, name); - return 0; - } - } else if (char_name_option == 2) { // letters/symbols in char_name_letters are forbidden - for (i = 0; i < NAME_LENGTH && name[i]; i++) - if (strchr(char_name_letters, name[i]) != NULL) { - mapif_rename_homun_ack(fd, account_id, char_id, 0, name); - return 0; - } - } - - mapif_rename_homun_ack(fd, account_id, char_id, 1, name); - return 0; -} - -int mapif_parse_SaveHomun(int fd) -{ - mapif_save_homun(fd,RFIFOL(fd,4),(struct s_homunculus *)RFIFOP(fd,8)); - return 0; -} - -int mapif_parse_DeleteHomun(int fd) -{ - mapif_delete_homun(fd,RFIFOL(fd,2)); - return 0; -} - -int mapif_parse_RenameHomun(int fd) -{ - mapif_rename_homun(fd, RFIFOL(fd, 2), RFIFOL(fd, 6), (char*)RFIFOP(fd, 10)); - return 0; -} - -int inter_homun_parse_frommap(int fd) -{ - switch(RFIFOW(fd,0)){ - case 0x3090: mapif_create_homun(fd); break; - case 0x3091: mapif_load_homun(fd); break; - case 0x3092: mapif_parse_SaveHomun(fd); break; - case 0x3093: mapif_parse_DeleteHomun(fd); break; - case 0x3094: mapif_parse_RenameHomun(fd); break; - default: - return 0; - } - return 1; -} diff --git a/src/char/int_homun.h b/src/char/int_homun.h deleted file mode 100644 index 1858ed4ba..000000000 --- a/src/char/int_homun.h +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder - -#ifndef _INT_HOMUN_H_ -#define _INT_HOMUN_H_ - -int inter_homun_init(void); -void inter_homun_final(void); -int inter_homun_save(void); -int inter_homun_delete(int homun_id); -int inter_homun_parse_frommap(int fd); - -extern char homun_txt[1024]; - -#endif /* _INT_HOMUN_H_ */ diff --git a/src/char/int_party.c b/src/char/int_party.c deleted file mode 100644 index f0668a820..000000000 --- a/src/char/int_party.c +++ /dev/null @@ -1,732 +0,0 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder - -#include "../common/cbasetypes.h" -#include "../common/mmo.h" -#include "../common/malloc.h" -#include "../common/socket.h" -#include "../common/db.h" -#include "../common/lock.h" -#include "../common/showmsg.h" -#include "char.h" -#include "inter.h" -#include "int_party.h" - -#include -#include -#include - -char party_txt[1024] = "save/party.txt"; -#ifndef TXT_SQL_CONVERT -struct party_data { - struct party party; - unsigned int min_lv, max_lv; - int family; //Is this party a family? if so, this holds the child id. - unsigned char size; //Total size of party. -}; - -static DBMap* party_db; // int party_id -> struct party_data* -static int party_newid = 100; - -int mapif_party_broken(int party_id, int flag); -int party_check_empty(struct party *p); -int mapif_parse_PartyLeave(int fd, int party_id, int account_id, int char_id); -int party_check_exp_share(struct party_data *p); -int mapif_party_optionchanged(int fd,struct party *p, int account_id, int flag); - -//Updates party's level range and unsets even share if broken. -static int int_party_check_lv(struct party_data *p) { - int i; - unsigned int lv; - p->min_lv = UINT_MAX; - p->max_lv = 0; - for(i=0;iparty.member[i].online) - continue; - - lv=p->party.member[i].lv; - if (lv < p->min_lv) p->min_lv = lv; - if (lv > p->max_lv) p->max_lv = lv; - } - - if (p->party.exp && !party_check_exp_share(p)) { - p->party.exp = 0; - mapif_party_optionchanged(0, &p->party, 0, 0); - return 0; - } - return 1; -} - -//Calculates the state of a party. -static void int_party_calc_state(struct party_data *p) -{ - int i; - unsigned int lv; - p->min_lv = UINT_MAX; - p->max_lv = 0; - p->party.count = - p->size = - p->family = 0; - - //Check party size. - for(i=0;iparty.member[i].lv) continue; - p->size++; - if(p->party.member[i].online) - p->party.count++; - } - if(p->size == 3) { - //Check Family State. - p->family = char_family( - p->party.member[0].char_id, - p->party.member[1].char_id, - p->party.member[2].char_id - ); - } - //max/min levels. - for(i=0;iparty.member[i].lv; - if (!lv) continue; - if(p->party.member[i].online && - //On families, the kid is not counted towards exp share rules. - p->party.member[i].char_id != p->family) - { - if( lv < p->min_lv ) p->min_lv=lv; - if( p->max_lv < lv ) p->max_lv=lv; - } - } - - if (p->party.exp && !party_check_exp_share(p)) { - p->party.exp = 0; //Set off even share. - mapif_party_optionchanged(0, &p->party, 0, 0); - } - return; -} - -// パ?ティデ?タの文字列への?換 -int inter_party_tostr(char *str, struct party *p) { - int i, len; - - len = sprintf(str, "%d\t%s\t%d,%d\t", p->party_id, p->name, p->exp, p->item); - for(i = 0; i < MAX_PARTY; i++) { - struct party_member *m = &p->member[i]; - len += sprintf(str + len, "%d,%d,%d\t", m->account_id, m->char_id, m->leader); - } - - return 0; -} -#endif //TXT_SQL_CONVERT -// パ?ティデ?タの文字列からの?換 -int inter_party_fromstr(char *str, struct party *p) { - int i, j; - int tmp_int[16]; - char tmp_str[256]; -#ifndef TXT_SQL_CONVERT - struct mmo_charstatus* status; -#endif - - memset(p, 0, sizeof(struct party)); - - if (sscanf(str, "%d\t%255[^\t]\t%d,%d\t", &tmp_int[0], tmp_str, &tmp_int[1], &tmp_int[2]) != 4) - return 1; - - p->party_id = tmp_int[0]; - memcpy(p->name, tmp_str, NAME_LENGTH); - p->exp = tmp_int[1]?1:0; - p->item = tmp_int[2]; - - for(j = 0; j < 3 && str != NULL; j++) - str = strchr(str + 1, '\t'); - - for(i = 0; i < MAX_PARTY; i++) { - struct party_member *m = &p->member[i]; - if (str == NULL) - return 1; - - if (sscanf(str + 1, "%d,%d,%d\t", &tmp_int[0], &tmp_int[1], &tmp_int[2]) != 3) - return 1; - - m->account_id = tmp_int[0]; - m->char_id = tmp_int[1]; - m->leader = tmp_int[2]?1:0; - - str = strchr(str + 1, '\t'); -#ifndef TXT_SQL_CONVERT - if (!m->account_id) continue; - //Lookup player for rest of data. - status = search_character(m->account_id, m->char_id); - if (!status) continue; - - memcpy(m->name, status->name, NAME_LENGTH); - m->class_ = status->class_; - m->map = status->last_point.map; - m->lv = status->base_level; -#endif //TXT_SQL_CONVERT - } - - return 0; -} -#ifndef TXT_SQL_CONVERT -// パ?ティデ?タのロ?ド -int inter_party_init() { - char line[8192]; - struct party_data *p; - FILE *fp; - int c = 0; - int i, j; - - party_db = idb_alloc(DB_OPT_RELEASE_DATA); - - if ((fp = fopen(party_txt, "r")) == NULL) - return 1; - - while(fgets(line, sizeof(line), fp)) - { - j = 0; - if (sscanf(line, "%d\t%%newid%%\n%n", &i, &j) == 1 && j > 0 && party_newid <= i) { - party_newid = i; - continue; - } - - p = (struct party_data*)aCalloc(sizeof(struct party_data), 1); - if (p == NULL){ - ShowFatalError("int_party: out of memory!\n"); - exit(EXIT_FAILURE); - } - memset(p, 0, sizeof(struct party_data)); - if (inter_party_fromstr(line, &p->party) == 0 && p->party.party_id > 0) { - int_party_calc_state(p); - if (p->party.party_id >= party_newid) - party_newid = p->party.party_id + 1; - idb_put(party_db, p->party.party_id, p); - party_check_empty(&p->party); - } else { - ShowError("int_party: broken data [%s] line %d\n", party_txt, c + 1); - aFree(p); - } - c++; - } - fclose(fp); - - return 0; -} - -void inter_party_final() -{ - party_db->destroy(party_db, NULL); - return; -} - -// パ?ティ?デ?タのセ?ブ用 -int inter_party_save_sub(DBKey key, void *data, va_list ap) { - char line[8192]; - FILE *fp; - - inter_party_tostr(line, &((struct party_data*)data)->party); - fp = va_arg(ap, FILE *); - fprintf(fp, "%s\n", line); - - return 0; -} - -// パ?ティ?デ?タのセ?ブ -int inter_party_save() { - FILE *fp; - int lock; - - if ((fp = lock_fopen(party_txt, &lock)) == NULL) { - ShowError("int_party: can't write [%s] !!! data is lost !!!\n", party_txt); - return 1; - } - party_db->foreach(party_db, inter_party_save_sub, fp); - lock_fclose(fp,party_txt, &lock); - return 0; -} - -// パ?ティ名?索用 -int search_partyname_sub(DBKey key,void *data,va_list ap) { - struct party_data *p = (struct party_data *)data,**dst; - char *str; - - str = va_arg(ap, char *); - dst = va_arg(ap, struct party_data **); - if (strncmpi(p->party.name, str, NAME_LENGTH) == 0) - *dst = p; - - return 0; -} - -// パ?ティ名?索 -struct party_data* search_partyname(char *str) { - struct party_data *p = NULL; - party_db->foreach(party_db, search_partyname_sub, str, &p); - return p; -} - -// Returns whether this party can keep having exp share or not. -int party_check_exp_share(struct party_data *p) { - return (p->party.count < 2|| p->max_lv - p->min_lv <= party_share_level); -} - -// パ?ティが空かどうかチェック -int party_check_empty(struct party *p) { - int i; - - for(i = 0; i < MAX_PARTY; i++) { - if (p->member[i].account_id > 0) { - return 0; - } - } - mapif_party_broken(p->party_id, 0); - idb_remove(party_db, p->party_id); - - return 1; -} - -// キャラの競合がないかチェック用 -int party_check_conflict_sub(DBKey key, void *data, va_list ap) { - struct party_data *p = (struct party_data *)data; - int party_id, account_id, char_id, i; - - party_id=va_arg(ap, int); - account_id=va_arg(ap, int); - char_id=va_arg(ap, int); - - if (p->party.party_id == party_id) //No conflict to check - return 0; - - for(i = 0; i < MAX_PARTY; i++) { - if(p->party.member[i].account_id == account_id && - p->party.member[i].char_id == char_id) - { - ShowWarning("int_party: party conflict! %d %d %d\n", account_id, party_id, p->party.party_id); - mapif_parse_PartyLeave(-1, p->party.party_id, account_id, char_id); - } - } - - return 0; -} - -// キャラの競合がないかチェック -int party_check_conflict(int party_id, int account_id, int char_id) { - party_db->foreach(party_db, party_check_conflict_sub, party_id, account_id, char_id); - return 0; -} - -//------------------------------------------------------------------- -// map serverへの通信 - -// パ?ティ作成可否 -int mapif_party_created(int fd,int account_id, int char_id, struct party *p) { - WFIFOHEAD(fd, 39); - WFIFOW(fd,0) = 0x3820; - WFIFOL(fd,2) = account_id; - WFIFOL(fd,6) = char_id; - if (p != NULL) { - WFIFOB(fd,10) = 0; - WFIFOL(fd,11) = p->party_id; - memcpy(WFIFOP(fd,15), p->name, NAME_LENGTH); - ShowInfo("Created party (%d - %s)\n", p->party_id, p->name); - } else { - WFIFOB(fd,10) = 1; - WFIFOL(fd,11) = 0; - memset(WFIFOP(fd,15), 0, NAME_LENGTH); - } - WFIFOSET(fd,39); - return 0; -} - -// パ?ティ情報見つからず -int mapif_party_noinfo(int fd, int party_id) { - WFIFOHEAD(fd, 8); - WFIFOW(fd,0) = 0x3821; - WFIFOW(fd,2) = 8; - WFIFOL(fd,4) = party_id; - WFIFOSET(fd,8); - ShowWarning("int_party: info not found %d\n", party_id); - - return 0; -} - -// パ?ティ情報まとめ送り -int mapif_party_info(int fd, struct party *p) { - unsigned char buf[2048]; - - WBUFW(buf,0) = 0x3821; - memcpy(buf + 4, p, sizeof(struct party)); - WBUFW(buf,2) = 4 + sizeof(struct party); - if (fd < 0) - mapif_sendall(buf, WBUFW(buf,2)); - else - mapif_send(fd, buf, WBUFW(buf,2)); - return 0; -} - -// パ?ティメンバ追加可否 -int mapif_party_memberadded(int fd, int party_id, int account_id, int char_id, int flag) { - WFIFOHEAD(fd, 15); - WFIFOW(fd,0) = 0x3822; - WFIFOL(fd,2) = party_id; - WFIFOL(fd,6) = account_id; - WFIFOL(fd,10) = char_id; - WFIFOB(fd,14) = flag; - WFIFOSET(fd,15); - - return 0; -} - -// パ?ティ設定?更通知 -int mapif_party_optionchanged(int fd,struct party *p, int account_id, int flag) { - unsigned char buf[15]; - - WBUFW(buf,0) = 0x3823; - WBUFL(buf,2) = p->party_id; - WBUFL(buf,6) = account_id; - WBUFW(buf,10) = p->exp; - WBUFW(buf,12) = p->item; - WBUFB(buf,14) = flag; - if (flag == 0) - mapif_sendall(buf, 15); - else - mapif_send(fd, buf, 15); - return 0; -} - -// パ?ティ?退通知 -int mapif_party_leaved(int party_id,int account_id, int char_id) { - unsigned char buf[16]; - - WBUFW(buf,0) = 0x3824; - WBUFL(buf,2) = party_id; - WBUFL(buf,6) = account_id; - WBUFL(buf,10) = char_id; - mapif_sendall(buf, 14); - return 0; -} - -// パ?ティマップ更新通知 -int mapif_party_membermoved(struct party *p, int idx) { - unsigned char buf[20]; - - WBUFW(buf,0) = 0x3825; - WBUFL(buf,2) = p->party_id; - WBUFL(buf,6) = p->member[idx].account_id; - WBUFL(buf,10) = p->member[idx].char_id; - WBUFW(buf,14) = p->member[idx].map; - WBUFB(buf,16) = p->member[idx].online; - WBUFW(buf,17) = p->member[idx].lv; - mapif_sendall(buf, 19); - return 0; -} - -// パ?ティ解散通知 -int mapif_party_broken(int party_id, int flag) { - unsigned char buf[7]; - WBUFW(buf,0) = 0x3826; - WBUFL(buf,2) = party_id; - WBUFB(buf,6) = flag; - mapif_sendall(buf, 7); - ShowInfo("Party broken (%d)\n", party_id); - - return 0; -} - -// パ?ティ??言 -int mapif_party_message(int party_id, int account_id, char *mes, int len, int sfd) { - unsigned char buf[2048]; - - WBUFW(buf,0) = 0x3827; - WBUFW(buf,2) = len + 12; - WBUFL(buf,4) = party_id; - WBUFL(buf,8) = account_id; - memcpy(WBUFP(buf,12), mes, len); - mapif_sendallwos(sfd, buf,len + 12); - - return 0; -} - -//------------------------------------------------------------------- -// map serverからの通信 - - -// パ?ティ -int mapif_parse_CreateParty(int fd, char *name, int item, int item2, struct party_member *leader) { - struct party_data *p; - int i; - - for(i = 0; i < NAME_LENGTH && name[i]; i++) { - if (!(name[i] & 0xe0) || name[i] == 0x7f) { - ShowInfo("int_party: illegal party name [%s]\n", name); - mapif_party_created(fd, leader->account_id, leader->char_id, NULL); - return 0; - } - } - - if ((p = search_partyname(name)) != NULL) { - ShowInfo("int_party: same name party exists [%s]\n", name); - mapif_party_created(fd, leader->account_id, leader->char_id, NULL); - return 0; - } - - // Check Authorised letters/symbols in the name of the character - if (char_name_option == 1) { // only letters/symbols in char_name_letters are authorised - for (i = 0; i < NAME_LENGTH && name[i]; i++) - if (strchr(char_name_letters, name[i]) == NULL) { - mapif_party_created(fd, leader->account_id, leader->char_id, NULL); - return 0; - } - } else if (char_name_option == 2) { // letters/symbols in char_name_letters are forbidden - for (i = 0; i < NAME_LENGTH && name[i]; i++) - if (strchr(char_name_letters, name[i]) != NULL) { - mapif_party_created(fd, leader->account_id, leader->char_id, NULL); - return 0; - } - } - - p = (struct party_data *) aCalloc(sizeof(struct party_data), 1); - if (p == NULL) { - ShowFatalError("int_party: out of memory !\n"); - mapif_party_created(fd,leader->account_id,leader->char_id,NULL); - return 0; - } - p->party.party_id = party_newid++; - memcpy(p->party.name, name, NAME_LENGTH); - p->party.exp = 0; - p->party.item=(item?1:0)|(item2?2:0); - memcpy(&p->party.member[0], leader, sizeof(struct party_member)); - p->party.member[0].leader = 1; - int_party_calc_state(p); - idb_put(party_db, p->party.party_id, p); - - mapif_party_created(fd, leader->account_id, leader->char_id, &p->party); - mapif_party_info(fd, &p->party); - - return 0; -} - -// パ?ティ情報要求 -int mapif_parse_PartyInfo(int fd, int party_id) -{ - struct party_data *p; - - p = (struct party_data*)idb_get(party_db, party_id); - if (p != NULL) - mapif_party_info(fd, &p->party); - else { - mapif_party_noinfo(fd, party_id); - char_clearparty(party_id); - } - - return 0; -} - -// パーティ追加要求 -int mapif_parse_PartyAddMember(int fd, int party_id, struct party_member *member) -{ - struct party_data *p; - int i; - - p = (struct party_data*)idb_get(party_db, party_id); - if( p == NULL || p->size == MAX_PARTY ) { - mapif_party_memberadded(fd, party_id, member->account_id, member->char_id, 1); - return 0; - } - - ARR_FIND( 0, MAX_PARTY, i, p->party.member[i].account_id == 0 ); - if( i == MAX_PARTY ) - {// Party full - mapif_party_memberadded(fd, party_id, member->account_id, member->char_id, 1); - return 0; - } - - memcpy(&p->party.member[i], member, sizeof(struct party_member)); - p->party.member[i].leader = 0; - if (p->party.member[i].online) p->party.count++; - p->size++; - if (p->size == 3) //Check family state. - int_party_calc_state(p); - else //Check even share range. - if (member->lv < p->min_lv || member->lv > p->max_lv || p->family) { - if (p->family) p->family = 0; //Family state broken. - int_party_check_lv(p); - } - - mapif_party_memberadded(fd, party_id, member->account_id, member->char_id, 0); - mapif_party_info(-1, &p->party); - - return 0; -} - -// パ?ティ?設定?更要求 -int mapif_parse_PartyChangeOption(int fd, int party_id, int account_id, int exp, int item) -{ - struct party_data *p; - int flag = 0; - - p = (struct party_data*)idb_get(party_db, party_id); - if (p == NULL) - return 0; - - p->party.exp = exp; - if (exp>0 && !party_check_exp_share(p)) { - flag |= 0x01; - p->party.exp = 0; - } - p->party.item = item&0x3; - mapif_party_optionchanged(fd, &p->party, account_id, flag); - return 0; -} - -// パ?ティ?退要求 -int mapif_parse_PartyLeave(int fd, int party_id, int account_id, int char_id) -{ - struct party_data *p; - int i,lv; - - p = (struct party_data*)idb_get(party_db, party_id); - if (!p) return 0; - - for(i = 0; i < MAX_PARTY; i++) { - if(p->party.member[i].account_id == account_id && - p->party.member[i].char_id == char_id) - { - mapif_party_leaved(party_id, account_id, char_id); - lv = p->party.member[i].lv; - if(p->party.member[i].online) p->party.count--; - memset(&p->party.member[i], 0, sizeof(struct party_member)); - p->size--; - if (lv == p->min_lv || lv == p->max_lv || p->family) - { - if(p->family) p->family = 0; //Family state broken. - int_party_check_lv(p); - } - if (party_check_empty(&p->party) == 0) - mapif_party_info(-1, &p->party); - return 0; - } - } - return 0; -} - -int mapif_parse_PartyChangeMap(int fd, int party_id, int account_id, int char_id, unsigned short map, int online, unsigned int lv) -{ - struct party_data *p; - int i; - - p = (struct party_data*)idb_get(party_db, party_id); - if (p == NULL) - return 0; - - for(i = 0; i < MAX_PARTY && - (p->party.member[i].account_id != account_id || - p->party.member[i].char_id != char_id); i++); - - if (i == MAX_PARTY) return 0; - - if (p->party.member[i].online != online) - { - p->party.member[i].online = online; - if (online) - p->party.count++; - else - p->party.count--; - // Even share check situations: Family state (always breaks) - // character logging on/off is max/min level (update level range) - // or character logging on/off has a different level (update level range using new level) - if (p->family || - (p->party.member[i].lv <= p->min_lv || p->party.member[i].lv >= p->max_lv) || - (p->party.member[i].lv != lv && (lv <= p->min_lv || lv >= p->max_lv)) - ) - { - p->party.member[i].lv = lv; - int_party_check_lv(p); - } - //Send online/offline update. - mapif_party_membermoved(&p->party, i); - } - if (p->party.member[i].lv != lv) { - if(p->party.member[i].lv == p->min_lv || - p->party.member[i].lv == p->max_lv) - { - p->party.member[i].lv = lv; - int_party_check_lv(p); - } else - p->party.member[i].lv = lv; - //There is no need to send level update to map servers - //since they do nothing with it. - } - if (p->party.member[i].map != map) { - p->party.member[i].map = map; - mapif_party_membermoved(&p->party, i); - } - return 0; -} - -// パ?ティ解散要求 -int mapif_parse_BreakParty(int fd, int party_id) { - - idb_remove(party_db, party_id); - mapif_party_broken(fd, party_id); - - return 0; -} - -// パ?ティメッセ?ジ送信 -int mapif_parse_PartyMessage(int fd, int party_id, int account_id, char *mes, int len) { - return mapif_party_message(party_id, account_id, mes, len, fd); -} -// パ?ティチェック要求 -int mapif_parse_PartyCheck(int fd, int party_id, int account_id, int char_id) { - return party_check_conflict(party_id, account_id, char_id); -} - -int mapif_parse_PartyLeaderChange(int fd,int party_id,int account_id,int char_id) -{ - struct party_data *p; - int i; - - p = (struct party_data*)idb_get(party_db, party_id); - if (p == NULL) - return 0; - - for (i = 0; i < MAX_PARTY; i++) - { - if(p->party.member[i].leader) - p->party.member[i].leader = 0; - if(p->party.member[i].account_id == account_id && - p->party.member[i].char_id == char_id) - p->party.member[i].leader = 1; - } - return 1; -} - -// map server からの通信 -// ?1パケットのみ解析すること -// ?パケット長デ?タはinter.cにセットしておくこと -// ?パケット長チェックや、RFIFOSKIPは呼び出し元で行われるので行ってはならない -// ?エラ?なら0(false)、そうでないなら1(true)をかえさなければならない -int inter_party_parse_frommap(int fd) { - RFIFOHEAD(fd); - switch(RFIFOW(fd,0)) { - case 0x3020: mapif_parse_CreateParty(fd, (char*)RFIFOP(fd,4), RFIFOB(fd,28), RFIFOB(fd,29), (struct party_member*)RFIFOP(fd,30)); break; - case 0x3021: mapif_parse_PartyInfo(fd, RFIFOL(fd,2)); break; - case 0x3022: mapif_parse_PartyAddMember(fd, RFIFOL(fd,4), (struct party_member*)RFIFOP(fd,8)); break; - case 0x3023: mapif_parse_PartyChangeOption(fd, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOW(fd,10), RFIFOW(fd,12)); break; - case 0x3024: mapif_parse_PartyLeave(fd, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10)); break; - case 0x3025: mapif_parse_PartyChangeMap(fd, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10), RFIFOW(fd,14), RFIFOB(fd,16), RFIFOW(fd,17)); break; - case 0x3026: mapif_parse_BreakParty(fd, RFIFOL(fd,2)); break; - case 0x3027: mapif_parse_PartyMessage(fd, RFIFOL(fd,4), RFIFOL(fd,8), (char*)RFIFOP(fd,12), RFIFOW(fd,2)-12); break; - case 0x3028: mapif_parse_PartyCheck(fd, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10)); break; - case 0x3029: mapif_parse_PartyLeaderChange(fd, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10)); break; - default: - return 0; - } - - return 1; -} - -// サ?バ?から?退要求(キャラ削除用) -int inter_party_leave(int party_id, int account_id, int char_id) { - return mapif_parse_PartyLeave(-1, party_id, account_id, char_id); -} -#endif //TXT_SQL_CONVERT diff --git a/src/char/int_party.h b/src/char/int_party.h deleted file mode 100644 index ad724e475..000000000 --- a/src/char/int_party.h +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder - -#ifndef _INT_PARTY_H_ -#define _INT_PARTY_H_ - -struct party; - -int inter_party_init(void); -void inter_party_final(void); -int inter_party_save(void); -int inter_party_parse_frommap(int fd); -int inter_party_leave(int party_id,int account_id, int char_id); - -extern char party_txt[1024]; - -//For the TXT->SQL converter -int inter_party_fromstr(char *str, struct party *p); - -#endif /* _INT_PARTY_H_ */ diff --git a/src/char/int_pet.c b/src/char/int_pet.c deleted file mode 100644 index 41d61fbc3..000000000 --- a/src/char/int_pet.c +++ /dev/null @@ -1,380 +0,0 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder - -#include "../common/mmo.h" -#include "../common/malloc.h" -#include "../common/socket.h" -#include "../common/db.h" -#include "../common/lock.h" -#include "../common/showmsg.h" -#include "char.h" -#include "inter.h" -#include "int_pet.h" - -#include -#include -#include - -char pet_txt[1024]="save/pet.txt"; - -#ifndef TXT_SQL_CONVERT -static DBMap* pet_db; // int pet_id -> struct s_pet* -static int pet_newid = 100; - -int inter_pet_tostr(char *str,struct s_pet *p) -{ - int len; - - if(p->hungry < 0) - p->hungry = 0; - else if(p->hungry > 100) - p->hungry = 100; - if(p->intimate < 0) - p->intimate = 0; - else if(p->intimate > 1000) - p->intimate = 1000; - - len=sprintf(str,"%d,%d,%s\t%d,%d,%d,%d,%d,%d,%d,%d,%d", - p->pet_id,p->class_,p->name,p->account_id,p->char_id,p->level,p->egg_id, - p->equip,p->intimate,p->hungry,p->rename_flag,p->incuvate); - - return 0; -} -#endif //TXT_SQL_CONVERT -int inter_pet_fromstr(char *str,struct s_pet *p) -{ - int s; - int tmp_int[16]; - char tmp_str[256]; - - memset(p,0,sizeof(struct s_pet)); - - s=sscanf(str,"%d,%d,%[^\t]\t%d,%d,%d,%d,%d,%d,%d,%d,%d",&tmp_int[0],&tmp_int[1],tmp_str,&tmp_int[2], - &tmp_int[3],&tmp_int[4],&tmp_int[5],&tmp_int[6],&tmp_int[7],&tmp_int[8],&tmp_int[9],&tmp_int[10]); - - if(s!=12) - return 1; - - p->pet_id = tmp_int[0]; - p->class_ = tmp_int[1]; - memcpy(p->name,tmp_str,NAME_LENGTH); - p->account_id = tmp_int[2]; - p->char_id = tmp_int[3]; - p->level = tmp_int[4]; - p->egg_id = tmp_int[5]; - p->equip = tmp_int[6]; - p->intimate = tmp_int[7]; - p->hungry = tmp_int[8]; - p->rename_flag = tmp_int[9]; - p->incuvate = tmp_int[10]; - - if(p->hungry < 0) - p->hungry = 0; - else if(p->hungry > 100) - p->hungry = 100; - if(p->intimate < 0) - p->intimate = 0; - else if(p->intimate > 1000) - p->intimate = 1000; - - return 0; -} -#ifndef TXT_SQL_CONVERT -int inter_pet_init() -{ - char line[8192]; - struct s_pet *p; - FILE *fp; - int c=0; - - pet_db= idb_alloc(DB_OPT_RELEASE_DATA); - - if( (fp=fopen(pet_txt,"r"))==NULL ) - return 1; - while(fgets(line, sizeof(line), fp)) - { - p = (struct s_pet*)aCalloc(sizeof(struct s_pet), 1); - if(p==NULL){ - ShowFatalError("int_pet: out of memory!\n"); - exit(EXIT_FAILURE); - } - memset(p,0,sizeof(struct s_pet)); - if(inter_pet_fromstr(line,p)==0 && p->pet_id>0){ - if( p->pet_id >= pet_newid) - pet_newid=p->pet_id+1; - idb_put(pet_db,p->pet_id,p); - }else{ - ShowError("int_pet: broken data [%s] line %d\n",pet_txt,c); - aFree(p); - } - c++; - } - fclose(fp); - return 0; -} - -void inter_pet_final() -{ - pet_db->destroy(pet_db, NULL); - return; -} - -int inter_pet_save_sub(DBKey key,void *data,va_list ap) -{ - char line[8192]; - FILE *fp; - inter_pet_tostr(line,(struct s_pet *)data); - fp=va_arg(ap,FILE *); - fprintf(fp,"%s\n",line); - return 0; -} - -int inter_pet_save() -{ - FILE *fp; - int lock; - if( (fp=lock_fopen(pet_txt,&lock))==NULL ){ - ShowError("int_pet: can't write [%s] !!! data is lost !!!\n",pet_txt); - return 1; - } - pet_db->foreach(pet_db,inter_pet_save_sub,fp); - lock_fclose(fp,pet_txt,&lock); - return 0; -} - -int inter_pet_delete(int pet_id) -{ - struct s_pet *p; - p = (struct s_pet*)idb_get(pet_db,pet_id); - if( p == NULL) - return 1; - else { - idb_remove(pet_db,pet_id); - ShowInfo("Deleted pet (pet_id: %d)\n",pet_id); - } - return 0; -} - -int mapif_pet_created(int fd,int account_id,struct s_pet *p) -{ - WFIFOHEAD(fd, 11); - WFIFOW(fd,0)=0x3880; - WFIFOL(fd,2)=account_id; - if(p!=NULL){ - WFIFOB(fd,6)=0; - WFIFOL(fd,7)=p->pet_id; - ShowInfo("Created pet (%d - %s)\n",p->pet_id,p->name); - }else{ - WFIFOB(fd,6)=1; - WFIFOL(fd,7)=0; - } - WFIFOSET(fd,11); - - return 0; -} - -int mapif_pet_info(int fd,int account_id,struct s_pet *p) -{ - WFIFOHEAD(fd, sizeof(struct s_pet) + 9); - WFIFOW(fd,0)=0x3881; - WFIFOW(fd,2)=sizeof(struct s_pet) + 9; - WFIFOL(fd,4)=account_id; - WFIFOB(fd,8)=0; - memcpy(WFIFOP(fd,9),p,sizeof(struct s_pet)); - WFIFOSET(fd,WFIFOW(fd,2)); - - return 0; -} - -int mapif_pet_noinfo(int fd,int account_id) -{ - WFIFOHEAD(fd, sizeof(struct s_pet) + 9); - WFIFOW(fd,0)=0x3881; - WFIFOW(fd,2)=sizeof(struct s_pet) + 9; - WFIFOL(fd,4)=account_id; - WFIFOB(fd,8)=1; - memset(WFIFOP(fd,9),0,sizeof(struct s_pet)); - WFIFOSET(fd,WFIFOW(fd,2)); - - return 0; -} - -int mapif_save_pet_ack(int fd,int account_id,int flag) -{ - WFIFOHEAD(fd, 7); - WFIFOW(fd,0)=0x3882; - WFIFOL(fd,2)=account_id; - WFIFOB(fd,6)=flag; - WFIFOSET(fd,7); - - return 0; -} - -int mapif_delete_pet_ack(int fd,int flag) -{ - WFIFOHEAD(fd, 3); - WFIFOW(fd,0)=0x3883; - WFIFOB(fd,2)=flag; - WFIFOSET(fd,3); - - return 0; -} - -int mapif_create_pet(int fd,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) -{ - struct s_pet *p; - p= (struct s_pet *) aCalloc(sizeof(struct s_pet), 1); - if(p==NULL){ - ShowFatalError("int_pet: out of memory !\n"); - mapif_pet_created(fd,account_id,NULL); - return 0; - } -// memset(p,0,sizeof(struct s_pet)); unnecessary after aCalloc [Skotlex] - p->pet_id = pet_newid++; - memcpy(p->name,pet_name,NAME_LENGTH); - if(incuvate == 1) - p->account_id = p->char_id = 0; - else { - p->account_id = account_id; - p->char_id = char_id; - } - p->class_ = pet_class; - p->level = pet_lv; - p->egg_id = pet_egg_id; - p->equip = pet_equip; - p->intimate = intimate; - p->hungry = hungry; - p->rename_flag = rename_flag; - p->incuvate = incuvate; - - if(p->hungry < 0) - p->hungry = 0; - else if(p->hungry > 100) - p->hungry = 100; - if(p->intimate < 0) - p->intimate = 0; - else if(p->intimate > 1000) - p->intimate = 1000; - - idb_put(pet_db,p->pet_id,p); - - mapif_pet_created(fd,account_id,p); - - return 0; -} - -int mapif_load_pet(int fd,int account_id,int char_id,int pet_id) -{ - struct s_pet *p; - p = (struct s_pet*)idb_get(pet_db,pet_id); - if(p!=NULL) { - if(p->incuvate == 1) { - p->account_id = p->char_id = 0; - mapif_pet_info(fd,account_id,p); - } - else if(account_id == p->account_id && char_id == p->char_id) - mapif_pet_info(fd,account_id,p); - else - mapif_pet_noinfo(fd,account_id); - } - else - mapif_pet_noinfo(fd,account_id); - - return 0; -} - -static void* create_pet(DBKey key, va_list args) { - struct s_pet *p; - p=(struct s_pet *)aCalloc(sizeof(struct s_pet),1); - p->pet_id = key.i; - return p; -} -int mapif_save_pet(int fd,int account_id,struct s_pet *data) -{ - struct s_pet *p; - int pet_id, len; - RFIFOHEAD(fd); - len=RFIFOW(fd,2); - - if(sizeof(struct s_pet)!=len-8) { - ShowError("inter pet: data size error %d %d\n",sizeof(struct s_pet),len-8); - } - else{ - pet_id = data->pet_id; - if (pet_id == 0) - pet_id = data->pet_id = pet_newid++; - p = (struct s_pet*)idb_ensure(pet_db,pet_id,create_pet); - if(data->hungry < 0) - data->hungry = 0; - else if(data->hungry > 100) - data->hungry = 100; - if(data->intimate < 0) - data->intimate = 0; - else if(data->intimate > 1000) - data->intimate = 1000; - memcpy(p,data,sizeof(struct s_pet)); - if(p->incuvate == 1) - p->account_id = p->char_id = 0; - - mapif_save_pet_ack(fd,account_id,0); - } - - return 0; -} - -int mapif_delete_pet(int fd,int pet_id) -{ - mapif_delete_pet_ack(fd,inter_pet_delete(pet_id)); - - return 0; -} - -int mapif_parse_CreatePet(int fd) -{ - RFIFOHEAD(fd); - mapif_create_pet(fd,RFIFOL(fd,2),RFIFOL(fd,6),RFIFOW(fd,10),RFIFOW(fd,12),RFIFOW(fd,14),RFIFOW(fd,16),RFIFOW(fd,18), - RFIFOW(fd,20),RFIFOB(fd,22),RFIFOB(fd,23),(char*)RFIFOP(fd,24)); - return 0; -} - -int mapif_parse_LoadPet(int fd) -{ - RFIFOHEAD(fd); - mapif_load_pet(fd,RFIFOL(fd,2),RFIFOL(fd,6),RFIFOL(fd,10)); - return 0; -} - -int mapif_parse_SavePet(int fd) -{ - RFIFOHEAD(fd); - mapif_save_pet(fd,RFIFOL(fd,4),(struct s_pet *)RFIFOP(fd,8)); - return 0; -} - -int mapif_parse_DeletePet(int fd) -{ - RFIFOHEAD(fd); - mapif_delete_pet(fd,RFIFOL(fd,2)); - return 0; -} - -// map server からの通信 -// ・1パケットのみ解析すること -// ・パケット長データはinter.cにセットしておくこと -// ・パケット長チェックや、RFIFOSKIPは呼び出し元で行われるので行ってはならない -// ・エラーなら0(false)、そうでないなら1(true)をかえさなければならない -int inter_pet_parse_frommap(int fd) -{ - RFIFOHEAD(fd); - switch(RFIFOW(fd,0)){ - case 0x3080: mapif_parse_CreatePet(fd); break; - case 0x3081: mapif_parse_LoadPet(fd); break; - case 0x3082: mapif_parse_SavePet(fd); break; - case 0x3083: mapif_parse_DeletePet(fd); break; - default: - return 0; - } - return 1; -} -#endif //TXT_SQL_CONVERT diff --git a/src/char/int_pet.h b/src/char/int_pet.h deleted file mode 100644 index 9234af109..000000000 --- a/src/char/int_pet.h +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder - -#ifndef _INT_PET_H_ -#define _INT_PET_H_ - -struct s_pet; - -int inter_pet_init(void); -void inter_pet_final(void); -int inter_pet_save(void); -int inter_pet_delete(int pet_id); - -int inter_pet_parse_frommap(int fd); - -extern char pet_txt[1024]; - -//Exported for use in the TXT-SQL converter. -int inter_pet_fromstr(char *str,struct s_pet *p); - -#endif /* _INT_PET_H_ */ diff --git a/src/char/int_status.c b/src/char/int_status.c deleted file mode 100644 index bf5d94155..000000000 --- a/src/char/int_status.c +++ /dev/null @@ -1,183 +0,0 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder - -#include "../common/mmo.h" -#include "../common/db.h" -#include "../common/lock.h" -#include "../common/malloc.h" -#include "../common/showmsg.h" -#include "int_status.h" - -#include - -// Contains all the status change data in-memory. [Skotlex] -static DBMap* scdata_db = NULL; // int char_id -> struct scdata* -char scdata_txt[1024]="save/scdata.txt"; //By [Skotlex] - -#ifdef ENABLE_SC_SAVING -static void* create_scdata(DBKey key, va_list args) -{ - struct scdata *data; - data = (struct scdata*)aCalloc(1, sizeof(struct scdata)); - data->account_id = va_arg(args, int); - data->char_id = key.i; - return data; -} - -/*========================================== - * Loads status change data of the player given. [Skotlex] - *------------------------------------------*/ -struct scdata* status_search_scdata(int aid, int cid) -{ - return (struct scdata*)scdata_db->ensure(scdata_db, i2key(cid), create_scdata, aid); -} - -/*========================================== - * Deletes status change data of the player given. [Skotlex] - * Should be invoked after the data of said player was successfully loaded. - *------------------------------------------*/ -void status_delete_scdata(int aid, int cid) -{ - struct scdata* scdata = (struct scdata*)idb_remove(scdata_db, cid); - if (scdata) - { - if (scdata->data) - aFree(scdata->data); - aFree(scdata); - } -} - - -static void inter_status_tostr(char* line, struct scdata *sc_data) -{ - int i, len; - - len = sprintf(line, "%d,%d,%d\t", sc_data->account_id, sc_data->char_id, sc_data->count); - for(i = 0; i < sc_data->count; i++) { - len += sprintf(line + len, "%d,%d,%d,%d,%d,%d\t", sc_data->data[i].type, sc_data->data[i].tick, - sc_data->data[i].val1, sc_data->data[i].val2, sc_data->data[i].val3, sc_data->data[i].val4); - } - return; -} - -static int inter_scdata_fromstr(char *line, struct scdata *sc_data) -{ - int i, len, next; - - if (sscanf(line,"%d,%d,%d\t%n",&sc_data->account_id, &sc_data->char_id, &sc_data->count, &next) < 3) - return 0; - - if (sc_data->count < 1) - return 0; - - sc_data->data = (struct status_change_data*)aCalloc(sc_data->count, sizeof (struct status_change_data)); - - for (i = 0; i < sc_data->count; i++) - { - if (sscanf(line + next, "%hu,%d,%d,%d,%d,%d\t%n", &sc_data->data[i].type, &sc_data->data[i].tick, - &sc_data->data[i].val1, &sc_data->data[i].val2, &sc_data->data[i].val3, &sc_data->data[i].val4, &len) < 6) - { - aFree(sc_data->data); - return 0; - } - next+=len; - } - return 1; -} -/*========================================== - * Loads all scdata from the given filename. - *------------------------------------------*/ -void status_load_scdata(const char* filename) -{ - FILE *fp; - int sd_count=0, sc_count=0; - char line[8192]; - struct scdata *sc; - - if ((fp = fopen(filename, "r")) == NULL) { - ShowError("status_load_scdata: Cannot open file %s!\n", filename); - return; - } - - while(fgets(line, sizeof(line), fp)) - { - sc = (struct scdata*)aCalloc(1, sizeof(struct scdata)); - if (inter_scdata_fromstr(line, sc)) { - sd_count++; - sc_count+= sc->count; - sc = (struct scdata*)idb_put(scdata_db, sc->char_id, sc); - if (sc) { - ShowError("Duplicate entry in %s for character %d\n", filename, sc->char_id); - if (sc->data) aFree(sc->data); - aFree(sc); - } - } else { - ShowError("status_load_scdata: Broken line data: %s\n", line); - aFree(sc); - } - } - fclose(fp); - ShowStatus("Loaded %d saved status changes for %d characters.\n", sc_count, sd_count); -} - -static int inter_status_save_sub(DBKey key, void *data, va_list ap) { - char line[8192]; - struct scdata * sc_data; - FILE *fp; - - sc_data = (struct scdata *)data; - if (sc_data->count < 1) - return 0; - - fp = va_arg(ap, FILE *); - inter_status_tostr(line, sc_data); - fprintf(fp, "%s\n", line); - return 0; -} - -/*========================================== - * Saves all scdata to the given filename. - *------------------------------------------*/ -void inter_status_save() -{ - FILE *fp; - int lock; - - if ((fp = lock_fopen(scdata_txt, &lock)) == NULL) { - ShowError("int_status: can't write [%s] !!! data is lost !!!\n", scdata_txt); - return; - } - scdata_db->foreach(scdata_db, inter_status_save_sub, fp); - lock_fclose(fp,scdata_txt, &lock); -} - -/*========================================== - * Initializes db. - *------------------------------------------*/ -void status_init() -{ - scdata_db = idb_alloc(DB_OPT_BASE); - status_load_scdata(scdata_txt); -} - -/*========================================== - * Frees up memory. - *------------------------------------------*/ -static int scdata_db_final(DBKey k,void *d,va_list ap) -{ - struct scdata *data = (struct scdata*)d; - if (data->data) - aFree(data->data); - aFree(data); - return 0; -} - -/*========================================== - * Final cleanup. - *------------------------------------------*/ -void status_final(void) -{ - scdata_db->destroy(scdata_db, scdata_db_final); -} - -#endif //ENABLE_SC_SAVING diff --git a/src/char/int_status.h b/src/char/int_status.h deleted file mode 100644 index 3202cd88e..000000000 --- a/src/char/int_status.h +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder - -#ifndef _INT_STATUS_H_ -#define _INT_STATUS_H_ - -struct status_change_data; - -struct scdata { - int account_id, char_id; - int count; - struct status_change_data* data; -}; - -extern char scdata_txt[1024]; - -struct scdata* status_search_scdata(int aid, int cid); -void status_delete_scdata(int aid, int cid); -void inter_status_save(void); -void status_init(void); -void status_final(void); - -#endif /* _INT_STATUS_H_ */ diff --git a/src/char/int_storage.c b/src/char/int_storage.c deleted file mode 100644 index 5ae51b833..000000000 --- a/src/char/int_storage.c +++ /dev/null @@ -1,481 +0,0 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder - -#include "../common/mmo.h" -#include "../common/malloc.h" -#include "../common/socket.h" -#include "../common/db.h" -#include "../common/lock.h" -#include "../common/showmsg.h" -#include "../common/utils.h" -#include "char.h" -#include "inter.h" -#include "int_storage.h" -#include "int_pet.h" -#include "int_guild.h" - -#include -#include -#include - -// ファイル名のデフォルト -// inter_config_read()で再設定される -char storage_txt[1024]="save/storage.txt"; -char guild_storage_txt[1024]="save/g_storage.txt"; - -#ifndef TXT_SQL_CONVERT -static DBMap* storage_db; // int account_id -> struct storage* -static DBMap* guild_storage_db; // int guild_id -> struct guild_storage* - -// 倉庫データを文字列に変換 -int storage_tostr(char *str,struct storage *p) -{ - int i,j,f=0; - char *str_p = str; - str_p += sprintf(str_p,"%d,%d\t",p->account_id,p->storage_amount); - - for(i=0;istorage_[i].nameid) && (p->storage_[i].amount) ){ - str_p += sprintf(str_p,"%d,%d,%d,%d,%d,%d,%d", - p->storage_[i].id,p->storage_[i].nameid,p->storage_[i].amount,p->storage_[i].equip, - p->storage_[i].identify,p->storage_[i].refine,p->storage_[i].attribute); - for(j=0; jstorage_[i].card[j]); - str_p += sprintf(str_p," "); - f++; - } - - *(str_p++)='\t'; - - *str_p='\0'; - if(!f) - str[0]=0; - return 0; -} -#endif //TXT_SQL_CONVERT -// 文字列を倉庫データに変換 -int storage_fromstr(char *str,struct storage *p) -{ - int tmp_int[256]; - char tmp_str[256]; - int set,next,len,i,j; - - set=sscanf(str,"%d,%d%n",&tmp_int[0],&tmp_int[1],&next); - p->storage_amount=tmp_int[1]; - - if(set!=2) - return 1; - if(str[next]=='\n' || str[next]=='\r') - return 0; - next++; - for(i=0;str[next] && str[next]!='\t' && i < MAX_STORAGE;i++){ - if(sscanf(str + next, "%d,%d,%d,%d,%d,%d,%d%[0-9,-]%n", - &tmp_int[0], &tmp_int[1], &tmp_int[2], &tmp_int[3], - &tmp_int[4], &tmp_int[5], &tmp_int[6], tmp_str, &len) == 8) { - p->storage_[i].id = tmp_int[0]; - p->storage_[i].nameid = tmp_int[1]; - p->storage_[i].amount = tmp_int[2]; - p->storage_[i].equip = tmp_int[3]; - p->storage_[i].identify = tmp_int[4]; - p->storage_[i].refine = tmp_int[5]; - p->storage_[i].attribute = tmp_int[6]; - - for(j = 0; j < MAX_SLOTS && tmp_str && sscanf(tmp_str, ",%d%[0-9,-]",&tmp_int[0], tmp_str) > 0; j++) - p->storage_[i].card[j] = tmp_int[0]; - - next += len; - if (str[next] == ' ') - next++; - } - else return 1; - } - if (i >= MAX_STORAGE && str[next] && str[next]!='\t') - ShowWarning("storage_fromstr: Found a storage line with more items than MAX_STORAGE (%d), remaining items have been discarded!\n", MAX_STORAGE); - return 0; -} -#ifndef TXT_SQL_CONVERT -int guild_storage_tostr(char *str,struct guild_storage *p) -{ - int i,j,f=0; - char *str_p = str; - str_p+=sprintf(str,"%d,%d\t",p->guild_id,p->storage_amount); - - for(i=0;istorage_[i].nameid) && (p->storage_[i].amount) ){ - str_p += sprintf(str_p,"%d,%d,%d,%d,%d,%d,%d", - p->storage_[i].id,p->storage_[i].nameid,p->storage_[i].amount,p->storage_[i].equip, - p->storage_[i].identify,p->storage_[i].refine,p->storage_[i].attribute); - for(j=0; jstorage_[i].card[j]); - str_p += sprintf(str_p," "); - f++; - } - - *(str_p++)='\t'; - - *str_p='\0'; - if(!f) - str[0]=0; - return 0; -} -#endif //TXT_SQL_CONVERT -int guild_storage_fromstr(char *str,struct guild_storage *p) -{ - int tmp_int[256]; - char tmp_str[256]; - int set,next,len,i,j; - - set=sscanf(str,"%d,%d%n",&tmp_int[0],&tmp_int[1],&next); - p->storage_amount=tmp_int[1]; - - if(set!=2) - return 1; - if(str[next]=='\n' || str[next]=='\r') - return 0; - next++; - for(i=0;str[next] && str[next]!='\t' && i < MAX_GUILD_STORAGE;i++){ - if(sscanf(str + next, "%d,%d,%d,%d,%d,%d,%d%[0-9,-]%n", - &tmp_int[0], &tmp_int[1], &tmp_int[2], &tmp_int[3], - &tmp_int[4], &tmp_int[5], &tmp_int[6], tmp_str, &len) == 8) - { - p->storage_[i].id = tmp_int[0]; - p->storage_[i].nameid = tmp_int[1]; - p->storage_[i].amount = tmp_int[2]; - p->storage_[i].equip = tmp_int[3]; - p->storage_[i].identify = tmp_int[4]; - p->storage_[i].refine = tmp_int[5]; - p->storage_[i].attribute = tmp_int[6]; - for(j = 0; j < MAX_SLOTS && tmp_str && sscanf(tmp_str, ",%d%[0-9,-]",&tmp_int[0], tmp_str) > 0; j++) - p->storage_[i].card[j] = tmp_int[0]; - next += len; - if (str[next] == ' ') - next++; - } - else return 1; - } - if (i >= MAX_GUILD_STORAGE && str[next] && str[next]!='\t') - ShowWarning("guild_storage_fromstr: Found a storage line with more items than MAX_GUILD_STORAGE (%d), remaining items have been discarded!\n", MAX_GUILD_STORAGE); - return 0; -} -#ifndef TXT_SQL_CONVERT -static void* create_storage(DBKey key, va_list args) { - struct storage *s; - s = (struct storage *) aCalloc(sizeof(struct storage), 1); - s->account_id=key.i; - return s; -} - -// アカウントから倉庫データインデックスを得る(新規倉庫追加可能) -struct storage *account2storage(int account_id) -{ - struct storage *s; - s = (struct storage*)idb_ensure(storage_db, account_id, create_storage); - return s; -} - -static void* create_guildstorage(DBKey key, va_list args) { - struct guild_storage *gs = NULL; - gs = (struct guild_storage *) aCalloc(sizeof(struct guild_storage), 1); - gs->guild_id=key.i; - return gs; -} - -struct guild_storage *guild2storage(int guild_id) -{ - struct guild_storage *gs = NULL; - if(inter_guild_search(guild_id) != NULL) - gs = (struct guild_storage*)idb_ensure(guild_storage_db, guild_id, create_guildstorage); - return gs; -} - -//--------------------------------------------------------- -// 倉庫データを読み込む -int inter_storage_init() -{ - char line[65536]; - int c=0,tmp_int; - struct storage *s; - struct guild_storage *gs; - FILE *fp; - - storage_db = idb_alloc(DB_OPT_RELEASE_DATA); - - fp=fopen(storage_txt,"r"); - if(fp==NULL){ - ShowError("can't read : %s\n",storage_txt); - return 1; - } - while(fgets(line, sizeof(line), fp)) - { - sscanf(line,"%d",&tmp_int); - s = (struct storage*)aCalloc(sizeof(struct storage), 1); - if(s==NULL){ - ShowFatalError("int_storage: out of memory!\n"); - exit(EXIT_FAILURE); - } -// memset(s,0,sizeof(struct storage)); aCalloc does this... - s->account_id=tmp_int; - if(s->account_id > 0 && storage_fromstr(line,s) == 0) { - idb_put(storage_db,s->account_id,s); - } - else{ - ShowError("int_storage: broken data [%s] line %d\n",storage_txt,c); - aFree(s); - } - c++; - } - fclose(fp); - - c = 0; - guild_storage_db = idb_alloc(DB_OPT_RELEASE_DATA); - - fp=fopen(guild_storage_txt,"r"); - if(fp==NULL){ - ShowError("can't read : %s\n",guild_storage_txt); - return 1; - } - while(fgets(line, sizeof(line), fp)) - { - sscanf(line,"%d",&tmp_int); - gs = (struct guild_storage*)aCalloc(sizeof(struct guild_storage), 1); - if(gs==NULL){ - ShowFatalError("int_storage: out of memory!\n"); - exit(EXIT_FAILURE); - } -// memset(gs,0,sizeof(struct guild_storage)); aCalloc... - gs->guild_id=tmp_int; - if(gs->guild_id > 0 && guild_storage_fromstr(line,gs) == 0) { - idb_put(guild_storage_db,gs->guild_id,gs); - } - else{ - ShowError("int_storage: broken data [%s] line %d\n",guild_storage_txt,c); - aFree(gs); - } - c++; - } - fclose(fp); - - return 0; -} - -void inter_storage_final() { - storage_db->destroy(storage_db, NULL); - guild_storage_db->destroy(guild_storage_db, NULL); - return; -} - -int inter_storage_save_sub(DBKey key,void *data,va_list ap) -{ - char line[65536]; - FILE *fp; - storage_tostr(line,(struct storage *)data); - fp=va_arg(ap,FILE *); - if(*line) - fprintf(fp,"%s\n",line); - return 0; -} -//--------------------------------------------------------- -// 倉庫データを書き込む -int inter_storage_save() -{ - FILE *fp; - int lock; - if( (fp=lock_fopen(storage_txt,&lock))==NULL ){ - ShowError("int_storage: can't write [%s] !!! data is lost !!!\n",storage_txt); - return 1; - } - storage_db->foreach(storage_db,inter_storage_save_sub,fp); - lock_fclose(fp,storage_txt,&lock); - return 0; -} - -int inter_guild_storage_save_sub(DBKey key,void *data,va_list ap) -{ - char line[65536]; - FILE *fp; - if(inter_guild_search(((struct guild_storage *)data)->guild_id) != NULL) { - guild_storage_tostr(line,(struct guild_storage *)data); - fp=va_arg(ap,FILE *); - if(*line) - fprintf(fp,"%s\n",line); - } - return 0; -} -//--------------------------------------------------------- -// 倉庫データを書き込む -int inter_guild_storage_save() -{ - FILE *fp; - int lock; - if( (fp=lock_fopen(guild_storage_txt,&lock))==NULL ){ - ShowError("int_storage: can't write [%s] !!! data is lost !!!\n",guild_storage_txt); - return 1; - } - guild_storage_db->foreach(guild_storage_db,inter_guild_storage_save_sub,fp); - lock_fclose(fp,guild_storage_txt,&lock); - return 0; -} - -// 倉庫データ削除 -int inter_storage_delete(int account_id) -{ - struct storage *s = (struct storage*)idb_get(storage_db,account_id); - if(s) { - int i; - for(i=0;istorage_amount;i++){ - if(s->storage_[i].card[0] == (short)0xff00) - inter_pet_delete( MakeDWord(s->storage_[i].card[1],s->storage_[i].card[2]) ); - } - idb_remove(storage_db,account_id); - } - return 0; -} - -// ギルド倉庫データ削除 -int inter_guild_storage_delete(int guild_id) -{ - struct guild_storage *gs = (struct guild_storage*)idb_get(guild_storage_db,guild_id); - if(gs) { - int i; - for(i=0;istorage_amount;i++){ - if(gs->storage_[i].card[0] == (short)0xff00) - inter_pet_delete( MakeDWord(gs->storage_[i].card[1],gs->storage_[i].card[2]) ); - } - idb_remove(guild_storage_db,guild_id); - } - return 0; -} - -//--------------------------------------------------------- -// map serverへの通信 - -// 倉庫データの送信 -int mapif_load_storage(int fd,int account_id) -{ - struct storage *s=account2storage(account_id); - WFIFOHEAD(fd, sizeof(struct storage)+8); - WFIFOW(fd,0)=0x3810; - WFIFOW(fd,2)=sizeof(struct storage)+8; - WFIFOL(fd,4)=account_id; - memcpy(WFIFOP(fd,8),s,sizeof(struct storage)); - WFIFOSET(fd,WFIFOW(fd,2)); - return 0; -} -// 倉庫データ保存完了送信 -int mapif_save_storage_ack(int fd,int account_id) -{ - WFIFOHEAD(fd, 7); - WFIFOW(fd,0)=0x3811; - WFIFOL(fd,2)=account_id; - WFIFOB(fd,6)=0; - WFIFOSET(fd,7); - return 0; -} - -int mapif_load_guild_storage(int fd,int account_id,int guild_id) -{ - struct guild_storage *gs=guild2storage(guild_id); - WFIFOHEAD(fd, sizeof(struct guild_storage)+12); - WFIFOW(fd,0)=0x3818; - if(gs) { - WFIFOW(fd,2)=sizeof(struct guild_storage)+12; - WFIFOL(fd,4)=account_id; - WFIFOL(fd,8)=guild_id; - memcpy(WFIFOP(fd,12),gs,sizeof(struct guild_storage)); - } - else { - WFIFOW(fd,2)=12; - WFIFOL(fd,4)=account_id; - WFIFOL(fd,8)=0; - } - WFIFOSET(fd,WFIFOW(fd,2)); - - return 0; -} -int mapif_save_guild_storage_ack(int fd,int account_id,int guild_id,int fail) -{ - WFIFOHEAD(fd, 11); - WFIFOW(fd,0)=0x3819; - WFIFOL(fd,2)=account_id; - WFIFOL(fd,6)=guild_id; - WFIFOB(fd,10)=fail; - WFIFOSET(fd,11); - return 0; -} - -//--------------------------------------------------------- -// map serverからの通信 - -// 倉庫データ要求受信 -int mapif_parse_LoadStorage(int fd) -{ - RFIFOHEAD(fd); - mapif_load_storage(fd,RFIFOL(fd,2)); - return 0; -} -// 倉庫データ受信&保存 -int mapif_parse_SaveStorage(int fd) -{ - struct storage *s; - int account_id, len; - RFIFOHEAD(fd); - account_id=RFIFOL(fd,4); - len=RFIFOW(fd,2); - if(sizeof(struct storage)!=len-8){ - ShowError("inter storage: data size error %d %d\n",sizeof(struct storage),len-8); - } - else { - s=account2storage(account_id); - memcpy(s,RFIFOP(fd,8),sizeof(struct storage)); - mapif_save_storage_ack(fd,account_id); - } - return 0; -} - -int mapif_parse_LoadGuildStorage(int fd) -{ - RFIFOHEAD(fd); - mapif_load_guild_storage(fd,RFIFOL(fd,2),RFIFOL(fd,6)); - return 0; -} -int mapif_parse_SaveGuildStorage(int fd) -{ - struct guild_storage *gs; - int guild_id, len; - RFIFOHEAD(fd); - guild_id=RFIFOL(fd,8); - len=RFIFOW(fd,2); - if(sizeof(struct guild_storage)!=len-12){ - ShowError("inter storage: data size error %d %d\n",sizeof(struct guild_storage),len-12); - } - else { - gs=guild2storage(guild_id); - if(gs) { - memcpy(gs,RFIFOP(fd,12),sizeof(struct guild_storage)); - mapif_save_guild_storage_ack(fd,RFIFOL(fd,4),guild_id,0); - } - else - mapif_save_guild_storage_ack(fd,RFIFOL(fd,4),guild_id,1); - } - return 0; -} - -// map server からの通信 -// ・1パケットのみ解析すること -// ・パケット長データはinter.cにセットしておくこと -// ・パケット長チェックや、RFIFOSKIPは呼び出し元で行われるので行ってはならない -// ・エラーなら0(false)、そうでないなら1(true)をかえさなければならない -int inter_storage_parse_frommap(int fd) -{ - RFIFOHEAD(fd); - switch(RFIFOW(fd,0)){ - case 0x3010: mapif_parse_LoadStorage(fd); break; - case 0x3011: mapif_parse_SaveStorage(fd); break; - case 0x3018: mapif_parse_LoadGuildStorage(fd); break; - case 0x3019: mapif_parse_SaveGuildStorage(fd); break; - default: - return 0; - } - return 1; -} -#endif //TXT_SQL_CONVERT diff --git a/src/char/int_storage.h b/src/char/int_storage.h deleted file mode 100644 index dbc487c4c..000000000 --- a/src/char/int_storage.h +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder - -#ifndef _INT_STORAGE_H_ -#define _INT_STORAGE_H_ - -struct storage; -struct guild_storage; - -int inter_storage_init(void); -void inter_storage_final(void); -int inter_storage_save(void); -int inter_guild_storage_save(void); -int inter_storage_delete(int account_id); -int inter_guild_storage_delete(int guild_id); -int inter_storage_parse_frommap(int fd); - -extern char storage_txt[1024]; -extern char guild_storage_txt[1024]; - -//Exported for use in the TXT-SQL converter. -int storage_fromstr(char *str,struct storage *p); -int guild_storage_fromstr(char *str,struct guild_storage *p); - -#endif /* _INT_STORAGE_H_ */ diff --git a/src/char/inter.c b/src/char/inter.c deleted file mode 100644 index c987ce8f2..000000000 --- a/src/char/inter.c +++ /dev/null @@ -1,711 +0,0 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder - -#include "../common/db.h" -#include "../common/mmo.h" -#include "../common/socket.h" -#include "../common/timer.h" -#include "../common/malloc.h" -#include "../common/lock.h" -#include "../common/showmsg.h" -#include "../common/strlib.h" -#include "char.h" -#include "inter.h" -#include "int_party.h" -#include "int_guild.h" -#include "int_status.h" -#include "int_storage.h" -#include "int_pet.h" -#include "int_homun.h" - -#include -#include -#include - -#define WISDATA_TTL (60*1000) // Existence time of Wisp/page data (60 seconds) - // that is the waiting time of answers of all map-servers -#define WISDELLIST_MAX 256 // Number of elements of Wisp/page data deletion list - -char accreg_txt[1024] = "save/accreg.txt"; -#ifndef TXT_SQL_CONVERT -char inter_log_filename[1024] = "log/inter.log"; -char main_chat_nick[16] = "Main"; - -static DBMap* accreg_db = NULL; // int account_id -> struct accreg* - -unsigned int party_share_level = 10; - -// sending packet list -// NOTE: This variable ain't used at all! And it's confusing.. where do I add that the length of packet 0x2b07 is 10? x.x [Skotlex] -int inter_send_packet_length[]={ - -1,-1,27,-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3000-0x300f - -1, 7, 0, 0, 0, 0, 0, 0, -1,11, 0, 0, 0, 0, 0, 0, - 35,-1,11,15, 34,29, 7,-1, 0, 0, 0, 0, 0, 0, 0, 0, - 10,-1,15, 0, 79,19, 7,-1, 0,-1,-1,-1, 14,67,186,-1, - 9, 9,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 11,-1, 7, 3, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; -// recv. packet list -int inter_recv_packet_length[]={ - -1,-1, 7,-1, -1,13,36, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3000-0x300f - 6,-1, 0, 0, 0, 0, 0, 0, 10,-1, 0, 0, 0, 0, 0, 0, //0x3010-0x301f - -1, 6,-1,14, 14,19, 6,-1, 14,14, 0, 0, 0, 0, 0, 0, //0x3020-0x302f - -1, 6,-1,-1, 55,19, 6,-1, 14,-1,-1,-1, 14,19,186,-1, //0x3030-0x303f - 5, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3040-0x304f - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3050-0x305f - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3060-0x306f - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3070-0x307f - 48,14,-1, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3080-0x308f - -1,10,-1, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3090-0x309f Homunculus packets [albator] -}; - -struct WisData { - int id, fd, count, len; - unsigned long tick; - unsigned char src[24], dst[24], msg[1024]; -}; -static DBMap* wis_db = NULL; // int wis_id -> struct WisData* -static int wis_dellist[WISDELLIST_MAX], wis_delnum; - - -//-------------------------------------------------------- - -// アカウント変数を文字列へ変換 -int inter_accreg_tostr(char *str, struct accreg *reg) { - int j; - char *p = str; - - p += sprintf(p, "%d\t", reg->account_id); - for(j = 0; j < reg->reg_num; j++) { - p += sprintf(p,"%s,%s ", reg->reg[j].str, reg->reg[j].value); - } - - return 0; -} -#endif //TXT_SQL_CONVERT -// アカウント変数を文字列から変換 -int inter_accreg_fromstr(const char *str, struct accreg *reg) { - int j, n; - const char *p = str; - - if (sscanf(p, "%d\t%n", ®->account_id, &n ) != 1 || reg->account_id <= 0) - return 1; - - for(j = 0, p += n; j < ACCOUNT_REG_NUM; j++, p += n) { - if (sscanf(p, "%[^,],%[^ ] %n", reg->reg[j].str, reg->reg[j].value, &n) != 2) - break; - } - reg->reg_num = j; - - return 0; -} -#ifndef TXT_SQL_CONVERT -// アカウント変数の読み込み -int inter_accreg_init(void) { - char line[8192]; - FILE *fp; - int c = 0; - struct accreg *reg; - - accreg_db = idb_alloc(DB_OPT_RELEASE_DATA); - - if( (fp = fopen(accreg_txt, "r")) == NULL) - return 1; - while(fgets(line, sizeof(line), fp)) - { - reg = (struct accreg*)aCalloc(sizeof(struct accreg), 1); - if (reg == NULL) { - ShowFatalError("inter: accreg: out of memory!\n"); - exit(EXIT_FAILURE); - } - if (inter_accreg_fromstr(line, reg) == 0 && reg->account_id > 0) { - idb_put(accreg_db, reg->account_id, reg); - } else { - ShowError("inter: accreg: broken data [%s] line %d\n", accreg_txt, c); - aFree(reg); - } - c++; - } - fclose(fp); - - return 0; -} - -// アカウント変数のセーブ用 -int inter_accreg_save_sub(DBKey key, void *data, va_list ap) { - char line[8192]; - FILE *fp; - struct accreg *reg = (struct accreg *)data; - - if (reg->reg_num > 0) { - inter_accreg_tostr(line,reg); - fp = va_arg(ap, FILE *); - fprintf(fp, "%s\n", line); - } - - return 0; -} - -// アカウント変数のセーブ -int inter_accreg_save(void) { - FILE *fp; - int lock; - - if ((fp = lock_fopen(accreg_txt,&lock)) == NULL) { - ShowError("int_accreg: can't write [%s] !!! data is lost !!!\n", accreg_txt); - return 1; - } - accreg_db->foreach(accreg_db, inter_accreg_save_sub,fp); - lock_fclose(fp, accreg_txt, &lock); - - return 0; -} - -//-------------------------------------------------------- -#endif //TXT_SQL_CONVERT -/*========================================== - * 設定ファイルを読み込む - *------------------------------------------*/ -static int inter_config_read(const char *cfgName) { - char line[1024], w1[1024], w2[1024]; - FILE *fp; - - fp = fopen(cfgName, "r"); - if (fp == NULL) { - ShowError("file not found: %s\n", cfgName); - return 1; - } - while(fgets(line, sizeof(line), fp)) - { - if (line[0] == '/' && line[1] == '/') - continue; - - if (sscanf(line,"%[^:]: %[^\r\n]", w1, w2) != 2) - continue; - - if (strcmpi(w1, "storage_txt") == 0) { - strncpy(storage_txt, w2, sizeof(storage_txt)); - } else if (strcmpi(w1, "party_txt") == 0) { - strncpy(party_txt, w2, sizeof(party_txt)); - } else if (strcmpi(w1, "pet_txt") == 0) { - strncpy(pet_txt, w2, sizeof(pet_txt)); - } else if (strcmpi(w1, "accreg_txt") == 0) { - strncpy(accreg_txt, w2, sizeof(accreg_txt)); - } else if (strcmpi(w1, "guild_txt") == 0) { - strncpy(guild_txt, w2, sizeof(guild_txt)); - } else if (strcmpi(w1, "castle_txt") == 0) { - strncpy(castle_txt, w2, sizeof(castle_txt)); - } else if (strcmpi(w1, "guild_storage_txt") == 0) { - strncpy(guild_storage_txt, w2, sizeof(guild_storage_txt)); -#ifndef TXT_SQL_CONVERT - } else if (strcmpi(w1, "homun_txt") == 0) { - strncpy(homun_txt, w2, sizeof(homun_txt)); - } else if (strcmpi(w1, "party_share_level") == 0) { - party_share_level = (unsigned int)atof(w2); - } else if (strcmpi(w1, "inter_log_filename") == 0) { - strncpy(inter_log_filename, w2, sizeof(inter_log_filename)); - } else if(strcmpi(w1,"log_inter")==0) { - log_inter = atoi(w2); - } else if(strcmpi(w1, "main_chat_nick")==0){ // Main chat nick [LuzZza] - strcpy(main_chat_nick, w2); -#endif //TXT_SQL_CONVERT - } else if (strcmpi(w1, "import") == 0) { - inter_config_read(w2); - } - } - fclose(fp); - - return 0; -} -#ifndef TXT_SQL_CONVERT -// ログ書き出し -int inter_log(char *fmt,...) { - FILE *logfp; - va_list ap; - - va_start(ap,fmt); - logfp = fopen(inter_log_filename, "a"); - if (logfp) { - vfprintf(logfp, fmt, ap); - fclose(logfp); - } - va_end(ap); - - return 0; -} - -// セーブ -int inter_save(void) { -#ifdef ENABLE_SC_SAVING - inter_status_save(); -#endif - inter_party_save(); - inter_guild_save(); - inter_storage_save(); - inter_guild_storage_save(); - inter_pet_save(); - inter_homun_save(); - inter_accreg_save(); - - return 0; -} -#endif //TXT_SQL_CONVERT -// 初期化 -int inter_init_txt(const char *file) { - inter_config_read(file); - -#ifndef TXT_SQL_CONVERT - wis_db = idb_alloc(DB_OPT_RELEASE_DATA); - - inter_party_init(); - inter_guild_init(); - inter_storage_init(); - inter_pet_init(); - inter_homun_init(); - inter_accreg_init(); -#endif //TXT_SQL_CONVERT - return 0; -} -#ifndef TXT_SQL_CONVERT -// finalize -void inter_final(void) { - accreg_db->destroy(accreg_db, NULL); - wis_db->destroy(wis_db, NULL); - - inter_party_final(); - inter_guild_final(); - inter_storage_final(); - inter_pet_final(); - inter_homun_final(); - - return; -} - -// マップサーバー接続 -int inter_mapif_init(int fd) { - inter_guild_mapif_init(fd); - - return 0; -} - -//-------------------------------------------------------- -// sended packets to map-server - -// GMメッセージ送信 -int mapif_GMmessage(unsigned char *mes, int len, unsigned long color, int sfd) { - unsigned char buf[2048]; - - if (len > 2048) len = 2047; //Make it fit to avoid crashes. [Skotlex] - WBUFW(buf,0) = 0x3800; - WBUFW(buf,2) = len; - WBUFL(buf,4) = color; - memcpy(WBUFP(buf,8), mes, len - 8); - mapif_sendallwos(sfd, buf, len); - - return 0; -} - -// Wisp/page transmission to one map-server -int mapif_wis_message2(struct WisData *wd, int fd) { - WFIFOHEAD(fd, 56+wd->len); - WFIFOW(fd, 0) = 0x3801; - WFIFOW(fd, 2) = 56 + wd->len; - WFIFOL(fd, 4) = wd->id; - memcpy(WFIFOP(fd, 8), wd->src, NAME_LENGTH); - memcpy(WFIFOP(fd,32), wd->dst, NAME_LENGTH); - memcpy(WFIFOP(fd,56), wd->msg, wd->len); - wd->count = 1; - WFIFOSET(fd,WFIFOW(fd,2)); - return 1; -} - -// Wisp/page transmission to all map-server -int mapif_wis_message(struct WisData *wd) { - unsigned char buf[2048]; - if (wd->len > 2047-56) wd->len = 2047-56; //Force it to fit to avoid crashes. [Skotlex] - - WBUFW(buf, 0) = 0x3801; - WBUFW(buf, 2) = 56 + wd->len; - WBUFL(buf, 4) = wd->id; - memcpy(WBUFP(buf, 8), wd->src, NAME_LENGTH); - memcpy(WBUFP(buf,32), wd->dst, NAME_LENGTH); - memcpy(WBUFP(buf,56), wd->msg, wd->len); - wd->count = mapif_sendall(buf, WBUFW(buf,2)); - - return 0; -} - -int mapif_wis_fail(int fd, char *src) { - unsigned char buf[27]; - WBUFW(buf, 0) = 0x3802; - memcpy(WBUFP(buf, 2), src, NAME_LENGTH); - WBUFB(buf,26) = 1; // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target - mapif_send(fd, buf, 27); - return 0; - -} - -// Wisp/page transmission result to map-server -int mapif_wis_end(struct WisData *wd, int flag) -{ - unsigned char buf[27]; - - WBUFW(buf, 0) = 0x3802; - memcpy(WBUFP(buf, 2), wd->src, 24); - WBUFB(buf,26) = flag; // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target - mapif_send(wd->fd, buf, 27); - - return 0; -} - -// Account registry transfer to map-server -static void mapif_account_reg(int fd, unsigned char *src) -{ - WBUFW(src,0)=0x3804; //NOTE: writing to RFIFO - mapif_sendallwos(fd, src, WBUFW(src,2)); -} - -// アカウント変数要求返信 -int mapif_account_reg_reply(int fd,int account_id, int char_id) -{ - struct accreg *reg = (struct accreg*)idb_get(accreg_db,account_id); - - WFIFOHEAD(fd, ACCOUNT_REG_NUM * 288+ 13); - WFIFOW(fd,0) = 0x3804; - WFIFOL(fd,4) = account_id; - WFIFOL(fd,8) = char_id; - WFIFOB(fd,12) = 2; //Acc Reg - if (reg == NULL) { - WFIFOW(fd,2) = 13; - } else { - int i, p; - for (p=13,i = 0; i < reg->reg_num; i++) { - p+= sprintf((char*)WFIFOP(fd,p), "%s", reg->reg[i].str)+1; //We add 1 to consider the '\0' in place. - p+= sprintf((char*)WFIFOP(fd,p), "%s", reg->reg[i].value)+1; - } - WFIFOW(fd,2)=p; - } - WFIFOSET(fd,WFIFOW(fd,2)); - return 0; -} - -//Request to kick char from a certain map server. [Skotlex] -int mapif_disconnectplayer(int fd, int account_id, int char_id, int reason) -{ - if (fd < 0) - return -1; - - WFIFOHEAD(fd, 7); - WFIFOW(fd,0) = 0x2b1f; - WFIFOL(fd,2) = account_id; - WFIFOB(fd,6) = reason; - WFIFOSET(fd,7); - - return 0; -} - -//-------------------------------------------------------- - -// Existence check of WISP data -int check_ttl_wisdata_sub(DBKey key, void *data, va_list ap) { - unsigned long tick; - struct WisData *wd = (struct WisData *)data; - tick = va_arg(ap, unsigned long); - - if (DIFF_TICK(tick, wd->tick) > WISDATA_TTL && wis_delnum < WISDELLIST_MAX) - wis_dellist[wis_delnum++] = wd->id; - - return 0; -} - -int check_ttl_wisdata(void) { - unsigned long tick = gettick(); - int i; - - do { - wis_delnum = 0; - wis_db->foreach(wis_db, check_ttl_wisdata_sub, tick); - for(i = 0; i < wis_delnum; i++) { - struct WisData *wd = (struct WisData*)idb_get(wis_db, wis_dellist[i]); - ShowWarning("inter: wis data id=%d time out : from %s to %s\n", wd->id, wd->src, wd->dst); - // removed. not send information after a timeout. Just no answer for the player - //mapif_wis_end(wd, 1); // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target - idb_remove(wis_db, wd->id); - } - } while(wis_delnum >= WISDELLIST_MAX); - - return 0; -} - -//-------------------------------------------------------- -// received packets from map-server - -// GMメッセージ送信 -int mapif_parse_GMmessage(int fd) { - RFIFOHEAD(fd); - mapif_GMmessage(RFIFOP(fd,8), RFIFOW(fd,2), RFIFOL(fd,4), fd); - - return 0; -} - -static struct WisData* mapif_create_whisper(int fd, char* src, char* dst, char* mes, int meslen) -{ - static int wisid = 0; - struct WisData* wd = (struct WisData *)aCalloc(sizeof(struct WisData), 1); - if (wd == NULL){ - ShowFatalError("inter: WisRequest: out of memory !\n"); - return NULL; - } - wd->id = ++wisid; - wd->fd = fd; - wd->len= meslen; - memcpy(wd->src, src, NAME_LENGTH); - memcpy(wd->dst, dst, NAME_LENGTH); - memcpy(wd->msg, mes, meslen); - wd->tick = gettick(); - return wd; -} - -// Wisp/page request to send -int mapif_parse_WisRequest(int fd) -{ - struct mmo_charstatus* char_status; - struct WisData* wd; - char name[NAME_LENGTH]; - int fd2; - - if (RFIFOW(fd,2)-52 >= sizeof(wd->msg)) { - ShowWarning("inter: Wis message size too long.\n"); - return 0; - } else if (RFIFOW(fd,2)-52 <= 0) { // normaly, impossible, but who knows... - ShowError("inter: Wis message doesn't exist.\n"); - return 0; - } - - safestrncpy(name, (char*)RFIFOP(fd,28), NAME_LENGTH); //Received name may be too large and not contain \0! [Skotlex] - - // search if character exists before to ask all map-servers - char_status = search_character_byname(name); - if (char_status == NULL) - return mapif_wis_fail(fd, (char*)RFIFOP(fd, 4)); - - // Character exists. - // to be sure of the correct name, rewrite it - memset(name, 0, NAME_LENGTH); - strncpy(name, char_status->name, NAME_LENGTH); - // if source is destination, don't ask other servers. - if (strcmp((char*)RFIFOP(fd,4),name) == 0) - return mapif_wis_fail(fd, (char*)RFIFOP(fd, 4)); - - //Look for online character. - fd2 = search_character_online(char_status->account_id, char_status->char_id); - if (fd2 >= 0) { //Character online, send whisper. - wd = mapif_create_whisper(fd, (char*)RFIFOP(fd, 4), (char*)RFIFOP(fd,28), (char*)RFIFOP(fd,52), RFIFOW(fd,2)-52); - if (!wd) return 1; - idb_put(wis_db, wd->id, wd); - mapif_wis_message2(wd, fd2); - return 0; - } - //Not found. - return mapif_wis_fail(fd, (char*)RFIFOP(fd,4)); -} - -// Wisp/page transmission result -int mapif_parse_WisReply(int fd) { - int id, flag; - struct WisData *wd; - RFIFOHEAD(fd); - id = RFIFOL(fd,2); - flag = RFIFOB(fd,6); - wd = (struct WisData*)idb_get(wis_db, id); - - if (wd == NULL) - return 0; // This wisp was probably suppress before, because it was timeout or because of target was found on another map-server - - if ((--wd->count) <= 0 || flag != 1) { - mapif_wis_end(wd, flag); // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target - idb_remove(wis_db, id); - } - - return 0; -} - -// Received wisp message from map-server for ALL gm (just copy the message and resends it to ALL map-servers) -int mapif_parse_WisToGM(int fd) { - unsigned char buf[2048]; // 0x3003/0x3803 .w .24B .w .?B - - ShowDebug("Sent packet back!\n"); - memcpy(WBUFP(buf,0), RFIFOP(fd,0), RFIFOW(fd,2)); - WBUFW(buf, 0) = 0x3803; - mapif_sendall(buf, RFIFOW(fd,2)); - - return 0; -} - -static void* create_accreg(DBKey key, va_list args) { - struct accreg *reg; - reg = (struct accreg*)aCalloc(sizeof(struct accreg), 1); - reg->account_id = key.i; - return reg; -} - -// アカウント変数保存要求 -int mapif_parse_Registry(int fd) { - int j, p, len; - struct accreg *reg; - RFIFOHEAD(fd); - - switch (RFIFOB(fd,12)) { - case 3: //Character registry - return char_parse_Registry(RFIFOL(fd,4), RFIFOL(fd,8), RFIFOP(fd,13), RFIFOW(fd,2)-13); - case 2: //Acc Reg - break; - case 1: //Acc Reg2, forward to login - return save_accreg2(RFIFOP(fd,4), RFIFOW(fd,2)-4); - default: //Error? - return 1; - } - reg = (struct accreg*)idb_ensure(accreg_db, RFIFOL(fd,4), create_accreg); - - for(j=0,p=13;jreg[j].str,&len); - reg->reg[j].str[len]='\0'; - p +=len+1; //+1 to skip the '\0' between strings. - sscanf((char*)RFIFOP(fd,p), "%255c%n",reg->reg[j].value,&len); - reg->reg[j].value[len]='\0'; - p +=len+1; - } - reg->reg_num=j; - mapif_account_reg(fd, RFIFOP(fd,0)); // 他のMAPサーバーに送信 - - return 0; -} - -// Request the value of all registries. -int mapif_parse_RegistryRequest(int fd) -{ - RFIFOHEAD(fd); - //Load Char Registry - if (RFIFOB(fd,12)) - char_account_reg_reply(fd,RFIFOL(fd,2),RFIFOL(fd,6)); - //Load Account Registry - if (RFIFOB(fd,11)) - mapif_account_reg_reply(fd,RFIFOL(fd,2),RFIFOL(fd,6)); - //Ask Login Server for Account2 values. - if (RFIFOB(fd,10)) - request_accreg2(RFIFOL(fd,2),RFIFOL(fd,6)); - return 1; -} - -static void mapif_namechange_ack(int fd, int account_id, int char_id, int type, int flag, char *name){ - WFIFOHEAD(fd, NAME_LENGTH+13); - WFIFOW(fd, 0) =0x3806; - WFIFOL(fd, 2) =account_id; - WFIFOL(fd, 6) =char_id; - WFIFOB(fd,10) =type; - WFIFOB(fd,11) =flag; - memcpy(WFIFOP(fd, 12), name, NAME_LENGTH); - WFIFOSET(fd, NAME_LENGTH+13); -} - -int mapif_parse_NameChangeRequest(int fd) -{ - int account_id, char_id, type; - char* name; - int i; - - RFIFOHEAD(fd); - account_id = RFIFOL(fd, 2); - char_id = RFIFOL(fd, 6); - type = RFIFOB(fd, 10); - name = (char*)RFIFOP(fd, 11); - - // Check Authorised letters/symbols in the name - if (char_name_option == 1) { // only letters/symbols in char_name_letters are authorised - for (i = 0; i < NAME_LENGTH && name[i]; i++) - if (strchr(char_name_letters, name[i]) == NULL) { - mapif_namechange_ack(fd, account_id, char_id, type, 0, name); - return 0; - } - } else if (char_name_option == 2) { // letters/symbols in char_name_letters are forbidden - for (i = 0; i < NAME_LENGTH && name[i]; i++) - if (strchr(char_name_letters, name[i]) != NULL) { - mapif_namechange_ack(fd, account_id, char_id, type, 0, name); - return 0; - } - } - //TODO: type holds the type of object to rename. - //If it were a player, it needs to have the guild information and db information - //updated here, because changing it on the map won't make it be saved [Skotlex] - - //name allowed. - mapif_namechange_ack(fd, account_id, char_id, type, 1, name); - return 0; -} - -//-------------------------------------------------------- - -// map server からの通信(1パケットのみ解析すること) -// エラーなら0(false)、処理できたなら1、 -// パケット長が足りなければ2をかえさなければならない -int inter_parse_frommap(int fd) { - int cmd, len; - RFIFOHEAD(fd); - cmd = RFIFOW(fd,0); - len = 0; - - // inter鯖管轄かを調べる - if (cmd < 0x3000 || cmd >= 0x3000 + ARRAYLENGTH(inter_recv_packet_length)) - return 0; - - if (inter_recv_packet_length[cmd-0x3000] == 0) //This is necessary, because otherwise we return 2 and the char server will just hang waiting for packets! [Skotlex] - return 0; - - // パケット長を調べる - if ((len = inter_check_length(fd, inter_recv_packet_length[cmd - 0x3000])) == 0) - return 2; - - switch(cmd) { - case 0x3000: mapif_parse_GMmessage(fd); break; - case 0x3001: mapif_parse_WisRequest(fd); break; - case 0x3002: mapif_parse_WisReply(fd); break; - case 0x3003: mapif_parse_WisToGM(fd); break; - case 0x3004: mapif_parse_Registry(fd); break; - case 0x3005: mapif_parse_RegistryRequest(fd); break; - case 0x3006: mapif_parse_NameChangeRequest(fd); break; - default: - if (inter_party_parse_frommap(fd)) - break; - if (inter_guild_parse_frommap(fd)) - break; - if (inter_storage_parse_frommap(fd)) - break; - if (inter_pet_parse_frommap(fd)) - break; - if (inter_homun_parse_frommap(fd)) - break; - return 0; - } - RFIFOSKIP(fd, len); - return 1; -} - -// RFIFOのパケット長確認 -// 必要パケット長があればパケット長、まだ足りなければ0 -int inter_check_length(int fd, int length) { - if (length == -1) { // 可変パケット長 - RFIFOHEAD(fd); - if (RFIFOREST(fd) < 4) // パケット長が未着 - return 0; - length = RFIFOW(fd,2); - } - - if ((int)RFIFOREST(fd) < length) // パケットが未着 - return 0; - - return length; -} -#endif //TXT_SQL_CONVERT diff --git a/src/char/inter.h b/src/char/inter.h deleted file mode 100644 index 4752f600c..000000000 --- a/src/char/inter.h +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder - -#ifndef _INTER_H_ -#define _INTER_H_ - -struct accreg; - -int inter_init_txt(const char *file); -void inter_final(void); -int inter_save(void); -int inter_parse_frommap(int fd); -int inter_mapif_init(int fd); -int mapif_disconnectplayer(int fd, int account_id, int char_id, int reason); - -int inter_check_length(int fd,int length); - -int inter_log(char *fmt,...); - -#define inter_cfgName "conf/inter_athena.conf" - -extern unsigned int party_share_level; -extern char inter_log_filename[1024]; -extern char main_chat_nick[16]; - -//For TXT->SQL conversion -extern char accreg_txt[]; -int inter_accreg_fromstr(const char *str, struct accreg *reg); - -#endif /* _INTER_H_ */ diff --git a/src/login/Makefile.in b/src/login/Makefile.in deleted file mode 100644 index aeb41b667..000000000 --- a/src/login/Makefile.in +++ /dev/null @@ -1,46 +0,0 @@ - -COMMON_OBJ = ../common/obj_all/core.o ../common/obj_all/socket.o ../common/obj_all/timer.o \ - ../common/obj_all/db.o ../common/obj_all/plugins.o ../common/obj_all/lock.o \ - ../common/obj_all/malloc.o ../common/obj_all/showmsg.o ../common/obj_all/utils.o \ - ../common/obj_all/strlib.o ../common/obj_all/grfio.o ../common/obj_all/mapindex.o \ - ../common/obj_all/ers.o ../common/obj_all/md5calc.o -COMMON_H = ../common/core.h ../common/socket.h ../common/timer.h ../common/mmo.h \ - ../common/version.h ../common/db.h ../common/plugins.h ../common/lock.h \ - ../common/malloc.h ../common/showmsg.h ../common/utils.h ../common/strlib.h \ - ../common/grfio.h ../common/mapindex.h \ - ../common/ers.h ../common/md5calc.h - -LOGIN_OBJ = obj_txt/login.o obj_txt/admin.o -LOGIN_H = login.h - -@SET_MAKE@ - -##################################################################### -.PHONY : all login-server clean help - -all: login-server - -login-server: obj_txt $(LOGIN_OBJ) $(COMMON_OBJ) - @CC@ @LDFLAGS@ -o ../../login-server@EXEEXT@ $(LOGIN_OBJ) $(COMMON_OBJ) @LIBS@ - -clean: - rm -rf *.o obj_txt ../../login-server@EXEEXT@ - -help: - @echo "possible targets are 'login-server' 'all' 'clean' 'help'" - @echo "'login-server' - login server (TXT version)" - @echo "'all' - builds all above targets" - @echo "'clean' - cleans builds and objects" - @echo "'help' - outputs this message" - -##################################################################### - -obj_txt: - -mkdir obj_txt - -obj_txt/%.o: %.c $(LOGIN_H) $(COMMON_H) - @CC@ @CFLAGS@ $(CUSTOM_CFLAGS) -DTXT_ONLY @CPPFLAGS@ -c $(OUTPUT_OPTION) $< - -# missing common object files -../common/obj_all/%.o: - @$(MAKE) -C ../common sql diff --git a/src/login/admin.c b/src/login/admin.c deleted file mode 100644 index 9bce1a02f..000000000 --- a/src/login/admin.c +++ /dev/null @@ -1,879 +0,0 @@ -#include "../common/cbasetypes.h" -#include "../common/mmo.h" -#include "../common/core.h" -#include "../common/socket.h" -#include "../common/db.h" -#include "../common/timer.h" -#include "../common/malloc.h" -#include "../common/strlib.h" -#include "../common/showmsg.h" -#include "../common/version.h" -#include "../common/md5calc.h" -#include "../common/lock.h" -#include "login.h" - -#include -#include -#include -#include // for stat/lstat/fstat - -extern struct Login_Config login_config; - -#define MAX_SERVERS 30 -extern struct mmo_char_server server[MAX_SERVERS]; -extern struct mmo_account* auth_dat; -extern uint32 auth_num; -extern int account_id_count; -extern char GM_account_filename[1024]; - -int charif_sendallwos(int sfd, unsigned char *buf, unsigned int len); -int search_account_index(char* account_name); -int mmo_auth_new(struct mmo_account* account); -void mmo_auth_sync(void); -int mmo_auth_tostr(char* str, struct mmo_account* p); -int read_gm_account(void); -void send_GM_accounts(int fd); -int isGM(int account_id); - -//--------------------------------------- -// Packet parsing for administation login -//--------------------------------------- -int parse_admin(int fd) -{ - unsigned int i, j; - char* account_name; - - uint32 ipl = session[fd]->client_addr; - char ip[16]; - ip2str(ipl, ip); - - if( session[fd]->flag.eof ) - { - do_close(fd); - ShowInfo("Remote administration has disconnected (session #%d).\n", fd); - return 0; - } - - while( RFIFOREST(fd) >= 2 ) - { - uint16 command = RFIFOW(fd,0); - - switch( command ) - { - - case 0x7530: // Request of the server version - ShowStatus("'ladmin': Sending of the server version (ip: %s)\n", ip); - WFIFOHEAD(fd,10); - WFIFOW(fd,0) = 0x7531; - WFIFOB(fd,2) = ATHENA_MAJOR_VERSION; - WFIFOB(fd,3) = ATHENA_MINOR_VERSION; - WFIFOB(fd,4) = ATHENA_REVISION; - WFIFOB(fd,5) = ATHENA_RELEASE_FLAG; - WFIFOB(fd,6) = ATHENA_OFFICIAL_FLAG; - WFIFOB(fd,7) = ATHENA_SERVER_LOGIN; - WFIFOW(fd,8) = ATHENA_MOD_VERSION; - WFIFOSET(fd,10); - RFIFOSKIP(fd,2); - break; - - case 0x7920: // Request of an accounts list - if (RFIFOREST(fd) < 10) - return 0; - { - int st, ed; - uint16 len; - CREATE_BUFFER(id, int, auth_num); - st = RFIFOL(fd,2); - ed = RFIFOL(fd,6); - RFIFOSKIP(fd,10); - WFIFOW(fd,0) = 0x7921; - if (st < 0) - st = 0; - if (ed > END_ACCOUNT_NUM || ed < st || ed <= 0) - ed = END_ACCOUNT_NUM; - ShowStatus("'ladmin': Sending an accounts list (ask: from %d to %d, ip: %s)\n", st, ed, ip); - // Sort before send - for(i = 0; i < auth_num; i++) { - unsigned int k; - id[i] = i; - for(j = 0; j < i; j++) { - if (auth_dat[id[i]].account_id < auth_dat[id[j]].account_id) { - for(k = i; k > j; k--) { - id[k] = id[k-1]; - } - id[j] = i; // id[i] - break; - } - } - } - // Sending accounts information - len = 4; - for(i = 0; i < auth_num && len < 30000; i++) { - int account_id = auth_dat[id[i]].account_id; // use sorted index - if (account_id >= st && account_id <= ed) { - j = id[i]; - WFIFOL(fd,len) = account_id; - WFIFOB(fd,len+4) = (unsigned char)isGM(account_id); - memcpy(WFIFOP(fd,len+5), auth_dat[j].userid, 24); - WFIFOB(fd,len+29) = auth_dat[j].sex; - WFIFOL(fd,len+30) = auth_dat[j].logincount; - if (auth_dat[j].state == 0 && auth_dat[j].unban_time != 0) // if no state and banished - WFIFOL(fd,len+34) = 7; // 6 = Your are Prohibited to log in until %s - else - WFIFOL(fd,len+34) = auth_dat[j].state; - len += 38; - } - } - WFIFOW(fd,2) = len; - WFIFOSET(fd,len); - //if (id) free(id); - DELETE_BUFFER(id); - } - break; - - case 0x7930: // Request for an account creation - if (RFIFOREST(fd) < 91) - return 0; - { - struct mmo_account ma; - safestrncpy(ma.userid, (char*)RFIFOP(fd, 2), NAME_LENGTH); - safestrncpy(ma.pass, (char*)RFIFOP(fd,26), NAME_LENGTH); - safestrncpy(ma.email, (char*)RFIFOP(fd,51), 40); - memcpy(ma.lastlogin, "-", 2); - ma.sex = RFIFOB(fd,50); - RFIFOSKIP(fd,91); - - WFIFOW(fd,0) = 0x7931; - WFIFOL(fd,2) = 0xffffffff; // invalid account id - safestrncpy((char*)WFIFOP(fd,6), ma.userid, 24); - if (strlen(ma.userid) < 4 || strlen(ma.pass) < 4) { - ShowNotice("'ladmin': Attempt to create an invalid account (account or pass is too short, ip: %s)\n", ip); - } else if (ma.sex != 'F' && ma.sex != 'M') { - ShowNotice("'ladmin': Attempt to create an invalid account (account: %s, received pass: %s, invalid sex, ip: %s)\n", ma.userid, ma.pass, ip); - } else if (account_id_count > END_ACCOUNT_NUM) { - ShowNotice("'ladmin': Attempt to create an account, but there is no more available id number (account: %s, pass: %s, sex: %c, ip: %s)\n", ma.userid, ma.pass, ma.sex, ip); - } else { - remove_control_chars(ma.userid); - remove_control_chars(ma.pass); - remove_control_chars(ma.email); - ARR_FIND( 0, auth_num, i, strncmp(auth_dat[i].userid, ma.userid, 24) == 0 ); - if( i < auth_num ) - ShowNotice("'ladmin': Attempt to create an already existing account (account: %s, pass: %s, received pass: %s, ip: %s)\n", auth_dat[i].userid, auth_dat[i].pass, ma.pass, ip); - else - { - int new_id; - new_id = mmo_auth_new(&ma); - ShowNotice("'ladmin': Account creation (account: %s (id: %d), pass: %s, sex: %c, email: %s, ip: %s)\n", ma.userid, new_id, ma.pass, ma.sex, auth_dat[i].email, ip); - WFIFOL(fd,2) = new_id; - mmo_auth_sync(); - } - } - WFIFOSET(fd,30); - } - break; - - case 0x7932: // Request for an account deletion - if (RFIFOREST(fd) < 26) - return 0; - WFIFOW(fd,0) = 0x7933; - WFIFOL(fd,2) = 0xFFFFFFFF; - account_name = (char*)RFIFOP(fd,2); - account_name[23] = '\0'; - remove_control_chars(account_name); - i = search_account_index(account_name); - if (i != -1) { - // Char-server is notified of deletion (for characters deletion). - unsigned char buf[65535]; - WBUFW(buf,0) = 0x2730; - WBUFL(buf,2) = auth_dat[i].account_id; - charif_sendallwos(-1, buf, 6); - // send answer - memcpy(WFIFOP(fd,6), auth_dat[i].userid, 24); - WFIFOL(fd,2) = auth_dat[i].account_id; - // save deleted account in log file - ShowNotice("'ladmin': Account deletion (account: %s, id: %d, ip: %s) - saved in next line:\n", auth_dat[i].userid, auth_dat[i].account_id, ip); - mmo_auth_tostr((char*)buf, &auth_dat[i]); - ShowNotice("%s\n", buf); - // delete account - memset(auth_dat[i].userid, '\0', sizeof(auth_dat[i].userid)); - auth_dat[i].account_id = -1; - mmo_auth_sync(); - } else { - memcpy(WFIFOP(fd,6), account_name, 24); - ShowNotice("'ladmin': Attempt to delete an unknown account (account: %s, ip: %s)\n", account_name, ip); - } - WFIFOSET(fd,30); - RFIFOSKIP(fd,26); - break; - - case 0x7934: // Request to change a password - if (RFIFOREST(fd) < 50) - return 0; - WFIFOW(fd,0) = 0x7935; - WFIFOL(fd,2) = 0xFFFFFFFF; /// WTF??? an unsigned being set to a -1 - account_name = (char*)RFIFOP(fd,2); - account_name[23] = '\0'; - remove_control_chars(account_name); - i = search_account_index(account_name); - if (i != -1) { - memcpy(WFIFOP(fd,6), auth_dat[i].userid, 24); - memcpy(auth_dat[i].pass, RFIFOP(fd,26), 24); - auth_dat[i].pass[23] = '\0'; - remove_control_chars(auth_dat[i].pass); - WFIFOL(fd,2) = auth_dat[i].account_id; - ShowNotice("'ladmin': Modification of a password (account: %s, new password: %s, ip: %s)\n", auth_dat[i].userid, auth_dat[i].pass, ip); - mmo_auth_sync(); - } else { - memcpy(WFIFOP(fd,6), account_name, 24); - ShowNotice("'ladmin': Attempt to modify the password of an unknown account (account: %s, ip: %s)\n", account_name, ip); - } - WFIFOSET(fd,30); - RFIFOSKIP(fd,50); - break; - - case 0x7936: // Request to modify a state - if (RFIFOREST(fd) < 50) - return 0; - { - char error_message[20]; - uint32 statut; - WFIFOW(fd,0) = 0x7937; - WFIFOL(fd,2) = 0xFFFFFFFF; // WTF??? - account_name = (char*)RFIFOP(fd,2); - account_name[23] = '\0'; - remove_control_chars(account_name); - statut = RFIFOL(fd,26); - memcpy(error_message, RFIFOP(fd,30), 20); - error_message[19] = '\0'; - remove_control_chars(error_message); - if (statut != 7 || error_message[0] == '\0') { // 7: // 6 = Your are Prohibited to log in until %s - strcpy(error_message, "-"); - } - i = search_account_index(account_name); - if (i != -1) { - memcpy(WFIFOP(fd,6), auth_dat[i].userid, 24); - WFIFOL(fd,2) = auth_dat[i].account_id; - if (auth_dat[i].state == statut && strcmp(auth_dat[i].error_message, error_message) == 0) - ShowNotice("'ladmin': Modification of a state, but the state of the account is already the good state (account: %s, received state: %d, ip: %s)\n", account_name, statut, ip); - else { - if (statut == 7) - ShowNotice("'ladmin': Modification of a state (account: %s, new state: %d - prohibited to login until '%s', ip: %s)\n", auth_dat[i].userid, statut, error_message, ip); - else - ShowNotice("'ladmin': Modification of a state (account: %s, new state: %d, ip: %s)\n", auth_dat[i].userid, statut, ip); - if (auth_dat[i].state == 0) { - unsigned char buf[16]; - WBUFW(buf,0) = 0x2731; - WBUFL(buf,2) = auth_dat[i].account_id; - WBUFB(buf,6) = 0; // 0: change of statut, 1: ban - WBUFL(buf,7) = statut; // status or final date of a banishment - charif_sendallwos(-1, buf, 11); - } - auth_dat[i].state = statut; - memcpy(auth_dat[i].error_message, error_message, 20); - mmo_auth_sync(); - } - } else { - memcpy(WFIFOP(fd,6), account_name, 24); - ShowNotice("'ladmin': Attempt to modify the state of an unknown account (account: %s, received state: %d, ip: %s)\n", account_name, statut, ip); - } - WFIFOL(fd,30) = statut; - } - WFIFOSET(fd,34); - RFIFOSKIP(fd,50); - break; - - case 0x7938: // Request for servers list and # of online players - { - uint8 server_num = 0; - ShowStatus("'ladmin': Sending of servers list (ip: %s)\n", ip); - for(i = 0; i < MAX_SERVERS; i++) { - if (server[i].fd >= 0) { - WFIFOL(fd,4+server_num*32) = htonl(server[i].ip); - WFIFOW(fd,4+server_num*32+4) = htons(server[i].port); - memcpy(WFIFOP(fd,4+server_num*32+6), server[i].name, 20); - WFIFOW(fd,4+server_num*32+26) = server[i].users; - WFIFOW(fd,4+server_num*32+28) = server[i].maintenance; - WFIFOW(fd,4+server_num*32+30) = server[i].new_; - server_num++; - } - } - WFIFOW(fd,0) = 0x7939; - WFIFOW(fd,2) = 4 + 32 * server_num; - WFIFOSET(fd,4+32*server_num); - RFIFOSKIP(fd,2); - break; - } - - case 0x793a: // Request to password check - if (RFIFOREST(fd) < 50) - return 0; - WFIFOW(fd,0) = 0x793b; - WFIFOL(fd,2) = 0xFFFFFFFF; // WTF??? - account_name = (char*)RFIFOP(fd,2); - account_name[23] = '\0'; - remove_control_chars(account_name); - i = search_account_index(account_name); - if (i != -1) { - char pass[25]; - memcpy(WFIFOP(fd,6), auth_dat[i].userid, 24); - memcpy(pass, RFIFOP(fd,26), 24); - pass[24] = '\0'; - remove_control_chars(pass); - if (strcmp(auth_dat[i].pass, pass) == 0) { - WFIFOL(fd,2) = auth_dat[i].account_id; - ShowNotice("'ladmin': Check of password OK (account: %s, password: %s, ip: %s)\n", auth_dat[i].userid, auth_dat[i].pass, ip); - } else { - ShowNotice("'ladmin': Failure of password check (account: %s, proposed pass: %s, ip: %s)\n", auth_dat[i].userid, pass, ip); - } - } else { - memcpy(WFIFOP(fd,6), account_name, 24); - ShowNotice("'ladmin': Attempt to check the password of an unknown account (account: %s, ip: %s)\n", account_name, ip); - } - WFIFOSET(fd,30); - RFIFOSKIP(fd,50); - break; - - case 0x793c: // Request to modify sex - if (RFIFOREST(fd) < 27) - return 0; - WFIFOW(fd,0) = 0x793d; - WFIFOL(fd,2) = 0xFFFFFFFF; // WTF??? - account_name = (char*)RFIFOP(fd,2); - account_name[23] = '\0'; - remove_control_chars(account_name); - memcpy(WFIFOP(fd,6), account_name, 24); - { - char sex; - sex = RFIFOB(fd,26); - if (sex != 'F' && sex != 'M') { - if (sex > 31) - ShowNotice("'ladmin': Attempt to give an invalid sex (account: %s, received sex: %c, ip: %s)\n", account_name, sex, ip); - else - ShowNotice("'ladmin': Attempt to give an invalid sex (account: %s, received sex: 'control char', ip: %s)\n", account_name, ip); - } else { - i = search_account_index(account_name); - if (i != -1) { - memcpy(WFIFOP(fd,6), auth_dat[i].userid, 24); - if (auth_dat[i].sex != ((sex == 'S' || sex == 's') ? 2 : (sex == 'M' || sex == 'm'))) { - unsigned char buf[16]; - WFIFOL(fd,2) = auth_dat[i].account_id; - auth_dat[i].sex = (sex == 'S' || sex == 's') ? 2 : (sex == 'M' || sex == 'm'); - ShowNotice("'ladmin': Modification of a sex (account: %s, new sex: %c, ip: %s)\n", auth_dat[i].userid, sex, ip); - mmo_auth_sync(); - // send to all char-server the change - WBUFW(buf,0) = 0x2723; - WBUFL(buf,2) = auth_dat[i].account_id; - WBUFB(buf,6) = auth_dat[i].sex; - charif_sendallwos(-1, buf, 7); - } else { - ShowNotice("'ladmin': Modification of a sex, but the sex is already the good sex (account: %s, sex: %c, ip: %s)\n", auth_dat[i].userid, sex, ip); - } - } else { - ShowNotice("'ladmin': Attempt to modify the sex of an unknown account (account: %s, received sex: %c, ip: %s)\n", account_name, sex, ip); - } - } - } - WFIFOSET(fd,30); - RFIFOSKIP(fd,27); - break; - - case 0x793e: // Request to modify GM level - if (RFIFOREST(fd) < 27) - return 0; - WFIFOW(fd,0) = 0x793f; - WFIFOL(fd,2) = 0xFFFFFFFF; // WTF??? - account_name = (char*)RFIFOP(fd,2); - account_name[23] = '\0'; - remove_control_chars(account_name); - memcpy(WFIFOP(fd,6), account_name, 24); - { - char new_gm_level; - new_gm_level = RFIFOB(fd,26); - if (new_gm_level < 0 || new_gm_level > 99) { - ShowNotice("'ladmin': Attempt to give an invalid GM level (account: %s, received GM level: %d, ip: %s)\n", account_name, (int)new_gm_level, ip); - } else { - i = search_account_index(account_name); - if (i != -1) { - int acc = auth_dat[i].account_id; - memcpy(WFIFOP(fd,6), auth_dat[i].userid, 24); - if (isGM(acc) != new_gm_level) { - // modification of the file - FILE *fp, *fp2; - int lock; - char line[512]; - int GM_account, GM_level; - int modify_flag; - char tmpstr[24]; - time_t raw_time; - if ((fp2 = lock_fopen(GM_account_filename, &lock)) != NULL) { - if ((fp = fopen(GM_account_filename, "r")) != NULL) { - time(&raw_time); - strftime(tmpstr, 23, login_config.date_format, localtime(&raw_time)); - modify_flag = 0; - // read/write GM file - while(fgets(line, sizeof(line), fp)) - { - while(line[0] != '\0' && (line[strlen(line)-1] == '\n' || line[strlen(line)-1] == '\r')) - line[strlen(line)-1] = '\0'; // TODO: remove this - if ((line[0] == '/' && line[1] == '/') || line[0] == '\0') - fprintf(fp2, "%s\n", line); - else { - if (sscanf(line, "%d %d", &GM_account, &GM_level) != 2 && sscanf(line, "%d: %d", &GM_account, &GM_level) != 2) - fprintf(fp2, "%s\n", line); - else if (GM_account != acc) - fprintf(fp2, "%s\n", line); - else if (new_gm_level < 1) { - fprintf(fp2, "// %s: 'ladmin' GM level removed on account %d '%s' (previous level: %d)\n//%d %d\n", tmpstr, acc, auth_dat[i].userid, GM_level, acc, new_gm_level); - modify_flag = 1; - } else { - fprintf(fp2, "// %s: 'ladmin' GM level on account %d '%s' (previous level: %d)\n%d %d\n", tmpstr, acc, auth_dat[i].userid, GM_level, acc, new_gm_level); - modify_flag = 1; - } - } - } - if (modify_flag == 0) - fprintf(fp2, "// %s: 'ladmin' GM level on account %d '%s' (previous level: 0)\n%d %d\n", tmpstr, acc, auth_dat[i].userid, acc, new_gm_level); - fclose(fp); - } else { - ShowNotice("'ladmin': Attempt to modify of a GM level - impossible to read GM accounts file (account: %s (%d), received GM level: %d, ip: %s)\n", auth_dat[i].userid, acc, (int)new_gm_level, ip); - } - if (lock_fclose(fp2, GM_account_filename, &lock) == 0) { - WFIFOL(fd,2) = acc; - ShowNotice("'ladmin': Modification of a GM level (account: %s (%d), new GM level: %d, ip: %s)\n", auth_dat[i].userid, acc, (int)new_gm_level, ip); - // read and send new GM informations - read_gm_account(); - send_GM_accounts(-1); - } else { - ShowNotice("'ladmin': Attempt to modify of a GM level - impossible to write GM accounts file (account: %s (%d), received GM level: %d, ip: %s)\n", auth_dat[i].userid, acc, (int)new_gm_level, ip); - } - } else { - ShowNotice("'ladmin': Attempt to modify of a GM level - impossible to write GM accounts file (account: %s (%d), received GM level: %d, ip: %s)\n", auth_dat[i].userid, acc, (int)new_gm_level, ip); - } - } else { - ShowNotice("'ladmin': Attempt to modify of a GM level, but the GM level is already the good GM level (account: %s (%d), GM level: %d, ip: %s)\n", auth_dat[i].userid, acc, (int)new_gm_level, ip); - } - } else { - ShowNotice("'ladmin': Attempt to modify the GM level of an unknown account (account: %s, received GM level: %d, ip: %s)\n", account_name, (int)new_gm_level, ip); - } - } - } - WFIFOSET(fd,30); - RFIFOSKIP(fd,27); - break; - - case 0x7940: // Request to modify e-mail - if (RFIFOREST(fd) < 66) - return 0; - WFIFOW(fd,0) = 0x7941; - WFIFOL(fd,2) = 0xFFFFFFFF; // WTF??? - account_name = (char*)RFIFOP(fd,2); - account_name[23] = '\0'; - remove_control_chars(account_name); - memcpy(WFIFOP(fd,6), account_name, 24); - { - char email[40]; - memcpy(email, RFIFOP(fd,26), 40); - if (e_mail_check(email) == 0) { - ShowNotice("'ladmin': Attempt to give an invalid e-mail (account: %s, ip: %s)\n", account_name, ip); - } else { - remove_control_chars(email); - i = search_account_index(account_name); - if (i != -1) { - memcpy(WFIFOP(fd,6), auth_dat[i].userid, 24); - memcpy(auth_dat[i].email, email, 40); - WFIFOL(fd,2) = auth_dat[i].account_id; - ShowNotice("'ladmin': Modification of an email (account: %s, new e-mail: %s, ip: %s)\n", auth_dat[i].userid, email, ip); - mmo_auth_sync(); - } else { - ShowNotice("'ladmin': Attempt to modify the e-mail of an unknown account (account: %s, received e-mail: %s, ip: %s)\n", account_name, email, ip); - } - } - } - WFIFOSET(fd,30); - RFIFOSKIP(fd,66); - break; - - case 0x7942: // Request to modify memo field - if ((int)RFIFOREST(fd) < 28 || (int)RFIFOREST(fd) < (28 + RFIFOW(fd,26))) - return 0; - WFIFOW(fd,0) = 0x7943; - WFIFOL(fd,2) = 0xFFFFFFFF; // WTF??? - account_name = (char*)RFIFOP(fd,2); - account_name[23] = '\0'; - remove_control_chars(account_name); - i = search_account_index(account_name); - if (i != -1) { - int size_of_memo = sizeof(auth_dat[i].memo); - memcpy(WFIFOP(fd,6), auth_dat[i].userid, 24); - memset(auth_dat[i].memo, '\0', size_of_memo); - if (RFIFOW(fd,26) == 0) { - strncpy(auth_dat[i].memo, "-", size_of_memo); - } else if (RFIFOW(fd,26) > size_of_memo - 1) { - memcpy(auth_dat[i].memo, RFIFOP(fd,28), size_of_memo - 1); - } else { - memcpy(auth_dat[i].memo, RFIFOP(fd,28), RFIFOW(fd,26)); - } - auth_dat[i].memo[size_of_memo - 1] = '\0'; - remove_control_chars(auth_dat[i].memo); - WFIFOL(fd,2) = auth_dat[i].account_id; - ShowNotice("'ladmin': Modification of a memo field (account: %s, new memo: %s, ip: %s)\n", auth_dat[i].userid, auth_dat[i].memo, ip); - mmo_auth_sync(); - } else { - memcpy(WFIFOP(fd,6), account_name, 24); - ShowNotice("'ladmin': Attempt to modify the memo field of an unknown account (account: %s, ip: %s)\n", account_name, ip); - } - WFIFOSET(fd,30); - RFIFOSKIP(fd,28 + RFIFOW(fd,26)); - break; - - case 0x7944: // Request to found an account id - if (RFIFOREST(fd) < 26) - return 0; - WFIFOW(fd,0) = 0x7945; - WFIFOL(fd,2) = 0xFFFFFFFF; // WTF??? - account_name = (char*)RFIFOP(fd,2); - account_name[23] = '\0'; - remove_control_chars(account_name); - i = search_account_index(account_name); - if (i != -1) { - memcpy(WFIFOP(fd,6), auth_dat[i].userid, 24); - WFIFOL(fd,2) = auth_dat[i].account_id; - ShowNotice("'ladmin': Request (by the name) of an account id (account: %s, id: %d, ip: %s)\n", auth_dat[i].userid, auth_dat[i].account_id, ip); - } else { - memcpy(WFIFOP(fd,6), account_name, 24); - ShowNotice("'ladmin': ID request (by the name) of an unknown account (account: %s, ip: %s)\n", account_name, ip); - } - WFIFOSET(fd,30); - RFIFOSKIP(fd,26); - break; - - case 0x7946: // Request to found an account name - if (RFIFOREST(fd) < 6) - return 0; - WFIFOW(fd,0) = 0x7947; - WFIFOL(fd,2) = RFIFOL(fd,2); - memset(WFIFOP(fd,6), '\0', 24); - for(i = 0; i < auth_num; i++) { - if (auth_dat[i].account_id == (int)RFIFOL(fd,2)) { - strncpy((char*)WFIFOP(fd,6), auth_dat[i].userid, 24); - ShowNotice("'ladmin': Request (by id) of an account name (account: %s, id: %d, ip: %s)\n", auth_dat[i].userid, RFIFOL(fd,2), ip); - break; - } - } - if (i == auth_num) { - ShowNotice("'ladmin': Name request (by id) of an unknown account (id: %d, ip: %s)\n", RFIFOL(fd,2), ip); - strncpy((char*)WFIFOP(fd,6), "", 24); - } - WFIFOSET(fd,30); - RFIFOSKIP(fd,6); - break; - - case 0x7948: // Request to change the validity limit (timestamp) (absolute value) - if (RFIFOREST(fd) < 30) - return 0; - { - time_t timestamp; - char tmpstr[2048]; - WFIFOW(fd,0) = 0x7949; - WFIFOL(fd,2) = 0xFFFFFFFF; // WTF??? - account_name = (char*)RFIFOP(fd,2); - account_name[23] = '\0'; - remove_control_chars(account_name); - timestamp = (time_t)RFIFOL(fd,26); - strftime(tmpstr, 24, login_config.date_format, localtime(×tamp)); - i = search_account_index(account_name); - if (i != -1) { - memcpy(WFIFOP(fd,6), auth_dat[i].userid, 24); - ShowNotice("'ladmin': Change of a validity limit (account: %s, new validity: %d (%s), ip: %s)\n", auth_dat[i].userid, timestamp, (timestamp == 0 ? "unlimited" : tmpstr), ip); - auth_dat[i].expiration_time = timestamp; - WFIFOL(fd,2) = auth_dat[i].account_id; - mmo_auth_sync(); - } else { - memcpy(WFIFOP(fd,6), account_name, 24); - ShowNotice("'ladmin': Attempt to change the validity limit of an unknown account (account: %s, received validity: %d (%s), ip: %s)\n", account_name, timestamp, (timestamp == 0 ? "unlimited" : tmpstr), ip); - } - WFIFOL(fd,30) = (unsigned int)timestamp; - } - WFIFOSET(fd,34); - RFIFOSKIP(fd,30); - break; - - case 0x794a: // Request to change the final date of a banishment (timestamp) (absolute value) - if (RFIFOREST(fd) < 30) - return 0; - { - time_t timestamp; - char tmpstr[2048]; - WFIFOW(fd,0) = 0x794b; - WFIFOL(fd,2) = 0xFFFFFFFF; // WTF??? - account_name = (char*)RFIFOP(fd,2); - account_name[23] = '\0'; - remove_control_chars(account_name); - timestamp = (time_t)RFIFOL(fd,26); - if (timestamp <= time(NULL)) - timestamp = 0; - strftime(tmpstr, 24, login_config.date_format, localtime(×tamp)); - i = search_account_index(account_name); - if (i != -1) { - memcpy(WFIFOP(fd,6), auth_dat[i].userid, 24); - WFIFOL(fd,2) = auth_dat[i].account_id; - ShowNotice("'ladmin': Change of the final date of a banishment (account: %s, new final date of banishment: %d (%s), ip: %s)\n", auth_dat[i].userid, timestamp, (timestamp == 0 ? "no banishment" : tmpstr), ip); - if (auth_dat[i].unban_time != timestamp) { - if (timestamp != 0) { - unsigned char buf[16]; - WBUFW(buf,0) = 0x2731; - WBUFL(buf,2) = auth_dat[i].account_id; - WBUFB(buf,6) = 1; // 0: change of statut, 1: ban - WBUFL(buf,7) = (unsigned int)timestamp; // status or final date of a banishment - charif_sendallwos(-1, buf, 11); - } - auth_dat[i].unban_time = timestamp; - mmo_auth_sync(); - } - } else { - memcpy(WFIFOP(fd,6), account_name, 24); - ShowNotice("'ladmin': Attempt to change the final date of a banishment of an unknown account (account: %s, received final date of banishment: %d (%s), ip: %s)\n", account_name, timestamp, (timestamp == 0 ? "no banishment" : tmpstr), ip); - } - WFIFOL(fd,30) = (unsigned int)timestamp; - } - WFIFOSET(fd,34); - RFIFOSKIP(fd,30); - break; - - case 0x794c: // Request to change the final date of a banishment (timestamp) (relative change) - if (RFIFOREST(fd) < 38) - return 0; - { - time_t timestamp; - struct tm *tmtime; - char tmpstr[2048]; - WFIFOW(fd,0) = 0x794d; - WFIFOL(fd,2) = 0xFFFFFFFF; // WTF??? - account_name = (char*)RFIFOP(fd,2); - account_name[23] = '\0'; - remove_control_chars(account_name); - i = search_account_index(account_name); - if (i != -1) { - WFIFOL(fd,2) = auth_dat[i].account_id; - memcpy(WFIFOP(fd,6), auth_dat[i].userid, 24); - if (auth_dat[i].unban_time == 0 || auth_dat[i].unban_time < time(NULL)) - timestamp = time(NULL); - else - timestamp = auth_dat[i].unban_time; - tmtime = localtime(×tamp); - tmtime->tm_year = tmtime->tm_year + (short)RFIFOW(fd,26); - tmtime->tm_mon = tmtime->tm_mon + (short)RFIFOW(fd,28); - tmtime->tm_mday = tmtime->tm_mday + (short)RFIFOW(fd,30); - tmtime->tm_hour = tmtime->tm_hour + (short)RFIFOW(fd,32); - tmtime->tm_min = tmtime->tm_min + (short)RFIFOW(fd,34); - tmtime->tm_sec = tmtime->tm_sec + (short)RFIFOW(fd,36); - timestamp = mktime(tmtime); - if (timestamp != -1) { - if (timestamp <= time(NULL)) - timestamp = 0; - strftime(tmpstr, 24, login_config.date_format, localtime(×tamp)); - ShowNotice("'ladmin': Adjustment of a final date of a banishment (account: %s, (%+d y %+d m %+d d %+d h %+d mn %+d s) -> new validity: %d (%s), ip: %s)\n", auth_dat[i].userid, (short)RFIFOW(fd,26), (short)RFIFOW(fd,28), (short)RFIFOW(fd,30), (short)RFIFOW(fd,32), (short)RFIFOW(fd,34), (short)RFIFOW(fd,36), timestamp, (timestamp == 0 ? "no banishment" : tmpstr), ip); - if (auth_dat[i].unban_time != timestamp) { - if (timestamp != 0) { - unsigned char buf[16]; - WBUFW(buf,0) = 0x2731; - WBUFL(buf,2) = auth_dat[i].account_id; - WBUFB(buf,6) = 1; // 0: change of statut, 1: ban - WBUFL(buf,7) = (unsigned int)timestamp; // status or final date of a banishment - charif_sendallwos(-1, buf, 11); - } - auth_dat[i].unban_time = timestamp; - mmo_auth_sync(); - } - } else { - strftime(tmpstr, 24, login_config.date_format, localtime(&auth_dat[i].unban_time)); - ShowNotice("'ladmin': Impossible to adjust the final date of a banishment (account: %s, %d (%s) + (%+d y %+d m %+d d %+d h %+d mn %+d s) -> ???, ip: %s)\n", auth_dat[i].userid, auth_dat[i].unban_time, (auth_dat[i].unban_time == 0 ? "no banishment" : tmpstr), (short)RFIFOW(fd,26), (short)RFIFOW(fd,28), (short)RFIFOW(fd,30), (short)RFIFOW(fd,32), (short)RFIFOW(fd,34), (short)RFIFOW(fd,36), ip); - } - WFIFOL(fd,30) = (unsigned long)auth_dat[i].unban_time; - } else { - memcpy(WFIFOP(fd,6), account_name, 24); - ShowNotice("'ladmin': Attempt to adjust the final date of a banishment of an unknown account (account: %s, ip: %s)\n", account_name, ip); - WFIFOL(fd,30) = 0; - } - } - WFIFOSET(fd,34); - RFIFOSKIP(fd,38); - break; - - case 0x794e: // Request to send a broadcast message - if (RFIFOREST(fd) < 8 || RFIFOREST(fd) < (8 + RFIFOL(fd,4))) - return 0; - WFIFOW(fd,0) = 0x794f; - WFIFOW(fd,2) = 0xFFFF; // WTF??? - if (RFIFOL(fd,4) < 1) { - ShowNotice("'ladmin': Receiving a message for broadcast, but message is void (ip: %s)\n", ip); - } else { - // at least 1 char-server - for(i = 0; i < MAX_SERVERS; i++) - if (server[i].fd >= 0) - break; - if (i == MAX_SERVERS) { - ShowNotice("'ladmin': Receiving a message for broadcast, but no char-server is online (ip: %s)\n", ip); - } else { - unsigned char buf[32000]; - char message[32000]; - WFIFOW(fd,2) = 0; - memset(message, '\0', sizeof(message)); - memcpy(message, RFIFOP(fd,8), RFIFOL(fd,4)); - message[sizeof(message)-1] = '\0'; - remove_control_chars(message); - if (RFIFOW(fd,2) == 0) - ShowNotice("'ladmin': Receiving a message for broadcast (message (in yellow): %s, ip: %s)\n", message, ip); - else - ShowNotice("'ladmin': Receiving a message for broadcast (message (in blue): %s, ip: %s)\n", message, ip); - // send same message to all char-servers (no answer) - memcpy(WBUFP(buf,0), RFIFOP(fd,0), 8 + RFIFOL(fd,4)); - WBUFW(buf,0) = 0x2726; - charif_sendallwos(-1, buf, 8 + RFIFOL(fd,4)); - } - } - WFIFOSET(fd,4); - RFIFOSKIP(fd,8 + RFIFOL(fd,4)); - break; - - case 0x7950: // Request to change the validity limite (timestamp) (relative change) - if (RFIFOREST(fd) < 38) - return 0; - { - time_t timestamp; - struct tm *tmtime; - char tmpstr[2048]; - char tmpstr2[2048]; - WFIFOW(fd,0) = 0x7951; - WFIFOL(fd,2) = 0xFFFFFFFF; // WTF??? - account_name = (char*)RFIFOP(fd,2); - account_name[23] = '\0'; - remove_control_chars(account_name); - i = search_account_index(account_name); - if (i != -1) { - WFIFOL(fd,2) = auth_dat[i].account_id; - memcpy(WFIFOP(fd,6), auth_dat[i].userid, 24); - timestamp = auth_dat[i].expiration_time; - if (timestamp == 0 || timestamp < time(NULL)) - timestamp = time(NULL); - tmtime = localtime(×tamp); - tmtime->tm_year = tmtime->tm_year + (short)RFIFOW(fd,26); - tmtime->tm_mon = tmtime->tm_mon + (short)RFIFOW(fd,28); - tmtime->tm_mday = tmtime->tm_mday + (short)RFIFOW(fd,30); - tmtime->tm_hour = tmtime->tm_hour + (short)RFIFOW(fd,32); - tmtime->tm_min = tmtime->tm_min + (short)RFIFOW(fd,34); - tmtime->tm_sec = tmtime->tm_sec + (short)RFIFOW(fd,36); - timestamp = mktime(tmtime); - if (timestamp != -1) { - strftime(tmpstr, 24, login_config.date_format, localtime(&auth_dat[i].expiration_time)); - strftime(tmpstr2, 24, login_config.date_format, localtime(×tamp)); - ShowNotice("'ladmin': Adjustment of a validity limit (account: %s, %d (%s) + (%+d y %+d m %+d d %+d h %+d mn %+d s) -> new validity: %d (%s), ip: %s)\n", auth_dat[i].userid, auth_dat[i].expiration_time, (auth_dat[i].expiration_time == 0 ? "unlimited" : tmpstr), (short)RFIFOW(fd,26), (short)RFIFOW(fd,28), (short)RFIFOW(fd,30), (short)RFIFOW(fd,32), (short)RFIFOW(fd,34), (short)RFIFOW(fd,36), timestamp, (timestamp == 0 ? "unlimited" : tmpstr2), ip); - auth_dat[i].expiration_time = timestamp; - mmo_auth_sync(); - WFIFOL(fd,30) = (unsigned long)auth_dat[i].expiration_time; - } else { - strftime(tmpstr, 24, login_config.date_format, localtime(&auth_dat[i].expiration_time)); - ShowNotice("'ladmin': Impossible to adjust a validity limit (account: %s, %d (%s) + (%+d y %+d m %+d d %+d h %+d mn %+d s) -> ???, ip: %s)\n", auth_dat[i].userid, auth_dat[i].expiration_time, (auth_dat[i].expiration_time == 0 ? "unlimited" : tmpstr), (short)RFIFOW(fd,26), (short)RFIFOW(fd,28), (short)RFIFOW(fd,30), (short)RFIFOW(fd,32), (short)RFIFOW(fd,34), (short)RFIFOW(fd,36), ip); - WFIFOL(fd,30) = 0; - } - } else { - memcpy(WFIFOP(fd,6), account_name, 24); - ShowNotice("'ladmin': Attempt to adjust the validity limit of an unknown account (account: %s, ip: %s)\n", account_name, ip); - WFIFOL(fd,30) = 0; - } - } - WFIFOSET(fd,34); - RFIFOSKIP(fd,38); - break; - - case 0x7952: // Request about informations of an account (by account name) - if (RFIFOREST(fd) < 26) - return 0; - WFIFOW(fd,0) = 0x7953; - WFIFOL(fd,2) = 0xFFFFFFFF; // WTF??? - account_name = (char*)RFIFOP(fd,2); - account_name[23] = '\0'; - remove_control_chars(account_name); - i = search_account_index(account_name); - if (i != -1) { - WFIFOL(fd,2) = auth_dat[i].account_id; - WFIFOB(fd,6) = (unsigned char)isGM(auth_dat[i].account_id); - memcpy(WFIFOP(fd,7), auth_dat[i].userid, 24); - WFIFOB(fd,31) = auth_dat[i].sex; - WFIFOL(fd,32) = auth_dat[i].logincount; - WFIFOL(fd,36) = auth_dat[i].state; - memcpy(WFIFOP(fd,40), auth_dat[i].error_message, 20); - memcpy(WFIFOP(fd,60), auth_dat[i].lastlogin, 24); - memcpy(WFIFOP(fd,84), auth_dat[i].last_ip, 16); - memcpy(WFIFOP(fd,100), auth_dat[i].email, 40); - WFIFOL(fd,140) = (unsigned long)auth_dat[i].expiration_time; - WFIFOL(fd,144) = (unsigned long)auth_dat[i].unban_time; - WFIFOW(fd,148) = (uint16)strlen(auth_dat[i].memo); - if (auth_dat[i].memo[0]) { - memcpy(WFIFOP(fd,150), auth_dat[i].memo, strlen(auth_dat[i].memo)); - } - ShowNotice("'ladmin': Sending information of an account (request by the name; account: %s, id: %d, ip: %s)\n", auth_dat[i].userid, auth_dat[i].account_id, ip); - WFIFOSET(fd,150+strlen(auth_dat[i].memo)); - } else { - memcpy(WFIFOP(fd,7), account_name, 24); - WFIFOW(fd,148) = 0; - ShowNotice("'ladmin': Attempt to obtain information (by the name) of an unknown account (account: %s, ip: %s)\n", account_name, ip); - WFIFOSET(fd,150); - } - RFIFOSKIP(fd,26); - break; - - case 0x7954: // Request about information of an account (by account id) - if (RFIFOREST(fd) < 6) - return 0; - WFIFOW(fd,0) = 0x7953; - WFIFOL(fd,2) = RFIFOL(fd,2); - memset(WFIFOP(fd,7), '\0', 24); - for(i = 0; i < auth_num; i++) { - if (auth_dat[i].account_id == (int)RFIFOL(fd,2)) { - ShowNotice("'ladmin': Sending information of an account (request by the id; account: %s, id: %d, ip: %s)\n", auth_dat[i].userid, RFIFOL(fd,2), ip); - WFIFOB(fd,6) = (unsigned char)isGM(auth_dat[i].account_id); - memcpy(WFIFOP(fd,7), auth_dat[i].userid, 24); - WFIFOB(fd,31) = auth_dat[i].sex; - WFIFOL(fd,32) = auth_dat[i].logincount; - WFIFOL(fd,36) = auth_dat[i].state; - memcpy(WFIFOP(fd,40), auth_dat[i].error_message, 20); - memcpy(WFIFOP(fd,60), auth_dat[i].lastlogin, 24); - memcpy(WFIFOP(fd,84), auth_dat[i].last_ip, 16); - memcpy(WFIFOP(fd,100), auth_dat[i].email, 40); - WFIFOL(fd,140) = (unsigned long)auth_dat[i].expiration_time; - WFIFOL(fd,144) = (unsigned long)auth_dat[i].unban_time; - WFIFOW(fd,148) = (uint16)strlen(auth_dat[i].memo); - if (auth_dat[i].memo[0]) { - memcpy(WFIFOP(fd,150), auth_dat[i].memo, strlen(auth_dat[i].memo)); - } - WFIFOSET(fd,150+strlen(auth_dat[i].memo)); - break; - } - } - if (i == auth_num) { - ShowNotice("'ladmin': Attempt to obtain information (by the id) of an unknown account (id: %d, ip: %s)\n", RFIFOL(fd,2), ip); - strncpy((char*)WFIFOP(fd,7), "", 24); - WFIFOW(fd,148) = 0; - WFIFOSET(fd,150); - } - RFIFOSKIP(fd,6); - break; - - case 0x7955: // Request to reload GM file (no answer) - ShowStatus("'ladmin': Request to re-load GM configuration file (ip: %s).\n", ip); - read_gm_account(); - // send GM accounts to all char-servers - send_GM_accounts(-1); - RFIFOSKIP(fd,2); - break; - - default: - ShowStatus("'ladmin': End of connection, unknown packet (ip: %s)\n", ip); - set_eof(fd); - return 0; - } - } - RFIFOSKIP(fd,RFIFOREST(fd)); - return 0; -} diff --git a/src/login/login.c b/src/login/login.c deleted file mode 100644 index 9bb77e093..000000000 --- a/src/login/login.c +++ /dev/null @@ -1,2362 +0,0 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder - -#include "../common/cbasetypes.h" -#include "../common/mmo.h" -#include "../common/core.h" -#include "../common/socket.h" -#include "../common/db.h" -#include "../common/timer.h" -#include "../common/malloc.h" -#include "../common/strlib.h" -#include "../common/showmsg.h" -#include "../common/version.h" -#include "../common/md5calc.h" -#include "../common/lock.h" -#include "login.h" - -#include -#include -#include -#include // for stat/lstat/fstat - -struct Login_Config login_config; - -int login_fd; // login server socket -#define MAX_SERVERS 30 -struct mmo_char_server server[MAX_SERVERS]; // char server data - -#define sex_num2str(num) ( (num == 0 ) ? 'F' : (num == 1 ) ? 'M' : 'S' ) -#define sex_str2num(str) ( (str == 'F' ) ? 0 : (str == 'M' ) ? 1 : 2 ) - -// Advanced subnet check [LuzZza] -struct s_subnet { - uint32 mask; - uint32 char_ip; - uint32 map_ip; -} subnet[16]; - -int subnet_count = 0; - -// GM account management -struct gm_account* gm_account_db = NULL; -unsigned int GM_num = 0; // number of gm accounts -char GM_account_filename[1024] = "conf/GM_account.txt"; -long creation_time_GM_account_file; // tracks the last-changed timestamp of the gm accounts file -int gm_account_filename_check_timer = 15; // Timer to check if GM_account file has been changed and reload GM account automaticaly (in seconds; default: 15) - -//Account registration flood protection [Kevin] -int allowed_regs = 1; -int time_allowed = 10; //in seconds -unsigned int new_reg_tick = 0; - - -// data handling (TXT) -char account_filename[1024] = "save/account.txt"; - -// account database -struct mmo_account* auth_dat = NULL; -unsigned int auth_num = 0, auth_max = 0; - -int account_id_count = START_ACCOUNT_NUM; - -// define the number of times that some players must authentify them before to save account file. -// it's just about normal authentication. If an account is created or modified, save is immediatly done. -// An authentication just change last connected IP and date. It already save in log file. -// set minimum auth change before save: -#define AUTH_BEFORE_SAVE_FILE 10 -// set divider of auth_num to found number of change before save -#define AUTH_SAVE_FILE_DIVIDER 50 -int auth_before_save_file = 0; // Counter. First save when 1st char-server do connection. - - -// ladmin configuration -bool admin_state = false; -char admin_pass[24] = ""; -uint32 admin_allowed_ip = 0; - -int parse_admin(int fd); - - -//----------------------------------------------------- -// Auth database -//----------------------------------------------------- -#define AUTH_TIMEOUT 30000 - -struct auth_node { - int account_id; - uint32 login_id1; - uint32 login_id2; - uint32 ip; - char sex; -}; - -static DBMap* auth_db; // int account_id -> struct auth_node* - -//----------------------------------------------------- -// Online User Database [Wizputer] -//----------------------------------------------------- - -struct online_login_data { - int account_id; - int waiting_disconnect; - int char_server; -}; - -static DBMap* online_db; // int account_id -> struct online_login_data* -static int waiting_disconnect_timer(int tid, unsigned int tick, int id, int data); - -static void* create_online_user(DBKey key, va_list args) -{ - struct online_login_data* p; - CREATE(p, struct online_login_data, 1); - p->account_id = key.i; - p->char_server = -1; - p->waiting_disconnect = -1; - return p; -} - -struct online_login_data* add_online_user(int char_server, int account_id) -{ - struct online_login_data* p; - if( !login_config.online_check ) - return NULL; - p = (struct online_login_data*)idb_ensure(online_db, account_id, create_online_user); - p->char_server = char_server; - if( p->waiting_disconnect != -1 ) - { - delete_timer(p->waiting_disconnect, waiting_disconnect_timer); - p->waiting_disconnect = -1; - } - return p; -} - -void remove_online_user(int account_id) -{ - struct online_login_data* p; - if( !login_config.online_check ) - return; - p = (struct online_login_data*)idb_get(online_db, account_id); - if( p == NULL ) - return; - if( p->waiting_disconnect != -1 ) - delete_timer(p->waiting_disconnect, waiting_disconnect_timer); - - idb_remove(online_db, account_id); -} - -static int waiting_disconnect_timer(int tid, unsigned int tick, int id, int data) -{ - struct online_login_data* p = (struct online_login_data*)idb_get(online_db, id); - if( p != NULL && p->waiting_disconnect == tid && p->account_id == id ) - { - p->waiting_disconnect = -1; - remove_online_user(id); - idb_remove(auth_db, id); - } - return 0; -} - -//-------------------------------------------------------------------- -// Packet send to all char-servers, except one (wos: without our self) -//-------------------------------------------------------------------- -int charif_sendallwos(int sfd, uint8* buf, size_t len) -{ - int i, c; - - for( i = 0, c = 0; i < MAX_SERVERS; ++i ) - { - int fd = server[i].fd; - if( session_isValid(fd) && fd != sfd ) - { - WFIFOHEAD(fd,len); - memcpy(WFIFOP(fd,0), buf, len); - WFIFOSET(fd,len); - ++c; - } - } - - return c; -} - -//---------------------------------------------------------------------- -// Determine if an account (id) is a GM account -// and returns its level (or 0 if it isn't a GM account or if not found) -//---------------------------------------------------------------------- -int isGM(int account_id) -{ - unsigned int i; - ARR_FIND( 0, GM_num, i, gm_account_db[i].account_id == account_id ); - return ( i < GM_num ) ? gm_account_db[i].level : 0; -} - -//---------------------------------------------------------------------- -// Adds a new GM using acc id and level -//---------------------------------------------------------------------- -void addGM(int account_id, int level) -{ - static unsigned int GM_max = 0; - unsigned int i; - - ARR_FIND( 0, auth_num, i, auth_dat[i].account_id == account_id ); - if( i == auth_num ) - return; // no such account - - ARR_FIND( 0, GM_num, i, gm_account_db[i].account_id == account_id ); - if( i < GM_num ) - { - if (gm_account_db[i].level == level) - ShowWarning("addGM: GM account %d defined twice (same level: %d).\n", account_id, level); - else { - ShowWarning("addGM: GM account %d defined twice (levels: %d and %d).\n", account_id, gm_account_db[i].level, level); - gm_account_db[i].level = level; - } - return; // entry already present - } - - // new account - if (GM_num >= GM_max) { - GM_max += 256; - RECREATE(gm_account_db, struct gm_account, GM_max); - } - gm_account_db[GM_num].account_id = account_id; - gm_account_db[GM_num].level = level; - GM_num++; - if (GM_num >= 4000) - ShowWarning("4000 GM accounts found. Next GM accounts are not read.\n"); -} - -//------------------------------------------------------- -// Reading function of GM accounts file (and their level) -//------------------------------------------------------- -int read_gm_account(void) -{ - char line[512]; - FILE *fp; - int account_id, level; - int line_counter; - struct stat file_stat; - int start_range = 0, end_range = 0, is_range = 0, current_id = 0; - - if(gm_account_db) aFree(gm_account_db); - CREATE(gm_account_db, struct gm_account, 1); - GM_num = 0; - - // get last modify time/date - if (stat(GM_account_filename, &file_stat)) - creation_time_GM_account_file = 0; // error - else - creation_time_GM_account_file = (long)file_stat.st_mtime; - - if ((fp = fopen(GM_account_filename, "r")) == NULL) { - ShowError("read_gm_account: GM accounts file [%s] not found.\n", GM_account_filename); - return 1; - } - - line_counter = 0; - // limited to 4000, because we send information to char-servers (more than 4000 GM accounts???) - // int (id) + int (level) = 8 bytes * 4000 = 32k (limit of packets in windows) - while(fgets(line, sizeof(line), fp) && GM_num < 4000) - { - line_counter++; - if ((line[0] == '/' && line[1] == '/') || line[0] == '\0' || line[0] == '\n' || line[0] == '\r') - continue; - is_range = (sscanf(line, "%d%*[-~]%d %d",&start_range,&end_range,&level)==3); // ID Range [MC Cameri] - if (!is_range && sscanf(line, "%d %d", &account_id, &level) != 2 && sscanf(line, "%d: %d", &account_id, &level) != 2) - ShowError("read_gm_account: file [%s], invalid 'acount_id|range level' format (line #%d).\n", GM_account_filename, line_counter); - else if (level <= 0) - ShowError("read_gm_account: file [%s] %dth account (line #%d) (invalid level [0 or negative]: %d).\n", GM_account_filename, GM_num+1, line_counter, level); - else { - if (level > 99) { - ShowNotice("read_gm_account: file [%s] %dth account (invalid level, but corrected: %d->99).\n", GM_account_filename, GM_num+1, level); - level = 99; - } - if (is_range) { - if (start_range==end_range) - ShowError("read_gm_account: file [%s] invalid range, beginning of range is equal to end of range (line #%d).\n", GM_account_filename, line_counter); - else if (start_range>end_range) - ShowError("read_gm_account: file [%s] invalid range, beginning of range must be lower than end of range (line #%d).\n", GM_account_filename, line_counter); - else - for (current_id = start_range;current_id<=end_range;current_id++) - addGM(current_id,level); - } else { - addGM(account_id,level); - } - } - } - fclose(fp); - - ShowStatus("read_gm_account: file '%s' read (%d GM accounts found).\n", GM_account_filename, GM_num); - - return 0; -} - - -//----------------------------------------------- -// Search an account id -// (return account index or -1 (if not found)) -// If exact account name is not found, -// the function checks without case sensitive -// and returns index if only 1 account is found -// and similar to the searched name. -//----------------------------------------------- -int search_account_index(char* account_name) -{ - unsigned int i, quantity; - int index; - - quantity = 0; - index = -1; - - for(i = 0; i < auth_num; i++) { - // Without case sensitive check (increase the number of similar account names found) - if (stricmp(auth_dat[i].userid, account_name) == 0) { - // Strict comparison (if found, we finish the function immediatly with correct value) - if (strcmp(auth_dat[i].userid, account_name) == 0) - return i; - quantity++; - index = i; - } - } - // Here, the exact account name is not found - // We return the found index of a similar account ONLY if there is 1 similar account - if (quantity == 1) - return index; - - // Exact account name is not found and 0 or more than 1 similar accounts have been found ==> we say not found - return -1; -} - -//-------------------------------------------------------- -// Create a string to save the account in the account file -//-------------------------------------------------------- -int mmo_auth_tostr(char* str, struct mmo_account* p) -{ - int i; - char *str_p = str; - - str_p += sprintf(str_p, "%d\t%s\t%s\t%s\t%c\t%d\t%u\t%s\t%s\t%ld\t%s\t%s\t%ld\t", - p->account_id, p->userid, p->pass, p->lastlogin, p->sex, - p->logincount, p->state, p->email, p->error_message, - (long)p->expiration_time, p->last_ip, p->memo, (long)p->unban_time); - - for(i = 0; i < p->account_reg2_num; i++) - if (p->account_reg2[i].str[0]) - str_p += sprintf(str_p, "%s,%s ", p->account_reg2[i].str, p->account_reg2[i].value); - - return 0; -} - -//--------------------------------- -// Reading of the accounts database -//--------------------------------- -int mmo_auth_init(void) -{ - FILE *fp; - int account_id; - uint32 state; - int logincount, n; - uint32 i, j; - char line[2048], *p, userid[2048], pass[2048], lastlogin[2048], sex, email[2048], error_message[2048], last_ip[2048], memo[2048]; - long unban_time; - long expiration_time; - char str[2048]; - char v[2048]; - int GM_count = 0; - int server_count = 0; - - auth_max = 256; - CREATE(auth_dat, struct mmo_account, auth_max); - - if ((fp = fopen(account_filename, "r")) == NULL) { - // no account file -> no account -> no login, including char-server (ERROR) - ShowError(CL_RED"mmmo_auth_init: Accounts file [%s] not found."CL_RESET"\n", account_filename); - return 0; - } - - while(fgets(line, sizeof(line), fp) != NULL) - { - if (line[0] == '/' && line[1] == '/') - continue; - - p = line; - - memset(userid, 0, sizeof(userid)); - memset(pass, 0, sizeof(pass)); - memset(lastlogin, 0, sizeof(lastlogin)); - memset(email, 0, sizeof(email)); - memset(error_message, 0, sizeof(error_message)); - memset(last_ip, 0, sizeof(last_ip)); - memset(memo, 0, sizeof(memo)); - - // database version reading (v2) - if (((i = sscanf(line, "%d\t%[^\t]\t%[^\t]\t%[^\t]\t%c\t%d\t%u\t" - "%[^\t]\t%[^\t]\t%ld\t%[^\t]\t%[^\t]\t%ld%n", - &account_id, userid, pass, lastlogin, &sex, &logincount, &state, - email, error_message, &expiration_time, last_ip, memo, &unban_time, &n)) == 13 && line[n] == '\t') || - ((i = sscanf(line, "%d\t%[^\t]\t%[^\t]\t%[^\t]\t%c\t%d\t%u\t" - "%[^\t]\t%[^\t]\t%ld\t%[^\t]\t%[^\t]%n", - &account_id, userid, pass, lastlogin, &sex, &logincount, &state, - email, error_message, &expiration_time, last_ip, memo, &n)) == 12 && line[n] == '\t')) { - n = n + 1; - - // Some checks - if (account_id > END_ACCOUNT_NUM) { - ShowError(CL_RED"mmmo_auth_init: an account has an id higher than %d\n", END_ACCOUNT_NUM); - ShowError(" account id #%d -> account not read (data is lost!)."CL_RESET"\n", account_id); - continue; - } - userid[23] = '\0'; - remove_control_chars(userid); - for(j = 0; j < auth_num; j++) { - if (auth_dat[j].account_id == account_id) { - ShowError(CL_RED"mmmo_auth_init: an account has an identical id to another.\n"); - ShowError(" account id #%d -> new account not read (data is lost!)."CL_RED"\n", account_id); - break; - } else if (strcmp(auth_dat[j].userid, userid) == 0) { - ShowError(CL_RED"mmmo_auth_init: account name already exists.\n"); - ShowError(" account name '%s' -> new account not read (data is lost!)."CL_RESET"\n", userid); // 2 lines, account name can be long. - break; - } - } - if (j != auth_num) - continue; - - if (auth_num >= auth_max) { - auth_max += 256; - auth_dat = (struct mmo_account*)aRealloc(auth_dat, sizeof(struct mmo_account) * auth_max); - } - - memset(&auth_dat[auth_num], '\0', sizeof(struct mmo_account)); - - auth_dat[auth_num].account_id = account_id; - - strncpy(auth_dat[auth_num].userid, userid, 24); - - pass[32] = '\0'; - remove_control_chars(pass); - strncpy(auth_dat[auth_num].pass, pass, 32); - - lastlogin[23] = '\0'; - remove_control_chars(lastlogin); - strncpy(auth_dat[auth_num].lastlogin, lastlogin, 24); - - auth_dat[auth_num].sex = sex; - - if (logincount >= 0) - auth_dat[auth_num].logincount = logincount; - else - auth_dat[auth_num].logincount = 0; - - if (state > 255) - auth_dat[auth_num].state = 100; - else - auth_dat[auth_num].state = state; - - if (e_mail_check(email) == 0) { - ShowNotice("Account %s (%d): invalid e-mail (replaced par a@a.com).\n", auth_dat[auth_num].userid, auth_dat[auth_num].account_id); - strncpy(auth_dat[auth_num].email, "a@a.com", 40); - } else { - remove_control_chars(email); - strncpy(auth_dat[auth_num].email, email, 40); - } - - error_message[19] = '\0'; - remove_control_chars(error_message); - if (error_message[0] == '\0' || state != 7) { // 7, because state is packet 0x006a value + 1 - strncpy(auth_dat[auth_num].error_message, "-", 20); - } else { - strncpy(auth_dat[auth_num].error_message, error_message, 20); - } - - if (i == 13) - auth_dat[auth_num].unban_time = (time_t)unban_time; - else - auth_dat[auth_num].unban_time = 0; - - auth_dat[auth_num].expiration_time = (time_t)expiration_time; - - last_ip[15] = '\0'; - remove_control_chars(last_ip); - strncpy(auth_dat[auth_num].last_ip, last_ip, 16); - - memo[254] = '\0'; - remove_control_chars(memo); - strncpy(auth_dat[auth_num].memo, memo, 255); - - for(j = 0; j < ACCOUNT_REG2_NUM; j++) { - p += n; - if (sscanf(p, "%[^\t,],%[^\t ] %n", str, v, &n) != 2) { - // We must check if a str is void. If it's, we can continue to read other REG2. - // Account line will have something like: str2,9 ,9 str3,1 (here, ,9 is not good) - if (p[0] == ',' && sscanf(p, ",%[^\t ] %n", v, &n) == 1) { - j--; - continue; - } else - break; - } - str[31] = '\0'; - remove_control_chars(str); - strncpy(auth_dat[auth_num].account_reg2[j].str, str, 32); - strncpy(auth_dat[auth_num].account_reg2[j].value,v,256); - } - auth_dat[auth_num].account_reg2_num = j; - - if (isGM(account_id) > 0) - GM_count++; - if (auth_dat[auth_num].sex == 'S') - server_count++; - - auth_num++; - if (account_id >= account_id_count) - account_id_count = account_id + 1; - - // Old athena database version reading (v1) - } else if ((i = sscanf(line, "%d\t%[^\t]\t%[^\t]\t%[^\t]\t%c\t%d\t%u\t%n", - &account_id, userid, pass, lastlogin, &sex, &logincount, &state, &n)) >= 5) { - if (account_id > END_ACCOUNT_NUM) { - ShowError(CL_RED"mmmo_auth_init: an account has an id higher than %d\n", END_ACCOUNT_NUM); - ShowError(" account id #%d -> account not read (data is lost!)."CL_RESET"\n", account_id); - continue; - } - userid[23] = '\0'; - remove_control_chars(userid); - for(j = 0; j < auth_num; j++) { - if (auth_dat[j].account_id == account_id) { - ShowError(CL_RED"mmo_auth_init: an account has an identical id to another.\n"); - ShowError(" account id #%d -> new account not read (data is lost!)."CL_RESET"\n", account_id); - break; - } else if (strcmp(auth_dat[j].userid, userid) == 0) { - ShowError(CL_RED"mmo_auth_init: account name already exists.\n"); - ShowError(" account name '%s' -> new account not read (data is lost!)."CL_RESET"\n", userid); - break; - } - } - if (j != auth_num) - continue; - - if (auth_num >= auth_max) { - auth_max += 256; - RECREATE(auth_dat, struct mmo_account, auth_max); - } - - memset(&auth_dat[auth_num], '\0', sizeof(struct mmo_account)); - - auth_dat[auth_num].account_id = account_id; - - strncpy(auth_dat[auth_num].userid, userid, 24); - - pass[23] = '\0'; - remove_control_chars(pass); - strncpy(auth_dat[auth_num].pass, pass, 24); - - lastlogin[23] = '\0'; - remove_control_chars(lastlogin); - strncpy(auth_dat[auth_num].lastlogin, lastlogin, 24); - - auth_dat[auth_num].sex = sex; - - if (i >= 6) { - if (logincount >= 0) - auth_dat[auth_num].logincount = logincount; - else - auth_dat[auth_num].logincount = 0; - } else - auth_dat[auth_num].logincount = 0; - - if (i >= 7) { - if (state > 255) - auth_dat[auth_num].state = 100; - else - auth_dat[auth_num].state = state; - } else - auth_dat[auth_num].state = 0; - - // Initialization of new data - strncpy(auth_dat[auth_num].email, "a@a.com", 40); - strncpy(auth_dat[auth_num].error_message, "-", 20); - auth_dat[auth_num].unban_time = 0; - auth_dat[auth_num].expiration_time = 0; - strncpy(auth_dat[auth_num].last_ip, "-", 16); - strncpy(auth_dat[auth_num].memo, "-", 255); - - for(j = 0; j < ACCOUNT_REG2_NUM; j++) { - p += n; - if (sscanf(p, "%[^\t,],%[^\t ] %n", str, v, &n) != 2) { - // We must check if a str is void. If it's, we can continue to read other REG2. - // Account line will have something like: str2,9 ,9 str3,1 (here, ,9 is not good) - if (p[0] == ',' && sscanf(p, ",%[^\t ] %n", v, &n) == 1) { - j--; - continue; - } else - break; - } - str[31] = '\0'; - remove_control_chars(str); - strncpy(auth_dat[auth_num].account_reg2[j].str, str, 32); - strncpy(auth_dat[auth_num].account_reg2[j].value,v,256); - } - auth_dat[auth_num].account_reg2_num = j; - - if (isGM(account_id) > 0) - GM_count++; - if (auth_dat[auth_num].sex == 'S') - server_count++; - - auth_num++; - if (account_id >= account_id_count) - account_id_count = account_id + 1; - - } else { - int i = 0; - if (sscanf(line, "%d\t%%newid%%\n%n", &account_id, &i) == 1 && - i > 0 && account_id > account_id_count) - account_id_count = account_id; - } - } - fclose(fp); - - if( auth_num == 0 ) - ShowNotice("mmo_auth_init: No account found in %s.\n", account_filename); - else - if( auth_num == 1 ) - ShowStatus("mmo_auth_init: 1 account read in %s,\n", account_filename); - else - ShowStatus("mmo_auth_init: %d accounts read in %s,\n", auth_num, account_filename); - - if( GM_count == 0 ) - ShowStatus(" of which is no GM account, and \n"); - else - if( GM_count == 1 ) - ShowStatus(" of which is 1 GM account, and \n"); - else - ShowStatus(" of which is %d GM accounts, and \n", GM_count); - - if( server_count == 0 ) - ShowStatus(" no server account ('S').\n"); - else - if( server_count == 1 ) - ShowStatus(" 1 server account ('S').\n"); - else - ShowStatus(" %d server accounts ('S').\n", server_count); - - return 0; -} - -//------------------------------------------ -// Writing of the accounts database file -// (accounts are sorted by id before save) -//------------------------------------------ -void mmo_auth_sync(void) -{ - FILE *fp; - unsigned int i, j, k; - int lock; - int account_id; - CREATE_BUFFER(id, int, auth_num); - char line[65536]; - - // Sorting before save - for(i = 0; i < auth_num; i++) { - id[i] = i; - account_id = auth_dat[i].account_id; - for(j = 0; j < i; j++) { - if (account_id < auth_dat[id[j]].account_id) { - for(k = i; k > j; k--) - id[k] = id[k-1]; - id[j] = i; // id[i] - break; - } - } - } - - // Data save - if ((fp = lock_fopen(account_filename, &lock)) == NULL) { - //if (id) aFree(id); - DELETE_BUFFER(id); - return; - } - - fprintf(fp, "// Accounts file: here are saved all information about the accounts.\n"); - fprintf(fp, "// Structure: ID, account name, password, last login time, sex, # of logins, state, email, error message for state 7, validity time, last (accepted) login ip, memo field, ban timestamp, repeated(register text, register value)\n"); - fprintf(fp, "// Some explanations:\n"); - fprintf(fp, "// account name : between 4 to 23 char for a normal account (standard client can't send less than 4 char).\n"); - fprintf(fp, "// account password: between 4 to 23 char\n"); - fprintf(fp, "// sex : M or F for normal accounts, S for server accounts\n"); - fprintf(fp, "// state : 0: account is ok, 1 to 256: error code of packet 0x006a + 1\n"); - fprintf(fp, "// email : between 3 to 39 char (a@a.com is like no email)\n"); - fprintf(fp, "// error message : text for the state 7: 'Your are Prohibited to login until '. Max 19 char\n"); - fprintf(fp, "// valitidy time : 0: unlimited account, : date calculated by addition of 1/1/1970 + value (number of seconds since the 1/1/1970)\n"); - fprintf(fp, "// memo field : max 254 char\n"); - fprintf(fp, "// ban time : 0: no ban, : banned until the date: date calculated by addition of 1/1/1970 + value (number of seconds since the 1/1/1970)\n"); - for(i = 0; i < auth_num; i++) { - k = id[i]; // use of sorted index - if (auth_dat[k].account_id == -1) - continue; - - mmo_auth_tostr(line, &auth_dat[k]); - fprintf(fp, "%s\n", line); - } - fprintf(fp, "%d\t%%newid%%\n", account_id_count); - - lock_fclose(fp, account_filename, &lock); - - // set new counter to minimum number of auth before save - auth_before_save_file = auth_num / AUTH_SAVE_FILE_DIVIDER; // Re-initialise counter. We have save. - if (auth_before_save_file < AUTH_BEFORE_SAVE_FILE) - auth_before_save_file = AUTH_BEFORE_SAVE_FILE; - - //if (id) aFree(id); - DELETE_BUFFER(id); - - return; -} - -//----------------------------------------------------- -// Check if we must save accounts file or not -// every minute, we check if we must save because we -// have do some authentications without arrive to -// the minimum of authentications for the save. -// Note: all other modification of accounts (deletion, -// change of some informations excepted lastip/ -// lastlogintime, creation) are always save -// immediatly and set the minimum of -// authentications to its initialization value. -//----------------------------------------------------- -int check_auth_sync(int tid, unsigned int tick, int id, int data) -{ - // we only save if necessary: - // we have do some authentications without do saving - if (auth_before_save_file < AUTH_BEFORE_SAVE_FILE || - auth_before_save_file < (int)(auth_num / AUTH_SAVE_FILE_DIVIDER)) - mmo_auth_sync(); - - return 0; -} - -//----------------------------------------------------- -// periodic ip address synchronization -//----------------------------------------------------- -static int sync_ip_addresses(int tid, unsigned int tick, int id, int data) -{ - uint8 buf[2]; - ShowInfo("IP Sync in progress...\n"); - WBUFW(buf,0) = 0x2735; - charif_sendallwos(-1, buf, 2); - return 0; -} - -//----------------------------------------------------- -// Send GM accounts to one or all char-servers -//----------------------------------------------------- -void send_GM_accounts(int fd) -{ - unsigned int i; - uint8 buf[32767]; - uint16 len; - - len = 4; - WBUFW(buf,0) = 0x2732; - for(i = 0; i < GM_num; i++) - // send only existing accounts. We can not create a GM account when server is online. - if (gm_account_db[i].level > 0) { - WBUFL(buf,len) = gm_account_db[i].account_id; - WBUFB(buf,len+4) = (uint8)gm_account_db[i].level; - len += 5; - if (len >= 32000) { - ShowWarning("send_GM_accounts: Too many accounts! Only %d out of %d were sent.\n", i, GM_num); - break; - } - } - - WBUFW(buf,2) = len; - if (fd == -1) // send to all charservers - charif_sendallwos(-1, buf, len); - else { // send only to target - WFIFOHEAD(fd,len); - memcpy(WFIFOP(fd,0), buf, len); - WFIFOSET(fd,len); - } - - return; -} - -//----------------------------------------------------- -// Check if GM file account have been changed -//----------------------------------------------------- -int check_GM_file(int tid, unsigned int tick, int id, int data) -{ - struct stat file_stat; - long new_time; - - // if we would not check - if (gm_account_filename_check_timer < 1) - return 0; - - // get last modify time/date - if (stat(GM_account_filename, &file_stat)) - new_time = 0; // error - else - new_time = (long)file_stat.st_mtime; - - if (new_time != creation_time_GM_account_file) { - read_gm_account(); - send_GM_accounts(-1); - } - - return 0; -} - - -//----------------------------------------------------- -// encrypted/unencrypted password check -//----------------------------------------------------- -bool check_encrypted(const char* str1, const char* str2, const char* passwd) -{ - char md5str[64], md5bin[32]; - - snprintf(md5str, sizeof(md5str), "%s%s", str1, str2); - md5str[sizeof(md5str)-1] = '\0'; - MD5_String2binary(md5str, md5bin); - - return (0==memcmp(passwd, md5bin, 16)); -} - -bool check_password(struct login_session_data* sd, int passwdenc, const char* passwd, const char* refpass) -{ - if(passwdenc == 0) - { - return (0==strcmp(passwd, refpass)); - } - else if(sd != NULL) - { - // password mode set to 1 -> (md5key, refpass) enable with - // password mode set to 2 -> (refpass, md5key) enable with - - return ((passwdenc&0x01) && check_encrypted(sd->md5key, refpass, passwd)) || - ((passwdenc&0x02) && check_encrypted(refpass, sd->md5key, passwd)); - } - return false; -} - - -//------------------------------------- -// Make new account -//------------------------------------- -int mmo_auth_new(struct mmo_account* account) -{ - static int num_regs = 0; // registration counter - unsigned int tick = gettick(); - - time_t expiration_time = 0; - unsigned int i = auth_num; - - // check if the account doesn't exist already - ARR_FIND( 0, auth_num, i, strcmp(account->userid, auth_dat[i].userid) == 0 ); - if( i < auth_num ) - { - ShowNotice("Attempt of creation of an already existant account (account: %s_%c, pass: %s, received pass: %s)\n", account->userid, account->sex, auth_dat[i].pass, account->pass); - return 1; // 1 = Incorrect Password - } - - //Account Registration Flood Protection by [Kevin] - if( DIFF_TICK(tick, new_reg_tick) < 0 && num_regs >= allowed_regs ) - { - ShowNotice("Account registration denied (registration limit exceeded)\n"); - return 3; - } - - if (auth_num >= auth_max) { - auth_max += 256; - auth_dat = (struct mmo_account*)aRealloc(auth_dat, sizeof(struct mmo_account) * auth_max); - } - - memset(&auth_dat[i], '\0', sizeof(struct mmo_account)); - - // find a suitable non-gm account id - while (isGM(account_id_count) > 0) - account_id_count++; - - auth_dat[i].account_id = account_id_count++; - safestrncpy(auth_dat[i].userid, account->userid, NAME_LENGTH); - if( login_config.use_md5_passwds ) - MD5_String(account->pass, auth_dat[i].pass); - else - safestrncpy(auth_dat[i].pass, account->pass, NAME_LENGTH); - safestrncpy(auth_dat[i].lastlogin, "-", sizeof(auth_dat[i].lastlogin)); - auth_dat[i].sex = account->sex; - auth_dat[i].logincount = 0; - auth_dat[i].state = 0; - safestrncpy(auth_dat[i].email, e_mail_check(account->email) ? account->email : "a@a.com", sizeof(auth_dat[i].email)); - safestrncpy(auth_dat[i].error_message, "-", sizeof(auth_dat[i].error_message)); - auth_dat[i].unban_time = 0; - if( login_config.start_limited_time != -1 ) - expiration_time = time(NULL) + login_config.start_limited_time; - auth_dat[i].expiration_time = expiration_time; - strncpy(auth_dat[i].last_ip, "-", 16); - strncpy(auth_dat[i].memo, "-", 255); - auth_dat[i].account_reg2_num = 0; - - ShowNotice("Account creation (account %s, id: %d, pass: %s, sex: %c)\n", account->userid, auth_num, account->pass, account->sex); - auth_num++; - - if( DIFF_TICK(tick, new_reg_tick) > 0 ) - {// Update the registration check. - num_regs = 0; - new_reg_tick = tick + time_allowed*1000; - } - ++num_regs; - - return 0; -} - -//----------------------------------------------------- -// Check/authentication of a connection -//----------------------------------------------------- -int mmo_auth(struct login_session_data* sd) -{ - unsigned int i; - time_t raw_time; - char tmpstr[256]; - int len; - char user_password[32+1]; // reserve for md5-ed pw - - char ip[16]; - ip2str(session[sd->fd]->client_addr, ip); - - // DNS Blacklist check - if( login_config.use_dnsbl ) - { - char r_ip[16]; - char ip_dnsbl[256]; - char* dnsbl_serv; - bool matched = false; - uint8* sin_addr = (uint8*)&session[sd->fd]->client_addr; - - sprintf(r_ip, "%u.%u.%u.%u", sin_addr[0], sin_addr[1], sin_addr[2], sin_addr[3]); - - for( dnsbl_serv = strtok(login_config.dnsbl_servs,","); !matched && dnsbl_serv != NULL; dnsbl_serv = strtok(NULL,",") ) - { - sprintf(ip_dnsbl, "%s.%s", r_ip, dnsbl_serv); - if( host2ip(ip_dnsbl) ) - matched = true; - } - - if( matched ) - { - ShowInfo("DNSBL: (%s) Blacklisted. User Kicked.\n", r_ip); - return 3; - } - } - - //Client Version check - if( login_config.check_client_version && sd->version != login_config.client_version_to_connect ) - return 5; - - len = strnlen(sd->userid, NAME_LENGTH); - - // Account creation with _M/_F - if( login_config.new_account_flag ) - { - if( len > 2 && strnlen(sd->passwd, NAME_LENGTH) > 0 && // valid user and password lengths - sd->passwdenc == 0 && // unencoded password - sd->userid[len-2] == '_' && memchr("FfMm", sd->userid[len-1], 4) && // _M/_F suffix - account_id_count <= END_ACCOUNT_NUM ) - { - struct mmo_account acc; - int result; - - len -= 2; - sd->userid[len] = '\0'; - - memset(&acc, '\0', sizeof(acc)); - safestrncpy(acc.userid, sd->userid, NAME_LENGTH); - safestrncpy(acc.pass, sd->passwd, NAME_LENGTH); - safestrncpy(acc.email, "a@a.com", sizeof(acc.email)); - acc.sex = TOUPPER(sd->userid[len+1]); - - result = mmo_auth_new(&acc); - if( result ) - return result;// Failed to make account. [Skotlex]. - - auth_before_save_file = 0; // Creation of an account -> save accounts file immediatly - } - } - - // Strict account search - ARR_FIND( 0, auth_num, i, strcmp(sd->userid, auth_dat[i].userid) == 0 ); - - // if strict account search fails, we do a no sensitive case research for index - if( i < auth_num ) - { - i = search_account_index(sd->userid); - if( i == -1 ) - i = auth_num; - else - memcpy(sd->userid, auth_dat[i].userid, NAME_LENGTH); // for the possible tests/checks afterwards (copy correcte sensitive case). - } - - if( i == auth_num ) - { - ShowNotice("Unknown account (account: %s, received pass: %s, ip: %s)\n", sd->userid, sd->passwd, ip); - return 0; // 0 = Unregistered ID - } - - if( login_config.use_md5_passwds ) - MD5_String(sd->passwd, user_password); - else - safestrncpy(user_password, sd->passwd, NAME_LENGTH); - - if( !check_password(sd, sd->passwdenc, user_password, auth_dat[i].pass) ) - { - ShowNotice("Invalid password (account: %s, pass: %s, received pass: %s, ip: %s)\n", sd->userid, auth_dat[i].pass, (sd->passwdenc) ? "[MD5]" : sd->passwd, ip); - return 1; // 1 = Incorrect Password - } - - if( auth_dat[i].expiration_time != 0 && auth_dat[i].expiration_time < time(NULL) ) - { - ShowNotice("Connection refused (account: %s, pass: %s, expired ID, ip: %s)\n", sd->userid, sd->passwd, ip); - return 2; // 2 = This ID is expired - } - - if( auth_dat[i].unban_time != 0 && auth_dat[i].unban_time > time(NULL) ) - { - strftime(tmpstr, 20, login_config.date_format, localtime(&auth_dat[i].unban_time)); - tmpstr[19] = '\0'; - ShowNotice("Connection refused (account: %s, pass: %s, banned until %s, ip: %s)\n", sd->userid, sd->passwd, tmpstr, ip); - return 6; // 6 = Your are Prohibited to log in until %s - } - - if( auth_dat[i].state ) - { - ShowNotice("Connection refused (account: %s, pass: %s, state: %d, ip: %s)\n", sd->userid, sd->passwd, auth_dat[i].state, ip); - return auth_dat[i].state - 1; - } - - ShowNotice("Authentication accepted (account: %s, id: %d, ip: %s)\n", sd->userid, auth_dat[i].account_id, ip); - - // auth start : time seed - time(&raw_time); - strftime(tmpstr, 24, "%Y-%m-%d %H:%M:%S",localtime(&raw_time)); - - sd->account_id = auth_dat[i].account_id; - sd->login_id1 = rand(); - sd->login_id2 = rand(); - safestrncpy(sd->lastlogin, auth_dat[i].lastlogin, 24); - sd->sex = auth_dat[i].sex; - - if( sd->sex != 'S' && sd->account_id < START_ACCOUNT_NUM ) - ShowWarning("Account %s has account id %d! Account IDs must be over %d to work properly!\n", sd->userid, sd->account_id, START_ACCOUNT_NUM); - - safestrncpy(auth_dat[i].lastlogin, tmpstr, sizeof(auth_dat[i].lastlogin)); - safestrncpy(auth_dat[i].last_ip, ip, sizeof(auth_dat[i].last_ip)); - auth_dat[i].unban_time = 0; - auth_dat[i].logincount++; - - // Save until for change ip/time of auth is not very useful => limited save for that - // Save there informations isnot necessary, because they are saved in log file. - if (--auth_before_save_file <= 0) // Reduce counter. 0 or less, we save - mmo_auth_sync(); - - return -1; // account OK -} - -static int online_db_setoffline(DBKey key, void* data, va_list ap) -{ - struct online_login_data* p = (struct online_login_data*)data; - int server = va_arg(ap, int); - if( server == -1 ) - { - p->char_server = -1; - if( p->waiting_disconnect != -1 ) - { - delete_timer(p->waiting_disconnect, waiting_disconnect_timer); - p->waiting_disconnect = -1; - } - } - else if( p->char_server == server ) - p->char_server = -2; //Char server disconnected. - return 0; -} - -//-------------------------------- -// Packet parsing for char-servers -//-------------------------------- -int parse_fromchar(int fd) -{ - unsigned int i; - int j, id; - uint32 ipl; - char ip[16]; - - ARR_FIND( 0, MAX_SERVERS, id, server[id].fd == fd ); - if( id == MAX_SERVERS ) - {// not a char server - set_eof(fd); - do_close(fd); - return 0; - } - - if( session[fd]->flag.eof ) - { - ShowStatus("Char-server '%s' has disconnected.\n", server[id].name); - online_db->foreach(online_db, online_db_setoffline, id); //Set all chars from this char server to offline. - memset(&server[id], 0, sizeof(struct mmo_char_server)); - server[id].fd = -1; - do_close(fd); - return 0; - } - - ipl = server[id].ip; - ip2str(ipl, ip); - - while( RFIFOREST(fd) >= 2 ) - { - uint16 command = RFIFOW(fd,0); - - switch( command ) - { - - case 0x2709: // request from map-server via char-server to reload GM accounts - RFIFOSKIP(fd,2); - ShowStatus("Char-server '%s': Request to re-load GM configuration file (ip: %s).\n", server[id].name, ip); - read_gm_account(); - // send GM accounts to all char-servers - send_GM_accounts(-1); - break; - - case 0x2712: // request from char-server to authenticate an account - if( RFIFOREST(fd) < 19 ) - return 0; - { - struct auth_node* node; - - int account_id = RFIFOL(fd,2); - int login_id1 = RFIFOL(fd,6); - int login_id2 = RFIFOL(fd,10); - char sex = sex_num2str(RFIFOB(fd,14)); - uint32 ip_ = ntohl(RFIFOL(fd,15)); - RFIFOSKIP(fd,19); - - node = (struct auth_node*)idb_get(auth_db, account_id); - if( node != NULL && - node->account_id == account_id && - node->login_id1 == login_id1 && - node->login_id2 == login_id2 && - node->sex == sex && - node->ip == ip_ ) - {// found - uint32 expiration_time; - char email[40]; - unsigned int k; - - //ShowStatus("Char-server '%s': authentication of the account %d accepted (ip: %s).\n", server[id].name, account_id, ip); - - // each auth entry can only be used once - idb_remove(auth_db, account_id); - - // retrieve email and account expiration time - ARR_FIND( 0, auth_num, k, auth_dat[k].account_id == account_id ); - if( k < auth_num ) - { - strcpy(email, auth_dat[k].email); - expiration_time = (uint32)auth_dat[k].expiration_time; - } - else - { - memset(email, 0, sizeof(email)); - expiration_time = 0; - } - - // send ack - WFIFOHEAD(fd,59); - WFIFOW(fd,0) = 0x2713; - WFIFOL(fd,2) = account_id; - WFIFOL(fd,6) = login_id1; - WFIFOL(fd,10) = login_id2; - WFIFOB(fd,14) = 0; - memcpy(WFIFOP(fd,15), email, 40); - WFIFOL(fd,55) = expiration_time; - WFIFOSET(fd,59); - } - else - {// authentication not found - ShowStatus("Char-server '%s': authentication of the account %d REFUSED (ip: %s).\n", server[id].name, account_id, ip); - WFIFOHEAD(fd,59); - WFIFOW(fd,0) = 0x2713; - WFIFOL(fd,2) = account_id; - WFIFOL(fd,6) = login_id1; - WFIFOL(fd,10) = login_id2; - WFIFOB(fd,14) = 1; - // It is unnecessary to send email - // It is unnecessary to send validity date of the account - WFIFOSET(fd,59); - } - } - break; - - case 0x2714: - if( RFIFOREST(fd) < 6 ) - return 0; - { - int users = RFIFOL(fd,2); - RFIFOSKIP(fd,6); - - // how many users on world? (update) - if( server[id].users != users ) - { - ShowStatus("set users %s : %d\n", server[id].name, users); - - server[id].users = users; - } - } - break; - - case 0x2715: // request from char server to change e-email from default "a@a.com" - if (RFIFOREST(fd) < 46) - return 0; - { - char email[40]; - int acc = RFIFOL(fd,2); - safestrncpy(email, (char*)RFIFOP(fd,6), 40); remove_control_chars(email); - RFIFOSKIP(fd,46); - - if( e_mail_check(email) == 0 ) - ShowNotice("Char-server '%s': Attempt to create an e-mail on an account with a default e-mail REFUSED - e-mail is invalid (account: %d, ip: %s)\n", server[id].name, acc, ip); - else - { - ARR_FIND( 0, auth_num, i, auth_dat[i].account_id == acc && (strcmp(auth_dat[i].email, "a@a.com") == 0 || auth_dat[i].email[0] == '\0') ); - if( i == auth_num ) - ShowNotice("Char-server '%s': Attempt to create an e-mail on an account with a default e-mail REFUSED - account doesn't exist or e-mail of account isn't default e-mail (account: %d, ip: %s).\n", server[id].name, acc, ip); - else - { - memcpy(auth_dat[i].email, email, 40); - ShowNotice("Char-server '%s': Create an e-mail on an account with a default e-mail (account: %d, new e-mail: %s, ip: %s).\n", server[id].name, acc, email, ip); - // Save - mmo_auth_sync(); - } - } - } - break; - - case 0x2716: // received an e-mail/limited time request, because a player comes back from a map-server to the char-server - if( RFIFOREST(fd) < 6 ) - return 0; - { - uint32 expiration_time = 0; - char email[40] = ""; - - int account_id = RFIFOL(fd,2); - RFIFOSKIP(fd,6); - - ARR_FIND( 0, auth_num, i, auth_dat[i].account_id == account_id ); - if( i == auth_num ) - ShowNotice("Char-server '%s': e-mail of the account %d NOT found (ip: %s).\n", server[id].name, RFIFOL(fd,2), ip); - else - { - safestrncpy(email, auth_dat[i].email, sizeof(email)); - expiration_time = (uint32)auth_dat[i].expiration_time; - } - - WFIFOHEAD(fd,50); - WFIFOW(fd,0) = 0x2717; - WFIFOL(fd,2) = account_id; - safestrncpy((char*)WFIFOP(fd,6), email, 40); - WFIFOL(fd,46) = expiration_time; - WFIFOSET(fd,50); - } - break; - - case 0x2719: // ping request from charserver - if( RFIFOREST(fd) < 2 ) - return 0; - RFIFOSKIP(fd,2); - - WFIFOHEAD(fd,2); - WFIFOW(fd,0) = 0x2718; - WFIFOSET(fd,2); - break; - - // Map server send information to change an email of an account via char-server - case 0x2722: // 0x2722 .L .40B .40B - if (RFIFOREST(fd) < 86) - return 0; - { - char actual_email[40]; - char new_email[40]; - int account_id = RFIFOL(fd,2); - safestrncpy(actual_email, (char*)RFIFOP(fd,6), 40); remove_control_chars(actual_email); - safestrncpy(new_email, (char*)RFIFOP(fd,46), 40); remove_control_chars(new_email); - RFIFOSKIP(fd, 86); - - if( e_mail_check(actual_email) == 0 ) - ShowNotice("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command), but actual email is invalid (account: %d, ip: %s)\n", server[id].name, account_id, ip); - else if( e_mail_check(new_email) == 0 ) - ShowNotice("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command) with a invalid new e-mail (account: %d, ip: %s)\n", server[id].name, account_id, ip); - else if( strcmpi(new_email, "a@a.com") == 0 ) - ShowNotice("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command) with a default e-mail (account: %d, ip: %s)\n", server[id].name, account_id, ip); - else { - ARR_FIND( 0, auth_num, i, auth_dat[i].account_id == account_id ); - if( i == auth_num ) - ShowNotice("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command), but account doesn't exist (account: %d, ip: %s).\n", server[id].name, account_id, ip); - else - if( strcmpi(auth_dat[i].email, actual_email) != 0 ) - ShowNotice("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command), but actual e-mail is incorrect (account: %d (%s), actual e-mail: %s, proposed e-mail: %s, ip: %s).\n", server[id].name, account_id, auth_dat[i].userid, auth_dat[i].email, actual_email, ip); - else { - safestrncpy(auth_dat[i].email, new_email, 40); - ShowNotice("Char-server '%s': Modify an e-mail on an account (@email GM command) (account: %d (%s), new e-mail: %s, ip: %s).\n", server[id].name, account_id, auth_dat[i].userid, new_email, ip); - // Save - mmo_auth_sync(); - } - } - } - break; - - case 0x2724: // Receiving an account state update request from a map-server (relayed via char-server) - if (RFIFOREST(fd) < 10) - return 0; - { - int account_id = RFIFOL(fd,2); - uint32 state = RFIFOL(fd,6); - RFIFOSKIP(fd,10); - - ARR_FIND( 0, auth_num, i, auth_dat[i].account_id == account_id ); - if( i == auth_num ) - ShowNotice("Char-server '%s': Error of Status change (account: %d not found, suggested status %d, ip: %s).\n", server[id].name, account_id, state, ip); - else - if( auth_dat[i].state == state ) - ShowNotice("Char-server '%s': Error of Status change - actual status is already the good status (account: %d, status %d, ip: %s).\n", server[id].name, account_id, state, ip); - else { - ShowNotice("Char-server '%s': Status change (account: %d, new status %d, ip: %s).\n", server[id].name, account_id, state, ip); - if (state != 0) { - uint8 buf[11]; - WBUFW(buf,0) = 0x2731; - WBUFL(buf,2) = account_id; - WBUFB(buf,6) = 0; // 0: change of state, 1: ban - WBUFL(buf,7) = state; // status or final date of a banishment - charif_sendallwos(-1, buf, 11); - } - auth_dat[i].state = state; - // Save - mmo_auth_sync(); - } - } - break; - - case 0x2725: // Receiving of map-server via char-server a ban request - if (RFIFOREST(fd) < 18) - return 0; - { - int account_id = RFIFOL(fd,2); - int year = (short)RFIFOW(fd,6); - int month = (short)RFIFOW(fd,8); - int mday = (short)RFIFOW(fd,10); - int hour = (short)RFIFOW(fd,12); - int min = (short)RFIFOW(fd,14); - int sec = (short)RFIFOW(fd,16); - RFIFOSKIP(fd,18); - - ARR_FIND( 0, auth_num, i, auth_dat[i].account_id == account_id ); - if( i == auth_num ) - ShowNotice("Char-server '%s': Error of ban request (account: %d not found, ip: %s).\n", server[id].name, account_id, ip); - else - { - time_t timestamp; - struct tm *tmtime; - if (auth_dat[i].unban_time == 0 || auth_dat[i].unban_time < time(NULL)) - timestamp = time(NULL); - else - timestamp = auth_dat[i].unban_time; - tmtime = localtime(×tamp); - tmtime->tm_year = tmtime->tm_year + year; - tmtime->tm_mon = tmtime->tm_mon + month; - tmtime->tm_mday = tmtime->tm_mday + mday; - tmtime->tm_hour = tmtime->tm_hour + hour; - tmtime->tm_min = tmtime->tm_min + min; - tmtime->tm_sec = tmtime->tm_sec + sec; - timestamp = mktime(tmtime); - if (timestamp == -1) - ShowNotice("Char-server '%s': Error of ban request (account: %d, invalid date, ip: %s).\n", server[id].name, account_id, ip); - else - if( timestamp <= time(NULL) || timestamp == 0 ) - ShowNotice("Char-server '%s': Error of ban request (account: %d, new date unbans the account, ip: %s).\n", server[id].name, account_id, ip); - else - { - unsigned char buf[16]; - char tmpstr[2048]; - strftime(tmpstr, 24, login_config.date_format, localtime(×tamp)); - ShowNotice("Char-server '%s': Ban request (account: %d, new final date of banishment: %d (%s), ip: %s).\n", server[id].name, account_id, timestamp, tmpstr, ip); - WBUFW(buf,0) = 0x2731; - WBUFL(buf,2) = auth_dat[i].account_id; - WBUFB(buf,6) = 1; // 0: change of status, 1: ban - WBUFL(buf,7) = (unsigned int)timestamp; // status or final date of a banishment - charif_sendallwos(-1, buf, 11); - auth_dat[i].unban_time = timestamp; - // Save - mmo_auth_sync(); - } - } - } - break; - - case 0x2727: // Change of sex (sex is reversed) - if( RFIFOREST(fd) < 6 ) - return 0; - { - int account_id = RFIFOL(fd,2); - RFIFOSKIP(fd,6); - - ARR_FIND( 0, auth_num, i, auth_dat[i].account_id == account_id ); - if( i == auth_num ) - ShowNotice("Char-server '%s': Error of sex change (account: %d not found, ip: %s).\n", server[id].name, account_id, ip); - else - if( auth_dat[i].sex == 'S' ) - ShowNotice("Char-server '%s': Error of sex change - account to change is a Server account (account: %d, ip: %s).\n", server[id].name, account_id, ip); - else - { - unsigned char buf[7]; - char sex = ( auth_dat[i].sex == 'M' ) ? 'F' : 'M'; //Change gender - - auth_dat[i].sex = sex; - - ShowNotice("Char-server '%s': Sex change (account: %d, new sex %c, ip: %s).\n", server[id].name, account_id, sex, ip); - WBUFW(buf,0) = 0x2723; - WBUFL(buf,2) = account_id; - WBUFB(buf,6) = sex_str2num(sex); - charif_sendallwos(-1, buf, 7); - // Save - mmo_auth_sync(); - } - } - break; - - case 0x2728: // We receive account_reg2 from a char-server, and we send them to other map-servers. - if( RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2) ) - return 0; - { - int acc = RFIFOL(fd,4); - - ARR_FIND( 0, auth_num, i, auth_dat[i].account_id == acc ); - if( i == auth_num ) - ShowStatus("Char-server '%s': receiving (from the char-server) of account_reg2 (account: %d not found, ip: %s).\n", server[id].name, acc, ip); - else - { - int len; - int p; - ShowNotice("char-server '%s': receiving (from the char-server) of account_reg2 (account: %d, ip: %s).\n", server[id].name, acc, ip); - for(j=0,p=13;jforeach(online_db, online_db_setoffline, id); //Set all chars from this char-server offline first - users = RFIFOW(fd,4); - for (i = 0; i < users; i++) { - aid = RFIFOL(fd,6+i*4); - p = (struct online_login_data*)idb_ensure(online_db, aid, create_online_user); - p->char_server = id; - if (p->waiting_disconnect != -1) - { - delete_timer(p->waiting_disconnect, waiting_disconnect_timer); - p->waiting_disconnect = -1; - } - } - } - RFIFOSKIP(fd,RFIFOW(fd,2)); - break; - - case 0x272e: //Request account_reg2 for a character. - if (RFIFOREST(fd) < 10) - return 0; - { - size_t off; - - int account_id = RFIFOL(fd,2); - int char_id = RFIFOL(fd,6); - RFIFOSKIP(fd,10); - - WFIFOHEAD(fd,10000); - WFIFOW(fd,0) = 0x2729; - WFIFOL(fd,4) = account_id; - WFIFOL(fd,8) = char_id; - WFIFOB(fd,12) = 1; //Type 1 for Account2 registry - - ARR_FIND( 0, auth_num, i, auth_dat[i].account_id == account_id ); - if( i == auth_num ) - { - //Account not found? Send at least empty data, map servers need a reply! - WFIFOW(fd,2) = 13; - WFIFOSET(fd,WFIFOW(fd,2)); - break; - } - - for( off = 13, j = 0; j < auth_dat[i].account_reg2_num && off < 9000; j++ ) - { - if( auth_dat[i].account_reg2[j].str[0] != '\0' ) - { - off += sprintf((char*)WFIFOP(fd,off), "%s", auth_dat[i].account_reg2[j].str)+1; //We add 1 to consider the '\0' in place. - off += sprintf((char*)WFIFOP(fd,off), "%s", auth_dat[i].account_reg2[j].value)+1; - } - } - - if( off >= 9000 ) - ShowWarning("Too many account2 registries for AID %d. Some registries were not sent.\n", account_id); - - WFIFOW(fd,2) = (uint16)off; - WFIFOSET(fd,WFIFOW(fd,2)); - } - break; - - case 0x2736: // WAN IP update from char-server - if( RFIFOREST(fd) < 6 ) - return 0; - server[id].ip = ntohl(RFIFOL(fd,2)); - ShowInfo("Updated IP of Server #%d to %d.%d.%d.%d.\n",id, CONVIP(server[id].ip)); - RFIFOSKIP(fd,6); - break; - - case 0x2737: //Request to set all offline. - ShowInfo("Setting accounts from char-server %d offline.\n", id); - online_db->foreach(online_db, online_db_setoffline, id); - RFIFOSKIP(fd,2); - break; - - default: - ShowError("parse_fromchar: Unknown packet 0x%x from a char-server! Disconnecting!\n", command); - set_eof(fd); - return 0; - } // switch - } // while - - RFIFOSKIP(fd,RFIFOREST(fd)); - return 0; -} - -//-------------------------------------------- -// Test to know if an IP come from LAN or WAN. -//-------------------------------------------- -int lan_subnetcheck(uint32 ip) -{ - int i; - ARR_FIND( 0, subnet_count, i, (subnet[i].char_ip & subnet[i].mask) == (ip & subnet[i].mask) ); - return ( i < subnet_count ) ? subnet[i].char_ip : 0; -} - -void login_auth_ok(struct login_session_data* sd) -{ - int fd = sd->fd; - uint32 ip = session[fd]->client_addr; - - uint8 server_num, n; - uint32 subnet_char_ip; - struct auth_node* node; - int i; - - sd->level = isGM(sd->account_id); - - if( sd->level < login_config.min_level_to_connect ) - { - ShowStatus("Connection refused: the minimum GM level for connection is %d (account: %s, GM level: %d).\n", login_config.min_level_to_connect, sd->userid, sd->level); - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x81; - WFIFOB(fd,2) = 1; // 01 = Server closed - WFIFOSET(fd,3); - return; - } - - server_num = 0; - for( i = 0; i < MAX_SERVERS; ++i ) - if( session_isValid(server[i].fd) ) - server_num++; - - if( server_num == 0 ) - {// if no char-server, don't send void list of servers, just disconnect the player with proper message - ShowStatus("Connection refused: there is no char-server online (account: %s).\n", sd->userid); - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x81; - WFIFOB(fd,2) = 1; // 01 = Server closed - WFIFOSET(fd,3); - return; - } - - if( login_config.online_check ) - { - struct online_login_data* data = (struct online_login_data*)idb_get(online_db, sd->account_id); - if( data ) - {// account is already marked as online! - if( data->char_server > -1 ) - {// Request char servers to kick this account out. [Skotlex] - uint8 buf[6]; - ShowNotice("User '%s' is already online - Rejected.\n", sd->userid); - WBUFW(buf,0) = 0x2734; - WBUFL(buf,2) = sd->account_id; - charif_sendallwos(-1, buf, 6); - if( data->waiting_disconnect == -1 ) - data->waiting_disconnect = add_timer(gettick()+AUTH_TIMEOUT, waiting_disconnect_timer, sd->account_id, 0); - - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x81; - WFIFOB(fd,2) = 8; // 08 = Server still recognizes your last login - WFIFOSET(fd,3); - return; - } - else - if( data->char_server == -1 ) - {// client has authed but did not access char-server yet - // wipe previous session - idb_remove(auth_db, sd->account_id); - remove_online_user(sd->account_id); - data = NULL; - } - } - } - - if( sd->level > 0 ) - ShowStatus("Connection of the GM (level:%d) account '%s' accepted.\n", sd->level, sd->userid); - else - ShowStatus("Connection of the account '%s' accepted.\n", sd->userid); - - WFIFOHEAD(fd,47+32*server_num); - WFIFOW(fd,0) = 0x69; - WFIFOW(fd,2) = 47+32*server_num; - WFIFOL(fd,4) = sd->login_id1; - WFIFOL(fd,8) = sd->account_id; - WFIFOL(fd,12) = sd->login_id2; - WFIFOL(fd,16) = 0; // in old version, that was for ip (not more used) - //memcpy(WFIFOP(fd,20), sd->lastlogin, 24); // in old version, that was for name (not more used) - WFIFOW(fd,44) = 0; // unknown - WFIFOB(fd,46) = sex_str2num(sd->sex); - for( i = 0, n = 0; i < MAX_SERVERS; ++i ) - { - if( !session_isValid(server[i].fd) ) - continue; - - subnet_char_ip = lan_subnetcheck(ip); // Advanced subnet check [LuzZza] - WFIFOL(fd,47+n*32) = htonl((subnet_char_ip) ? subnet_char_ip : server[i].ip); - WFIFOW(fd,47+n*32+4) = ntows(htons(server[i].port)); // [!] LE byte order here [!] - memcpy(WFIFOP(fd,47+n*32+6), server[i].name, 20); - WFIFOW(fd,47+n*32+26) = server[i].users; - WFIFOW(fd,47+n*32+28) = server[i].maintenance; - WFIFOW(fd,47+n*32+30) = server[i].new_; - n++; - } - WFIFOSET(fd,47+32*server_num); - - // create temporary auth entry - CREATE(node, struct auth_node, 1); - node->account_id = sd->account_id; - node->login_id1 = sd->login_id1; - node->login_id2 = sd->login_id2; - node->sex = sd->sex; - node->ip = ip; - idb_put(auth_db, sd->account_id, node); - - if( login_config.online_check ) - { - struct online_login_data* data; - - // mark client as 'online' - data = add_online_user(-1, sd->account_id); - - // schedule deletion of this node - data->waiting_disconnect = add_timer(gettick()+AUTH_TIMEOUT, waiting_disconnect_timer, sd->account_id, 0); - } -} - -void login_auth_failed(struct login_session_data* sd, int result) -{ - int fd = sd->fd; - - WFIFOHEAD(fd,23); - WFIFOW(fd,0) = 0x6a; - WFIFOB(fd,2) = (uint8)result; - if( result != 6 ) - memset(WFIFOP(fd,3), '\0', 20); - else - {// 6 = Your are Prohibited to log in until %s - char tmpstr[20]; - int i = search_account_index(sd->userid); - time_t unban_time = ( i >= 0 ) ? auth_dat[i].unban_time : 0; - strftime(tmpstr, 20, login_config.date_format, localtime(&unban_time)); - safestrncpy((char*)WFIFOP(fd,3), tmpstr, 20); // ban timestamp goes here - } - WFIFOSET(fd,23); -} - -//---------------------------------------------------------------------------------------- -// Default packet parsing (normal players or administation/char-server connection requests) -//---------------------------------------------------------------------------------------- -int parse_login(int fd) -{ - struct login_session_data* sd = session[fd]->session_data; - int result; - uint32 ipl; - char ip[16]; - - if( session[fd]->flag.eof ) - { - do_close(fd); - return 0; - } - - if( sd == NULL ) { - sd = CREATE(session[fd]->session_data, struct login_session_data, 1); - sd->fd = fd; - } - - ipl = session[fd]->client_addr; - ip2str(ipl, ip); - - while( RFIFOREST(fd) >= 2 ) - { - uint16 command = RFIFOW(fd,0); - - switch( command ) - { - - case 0x0200: // New alive packet: structure: 0x200 .24B. used to verify if client is always alive. - if (RFIFOREST(fd) < 26) - return 0; - RFIFOSKIP(fd,26); - break; - - case 0x0204: // New alive packet: structure: 0x204 .16B. (new ragexe from 22 june 2004) - if (RFIFOREST(fd) < 18) - return 0; - RFIFOSKIP(fd,18); - break; - - case 0x0064: // request client login - case 0x01dd: // request client login (encryption mode) - case 0x0277: // New login packet (kRO 2006-04-24aSakexe langtype 0) - case 0x02b0: // New login packet (kRO 2007-05-14aSakexe langtype 0) - { - size_t packet_len = RFIFOREST(fd); // assume no other packet was sent - - if( (command == 0x0064 && packet_len < 55) - || (command == 0x01dd && packet_len < 47) - || (command == 0x0277 && packet_len < 84) - || (command == 0x02b0 && packet_len < 85) ) - return 0; - - // S 0064 .l .24B .24B .B - // S 01dd .l .24B .16B .B - // S 0277 .l .24B .24B .29B .B - // S 02b0 .l .24B .24B .30B .B - - sd->version = RFIFOL(fd,2); - safestrncpy(sd->userid, (char*)RFIFOP(fd,6), NAME_LENGTH); remove_control_chars(sd->userid); - if (command != 0x01dd) { - ShowStatus("Request for connection of %s (ip: %s).\n", sd->userid, ip); - safestrncpy(sd->passwd, (char*)RFIFOP(fd,30), NAME_LENGTH); remove_control_chars(sd->passwd); - sd->passwdenc = 0; - } else { - ShowStatus("Request for connection (encryption mode) of %s (ip: %s).\n", sd->userid, ip); - memcpy(sd->passwd, RFIFOP(fd,30), 16); sd->passwd[16] = '\0'; // raw binary data here! - sd->passwdenc = PASSWORDENC; - } - RFIFOSKIP(fd,packet_len); - - result = mmo_auth(sd); - - if( result == -1 ) - login_auth_ok(sd); - else - login_auth_failed(sd, result); - } - break; - - case 0x01db: // Sending request of the coding key - case 0x791a: // Sending request of the coding key (administration packet) - RFIFOSKIP(fd,2); - { - unsigned int i; - - memset(sd->md5key, '\0', sizeof(sd->md5key)); - sd->md5keylen = (uint16)(12 + rand() % 4); - for( i = 0; i < sd->md5keylen; ++i ) - sd->md5key[i] = (char)(1 + rand() % 255); - - WFIFOHEAD(fd,4 + sd->md5keylen); - WFIFOW(fd,0) = 0x01dc; - WFIFOW(fd,2) = 4 + sd->md5keylen; - memcpy(WFIFOP(fd,4), sd->md5key, sd->md5keylen); - WFIFOSET(fd,WFIFOW(fd,2)); - } - break; - - case 0x2710: // Connection request of a char-server - if (RFIFOREST(fd) < 86) - return 0; - { - char server_name[20]; - uint32 server_ip; - uint16 server_port; - uint16 maintenance; - uint16 new_; - - safestrncpy(sd->userid, (char*)RFIFOP(fd,2), NAME_LENGTH); //remove_control_chars(account.userid); - safestrncpy(sd->passwd, (char*)RFIFOP(fd,26), NAME_LENGTH); //remove_control_chars(account.passwd); - sd->passwdenc = 0; - sd->version = login_config.client_version_to_connect; // hack to skip version check - - server_ip = ntohl(RFIFOL(fd,54)); - server_port = ntohs(RFIFOW(fd,58)); - - safestrncpy(server_name, (char*)RFIFOP(fd,60), 20); remove_control_chars(server_name); - maintenance = RFIFOW(fd,82); - new_ = RFIFOW(fd,84); - RFIFOSKIP(fd,86); - - ShowInfo("Connection request of the char-server '%s' @ %d.%d.%d.%d:%d (account: '%s', pass: '%s', ip: '%s')\n", server_name, CONVIP(server_ip), server_port, sd->userid, sd->passwd, ip); - - result = mmo_auth(sd); - if( result == -1 && sd->sex == 'S' && sd->account_id < MAX_SERVERS && server[sd->account_id].fd == -1 ) - { - ShowStatus("Connection of the char-server '%s' accepted.\n", server_name); - safestrncpy(server[sd->account_id].name, server_name, sizeof(server[sd->account_id].name)); - server[sd->account_id].fd = fd; - server[sd->account_id].ip = server_ip; - server[sd->account_id].port = server_port; - server[sd->account_id].users = 0; - server[sd->account_id].maintenance = maintenance; - server[sd->account_id].new_ = new_; - - session[fd]->func_parse = parse_fromchar; - session[fd]->flag.server = 1; - realloc_fifo(fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK); - - // send connection success - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x2711; - WFIFOB(fd,2) = 0; - WFIFOSET(fd,3); - - // send GM account to char-server - send_GM_accounts(fd); - } - else - { - ShowNotice("Connection of the char-server '%s' REFUSED.\n", server_name); - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x2711; - WFIFOB(fd,2) = 3; - WFIFOSET(fd,3); - } - } - return 0; // processing will continue elsewhere - - case 0x7530: // Server version information request - ShowStatus("Sending server version information to ip: %s\n", ip); - RFIFOSKIP(fd,2); - WFIFOHEAD(fd,10); - WFIFOW(fd,0) = 0x7531; - WFIFOB(fd,2) = ATHENA_MAJOR_VERSION; - WFIFOB(fd,3) = ATHENA_MINOR_VERSION; - WFIFOB(fd,4) = ATHENA_REVISION; - WFIFOB(fd,5) = ATHENA_RELEASE_FLAG; - WFIFOB(fd,6) = ATHENA_OFFICIAL_FLAG; - WFIFOB(fd,7) = ATHENA_SERVER_LOGIN; - WFIFOW(fd,8) = ATHENA_MOD_VERSION; - WFIFOSET(fd,10); - break; - - case 0x7918: // Request for administation login - if ((int)RFIFOREST(fd) < 4 || (int)RFIFOREST(fd) < ((RFIFOW(fd,2) == 0) ? 28 : 20)) - return 0; - WFIFOW(fd,0) = 0x7919; - WFIFOB(fd,2) = 1; - if( session[fd]->client_addr != admin_allowed_ip ) { - ShowNotice("'ladmin'-login: Connection in administration mode refused: IP isn't authorised (ladmin_allow, ip: %s).\n", ip); - } else { - struct login_session_data *ld = (struct login_session_data*)session[fd]->session_data; - if (RFIFOW(fd,2) == 0) { // non encrypted password - char password[25]; - memcpy(password, RFIFOP(fd,4), 24); - password[24] = '\0'; - remove_control_chars(password); - if( !admin_state ) - ShowNotice("'ladmin'-login: Connection in administration mode REFUSED - remote administration is disabled (non encrypted password: %s, ip: %s)\n", password, ip); - else - if( strcmp(password, admin_pass) != 0) - ShowNotice("'ladmin'-login: Connection in administration mode REFUSED - invalid password (non encrypted password: %s, ip: %s)\n", password, ip); - else { - // If remote administration is enabled and password sent by client matches password read from login server configuration file - ShowNotice("'ladmin'-login: Connection in administration mode accepted (non encrypted password: %s, ip: %s)\n", password, ip); - WFIFOB(fd,2) = 0; - session[fd]->func_parse = parse_admin; - } - } else { // encrypted password - if (!ld) - ShowError("'ladmin'-login: error! MD5 key not created/requested for an administration login.\n"); - else { - char md5str[64] = "", md5bin[32]; - if (RFIFOW(fd,2) == 1) { - sprintf(md5str, "%s%s", ld->md5key, admin_pass); // 20 24 - } else if (RFIFOW(fd,2) == 2) { - sprintf(md5str, "%s%s", admin_pass, ld->md5key); // 24 20 - } - MD5_String2binary(md5str, md5bin); - if( !admin_state ) - ShowNotice("'ladmin'-login: Connection in administration mode REFUSED - remote administration is disabled (encrypted password, ip: %s)\n", ip); - else - if( memcmp(md5bin, RFIFOP(fd,4), 16) != 0 ) - ShowNotice("'ladmin'-login: Connection in administration mode REFUSED - invalid password (encrypted password, ip: %s)\n", ip); - else { - // If remote administration is enabled and password hash sent by client matches hash of password read from login server configuration file - ShowNotice("'ladmin'-login: Connection in administration mode accepted (encrypted password, ip: %s)\n", ip); - ShowNotice("Connection of a remote administration accepted (encrypted password).\n"); - WFIFOB(fd,2) = 0; - session[fd]->func_parse = parse_admin; - } - } - } - } - WFIFOSET(fd,3); - - RFIFOSKIP(fd, (RFIFOW(fd,2) == 0) ? 28 : 20); - break; - - default: - ShowNotice("Abnormal end of connection (ip: %s): Unknown packet 0x%x\n", ip, command); - set_eof(fd); - return 0; - } - } - - RFIFOSKIP(fd,RFIFOREST(fd)); - return 0; -} - -//----------------------- -// Console Command Parser [Wizputer] -//----------------------- -int parse_console(char* buf) -{ - char command[256]; - - memset(command, 0, sizeof(command)); - - sscanf(buf, "%[^\n]", command); - - ShowInfo("Console command :%s", command); - - if( strcmpi("shutdown", command) == 0 || - strcmpi("exit", command) == 0 || - strcmpi("quit", command) == 0 || - strcmpi("end", command) == 0 ) - runflag = 0; - else - if( strcmpi("alive", command) == 0 || - strcmpi("status", command) == 0 ) - ShowInfo(CL_CYAN"Console: "CL_BOLD"I'm Alive."CL_RESET"\n"); - else - if( strcmpi("help", command) == 0 ) { - ShowInfo(CL_BOLD"Help of commands:"CL_RESET"\n"); - ShowInfo(" To shutdown the server:\n"); - ShowInfo(" 'shutdown|exit|quit|end'\n"); - ShowInfo(" To know if server is alive:\n"); - ShowInfo(" 'alive|status'\n"); - } - - return 0; -} - -static int online_data_cleanup_sub(DBKey key, void *data, va_list ap) -{ - struct online_login_data *character= (struct online_login_data*)data; - if (character->char_server == -2) //Unknown server.. set them offline - remove_online_user(character->account_id); - return 0; -} - -static int online_data_cleanup(int tid, unsigned int tick, int id, int data) -{ - online_db->foreach(online_db, online_data_cleanup_sub); - return 0; -} - -//---------------------------------- -// Reading Lan Support configuration -//---------------------------------- -int login_lan_config_read(const char *lancfgName) -{ - FILE *fp; - int line_num = 0; - char line[1024], w1[64], w2[64], w3[64], w4[64]; - - if((fp = fopen(lancfgName, "r")) == NULL) { - ShowWarning("LAN Support configuration file is not found: %s\n", lancfgName); - return 1; - } - - ShowInfo("Reading the configuration file %s...\n", lancfgName); - - while(fgets(line, sizeof(line), fp)) - { - line_num++; - if ((line[0] == '/' && line[1] == '/') || line[0] == '\n' || line[1] == '\n') - continue; - - if(sscanf(line,"%[^:]: %[^:]:%[^:]:%[^\r\n]", w1, w2, w3, w4) != 4) - { - ShowWarning("Error syntax of configuration file %s in line %d.\n", lancfgName, line_num); - continue; - } - - if( strcmpi(w1, "subnet") == 0 ) - { - subnet[subnet_count].mask = str2ip(w2); - subnet[subnet_count].char_ip = str2ip(w3); - subnet[subnet_count].map_ip = str2ip(w4); - - if( (subnet[subnet_count].char_ip & subnet[subnet_count].mask) != (subnet[subnet_count].map_ip & subnet[subnet_count].mask) ) - { - ShowError("%s: Configuration Error: The char server (%s) and map server (%s) belong to different subnetworks!\n", lancfgName, w3, w4); - continue; - } - - subnet_count++; - } - } - - ShowStatus("Read information about %d subnetworks.\n", subnet_count); - - fclose(fp); - return 0; -} - -//----------------------------------- -// Reading main configuration file -//----------------------------------- -int login_config_read(const char* cfgName) -{ - char line[1024], w1[1024], w2[1024]; - FILE* fp = fopen(cfgName, "r"); - if (fp == NULL) { - ShowError("Configuration file (%s) not found.\n", cfgName); - return 1; - } - ShowInfo("Reading configuration file %s...\n", cfgName); - while(fgets(line, sizeof(line), fp)) - { - if (line[0] == '/' && line[1] == '/') - continue; - - if (sscanf(line, "%[^:]: %[^\r\n]", w1, w2) < 2) - continue; - - if(!strcmpi(w1,"timestamp_format")) - strncpy(timestamp_format, w2, 20); - else if(!strcmpi(w1,"stdout_with_ansisequence")) - stdout_with_ansisequence = config_switch(w2); - else if(!strcmpi(w1,"console_silent")) { - ShowInfo("Console Silent Setting: %d\n", atoi(w2)); - msg_silent = atoi(w2); - } - else if( !strcmpi(w1, "bind_ip") ) { - char ip_str[16]; - login_config.login_ip = host2ip(w2); - if( login_config.login_ip ) - ShowStatus("Login server binding IP address : %s -> %s\n", w2, ip2str(login_config.login_ip, ip_str)); - } - else if( !strcmpi(w1, "login_port") ) { - login_config.login_port = (uint16)atoi(w2); - ShowStatus("set login_port : %s\n",w2); - } - else if(!strcmpi(w1, "log_login")) - login_config.log_login = (bool)config_switch(w2); - - else if (strcmpi(w1, "admin_state") == 0) { - admin_state = (bool)config_switch(w2); - } else if (strcmpi(w1, "admin_pass") == 0) { - memset(admin_pass, 0, sizeof(admin_pass)); - strncpy(admin_pass, w2, sizeof(admin_pass)); - admin_pass[sizeof(admin_pass)-1] = '\0'; - } else if (strcmpi(w1, "admin_allowed_ip") == 0) - admin_allowed_ip = host2ip(w2); - else if (strcmpi(w1, "account_filename") == 0) { - memset(account_filename, 0, sizeof(account_filename)); - strncpy(account_filename, w2, sizeof(account_filename)); - account_filename[sizeof(account_filename)-1] = '\0'; - } else if (strcmpi(w1, "gm_account_filename") == 0) { - memset(GM_account_filename, 0, sizeof(GM_account_filename)); - strncpy(GM_account_filename, w2, sizeof(GM_account_filename)); - GM_account_filename[sizeof(GM_account_filename)-1] = '\0'; - } - else if (strcmpi(w1, "gm_account_filename_check_timer") == 0) - gm_account_filename_check_timer = atoi(w2); - - else if(!strcmpi(w1, "new_account")) - login_config.new_account_flag = (bool)config_switch(w2); - else if(!strcmpi(w1, "start_limited_time")) - login_config.start_limited_time = atoi(w2); - else if(!strcmpi(w1, "check_client_version")) - login_config.check_client_version = (bool)config_switch(w2); - else if(!strcmpi(w1, "client_version_to_connect")) - login_config.client_version_to_connect = atoi(w2); - else if(!strcmpi(w1, "use_MD5_passwords")) - login_config.use_md5_passwds = (bool)config_switch(w2); - else if(!strcmpi(w1, "min_level_to_connect")) - login_config.min_level_to_connect = atoi(w2); - else if(!strcmpi(w1, "date_format")) - safestrncpy(login_config.date_format, w2, sizeof(login_config.date_format)); - else if(!strcmpi(w1, "console")) - login_config.console = (bool)config_switch(w2); -// else if(!strcmpi(w1, "case_sensitive")) -// login_config.case_sensitive = config_switch(w2); - else if(!strcmpi(w1, "allowed_regs")) //account flood protection system - allowed_regs = atoi(w2); - else if(!strcmpi(w1, "time_allowed")) - time_allowed = atoi(w2); - else if(!strcmpi(w1, "online_check")) - login_config.online_check = (bool)config_switch(w2); - else if(!strcmpi(w1, "use_dnsbl")) - login_config.use_dnsbl = (bool)config_switch(w2); - else if(!strcmpi(w1, "dnsbl_servers")) - safestrncpy(login_config.dnsbl_servs, w2, sizeof(login_config.dnsbl_servs)); - else if(!strcmpi(w1, "ip_sync_interval")) - login_config.ip_sync_interval = (unsigned int)1000*60*atoi(w2); //w2 comes in minutes. - else if(!strcmpi(w1, "import")) - login_config_read(w2); - } - fclose(fp); - ShowInfo("Finished reading %s.\n", cfgName); - return 0; -} - -//------------------------------------- -// Displaying of configuration warnings -//------------------------------------- -void display_conf_warnings(void) -{ - if( admin_state ) { - if (admin_pass[0] == '\0') { - ShowWarning("Administrator password is void (admin_pass).\n"); - } else if (strcmp(admin_pass, "admin") == 0) { - ShowWarning("You are using the default administrator password (admin_pass).\n"); - ShowWarning(" We highly recommend that you change it.\n"); - } - } - - if (gm_account_filename_check_timer < 0) { - ShowWarning("Invalid value for gm_account_filename_check_timer parameter. Setting to 15 sec (default).\n"); - gm_account_filename_check_timer = 15; - } else if (gm_account_filename_check_timer == 1) { - ShowWarning("Invalid value for gm_account_filename_check_timer parameter. Setting to 2 sec (minimum value).\n"); - gm_account_filename_check_timer = 2; - } - - if (login_config.min_level_to_connect < 0) { // 0: all players, 1-99 at least gm level x - ShowWarning("Invalid value for min_level_to_connect (%d) parameter -> setting 0 (any player).\n", login_config.min_level_to_connect); - login_config.min_level_to_connect = 0; - } else if (login_config.min_level_to_connect > 99) { // 0: all players, 1-99 at least gm level x - ShowWarning("Invalid value for min_level_to_connect (%d) parameter -> setting to 99 (only GM level 99)\n", login_config.min_level_to_connect); - login_config.min_level_to_connect = 99; - } - - if (login_config.start_limited_time < -1) { // -1: create unlimited account, 0 or more: additionnal sec from now to create limited time - ShowWarning("Invalid value for start_limited_time parameter\n"); - ShowWarning(" -> setting to -1 (new accounts are created with unlimited time).\n"); - login_config.start_limited_time = -1; - } - - return; -} - -void login_set_defaults() -{ - login_config.login_ip = INADDR_ANY; - login_config.login_port = 6900; - login_config.ip_sync_interval = 0; - login_config.log_login = true; - safestrncpy(login_config.date_format, "%Y-%m-%d %H:%M:%S", sizeof(login_config.date_format)); - login_config.console = false; - login_config.new_account_flag = true; -// login_config.case_sensitive = true; - login_config.use_md5_passwds = false; -// login_config.login_gm_read = true; - login_config.min_level_to_connect = 0; - login_config.online_check = true; - login_config.check_client_version = false; - login_config.client_version_to_connect = 20; - -// login_config.ipban = true; -// login_config.dynamic_pass_failure_ban = true; -// login_config.dynamic_pass_failure_ban_interval = 5; -// login_config.dynamic_pass_failure_ban_limit = 7; -// login_config.dynamic_pass_failure_ban_duration = 5; - login_config.use_dnsbl = false; - safestrncpy(login_config.dnsbl_servs, "", sizeof(login_config.dnsbl_servs)); -} - -//-------------------------------------- -// Function called at exit of the server -//-------------------------------------- -void do_final(void) -{ - int i, fd; - ShowStatus("Terminating...\n"); - - mmo_auth_sync(); - online_db->destroy(online_db, NULL); - auth_db->destroy(auth_db, NULL); - - if(auth_dat) aFree(auth_dat); - if(gm_account_db) aFree(gm_account_db); - - for (i = 0; i < MAX_SERVERS; i++) { - if ((fd = server[i].fd) >= 0) { - memset(&server[i], 0, sizeof(struct mmo_char_server)); - server[i].fd = -1; - do_close(fd); - } - } - do_close(login_fd); - - ShowStatus("Finished.\n"); -} - -//------------------------------ -// Function called when the server -// has received a crash signal. -//------------------------------ -void do_abort(void) -{ -} - -void set_server_type(void) -{ - SERVER_TYPE = ATHENA_SERVER_LOGIN; -} - -//------------------------------ -// Login server initialization -//------------------------------ -int do_init(int argc, char** argv) -{ - int i; - - login_set_defaults(); - - // read login-server configuration - login_config_read((argc > 1) ? argv[1] : LOGIN_CONF_NAME); - display_conf_warnings(); // not in login_config_read, because we can use 'import' option, and display same message twice or more - login_lan_config_read((argc > 2) ? argv[2] : LAN_CONF_NAME); - - srand((unsigned int)time(NULL)); - - for( i = 0; i < MAX_SERVERS; i++ ) - server[i].fd = -1; - - // Accounts database init - mmo_auth_init(); - - // Online user database init - online_db = idb_alloc(DB_OPT_RELEASE_DATA); - add_timer_func_list(waiting_disconnect_timer, "waiting_disconnect_timer"); - - // Interserver auth init - auth_db = idb_alloc(DB_OPT_RELEASE_DATA); - - // Read account information. - read_gm_account(); - - // set default parser as parse_login function - set_defaultparse(parse_login); - - add_timer_func_list(check_auth_sync, "check_auth_sync"); - add_timer_interval(gettick() + 60000, check_auth_sync, 0, 0, 60000); // every 60 sec we check if we must save accounts file (only if necessary to save) - - // every x sec we check if gm file has been changed - if( gm_account_filename_check_timer ) { - add_timer_func_list(check_GM_file, "check_GM_file"); - add_timer_interval(gettick() + gm_account_filename_check_timer * 1000, check_GM_file, 0, 0, gm_account_filename_check_timer * 1000); - } - - // every 10 minutes cleanup online account db. - add_timer_func_list(online_data_cleanup, "online_data_cleanup"); - add_timer_interval(gettick() + 600*1000, online_data_cleanup, 0, 0, 600*1000); - - // add timer to detect ip address change and perform update - if (login_config.ip_sync_interval) { - add_timer_func_list(sync_ip_addresses, "sync_ip_addresses"); - add_timer_interval(gettick() + login_config.ip_sync_interval, sync_ip_addresses, 0, 0, login_config.ip_sync_interval); - } - - if( login_config.console ) - { - //##TODO invoke a CONSOLE_START plugin event - } - - new_reg_tick = gettick(); - - // server port open & binding - login_fd = make_listen_bind(login_config.login_ip, login_config.login_port); - - ShowStatus("The login-server is "CL_GREEN"ready"CL_RESET" (Server is listening on the port %u).\n\n", login_config.login_port); - - return 0; -} diff --git a/src/login/login.h b/src/login/login.h deleted file mode 100644 index 1147d6bb6..000000000 --- a/src/login/login.h +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder - -#ifndef _LOGIN_H_ -#define _LOGIN_H_ - -#include "../common/mmo.h" // NAME_LENGTH - -#define LOGIN_CONF_NAME "conf/login_athena.conf" -#define LAN_CONF_NAME "conf/subnet_athena.conf" - -// supported encryption types: 1- passwordencrypt, 2- passwordencrypt2, 3- both -#define PASSWORDENC 3 - -struct login_session_data { - - int account_id; - long login_id1; - long login_id2; - char sex; - - char userid[NAME_LENGTH]; - char passwd[NAME_LENGTH]; - int passwdenc; - char md5key[20]; - uint16 md5keylen; - - char lastlogin[24]; - uint8 level; - int version; - - int fd; -}; - -struct mmo_char_server { - - char name[20]; - int fd; - uint32 ip; - uint16 port; - uint16 users; // user count on this server - uint16 maintenance; // in maintenance mode? - uint16 new_; // allows creating new chars? -}; - -struct Login_Config { - - uint32 login_ip; // the address to bind to - uint16 login_port; // the port to bind to - unsigned int ip_sync_interval; // interval (in minutes) to execute a DNS/IP update (for dynamic IPs) - bool log_login; // whether to log login server actions or not - char date_format[32]; // date format used in messages - bool console; // console input system enabled? - bool new_account_flag; // autoregistration via _M/_F ? - int start_limited_time; // new account expiration time (-1: unlimited) -// bool case_sensitive; // are logins case sensitive ? - bool use_md5_passwds; // work with password hashes instead of plaintext passwords? -// bool login_gm_read; // should the login server handle info about gm accounts? - int min_level_to_connect; // minimum level of player/GM (0: player, 1-99: GM) to connect - bool online_check; // reject incoming players that are already registered as online ? - bool check_client_version; // check the clientversion set in the clientinfo ? - int client_version_to_connect; // the client version needed to connect (if checking is enabled) - -// bool ipban; // perform IP blocking (via contents of `ipbanlist`) ? -// bool dynamic_pass_failure_ban; // automatic IP blocking due to failed login attemps ? -// unsigned int dynamic_pass_failure_ban_interval; // how far to scan the loginlog for password failures -// unsigned int dynamic_pass_failure_ban_limit; // number of failures needed to trigger the ipban -// unsigned int dynamic_pass_failure_ban_duration; // duration of the ipban - bool use_dnsbl; // dns blacklist blocking ? - char dnsbl_servs[1024]; // comma-separated list of dnsbl servers - -}; - -struct mmo_account { - - int account_id; - char sex; - char userid[24]; - char pass[32+1]; // 23+1 for normal, 32+1 for md5-ed passwords - char lastlogin[24]; - int logincount; - uint32 state; // packet 0x006a value + 1 (0: compte OK) - char email[40]; // e-mail (by default: a@a.com) - char error_message[20]; // Message of error code #6 = Your are Prohibited to log in until %s (packet 0x006a) - time_t unban_time; // # of seconds 1/1/1970 (timestamp): ban time limit of the account (0 = no ban) - time_t expiration_time; // # of seconds 1/1/1970 (timestamp): Validity limit of the account (0 = unlimited) - char last_ip[16]; // save of last IP of connection - char memo[255]; // a memo field - int account_reg2_num; - struct global_reg account_reg2[ACCOUNT_REG2_NUM]; // account script variables (stored on login server) -}; - - -#endif /* _LOGIN_H_ */ -- cgit v1.2.3-70-g09d2 From 81472b872dfc7f8e22361c7e2fdde2d8f03cf3ce Mon Sep 17 00:00:00 2001 From: Kevin Date: Sat, 12 Apr 2008 08:43:29 +0000 Subject: TXT code has been re uploaded. Please note this does not change the fact that TXT support has been dropped. There is no guarantee the code base will be managed and it will in the near future be REMOVED. If there is in ANY way TXT support in the future, it will be abstracted through a sql interface so only the sql code has to be maintained. git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@12572 54d463be-8e91-2dee-dedb-b68131a5f0ec --- src/char/Makefile.in | 47 + src/char/char.c | 4290 ++++++++++++++++++++++++++++++++++++++++++++++++ src/char/char.h | 54 + src/char/int_guild.c | 1579 ++++++++++++++++++ src/char/int_guild.h | 26 + src/char/int_homun.c | 365 ++++ src/char/int_homun.h | 15 + src/char/int_party.c | 732 +++++++++ src/char/int_party.h | 20 + src/char/int_pet.c | 380 +++++ src/char/int_pet.h | 21 + src/char/int_status.c | 183 +++ src/char/int_status.h | 23 + src/char/int_storage.c | 481 ++++++ src/char/int_storage.h | 25 + src/char/inter.c | 711 ++++++++ src/char/inter.h | 30 + src/login/Makefile.in | 46 + src/login/admin.c | 879 ++++++++++ src/login/login.c | 2362 ++++++++++++++++++++++++++ src/login/login.h | 94 ++ 21 files changed, 12363 insertions(+) create mode 100644 src/char/Makefile.in create mode 100644 src/char/char.c create mode 100644 src/char/char.h create mode 100644 src/char/int_guild.c create mode 100644 src/char/int_guild.h create mode 100644 src/char/int_homun.c create mode 100644 src/char/int_homun.h create mode 100644 src/char/int_party.c create mode 100644 src/char/int_party.h create mode 100644 src/char/int_pet.c create mode 100644 src/char/int_pet.h create mode 100644 src/char/int_status.c create mode 100644 src/char/int_status.h create mode 100644 src/char/int_storage.c create mode 100644 src/char/int_storage.h create mode 100644 src/char/inter.c create mode 100644 src/char/inter.h create mode 100644 src/login/Makefile.in create mode 100644 src/login/admin.c create mode 100644 src/login/login.c create mode 100644 src/login/login.h (limited to 'src/char/Makefile.in') diff --git a/src/char/Makefile.in b/src/char/Makefile.in new file mode 100644 index 000000000..7835daa7f --- /dev/null +++ b/src/char/Makefile.in @@ -0,0 +1,47 @@ + +COMMON_OBJ = ../common/obj_all/core.o ../common/obj_all/socket.o ../common/obj_all/timer.o \ + ../common/obj_all/db.o ../common/obj_all/plugins.o ../common/obj_all/lock.o \ + ../common/obj_all/malloc.o ../common/obj_all/showmsg.o ../common/obj_all/utils.o \ + ../common/obj_all/strlib.o ../common/obj_all/grfio.o \ + ../common/obj_all/mapindex.o ../common/obj_all/ers.o +COMMON_H = ../common/core.h ../common/socket.h ../common/timer.h ../common/mmo.h \ + ../common/version.h ../common/db.h ../common/plugins.h ../common/lock.h \ + ../common/malloc.h ../common/showmsg.h ../common/utils.h \ + ../common/strlib.h ../common/grfio.h \ + ../common/mapindex.h ../common/ers.h + +CHAR_OBJ = obj_txt/char.o obj_txt/inter.o obj_txt/int_party.o obj_txt/int_guild.o \ + obj_txt/int_storage.o obj_txt/int_status.o obj_txt/int_pet.o obj_txt/int_homun.o +CHAR_H = char.h inter.h int_party.h int_guild.h int_storage.h int_status.h int_pet.h int_homun.h + +@SET_MAKE@ + +##################################################################### +.PHONY : all char-server clean help + +all: char-server + +char-server: obj_txt $(CHAR_OBJ) $(COMMON_OBJ) + @CC@ @LDFLAGS@ -o ../../char-server@EXEEXT@ $(CHAR_OBJ) $(COMMON_OBJ) @LIBS@ + +clean: + rm -rf *.o obj_txt ../../char-server@EXEEXT@ + +help: + @echo "possible targets are 'char-server' 'all' 'clean' 'help'" + @echo "'char-server' - char server (TXT version)" + @echo "'all' - builds all above targets" + @echo "'clean' - cleans builds and objects" + @echo "'help' - outputs this message" + +##################################################################### + +obj_txt: + -mkdir obj_txt + +obj_txt/%.o: %.c $(CHAR_H) $(COMMON_H) + @CC@ @CFLAGS@ $(CUSTOM_CFLAGS) -DTXT_ONLY @CPPFLAGS@ -c $(OUTPUT_OPTION) $< + +# missing common object files +../common/obj_all/%.o: + @$(MAKE) -C ../common txt diff --git a/src/char/char.c b/src/char/char.c new file mode 100644 index 000000000..13da079ab --- /dev/null +++ b/src/char/char.c @@ -0,0 +1,4290 @@ +// Copyright (c) Athena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + +#include "../common/cbasetypes.h" +#include "../common/mmo.h" +#include "../common/db.h" +#include "../common/lock.h" +#include "../common/malloc.h" +#include "../common/core.h" +#include "../common/socket.h" +#include "../common/strlib.h" +#include "../common/showmsg.h" +#include "../common/timer.h" +#include "../common/lock.h" +#include "../common/malloc.h" +#include "../common/mapindex.h" +#include "../common/showmsg.h" +#include "../common/utils.h" +#include "../common/version.h" +#include "inter.h" +#include "int_guild.h" +#include "int_homun.h" +#include "int_pet.h" +#include "int_party.h" +#include "int_storage.h" +#include "int_status.h" +#include "char.h" + +#include +#ifdef WIN32 +#include +#else +#include +#include +#include +#endif +#include +#include +#include +#include +#include +#include +#include + +// private declarations +#define CHAR_CONF_NAME "conf/char_athena.conf" +#define LAN_CONF_NAME "conf/subnet_athena.conf" + +char char_txt[1024] = "save/athena.txt"; +char friends_txt[1024] = "save/friends.txt"; +char hotkeys_txt[1024] = "save/hotkeys.txt"; +char char_log_filename[1024] = "log/char.log"; + +int save_log = 1; // show loading/saving messages + +#ifndef TXT_SQL_CONVERT +char db_path[1024] = "db"; + +struct mmo_map_server { + int fd; + uint32 ip; + uint16 port; + int users; + unsigned short map[MAX_MAP_PER_SERVER]; +} server[MAX_MAP_SERVERS]; + +int login_fd=-1, char_fd=-1; +char userid[24]; +char passwd[24]; +char server_name[20]; +char wisp_server_name[NAME_LENGTH] = "Server"; +char login_ip_str[128]; +uint32 login_ip = 0; +uint16 login_port = 6900; +char char_ip_str[128]; +uint32 char_ip = 0; +char bind_ip_str[128]; +uint32 bind_ip = INADDR_ANY; +uint16 char_port = 6121; +int char_maintenance = 0; +bool char_new = true; +int char_new_display = 0; + +int email_creation = 0; // disabled by default + +bool name_ignoring_case = false; // Allow or not identical name for characters but with a different case by [Yor] +int char_name_option = 0; // Option to know which letters/symbols are authorised in the name of a character (0: all, 1: only those in char_name_letters, 2: all EXCEPT those in char_name_letters) by [Yor] +char unknown_char_name[1024] = "Unknown"; // Name to use when the requested name cannot be determined +#define TRIM_CHARS "\032\t\x0A\x0D " //The following characters are trimmed regardless because they cause confusion and problems on the servers. [Skotlex] +char char_name_letters[1024] = ""; // list of letters/symbols authorised (or not) in a character name. by [Yor] +bool char_rename = true; + +int log_char = 1; // loggin char or not [devil] +int log_inter = 1; // loggin inter or not [devil] + +static int online_check = 1; //If one, it won't let players connect when their account is already registered online and will send the relevant map server a kick user request. [Skotlex] + +// Advanced subnet check [LuzZza] +struct s_subnet { + uint32 mask; + uint32 char_ip; + uint32 map_ip; +} subnet[16]; +int subnet_count = 0; + +struct char_session_data { + bool auth; // whether the session is authed or not + int account_id, login_id1, login_id2, sex; + int found_char[MAX_CHARS]; // ids of chars on this account + char email[40]; // e-mail (default: a@a.com) by [Yor] + time_t expiration_time; // # of seconds 1/1/1970 (timestamp): Validity limit of the account (0 = unlimited) +}; + +int char_id_count = START_CHAR_NUM; +struct character_data *char_dat; + +int char_num, char_max; +int max_connect_user = 0; +int gm_allow_level = 99; +int autosave_interval = DEFAULT_AUTOSAVE_INTERVAL; +int start_zeny = 500; +int start_weapon = 1201; +int start_armor = 2301; +int guild_exp_rate = 100; + +//Custom limits for the fame lists. [Skotlex] +int fame_list_size_chemist = MAX_FAME_LIST; +int fame_list_size_smith = MAX_FAME_LIST; +int fame_list_size_taekwon = MAX_FAME_LIST; + +// Char-server-side stored fame lists [DracoRPG] +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]; + +// Initial position (it's possible to set it in conf file) +struct point start_point = { 0, 53, 111 }; + +struct gm_account *gm_account = NULL; +int GM_num = 0; + +// online players by [Yor] +char online_txt_filename[1024] = "online.txt"; +char online_html_filename[1024] = "online.html"; +int online_sorting_option = 0; // sorting option to display online players in online files +int online_display_option = 1; // display options: to know which columns must be displayed +int online_refresh_html = 20; // refresh time (in sec) of the html file in the explorer +int online_gm_display_min_level = 20; // minimum GM level to display 'GM' when we want to display it + +int console = 0; + +//----------------------------------------------------- +// Auth database +//----------------------------------------------------- +#define AUTH_TIMEOUT 30000 + +struct auth_node { + int account_id; + int char_id; + uint32 login_id1; + uint32 login_id2; + uint32 ip; + int sex; + time_t expiration_time; // # of seconds 1/1/1970 (timestamp): Validity limit of the account (0 = unlimited) +}; + +static DBMap* auth_db; // int account_id -> struct auth_node* + +//----------------------------------------------------- +// Online User Database +//----------------------------------------------------- + +struct online_char_data { + int account_id; + int char_id; + int fd; + int waiting_disconnect; + short server; +}; + +static DBMap* online_char_db; // int account_id -> struct online_char_data* +static int chardb_waiting_disconnect(int tid, unsigned int tick, int id, int data); + +static void* create_online_char_data(DBKey key, va_list args) +{ + struct online_char_data* character; + CREATE(character, struct online_char_data, 1); + character->account_id = key.i; + character->char_id = -1; + character->server = -1; + character->fd = -1; + character->waiting_disconnect = -1; + return character; +} + +void set_char_online(int map_id, int char_id, int account_id) +{ + struct online_char_data* character; + + character = (struct online_char_data*)idb_ensure(online_char_db, account_id, create_online_char_data); + if (online_check && character->char_id != -1 && character->server > -1 && character->server != map_id && map_id != -3) + { + //char == 99 <- Character logging in, so someone has logged in while one + //char is still on map-server, so kick him out, but don't print "error" + //as this is normal behaviour. [Skotlex] + if (char_id != 99) + ShowNotice("set_char_online: Character %d:%d marked in map server %d, but map server %d claims to have (%d:%d) online!\n", + character->account_id, character->char_id, character->server, map_id, account_id, char_id); + mapif_disconnectplayer(server[character->server].fd, character->account_id, character->char_id, 2); + } + + if( character->server > -1 ) + server[character->server].users++; + + if(character->waiting_disconnect != -1) { + delete_timer(character->waiting_disconnect, chardb_waiting_disconnect); + character->waiting_disconnect = -1; + } + + //If user is NOT at char screen, delete entry [Kevin] + if(character->char_id != -1) + { + idb_remove(online_char_db, account_id); + } + + if (login_fd > 0 && !session[login_fd]->flag.eof) + { + WFIFOHEAD(login_fd,6); + WFIFOW(login_fd,0) = 0x272b; + WFIFOL(login_fd,2) = account_id; + WFIFOSET(login_fd,6); + } +} + +void set_char_offline(int char_id, int account_id) +{ + struct online_char_data* character; + + if ((character = (struct online_char_data*)idb_get(online_char_db, account_id)) != NULL) + { //We don't free yet to avoid aCalloc/aFree spamming during char change. [Skotlex] + if( character->server > -1 ) + server[character->server].users--; + + character->char_id = -1; + character->server = -1; + if(character->waiting_disconnect != -1){ + delete_timer(character->waiting_disconnect, chardb_waiting_disconnect); + character->waiting_disconnect = -1; + } + } + + if (login_fd > 0 && !session[login_fd]->flag.eof) + { + WFIFOHEAD(login_fd,6); + WFIFOW(login_fd,0) = 0x272c; + WFIFOL(login_fd,2) = account_id; + WFIFOSET(login_fd,6); + } +} + +static int char_db_setoffline(DBKey key, void* data, va_list ap) +{ + struct online_char_data* character = (struct online_char_data*)data; + int server = va_arg(ap, int); + if (server == -1) { + character->char_id = -1; + character->server = -1; + if(character->waiting_disconnect != -1){ + delete_timer(character->waiting_disconnect, chardb_waiting_disconnect); + character->waiting_disconnect = -1; + } + } else if (character->server == server) + character->server = -2; //In some map server that we aren't connected to. + return 0; +} + +static int char_db_kickoffline(DBKey key, void* data, va_list ap) +{ + struct online_char_data* character = (struct online_char_data*)data; + int server_id = va_arg(ap, int); + + if (server_id > -1 && character->server != server_id) + return 0; + + //Kick out any connected characters, and set them offline as appropiate. + if (character->server > -1) + mapif_disconnectplayer(server[character->server].fd, character->account_id, character->char_id, 1); + else if (character->waiting_disconnect == -1) + set_char_offline(character->char_id, character->account_id); + else + return 0; // fail + + return 1; +} + +void set_all_offline(int id) +{ + if (id < 0) + ShowNotice("Sending all users offline.\n"); + else + ShowNotice("Sending users of map-server %d offline.\n",id); + online_char_db->foreach(online_char_db,char_db_kickoffline,id); + + if (id >= 0 || login_fd <= 0 || session[login_fd]->flag.eof) + return; + //Tell login-server to also mark all our characters as offline. + WFIFOHEAD(login_fd,2); + WFIFOW(login_fd,0) = 0x2737; + WFIFOSET(login_fd,2); +} + +//------------------------------ +// Writing function of logs file +//------------------------------ +int char_log(char *fmt, ...) +{ + if(log_char) + { + FILE *logfp; + va_list ap; + time_t raw_time; + char tmpstr[2048]; + + va_start(ap, fmt); + + logfp = fopen(char_log_filename, "a"); + if (logfp) { + if (fmt[0] == '\0') // jump a line if no message + fprintf(logfp, "\n"); + else { + time(&raw_time); + strftime(tmpstr, 24, "%d-%m-%Y %H:%M:%S", localtime(&raw_time)); + sprintf(tmpstr + 19, ": %s", fmt); + vfprintf(logfp, tmpstr, ap); + } + fclose(logfp); + } + va_end(ap); + } + return 0; +} + +//---------------------------------------------------------------------- +// Determine if an account (id) is a GM account +// and returns its level (or 0 if it isn't a GM account or if not found) +//---------------------------------------------------------------------- +int isGM(int account_id) +{ + int i; + + for(i = 0; i < GM_num; i++) + if (gm_account[i].account_id == account_id) + return gm_account[i].level; + return 0; +} + +//Search character data from the aid/cid givem +struct mmo_charstatus* search_character(int aid, int cid) +{ + int i; + for (i = 0; i < char_num; i++) { + if (char_dat[i].status.char_id == cid && char_dat[i].status.account_id == aid) + return &char_dat[i].status; + } + return NULL; +} + +struct mmo_charstatus* search_character_byname(char* character_name) +{ + int i = search_character_index(character_name); + if (i == -1) return NULL; + return &char_dat[i].status; +} + +// Searches if the given character is online, and returns the fd of the +// map-server it is connected to. +int search_character_online(int aid, int cid) +{ + //Look for online character. + struct online_char_data* character; + character = idb_get(online_char_db, aid); + if(character && + character->char_id == cid && + character->server > -1) + return server[character->server].fd; + return -1; +} + +//---------------------------------------------- +// Search an character id +// (return character index or -1 (if not found)) +// If exact character name is not found, +// the function checks without case sensitive +// and returns index if only 1 character is found +// and similar to the searched name. +//---------------------------------------------- +int search_character_index(char* character_name) +{ + int i, quantity, index; + + quantity = 0; + index = -1; + for(i = 0; i < char_num; i++) { + // Without case sensitive check (increase the number of similar character names found) + if (stricmp(char_dat[i].status.name, character_name) == 0) { + // Strict comparison (if found, we finish the function immediatly with correct value) + if (strcmp(char_dat[i].status.name, character_name) == 0) + return i; + quantity++; + index = i; + } + } + // Here, the exact character name is not found + // We return the found index of a similar account ONLY if there is 1 similar character + if (quantity == 1) + return index; + + // Exact character name is not found and 0 or more than 1 similar characters have been found ==> we say not found + return -1; +} + +/*--------------------------------------------------- + Make a data line for friends list + --------------------------------------------------*/ +int mmo_friends_list_data_str(char *str, struct mmo_charstatus *p) +{ + int i; + char *str_p = str; + str_p += sprintf(str_p, "%d", p->char_id); + + for (i=0;ifriends[i].account_id > 0 && p->friends[i].char_id > 0 && p->friends[i].name[0]) + str_p += sprintf(str_p, ",%d,%d,%s", p->friends[i].account_id, p->friends[i].char_id, p->friends[i].name); + } + + str_p += '\0'; + + return 0; +} + +/*--------------------------------------------------- + Make a data line for hotkeys list + --------------------------------------------------*/ +int mmo_hotkeys_tostr(char *str, struct mmo_charstatus *p) +{ +#ifdef HOTKEY_SAVING + int i; + char *str_p = str; + str_p += sprintf(str_p, "%d", p->char_id); + for (i=0;ihotkeys[i].type, p->hotkeys[i].id, p->hotkeys[i].lv); + str_p += '\0'; +#endif + + return 0; +} + +//------------------------------------------------- +// Function to create the character line (for save) +//------------------------------------------------- +int mmo_char_tostr(char *str, struct mmo_charstatus *p, struct global_reg *reg, int reg_num) +{ + int i,j; + char *str_p = str; + + str_p += sprintf(str_p, + "%d\t%d,%d\t%s\t%d,%d,%d\t%u,%u,%d" //Up to Zeny field + "\t%d,%d,%d,%d\t%d,%d,%d,%d,%d,%d\t%d,%d" //Up to Skill Point + "\t%d,%d,%d\t%d,%d,%d,%d" //Up to hom id + "\t%d,%d,%d\t%d,%d,%d,%d,%d" //Up to head bottom + "\t%d,%d,%d\t%d,%d,%d" //last point + save point + ",%d,%d,%d,%d,%d\t", //Family info + p->char_id, p->account_id, p->slot, p->name, // + p->class_, p->base_level, p->job_level, + p->base_exp, p->job_exp, p->zeny, + p->hp, p->max_hp, p->sp, p->max_sp, + p->str, p->agi, p->vit, p->int_, p->dex, p->luk, + p->status_point, p->skill_point, + p->option, p->karma, p->manner, // + p->party_id, p->guild_id, p->pet_id, p->hom_id, + p->hair, p->hair_color, p->clothes_color, + p->weapon, p->shield, p->head_top, p->head_mid, p->head_bottom, + p->last_point.map, p->last_point.x, p->last_point.y, // + p->save_point.map, p->save_point.x, p->save_point.y, + p->partner_id,p->father,p->mother,p->child,p->fame); + for(i = 0; i < MAX_MEMOPOINTS; i++) + if (p->memo_point[i].map) { + str_p += sprintf(str_p, "%d,%d,%d ", p->memo_point[i].map, p->memo_point[i].x, p->memo_point[i].y); + } + *(str_p++) = '\t'; + + for(i = 0; i < MAX_INVENTORY; i++) + if (p->inventory[i].nameid) { + str_p += sprintf(str_p,"%d,%d,%d,%d,%d,%d,%d", + p->inventory[i].id,p->inventory[i].nameid,p->inventory[i].amount,p->inventory[i].equip, + p->inventory[i].identify,p->inventory[i].refine,p->inventory[i].attribute); + for(j=0; jinventory[i].card[j]); + str_p += sprintf(str_p," "); + } + *(str_p++) = '\t'; + + for(i = 0; i < MAX_CART; i++) + if (p->cart[i].nameid) { + str_p += sprintf(str_p,"%d,%d,%d,%d,%d,%d,%d", + p->cart[i].id,p->cart[i].nameid,p->cart[i].amount,p->cart[i].equip, + p->cart[i].identify,p->cart[i].refine,p->cart[i].attribute); + for(j=0; jcart[i].card[j]); + str_p += sprintf(str_p," "); + } + *(str_p++) = '\t'; + + for(i = 0; i < MAX_SKILL; i++) + if (p->skill[i].id && p->skill[i].flag != 1) { + str_p += sprintf(str_p, "%d,%d ", p->skill[i].id, (p->skill[i].flag == 0) ? p->skill[i].lv : p->skill[i].flag-2); + } + *(str_p++) = '\t'; + + for(i = 0; i < reg_num; i++) + if (reg[i].str[0]) + str_p += sprintf(str_p, "%s,%s ", reg[i].str, reg[i].value); + *(str_p++) = '\t'; + + *str_p = '\0'; + return 0; +} +#endif //TXT_SQL_CONVERT +//------------------------------------------------------------------------- +// Function to set the character from the line (at read of characters file) +//------------------------------------------------------------------------- +int mmo_char_fromstr(char *str, struct mmo_charstatus *p, struct global_reg *reg, int *reg_num) +{ + char tmp_str[3][128]; //To avoid deleting chars with too long names. + int tmp_int[256]; + unsigned int tmp_uint[2]; //To read exp.... + int next, len, i, j; + + // initilialise character + memset(p, '\0', sizeof(struct mmo_charstatus)); + +// Char structure of version 1500 (homun + mapindex maps) + if (sscanf(str, "%d\t%d,%d\t%127[^\t]\t%d,%d,%d\t%u,%u,%d\t%d,%d,%d,%d\t%d,%d,%d,%d,%d,%d\t%d,%d" + "\t%d,%d,%d\t%d,%d,%d,%d\t%d,%d,%d\t%d,%d,%d,%d,%d" + "\t%d,%d,%d\t%d,%d,%d,%d,%d,%d,%d,%d%n", + &tmp_int[0], &tmp_int[1], &tmp_int[2], tmp_str[0], + &tmp_int[3], &tmp_int[4], &tmp_int[5], + &tmp_uint[0], &tmp_uint[1], &tmp_int[8], + &tmp_int[9], &tmp_int[10], &tmp_int[11], &tmp_int[12], + &tmp_int[13], &tmp_int[14], &tmp_int[15], &tmp_int[16], &tmp_int[17], &tmp_int[18], + &tmp_int[19], &tmp_int[20], + &tmp_int[21], &tmp_int[22], &tmp_int[23], // + &tmp_int[24], &tmp_int[25], &tmp_int[26], &tmp_int[44], + &tmp_int[27], &tmp_int[28], &tmp_int[29], + &tmp_int[30], &tmp_int[31], &tmp_int[32], &tmp_int[33], &tmp_int[34], + &tmp_int[45], &tmp_int[35], &tmp_int[36], + &tmp_int[46], &tmp_int[37], &tmp_int[38], &tmp_int[39], + &tmp_int[40], &tmp_int[41], &tmp_int[42], &tmp_int[43], &next) != 48) + { + tmp_int[44] = 0; //Hom ID. +// Char structure of version 1488 (fame field addition) + if (sscanf(str, "%d\t%d,%d\t%127[^\t]\t%d,%d,%d\t%u,%u,%d\t%d,%d,%d,%d\t%d,%d,%d,%d,%d,%d\t%d,%d" + "\t%d,%d,%d\t%d,%d,%d\t%d,%d,%d\t%d,%d,%d,%d,%d" + "\t%127[^,],%d,%d\t%127[^,],%d,%d,%d,%d,%d,%d,%d%n", + &tmp_int[0], &tmp_int[1], &tmp_int[2], tmp_str[0], + &tmp_int[3], &tmp_int[4], &tmp_int[5], + &tmp_uint[0], &tmp_uint[1], &tmp_int[8], + &tmp_int[9], &tmp_int[10], &tmp_int[11], &tmp_int[12], + &tmp_int[13], &tmp_int[14], &tmp_int[15], &tmp_int[16], &tmp_int[17], &tmp_int[18], + &tmp_int[19], &tmp_int[20], + &tmp_int[21], &tmp_int[22], &tmp_int[23], // + &tmp_int[24], &tmp_int[25], &tmp_int[26], + &tmp_int[27], &tmp_int[28], &tmp_int[29], + &tmp_int[30], &tmp_int[31], &tmp_int[32], &tmp_int[33], &tmp_int[34], + tmp_str[1], &tmp_int[35], &tmp_int[36], + tmp_str[2], &tmp_int[37], &tmp_int[38], &tmp_int[39], + &tmp_int[40], &tmp_int[41], &tmp_int[42], &tmp_int[43], &next) != 47) + { + tmp_int[43] = 0; //Fame +// Char structure of version 1363 (family data addition) + if (sscanf(str, "%d\t%d,%d\t%127[^\t]\t%d,%d,%d\t%u,%u,%d\t%d,%d,%d,%d\t%d,%d,%d,%d,%d,%d\t%d,%d" + "\t%d,%d,%d\t%d,%d,%d\t%d,%d,%d\t%d,%d,%d,%d,%d" + "\t%127[^,],%d,%d\t%127[^,],%d,%d,%d,%d,%d,%d%n", + &tmp_int[0], &tmp_int[1], &tmp_int[2], tmp_str[0], // + &tmp_int[3], &tmp_int[4], &tmp_int[5], + &tmp_uint[0], &tmp_uint[1], &tmp_int[8], + &tmp_int[9], &tmp_int[10], &tmp_int[11], &tmp_int[12], + &tmp_int[13], &tmp_int[14], &tmp_int[15], &tmp_int[16], &tmp_int[17], &tmp_int[18], + &tmp_int[19], &tmp_int[20], + &tmp_int[21], &tmp_int[22], &tmp_int[23], // + &tmp_int[24], &tmp_int[25], &tmp_int[26], + &tmp_int[27], &tmp_int[28], &tmp_int[29], + &tmp_int[30], &tmp_int[31], &tmp_int[32], &tmp_int[33], &tmp_int[34], + tmp_str[1], &tmp_int[35], &tmp_int[36], // + tmp_str[2], &tmp_int[37], &tmp_int[38], &tmp_int[39], + &tmp_int[40], &tmp_int[41], &tmp_int[42], &next) != 46) + { + tmp_int[40] = 0; // father + tmp_int[41] = 0; // mother + tmp_int[42] = 0; // child +// Char structure version 1008 (marriage partner addition) + if (sscanf(str, "%d\t%d,%d\t%127[^\t]\t%d,%d,%d\t%u,%u,%d\t%d,%d,%d,%d\t%d,%d,%d,%d,%d,%d\t%d,%d" + "\t%d,%d,%d\t%d,%d,%d\t%d,%d,%d\t%d,%d,%d,%d,%d" + "\t%127[^,],%d,%d\t%127[^,],%d,%d,%d%n", + &tmp_int[0], &tmp_int[1], &tmp_int[2], tmp_str[0], // + &tmp_int[3], &tmp_int[4], &tmp_int[5], + &tmp_uint[0], &tmp_uint[1], &tmp_int[8], + &tmp_int[9], &tmp_int[10], &tmp_int[11], &tmp_int[12], + &tmp_int[13], &tmp_int[14], &tmp_int[15], &tmp_int[16], &tmp_int[17], &tmp_int[18], + &tmp_int[19], &tmp_int[20], + &tmp_int[21], &tmp_int[22], &tmp_int[23], // + &tmp_int[24], &tmp_int[25], &tmp_int[26], + &tmp_int[27], &tmp_int[28], &tmp_int[29], + &tmp_int[30], &tmp_int[31], &tmp_int[32], &tmp_int[33], &tmp_int[34], + tmp_str[1], &tmp_int[35], &tmp_int[36], // + tmp_str[2], &tmp_int[37], &tmp_int[38], &tmp_int[39], &next) != 43) + { + tmp_int[39] = 0; // partner id +// Char structure version 384 (pet addition) + if (sscanf(str, "%d\t%d,%d\t%127[^\t]\t%d,%d,%d\t%u,%u,%d\t%d,%d,%d,%d\t%d,%d,%d,%d,%d,%d\t%d,%d" + "\t%d,%d,%d\t%d,%d,%d\t%d,%d,%d\t%d,%d,%d,%d,%d" + "\t%127[^,],%d,%d\t%127[^,],%d,%d%n", + &tmp_int[0], &tmp_int[1], &tmp_int[2], tmp_str[0], // + &tmp_int[3], &tmp_int[4], &tmp_int[5], + &tmp_uint[0], &tmp_uint[1], &tmp_int[8], + &tmp_int[9], &tmp_int[10], &tmp_int[11], &tmp_int[12], + &tmp_int[13], &tmp_int[14], &tmp_int[15], &tmp_int[16], &tmp_int[17], &tmp_int[18], + &tmp_int[19], &tmp_int[20], + &tmp_int[21], &tmp_int[22], &tmp_int[23], // + &tmp_int[24], &tmp_int[25], &tmp_int[26], + &tmp_int[27], &tmp_int[28], &tmp_int[29], + &tmp_int[30], &tmp_int[31], &tmp_int[32], &tmp_int[33], &tmp_int[34], + tmp_str[1], &tmp_int[35], &tmp_int[36], // + tmp_str[2], &tmp_int[37], &tmp_int[38], &next) != 42) + { + tmp_int[26] = 0; // pet id +// Char structure of a version 1 (original data structure) + if (sscanf(str, "%d\t%d,%d\t%127[^\t]\t%d,%d,%d\t%u,%u,%d\t%d,%d,%d,%d\t%d,%d,%d,%d,%d,%d\t%d,%d" + "\t%d,%d,%d\t%d,%d\t%d,%d,%d\t%d,%d,%d,%d,%d" + "\t%127[^,],%d,%d\t%127[^,],%d,%d%n", + &tmp_int[0], &tmp_int[1], &tmp_int[2], tmp_str[0], // + &tmp_int[3], &tmp_int[4], &tmp_int[5], + &tmp_uint[0], &tmp_uint[1], &tmp_int[8], + &tmp_int[9], &tmp_int[10], &tmp_int[11], &tmp_int[12], + &tmp_int[13], &tmp_int[14], &tmp_int[15], &tmp_int[16], &tmp_int[17], &tmp_int[18], + &tmp_int[19], &tmp_int[20], + &tmp_int[21], &tmp_int[22], &tmp_int[23], // + &tmp_int[24], &tmp_int[25], // + &tmp_int[27], &tmp_int[28], &tmp_int[29], + &tmp_int[30], &tmp_int[31], &tmp_int[32], &tmp_int[33], &tmp_int[34], + tmp_str[1], &tmp_int[35], &tmp_int[36], // + tmp_str[2], &tmp_int[37], &tmp_int[38], &next) != 41) + { + ShowError("Char-loading: Unrecognized character data version, info lost!\n"); + ShowDebug("Character info: %s\n", str); + return 0; + } + } // Char structure version 384 (pet addition) + } // Char structure version 1008 (marriage partner addition) + } // Char structure of version 1363 (family data addition) + } // Char structure of version 1488 (fame field addition) + //Convert save data from string to integer for older formats + tmp_int[45] = mapindex_name2id(tmp_str[1]); + tmp_int[46] = mapindex_name2id(tmp_str[2]); + } // Char structure of version 1500 (homun + mapindex maps) + + memcpy(p->name, tmp_str[0], NAME_LENGTH); //Overflow protection [Skotlex] + p->char_id = tmp_int[0]; + p->account_id = tmp_int[1]; + p->slot = tmp_int[2]; + p->class_ = tmp_int[3]; + p->base_level = tmp_int[4]; + p->job_level = tmp_int[5]; + p->base_exp = tmp_uint[0]; + p->job_exp = tmp_uint[1]; + p->zeny = tmp_int[8]; + p->hp = tmp_int[9]; + p->max_hp = tmp_int[10]; + p->sp = tmp_int[11]; + p->max_sp = tmp_int[12]; + p->str = tmp_int[13]; + p->agi = tmp_int[14]; + p->vit = tmp_int[15]; + p->int_ = tmp_int[16]; + p->dex = tmp_int[17]; + p->luk = tmp_int[18]; + p->status_point = min(tmp_int[19], USHRT_MAX); + p->skill_point = min(tmp_int[20], USHRT_MAX); + p->option = tmp_int[21]; + p->karma = tmp_int[22]; + p->manner = tmp_int[23]; + p->party_id = tmp_int[24]; + p->guild_id = tmp_int[25]; + p->pet_id = tmp_int[26]; + p->hair = tmp_int[27]; + p->hair_color = tmp_int[28]; + p->clothes_color = tmp_int[29]; + p->weapon = tmp_int[30]; + p->shield = tmp_int[31]; + p->head_top = tmp_int[32]; + p->head_mid = tmp_int[33]; + p->head_bottom = tmp_int[34]; + p->last_point.x = tmp_int[35]; + p->last_point.y = tmp_int[36]; + p->save_point.x = tmp_int[37]; + p->save_point.y = tmp_int[38]; + p->partner_id = tmp_int[39]; + p->father = tmp_int[40]; + p->mother = tmp_int[41]; + p->child = tmp_int[42]; + p->fame = tmp_int[43]; + p->hom_id = tmp_int[44]; + p->last_point.map = tmp_int[45]; + p->save_point.map = tmp_int[46]; + +#ifndef TXT_SQL_CONVERT + // Some checks + for(i = 0; i < char_num; i++) { + if (char_dat[i].status.char_id == p->char_id) { + ShowError(CL_RED"mmmo_auth_init: a character has an identical id to another.\n"); + ShowError(" character id #%d -> new character not readed.\n", p->char_id); + ShowError(" Character saved in log file."CL_RESET"\n"); + return -1; + } else if (strcmp(char_dat[i].status.name, p->name) == 0) { + ShowError(CL_RED"mmmo_auth_init: a character name already exists.\n"); + ShowError(" character name '%s' -> new character not read.\n", p->name); + ShowError(" Character saved in log file."CL_RESET"\n"); + return -2; + } + } + + if (strcmpi(wisp_server_name, p->name) == 0) { + ShowWarning("mmo_auth_init: ******WARNING: character name has wisp server name.\n"); + ShowWarning(" Character name '%s' = wisp server name '%s'.\n", p->name, wisp_server_name); + ShowWarning(" Character readed. Suggestion: change the wisp server name.\n"); + char_log("mmo_auth_init: ******WARNING: character name has wisp server name: Character name '%s' = wisp server name '%s'.\n", + p->name, wisp_server_name); + } +#endif //TXT_SQL_CONVERT + if (str[next] == '\n' || str[next] == '\r') + return 1; // 新規データ + + next++; + + for(i = 0; str[next] && str[next] != '\t'; i++) { + //mapindex memo format + if (sscanf(str+next, "%d,%d,%d%n", &tmp_int[2], &tmp_int[0], &tmp_int[1], &len) != 3) + { //Old string-based memo format. + if (sscanf(str+next, "%[^,],%d,%d%n", tmp_str[0], &tmp_int[0], &tmp_int[1], &len) != 3) + return -3; + tmp_int[2] = mapindex_name2id(tmp_str[0]); + } + if (i < MAX_MEMOPOINTS) + { //Avoid overflowing (but we must also read through all saved memos) + p->memo_point[i].x = tmp_int[0]; + p->memo_point[i].y = tmp_int[1]; + p->memo_point[i].map = tmp_int[2]; + } + next += len; + if (str[next] == ' ') + next++; + } + + next++; + + for(i = 0; str[next] && str[next] != '\t'; i++) { + if(sscanf(str + next, "%d,%d,%d,%d,%d,%d,%d%[0-9,-]%n", + &tmp_int[0], &tmp_int[1], &tmp_int[2], &tmp_int[3], + &tmp_int[4], &tmp_int[5], &tmp_int[6], tmp_str[0], &len) == 8) + { + p->inventory[i].id = tmp_int[0]; + p->inventory[i].nameid = tmp_int[1]; + p->inventory[i].amount = tmp_int[2]; + p->inventory[i].equip = tmp_int[3]; + p->inventory[i].identify = tmp_int[4]; + p->inventory[i].refine = tmp_int[5]; + p->inventory[i].attribute = tmp_int[6]; + + for(j = 0; j < MAX_SLOTS && tmp_str[0] && sscanf(tmp_str[0], ",%d%[0-9,-]",&tmp_int[0], tmp_str[0]) > 0; j++) + p->inventory[i].card[j] = tmp_int[0]; + + next += len; + if (str[next] == ' ') + next++; + } else // invalid structure + return -4; + } + next++; + + for(i = 0; str[next] && str[next] != '\t'; i++) { + if(sscanf(str + next, "%d,%d,%d,%d,%d,%d,%d%[0-9,-]%n", + &tmp_int[0], &tmp_int[1], &tmp_int[2], &tmp_int[3], + &tmp_int[4], &tmp_int[5], &tmp_int[6], tmp_str[0], &len) == 8) + { + p->cart[i].id = tmp_int[0]; + p->cart[i].nameid = tmp_int[1]; + p->cart[i].amount = tmp_int[2]; + p->cart[i].equip = tmp_int[3]; + p->cart[i].identify = tmp_int[4]; + p->cart[i].refine = tmp_int[5]; + p->cart[i].attribute = tmp_int[6]; + + for(j = 0; j < MAX_SLOTS && tmp_str && sscanf(tmp_str[0], ",%d%[0-9,-]",&tmp_int[0], tmp_str[0]) > 0; j++) + p->cart[i].card[j] = tmp_int[0]; + + next += len; + if (str[next] == ' ') + next++; + } else // invalid structure + return -5; + } + + next++; + + for(i = 0; str[next] && str[next] != '\t'; i++) { + if (sscanf(str + next, "%d,%d%n", &tmp_int[0], &tmp_int[1], &len) != 2) + return -6; + p->skill[tmp_int[0]].id = tmp_int[0]; + p->skill[tmp_int[0]].lv = tmp_int[1]; + next += len; + if (str[next] == ' ') + next++; + } + + next++; + + for(i = 0; str[next] && str[next] != '\t' && str[next] != '\n' && str[next] != '\r'; i++) { // global_reg実装以前のathena.txt互換のため一応'\n'チェック + if (sscanf(str + next, "%[^,],%[^ ] %n", reg[i].str, reg[i].value, &len) != 2) { + // because some scripts are not correct, the str can be "". So, we must check that. + // If it's, we must not refuse the character, but just this REG value. + // Character line will have something like: nov_2nd_cos,9 ,9 nov_1_2_cos_c,1 (here, ,9 is not good) + if (str[next] == ',' && sscanf(str + next, ",%[^ ] %n", reg[i].value, &len) == 1) + i--; + else + return -7; + } + next += len; + if (str[next] == ' ') + next++; + } + *reg_num = i; + + return 1; +} + +//--------------------------------- +// Function to read friend list +//--------------------------------- +int parse_friend_txt(struct mmo_charstatus *p) +{ + char line[1024], temp[1024]; + int pos = 0, count = 0, next; + int i,len; + FILE *fp; + + // Open the file and look for the ID + fp = fopen(friends_txt, "r"); + + if(fp == NULL) + return -1; + + while(fgets(line, sizeof(line), fp)) + { + if(line[0] == '/' && line[1] == '/') + continue; + if (sscanf(line, "%d%n",&i, &pos) < 1 || i != p->char_id) + continue; //Not this line... + //Read friends + len = strlen(line); + next = pos; + for (count = 0; next < len && count < MAX_FRIENDS; count++) + { //Read friends. + if (sscanf(line+next, ",%d,%d,%23[^,^\n]%n",&p->friends[count].account_id,&p->friends[count].char_id, p->friends[count].name, &pos) < 3) + { //Invalid friend? + memset(&p->friends[count], 0, sizeof(p->friends[count])); + break; + } + next+=pos; + //What IF the name contains a comma? while the next field is not a + //number, we assume it belongs to the current name. [Skotlex] + //NOTE: Of course, this will fail if someone sets their name to something like + //Bob,2005 but... meh, it's the problem of parsing a text file (encasing it in " + //won't do as quotes are also valid name chars!) + while(next < len && sscanf(line+next, ",%23[^,^\n]%n", temp, &pos) > 0) + { + if (atoi(temp)) //We read the next friend, just continue. + break; + //Append the name. + next+=pos; + i = strlen(p->friends[count].name); + if (i + strlen(temp) +1 < NAME_LENGTH) + { + p->friends[count].name[i] = ','; + strcpy(p->friends[count].name+i+1, temp); + } + } //End Guess Block + } //Friend's for. + break; //Found friends. + } + fclose(fp); + return count; +} + +//--------------------------------- +// Function to read hotkey list +//--------------------------------- +int parse_hotkey_txt(struct mmo_charstatus *p) +{ +#ifdef HOTKEY_SAVING + char line[1024]; + int pos = 0, count = 0, next; + int i,len; + int type, id, lv; + FILE *fp; + + // Open the file and look for the ID + fp = fopen(hotkeys_txt, "r"); + if(fp == NULL) + return -1; + + while(fgets(line, sizeof(line), fp)) + { + if(line[0] == '/' && line[1] == '/') + continue; + if (sscanf(line, "%d%n",&i, &pos) < 1 || i != p->char_id) + continue; //Not this line... + //Read hotkeys + len = strlen(line); + next = pos; + for (count = 0; next < len && count < MAX_HOTKEYS; count++) + { + if (sscanf(line+next, ",%d,%d,%d%n",&type,&id,&lv, &pos) < 3) + //Invalid entry? + break; + p->hotkeys[count].type = type; + p->hotkeys[count].id = id; + p->hotkeys[count].lv = lv; + next+=pos; + } + break; //Found hotkeys. + } + fclose(fp); + return count; +#else + return 0; +#endif +} + + + +#ifndef TXT_SQL_CONVERT +//--------------------------------- +// Function to read characters file +//--------------------------------- +int mmo_char_init(void) +{ + char line[65536]; + int ret, line_count; + FILE* fp; + + char_num = 0; + char_max = 0; + char_dat = NULL; + + fp = fopen(char_txt, "r"); + + if (fp == NULL) { + ShowError("Characters file not found: %s.\n", char_txt); + char_log("Characters file not found: %s.\n", char_txt); + char_log("Id for the next created character: %d.\n", char_id_count); + return 0; + } + + line_count = 0; + while(fgets(line, sizeof(line), fp)) + { + int i, j; + line_count++; + + if (line[0] == '/' && line[1] == '/') + continue; + + j = 0; + if (sscanf(line, "%d\t%%newid%%%n", &i, &j) == 1 && j > 0) { + if (char_id_count < i) + char_id_count = i; + continue; + } + + if (char_num >= char_max) { + char_max += 256; + char_dat = (struct character_data*)aRealloc(char_dat, sizeof(struct character_data) * char_max); + if (!char_dat) { + ShowFatalError("Out of memory: mmo_char_init (realloc of char_dat).\n"); + char_log("Out of memory: mmo_char_init (realloc of char_dat).\n"); + exit(EXIT_FAILURE); + } + } + + ret = mmo_char_fromstr(line, &char_dat[char_num].status, char_dat[char_num].global, &char_dat[char_num].global_num); + + // Initialize friends list + parse_friend_txt(&char_dat[char_num].status); // Grab friends for the character + // Initialize hotkey list + parse_hotkey_txt(&char_dat[char_num].status); // Grab hotkeys for the character + + if (ret > 0) { // negative value or zero for errors + if (char_dat[char_num].status.char_id >= char_id_count) + char_id_count = char_dat[char_num].status.char_id + 1; + char_num++; + } else { + ShowError("mmo_char_init: in characters file, unable to read the line #%d.\n", line_count); + ShowError(" -> Character saved in log file.\n"); + switch (ret) { + case -1: + char_log("Duplicate character id in the next character line (character not readed):\n"); + break; + case -2: + char_log("Duplicate character name in the next character line (character not readed):\n"); + break; + case -3: + char_log("Invalid memo point structure in the next character line (character not readed):\n"); + break; + case -4: + char_log("Invalid inventory item structure in the next character line (character not readed):\n"); + break; + case -5: + char_log("Invalid cart item structure in the next character line (character not readed):\n"); + break; + case -6: + char_log("Invalid skill structure in the next character line (character not readed):\n"); + break; + case -7: + char_log("Invalid register structure in the next character line (character not readed):\n"); + break; + default: // 0 + char_log("Unabled to get a character in the next line - Basic structure of line (before inventory) is incorrect (character not readed):\n"); + break; + } + char_log("%s", line); + } + } + fclose(fp); + + if (char_num == 0) { + ShowNotice("mmo_char_init: No character found in %s.\n", char_txt); + char_log("mmo_char_init: No character found in %s.\n", char_txt); + } else if (char_num == 1) { + ShowStatus("mmo_char_init: 1 character read in %s.\n", char_txt); + char_log("mmo_char_init: 1 character read in %s.\n", char_txt); + } else { + ShowStatus("mmo_char_init: %d characters read in %s.\n", char_num, char_txt); + char_log("mmo_char_init: %d characters read in %s.\n", char_num, char_txt); + } + + char_log("Id for the next created character: %d.\n", char_id_count); + + return 0; +} + +//--------------------------------------------------------- +// Function to save characters in files (speed up by [Yor]) +//--------------------------------------------------------- +void mmo_char_sync(void) +{ + char line[65536],f_line[1024]; + int i, j, k; + int lock; + FILE *fp,*f_fp; + CREATE_BUFFER(id, int, char_num); + + // Sorting before save (by [Yor]) + for(i = 0; i < char_num; i++) { + id[i] = i; + for(j = 0; j < i; j++) { + if ((char_dat[i].status.account_id < char_dat[id[j]].status.account_id) || + // if same account id, we sort by slot. + (char_dat[i].status.account_id == char_dat[id[j]].status.account_id && + char_dat[i].status.slot < char_dat[id[j]].status.slot)) { + for(k = i; k > j; k--) + id[k] = id[k-1]; + id[j] = i; // id[i] + break; + } + } + } + + // Data save + fp = lock_fopen(char_txt, &lock); + if (fp == NULL) { + ShowWarning("Server cannot save characters.\n"); + char_log("WARNING: Server cannot save characters.\n"); + } else { + for(i = 0; i < char_num; i++) { + mmo_char_tostr(line, &char_dat[id[i]].status, char_dat[id[i]].global, char_dat[id[i]].global_num); // use of sorted index + fprintf(fp, "%s\n", line); + } + fprintf(fp, "%d\t%%newid%%\n", char_id_count); + lock_fclose(fp, char_txt, &lock); + } + + // Friends List data save (davidsiaw) + f_fp = lock_fopen(friends_txt, &lock); + for(i = 0; i < char_num; i++) { + mmo_friends_list_data_str(f_line, &char_dat[id[i]].status); + fprintf(f_fp, "%s\n", f_line); + } + + lock_fclose(f_fp, friends_txt, &lock); + +#ifdef HOTKEY_SAVING + // Hotkey List data save (Skotlex) + f_fp = lock_fopen(hotkeys_txt, &lock); + for(i = 0; i < char_num; i++) { + mmo_hotkeys_tostr(f_line, &char_dat[id[i]].status); + fprintf(f_fp, "%s\n", f_line); + } + + lock_fclose(f_fp, hotkeys_txt, &lock); +#endif + + DELETE_BUFFER(id); + + return; +} + +//---------------------------------------------------- +// Function to save (in a periodic way) datas in files +//---------------------------------------------------- +int mmo_char_sync_timer(int tid, unsigned int tick, int id, int data) +{ + if (save_log) + ShowInfo("Saving all files...\n"); + mmo_char_sync(); + inter_save(); + return 0; +} + +//----------------------------------- +// Function to create a new character +//----------------------------------- +int make_new_char(struct char_session_data* sd, char* name_, int str, int agi, int vit, int int_, int dex, int luk, int slot, int hair_color, int hair_style) +{ + char name[NAME_LENGTH]; + int i; + + safestrncpy(name, name_, NAME_LENGTH); + normalize_name(name,TRIM_CHARS); + + // check length of character name + if( name[0] == '\0' ) + return -2; // empty character name + + // check content of character name + if( remove_control_chars(name) ) + return -2; // control chars in name + + // check for reserved names + if( strcmpi(name, main_chat_nick) == 0 || strcmpi(name, wisp_server_name) == 0 ) + return -1; // nick reserved for internal server messages + + // Check Authorised letters/symbols in the name of the character + if( char_name_option == 1 ) { // only letters/symbols in char_name_letters are authorised + for( i = 0; i < NAME_LENGTH && name[i]; i++ ) + if( strchr(char_name_letters, name[i]) == NULL ) + return -2; + } else + if( char_name_option == 2 ) { // letters/symbols in char_name_letters are forbidden + for( i = 0; i < NAME_LENGTH && name[i]; i++ ) + if( strchr(char_name_letters, name[i]) != NULL ) + return -2; + } // else, all letters/symbols are authorised (except control char removed before) + + // check name (already in use?) + ARR_FIND( 0, char_num, i, + (name_ignoring_case && strncmp(char_dat[i].status.name, name, NAME_LENGTH) == 0) || + (!name_ignoring_case && strncmpi(char_dat[i].status.name, name, NAME_LENGTH) == 0) ); + if( i < char_num ) + return -1; // name already exists + + //check other inputs + if((slot >= MAX_CHARS) // slots + || (hair_style >= 24) // hair style + || (hair_color >= 9) // hair color + || (str + agi + vit + int_ + dex + luk != 6*5 ) // stats + || (str < 1 || str > 9 || agi < 1 || agi > 9 || vit < 1 || vit > 9 || int_ < 1 || int_ > 9 || dex < 1 || dex > 9 || luk < 1 || luk > 9) // individual stat values + || (str + int_ != 10 || agi + luk != 10 || vit + dex != 10) ) // pairs + return -2; // invalid input + + // check char slot + ARR_FIND( 0, char_num, i, char_dat[i].status.account_id == sd->account_id && char_dat[i].status.slot == slot ); + if( i < char_num ) + return -2; // slot already in use + + if (char_num >= char_max) { + char_max += 256; + RECREATE(char_dat, struct character_data, char_max); + if (!char_dat) { + ShowFatalError("Out of memory: make_new_char (realloc of char_dat).\n"); + char_log("Out of memory: make_new_char (realloc of char_dat).\n"); + exit(EXIT_FAILURE); + } + } + + // validation success, log result + char_log("make new char: account: %d, slot %d, name: %s, stats: %d/%d/%d/%d/%d/%d, hair: %d, hair color: %d.\n", + sd->account_id, slot, name, str, agi, vit, int_, dex, luk, hair_style, hair_color); + + i = char_num; + memset(&char_dat[i], 0, sizeof(struct character_data)); + + char_dat[i].status.char_id = char_id_count++; + char_dat[i].status.account_id = sd->account_id; + char_dat[i].status.slot = slot; + safestrncpy(char_dat[i].status.name,name,NAME_LENGTH); + char_dat[i].status.class_ = 0; + char_dat[i].status.base_level = 1; + char_dat[i].status.job_level = 1; + char_dat[i].status.base_exp = 0; + char_dat[i].status.job_exp = 0; + char_dat[i].status.zeny = start_zeny; + char_dat[i].status.str = str; + char_dat[i].status.agi = agi; + char_dat[i].status.vit = vit; + char_dat[i].status.int_ = int_; + char_dat[i].status.dex = dex; + char_dat[i].status.luk = luk; + char_dat[i].status.max_hp = 40 * (100 + char_dat[i].status.vit) / 100; + char_dat[i].status.max_sp = 11 * (100 + char_dat[i].status.int_) / 100; + char_dat[i].status.hp = char_dat[i].status.max_hp; + char_dat[i].status.sp = char_dat[i].status.max_sp; + char_dat[i].status.status_point = 0; + char_dat[i].status.skill_point = 0; + char_dat[i].status.option = 0; + char_dat[i].status.karma = 0; + char_dat[i].status.manner = 0; + char_dat[i].status.party_id = 0; + char_dat[i].status.guild_id = 0; + char_dat[i].status.hair = hair_style; + char_dat[i].status.hair_color = hair_color; + char_dat[i].status.clothes_color = 0; + char_dat[i].status.inventory[0].nameid = start_weapon; // Knife + char_dat[i].status.inventory[0].amount = 1; + char_dat[i].status.inventory[0].identify = 1; + char_dat[i].status.inventory[1].nameid = start_armor; // Cotton Shirt + char_dat[i].status.inventory[1].amount = 1; + char_dat[i].status.inventory[1].identify = 1; + char_dat[i].status.weapon = 0; // W_FIST + char_dat[i].status.shield = 0; + char_dat[i].status.head_top = 0; + char_dat[i].status.head_mid = 0; + char_dat[i].status.head_bottom = 0; + memcpy(&char_dat[i].status.last_point, &start_point, sizeof(start_point)); + memcpy(&char_dat[i].status.save_point, &start_point, sizeof(start_point)); + char_num++; + + ShowInfo("Created char: account: %d, char: %d, slot: %d, name: %s\n", sd->account_id, i, slot, name); + mmo_char_sync(); + return i; +} + +//---------------------------------------------------- +// This function return the name of the job (by [Yor]) +//---------------------------------------------------- +char * job_name(int class_) +{ + switch (class_) { + case JOB_NOVICE: return "Novice"; + case JOB_SWORDMAN: return "Swordsman"; + case JOB_MAGE: return "Mage"; + case JOB_ARCHER: return "Archer"; + case JOB_ACOLYTE: return "Acolyte"; + case JOB_MERCHANT: return "Merchant"; + case JOB_THIEF: return "Thief"; + case JOB_KNIGHT: return "Knight"; + case JOB_PRIEST: return "Priest"; + case JOB_WIZARD: return "Wizard"; + case JOB_BLACKSMITH: return "Blacksmith"; + case JOB_HUNTER: return "Hunter"; + case JOB_ASSASSIN: return "Assassin"; + case JOB_KNIGHT2: return "Peco-Knight"; + case JOB_CRUSADER: return "Crusader"; + case JOB_MONK: return "Monk"; + case JOB_SAGE: return "Sage"; + case JOB_ROGUE: return "Rogue"; + case JOB_ALCHEMIST: return "Alchemist"; + case JOB_BARD: return "Bard"; + case JOB_DANCER: return "Dancer"; + case JOB_CRUSADER2: return "Peco-Crusader"; + case JOB_WEDDING: return "Wedding"; + case JOB_SUPER_NOVICE: return "Super Novice"; + case JOB_GUNSLINGER: return "Gunslinger"; + case JOB_NINJA: return "Ninja"; + case JOB_XMAS: return "Christmas"; + case JOB_NOVICE_HIGH: return "Novice High"; + case JOB_SWORDMAN_HIGH: return "Swordsman High"; + case JOB_MAGE_HIGH: return "Mage High"; + case JOB_ARCHER_HIGH: return "Archer High"; + case JOB_ACOLYTE_HIGH: return "Acolyte High"; + case JOB_MERCHANT_HIGH: return "Merchant High"; + case JOB_THIEF_HIGH: return "Thief High"; + case JOB_LORD_KNIGHT: return "Lord Knight"; + case JOB_HIGH_PRIEST: return "High Priest"; + case JOB_HIGH_WIZARD: return "High Wizard"; + case JOB_WHITESMITH: return "Whitesmith"; + case JOB_SNIPER: return "Sniper"; + case JOB_ASSASSIN_CROSS: return "Assassin Cross"; + case JOB_LORD_KNIGHT2: return "Peko Knight"; + case JOB_PALADIN: return "Paladin"; + case JOB_CHAMPION: return "Champion"; + case JOB_PROFESSOR: return "Professor"; + case JOB_STALKER: return "Stalker"; + case JOB_CREATOR: return "Creator"; + case JOB_CLOWN: return "Clown"; + case JOB_GYPSY: return "Gypsy"; + case JOB_PALADIN2: return "Peko Paladin"; + case JOB_BABY: return "Baby Novice"; + case JOB_BABY_SWORDMAN: return "Baby Swordsman"; + case JOB_BABY_MAGE: return "Baby Mage"; + case JOB_BABY_ARCHER: return "Baby Archer"; + case JOB_BABY_ACOLYTE: return "Baby Acolyte"; + case JOB_BABY_MERCHANT: return "Baby Merchant"; + case JOB_BABY_THIEF: return "Baby Thief"; + case JOB_BABY_KNIGHT: return "Baby Knight"; + case JOB_BABY_PRIEST: return "Baby Priest"; + case JOB_BABY_WIZARD: return "Baby Wizard"; + case JOB_BABY_BLACKSMITH: return "Baby Blacksmith"; + case JOB_BABY_HUNTER: return "Baby Hunter"; + case JOB_BABY_ASSASSIN: return "Baby Assassin"; + case JOB_BABY_KNIGHT2: return "Baby Peco Knight"; + case JOB_BABY_CRUSADER: return "Baby Crusader"; + case JOB_BABY_MONK: return "Baby Monk"; + case JOB_BABY_SAGE: return "Baby Sage"; + case JOB_BABY_ROGUE: return "Baby Rogue"; + case JOB_BABY_ALCHEMIST: return "Baby Alchemist"; + case JOB_BABY_BARD: return "Baby Bard"; + case JOB_BABY_DANCER: return "Baby Dancer"; + case JOB_BABY_CRUSADER2: return "Baby Peco Crusader"; + case JOB_SUPER_BABY: return "Super Baby"; + case JOB_TAEKWON: return "Taekwon"; + case JOB_STAR_GLADIATOR: return "Star Gladiator"; + case JOB_STAR_GLADIATOR2: return "Flying Star Gladiator"; + case JOB_SOUL_LINKER: return "Soul Linker"; + } + return "Unknown Job"; +} + +static int create_online_files_sub(DBKey key, void* data, va_list va) +{ + struct online_char_data *character; + int* players; + int *id; + int j,k,l; + character = (struct online_char_data*) data; + players = va_arg(va, int*); + id = va_arg(va, int*); + + // check if map-server is online + if (character->server == -1 || character->char_id == -1) { //Character not currently online. + return -1; + } + + j = character->server; + if (server[j].fd < 0) { + server[j].users = 0; + return -1; + } + // search position of character in char_dat and sort online characters. + for(j = 0; j < char_num; j++) { + if (char_dat[j].status.char_id != character->char_id) + continue; + id[*players] = j; + // use sorting option + switch (online_sorting_option) { + case 1: // by name (without case sensitive) + for(k = 0; k < *players; k++) + if (stricmp(char_dat[j].status.name, char_dat[id[k]].status.name) < 0 || + // if same name, we sort with case sensitive. + (stricmp(char_dat[j].status.name, char_dat[id[k]].status.name) == 0 && + strcmp(char_dat[j].status.name, char_dat[id[k]].status.name) < 0)) { + for(l = *players; l > k; l--) + id[l] = id[l-1]; + id[k] = j; // id[*players] + break; + } + break; + case 2: // by zeny + for(k = 0; k < *players; k++) + if (char_dat[j].status.zeny < char_dat[id[k]].status.zeny || + // if same number of zenys, we sort by name. + (char_dat[j].status.zeny == char_dat[id[k]].status.zeny && + stricmp(char_dat[j].status.name, char_dat[id[k]].status.name) < 0)) { + for(l = *players; l > k; l--) + id[l] = id[l-1]; + id[k] = j; // id[*players] + break; + } + break; + case 3: // by base level + for(k = 0; k < *players; k++) + if (char_dat[j].status.base_level < char_dat[id[k]].status.base_level || + // if same base level, we sort by base exp. + (char_dat[j].status.base_level == char_dat[id[k]].status.base_level && + char_dat[j].status.base_exp < char_dat[id[k]].status.base_exp)) { + for(l = *players; l > k; l--) + id[l] = id[l-1]; + id[k] = j; // id[*players] + break; + } + break; + case 4: // by job (and job level) + for(k = 0; k < *players; k++) + if (char_dat[j].status.class_ < char_dat[id[k]].status.class_ || + // if same job, we sort by job level. + (char_dat[j].status.class_ == char_dat[id[k]].status.class_ && + char_dat[j].status.job_level < char_dat[id[k]].status.job_level) || + // if same job and job level, we sort by job exp. + (char_dat[j].status.class_ == char_dat[id[k]].status.class_ && + char_dat[j].status.job_level == char_dat[id[k]].status.job_level && + char_dat[j].status.job_exp < char_dat[id[k]].status.job_exp)) { + for(l = *players; l > k; l--) + id[l] = id[l-1]; + id[k] = j; // id[*players] + break; + } + break; + case 5: // by location map name + { + const char *map1, *map2; + map1 = mapindex_id2name(char_dat[j].status.last_point.map); + + for(k = 0; k < *players; k++) { + map2 = mapindex_id2name(char_dat[id[k]].status.last_point.map); + if (!map1 || !map2 || //Avoid sorting if either one failed to resolve. + stricmp(map1, map2) < 0 || + // if same map name, we sort by name. + (stricmp(map1, map2) == 0 && + stricmp(char_dat[j].status.name, char_dat[id[k]].status.name) < 0)) { + for(l = *players; l > k; l--) + id[l] = id[l-1]; + id[k] = j; // id[*players] + break; + } + } + } + break; + default: // 0 or invalid value: no sorting + break; + } + (*players)++; + break; + } + return 0; +} +//------------------------------------------------------------- +// Function to create the online files (txt and html). by [Yor] +//------------------------------------------------------------- +void create_online_files(void) +{ + unsigned int k, j; // for loop with strlen comparing + int i, l; // for loops + int players; // count the number of players + FILE *fp; // for the txt file + FILE *fp2; // for the html file + char temp[256]; // to prepare what we must display + time_t time_server; // for number of seconds + struct tm *datetime; // variable for time in structure ->tm_mday, ->tm_sec, ... + int id[4096]; + + if (online_display_option == 0) // we display nothing, so return + return; + + // Get number of online players, id of each online players, and verify if a server is offline + players = 0; + online_char_db->foreach(online_char_db, create_online_files_sub, &players, &id); + + // write files + fp = fopen(online_txt_filename, "w"); + if (fp != NULL) { + fp2 = fopen(online_html_filename, "w"); + if (fp2 != NULL) { + // get time + time(&time_server); // get time in seconds since 1/1/1970 + datetime = localtime(&time_server); // convert seconds in structure + strftime(temp, sizeof(temp), "%d %b %Y %X", datetime); // like sprintf, but only for date/time (05 dec 2003 15:12:52) + // write heading + fprintf(fp2, "\n"); + fprintf(fp2, " \n", online_refresh_html); // update on client explorer every x seconds + fprintf(fp2, " \n"); + fprintf(fp2, " Online Players on %s\n", server_name); + fprintf(fp2, " \n"); + fprintf(fp2, " \n"); + fprintf(fp2, "

Online Players on %s (%s):

\n", server_name, temp); + fprintf(fp, "Online Players on %s (%s):\n", server_name, temp); + fprintf(fp, "\n"); + + for (i = 0; i < players; i++) { + // if it's the first player + if (i == 0) { + j = 0; // count the number of characters for the txt version and to set the separate line + fprintf(fp2, " \n"); + fprintf(fp2, " \n"); + if ((online_display_option & 1) || (online_display_option & 64)) { + fprintf(fp2, " \n"); + if (online_display_option & 64) { + fprintf(fp, "Name "); // 30 + j += 30; + } else { + fprintf(fp, "Name "); // 25 + j += 25; + } + } + if ((online_display_option & 6) == 6) { + fprintf(fp2, " \n"); + fprintf(fp, "Job Levels "); // 27 + j += 27; + } else if (online_display_option & 2) { + fprintf(fp2, " \n"); + fprintf(fp, "Job "); // 19 + j += 19; + } else if (online_display_option & 4) { + fprintf(fp2, " \n"); + fprintf(fp, " Levels "); // 8 + j += 8; + } + if (online_display_option & 24) { // 8 or 16 + fprintf(fp2, " \n"); + if (online_display_option & 16) { + fprintf(fp, "Location ( x , y ) "); // 23 + j += 23; + } else { + fprintf(fp, "Location "); // 13 + j += 13; + } + } + if (online_display_option & 32) { + fprintf(fp2, " \n"); + fprintf(fp, " Zenys "); // 16 + j += 16; + } + fprintf(fp2, " \n"); + fprintf(fp, "\n"); + for (k = 0; k < j; k++) + fprintf(fp, "-"); + fprintf(fp, "\n"); + } + fprintf(fp2, " \n"); + // get id of the character (more speed) + j = id[i]; + // displaying the character name + if ((online_display_option & 1) || (online_display_option & 64)) { // without/with 'GM' display + strcpy(temp, char_dat[j].status.name); + l = isGM(char_dat[j].status.account_id); + if (online_display_option & 64) { + if (l >= online_gm_display_min_level) + fprintf(fp, "%-24s (GM) ", temp); + else + fprintf(fp, "%-24s ", temp); + } else + fprintf(fp, "%-24s ", temp); + // name of the character in the html (no < >, because that create problem in html code) + fprintf(fp2, " \n"); + } + // displaying of the job + if (online_display_option & 6) { + char * jobname = job_name(char_dat[j].status.class_); + if ((online_display_option & 6) == 6) { + fprintf(fp2, " \n", jobname, char_dat[j].status.base_level, char_dat[j].status.job_level); + fprintf(fp, "%-18s %3d/%3d ", jobname, char_dat[j].status.base_level, char_dat[j].status.job_level); + } else if (online_display_option & 2) { + fprintf(fp2, " \n", jobname); + fprintf(fp, "%-18s ", jobname); + } else if (online_display_option & 4) { + fprintf(fp2, " \n", char_dat[j].status.base_level, char_dat[j].status.job_level); + fprintf(fp, "%3d/%3d ", char_dat[j].status.base_level, char_dat[j].status.job_level); + } + } + // displaying of the map + if (online_display_option & 24) { // 8 or 16 + // prepare map name + memcpy(temp, mapindex_id2name(char_dat[j].status.last_point.map), MAP_NAME_LENGTH); + // write map name + if (online_display_option & 16) { // map-name AND coordinates + fprintf(fp2, " \n", temp, char_dat[j].status.last_point.x, char_dat[j].status.last_point.y); + fprintf(fp, "%-12s (%3d,%3d) ", temp, char_dat[j].status.last_point.x, char_dat[j].status.last_point.y); + } else { + fprintf(fp2, " \n", temp); + fprintf(fp, "%-12s ", temp); + } + } + // displaying nimber of zenys + if (online_display_option & 32) { + // write number of zenys + if (char_dat[j].status.zeny == 0) { // if no zeny + fprintf(fp2, " \n"); + fprintf(fp, " no zeny "); + } else { + fprintf(fp2, " \n", char_dat[j].status.zeny); + fprintf(fp, "%13d z ", char_dat[j].status.zeny); + } + } + fprintf(fp, "\n"); + fprintf(fp2, " \n"); + } + // If we display at least 1 player + if (players > 0) { + fprintf(fp2, "
NameJob (levels)JobLevelsLocationzenys
"); + if ((online_display_option & 64) && l >= online_gm_display_min_level) + fprintf(fp2, ""); + for (k = 0; k < strlen(temp); k++) { + switch(temp[k]) { + case '<': // < + fprintf(fp2, "<"); + break; + case '>': // > + fprintf(fp2, ">"); + break; + default: + fprintf(fp2, "%c", temp[k]); + break; + }; + } + if ((online_display_option & 64) && l >= online_gm_display_min_level) + fprintf(fp2, " (GM)"); + fprintf(fp2, "%s %d/%d%s%d/%d%s (%d, %d)%sno zeny%d z
\n"); + fprintf(fp, "\n"); + } + + // Displaying number of online players + if (players == 0) { + fprintf(fp2, "

No user is online.

\n"); + fprintf(fp, "No user is online.\n"); + } else if (players == 1) { + fprintf(fp2, "

%d user is online.

\n", players); + fprintf(fp, "%d user is online.\n", players); + } else { + fprintf(fp2, "

%d users are online.

\n", players); + fprintf(fp, "%d users are online.\n", players); + } + fprintf(fp2, " \n"); + fprintf(fp2, "\n"); + fclose(fp2); + } + fclose(fp); + } + + return; +} + +//--------------------------------------------------------------------- +// This function return the number of online players in all map-servers +//--------------------------------------------------------------------- +int count_users(void) +{ + int i, users; + + users = 0; + for(i = 0; i < MAX_MAP_SERVERS; i++) + if (server[i].fd >= 0) + users += server[i].users; + + return users; +} + +/// Writes char data to the buffer in the format used by the client. +/// Used in packets 0x6b (chars info) and 0x6d (new char info) +/// Returns the size (106 or 108) +int mmo_char_tobuf(uint8* buf, struct mmo_charstatus* p) +{ + if( buf == NULL || p == NULL ) + return 0; + + WBUFL(buf,0) = p->char_id; + WBUFL(buf,4) = min(p->base_exp, LONG_MAX); + WBUFL(buf,8) = p->zeny; + WBUFL(buf,12) = min(p->job_exp, LONG_MAX); + WBUFL(buf,16) = p->job_level; + WBUFL(buf,20) = 0; // probably opt1 + WBUFL(buf,24) = 0; // probably opt2 + WBUFL(buf,28) = p->option; + WBUFL(buf,32) = p->karma; + WBUFL(buf,36) = p->manner; + WBUFW(buf,40) = min(p->status_point, SHRT_MAX); + WBUFW(buf,42) = min(p->hp, SHRT_MAX); + WBUFW(buf,44) = min(p->max_hp, SHRT_MAX); + WBUFW(buf,46) = min(p->sp, SHRT_MAX); + WBUFW(buf,48) = min(p->max_sp, SHRT_MAX); + WBUFW(buf,50) = DEFAULT_WALK_SPEED; // p->speed; + WBUFW(buf,52) = p->class_; + WBUFW(buf,54) = p->hair; + WBUFW(buf,56) = p->option&0x20 ? 0 : p->weapon; //When the weapon is sent and your option is riding, the client crashes on login!? + WBUFW(buf,58) = p->base_level; + WBUFW(buf,60) = min(p->skill_point, SHRT_MAX); + WBUFW(buf,62) = p->head_bottom; + WBUFW(buf,64) = p->shield; + WBUFW(buf,66) = p->head_top; + WBUFW(buf,68) = p->head_mid; + WBUFW(buf,70) = p->hair_color; + WBUFW(buf,72) = p->clothes_color; + memcpy(WBUFP(buf,74), p->name, NAME_LENGTH); + WBUFB(buf,98) = min(p->str, UCHAR_MAX); + WBUFB(buf,99) = min(p->agi, UCHAR_MAX); + WBUFB(buf,100) = min(p->vit, UCHAR_MAX); + WBUFB(buf,101) = min(p->int_, UCHAR_MAX); + WBUFB(buf,102) = min(p->dex, UCHAR_MAX); + WBUFB(buf,103) = min(p->luk, UCHAR_MAX); + WBUFW(buf,104) = p->slot; + if (char_rename) { + WBUFW(buf,106) = 1;// Rename bit (0=rename,1=no rename) + return 108; + } else { + return 106; + } +} + +//---------------------------------------- +// Function to send characters to a player +//---------------------------------------- +int mmo_char_send006b(int fd, struct char_session_data* sd) +{ + int i, j, found_num; + + found_num = 0; + for(i = 0; i < char_num; i++) { + if (char_dat[i].status.account_id == sd->account_id) { + sd->found_char[found_num] = i; + if( ++found_num == MAX_CHARS ) + break; + } + } + for(i = found_num; i < MAX_CHARS; i++) + sd->found_char[i] = -1; + + j = 24; // offset + WFIFOHEAD(fd,j + found_num*108); // or 106(!) + WFIFOW(fd,0) = 0x6b; + memset(WFIFOP(fd,4), 0, 20); // unknown bytes + for(i = 0; i < found_num; i++) + j += mmo_char_tobuf(WFIFOP(fd,j), &char_dat[sd->found_char[i]].status); + WFIFOW(fd,2) = j; // packet len + WFIFOSET(fd,j); + + return 0; +} + +// 離婚(char削除時に使用) +int char_divorce(struct mmo_charstatus *cs) +{ + if (cs == NULL) + return 0; + + if (cs->partner_id > 0){ + int i, j; + for(i = 0; i < char_num; i++) { + if (char_dat[i].status.char_id == cs->partner_id && char_dat[i].status.partner_id == cs->char_id) { + cs->partner_id = 0; + char_dat[i].status.partner_id = 0; + for(j = 0; j < MAX_INVENTORY; j++) + if (char_dat[i].status.inventory[j].nameid == WEDDING_RING_M || char_dat[i].status.inventory[j].nameid == WEDDING_RING_F) + memset(&char_dat[i].status.inventory[j], 0, sizeof(char_dat[i].status.inventory[0])); + if (cs->inventory[j].nameid == WEDDING_RING_M || cs->inventory[j].nameid == WEDDING_RING_F) + memset(&cs->inventory[j], 0, sizeof(cs->inventory[0])); + return 0; + } + } + } + return 0; +} + +int char_married(int pl1,int pl2) +{ + return (char_dat[pl1].status.char_id == char_dat[pl2].status.partner_id && char_dat[pl2].status.char_id == char_dat[pl1].status.partner_id); +} + +int char_child(int parent_id, int child_id) +{ + return (char_dat[parent_id].status.child == char_dat[child_id].status.char_id && + ((char_dat[parent_id].status.char_id == char_dat[child_id].status.father) || + (char_dat[parent_id].status.char_id == char_dat[child_id].status.mother))); +} + +int char_family(int cid1, int cid2, int cid3) +{ + int i, idx1 = -1, idx2 =-1;//, idx3 =-1; + for(i = 0; i < char_num && (idx1 == -1 || idx2 == -1/* || idx3 == 1*/); i++) + { + if (char_dat[i].status.char_id == cid1) + idx1 = i; + if (char_dat[i].status.char_id == cid2) + idx2 = i; +// if (char_dat[i].status.char_id == cid2) +// idx3 = i; + } + if (idx1 == -1 || idx2 == -1/* || idx3 == -1*/) + return 0; //Some character not found?? + + //Unless the dbs are corrupted, these 3 checks should suffice, even though + //we could do a lot more checks and force cross-reference integrity. + if(char_dat[idx1].status.partner_id == cid2 && + char_dat[idx1].status.child == cid3) + return cid3; //cid1/cid2 parents. cid3 child. + + if(char_dat[idx1].status.partner_id == cid3 && + char_dat[idx1].status.child == cid2) + return cid2; //cid1/cid3 parents. cid2 child. + + if(char_dat[idx2].status.partner_id == cid3 && + char_dat[idx2].status.child == cid1) + return cid1; //cid2/cid3 parents. cid1 child. + return 0; +} + +//Clears the given party id from all characters. +//Since sometimes the party format changes and parties must be wiped, this +//method is required to prevent stress during the "party not found!" stages. +void char_clearparty(int party_id) +{ + int i; + for(i = 0; i < char_num; i++) + { + if (char_dat[i].status.party_id == party_id) + char_dat[i].status.party_id = 0; + } +} + +//---------------------------------------------------------------------- +// Force disconnection of an online player (with account value) by [Yor] +//---------------------------------------------------------------------- +int disconnect_player(int account_id) +{ + int i; + struct char_session_data *sd; + + // disconnect player if online on char-server + for(i = 0; i < fd_max; i++) { + if (session[i] && (sd = (struct char_session_data*)session[i]->session_data)) { + if (sd->account_id == account_id) { + set_eof(i); + return 1; + } + } + } + + return 0; +} + +// キャラ削除に伴うデータ削除 +static int char_delete(struct mmo_charstatus *cs) +{ + int j; + + // ペット削除 + if (cs->pet_id) + inter_pet_delete(cs->pet_id); + if (cs->hom_id) + inter_homun_delete(cs->hom_id); + for (j = 0; j < MAX_INVENTORY; j++) + if (cs->inventory[j].card[0] == (short)0xff00) + inter_pet_delete(MakeDWord(cs->inventory[j].card[1],cs->inventory[j].card[2])); + for (j = 0; j < MAX_CART; j++) + if (cs->cart[j].card[0] == (short)0xff00) + inter_pet_delete( MakeDWord(cs->cart[j].card[1],cs->cart[j].card[2]) ); + // ギルド脱退 + if (cs->guild_id) + inter_guild_leave(cs->guild_id, cs->account_id, cs->char_id); + // パーティー脱退 + if (cs->party_id) + inter_party_leave(cs->party_id, cs->account_id, cs->char_id); + // 離婚 + if (cs->partner_id){ + // 離婚情報をmapに通知 + unsigned char buf[10]; + WBUFW(buf,0) = 0x2b12; + WBUFL(buf,2) = cs->char_id; + WBUFL(buf,6) = cs->partner_id; + mapif_sendall(buf,10); + // 離婚 + char_divorce(cs); + } +#ifdef ENABLE_SC_SAVING + status_delete_scdata(cs->account_id, cs->char_id); +#endif + return 0; +} + +static void char_auth_ok(int fd, struct char_session_data *sd) +{ + struct online_char_data* character; + if (max_connect_user && count_users() >= max_connect_user && isGM(sd->account_id) < gm_allow_level) + { + // refuse connection (over populated) + WFIFOW(fd,0) = 0x6c; + WFIFOW(fd,2) = 0; + WFIFOSET(fd,3); + return; + } + + if( online_check && (character = (struct online_char_data*)idb_get(online_char_db, sd->account_id)) != NULL ) + { // check if character is not online already. [Skotlex] + if (character->server > -1) + { //Character already online. KICK KICK KICK + mapif_disconnectplayer(server[character->server].fd, character->account_id, character->char_id, 2); + if (character->waiting_disconnect == -1) + character->waiting_disconnect = add_timer(gettick()+20000, chardb_waiting_disconnect, character->account_id, 0); + WFIFOW(fd,0) = 0x81; + WFIFOB(fd,2) = 8; + WFIFOSET(fd,3); + return; + } + if (character->fd >= 0 && character->fd != fd) + { //There's already a connection from this account that hasn't picked a char yet. + WFIFOW(fd,0) = 0x81; + WFIFOB(fd,2) = 8; + WFIFOSET(fd,3); + return; + } + character->fd = fd; + } + + if (login_fd > 0) { + // request to login-server to obtain e-mail/time limit + //FIXME: isn't this part of the auth_ok packet? [ultramage] + WFIFOHEAD(login_fd,6); + WFIFOW(login_fd,0) = 0x2716; + WFIFOL(login_fd,2) = sd->account_id; + WFIFOSET(login_fd,6); + } + + // mark session as 'authed' + sd->auth = true; + + // set char online on charserver + set_char_online(-1, 99, sd->account_id); + + // send characters to player + mmo_char_send006b(fd, sd); +} + +int send_accounts_tologin(int tid, unsigned int tick, int id, int data); + +int parse_fromlogin(int fd) +{ + int i; + struct char_session_data *sd; + + // only login-server can have an access to here. + // so, if it isn't the login-server, we disconnect the session. + if( fd != login_fd ) + set_eof(fd); + + if(session[fd]->flag.eof) { + if (fd == login_fd) { + ShowWarning("Connection to login-server lost (connection #%d).\n", fd); + login_fd = -1; + } + do_close(fd); + return 0; + } + + sd = (struct char_session_data*)session[fd]->session_data; + + while(RFIFOREST(fd) >= 2) + { + uint16 command = RFIFOW(fd,0); + + switch( command ) + { + + // acknowledgement of connect-to-loginserver request + case 0x2711: + if (RFIFOREST(fd) < 3) + return 0; + + if (RFIFOB(fd,2)) { + //printf("connect login server error : %d\n", RFIFOB(fd,2)); + ShowError("Can not connect to login-server.\n"); + ShowError("The server communication passwords (default s1/p1) are probably invalid.\n"); + ShowInfo("Also, please make sure your accounts file (default: accounts.txt) has those values present.\n"); + ShowInfo("The communication passwords can be changed in map_athena.conf and char_athena.conf\n"); + } else { + ShowStatus("Connected to login-server (connection #%d).\n", fd); + + //Send online accounts to login server. + send_accounts_tologin(-1, gettick(), 0, 0); + + // if no map-server already connected, display a message... + ARR_FIND( 0, MAX_MAP_SERVERS, i, server[i].fd > 0 && server[i].map[0] ); + if( i == MAX_MAP_SERVERS ) + ShowStatus("Awaiting maps from map-server.\n"); + } + RFIFOSKIP(fd,3); + break; + + // acknowledgement of account authentication request + case 0x2713: + if (RFIFOREST(fd) < 59) + return 0; + { + int account_id = RFIFOL(fd,2); + int login_id1 = RFIFOL(fd,6); + int login_id2 = RFIFOL(fd,10); + bool result = RFIFOB(fd,14); + const char* email = (const char*)RFIFOP(fd,15); + time_t expiration_time = (time_t)RFIFOL(fd,55); + + // find the session with this account id + ARR_FIND( 0, fd_max, i, session[i] && (sd = (struct char_session_data*)session[i]->session_data) && + sd->account_id == account_id && sd->login_id1 == login_id1 && sd->login_id2 == login_id2 ); + if( i < fd_max ) + { + if( result ) { // failure + WFIFOHEAD(i,3); + WFIFOW(i,0) = 0x6c; + WFIFOB(i,2) = 0x42; + WFIFOSET(i,3); + } else { // success + memcpy(sd->email, email, 40); + if (e_mail_check(sd->email) == 0) + strncpy(sd->email, "a@a.com", 40); // default e-mail + sd->expiration_time = expiration_time; + char_auth_ok(i, sd); + } + } + } + RFIFOSKIP(fd,59); + break; + + // Receiving of an e-mail/time limit from the login-server (answer of a request because a player comes back from map-server to char-server) by [Yor] + case 0x2717: + if (RFIFOREST(fd) < 50) + return 0; + for(i = 0; i < fd_max; i++) { + if (session[i] && (sd = (struct char_session_data*)session[i]->session_data)) { + if (sd->account_id == RFIFOL(fd,2)) { + memcpy(sd->email, RFIFOP(fd,6), 40); + if (e_mail_check(sd->email) == 0) + strncpy(sd->email, "a@a.com", 40); // default e-mail + sd->expiration_time = (time_t)RFIFOL(fd,46); + break; + } + } + } + RFIFOSKIP(fd,50); + break; + + // login-server alive packet + case 0x2718: + if (RFIFOREST(fd) < 2) + return 0; + RFIFOSKIP(fd,2); + break; + + // changesex reply + case 0x2723: + if (RFIFOREST(fd) < 7) + return 0; + { + int i, j; + unsigned char buf[7]; + + int acc = RFIFOL(fd,2); + int sex = RFIFOB(fd,6); + RFIFOSKIP(fd,7); + + if( acc > 0 ) + { + struct auth_node* node = (struct auth_node*)idb_get(auth_db, acc); + if( node != NULL ) + node->sex = sex; + + ARR_FIND( 0, char_num, i, char_dat[i].status.account_id == acc ); + if( i < char_num ) + { + int jobclass = char_dat[i].status.class_; + char_dat[i].status.sex = sex; + if (jobclass == JOB_BARD || jobclass == JOB_DANCER || + jobclass == JOB_CLOWN || jobclass == JOB_GYPSY || + jobclass == JOB_BABY_BARD || jobclass == JOB_BABY_DANCER) { + // job modification + if (jobclass == JOB_BARD || jobclass == JOB_DANCER) { + char_dat[i].status.class_ = (sex) ? JOB_BARD : JOB_DANCER; + } else if (jobclass == JOB_CLOWN || jobclass == JOB_GYPSY) { + char_dat[i].status.class_ = (sex) ? JOB_CLOWN : JOB_GYPSY; + } else if (jobclass == JOB_BABY_BARD || jobclass == JOB_BABY_DANCER) { + char_dat[i].status.class_ = (sex) ? JOB_BABY_BARD : JOB_BABY_DANCER; + } + // remove specifical skills of classes 19, 4020 and 4042 + for(j = 315; j <= 322; j++) { + if (char_dat[i].status.skill[j].id > 0 && !char_dat[i].status.skill[j].flag) { + if (char_dat[i].status.skill_point > USHRT_MAX - char_dat[i].status.skill[j].lv) + char_dat[i].status.skill_point = USHRT_MAX; + else + char_dat[i].status.skill_point += char_dat[i].status.skill[j].lv; + char_dat[i].status.skill[j].id = 0; + char_dat[i].status.skill[j].lv = 0; + } + } + // remove specifical skills of classes 20, 4021 and 4043 + for(j = 323; j <= 330; j++) { + if (char_dat[i].status.skill[j].id > 0 && !char_dat[i].status.skill[j].flag) { + if (char_dat[i].status.skill_point > USHRT_MAX - char_dat[i].status.skill[j].lv) + char_dat[i].status.skill_point = USHRT_MAX; + else + char_dat[i].status.skill_point += char_dat[i].status.skill[j].lv; + + char_dat[i].status.skill[j].id = 0; + char_dat[i].status.skill[j].lv = 0; + } + } + } + // to avoid any problem with equipment and invalid sex, equipment is unequiped. + for (j = 0; j < MAX_INVENTORY; j++) { + if (char_dat[i].status.inventory[j].nameid && char_dat[i].status.inventory[j].equip) + char_dat[i].status.inventory[j].equip = 0; + } + char_dat[i].status.weapon = 0; + char_dat[i].status.shield = 0; + char_dat[i].status.head_top = 0; + char_dat[i].status.head_mid = 0; + char_dat[i].status.head_bottom = 0; + + if (char_dat[i].status.guild_id) //If there is a guild, update the guild_member data [Skotlex] + inter_guild_sex_changed(char_dat[i].status.guild_id, acc, char_dat[i].status.char_id, sex); + } + // disconnect player if online on char-server + disconnect_player(acc); + } + WBUFW(buf,0) = 0x2b0d; + WBUFL(buf,2) = acc; + WBUFB(buf,6) = sex; + mapif_sendall(buf, 7); + } + break; + + case 0x2726: // Request to send a broadcast message (no answer) + if (RFIFOREST(fd) < 8 || RFIFOREST(fd) < (8 + RFIFOL(fd,4))) + return 0; + if (RFIFOL(fd,4) < 1) + char_log("Receiving a message for broadcast, but message is void.\n"); + else + { + // at least 1 map-server + ARR_FIND( 0, MAX_MAP_SERVERS, i, server[i].fd >= 0 ); + if (i == MAX_MAP_SERVERS) + char_log("'ladmin': Receiving a message for broadcast, but no map-server is online.\n"); + else { + unsigned char buf[128]; + char message[4096]; // +1 to add a null terminated if not exist in the packet + int lp; + char *p; + memset(message, '\0', sizeof(message)); + memcpy(message, RFIFOP(fd,8), RFIFOL(fd,4)); + message[sizeof(message)-1] = '\0'; + remove_control_chars(message); + // remove all first spaces + p = message; + while(p[0] == ' ') + p++; + // if message is only composed of spaces + if (p[0] == '\0') + char_log("Receiving a message for broadcast, but message is only a lot of spaces.\n"); + // else send message to all map-servers + else { + if (RFIFOW(fd,2) == 0) { + char_log("'ladmin': Receiving a message for broadcast (message (in yellow): %s)\n", + message); + lp = 4; + } else { + char_log("'ladmin': Receiving a message for broadcast (message (in blue): %s)\n", + message); + lp = 8; + } + // split message to max 80 char + while(p[0] != '\0') { // if not finish + if (p[0] == ' ') // jump if first char is a space + p++; + else { + char split[80]; + char* last_space; + sscanf(p, "%79[^\t]", split); // max 79 char, any char (\t is control char and control char was removed before) + split[sizeof(split)-1] = '\0'; // last char always \0 + if ((last_space = strrchr(split, ' ')) != NULL) { // searching space from end of the string + last_space[0] = '\0'; // replace it by NULL to have correct length of split + p++; // to jump the new NULL + } + p += strlen(split); + // send broadcast to all map-servers + WBUFW(buf,0) = 0x3800; + WBUFW(buf,2) = lp + strlen(split) + 1; + WBUFL(buf,4) = 0x65756c62; // only write if in blue (lp = 8) + memcpy(WBUFP(buf,lp), split, strlen(split) + 1); + mapif_sendall(buf, WBUFW(buf,2)); + } + } + } + } + } + RFIFOSKIP(fd,8 + RFIFOL(fd,4)); + break; + + // account_reg2変更通知 + case 0x2729: + if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2)) + return 0; + { //Receive account_reg2 registry, forward to map servers. + unsigned char buf[ACCOUNT_REG2_NUM*(256+32+2)+16]; + memcpy(buf,RFIFOP(fd,0), RFIFOW(fd,2)); +// WBUFW(buf,0) = 0x2b11; + WBUFW(buf,0) = 0x3804; //Map server can now receive all kinds of reg values with the same packet. [Skotlex] + mapif_sendall(buf, WBUFW(buf,2)); + RFIFOSKIP(fd, RFIFOW(fd,2)); + } + break; + + // Account deletion notification (from login-server) + case 0x2730: + if (RFIFOREST(fd) < 6) + return 0; + // Deletion of all characters of the account + for(i = 0; i < char_num; i++) { + if (char_dat[i].status.account_id == RFIFOL(fd,2)) { + char_delete(&char_dat[i].status); + if (i < char_num - 1) { + memcpy(&char_dat[i], &char_dat[char_num-1], sizeof(struct character_data)); + // if moved character owns to deleted account, check again it's character + if (char_dat[i].status.account_id == RFIFOL(fd,2)) { + i--; + // Correct moved character reference in the character's owner by [Yor] + } else { + int j, k; + struct char_session_data *sd2; + for (j = 0; j < fd_max; j++) { + if (session[j] && (sd2 = (struct char_session_data*)session[j]->session_data) && + sd2->account_id == char_dat[char_num-1].status.account_id) { + for (k = 0; k < MAX_CHARS; k++) { + if (sd2->found_char[k] == char_num-1) { + sd2->found_char[k] = i; + break; + } + } + break; + } + } + } + } + char_num--; + } + } + // Deletion of the storage + inter_storage_delete(RFIFOL(fd,2)); + // send to all map-servers to disconnect the player + { + unsigned char buf[6]; + WBUFW(buf,0) = 0x2b13; + WBUFL(buf,2) = RFIFOL(fd,2); + mapif_sendall(buf, 6); + } + // disconnect player if online on char-server + disconnect_player(RFIFOL(fd,2)); + RFIFOSKIP(fd,6); + break; + + // State change of account/ban notification (from login-server) by [Yor] + case 0x2731: + if (RFIFOREST(fd) < 11) + return 0; + // send to all map-servers to disconnect the player + { + unsigned char buf[11]; + WBUFW(buf,0) = 0x2b14; + WBUFL(buf,2) = RFIFOL(fd,2); + WBUFB(buf,6) = RFIFOB(fd,6); // 0: change of statut, 1: ban + WBUFL(buf,7) = RFIFOL(fd,7); // status or final date of a banishment + mapif_sendall(buf, 11); + } + // disconnect player if online on char-server + disconnect_player(RFIFOL(fd,2)); + RFIFOSKIP(fd,11); + break; + + // Receiving GM acounts info from login-server (by [Yor]) + case 0x2732: + if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2)) + return 0; + { + unsigned char buf[32000]; //FIXME: this will crash + if (gm_account != NULL) + aFree(gm_account); + CREATE(gm_account, struct gm_account, (RFIFOW(fd,2) - 4)/5); + GM_num = 0; + for (i = 4; i < RFIFOW(fd,2); i = i + 5) { + gm_account[GM_num].account_id = RFIFOL(fd,i); + gm_account[GM_num].level = (int)RFIFOB(fd,i+4); + //printf("GM account: %d -> level %d\n", gm_account[GM_num].account_id, gm_account[GM_num].level); + GM_num++; + } + ShowStatus("From login-server: receiving information of %d GM accounts.\n", GM_num); + char_log("From login-server: receiving information of %d GM accounts.\n", GM_num); + // send new gm acccounts level to map-servers + memcpy(buf, RFIFOP(fd,0), RFIFOW(fd,2)); + WBUFW(buf,0) = 0x2b15; + mapif_sendall(buf, RFIFOW(fd,2)); + + RFIFOSKIP(fd,RFIFOW(fd,2)); + } + break; + + // Login server request to kick a character out. [Skotlex] + case 0x2734: + if (RFIFOREST(fd) < 6) + return 0; + { + int aid = RFIFOL(fd,2); + struct online_char_data* character = (struct online_char_data*)idb_get(online_char_db, aid); + RFIFOSKIP(fd,6); + if( character != NULL ) + {// account is already marked as online! + if( character->server > -1 ) + { //Kick it from the map server it is on. + mapif_disconnectplayer(server[character->server].fd, character->account_id, character->char_id, 2); + if (character->waiting_disconnect == -1) + character->waiting_disconnect = add_timer(gettick()+AUTH_TIMEOUT, chardb_waiting_disconnect, character->account_id, 0); + } + else + {// Manual kick from char server. + struct char_session_data *tsd; + int i; + ARR_FIND( 0, fd_max, i, session[i] && (tsd = (struct char_session_data*)session[i]->session_data) && tsd->account_id == aid ); + if( i < fd_max ) + { + WFIFOHEAD(i,3); + WFIFOW(i,0) = 0x81; + WFIFOB(i,2) = 2; // "Someone has already logged in with this id" + WFIFOSET(i,3); + set_eof(i); + } + else //Shouldn't happen, but just in case. + set_char_offline(99, aid); + } + } + } + break; + + case 0x2735: + { + unsigned char buf[2]; + uint32 new_ip = 0; + + WBUFW(buf,0) = 0x2b1e; + mapif_sendall(buf, 2); + + new_ip = host2ip(login_ip_str); + if (new_ip && new_ip != login_ip) + login_ip = new_ip; //Update login up. + + new_ip = host2ip(char_ip_str); + if (new_ip && new_ip != char_ip) + { //Update ip. + char_ip = new_ip; + ShowInfo("Updating IP for [%s].\n", char_ip_str); + WFIFOHEAD(fd,6); + WFIFOW(fd,0) = 0x2736; + WFIFOL(fd,2) = htonl(char_ip); + WFIFOSET(fd,6); + } + + RFIFOSKIP(fd,2); + } + break; + + default: + ShowError("Unknown packet 0x%04x received from login-server, disconnecting.\n", RFIFOW(fd,0)); + set_eof(fd); + return 0; + } + } + + RFIFOFLUSH(fd); + return 0; +} + +int request_accreg2(int account_id, int char_id) +{ + if (login_fd > 0) { + WFIFOHEAD(login_fd,10); + WFIFOW(login_fd,0) = 0x272e; + WFIFOL(login_fd,2) = account_id; + WFIFOL(login_fd,6) = char_id; + WFIFOSET(login_fd,10); + return 1; + } + return 0; +} + +//Send packet forward to login-server for account saving +int save_accreg2(unsigned char* buf, int len) +{ + if (login_fd > 0) { + WFIFOHEAD(login_fd,len+4); + memcpy(WFIFOP(login_fd,4), buf, len); + WFIFOW(login_fd,0) = 0x2728; + WFIFOW(login_fd,2) = len+4; + WFIFOSET(login_fd,len+4); + return 1; + } + return 0; +} + +//Receive Registry information for a character. +int char_parse_Registry(int account_id, int char_id, unsigned char *buf, int buf_len) +{ + int i,j,p,len; + for (i = 0; i < char_num; i++) { + if (char_dat[i].status.account_id == account_id && char_dat[i].status.char_id == char_id) + break; + } + if(i >= char_num) //Character not found? + return 1; + for(j=0,p=0;j= char_num){ //Character not found? Sent empty packet. + WFIFOW(fd,2)=13; + }else{ + for (p=13,j = 0; j < char_dat[i].global_num; j++) { + if (char_dat[i].global[j].str[0]) { + p+= sprintf((char*)WFIFOP(fd,p), "%s", char_dat[i].global[j].str)+1; //We add 1 to consider the '\0' in place. + p+= sprintf((char*)WFIFOP(fd,p), "%s", char_dat[i].global[j].value)+1; + } + } + WFIFOW(fd,2)=p; + } + WFIFOSET(fd,WFIFOW(fd,2)); + return 0; +} + +void char_read_fame_list(void) +{ + int i, j, k; + struct fame_list fame_item; + CREATE_BUFFER(id, int, char_num); + + for(i = 0; i < char_num; i++) { + id[i] = i; + for(j = 0; j < i; j++) { + if (char_dat[i].status.fame > char_dat[id[j]].status.fame) { + for(k = i; k > j; k--) + id[k] = id[k-1]; + id[j] = i; // id[i] + break; + } + } + } + + // Empty ranking lists + 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)); + // Build Blacksmith ranking list + for (i = 0, j = 0; i < char_num && j < fame_list_size_smith; i++) { + if (char_dat[id[i]].status.fame && ( + char_dat[id[i]].status.class_ == JOB_BLACKSMITH || + char_dat[id[i]].status.class_ == JOB_WHITESMITH || + char_dat[id[i]].status.class_ == JOB_BABY_BLACKSMITH)) + { + fame_item.id = char_dat[id[i]].status.char_id; + fame_item.fame = char_dat[id[i]].status.fame; + strncpy(fame_item.name, char_dat[id[i]].status.name, NAME_LENGTH); + + memcpy(&smith_fame_list[j],&fame_item,sizeof(struct fame_list)); + j++; + } + } + // Build Alchemist ranking list + for (i = 0, j = 0; i < char_num && j < fame_list_size_chemist; i++) { + if (char_dat[id[i]].status.fame && ( + char_dat[id[i]].status.class_ == JOB_ALCHEMIST || + char_dat[id[i]].status.class_ == JOB_CREATOR || + char_dat[id[i]].status.class_ == JOB_BABY_ALCHEMIST)) + { + fame_item.id = char_dat[id[i]].status.char_id; + fame_item.fame = char_dat[id[i]].status.fame; + strncpy(fame_item.name, char_dat[id[i]].status.name, NAME_LENGTH); + + memcpy(&chemist_fame_list[j],&fame_item,sizeof(struct fame_list)); + + j++; + } + } + // Build Taekwon ranking list + for (i = 0, j = 0; i < char_num && j < fame_list_size_taekwon; i++) { + if (char_dat[id[i]].status.fame && + char_dat[id[i]].status.class_ == JOB_TAEKWON) + { + fame_item.id = char_dat[id[i]].status.char_id; + fame_item.fame = char_dat[id[i]].status.fame; + strncpy(fame_item.name, char_dat[id[i]].status.name, NAME_LENGTH); + + memcpy(&taekwon_fame_list[j],&fame_item,sizeof(struct fame_list)); + + j++; + } + } + DELETE_BUFFER(id); +} +// Send map-servers the fame ranking lists +int char_send_fame_list(int fd) +{ + int i, len = 8; + unsigned char buf[32000]; + + WBUFW(buf,0) = 0x2b1b; + + for(i = 0; i < fame_list_size_smith && smith_fame_list[i].id; i++) { + memcpy(WBUFP(buf, len), &smith_fame_list[i], sizeof(struct fame_list)); + len += sizeof(struct fame_list); + } + // add blacksmith's block length + WBUFW(buf, 6) = len; + + for(i = 0; i < fame_list_size_chemist && chemist_fame_list[i].id; i++) { + memcpy(WBUFP(buf, len), &chemist_fame_list[i], sizeof(struct fame_list)); + len += sizeof(struct fame_list); + } + // add alchemist's block length + WBUFW(buf, 4) = len; + + for(i = 0; i < fame_list_size_taekwon && taekwon_fame_list[i].id; i++) { + memcpy(WBUFP(buf, len), &taekwon_fame_list[i], sizeof(struct fame_list)); + len += sizeof(struct fame_list); + } + // add total packet length + WBUFW(buf, 2) = len; + + if(fd!=-1) + mapif_send(fd, buf, len); + else + mapif_sendall(buf, len); + + return 0; +} + +void char_update_fame_list(int type, int index, int fame) +{ + unsigned char buf[9]; + WBUFW(buf,0) = 0x2b22; + WBUFB(buf,2) = type; + WBUFB(buf,3) = index; + WBUFL(buf,4) = fame; + mapif_sendall(buf, 8); +} + +//Loads a character's name and stores it in the buffer given (must be NAME_LENGTH in size) +//Returns 1 on found, 0 on not found (buffer is filled with Unknown char name) +int char_loadName(int char_id, char* name) +{ + int j; + for( j = 0; j < char_num && char_dat[j].status.char_id != char_id; ++j ) + ;// find char + if( j < char_num ) + strncpy(name, char_dat[j].status.name, NAME_LENGTH); + else + strncpy(name, unknown_char_name, NAME_LENGTH); + + return (j < char_num) ? 1 : 0; +} + +int search_mapserver(unsigned short map, uint32 ip, uint16 port); + +int parse_frommap(int fd) +{ + int i, j; + int id; + + ARR_FIND( 0, MAX_MAP_SERVERS, id, server[id].fd == fd ); + if(id == MAX_MAP_SERVERS) + set_eof(fd); + if(session[fd]->flag.eof) { + if (id < MAX_MAP_SERVERS) { + unsigned char buf[16384]; + ShowStatus("Map-server %d (session #%d) has disconnected.\n", id, fd); + //Notify other map servers that this one is gone. [Skotlex] + WBUFW(buf,0) = 0x2b20; + WBUFL(buf,4) = htonl(server[id].ip); + WBUFW(buf,8) = htons(server[id].port); + j = 0; + for(i = 0; i < MAX_MAP_PER_SERVER; i++) + if (server[id].map[i]) + WBUFW(buf,10+(j++)*4) = server[id].map[i]; + if (j > 0) { + WBUFW(buf,2) = j * 4 + 10; + mapif_sendallwos(fd, buf, WBUFW(buf,2)); + } + server[id].fd = -1; + online_char_db->foreach(online_char_db,char_db_setoffline,i); //Tag relevant chars as 'in disconnected' server. + } + do_close(fd); + create_online_files(); + return 0; + } + + while(RFIFOREST(fd) >= 2) + { + //ShowDebug("Received packet 0x%4x (%d bytes) from map-server (connection %d)\n", RFIFOW(fd, 0), RFIFOREST(fd), fd); + + switch(RFIFOW(fd,0)) + { + + case 0x2af7: // request from map-server to reload GM accounts. Transmission to login-server + if (login_fd > 0) { // don't send request if no login-server + WFIFOHEAD(login_fd,2); + WFIFOW(login_fd,0) = 0x2709; + WFIFOSET(login_fd,2); + } + RFIFOSKIP(fd,2); + break; + + case 0x2afa: // Receiving map names list from the map-server + if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2)) + return 0; + + memset(server[id].map, 0, sizeof(server[id].map)); + j = 0; + for(i = 4; i < RFIFOW(fd,2); i += 4) { + server[id].map[j] = RFIFOW(fd,i); + j++; + } + + ShowStatus("Map-Server %d connected: %d maps, from IP %d.%d.%d.%d port %d.\n", + id, j, CONVIP(server[id].ip), server[id].port); + ShowStatus("Map-server %d loading complete.\n", id); + char_log("Map-Server %d connected: %d maps, from IP %d.%d.%d.%d port %d. Map-server %d loading complete.\n", + id, j, CONVIP(server[id].ip), server[id].port, id); + + // send name for wisp to player + WFIFOHEAD(fd, 3 + NAME_LENGTH); + WFIFOW(fd,0) = 0x2afb; + WFIFOB(fd,2) = 0; + memcpy(WFIFOP(fd,3), wisp_server_name, NAME_LENGTH); + WFIFOSET(fd,3+NAME_LENGTH); + + char_send_fame_list(fd); //Send fame list. + + { + unsigned char buf[16384]; + int x; + if (j == 0) { + ShowWarning("Map-server %d has NO maps.\n", id); + char_log("WARNING: Map-server %d has NO maps.\n", id); + } else { + // Transmitting maps information to the other map-servers + WBUFW(buf,0) = 0x2b04; + WBUFW(buf,2) = j * 4 + 10; + WBUFL(buf,4) = htonl(server[id].ip); + WBUFW(buf,8) = htons(server[id].port); + memcpy(WBUFP(buf,10), RFIFOP(fd,4), j * 4); + mapif_sendallwos(fd, buf, WBUFW(buf,2)); + } + // Transmitting the maps of the other map-servers to the new map-server + for(x = 0; x < MAX_MAP_SERVERS; x++) { + if (server[x].fd > 0 && x != id) { + WFIFOHEAD(fd,10 +4*MAX_MAP_PER_SERVER); + WFIFOW(fd,0) = 0x2b04; + WFIFOL(fd,4) = htonl(server[x].ip); + WFIFOW(fd,8) = htons(server[x].port); + j = 0; + for(i = 0; i < MAX_MAP_PER_SERVER; i++) + if (server[x].map[i]) + WFIFOW(fd,10+(j++)*4) = server[x].map[i]; + if (j > 0) { + WFIFOW(fd,2) = j * 4 + 10; + WFIFOSET(fd,WFIFOW(fd,2)); + } + } + } + } + RFIFOSKIP(fd,RFIFOW(fd,2)); + break; + + case 0x2afc: //Packet command is now used for sc_data request. [Skotlex] + if (RFIFOREST(fd) < 10) + return 0; + { +#ifdef ENABLE_SC_SAVING + int aid, cid; + struct scdata *data; + aid = RFIFOL(fd,2); + cid = RFIFOL(fd,6); + data = status_search_scdata(aid, cid); + if (data->count > 0) + { //Deliver status change data. + WFIFOW(fd,0) = 0x2b1d; + WFIFOW(fd,2) = 14 + data->count*sizeof(struct status_change_data); + WFIFOL(fd,4) = aid; + WFIFOL(fd,8) = cid; + WFIFOW(fd,12) = data->count; + for (i = 0; i < data->count; i++) + memcpy(WFIFOP(fd,14+i*sizeof(struct status_change_data)), &data->data[i], sizeof(struct status_change_data)); + WFIFOSET(fd, WFIFOW(fd,2)); + status_delete_scdata(aid, cid); //Data sent, so it needs be discarded now. + } +#endif + RFIFOSKIP(fd, 10); + } + break; + + case 0x2afe: //set MAP user count + if (RFIFOREST(fd) < 4) + return 0; + if (RFIFOW(fd,2) != server[id].users) { + server[id].users = RFIFOW(fd,2); + ShowInfo("User Count: %d (Server: %d)\n", server[id].users, id); + } + RFIFOSKIP(fd, 4); + break; + + case 0x2aff: //set MAP users + if (RFIFOREST(fd) < 6 || RFIFOREST(fd) < RFIFOW(fd,2)) + return 0; + //TODO: When data mismatches memory, update guild/party online/offline states. + server[id].users = RFIFOW(fd,4); + online_char_db->foreach(online_char_db,char_db_setoffline,id); //Set all chars from this server as 'unknown' + for(i = 0; i < server[id].users; i++) { + int aid, cid; + struct online_char_data* character; + aid = RFIFOL(fd,6+i*8); + cid = RFIFOL(fd,6+i*8+4); + character = (struct online_char_data*)idb_ensure(online_char_db, aid, create_online_char_data); + if (online_check && character->server > -1 && character->server != id) + { + ShowNotice("Set map user: Character (%d:%d) marked on map server %d, but map server %d claims to have (%d:%d) online!\n", + character->account_id, character->char_id, character->server, id, aid, cid); + mapif_disconnectplayer(server[character->server].fd, character->account_id, character->char_id, 2); + } + character->char_id = cid; + character->server = id; + } + //If any chars remain in -2, they will be cleaned in the cleanup timer. + RFIFOSKIP(fd,6+i*8); + break; + + case 0x2b01: // Receive character data from map-server for saving + if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2)) + return 0; + for(i = 0; i < char_num; i++) { + if (char_dat[i].status.account_id == RFIFOL(fd,4) && + char_dat[i].status.char_id == RFIFOL(fd,8)) + break; + } + if (i != char_num) + memcpy(&char_dat[i].status, RFIFOP(fd,13), sizeof(struct mmo_charstatus)); + if (RFIFOB(fd,12)) + { //Flag, set character offline. [Skotlex] + set_char_offline(RFIFOL(fd,8),RFIFOL(fd,4)); + WFIFOW(fd,0) = 0x2b21; //Save ack only needed on final save. + WFIFOL(fd,2) = RFIFOL(fd,4); + WFIFOL(fd,6) = RFIFOL(fd,8); + WFIFOSET(fd,10); + } + RFIFOSKIP(fd,RFIFOW(fd,2)); + break; + + case 0x2b02: // req char selection + if( RFIFOREST(fd) < 18 ) + return 0; + { + struct auth_node* node; + + int account_id = RFIFOL(fd,2); + uint32 login_id1 = RFIFOL(fd,6); + uint32 login_id2 = RFIFOL(fd,10); + uint32 ip = RFIFOL(fd,14); + RFIFOSKIP(fd,18); + + // create temporary auth entry + CREATE(node, struct auth_node, 1); + node->account_id = account_id; + node->char_id = 0; + node->login_id1 = login_id1; + node->login_id2 = login_id2; + //node->sex = 0; + node->ip = ntohl(ip); + node->expiration_time = 0; // unlimited/unknown time by default (not display in map-server) + idb_put(auth_db, account_id, node); + + //Set char to "@ char select" in online db [Kevin] + set_char_online(-3, 99, account_id); + + WFIFOHEAD(fd,7); + WFIFOW(fd,0) = 0x2b03; + WFIFOL(fd,2) = account_id; + WFIFOB(fd,6) = 0; + WFIFOSET(fd,7); + } + break; + + case 0x2b05: // request "change map server" + if (RFIFOREST(fd) < 35) + return 0; + { + unsigned short name; + int map_id, map_fd = -1; + struct online_char_data* data; + struct mmo_charstatus* char_data; + + name = RFIFOW(fd,18); + map_id = search_mapserver(name, ntohl(RFIFOL(fd,24)), ntohs(RFIFOW(fd,28))); //Locate mapserver by ip and port. + if (map_id >= 0) + map_fd = server[map_id].fd; + for(i = 0; i < char_num; i++) { + if (char_dat[i].status.account_id == RFIFOL(fd,2) && + char_dat[i].status.char_id == RFIFOL(fd,14)) + break; + } + char_data = i < char_num ? &char_dat[i].status : NULL; + //Tell the new map server about this player using Kevin's new auth packet. [Skotlex] + if (map_fd >= 0 && session[map_fd] && char_data) + { //Send the map server the auth of this player. + //Update the "last map" as this is where the player must be spawned on the new map server. + char_data->last_point.map = RFIFOW(fd,18); + char_data->last_point.x = RFIFOW(fd,20); + char_data->last_point.y = RFIFOW(fd,22); + char_data->sex = RFIFOB(fd,30); + + WFIFOHEAD(map_fd, 20 + sizeof(struct mmo_charstatus)); + WFIFOW(map_fd,0) = 0x2afd; + WFIFOW(map_fd,2) = 20 + sizeof(struct mmo_charstatus); + WFIFOL(map_fd,4) = RFIFOL(fd,2); //Account ID + WFIFOL(map_fd,8) = RFIFOL(fd,6); //Login1 + WFIFOL(map_fd,16) = RFIFOL(fd,10); //Login2 + WFIFOL(map_fd,12) = (unsigned long)0; //TODO: expiration_time, how do I figure it out right now? + memcpy(WFIFOP(map_fd,20), char_data, sizeof(struct mmo_charstatus)); + WFIFOSET(map_fd, WFIFOW(map_fd,2)); + + data = (struct online_char_data*)idb_ensure(online_char_db, RFIFOL(fd,2), create_online_char_data); + data->char_id = char_data->char_id; + data->server = map_id; //Update server where char is. + + //Reply with an ack. + WFIFOHEAD(fd,30); + WFIFOW(fd,0) = 0x2b06; + memcpy(WFIFOP(fd,2), RFIFOP(fd,2), 28); + WFIFOSET(fd,30); + } else { //Reply with nak + WFIFOHEAD(fd,30); + WFIFOW(fd,0) = 0x2b06; + memcpy(WFIFOP(fd,2), RFIFOP(fd,2), 28); + WFIFOL(fd,6) = 0; //Set login1 to 0. + WFIFOSET(fd,30); + } + RFIFOSKIP(fd,35); + } + break; + + case 0x2b08: // char name request + if (RFIFOREST(fd) < 6) + return 0; + + WFIFOHEAD(fd,30); + WFIFOW(fd,0) = 0x2b09; + WFIFOL(fd,2) = RFIFOL(fd,2); + char_loadName((int)RFIFOL(fd,2), (char*)WFIFOP(fd,6)); + WFIFOSET(fd,30); + + RFIFOSKIP(fd,6); + break; + + case 0x2b0c: // Map server send information to change an email of an account -> login-server + if (RFIFOREST(fd) < 86) + return 0; + if (login_fd > 0) { // don't send request if no login-server + WFIFOHEAD(login_fd,86); + memcpy(WFIFOP(login_fd,0), RFIFOP(fd,0),86); // 0x2722 .L .40B .40B + WFIFOW(login_fd,0) = 0x2722; + WFIFOSET(login_fd,86); + } + RFIFOSKIP(fd, 86); + break; + + case 0x2b0e: // Request from map-server to change an account's status (will just be forwarded to login server) + if (RFIFOREST(fd) < 44) + return 0; + { + int result = 0; // 0-login-server request done, 1-player not found, 2-gm level too low, 3-login-server offline + char character_name[NAME_LENGTH]; + + int acc = RFIFOL(fd,2); // account_id of who ask (-1 if server itself made this request) + const char* name = (char*)RFIFOP(fd,6); // name of the target character + int type = RFIFOW(fd,30); // type of operation: 1-block, 2-ban, 3-unblock, 4-unban + short year = RFIFOW(fd,32); + short month = RFIFOW(fd,34); + short day = RFIFOW(fd,36); + short hour = RFIFOW(fd,38); + short minute = RFIFOW(fd,40); + short second = RFIFOW(fd,42); + RFIFOSKIP(fd,44); + + safestrncpy(character_name, name, NAME_LENGTH); + i = search_character_index(character_name); + if( i < 0 ) + { + result = 1; // 1-player not found + } + else + { + char name[NAME_LENGTH]; + int account_id; + + account_id = char_dat[i].status.account_id; + safestrncpy(name, char_dat[i].status.name, NAME_LENGTH); + + if( login_fd <= 0 ) + result = 3; // 3-login-server offline + else + if( acc != -1 && isGM(acc) < isGM(account_id) ) + result = 2; // 2-gm level too low + else + switch( type ) { + case 1: // block + WFIFOHEAD(login_fd,10); + WFIFOW(login_fd,0) = 0x2724; + WFIFOL(login_fd,2) = account_id; + WFIFOL(login_fd,6) = 5; // new account status + WFIFOSET(login_fd,10); + break; + case 2: // ban + WFIFOHEAD(login_fd,18); + WFIFOW(login_fd, 0) = 0x2725; + WFIFOL(login_fd, 2) = account_id; + WFIFOW(login_fd, 6) = year; + WFIFOW(login_fd, 8) = month; + WFIFOW(login_fd,10) = day; + WFIFOW(login_fd,12) = hour; + WFIFOW(login_fd,14) = minute; + WFIFOW(login_fd,16) = second; + WFIFOSET(login_fd,18); + break; + case 3: // unblock + WFIFOHEAD(login_fd,10); + WFIFOW(login_fd,0) = 0x2724; + WFIFOL(login_fd,2) = account_id; + WFIFOL(login_fd,6) = 0; // new account status + WFIFOSET(login_fd,10); + break; + case 4: // unban + WFIFOHEAD(login_fd,6); + WFIFOW(login_fd,0) = 0x272a; + WFIFOL(login_fd,2) = account_id; + WFIFOSET(login_fd,6); + break; + case 5: // changesex + WFIFOHEAD(login_fd,6); + WFIFOW(login_fd,0) = 0x2727; + WFIFOL(login_fd,2) = account_id; + WFIFOSET(login_fd,6); + break; + } + } + + // send answer if a player ask, not if the server ask + if( acc != -1 ) { + WFIFOHEAD(fd,34); + WFIFOW(fd, 0) = 0x2b0f; + WFIFOL(fd, 2) = acc; + safestrncpy((char*)WFIFOP(fd,6), name, NAME_LENGTH); + WFIFOW(fd,30) = type; + WFIFOW(fd,32) = result; + WFIFOSET(fd,34); + } + } + break; + + case 0x2b10: // Update and send fame ranking list + if (RFIFOREST(fd) < 11) + return 0; + { + int cid = RFIFOL(fd, 2); + int fame = RFIFOL(fd, 6); + char type = RFIFOB(fd, 10); + int size; + struct fame_list* list; + int player_pos; + int fame_pos; + + switch(type) + { + case 1: size = fame_list_size_smith; list = smith_fame_list; break; + case 2: size = fame_list_size_chemist; list = chemist_fame_list; break; + case 3: size = fame_list_size_taekwon; list = taekwon_fame_list; break; + default: size = 0; list = NULL; break; + } + + ARR_FIND(0, size, player_pos, list[player_pos].id == cid);// position of the player + ARR_FIND(0, size, fame_pos, list[fame_pos].fame <= fame);// where the player should be + + if( player_pos == size && fame_pos == size ) + ;// not on list and not enough fame to get on it + else if( fame_pos == player_pos ) + {// same position + list[player_pos].fame = fame; + char_update_fame_list(type, player_pos, fame); + } + else + {// move in the list + if( player_pos == size ) + {// new ranker - not in the list + ARR_MOVE(size - 1, fame_pos, list, struct fame_list); + list[fame_pos].id = cid; + list[fame_pos].fame = fame; + char_loadName(cid, list[fame_pos].name); + } + else + {// already in the list + if( fame_pos == size ) + --fame_pos;// move to the end of the list + ARR_MOVE(player_pos, fame_pos, list, struct fame_list); + list[fame_pos].fame = fame; + } + char_send_fame_list(-1); + } + + RFIFOSKIP(fd,11); + } + break; + + case 0x2b16: // Receive rates [Wizputer] + if (RFIFOREST(fd) < 6 || RFIFOREST(fd) < RFIFOW(fd,8)) + return 0; + // Txt doesn't need this packet, so just skip it + RFIFOSKIP(fd,RFIFOW(fd,8)); + break; + + case 0x2b17: // Character disconnected set online 0 [Wizputer] + if (RFIFOREST(fd) < 6) + return 0; + set_char_offline(RFIFOL(fd,2),RFIFOL(fd,6)); + RFIFOSKIP(fd,10); + break; + + case 0x2b18: // Reset all chars to offline [Wizputer] + set_all_offline(id); + RFIFOSKIP(fd,2); + break; + + case 0x2b19: // Character set online [Wizputer] + if (RFIFOREST(fd) < 10) + return 0; + set_char_online(id, RFIFOL(fd,2),RFIFOL(fd,6)); + RFIFOSKIP(fd,10); + break; + + case 0x2b1a: // Build and send fame ranking lists [DracoRPG] + if (RFIFOREST(fd) < 2) + return 0; + char_read_fame_list(); + char_send_fame_list(-1); + RFIFOSKIP(fd,2); + break; + + case 0x2b1c: //Request to save status change data. [Skotlex] + if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2)) + return 0; + { +#ifdef ENABLE_SC_SAVING + int count, aid, cid; + struct scdata *data; + + aid = RFIFOL(fd, 4); + cid = RFIFOL(fd, 8); + count = RFIFOW(fd, 12); + + data = status_search_scdata(aid, cid); + if (data->count != count) + { + data->count = count; + data->data = (struct status_change_data*)aRealloc(data->data, count*sizeof(struct status_change_data)); + } + for (i = 0; i < count; i++) + memcpy (&data->data[i], RFIFOP(fd, 14+i*sizeof(struct status_change_data)), sizeof(struct status_change_data)); +#endif + RFIFOSKIP(fd, RFIFOW(fd, 2)); + } + break; + + case 0x2b23: // map-server alive packet + WFIFOHEAD(fd,2); + WFIFOW(fd,0) = 0x2b24; + WFIFOSET(fd,2); + RFIFOSKIP(fd,2); + break; + + case 0x2736: // ip address update + if (RFIFOREST(fd) < 6) return 0; + server[id].ip = ntohl(RFIFOL(fd, 2)); + ShowInfo("Updated IP address of map-server #%d to %d.%d.%d.%d.\n", id, CONVIP(server[id].ip)); + RFIFOSKIP(fd,6); + break; + + default: + { + // inter server - packet + int r = inter_parse_frommap(fd); + if (r == 1) break; // processed + if (r == 2) return 0; // need more packet + + // no inter server packet. no char server packet -> disconnect + ShowError("Unknown packet 0x%04x from map server, disconnecting.\n", RFIFOW(fd,0)); + set_eof(fd); + return 0; + } + } // switch + } // while + + return 0; +} + +// Searches for the mapserver that has a given map (and optionally ip/port, if not -1). +// If found, returns the server's index in the 'server' array (otherwise returns -1). +int search_mapserver(unsigned short map, uint32 ip, uint16 port) +{ + int i, j; + + for(i = 0; i < MAX_MAP_SERVERS; i++) + { + if (server[i].fd > 0 + && (ip == (uint32)-1 || server[i].ip == ip) + && (port == (uint16)-1 || server[i].port == port)) + { + for (j = 0; server[i].map[j]; j++) + if (server[i].map[j] == map) + return i; + } + } + + return -1; +} + +// char_mapifの初期化処理(現在はinter_mapif初期化のみ) +static int char_mapif_init(int fd) +{ + return inter_mapif_init(fd); +} + +//-------------------------------------------- +// Test to know if an IP come from LAN or WAN. +//-------------------------------------------- +int lan_subnetcheck(uint32 ip) +{ + int i; + ARR_FIND( 0, subnet_count, i, (subnet[i].char_ip & subnet[i].mask) == (ip & subnet[i].mask) ); + if ( i < subnet_count ) { + ShowInfo("Subnet check [%u.%u.%u.%u]: Matches "CL_CYAN"%u.%u.%u.%u/%u.%u.%u.%u"CL_RESET"\n", CONVIP(ip), CONVIP(subnet[i].char_ip & subnet[i].mask), CONVIP(subnet[i].mask)); + return subnet[i].char_ip; + } else { + ShowInfo("Subnet check [%u.%u.%u.%u]: "CL_CYAN"WAN"CL_RESET"\n", CONVIP(ip)); + return 0; + } +} + +int parse_char(int fd) +{ + int i, ch; + char email[40]; + unsigned short cmd; + int map_fd; + struct char_session_data* sd; + uint32 ipl = session[fd]->client_addr; + + sd = (struct char_session_data*)session[fd]->session_data; + + // disconnect any player if no login-server. + if(login_fd < 0) + set_eof(fd); + + if(session[fd]->flag.eof) + { + if( sd != NULL && sd->auth ) + { + struct online_char_data* data = (struct online_char_data*)idb_get(online_char_db, sd->account_id); + if( data == NULL || data->server == -1) //If it is not in any server, send it offline. [Skotlex] + set_char_offline(-1,sd->account_id); + if( data != NULL && data->fd == fd) + data->fd = -1; + } + do_close(fd); + return 0; + } + + while( RFIFOREST(fd) >= 2 ) + { + //For use in packets that depend on an sd being present [Skotlex] + #define FIFOSD_CHECK(rest) { if(RFIFOREST(fd) < rest) return 0; if (sd==NULL || !sd->auth) { RFIFOSKIP(fd,rest); return 0; } } + + cmd = RFIFOW(fd,0); + switch( cmd ) + { + + // request to connect + // 0065 .L .L .L .W .B + case 0x65: + if( RFIFOREST(fd) < 17 ) + return 0; + { + struct auth_node* node; + int GM_value; + + int account_id = RFIFOL(fd,2); + uint32 login_id1 = RFIFOL(fd,6); + uint32 login_id2 = RFIFOL(fd,10); + int sex = RFIFOB(fd,16); + RFIFOSKIP(fd,17); + + ShowInfo("request connect - account_id:%d/login_id1:%d/login_id2:%d\n", account_id, login_id1, login_id2); + + if (sd) { + //Received again auth packet for already authentified account?? Discard it. + //TODO: Perhaps log this as a hack attempt? + //TODO: and perhaps send back a reply? + break; + } + + if( (GM_value = isGM(account_id)) != 0 ) + ShowInfo("Account Logged On; Account ID: %d (GM level %d).\n", account_id, GM_value); + else + ShowInfo("Account Logged On; Account ID: %d.\n", account_id); + + CREATE(session[fd]->session_data, struct char_session_data, 1); + sd = (struct char_session_data*)session[fd]->session_data; + strncpy(sd->email, "no mail", 40); // put here a mail without '@' to refuse deletion if we don't receive the e-mail + sd->expiration_time = 0; // unknown or unlimited (not displaying on map-server) + sd->account_id = account_id; + sd->login_id1 = login_id1; + sd->login_id2 = login_id2; + sd->sex = sex; + sd->auth = false; // not authed yet + + // send back account_id + WFIFOHEAD(fd,4); + WFIFOL(fd,0) = account_id; + WFIFOSET(fd,4); + + // search authentification + node = (struct auth_node*)idb_get(auth_db, account_id); + if( node != NULL && + node->account_id == account_id && + node->login_id1 == login_id1 && + node->login_id2 == login_id2 && + node->ip == ipl ) + {// authentication found (coming from map server) + idb_remove(auth_db, account_id); + char_auth_ok(fd, sd); + } + else + {// authentication not found (coming from login server) + if (login_fd > 0) { // don't send request if no login-server + WFIFOHEAD(login_fd,19); + WFIFOW(login_fd,0) = 0x2712; // ask login-server to authentify an account + WFIFOL(login_fd,2) = sd->account_id; + WFIFOL(login_fd,6) = sd->login_id1; + WFIFOL(login_fd,10) = sd->login_id2; + WFIFOB(login_fd,14) = sd->sex; + WFIFOL(login_fd,15) = htonl(ipl); + WFIFOSET(login_fd,19); + } else { // if no login-server, we must refuse connection + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x6c; + WFIFOB(fd,2) = 0; + WFIFOSET(fd,3); + } + } + } + break; + + // char select + case 0x66: + FIFOSD_CHECK(3); + { + struct mmo_charstatus *cd; + uint32 subnet_map_ip; + struct auth_node* node; + + int slot = RFIFOB(fd,2); + RFIFOSKIP(fd,3); + + // if we activated email creation and email is default email + if (email_creation != 0 && strcmp(sd->email, "a@a.com") == 0 && login_fd > 0) { // to modify an e-mail, login-server must be online + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x70; + WFIFOB(fd,2) = 0; // 00 = Incorrect Email address + WFIFOSET(fd,3); + break; + } + // otherwise, load the character + ARR_FIND( 0, MAX_CHARS, ch, sd->found_char[ch] >= 0 && char_dat[sd->found_char[ch]].status.slot == slot ); + if (ch == MAX_CHARS) + { //Not found?? May be forged packet. + break; + } + cd = &char_dat[sd->found_char[ch]].status; + char_log("Character Selected, Account ID: %d, Character Slot: %d, Character Name: %s.\n", sd->account_id, slot, cd->name); + + cd->sex = sd->sex; + + // searching map server + i = search_mapserver(cd->last_point.map,-1,-1); + + // if map is not found, we check major cities + if (i < 0) { + unsigned short j; + //First check that there's actually a map server online. + ARR_FIND( 0, MAX_MAP_SERVERS, j, server[j].fd >= 0 && server[j].map[0] ); + if (j == MAX_MAP_SERVERS) { + ShowInfo("Connection Closed. No map servers available.\n"); + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x81; + WFIFOB(fd,2) = 1; // 01 = Server closed + WFIFOSET(fd,3); + break; + } + if ((i = search_mapserver((j=mapindex_name2id(MAP_PRONTERA)),-1,-1)) >= 0) { + cd->last_point.x = 273; + cd->last_point.y = 354; + } else if ((i = search_mapserver((j=mapindex_name2id(MAP_GEFFEN)),-1,-1)) >= 0) { + cd->last_point.x = 120; + cd->last_point.y = 100; + } else if ((i = search_mapserver((j=mapindex_name2id(MAP_MORROC)),-1,-1)) >= 0) { + cd->last_point.x = 160; + cd->last_point.y = 94; + } else if ((i = search_mapserver((j=mapindex_name2id(MAP_ALBERTA)),-1,-1)) >= 0) { + cd->last_point.x = 116; + cd->last_point.y = 57; + } else if ((i = search_mapserver((j=mapindex_name2id(MAP_PAYON)),-1,-1)) >= 0) { + cd->last_point.x = 87; + cd->last_point.y = 117; + } else if ((i = search_mapserver((j=mapindex_name2id(MAP_IZLUDE)),-1,-1)) >= 0) { + cd->last_point.x = 94; + cd->last_point.y = 103; + } else { + ShowInfo("Connection Closed. No map server available that has a major city, and unable to find map-server for '%s'.\n", mapindex_id2name(cd->last_point.map)); + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x81; + WFIFOB(fd,2) = 1; // 01 = Server closed + WFIFOSET(fd,3); + break; + } + ShowWarning("Unable to find map-server for '%s', sending to major city '%s'.\n", mapindex_id2name(cd->last_point.map), mapindex_id2name(j)); + cd->last_point.map = j; + } + + //Send NEW auth packet [Kevin] + //FIXME: is this case even possible? [ultramage] + if ((map_fd = server[i].fd) < 1 || session[map_fd] == NULL) + { + ShowError("parse_char: Attempting to write to invalid session %d! Map Server #%d disconnected.\n", map_fd, i); + server[i].fd = -1; + memset(&server[i], 0, sizeof(struct mmo_map_server)); + //Send server closed. + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x81; + WFIFOB(fd,2) = 1; // 01 = Server closed + WFIFOSET(fd,3); + break; + } + + //Send player to map + WFIFOHEAD(fd,28); + WFIFOW(fd,0) = 0x71; + WFIFOL(fd,2) = cd->char_id; + mapindex_getmapname_ext(mapindex_id2name(cd->last_point.map), (char*)WFIFOP(fd,6)); + + // Advanced subnet check [LuzZza] + subnet_map_ip = lan_subnetcheck(ipl); + WFIFOL(fd,22) = htonl((subnet_map_ip) ? subnet_map_ip : server[i].ip); + WFIFOW(fd,26) = ntows(htons(server[i].port)); // [!] LE byte order here [!] + WFIFOSET(fd,28); + + ShowInfo("Character selection '%s' (account: %d, slot: %d).\n", cd->name, sd->account_id, ch); + + //Send auth ok to map server + WFIFOHEAD(map_fd,20 + sizeof(struct mmo_charstatus)); + WFIFOW(map_fd,0) = 0x2afd; + WFIFOW(map_fd,2) = 20 + sizeof(struct mmo_charstatus); + WFIFOL(map_fd,4) = sd->account_id; + WFIFOL(map_fd,8) = sd->login_id1; + WFIFOL(map_fd,16) = sd->login_id2; + WFIFOL(map_fd,12) = (unsigned long)sd->expiration_time; + memcpy(WFIFOP(map_fd,20), cd, sizeof(struct mmo_charstatus)); + WFIFOSET(map_fd, WFIFOW(map_fd,2)); + + // create temporary auth entry + CREATE(node, struct auth_node, 1); + node->account_id = sd->account_id; + node->char_id = cd->char_id; + node->login_id1 = sd->login_id1; + node->login_id2 = sd->login_id2; + node->sex = sd->sex; + node->expiration_time = sd->expiration_time; + node->ip = ipl; + idb_put(auth_db, sd->account_id, node); + } + break; + + // create new char + // S 0067 .24B .B .B .B .B .B .B .B .W .W + case 0x67: + FIFOSD_CHECK(37); + + if( !char_new ) //turn character creation on/off [Kevin] + i = -2; + else + i = make_new_char(sd, (char*)RFIFOP(fd,2),RFIFOB(fd,26),RFIFOB(fd,27),RFIFOB(fd,28),RFIFOB(fd,29),RFIFOB(fd,30),RFIFOB(fd,31),RFIFOB(fd,32),RFIFOW(fd,33),RFIFOW(fd,35)); + + //'Charname already exists' (-1), 'Char creation denied' (-2) and 'You are underaged' (-3) + if (i < 0) + { + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x6e; + switch (i) { + case -1: WFIFOB(fd,2) = 0x00; break; + case -2: WFIFOB(fd,2) = 0x02; break; + case -3: WFIFOB(fd,2) = 0x01; break; + } + WFIFOSET(fd,3); + } + else + { + int len; + // send to player + WFIFOHEAD(fd,110); + WFIFOW(fd,0) = 0x6d; + len = 2 + mmo_char_tobuf(WFIFOP(fd,2), &char_dat[i].status); + WFIFOSET(fd,len); + + // add new entry to the chars list + ARR_FIND( 0, MAX_CHARS, ch, sd->found_char[ch] == -1 ); + if( ch < MAX_CHARS ) + sd->found_char[ch] = i; // position of the new char in the char_dat[] array + } + + RFIFOSKIP(fd,37); + break; + + // delete char + case 0x68: + // 2004-04-19aSakexe+ langtype 12 char deletion packet + case 0x1fb: + if (cmd == 0x68) FIFOSD_CHECK(46); + if (cmd == 0x1fb) FIFOSD_CHECK(56); + { + int cid = RFIFOL(fd,2); + struct mmo_charstatus* cs = NULL; + ShowInfo(CL_RED"Request Char Deletion: "CL_GREEN"%d (%d)"CL_RESET"\n", sd->account_id, cid); + memcpy(email, RFIFOP(fd,6), 40); + RFIFOSKIP(fd,RFIFOREST(fd)); // hack to make the other deletion packet work + + if (e_mail_check(email) == 0) + strncpy(email, "a@a.com", 40); // default e-mail + + // BEGIN HACK: "change email using the char deletion 'confirm email' menu" + // if we activated email creation and email is default email + if (email_creation != 0 && strcmp(sd->email, "a@a.com") == 0 && login_fd > 0) { // to modify an e-mail, login-server must be online + // if sended email is incorrect e-mail + if (strcmp(email, "a@a.com") == 0) { + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x70; + WFIFOB(fd,2) = 0; // 00 = Incorrect Email address + WFIFOSET(fd,3); + break; + } + // we change the packet to set it like selection. + ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] != -1 && char_dat[sd->found_char[i]].status.char_id == cid ); + if( i < MAX_CHARS ) + { + // we save new e-mail + memcpy(sd->email, email, 40); + // we send new e-mail to login-server ('online' login-server is checked before) + WFIFOHEAD(login_fd,46); + WFIFOW(login_fd,0) = 0x2715; + WFIFOL(login_fd,2) = sd->account_id; + memcpy(WFIFOP(login_fd, 6), email, 40); + WFIFOSET(login_fd,46); + + // change value to put new packet (char selection) + RFIFOSKIP(fd,-3); //FIXME: Will this work? Messing with the received buffer is ugly anyway... + RFIFOW(fd,0) = 0x66; + RFIFOB(fd,2) = char_dat[sd->found_char[i]].status.slot; + // not send packet, it's modify of actual packet + } else { + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x70; + WFIFOB(fd,2) = 0; // 00 = Incorrect Email address + WFIFOSET(fd,3); + } + break; + } + // END HACK + + // otherwise, we delete the character + if (strcmpi(email, sd->email) != 0) { // if it's an invalid email + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x70; + WFIFOB(fd,2) = 0; // 00 = Incorrect Email address + WFIFOSET(fd,3); + break; + } + + // check if this char exists + ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] != -1 && char_dat[sd->found_char[i]].status.char_id == cid ); + if( i == MAX_CHARS ) + { // Such a character does not exist in the account + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x70; + WFIFOB(fd,2) = 0; + WFIFOSET(fd,3); + break; + } + + // deletion process + cs = &char_dat[sd->found_char[i]].status; + char_delete(cs); + if (sd->found_char[i] != char_num - 1) { + int j, k; + struct char_session_data *sd2; + memcpy(&char_dat[sd->found_char[i]], &char_dat[char_num-1], sizeof(struct mmo_charstatus)); + // Correct moved character reference in the character's owner + for (j = 0; j < fd_max; j++) { + if (session[j] && (sd2 = (struct char_session_data*)session[j]->session_data) && + sd2->account_id == char_dat[char_num-1].status.account_id) { + for (k = 0; k < MAX_CHARS; k++) { + if (sd2->found_char[k] == char_num-1) { + sd2->found_char[k] = sd->found_char[i]; + break; + } + } + break; + } + } + } + char_num--; + + // remove char from list and compact it + for(ch = i; ch < MAX_CHARS-1; ch++) + sd->found_char[ch] = sd->found_char[ch+1]; + sd->found_char[MAX_CHARS-1] = -1; + + /* Char successfully deleted.*/ + WFIFOHEAD(fd,2); + WFIFOW(fd,0) = 0x6f; + WFIFOSET(fd,2); + } + break; + + // client keep-alive packet (every 12 seconds) + // R 0187 .l + case 0x187: + if (RFIFOREST(fd) < 6) + return 0; + RFIFOSKIP(fd,6); + break; + + // char rename request + // R 028d .l .l .24B + case 0x28d: + FIFOSD_CHECK(34); + //not implemented + RFIFOSKIP(fd,34); + break; + + // login as map-server + case 0x2af8: + if (RFIFOREST(fd) < 60) + return 0; + { + char* l_user = (char*)RFIFOP(fd,2); + char* l_pass = (char*)RFIFOP(fd,26); + l_user[23] = '\0'; + l_pass[23] = '\0'; + ARR_FIND( 0, MAX_MAP_SERVERS, i, server[i].fd <= 0 ); + if (i == MAX_MAP_SERVERS || strcmp(l_user, userid) || strcmp(l_pass, passwd)) { + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x2af9; + WFIFOB(fd,2) = 3; + WFIFOSET(fd,3); + } else { + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x2af9; + WFIFOB(fd,2) = 0; + WFIFOSET(fd,3); + + server[i].fd = fd; + server[i].ip = ntohl(RFIFOL(fd,54)); + server[i].port = ntohs(RFIFOW(fd,58)); + server[i].users = 0; + memset(server[i].map, 0, sizeof(server[i].map)); + session[fd]->func_parse = parse_frommap; + session[fd]->flag.server = 1; + realloc_fifo(fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK); + char_mapif_init(fd); + // send gm acccounts level to map-servers + WFIFOHEAD(fd,4+5*GM_num); + WFIFOW(fd,0) = 0x2b15; + for(i = 0; i < GM_num; i++) { + WFIFOL(fd,4+5*i) = gm_account[i].account_id; + WFIFOB(fd,4+5*i+4) = (unsigned char)gm_account[i].level; + } + WFIFOW(fd,2) = 4+5*GM_num; + WFIFOSET(fd,WFIFOW(fd,2)); + } + + RFIFOSKIP(fd,60); + } + return 0; // avoid processing of followup packets here + + // Athena info get + case 0x7530: + WFIFOHEAD(fd,10); + WFIFOW(fd,0) = 0x7531; + WFIFOB(fd,2) = ATHENA_MAJOR_VERSION; + WFIFOB(fd,3) = ATHENA_MINOR_VERSION; + WFIFOB(fd,4) = ATHENA_REVISION; + WFIFOB(fd,5) = ATHENA_RELEASE_FLAG; + WFIFOB(fd,6) = ATHENA_OFFICIAL_FLAG; + WFIFOB(fd,7) = ATHENA_SERVER_INTER | ATHENA_SERVER_CHAR; + WFIFOW(fd,8) = ATHENA_MOD_VERSION; + WFIFOSET(fd,10); + + RFIFOSKIP(fd,2); + break; + + // unknown packet received + default: + ShowError("parse_char: Received unknown packet "CL_WHITE"0x%x"CL_RESET" from ip '"CL_WHITE"%s"CL_RESET"'! Disconnecting!\n", RFIFOW(fd,0), ip2str(ipl, NULL)); + set_eof(fd); + return 0; + } + } + + RFIFOFLUSH(fd); + return 0; +} + +// Console Command Parser [Wizputer] +int parse_console(char* buf) +{ + char command[256]; + + memset(command, 0, sizeof(command)); + + sscanf(buf, "%[^\n]", command); + + //login_log("Console command :%s\n", command); + + if( strcmpi("shutdown", command) == 0 || + strcmpi("exit", command) == 0 || + strcmpi("quit", command) == 0 || + strcmpi("end", command) == 0 ) + runflag = 0; + else if( strcmpi("alive", command) == 0 || + strcmpi("status", command) == 0 ) + ShowInfo(CL_CYAN"Console: "CL_BOLD"I'm Alive."CL_RESET"\n"); + else if( strcmpi("help", command) == 0 ){ + ShowInfo(CL_BOLD"Help of commands:"CL_RESET"\n"); + ShowInfo(" To shutdown the server:\n"); + ShowInfo(" 'shutdown|exit|qui|end'\n"); + ShowInfo(" To know if server is alive:\n"); + ShowInfo(" 'alive|status'\n"); + } + + return 0; +} + +// 全てのMAPサーバーにデータ送信(送信したmap鯖の数を返す) +int mapif_sendall(unsigned char *buf, unsigned int len) +{ + int i, c; + + c = 0; + for(i = 0; i < MAX_MAP_SERVERS; i++) { + int fd; + if ((fd = server[i].fd) > 0) { + WFIFOHEAD(fd,len); + memcpy(WFIFOP(fd,0), buf, len); + WFIFOSET(fd,len); + c++; + } + } + + return c; +} + +// 自分以外の全てのMAPサーバーにデータ送信(送信したmap鯖の数を返す) +int mapif_sendallwos(int sfd, unsigned char *buf, unsigned int len) +{ + int i, c; + + c = 0; + for(i = 0; i < MAX_MAP_SERVERS; i++) { + int fd; + if ((fd = server[i].fd) > 0 && fd != sfd) { + WFIFOHEAD(fd,len); + memcpy(WFIFOP(fd,0), buf, len); + WFIFOSET(fd,len); + c++; + } + } + + return c; +} +// MAPサーバーにデータ送信(map鯖生存確認有り) +int mapif_send(int fd, unsigned char *buf, unsigned int len) +{ + int i; + + if (fd >= 0) { + for(i = 0; i < MAX_MAP_SERVERS; i++) { + if (fd == server[i].fd) { + WFIFOHEAD(fd,len); + memcpy(WFIFOP(fd,0), buf, len); + WFIFOSET(fd,len); + return 1; + } + } + } + return 0; +} + +int broadcast_user_count(int tid, unsigned int tick, int id, int data) +{ + uint8 buf[6]; + int users = count_users(); + + // only send an update when needed + static int prev_users = 0; + if( prev_users == users ) + return 0; + prev_users = users; + + if( login_fd > 0 && session[login_fd] ) + { + // send number of user to login server + WFIFOHEAD(login_fd,6); + WFIFOW(login_fd,0) = 0x2714; + WFIFOL(login_fd,2) = users; + WFIFOSET(login_fd,6); + } + + // send number of players to all map-servers + WBUFW(buf,0) = 0x2b00; + WBUFL(buf,2) = users; + mapif_sendall(buf,6); + + // refresh online files (txt and html) + create_online_files(); + + return 0; +} + +/// load this char's account id into the 'online accounts' packet +static int send_accounts_tologin_sub(DBKey key, void* data, va_list ap) +{ + struct online_char_data* character = (struct online_char_data*)data; + int* i = va_arg(ap, int*); + + if(character->server > -1) + { + WFIFOL(login_fd,8+(*i)*4) = character->account_id; + (*i)++; + return 1; + } + return 0; +} + +int send_accounts_tologin(int tid, unsigned int tick, int id, int data) +{ + if (login_fd > 0 && session[login_fd]) + { + // send account list to login server + int users = online_char_db->size(online_char_db); + int i = 0; + + WFIFOHEAD(login_fd,8+users*4); + WFIFOW(login_fd,0) = 0x272d; + online_char_db->foreach(online_char_db, send_accounts_tologin_sub, &i, users); + WFIFOW(login_fd,2) = 8+ i*4; + WFIFOL(login_fd,4) = i; + WFIFOSET(login_fd,WFIFOW(login_fd,2)); + } + return 0; +} + +int check_connect_login_server(int tid, unsigned int tick, int id, int data) +{ + if (login_fd > 0 && session[login_fd] != NULL) + return 0; + + ShowInfo("Attempt to connect to login-server...\n"); + login_fd = make_connection(login_ip, login_port); + if (login_fd == -1) + { //Try again later. [Skotlex] + login_fd = 0; + return 0; + } + session[login_fd]->func_parse = parse_fromlogin; + session[login_fd]->flag.server = 1; + realloc_fifo(login_fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK); + + WFIFOHEAD(login_fd,86); + WFIFOW(login_fd,0) = 0x2710; + memcpy(WFIFOP(login_fd,2), userid, 24); + memcpy(WFIFOP(login_fd,26), passwd, 24); + WFIFOL(login_fd,50) = 0; + WFIFOL(login_fd,54) = htonl(char_ip); + WFIFOL(login_fd,58) = htons(char_port); + memcpy(WFIFOP(login_fd,60), server_name, 20); + WFIFOW(login_fd,80) = 0; + WFIFOW(login_fd,82) = char_maintenance; + WFIFOW(login_fd,84) = char_new_display; //only display (New) if they want to [Kevin] + WFIFOSET(login_fd,86); + + return 1; +} + +// sends a ping packet to login server (will receive pong 0x2718) +int ping_login_server(int tid, unsigned int tick, int id, int data) +{ + if (login_fd > 0 && session[login_fd] != NULL) + { + WFIFOHEAD(login_fd,2); + WFIFOW(login_fd,0) = 0x2719; + WFIFOSET(login_fd,2); + } + return 0; +} + +//------------------------------------------------ +//Invoked 15 seconds after mapif_disconnectplayer in case the map server doesn't +//replies/disconnect the player we tried to kick. [Skotlex] +//------------------------------------------------ +static int chardb_waiting_disconnect(int tid, unsigned int tick, int id, int data) +{ + struct online_char_data* character; + if ((character = (struct online_char_data*)idb_get(online_char_db, id)) != NULL && character->waiting_disconnect == tid) + { //Mark it offline due to timeout. + character->waiting_disconnect = -1; + set_char_offline(character->char_id, character->account_id); + } + return 0; +} + +static int online_data_cleanup_sub(DBKey key, void *data, va_list ap) +{ + struct online_char_data *character= (struct online_char_data*)data; + if (character->fd != -1) + return 0; //Character still connected + if (character->server == -2) //Unknown server.. set them offline + set_char_offline(character->char_id, character->account_id); + if (character->server < 0) + //Free data from players that have not been online for a while. + db_remove(online_char_db, key); + return 0; +} + +static int online_data_cleanup(int tid, unsigned int tick, int id, int data) +{ + online_char_db->foreach(online_char_db, online_data_cleanup_sub); + return 0; +} + +//---------------------------------- +// Reading Lan Support configuration +// Rewrote: Anvanced subnet check [LuzZza] +//---------------------------------- +int char_lan_config_read(const char *lancfgName) +{ + FILE *fp; + int line_num = 0; + char line[1024], w1[64], w2[64], w3[64], w4[64]; + + if((fp = fopen(lancfgName, "r")) == NULL) { + ShowWarning("LAN Support configuration file is not found: %s\n", lancfgName); + return 1; + } + + ShowInfo("Reading the configuration file %s...\n", lancfgName); + + while(fgets(line, sizeof(line), fp)) + { + line_num++; + if ((line[0] == '/' && line[1] == '/') || line[0] == '\n' || line[1] == '\n') + continue; + + if(sscanf(line,"%[^:]: %[^:]:%[^:]:%[^\r\n]", w1, w2, w3, w4) != 4) { + + ShowWarning("Error syntax of configuration file %s in line %d.\n", lancfgName, line_num); + continue; + } + + remove_control_chars(w1); + remove_control_chars(w2); + remove_control_chars(w3); + remove_control_chars(w4); + + if( strcmpi(w1, "subnet") == 0 ) + { + subnet[subnet_count].mask = str2ip(w2); + subnet[subnet_count].char_ip = str2ip(w3); + subnet[subnet_count].map_ip = str2ip(w4); + + if( (subnet[subnet_count].char_ip & subnet[subnet_count].mask) != (subnet[subnet_count].map_ip & subnet[subnet_count].mask) ) + { + ShowError("%s: Configuration Error: The char server (%s) and map server (%s) belong to different subnetworks!\n", lancfgName, w3, w4); + continue; + } + + subnet_count++; + } + } + + ShowStatus("Read information about %d subnetworks.\n", subnet_count); + + fclose(fp); + return 0; +} +#endif //TXT_SQL_CONVERT + +int char_config_read(const char *cfgName) +{ + char line[1024], w1[1024], w2[1024]; + FILE* fp = fopen(cfgName, "r"); + + if (fp == NULL) { + ShowError("Configuration file not found: %s.\n", cfgName); + return 1; + } + + ShowInfo("Reading configuration file %s...\n", cfgName); + while(fgets(line, sizeof(line), fp)) + { + if (line[0] == '/' && line[1] == '/') + continue; + + if (sscanf(line, "%[^:]: %[^\r\n]", w1, w2) != 2) + continue; + + remove_control_chars(w1); + remove_control_chars(w2); + if(strcmpi(w1,"timestamp_format") == 0) { + strncpy(timestamp_format, w2, 20); + } else if(strcmpi(w1,"console_silent")==0){ + ShowInfo("Console Silent Setting: %d\n", atoi(w2)); + msg_silent = atoi(w2); +#ifndef TXT_SQL_CONVERT + } else if(strcmpi(w1,"stdout_with_ansisequence")==0){ + stdout_with_ansisequence = config_switch(w2); + } else if (strcmpi(w1, "userid") == 0) { + strncpy(userid, w2, 24); + } else if (strcmpi(w1, "passwd") == 0) { + strncpy(passwd, w2, 24); + } else if (strcmpi(w1, "server_name") == 0) { + strncpy(server_name, w2, 20); + server_name[sizeof(server_name) - 1] = '\0'; + ShowStatus("%s server has been initialized\n", w2); + } else if (strcmpi(w1, "wisp_server_name") == 0) { + if (strlen(w2) >= 4) { + memcpy(wisp_server_name, w2, sizeof(wisp_server_name)); + wisp_server_name[sizeof(wisp_server_name) - 1] = '\0'; + } + } else if (strcmpi(w1, "login_ip") == 0) { + char ip_str[16]; + login_ip = host2ip(w2); + if (login_ip) { + strncpy(login_ip_str, w2, sizeof(login_ip_str)); + ShowStatus("Login server IP address : %s -> %s\n", w2, ip2str(login_ip, ip_str)); + } + } else if (strcmpi(w1, "login_port") == 0) { + login_port = atoi(w2); + } else if (strcmpi(w1, "char_ip") == 0) { + char ip_str[16]; + char_ip = host2ip(w2); + if (char_ip){ + strncpy(char_ip_str, w2, sizeof(char_ip_str)); + ShowStatus("Character server IP address : %s -> %s\n", w2, ip2str(char_ip, ip_str)); + } + } else if (strcmpi(w1, "bind_ip") == 0) { + char ip_str[16]; + bind_ip = host2ip(w2); + if (bind_ip) { + strncpy(bind_ip_str, w2, sizeof(bind_ip_str)); + ShowStatus("Character server binding IP address : %s -> %s\n", w2, ip2str(bind_ip, ip_str)); + } + } else if (strcmpi(w1, "char_port") == 0) { + char_port = atoi(w2); + } else if (strcmpi(w1, "char_maintenance") == 0) { + char_maintenance = atoi(w2); + } else if (strcmpi(w1, "char_new") == 0) { + char_new = (bool)atoi(w2); + } else if (strcmpi(w1, "char_new_display") == 0) { + char_new_display = atoi(w2); + } else if (strcmpi(w1, "email_creation") == 0) { + email_creation = config_switch(w2); + } else if (strcmpi(w1, "scdata_txt") == 0) { //By Skotlex + strcpy(scdata_txt, w2); +#endif + } else if (strcmpi(w1, "char_txt") == 0) { + strcpy(char_txt, w2); + } else if (strcmpi(w1, "friends_txt") == 0) { //By davidsiaw + strcpy(friends_txt, w2); + } else if (strcmpi(w1, "hotkeys_txt") == 0) { //By davidsiaw + strcpy(hotkeys_txt, w2); +#ifndef TXT_SQL_CONVERT + } else if (strcmpi(w1, "max_connect_user") == 0) { + max_connect_user = atoi(w2); + if (max_connect_user < 0) + max_connect_user = 0; // unlimited online players + } else if(strcmpi(w1, "gm_allow_level") == 0) { + gm_allow_level = atoi(w2); + if(gm_allow_level < 0) + gm_allow_level = 99; + } else if (strcmpi(w1, "online_check") == 0) { + online_check = config_switch(w2); + } else if (strcmpi(w1, "autosave_time") == 0) { + autosave_interval = atoi(w2)*1000; + if (autosave_interval <= 0) + autosave_interval = DEFAULT_AUTOSAVE_INTERVAL; + } else if (strcmpi(w1, "save_log") == 0) { + save_log = config_switch(w2); + } else if (strcmpi(w1, "start_point") == 0) { + char map[MAP_NAME_LENGTH_EXT]; + int x, y; + if (sscanf(w2, "%15[^,],%d,%d", map, &x, &y) < 3) + continue; + start_point.map = mapindex_name2id(map); + if (!start_point.map) { + ShowError("Specified start_point %s not found in map-index cache.\n", map); + start_point.map = 0; + } + start_point.x = x; + start_point.y = y; + } else if (strcmpi(w1, "start_zeny") == 0) { + start_zeny = atoi(w2); + if (start_zeny < 0) + start_zeny = 0; + } else if (strcmpi(w1, "start_weapon") == 0) { + start_weapon = atoi(w2); + if (start_weapon < 0) + start_weapon = 0; + } else if (strcmpi(w1, "start_armor") == 0) { + start_armor = atoi(w2); + if (start_armor < 0) + start_armor = 0; + } else if(strcmpi(w1,"log_char")==0) { //log char or not [devil] + log_char = atoi(w2); + } else if (strcmpi(w1, "unknown_char_name") == 0) { + strcpy(unknown_char_name, w2); + unknown_char_name[NAME_LENGTH-1] = '\0'; + } else if (strcmpi(w1, "char_log_filename") == 0) { + strcpy(char_log_filename, w2); + } else if (strcmpi(w1, "name_ignoring_case") == 0) { + name_ignoring_case = (bool)config_switch(w2); + } else if (strcmpi(w1, "char_name_option") == 0) { + char_name_option = atoi(w2); + } else if (strcmpi(w1, "char_name_letters") == 0) { + strcpy(char_name_letters, w2); + } else if (strcmpi(w1, "char_rename") == 0) { + char_rename = config_switch(w2); +// online files options + } else if (strcmpi(w1, "online_txt_filename") == 0) { + strcpy(online_txt_filename, w2); + } else if (strcmpi(w1, "online_html_filename") == 0) { + strcpy(online_html_filename, w2); + } else if (strcmpi(w1, "online_sorting_option") == 0) { + online_sorting_option = atoi(w2); + } else if (strcmpi(w1, "online_display_option") == 0) { + online_display_option = atoi(w2); + } else if (strcmpi(w1, "online_gm_display_min_level") == 0) { // minimum GM level to display 'GM' when we want to display it + online_gm_display_min_level = atoi(w2); + if (online_gm_display_min_level < 5) // send online file every 5 seconds to player is enough + online_gm_display_min_level = 5; + } else if (strcmpi(w1, "online_refresh_html") == 0) { + online_refresh_html = atoi(w2); + if (online_refresh_html < 1) + online_refresh_html = 1; + } else if(strcmpi(w1,"db_path")==0) { + strcpy(db_path,w2); + } else if (strcmpi(w1, "console") == 0) { + console = config_switch(w2); + } else if (strcmpi(w1, "fame_list_alchemist") == 0) { + fame_list_size_chemist = atoi(w2); + if (fame_list_size_chemist > MAX_FAME_LIST) { + ShowWarning("Max fame list size is %d (fame_list_alchemist)\n", MAX_FAME_LIST); + fame_list_size_chemist = MAX_FAME_LIST; + } + } else if (strcmpi(w1, "fame_list_blacksmith") == 0) { + fame_list_size_smith = atoi(w2); + if (fame_list_size_smith > MAX_FAME_LIST) { + ShowWarning("Max fame list size is %d (fame_list_blacksmith)\n", MAX_FAME_LIST); + fame_list_size_smith = MAX_FAME_LIST; + } + } else if (strcmpi(w1, "fame_list_taekwon") == 0) { + fame_list_size_taekwon = atoi(w2); + if (fame_list_size_taekwon > MAX_FAME_LIST) { + ShowWarning("Max fame list size is %d (fame_list_taekwon)\n", MAX_FAME_LIST); + fame_list_size_taekwon = MAX_FAME_LIST; + } + } else if (strcmpi(w1, "guild_exp_rate") == 0) { + guild_exp_rate = atoi(w2); +#endif //TXT_SQL_CONVERT + } else if (strcmpi(w1, "import") == 0) { + char_config_read(w2); + } + } + fclose(fp); + + ShowInfo("Done reading %s.\n", cfgName); + return 0; +} + +#ifndef TXT_SQL_CONVERT +int chardb_final(int key, void* data, va_list va) +{ + aFree(data); + return 0; +} +void do_final(void) +{ + ShowStatus("Terminating server.\n"); + + mmo_char_sync(); + inter_save(); + set_all_offline(-1); + flush_fifos(); + // write online players files with no player + online_char_db->clear(online_char_db, NULL); //clean the db... + create_online_files(); + online_char_db->destroy(online_char_db, NULL); //dispose the db... + auth_db->destroy(auth_db, NULL); + + if(gm_account) aFree(gm_account); + if(char_dat) aFree(char_dat); + + if (login_fd > 0) + do_close(login_fd); + if (char_fd > 0) + do_close(char_fd); + +#ifdef ENABLE_SC_SAVING + status_final(); +#endif + inter_final(); + mapindex_final(); + + char_log("----End of char-server (normal end with closing of all files).\n"); +} + +//------------------------------ +// Function called when the server +// has received a crash signal. +//------------------------------ +void do_abort(void) +{ +} + +void set_server_type(void) +{ + SERVER_TYPE = ATHENA_SERVER_CHAR; +} + +int do_init(int argc, char **argv) +{ + int i; + + for(i = 0; i < MAX_MAP_SERVERS; i++) { + memset(&server[i], 0, sizeof(struct mmo_map_server)); + server[i].fd = -1; + } + + //Read map indexes + mapindex_init(); + start_point.map = mapindex_name2id("new_zone01"); + + char_config_read((argc < 2) ? CHAR_CONF_NAME : argv[1]); + char_lan_config_read((argc > 3) ? argv[3] : LAN_CONF_NAME); + + if (strcmp(userid, "s1")==0 && strcmp(passwd, "p1")==0) { + ShowError("Using the default user/password s1/p1 is NOT RECOMMENDED.\n"); + ShowNotice("Please edit your save/account.txt file to create a proper inter-server user/password (gender 'S')\n"); + ShowNotice("And then change the user/password to use in conf/char_athena.conf (or conf/import/char_conf.txt)\n"); + } + + ShowInfo("Finished reading the char-server configuration.\n"); + + // a newline in the log... + char_log(""); + // moved behind char_config_read in case we changed the filename [celest] + char_log("The char-server starting...\n"); + + ShowInfo("Initializing char server.\n"); + auth_db = idb_alloc(DB_OPT_RELEASE_DATA); + online_char_db = idb_alloc(DB_OPT_RELEASE_DATA); + mmo_char_init(); + char_read_fame_list(); //Read fame lists. +#ifdef ENABLE_SC_SAVING + status_init(); +#endif + inter_init_txt((argc > 2) ? argv[2] : inter_cfgName); // inter server 初期化 + ShowInfo("char server initialized.\n"); + + set_defaultparse(parse_char); + + if ((naddr_ != 0) && (!login_ip || !char_ip)) + { + char ip_str[16]; + ip2str(addr_[0], ip_str); + + if (naddr_ > 1) + ShowStatus("Multiple interfaces detected.. using %s as our IP address\n", ip_str); + else + ShowStatus("Defaulting to %s as our IP address\n", ip_str); + if (!login_ip) { + strcpy(login_ip_str, ip_str); + login_ip = str2ip(login_ip_str); + } + if (!char_ip) { + strcpy(char_ip_str, ip_str); + char_ip = str2ip(char_ip_str); + } + } + + // establish char-login connection if not present + add_timer_func_list(check_connect_login_server, "check_connect_login_server"); + add_timer_interval(gettick() + 1000, check_connect_login_server, 0, 0, 10 * 1000); + + // keep the char-login connection alive + add_timer_func_list(ping_login_server, "ping_login_server"); + add_timer_interval(gettick() + 1000, ping_login_server, 0, 0, ((int)stall_time-2) * 1000); + + // periodically update the overall user count on all mapservers + login server + add_timer_func_list(broadcast_user_count, "broadcast_user_count"); + add_timer_interval(gettick() + 1000, broadcast_user_count, 0, 0, 5 * 1000); + + // send a list of all online account IDs to login server + add_timer_func_list(send_accounts_tologin, "send_accounts_tologin"); + add_timer_interval(gettick() + 1000, send_accounts_tologin, 0, 0, 3600 * 1000); //Sync online accounts every hour + + // ??? + add_timer_func_list(chardb_waiting_disconnect, "chardb_waiting_disconnect"); + + // ??? + add_timer_func_list(online_data_cleanup, "online_data_cleanup"); + add_timer_interval(gettick() + 1000, online_data_cleanup, 0, 0, 600 * 1000); + + // periodic flush of all saved data to disk + add_timer_func_list(mmo_char_sync_timer, "mmo_char_sync_timer"); + add_timer_interval(gettick() + 1000, mmo_char_sync_timer, 0, 0, autosave_interval); + + if( console ) + { + //##TODO invoke a CONSOLE_START plugin event + } + + char_fd = make_listen_bind(bind_ip, char_port); + char_log("The char-server is ready (Server is listening on the port %d).\n", char_port); + ShowStatus("The char-server is "CL_GREEN"ready"CL_RESET" (Server is listening on the port %d).\n\n", char_port); + + return 0; +} + +#endif //TXT_SQL_CONVERT diff --git a/src/char/char.h b/src/char/char.h new file mode 100644 index 000000000..72077ac09 --- /dev/null +++ b/src/char/char.h @@ -0,0 +1,54 @@ +// Copyright (c) Athena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + +#ifndef _CHAR_H_ +#define _CHAR_H_ + +#include "../common/mmo.h" + +#define START_CHAR_NUM 150000 +#define MAX_MAP_SERVERS 30 + +#define DEFAULT_AUTOSAVE_INTERVAL 300*1000 + +struct character_data { + struct mmo_charstatus status; + int global_num; + struct global_reg global[GLOBAL_REG_NUM]; +}; + +struct mmo_charstatus* search_character(int aid, int cid); +struct mmo_charstatus* search_character_byname(char* character_name); +int search_character_index(char* character_name); +char* search_character_name(int index); +int search_character_online(int aid, int cid); + +int mapif_sendall(unsigned char *buf, unsigned int len); +int mapif_sendallwos(int fd,unsigned char *buf, unsigned int len); +int mapif_send(int fd,unsigned char *buf, unsigned int len); + +int char_married(int pl1,int pl2); +int char_child(int parent_id, int child_id); +int char_family(int cid1, int cid2, int cid3); +void char_clearparty(int party_id); + +int char_log(char *fmt, ...); + +int request_accreg2(int account_id, int char_id); +int char_parse_Registry(int account_id, int char_id, unsigned char *buf, int len); +int save_accreg2(unsigned char *buf, int len); +int char_account_reg_reply(int fd,int account_id,int char_id); + +extern int char_name_option; +extern char char_name_letters[]; +extern int autosave_interval; +extern char db_path[]; +extern int guild_exp_rate; +extern int log_inter; +//Exported for use in the TXT-SQL converter. +extern char char_txt[]; +int char_config_read(const char *cfgName); +int mmo_char_fromstr(char *str, struct mmo_charstatus *p, struct global_reg *reg, int *reg_num); +int parse_friend_txt(struct mmo_charstatus *p); + +#endif /* _CHAR_H_ */ diff --git a/src/char/int_guild.c b/src/char/int_guild.c new file mode 100644 index 000000000..e8379c130 --- /dev/null +++ b/src/char/int_guild.c @@ -0,0 +1,1579 @@ +// Copyright (c) Athena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + +#include "../common/cbasetypes.h" +#include "../common/mmo.h" +#include "../common/malloc.h" +#include "../common/socket.h" +#include "../common/db.h" +#include "../common/lock.h" +#include "../common/showmsg.h" +#include "../common/strlib.h" +#include "char.h" +#include "inter.h" +#include "int_storage.h" +#include "int_guild.h" + +#include +#include +#include + +char guild_txt[1024] = "save/guild.txt"; +char castle_txt[1024] = "save/castle.txt"; + +#ifndef TXT_SQL_CONVERT +static DBMap* guild_db; // int guild_id -> struct guild* +static DBMap* castle_db; // int castle_id -> struct guild_castle* + +static int guild_newid = 10000; + +static unsigned int guild_exp[100]; + +int mapif_guild_broken(int guild_id, int flag); +static bool guild_check_empty(struct guild *g); +int guild_calcinfo(struct guild *g); +int mapif_guild_basicinfochanged(int guild_id, int type, const void *data, int len); +int mapif_guild_info(int fd, struct guild *g); +int guild_break_sub(DBKey key, void *data, va_list ap); + +/// serializes the guild data structure into the provided string +int inter_guild_tostr(char* str, struct guild* g) +{ + int i, c, len; + + // save guild base info + len = sprintf(str, "%d\t%s\t%s\t%d,%d,%u,%d,%d\t%s#\t%s#\t", + g->guild_id, g->name, g->master, g->guild_lv, g->max_member, g->exp, g->skill_point, 0, g->mes1, g->mes2); + + // save guild member info + for(i = 0; i < g->max_member; i++) + { + struct guild_member *m = &g->member[i]; + len += sprintf(str + len, "%d,%d,%d,%d,%d,%d,%d,%u,%d,%d\t%s\t", + m->account_id, m->char_id, + m->hair, m->hair_color, m->gender, + m->class_, m->lv, m->exp, m->exp_payper, m->position, + ((m->account_id > 0) ? m->name : "-")); + } + + // save guild position info + for(i = 0; i < MAX_GUILDPOSITION; i++) { + struct guild_position *p = &g->position[i]; + len += sprintf(str + len, "%d,%d\t%s#\t", p->mode, p->exp_mode, p->name); + } + + // save guild emblem + len += sprintf(str + len, "%d,%d,", g->emblem_len, g->emblem_id); + for(i = 0; i < g->emblem_len; i++) { + len += sprintf(str + len, "%02x", (unsigned char)(g->emblem_data[i])); + } + len += sprintf(str + len, "$\t"); + + // save guild alliance info + c = 0; + for(i = 0; i < MAX_GUILDALLIANCE; i++) + if (g->alliance[i].guild_id > 0) + c++; + len += sprintf(str + len, "%d\t", c); + for(i = 0; i < MAX_GUILDALLIANCE; i++) { + struct guild_alliance *a = &g->alliance[i]; + if (a->guild_id > 0) + len += sprintf(str + len, "%d,%d\t%s\t", a->guild_id, a->opposition, a->name); + } + + // save guild expulsion info + c = 0; + for(i = 0; i < MAX_GUILDEXPULSION; i++) + if (g->expulsion[i].account_id > 0) + c++; + len += sprintf(str + len, "%d\t", c); + for(i = 0; i < MAX_GUILDEXPULSION; i++) { + struct guild_expulsion *e = &g->expulsion[i]; + if (e->account_id > 0) + len += sprintf(str + len, "%d,%d,%d,%d\t%s\t%s\t%s#\t", + e->account_id, 0, 0, 0, e->name, "#", e->mes ); + } + + // save guild skill info + for(i = 0; i < MAX_GUILDSKILL; i++) { + len += sprintf(str + len, "%d,%d ", g->skill[i].id, g->skill[i].lv); + } + len += sprintf(str + len, "\t"); + + return 0; +} +#endif //TXT_SQL_CONVERT + +/// parses the guild data string into a guild data structure +int inter_guild_fromstr(char* str, struct guild* g) +{ + int i, c; + char *pstr; + + memset(g, 0, sizeof(struct guild)); + + {// load guild base info + int guildid; + char name[256]; // only 24 used + char master[256]; // only 24 used + int guildlv; + int max_member; + unsigned int exp; + int skpoint; + char mes1[256]; // only 60 used + char mes2[256]; // only 120 used + int len; + + if( sscanf(str, "%d\t%[^\t]\t%[^\t]\t%d,%d,%u,%d,%*d\t%[^\t]\t%[^\t]\t%n", + &guildid, name, master, &guildlv, &max_member, &exp, &skpoint, mes1, mes2, &len) < 9 ) + return 1; + + // remove '#' + mes1[strlen(mes1)-1] = '\0'; + mes2[strlen(mes2)-1] = '\0'; + + g->guild_id = guildid; + g->guild_lv = guildlv; + g->max_member = max_member; + g->exp = exp; + g->skill_point = skpoint; + safestrncpy(g->name, name, sizeof(g->name)); + safestrncpy(g->master, master, sizeof(g->master)); + safestrncpy(g->mes1, mes1, sizeof(g->mes1)); + safestrncpy(g->mes2, mes2, sizeof(g->mes2)); + + str+= len; + } + + {// load guild member info + int accountid; + int charid; + int hair, hair_color, gender; + int class_, lv; + unsigned int exp; + int exp_payper; + int position; + char name[256]; // only 24 used + int len; + int i; + + for( i = 0; i < g->max_member; i++ ) + { + struct guild_member* m = &g->member[i]; + if (sscanf(str, "%d,%d,%d,%d,%d,%d,%d,%u,%d,%d\t%[^\t]\t%n", + &accountid, &charid, &hair, &hair_color, &gender, + &class_, &lv, &exp, &exp_payper, &position, + name, &len) < 11) + return 1; + + m->account_id = accountid; + m->char_id = charid; + m->hair = hair; + m->hair_color = hair_color; + m->gender = gender; + m->class_ = class_; + m->lv = lv; + m->exp = exp; + m->exp_payper = exp_payper; + m->position = position; + safestrncpy(m->name, name, NAME_LENGTH); + + str+= len; + } + } + + {// load guild position info + int mode, exp_mode; + char name[256]; // only 24 used + int len; + int i = 0; + int j; + + while (sscanf(str, "%d,%d%n", &mode, &exp_mode, &j) == 2 && str[j] == '\t') + { + struct guild_position *p = &g->position[i]; + if (sscanf(str, "%d,%d\t%[^\t]\t%n", &mode, &exp_mode, name, &len) < 3) + return 1; + + p->mode = mode; + p->exp_mode = exp_mode; + name[strlen(name)-1] = 0; + safestrncpy(p->name, name, NAME_LENGTH); + + i++; + str+= len; + } + } + + {// load guild emblem + int emblemlen; + int emblemid; + char emblem[4096]; + int len; + + emblemid = 0; + if( sscanf(str, "%d,%d,%[^\t]\t%n", &emblemlen, &emblemid, emblem, &len) < 3 ) + if( sscanf(str, "%d,%[^\t]\t%n", &emblemlen, emblem, &len) < 2 ) //! pre-svn format + return 1; + + g->emblem_len = emblemlen; + g->emblem_id = emblemid; + for(i = 0, pstr = emblem; i < g->emblem_len; i++, pstr += 2) { + int c1 = pstr[0], c2 = pstr[1], x1 = 0, x2 = 0; + if (c1 >= '0' && c1 <= '9') x1 = c1 - '0'; + if (c1 >= 'a' && c1 <= 'f') x1 = c1 - 'a' + 10; + if (c1 >= 'A' && c1 <= 'F') x1 = c1 - 'A' + 10; + if (c2 >= '0' && c2 <= '9') x2 = c2 - '0'; + if (c2 >= 'a' && c2 <= 'f') x2 = c2 - 'a' + 10; + if (c2 >= 'A' && c2 <= 'F') x2 = c2 - 'A' + 10; + g->emblem_data[i] = (x1<<4) | x2; + } + + str+= len; + } + + {// load guild alliance info + int guildid; + int opposition; + char name[256]; // only 24 used + int len; + + if (sscanf(str, "%d\t%n", &c, &len) < 1) + return 1; + str+= len; + + for(i = 0; i < c; i++) + { + struct guild_alliance* a = &g->alliance[i]; + if (sscanf(str, "%d,%d\t%[^\t]\t%n", &guildid, &opposition, name, &len) < 3) + return 1; + + a->guild_id = guildid; + a->opposition = opposition; + safestrncpy(a->name, name, NAME_LENGTH); + + str+= len; + } + } + + {// load guild expulsion info + int accountid; + char name[256]; // only 24 used + char message[256]; // only 40 used + int len; + int i; + + if (sscanf(str, "%d\t%n", &c, &len) < 1) + return 1; + str+= len; + + for(i = 0; i < c; i++) + { + struct guild_expulsion *e = &g->expulsion[i]; + if (sscanf(str, "%d,%*d,%*d,%*d\t%[^\t]\t%*[^\t]\t%[^\t]\t%n", &accountid, name, message, &len) < 3) + return 1; + + e->account_id = accountid; + safestrncpy(e->name, name, sizeof(e->name)); + message[strlen(message)-1] = 0; // remove '#' + safestrncpy(e->mes, message, sizeof(e->mes)); + + str+= len; + } + } + + {// load guild skill info + int skillid; + int skilllv; + int len; + int i; + + for(i = 0; i < MAX_GUILDSKILL; i++) + { + if (sscanf(str, "%d,%d %n", &skillid, &skilllv, &len) < 2) + break; + g->skill[i].id = skillid; + g->skill[i].lv = skilllv; + + str+= len; + } + str = strchr(str, '\t'); + } + + return 0; +} + +#ifndef TXT_SQL_CONVERT +// ギルド城データの文字列への変換 +int inter_guildcastle_tostr(char *str, struct guild_castle *gc) +{ + int len; + + len = sprintf(str, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d", + gc->castle_id, gc->guild_id, gc->economy, gc->defense, gc->triggerE, + gc->triggerD, gc->nextTime, gc->payTime, gc->createTime, gc->visibleC, + gc->guardian[0].visible, gc->guardian[1].visible, gc->guardian[2].visible, gc->guardian[3].visible, + gc->guardian[4].visible, gc->guardian[5].visible, gc->guardian[6].visible, gc->guardian[7].visible); + + return 0; +} +#endif ///TXT_SQL_CONVERT + +// ギルド城データの文字列からの変換 +int inter_guildcastle_fromstr(char *str, struct guild_castle *gc) +{ + int castleid, guildid, economy, defense, triggerE, triggerD, nextTime, payTime, createTime, visibleC; + int guardian[8]; + int dummy; + + memset(gc, 0, sizeof(struct guild_castle)); + // structure of guild castle with the guardian hp included + if( sscanf(str, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d", + &castleid, &guildid, &economy, &defense, &triggerE, &triggerD, &nextTime, &payTime, &createTime, &visibleC, + &guardian[0], &guardian[1], &guardian[2], &guardian[3], &guardian[4], &guardian[5], &guardian[6], &guardian[7], + &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy) != 26 ) + // structure of guild castle without the hps (current one) + if( sscanf(str, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d", + &castleid, &guildid, &economy, &defense, &triggerE, &triggerD, &nextTime, &payTime, &createTime, &visibleC, + &guardian[0], &guardian[1], &guardian[2], &guardian[3], &guardian[4], &guardian[5], &guardian[6], &guardian[7]) != 18 ) + return 1; + + gc->castle_id = castleid; + gc->guild_id = guildid; + gc->economy = economy; + gc->defense = defense; + gc->triggerE = triggerE; + gc->triggerD = triggerD; + gc->nextTime = nextTime; + gc->payTime = payTime; + gc->createTime = createTime; + gc->visibleC = visibleC; + gc->guardian[0].visible = guardian[0]; + gc->guardian[1].visible = guardian[1]; + gc->guardian[2].visible = guardian[2]; + gc->guardian[3].visible = guardian[3]; + gc->guardian[4].visible = guardian[4]; + gc->guardian[5].visible = guardian[5]; + gc->guardian[6].visible = guardian[6]; + gc->guardian[7].visible = guardian[7]; + + return 0; +} + +#ifndef TXT_SQL_CONVERT +// ギルド関連データベース読み込み +int inter_guild_readdb(void) +{ + int i; + FILE *fp; + char line[1024]; + char path[1024]; + + sprintf(path, "%s%s", db_path, "/exp_guild.txt"); + fp = fopen(path, "r"); + if (fp == NULL) { + ShowError("can't read db/exp_guild.txt\n"); + return 1; + } + i = 0; + while(fgets(line, sizeof(line), fp) && i < 100) + { + if (line[0] == '/' && line[1] == '/') + continue; + guild_exp[i] = (unsigned int)atof(line); + i++; + } + fclose(fp); + + return 0; +} + +// ギルドデータの読み込み +int inter_guild_init() +{ + char line[16384]; + struct guild *g; + struct guild_castle *gc; + FILE *fp; + int i, j, c = 0; + + inter_guild_readdb(); + + guild_db = idb_alloc(DB_OPT_RELEASE_DATA); + castle_db = idb_alloc(DB_OPT_RELEASE_DATA); + + if ((fp = fopen(guild_txt,"r")) == NULL) + return 1; + while(fgets(line, sizeof(line), fp)) + { + j = 0; + if (sscanf(line, "%d\t%%newid%%\n%n", &i, &j) == 1 && j > 0 && guild_newid <= i) { + guild_newid = i; + continue; + } + + g = (struct guild *) aCalloc(sizeof(struct guild), 1); + if(g == NULL){ + ShowFatalError("int_guild: out of memory!\n"); + exit(EXIT_FAILURE); + } +// memset(g, 0, sizeof(struct guild)); not needed... + if (inter_guild_fromstr(line, g) == 0 && g->guild_id > 0) { + if (g->guild_id >= guild_newid) + guild_newid = g->guild_id + 1; + idb_put(guild_db, g->guild_id, g); + guild_check_empty(g); + guild_calcinfo(g); + } else { + ShowError("int_guild: broken data [%s] line %d\n", guild_txt, c); + aFree(g); + } + c++; + } + fclose(fp); + + c = 0;//カウンタ初期化 + + if ((fp = fopen(castle_txt, "r")) == NULL) { + return 1; + } + + while(fgets(line, sizeof(line), fp)) + { + gc = (struct guild_castle *) aCalloc(sizeof(struct guild_castle), 1); + if(gc == NULL){ + ShowFatalError("int_guild: out of memory!\n"); + exit(EXIT_FAILURE); + } +// memset(gc, 0, sizeof(struct guild_castle)); No need... + if (inter_guildcastle_fromstr(line, gc) == 0) { + idb_put(castle_db, gc->castle_id, gc); + } else { + ShowError("int_guild: broken data [%s] line %d\n", castle_txt, c); + aFree(gc); + } + c++; + } + + fclose(fp); + + if (!c) { + ShowStatus(" %s - making Default Data...\n", castle_txt); + //デフォルトデータを作成 + for(i = 0; i < MAX_GUILDCASTLE; i++) { + gc = (struct guild_castle *) aCalloc(sizeof(struct guild_castle), 1); + if (gc == NULL) { + ShowFatalError("int_guild: out of memory!\n"); + exit(EXIT_FAILURE); + } + gc->castle_id = i; + idb_put(castle_db, gc->castle_id, gc); + } + ShowStatus(" %s - making done\n",castle_txt); + return 0; + } + + return 0; +} + +void inter_guild_final() +{ + castle_db->destroy(castle_db, NULL); + guild_db->destroy(guild_db, NULL); + return; +} + +struct guild *inter_guild_search(int guild_id) +{ + return (struct guild*)idb_get(guild_db, guild_id); +} + +// ギルドデータのセーブ +int inter_guild_save() +{ + FILE *fp; + int lock; + DBIterator* iter; + struct guild* g; + struct guild_castle* gc; + + // save guild data + if ((fp = lock_fopen(guild_txt, &lock)) == NULL) { + ShowError("int_guild: can't write [%s] !!! data is lost !!!\n", guild_txt); + return 1; + } + + iter = guild_db->iterator(guild_db); + for( g = (struct guild*)iter->first(iter,NULL); iter->exists(iter); g = (struct guild*)iter->next(iter,NULL) ) + { + char line[16384]; + inter_guild_tostr(line, g); + fprintf(fp, "%s\n", line); + } + iter->destroy(iter); + +// fprintf(fp, "%d\t%%newid%%\n", guild_newid); + lock_fclose(fp, guild_txt, &lock); + + // save castle data + if ((fp = lock_fopen(castle_txt,&lock)) == NULL) { + ShowError("int_guild: can't write [%s] !!! data is lost !!!\n", castle_txt); + return 1; + } + + iter = castle_db->iterator(castle_db); + for( gc = (struct guild_castle*)iter->first(iter,NULL); iter->exists(iter); gc = (struct guild_castle*)iter->next(iter,NULL) ) + { + char line[16384]; + inter_guildcastle_tostr(line, gc); + fprintf(fp, "%s\n", line); + } + iter->destroy(iter); + + lock_fclose(fp, castle_txt, &lock); + + return 0; +} + +// ギルド名検索 +struct guild* search_guildname(char *str) +{ + DBIterator* iter; + struct guild* g; + + iter = guild_db->iterator(guild_db); + for( g = (struct guild*)iter->first(iter,NULL); iter->exists(iter); g = (struct guild*)iter->next(iter,NULL) ) + { + if (strcmpi(g->name, str) == 0) + break; + } + iter->destroy(iter); + + return g; +} + +// ギルドが空かどうかチェック +static bool guild_check_empty(struct guild *g) +{ + int i; + ARR_FIND( 0, g->max_member, i, g->member[i].account_id > 0 ); + if( i < g->max_member) + return false; // not empty + + // 誰もいないので解散 + guild_db->foreach(guild_db, guild_break_sub, g->guild_id); + inter_guild_storage_delete(g->guild_id); + mapif_guild_broken(g->guild_id, 0); + idb_remove(guild_db, g->guild_id); + return true; +} + +unsigned int guild_nextexp(int level) +{ + if (level == 0) + return 1; + if (level > 0 && level < 100) + return guild_exp[level-1]; + + return 0; +} + +// ギルドスキルがあるか確認 +int guild_checkskill(struct guild *g, int id) +{ + int idx = id - GD_SKILLBASE; + + + if(idx < 0 || idx >= MAX_GUILDSKILL) + + return 0; + + return g->skill[idx].lv; +} + +// ギルドの情報の再計算 +int guild_calcinfo(struct guild *g) +{ + int i, c; + unsigned int nextexp; + struct guild before = *g; + + // スキルIDの設定 + for(i = 0; i < MAX_GUILDSKILL; i++) + g->skill[i].id=i+GD_SKILLBASE; + + // ギルドレベル + if (g->guild_lv <= 0) + g->guild_lv = 1; + nextexp = guild_nextexp(g->guild_lv); + if (nextexp > 0) { + while(g->exp >= nextexp && nextexp > 0) { //fixed guild exp overflow [Kevin] + g->exp -= nextexp; + g->guild_lv++; + g->skill_point++; + nextexp = guild_nextexp(g->guild_lv); + } + } + + // ギルドの次の経験値 + g->next_exp = guild_nextexp(g->guild_lv); + + // メンバ上限(ギルド拡張適用) + g->max_member = 16 + guild_checkskill(g, GD_EXTENSION) * 6; //Guild Extention skill - currently adds 6 to max per skill lv. + if(g->max_member > MAX_GUILD) + { + ShowError("Guild %d:%s has capacity for too many guild members (%d), max supported is %d\n", g->guild_id, g->name, g->max_member, MAX_GUILD); + g->max_member = MAX_GUILD; + } + + // 平均レベルとオンライン人数 + g->average_lv = 0; + g->connect_member = 0; + c = 0; + for(i = 0; i < g->max_member; i++) { + if (g->member[i].account_id > 0) { + g->average_lv += g->member[i].lv; + c++; + if (g->member[i].online > 0) + g->connect_member++; + } + } + if(c) g->average_lv /= c; + + // 全データを送る必要がありそう + if (g->max_member != before.max_member || + g->guild_lv != before.guild_lv || + g->skill_point != before.skill_point) { + mapif_guild_info(-1, g); + return 1; + } + + return 0; +} + +//------------------------------------------------------------------- +// map serverへの通信 + +// ギルド作成可否 +int mapif_guild_created(int fd, int account_id, struct guild *g) +{ + WFIFOHEAD(fd, 10); + WFIFOW(fd,0) = 0x3830; + WFIFOL(fd,2) = account_id; + if (g != NULL) { + WFIFOL(fd,6) = g->guild_id; + ShowInfo("Created Guild (%d %s)\n", g->guild_id, g->name); + }else{ + WFIFOL(fd,6) = 0; + } + WFIFOSET(fd,10); + return 0; +} + +// ギルド情報見つからず +int mapif_guild_noinfo(int fd, int guild_id) +{ + WFIFOHEAD(fd, 8); + WFIFOW(fd,0) = 0x3831; + WFIFOW(fd,2) = 8; + WFIFOL(fd,4) = guild_id; + WFIFOSET(fd,8); + ShowNotice("int_guild: info not found %d\n", guild_id); + + return 0; +} + +// ギルド情報まとめ送り +int mapif_guild_info(int fd, struct guild *g) +{ + unsigned char buf[8+sizeof(struct guild)]; + + WBUFW(buf,0) = 0x3831; + memcpy(buf + 4, g, sizeof(struct guild)); + WBUFW(buf,2) = 4 + sizeof(struct guild); + if (fd < 0) + mapif_sendall(buf, WBUFW(buf,2)); + else + mapif_send(fd, buf, WBUFW(buf,2)); + + return 0; +} + +// メンバ追加可否 +int mapif_guild_memberadded(int fd, int guild_id, int account_id, int char_id, int flag) +{ + WFIFOHEAD(fd, 15); + WFIFOW(fd,0) = 0x3832; + WFIFOL(fd,2) = guild_id; + WFIFOL(fd,6) = account_id; + WFIFOL(fd,10) = char_id; + WFIFOB(fd,14) = flag; + WFIFOSET(fd, 15); + + return 0; +} + +// 脱退/追放通知 +int mapif_guild_leaved(int guild_id, int account_id, int char_id, int flag, const char *name, const char *mes) +{ + unsigned char buf[79]; + + WBUFW(buf, 0) = 0x3834; + WBUFL(buf, 2) = guild_id; + WBUFL(buf, 6) = account_id; + WBUFL(buf,10) = char_id; + WBUFB(buf,14) = flag; + memcpy(WBUFP(buf,15), mes, 40); + memcpy(WBUFP(buf,55), name, NAME_LENGTH); + mapif_sendall(buf, 55+NAME_LENGTH); +// mapif_sendall(buf, 79); + ShowInfo("Character left guild (Guild %d, %d - %s: %s)\n", guild_id, account_id, name, mes); + + return 0; +} + +// オンライン状態とLv更新通知 +int mapif_guild_memberinfoshort(struct guild *g, int idx) +{ + unsigned char buf[19]; + + WBUFW(buf, 0) = 0x3835; + WBUFL(buf, 2) = g->guild_id; + WBUFL(buf, 6) = g->member[idx].account_id; + WBUFL(buf,10) = g->member[idx].char_id; + WBUFB(buf,14) = (unsigned char)g->member[idx].online; + WBUFW(buf,15) = g->member[idx].lv; + WBUFW(buf,17) = g->member[idx].class_; + mapif_sendall(buf, 19); + return 0; +} + +// 解散通知 +int mapif_guild_broken(int guild_id, int flag) +{ + unsigned char buf[7]; + + WBUFW(buf,0) = 0x3836; + WBUFL(buf,2) = guild_id; + WBUFB(buf,6) = flag; + mapif_sendall(buf, 7); + ShowInfo("Guild Break (%d)\n", guild_id); + + return 0; +} + +// ギルド内発言 +int mapif_guild_message(int guild_id, int account_id, char *mes, int len, int sfd) +{ + unsigned char buf[2048]; + + WBUFW(buf,0) = 0x3837; + WBUFW(buf,2) = len + 12; + WBUFL(buf,4) = guild_id; + WBUFL(buf,8) = account_id; + memcpy(WBUFP(buf,12), mes, len); + mapif_sendallwos(sfd, buf, len + 12); + + return 0; +} + +// ギルド基本情報変更通知 +int mapif_guild_basicinfochanged(int guild_id, int type, const void *data, int len) +{ + unsigned char buf[2048]; + + WBUFW(buf,0) = 0x3839; + WBUFW(buf,2) = len+10; + WBUFL(buf,4) = guild_id; + WBUFW(buf,8) = type; + memcpy(WBUFP(buf,10),data,len); + mapif_sendall(buf,len+10); + return 0; +} + +// ギルドメンバ情報変更通知 +int mapif_guild_memberinfochanged(int guild_id, int account_id, int char_id, int type, const void *data, int len) +{ + unsigned char buf[4096]; + + WBUFW(buf, 0) = 0x383a; + WBUFW(buf, 2) = len + 18; + WBUFL(buf, 4) = guild_id; + WBUFL(buf, 8) = account_id; + WBUFL(buf,12) = char_id; + WBUFW(buf,16) = type; + memcpy(WBUFP(buf,18), data, len); + mapif_sendall(buf,len+18); + + return 0; +} + +// ギルドスキルアップ通知 +int mapif_guild_skillupack(int guild_id, int skill_num, int account_id) +{ + unsigned char buf[14]; + + WBUFW(buf, 0) = 0x383c; + WBUFL(buf, 2) = guild_id; + WBUFL(buf, 6) = skill_num; + WBUFL(buf,10) = account_id; + mapif_sendall(buf, 14); + + return 0; +} + +// ギルド同盟/敵対通知 +int mapif_guild_alliance(int guild_id1, int guild_id2, int account_id1, int account_id2, int flag, const char *name1, const char *name2) +{ + unsigned char buf[67]; + + WBUFW(buf, 0) = 0x383d; + WBUFL(buf, 2) = guild_id1; + WBUFL(buf, 6) = guild_id2; + WBUFL(buf,10) = account_id1; + WBUFL(buf,14) = account_id2; + WBUFB(buf,18) = flag; + memcpy(WBUFP(buf,19), name1, NAME_LENGTH); + memcpy(WBUFP(buf,19+NAME_LENGTH), name2, NAME_LENGTH); + mapif_sendall(buf,19+2*NAME_LENGTH); +/* + memcpy(WBUFP(buf,43), name2, NAME_LENGTH); + mapif_sendall(buf, 67); +*/ + return 0; +} + +// ギルド役職変更通知 +int mapif_guild_position(struct guild *g, int idx) +{ + unsigned char buf[2048]; + + WBUFW(buf,0) = 0x383b; + WBUFW(buf,2) = sizeof(struct guild_position) + 12; + WBUFL(buf,4) = g->guild_id; + WBUFL(buf,8) = idx; + memcpy(WBUFP(buf,12), &g->position[idx], sizeof(struct guild_position)); + mapif_sendall(buf, WBUFW(buf,2)); + + return 0; +} + +// ギルド告知変更通知 +int mapif_guild_notice(struct guild *g) +{ + unsigned char buf[186]; + + WBUFW(buf,0) = 0x383e; + WBUFL(buf,2) = g->guild_id; + memcpy(WBUFP(buf,6), g->mes1, 60); + memcpy(WBUFP(buf,66), g->mes2, 120); + mapif_sendall(buf, 186); + + return 0; +} + +// ギルドエンブレム変更通知 +int mapif_guild_emblem(struct guild *g) +{ + unsigned char buf[2048]; + + WBUFW(buf,0) = 0x383f; + WBUFW(buf,2) = g->emblem_len + 12; + WBUFL(buf,4) = g->guild_id; + WBUFL(buf,8) = g->emblem_id; + memcpy(WBUFP(buf,12), g->emblem_data, g->emblem_len); + mapif_sendall(buf, WBUFW(buf,2)); + + return 0; +} + +int mapif_guild_master_changed(struct guild *g, int aid, int cid) +{ + unsigned char buf[14]; + WBUFW(buf,0)=0x3843; + WBUFL(buf,2)=g->guild_id; + WBUFL(buf,6)=aid; + WBUFL(buf,10)=cid; + mapif_sendall(buf,14); + return 0; +} + +int mapif_guild_castle_dataload(int castle_id, int index, int value) +{ + unsigned char buf[9]; + + WBUFW(buf,0) = 0x3840; + WBUFW(buf,2) = castle_id; + WBUFB(buf,4) = index; + WBUFL(buf,5) = value; + mapif_sendall(buf,9); + + return 0; +} + +int mapif_guild_castle_datasave(int castle_id, int index, int value) +{ + unsigned char buf[9]; + + WBUFW(buf,0) = 0x3841; + WBUFW(buf,2) = castle_id; + WBUFB(buf,4) = index; + WBUFL(buf,5) = value; + mapif_sendall(buf,9); + + return 0; +} + +int mapif_guild_castle_alldataload(int fd) +{ + DBIterator* iter; + struct guild_castle* gc; + int len = 4; + + WFIFOHEAD(fd, 4 + MAX_GUILDCASTLE*sizeof(struct guild_castle)); + WFIFOW(fd,0) = 0x3842; + iter = castle_db->iterator(castle_db); + for( gc = (struct guild_castle*)iter->first(iter,NULL); iter->exists(iter); gc = (struct guild_castle*)iter->next(iter,NULL) ) + { + memcpy(WFIFOP(fd,len), gc, sizeof(struct guild_castle)); + len += sizeof(struct guild_castle); + } + iter->destroy(iter); + WFIFOW(fd,2) = len; + WFIFOSET(fd, len); + + return 0; +} + +//------------------------------------------------------------------- +// map serverからの通信 + +// ギルド作成要求 +int mapif_parse_CreateGuild(int fd, int account_id, char *name, struct guild_member *master) +{ + struct guild *g; + int i; + + for(i = 0; i < NAME_LENGTH && name[i]; i++) { + if (!(name[i] & 0xe0) || name[i] == 0x7f) { + ShowInfo("Create Guild: illegal guild name [%s]\n", name); + mapif_guild_created(fd, account_id, NULL); + return 0; + } + } + + if ((g = search_guildname(name)) != NULL) { + ShowInfo("Create Guild: same name guild exists [%s]\n", name); + mapif_guild_created(fd, account_id, NULL); + return 0; + } + + // Check Authorised letters/symbols in the name of the character + if (char_name_option == 1) { // only letters/symbols in char_name_letters are authorised + for (i = 0; i < NAME_LENGTH && name[i]; i++) + if (strchr(char_name_letters, name[i]) == NULL) { + mapif_guild_created(fd,account_id,NULL); + return 0; + } + } else if (char_name_option == 2) { // letters/symbols in char_name_letters are forbidden + for (i = 0; i < NAME_LENGTH && name[i]; i++) + if (strchr(char_name_letters, name[i]) != NULL) { + mapif_guild_created(fd,account_id,NULL); + return 0; + } + } + + g = (struct guild *) aCalloc(sizeof(struct guild), 1); + if (g == NULL) { + ShowFatalError("int_guild: CreateGuild: out of memory !\n"); + mapif_guild_created(fd, account_id, NULL); + exit(EXIT_FAILURE); + } +// memset(g, 0, sizeof(struct guild)); Meh... + g->guild_id = guild_newid++; + memcpy(g->name, name, NAME_LENGTH); + memcpy(g->master, master->name, NAME_LENGTH); + memcpy(&g->member[0], master, sizeof(struct guild_member)); + + g->position[0].mode = 0x11; + strcpy(g->position[ 0].name, "GuildMaster"); + strcpy(g->position[MAX_GUILDPOSITION-1].name, "Newbie"); + for(i = 1; i < MAX_GUILDPOSITION-1; i++) + sprintf(g->position[i].name, "Position %d", i + 1); + + // ここでギルド情報計算が必要と思われる + g->max_member = 16; + g->average_lv = master->lv; + g->connect_member = 1; + for(i = 0; i < MAX_GUILDSKILL; i++) + g->skill[i].id=i + GD_SKILLBASE; + + idb_put(guild_db, g->guild_id, g); + + mapif_guild_created(fd, account_id, g); + mapif_guild_info(fd, g); + + if(log_inter) + inter_log("guild %s (id=%d) created by master %s (id=%d)\n", + name, g->guild_id, master->name, master->account_id); + + return 0; +} + +// ギルド情報要求 +int mapif_parse_GuildInfo(int fd, int guild_id) +{ + struct guild *g; + + g = (struct guild*)idb_get(guild_db, guild_id); + if (g != NULL){ + guild_calcinfo(g); + mapif_guild_info(fd, g); + } else + mapif_guild_noinfo(fd, guild_id); + + return 0; +} + +// ギルドメンバ追加要求 +int mapif_parse_GuildAddMember(int fd, int guild_id, struct guild_member *m) +{ + struct guild *g; + int i; + + g = (struct guild*)idb_get(guild_db, guild_id); + if (g == NULL) { + mapif_guild_memberadded(fd, guild_id, m->account_id, m->char_id, 1); + return 0; + } + + ARR_FIND( 0, g->max_member, i, g->member[i].account_id == 0 ); + if( i < g->max_member ) + { + memcpy(&g->member[i], m, sizeof(struct guild_member)); + mapif_guild_memberadded(fd, guild_id, m->account_id, m->char_id, 0); + guild_calcinfo(g); + mapif_guild_info(-1, g); + } + else + mapif_guild_memberadded(fd, guild_id, m->account_id, m->char_id, 1); + + return 0; +} + +// Delete member from guild +int mapif_parse_GuildLeave(int fd, int guild_id, int account_id, int char_id, int flag, const char *mes) +{ + int i, j; + + struct guild* g = (struct guild*)idb_get(guild_db, guild_id); + if( g == NULL ) + { + //TODO + return 0; + } + + // Find the member + ARR_FIND( 0, g->max_member, i, g->member[i].account_id == account_id && g->member[i].char_id == char_id ); + if( i == g->max_member ) + { + //TODO + return 0; + } + + if( flag ) + { // 追放の場合追放リストに入れる + ARR_FIND( 0, MAX_GUILDEXPULSION, j, g->expulsion[j].account_id == 0 ); + if (j == MAX_GUILDEXPULSION) + { // 一杯なので古いのを消す + for(j = 0; j < MAX_GUILDEXPULSION - 1; j++) + g->expulsion[j] = g->expulsion[j+1]; + j = MAX_GUILDEXPULSION - 1; + } + // Save the expulsion entry + g->expulsion[j].account_id = account_id; + safestrncpy(g->expulsion[j].name, g->member[i].name, NAME_LENGTH); + safestrncpy(g->expulsion[j].mes, mes, 40); + } + + mapif_guild_leaved(guild_id, account_id, char_id, flag, g->member[i].name, mes); + + memset(&g->member[i], 0, sizeof(struct guild_member)); + + if (guild_check_empty(g) == 0) + mapif_guild_info(-1,g);// まだ人がいるのでデータ送信 + + return 0; +} + +// オンライン/Lv更新 +int mapif_parse_GuildChangeMemberInfoShort(int fd, int guild_id, int account_id, int char_id, int online, int lv, int class_) +{ + struct guild *g; + int i, sum, c; + + g = (struct guild*)idb_get(guild_db, guild_id); + if (g == NULL) + return 0; + + ARR_FIND( 0, g->max_member, i, g->member[i].account_id == account_id && g->member[i].char_id == char_id ); + if( i < g->max_member ) + { + g->member[i].online = online; + g->member[i].lv = lv; + g->member[i].class_ = class_; + mapif_guild_memberinfoshort(g, i); + } + + g->average_lv = 0; + g->connect_member = 0; + c = 0; // member count + sum = 0; // total sum of base levels + + for(i = 0; i < g->max_member; i++) + { + if( g->member[i].account_id > 0 ) + { + sum += g->member[i].lv; + c++; + } + if( g->member[i].online ) + g->connect_member++; + } + + if( c ) // this check should always succeed... + g->average_lv = sum / c; + + //FIXME: how about sending a mapif_guild_info() update to the mapserver? [ultramage] + + return 0; +} + +// ギルド解散処理用(同盟/敵対を解除) +int guild_break_sub(DBKey key, void *data, va_list ap) +{ + struct guild *g = (struct guild *)data; + int guild_id = va_arg(ap, int); + int i; + + for(i = 0; i < MAX_GUILDALLIANCE; i++) { + if (g->alliance[i].guild_id == guild_id) + g->alliance[i].guild_id = 0; + } + return 0; +} + +// ギルド解散要求 +int mapif_parse_BreakGuild(int fd, int guild_id) +{ + struct guild *g; + + g = (struct guild*)idb_get(guild_db, guild_id); + if(g == NULL) + return 0; + + guild_db->foreach(guild_db, guild_break_sub, guild_id); + inter_guild_storage_delete(guild_id); + mapif_guild_broken(guild_id, 0); + + if(log_inter) + inter_log("guild %s (id=%d) broken\n", g->name, guild_id); + + idb_remove(guild_db, guild_id); + return 0; +} + +// ギルドメッセージ送信 +int mapif_parse_GuildMessage(int fd, int guild_id, int account_id, char *mes, int len) +{ + return mapif_guild_message(guild_id, account_id, mes, len, fd); +} + +// ギルド基本データ変更要求 +int mapif_parse_GuildBasicInfoChange(int fd, int guild_id, int type, const char *data, int len) +{ + struct guild *g; + short dw = *((short *)data); + + g = (struct guild*)idb_get(guild_db, guild_id); + if (g == NULL) + return 0; + + switch(type) { + case GBI_GUILDLV: + if (dw > 0 && g->guild_lv + dw <= 50) { + g->guild_lv+=dw; + g->skill_point+=dw; + } else if (dw < 0 && g->guild_lv + dw >= 1) + g->guild_lv += dw; + mapif_guild_info(-1, g); + return 0; + default: + ShowError("int_guild: GuildBasicInfoChange: Unknown type %d\n", type); + break; + } + mapif_guild_basicinfochanged(guild_id, type, data, len); + + return 0; +} + +// ギルドメンバデータ変更要求 +int mapif_parse_GuildMemberInfoChange(int fd, int guild_id, int account_id, int char_id, int type, const char *data, int len) +{ + int i; + struct guild *g; + + g = (struct guild*)idb_get(guild_db, guild_id); + if(g == NULL) + return 0; + + for(i = 0; i < g->max_member; i++) + if (g->member[i].account_id == account_id && g->member[i].char_id == char_id) + break; + if (i == g->max_member) { + ShowWarning("int_guild: GuildMemberChange: Not found %d,%d in %d[%s]\n", account_id, char_id, guild_id, g->name); + return 0; + } + switch(type) { + case GMI_POSITION: // 役職 + g->member[i].position = *((int *)data); + break; + case GMI_EXP: // EXP + { + unsigned int exp, old_exp=g->member[i].exp; + g->member[i].exp=*((unsigned int *)data); + if (g->member[i].exp > old_exp) + { + exp = g->member[i].exp - old_exp; + if (guild_exp_rate != 100) + exp = exp*guild_exp_rate/100; + if (exp > UINT_MAX - g->exp) + g->exp = UINT_MAX; + else + g->exp+=exp; + guild_calcinfo(g); + mapif_guild_basicinfochanged(guild_id,GBI_EXP,&g->exp,4); + } + break; + } + case GMI_HAIR: + { + g->member[i].hair=*((int *)data); + mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len); + break; + } + case GMI_HAIR_COLOR: + { + g->member[i].hair_color=*((int *)data); + mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len); + break; + } + case GMI_GENDER: + { + g->member[i].gender=*((int *)data); + mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len); + break; + } + case GMI_CLASS: + { + g->member[i].class_=*((int *)data); + mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len); + break; + } + case GMI_LEVEL: + { + g->member[i].lv=*((int *)data); + mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len); + break; + } + + default: + ShowError("int_guild: GuildMemberInfoChange: Unknown type %d\n", type); + break; + } + mapif_guild_memberinfochanged(guild_id, account_id, char_id, type, data, len); + + return 0; +} + +int inter_guild_sex_changed(int guild_id,int account_id,int char_id, int gender) +{ + return mapif_parse_GuildMemberInfoChange(0, guild_id, account_id, char_id, GMI_GENDER, (const char*)&gender, sizeof(gender)); +} + +// ギルド役職名変更要求 +int mapif_parse_GuildPosition(int fd, int guild_id, int idx, struct guild_position *p) +{ + struct guild *g = (struct guild*)idb_get(guild_db, guild_id); + + if (g == NULL || idx < 0 || idx >= MAX_GUILDPOSITION) { + return 0; + } + memcpy(&g->position[idx], p, sizeof(struct guild_position)); + mapif_guild_position(g, idx); + ShowInfo("int_guild: position [%d] changed\n", idx); + + return 0; +} + +// ギルドスキルアップ要求 +int mapif_parse_GuildSkillUp(int fd, int guild_id, int skill_num, int account_id) +{ + struct guild *g = (struct guild*)idb_get(guild_db, guild_id); + int idx = skill_num - GD_SKILLBASE; + + if (g == NULL || idx < 0 || idx >= MAX_GUILDSKILL) + return 0; + + if (g->skill_point > 0 && g->skill[idx].id > 0 && g->skill[idx].lv < 10) { + g->skill[idx].lv++; + g->skill_point--; + if (guild_calcinfo(g) == 0) + mapif_guild_info(-1, g); + mapif_guild_skillupack(guild_id, skill_num, account_id); + } + + return 0; +} + +//Manual deletion of an alliance when partnering guild does not exists. [Skotlex] +static int mapif_parse_GuildDeleteAlliance(struct guild *g, int guild_id, int account_id1, int account_id2, int flag) +{ + int i; + char name[NAME_LENGTH]; + for(i=0;ialliance[i].guild_id == guild_id) + { + strcpy(name, g->alliance[i].name); + g->alliance[i].guild_id=0; + break; + } + if (i == MAX_GUILDALLIANCE) + return -1; + + mapif_guild_alliance(g->guild_id,guild_id,account_id1,account_id2,flag,g->name,name); + return 0; +} + +// ギルド同盟要求 +int mapif_parse_GuildAlliance(int fd, int guild_id1, int guild_id2, int account_id1, int account_id2, int flag) +{ + struct guild *g[2]; + int j, i; + + g[0] = (struct guild*)idb_get(guild_db, guild_id1); + g[1] = (struct guild*)idb_get(guild_db, guild_id2); + + if(g[0] && g[1]==NULL && (flag&0x8)) //Requested to remove an alliance with a not found guild. + return mapif_parse_GuildDeleteAlliance(g[0], guild_id2, + account_id1, account_id2, flag); //Try to do a manual removal of said guild. + + if (g[0] == NULL || g[1] == NULL) + return 0; + + if (!(flag & 0x8)) { + for(i = 0; i < 2 - (flag & 1); i++) { + for(j = 0; j < MAX_GUILDALLIANCE; j++) + if (g[i]->alliance[j].guild_id == 0) { + g[i]->alliance[j].guild_id = g[1-i]->guild_id; + memcpy(g[i]->alliance[j].name, g[1-i]->name, NAME_LENGTH); + g[i]->alliance[j].opposition = flag & 1; + break; + } + } + } else { // 関係解消 + for(i = 0; i < 2 - (flag & 1); i++) { + for(j = 0; j < MAX_GUILDALLIANCE; j++) + if (g[i]->alliance[j].guild_id == g[1-i]->guild_id && g[i]->alliance[j].opposition == (flag & 1)) { + g[i]->alliance[j].guild_id = 0; + break; + } + } + } + mapif_guild_alliance(guild_id1, guild_id2, account_id1, account_id2, flag, g[0]->name, g[1]->name); + + return 0; +} + +// ギルド告知変更要求 +int mapif_parse_GuildNotice(int fd, int guild_id, const char *mes1, const char *mes2) +{ + struct guild *g; + + g = (struct guild*)idb_get(guild_db, guild_id); + if (g == NULL) + return 0; + memcpy(g->mes1, mes1, 60); + memcpy(g->mes2, mes2, 120); + + return mapif_guild_notice(g); +} + +// ギルドエンブレム変更要求 +int mapif_parse_GuildEmblem(int fd, int len, int guild_id, int dummy, const char *data) +{ + struct guild *g; + + g = (struct guild*)idb_get(guild_db, guild_id); + if (g == NULL) + return 0; + memcpy(g->emblem_data, data, len); + g->emblem_len = len; + g->emblem_id++; + + return mapif_guild_emblem(g); +} + +int mapif_parse_GuildCastleDataLoad(int fd, int castle_id, int index) +{ + struct guild_castle *gc = (struct guild_castle*)idb_get(castle_db, castle_id); + + if (gc == NULL) { + return mapif_guild_castle_dataload(castle_id, 0, 0); + } + switch(index) { + case 1: return mapif_guild_castle_dataload(gc->castle_id, index, gc->guild_id); + case 2: return mapif_guild_castle_dataload(gc->castle_id, index, gc->economy); + case 3: return mapif_guild_castle_dataload(gc->castle_id, index, gc->defense); + case 4: return mapif_guild_castle_dataload(gc->castle_id, index, gc->triggerE); + case 5: return mapif_guild_castle_dataload(gc->castle_id, index, gc->triggerD); + case 6: return mapif_guild_castle_dataload(gc->castle_id, index, gc->nextTime); + case 7: return mapif_guild_castle_dataload(gc->castle_id, index, gc->payTime); + case 8: return mapif_guild_castle_dataload(gc->castle_id, index, gc->createTime); + case 9: return mapif_guild_castle_dataload(gc->castle_id, index, gc->visibleC); + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: + case 16: + case 17: + return mapif_guild_castle_dataload(gc->castle_id, index, gc->guardian[index-10].visible); + default: + ShowError("mapif_parse_GuildCastleDataLoad ERROR!! (Not found index=%d)\n", index); + return 0; + } + + return 0; +} + +int mapif_parse_GuildCastleDataSave(int fd, int castle_id, int index, int value) +{ + struct guild_castle *gc = (struct guild_castle*)idb_get(castle_db, castle_id); + + if (gc == NULL) + return mapif_guild_castle_datasave(castle_id, index, value); + + switch(index) { + case 1: + if (gc->guild_id != value) { + int gid = (value) ? value : gc->guild_id; + struct guild *g = (struct guild*)idb_get(guild_db, gid); + if(log_inter) + inter_log("guild %s (id=%d) %s castle id=%d\n", + (g) ? g->name : "??", gid, (value) ? "occupy" : "abandon", castle_id); + } + gc->guild_id = value; + if(gc->guild_id == 0) { + //Delete guardians. + memset(&gc->guardian, 0, sizeof(gc->guardian)); + } + break; + case 2: gc->economy = value; break; + case 3: gc->defense = value; break; + case 4: gc->triggerE = value; break; + case 5: gc->triggerD = value; break; + case 6: gc->nextTime = value; break; + case 7: gc->payTime = value; break; + case 8: gc->createTime = value; break; + case 9: gc->visibleC = value; break; + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: + case 16: + case 17: + gc->guardian[index-10].visible = value; break; + default: + ShowError("mapif_parse_GuildCastleDataSave ERROR!! (Not found index=%d)\n", index); + return 0; + } + + return mapif_guild_castle_datasave(gc->castle_id, index, value); +} + +int mapif_parse_GuildMasterChange(int fd, int guild_id, const char* name, int len) +{ + struct guild *g = (struct guild*)idb_get(guild_db, guild_id); + struct guild_member gm; + int pos; + + if(g==NULL || g->guild_id<=0 || len > NAME_LENGTH) + return 0; + + for (pos = 0; pos < g->max_member && strncmp(g->member[pos].name, name, len); pos++); + + if (pos == g->max_member) + return 0; //Character not found?? + + memcpy(&gm, &g->member[pos], sizeof (struct guild_member)); + memcpy(&g->member[pos], &g->member[0], sizeof(struct guild_member)); + memcpy(&g->member[0], &gm, sizeof(struct guild_member)); + + g->member[pos].position = g->member[0].position; + g->member[0].position = 0; //Position 0: guild Master. + safestrncpy(g->master, name, NAME_LENGTH); + + ShowInfo("int_guild: Guildmaster Changed to %s (Guild %d - %s)\n",name, guild_id, g->name); + return mapif_guild_master_changed(g, g->member[0].account_id, g->member[0].char_id); +} + +// map server からの通信 +// ・1パケットのみ解析すること +// ・パケット長データはinter.cにセットしておくこと +// ・パケット長チェックや、RFIFOSKIPは呼び出し元で行われるので行ってはならない +// ・エラーなら0(false)、そうでないなら1(true)をかえさなければならない +int inter_guild_parse_frommap(int fd) +{ + RFIFOHEAD(fd); + switch(RFIFOW(fd,0)) { + case 0x3030: mapif_parse_CreateGuild(fd, RFIFOL(fd,4), (char*)RFIFOP(fd,8), (struct guild_member *)RFIFOP(fd,32)); break; + case 0x3031: mapif_parse_GuildInfo(fd, RFIFOL(fd,2)); break; + case 0x3032: mapif_parse_GuildAddMember(fd, RFIFOL(fd,4), (struct guild_member *)RFIFOP(fd,8)); break; + case 0x3033: mapif_parse_GuildMasterChange(fd,RFIFOL(fd,4),(const char*)RFIFOP(fd,8),RFIFOW(fd,2)-8); break; + case 0x3034: mapif_parse_GuildLeave(fd, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10), RFIFOB(fd,14), (const char*)RFIFOP(fd,15)); break; + case 0x3035: mapif_parse_GuildChangeMemberInfoShort(fd, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10), RFIFOB(fd,14), RFIFOW(fd,15), RFIFOW(fd,17)); break; + case 0x3036: mapif_parse_BreakGuild(fd, RFIFOL(fd,2)); break; + case 0x3037: mapif_parse_GuildMessage(fd, RFIFOL(fd,4), RFIFOL(fd,8), (char*)RFIFOP(fd,12), RFIFOW(fd,2)-12); break; + case 0x3039: mapif_parse_GuildBasicInfoChange(fd, RFIFOL(fd,4), RFIFOW(fd,8), (const char*)RFIFOP(fd,10), RFIFOW(fd,2)-10); break; + case 0x303A: mapif_parse_GuildMemberInfoChange(fd, RFIFOL(fd,4), RFIFOL(fd,8), RFIFOL(fd,12), RFIFOW(fd,16), (const char*)RFIFOP(fd,18), RFIFOW(fd,2)-18); break; + case 0x303B: mapif_parse_GuildPosition(fd, RFIFOL(fd,4), RFIFOL(fd,8), (struct guild_position *)RFIFOP(fd,12)); break; + case 0x303C: mapif_parse_GuildSkillUp(fd, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10)); break; + case 0x303D: mapif_parse_GuildAlliance(fd, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10), RFIFOL(fd,14), RFIFOB(fd,18)); break; + case 0x303E: mapif_parse_GuildNotice(fd, RFIFOL(fd,2), (const char*)RFIFOP(fd,6), (const char*)RFIFOP(fd,66)); break; + case 0x303F: mapif_parse_GuildEmblem(fd, RFIFOW(fd,2)-12, RFIFOL(fd,4), RFIFOL(fd,8), (const char*)RFIFOP(fd,12)); break; + case 0x3040: mapif_parse_GuildCastleDataLoad(fd, RFIFOW(fd,2), RFIFOB(fd,4)); break; + case 0x3041: mapif_parse_GuildCastleDataSave(fd, RFIFOW(fd,2), RFIFOB(fd,4), RFIFOL(fd,5)); break; + + default: + return 0; + } + + return 1; +} + +// processes a mapserver connection event +int inter_guild_mapif_init(int fd) +{ + return mapif_guild_castle_alldataload(fd); +} + +// サーバーから脱退要求(キャラ削除用) +int inter_guild_leave(int guild_id, int account_id, int char_id) +{ + return mapif_parse_GuildLeave(-1, guild_id, account_id, char_id, 0, "** Character Deleted **"); +} +#endif //TXT_SQL_CONVERT diff --git a/src/char/int_guild.h b/src/char/int_guild.h new file mode 100644 index 000000000..06293eb0f --- /dev/null +++ b/src/char/int_guild.h @@ -0,0 +1,26 @@ +// Copyright (c) Athena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + +#ifndef _INT_GUILD_H_ +#define _INT_GUILD_H_ + +struct guild; +struct guild_castle; + +int inter_guild_init(void); +void inter_guild_final(void); +int inter_guild_save(void); +int inter_guild_parse_frommap(int fd); +struct guild *inter_guild_search(int guild_id); +int inter_guild_mapif_init(int fd); +int inter_guild_leave(int guild_id,int account_id,int char_id); +int inter_guild_sex_changed(int guild_id,int account_id,int char_id, int gender); + +extern char guild_txt[1024]; +extern char castle_txt[1024]; + +//For the TXT->SQL converter +int inter_guild_fromstr(char *str, struct guild *g); +int inter_guildcastle_fromstr(char *str, struct guild_castle *gc); + +#endif /* _INT_GUILD_H_ */ diff --git a/src/char/int_homun.c b/src/char/int_homun.c new file mode 100644 index 000000000..d547b60f7 --- /dev/null +++ b/src/char/int_homun.c @@ -0,0 +1,365 @@ +// Copyright (c) Athena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + +#include "../common/mmo.h" +#include "../common/malloc.h" +#include "../common/socket.h" +#include "../common/db.h" +#include "../common/lock.h" +#include "../common/showmsg.h" +#include "char.h" +#include "inter.h" +#include "int_homun.h" + +#include +#include +#include + +char homun_txt[1024]="save/homun.txt"; + +static DBMap* homun_db; // int hom_id -> struct s_homunculus* +static int homun_newid = 100; + +int inter_homun_tostr(char *str,struct s_homunculus *p) +{ + int i; + + str+=sprintf(str,"%d,%d\t%s\t%d,%d,%d,%d,%d," + "%u,%d,%d,%d," + "%u,%d,%d," + "%d,%d,%d,%d,%d,%d\t", + p->hom_id, p->class_, p->name, + p->char_id, p->hp, p->max_hp, p->sp, p->max_sp, + p->intimacy, p->hunger, p->skillpts, p->level, + p->exp, p->rename_flag, p->vaporize, + p->str, p->agi, p->vit, p->int_, p->dex, p->luk); + + for (i = 0; i < MAX_HOMUNSKILL; i++) + { + if (p->hskill[i].id && !p->hskill[i].flag) + str+=sprintf(str,"%d,%d,", p->hskill[i].id, p->hskill[i].lv); + } + + return 0; +} + +int inter_homun_fromstr(char *str,struct s_homunculus *p) +{ + int i, next, len; + int tmp_int[25]; + unsigned int tmp_uint[5]; + char tmp_str[256]; + + memset(p,0,sizeof(struct s_homunculus)); + + i=sscanf(str,"%d,%d\t%127[^\t]\t%d,%d,%d,%d,%d," + "%u,%d,%d,%d," + "%u,%d,%d," + "%d,%d,%d,%d,%d,%d\t%n", + &tmp_int[0],&tmp_int[1],tmp_str, + &tmp_int[2],&tmp_int[3],&tmp_int[4],&tmp_int[5],&tmp_int[6], + &tmp_uint[0],&tmp_int[7],&tmp_int[8],&tmp_int[9], + &tmp_uint[1],&tmp_int[10],&tmp_int[11], + &tmp_int[12],&tmp_int[13],&tmp_int[14],&tmp_int[15],&tmp_int[16],&tmp_int[17], + &next); + + if(i!=21) + return 1; + + p->hom_id = tmp_int[0]; + p->class_ = tmp_int[1]; + memcpy(p->name, tmp_str, NAME_LENGTH); + + p->char_id = tmp_int[2]; + p->hp = tmp_int[3]; + p->max_hp = tmp_int[4]; + p->sp = tmp_int[5]; + p->max_sp = tmp_int[6]; + + p->intimacy = tmp_uint[0]; + p->hunger = tmp_int[7]; + p->skillpts = tmp_int[8]; + p->level = tmp_int[9]; + + p->exp = tmp_uint[1]; + p->rename_flag = tmp_int[10]; + p->vaporize = tmp_int[11]; + + p->str = tmp_int[12]; + p->agi = tmp_int[13]; + p->vit = tmp_int[14]; + p->int_= tmp_int[15]; + p->dex = tmp_int[16]; + p->luk = tmp_int[17]; + + //Read skills. + while(str[next] && str[next] != '\n' && str[next] != '\r') { + if (sscanf(str+next, "%d,%d,%n", &tmp_int[0], &tmp_int[1], &len) != 2) + return 2; + + if (tmp_int[0] >= HM_SKILLBASE && tmp_int[0] < HM_SKILLBASE+MAX_HOMUNSKILL) + { + i = tmp_int[0] - HM_SKILLBASE; + p->hskill[i].id = tmp_int[0]; + p->hskill[i].lv = tmp_int[1]; + } else + ShowError("Read Homun: Unsupported Skill ID %d for homunculus (Homun ID=%d)\n", tmp_int[0], p->hom_id); + next += len; + if (str[next] == ' ') + next++; + } + return 0; +} + +int inter_homun_init() +{ + char line[8192]; + struct s_homunculus *p; + FILE *fp; + int c=0; + + homun_db= idb_alloc(DB_OPT_RELEASE_DATA); + + if( (fp=fopen(homun_txt,"r"))==NULL ) + return 1; + while(fgets(line, sizeof(line), fp)) + { + p = (struct s_homunculus*)aCalloc(sizeof(struct s_homunculus), 1); + if(p==NULL){ + ShowFatalError("int_homun: out of memory!\n"); + exit(EXIT_FAILURE); + } + if(inter_homun_fromstr(line,p)==0 && p->hom_id>0){ + if( p->hom_id >= homun_newid) + homun_newid=p->hom_id+1; + idb_put(homun_db,p->hom_id,p); + }else{ + ShowError("int_homun: broken data [%s] line %d\n",homun_txt,c); + aFree(p); + } + c++; + } + fclose(fp); + return 0; +} + +void inter_homun_final() +{ + homun_db->destroy(homun_db, NULL); + return; +} + +int inter_homun_save_sub(DBKey key,void *data,va_list ap) +{ + char line[8192]; + FILE *fp; + inter_homun_tostr(line,(struct s_homunculus *)data); + fp=va_arg(ap,FILE *); + fprintf(fp,"%s\n",line); + return 0; +} + +int inter_homun_save() +{ + FILE *fp; + int lock; + if( (fp=lock_fopen(homun_txt,&lock))==NULL ){ + ShowError("int_homun: can't write [%s] !!! data is lost !!!\n",homun_txt); + return 1; + } + homun_db->foreach(homun_db,inter_homun_save_sub,fp); + lock_fclose(fp,homun_txt,&lock); + return 0; +} + +int inter_homun_delete(int hom_id) +{ + struct s_homunculus *p; + p = (struct s_homunculus*)idb_get(homun_db,hom_id); + if( p == NULL) + return 0; + idb_remove(homun_db,hom_id); + ShowInfo("Deleted homun (hom_id: %d)\n",hom_id); + return 1; +} + +int mapif_homun_created(int fd,int account_id, struct s_homunculus *p) +{ + WFIFOHEAD(fd, sizeof(struct s_homunculus)+9); + WFIFOW(fd, 0) =0x3890; + WFIFOW(fd,2) = sizeof(struct s_homunculus)+9; + WFIFOL(fd,4) = account_id; + WFIFOB(fd,8)= p->hom_id?1:0; + memcpy(WFIFOP(fd,9), p, sizeof(struct s_homunculus)); + WFIFOSET(fd, WFIFOW(fd,2)); + return 0; +} + +int mapif_homun_info(int fd,int account_id,struct s_homunculus *p) +{ + WFIFOHEAD(fd, sizeof(struct s_homunculus)+9); + WFIFOW(fd,0) = 0x3891; + WFIFOW(fd,2) = sizeof(struct s_homunculus)+9; + WFIFOL(fd,4) = account_id; + WFIFOB(fd,8) = 1; // account loaded with success + + memcpy(WFIFOP(fd,9), p, sizeof(struct s_homunculus)); + WFIFOSET(fd,WFIFOW(fd,2)); + return 0; +} + +int mapif_homun_noinfo(int fd,int account_id) +{ + WFIFOHEAD(fd,sizeof(struct s_homunculus) + 9); + WFIFOW(fd,0)=0x3891; + WFIFOW(fd,2)=sizeof(struct s_homunculus) + 9; + WFIFOL(fd,4)=account_id; + WFIFOB(fd,8)=0; + memset(WFIFOP(fd,9),0,sizeof(struct s_homunculus)); + WFIFOSET(fd,WFIFOW(fd,2)); + + return 0; +} + +int mapif_save_homun_ack(int fd,int account_id,int flag) +{ + WFIFOHEAD(fd, 7); + WFIFOW(fd,0)=0x3892; + WFIFOL(fd,2)=account_id; + WFIFOB(fd,6)=flag; + WFIFOSET(fd,7); + return 0; +} + +int mapif_delete_homun_ack(int fd,int flag) +{ + WFIFOHEAD(fd, 3); + WFIFOW(fd,0)=0x3893; + WFIFOB(fd,2)=flag; + WFIFOSET(fd,3); + return 0; +} + +int mapif_rename_homun_ack(int fd, int account_id, int char_id, int flag, char *name){ + WFIFOHEAD(fd, NAME_LENGTH+12); + WFIFOW(fd, 0) =0x3894; + WFIFOL(fd, 2) =account_id; + WFIFOL(fd, 6) =char_id; + WFIFOB(fd, 10) =flag; + memcpy(WFIFOP(fd, 11), name, NAME_LENGTH); + WFIFOSET(fd, NAME_LENGTH+12); + + return 0; +} + +int mapif_create_homun(int fd) +{ + struct s_homunculus *p; + p= (struct s_homunculus *) aCalloc(sizeof(struct s_homunculus), 1); + if(p==NULL){ + ShowFatalError("int_homun: out of memory !\n"); + //Sending the received data will pass hom_id == 0 <- fail. + mapif_homun_created(fd,RFIFOL(fd,4),(struct s_homunculus*)RFIFOP(fd,8)); + return 0; + } + memcpy(p, RFIFOP(fd,8), sizeof(struct s_homunculus)); + p->hom_id = homun_newid++; //New ID + idb_put(homun_db,p->hom_id,p); + mapif_homun_created(fd,RFIFOL(fd,4),p); + return 0; +} + +int mapif_load_homun(int fd) +{ + struct s_homunculus *p; + int account_id; + account_id = RFIFOL(fd,2); + + p = (struct s_homunculus*)idb_get(homun_db,RFIFOL(fd,6)); + if(p==NULL) { + mapif_homun_noinfo(fd,account_id); + return 0; + } + mapif_homun_info(fd,account_id,p); + return 0; +} + +static void* create_homun(DBKey key, va_list args) { + struct s_homunculus *p; + p=(struct s_homunculus *)aCalloc(sizeof(struct s_homunculus),1); + p->hom_id = key.i; + return p; +} +int mapif_save_homun(int fd,int account_id,struct s_homunculus *data) +{ + struct s_homunculus *p; + int hom_id; + + if (data->hom_id == 0) + data->hom_id = homun_newid++; + hom_id = data->hom_id; + p = (struct s_homunculus*)idb_ensure(homun_db,hom_id,create_homun); + memcpy(p,data,sizeof(struct s_homunculus)); + mapif_save_homun_ack(fd,account_id,1); + return 0; +} + +int mapif_delete_homun(int fd,int hom_id) +{ + mapif_delete_homun_ack(fd,inter_homun_delete(hom_id)); + return 0; +} + +int mapif_rename_homun(int fd, int account_id, int char_id, char *name){ + int i; + + // Check Authorised letters/symbols in the name of the homun + if (char_name_option == 1) { // only letters/symbols in char_name_letters are authorised + for (i = 0; i < NAME_LENGTH && name[i]; i++) + if (strchr(char_name_letters, name[i]) == NULL) { + mapif_rename_homun_ack(fd, account_id, char_id, 0, name); + return 0; + } + } else if (char_name_option == 2) { // letters/symbols in char_name_letters are forbidden + for (i = 0; i < NAME_LENGTH && name[i]; i++) + if (strchr(char_name_letters, name[i]) != NULL) { + mapif_rename_homun_ack(fd, account_id, char_id, 0, name); + return 0; + } + } + + mapif_rename_homun_ack(fd, account_id, char_id, 1, name); + return 0; +} + +int mapif_parse_SaveHomun(int fd) +{ + mapif_save_homun(fd,RFIFOL(fd,4),(struct s_homunculus *)RFIFOP(fd,8)); + return 0; +} + +int mapif_parse_DeleteHomun(int fd) +{ + mapif_delete_homun(fd,RFIFOL(fd,2)); + return 0; +} + +int mapif_parse_RenameHomun(int fd) +{ + mapif_rename_homun(fd, RFIFOL(fd, 2), RFIFOL(fd, 6), (char*)RFIFOP(fd, 10)); + return 0; +} + +int inter_homun_parse_frommap(int fd) +{ + switch(RFIFOW(fd,0)){ + case 0x3090: mapif_create_homun(fd); break; + case 0x3091: mapif_load_homun(fd); break; + case 0x3092: mapif_parse_SaveHomun(fd); break; + case 0x3093: mapif_parse_DeleteHomun(fd); break; + case 0x3094: mapif_parse_RenameHomun(fd); break; + default: + return 0; + } + return 1; +} diff --git a/src/char/int_homun.h b/src/char/int_homun.h new file mode 100644 index 000000000..1858ed4ba --- /dev/null +++ b/src/char/int_homun.h @@ -0,0 +1,15 @@ +// Copyright (c) Athena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + +#ifndef _INT_HOMUN_H_ +#define _INT_HOMUN_H_ + +int inter_homun_init(void); +void inter_homun_final(void); +int inter_homun_save(void); +int inter_homun_delete(int homun_id); +int inter_homun_parse_frommap(int fd); + +extern char homun_txt[1024]; + +#endif /* _INT_HOMUN_H_ */ diff --git a/src/char/int_party.c b/src/char/int_party.c new file mode 100644 index 000000000..f0668a820 --- /dev/null +++ b/src/char/int_party.c @@ -0,0 +1,732 @@ +// Copyright (c) Athena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + +#include "../common/cbasetypes.h" +#include "../common/mmo.h" +#include "../common/malloc.h" +#include "../common/socket.h" +#include "../common/db.h" +#include "../common/lock.h" +#include "../common/showmsg.h" +#include "char.h" +#include "inter.h" +#include "int_party.h" + +#include +#include +#include + +char party_txt[1024] = "save/party.txt"; +#ifndef TXT_SQL_CONVERT +struct party_data { + struct party party; + unsigned int min_lv, max_lv; + int family; //Is this party a family? if so, this holds the child id. + unsigned char size; //Total size of party. +}; + +static DBMap* party_db; // int party_id -> struct party_data* +static int party_newid = 100; + +int mapif_party_broken(int party_id, int flag); +int party_check_empty(struct party *p); +int mapif_parse_PartyLeave(int fd, int party_id, int account_id, int char_id); +int party_check_exp_share(struct party_data *p); +int mapif_party_optionchanged(int fd,struct party *p, int account_id, int flag); + +//Updates party's level range and unsets even share if broken. +static int int_party_check_lv(struct party_data *p) { + int i; + unsigned int lv; + p->min_lv = UINT_MAX; + p->max_lv = 0; + for(i=0;iparty.member[i].online) + continue; + + lv=p->party.member[i].lv; + if (lv < p->min_lv) p->min_lv = lv; + if (lv > p->max_lv) p->max_lv = lv; + } + + if (p->party.exp && !party_check_exp_share(p)) { + p->party.exp = 0; + mapif_party_optionchanged(0, &p->party, 0, 0); + return 0; + } + return 1; +} + +//Calculates the state of a party. +static void int_party_calc_state(struct party_data *p) +{ + int i; + unsigned int lv; + p->min_lv = UINT_MAX; + p->max_lv = 0; + p->party.count = + p->size = + p->family = 0; + + //Check party size. + for(i=0;iparty.member[i].lv) continue; + p->size++; + if(p->party.member[i].online) + p->party.count++; + } + if(p->size == 3) { + //Check Family State. + p->family = char_family( + p->party.member[0].char_id, + p->party.member[1].char_id, + p->party.member[2].char_id + ); + } + //max/min levels. + for(i=0;iparty.member[i].lv; + if (!lv) continue; + if(p->party.member[i].online && + //On families, the kid is not counted towards exp share rules. + p->party.member[i].char_id != p->family) + { + if( lv < p->min_lv ) p->min_lv=lv; + if( p->max_lv < lv ) p->max_lv=lv; + } + } + + if (p->party.exp && !party_check_exp_share(p)) { + p->party.exp = 0; //Set off even share. + mapif_party_optionchanged(0, &p->party, 0, 0); + } + return; +} + +// パ?ティデ?タの文字列への?換 +int inter_party_tostr(char *str, struct party *p) { + int i, len; + + len = sprintf(str, "%d\t%s\t%d,%d\t", p->party_id, p->name, p->exp, p->item); + for(i = 0; i < MAX_PARTY; i++) { + struct party_member *m = &p->member[i]; + len += sprintf(str + len, "%d,%d,%d\t", m->account_id, m->char_id, m->leader); + } + + return 0; +} +#endif //TXT_SQL_CONVERT +// パ?ティデ?タの文字列からの?換 +int inter_party_fromstr(char *str, struct party *p) { + int i, j; + int tmp_int[16]; + char tmp_str[256]; +#ifndef TXT_SQL_CONVERT + struct mmo_charstatus* status; +#endif + + memset(p, 0, sizeof(struct party)); + + if (sscanf(str, "%d\t%255[^\t]\t%d,%d\t", &tmp_int[0], tmp_str, &tmp_int[1], &tmp_int[2]) != 4) + return 1; + + p->party_id = tmp_int[0]; + memcpy(p->name, tmp_str, NAME_LENGTH); + p->exp = tmp_int[1]?1:0; + p->item = tmp_int[2]; + + for(j = 0; j < 3 && str != NULL; j++) + str = strchr(str + 1, '\t'); + + for(i = 0; i < MAX_PARTY; i++) { + struct party_member *m = &p->member[i]; + if (str == NULL) + return 1; + + if (sscanf(str + 1, "%d,%d,%d\t", &tmp_int[0], &tmp_int[1], &tmp_int[2]) != 3) + return 1; + + m->account_id = tmp_int[0]; + m->char_id = tmp_int[1]; + m->leader = tmp_int[2]?1:0; + + str = strchr(str + 1, '\t'); +#ifndef TXT_SQL_CONVERT + if (!m->account_id) continue; + //Lookup player for rest of data. + status = search_character(m->account_id, m->char_id); + if (!status) continue; + + memcpy(m->name, status->name, NAME_LENGTH); + m->class_ = status->class_; + m->map = status->last_point.map; + m->lv = status->base_level; +#endif //TXT_SQL_CONVERT + } + + return 0; +} +#ifndef TXT_SQL_CONVERT +// パ?ティデ?タのロ?ド +int inter_party_init() { + char line[8192]; + struct party_data *p; + FILE *fp; + int c = 0; + int i, j; + + party_db = idb_alloc(DB_OPT_RELEASE_DATA); + + if ((fp = fopen(party_txt, "r")) == NULL) + return 1; + + while(fgets(line, sizeof(line), fp)) + { + j = 0; + if (sscanf(line, "%d\t%%newid%%\n%n", &i, &j) == 1 && j > 0 && party_newid <= i) { + party_newid = i; + continue; + } + + p = (struct party_data*)aCalloc(sizeof(struct party_data), 1); + if (p == NULL){ + ShowFatalError("int_party: out of memory!\n"); + exit(EXIT_FAILURE); + } + memset(p, 0, sizeof(struct party_data)); + if (inter_party_fromstr(line, &p->party) == 0 && p->party.party_id > 0) { + int_party_calc_state(p); + if (p->party.party_id >= party_newid) + party_newid = p->party.party_id + 1; + idb_put(party_db, p->party.party_id, p); + party_check_empty(&p->party); + } else { + ShowError("int_party: broken data [%s] line %d\n", party_txt, c + 1); + aFree(p); + } + c++; + } + fclose(fp); + + return 0; +} + +void inter_party_final() +{ + party_db->destroy(party_db, NULL); + return; +} + +// パ?ティ?デ?タのセ?ブ用 +int inter_party_save_sub(DBKey key, void *data, va_list ap) { + char line[8192]; + FILE *fp; + + inter_party_tostr(line, &((struct party_data*)data)->party); + fp = va_arg(ap, FILE *); + fprintf(fp, "%s\n", line); + + return 0; +} + +// パ?ティ?デ?タのセ?ブ +int inter_party_save() { + FILE *fp; + int lock; + + if ((fp = lock_fopen(party_txt, &lock)) == NULL) { + ShowError("int_party: can't write [%s] !!! data is lost !!!\n", party_txt); + return 1; + } + party_db->foreach(party_db, inter_party_save_sub, fp); + lock_fclose(fp,party_txt, &lock); + return 0; +} + +// パ?ティ名?索用 +int search_partyname_sub(DBKey key,void *data,va_list ap) { + struct party_data *p = (struct party_data *)data,**dst; + char *str; + + str = va_arg(ap, char *); + dst = va_arg(ap, struct party_data **); + if (strncmpi(p->party.name, str, NAME_LENGTH) == 0) + *dst = p; + + return 0; +} + +// パ?ティ名?索 +struct party_data* search_partyname(char *str) { + struct party_data *p = NULL; + party_db->foreach(party_db, search_partyname_sub, str, &p); + return p; +} + +// Returns whether this party can keep having exp share or not. +int party_check_exp_share(struct party_data *p) { + return (p->party.count < 2|| p->max_lv - p->min_lv <= party_share_level); +} + +// パ?ティが空かどうかチェック +int party_check_empty(struct party *p) { + int i; + + for(i = 0; i < MAX_PARTY; i++) { + if (p->member[i].account_id > 0) { + return 0; + } + } + mapif_party_broken(p->party_id, 0); + idb_remove(party_db, p->party_id); + + return 1; +} + +// キャラの競合がないかチェック用 +int party_check_conflict_sub(DBKey key, void *data, va_list ap) { + struct party_data *p = (struct party_data *)data; + int party_id, account_id, char_id, i; + + party_id=va_arg(ap, int); + account_id=va_arg(ap, int); + char_id=va_arg(ap, int); + + if (p->party.party_id == party_id) //No conflict to check + return 0; + + for(i = 0; i < MAX_PARTY; i++) { + if(p->party.member[i].account_id == account_id && + p->party.member[i].char_id == char_id) + { + ShowWarning("int_party: party conflict! %d %d %d\n", account_id, party_id, p->party.party_id); + mapif_parse_PartyLeave(-1, p->party.party_id, account_id, char_id); + } + } + + return 0; +} + +// キャラの競合がないかチェック +int party_check_conflict(int party_id, int account_id, int char_id) { + party_db->foreach(party_db, party_check_conflict_sub, party_id, account_id, char_id); + return 0; +} + +//------------------------------------------------------------------- +// map serverへの通信 + +// パ?ティ作成可否 +int mapif_party_created(int fd,int account_id, int char_id, struct party *p) { + WFIFOHEAD(fd, 39); + WFIFOW(fd,0) = 0x3820; + WFIFOL(fd,2) = account_id; + WFIFOL(fd,6) = char_id; + if (p != NULL) { + WFIFOB(fd,10) = 0; + WFIFOL(fd,11) = p->party_id; + memcpy(WFIFOP(fd,15), p->name, NAME_LENGTH); + ShowInfo("Created party (%d - %s)\n", p->party_id, p->name); + } else { + WFIFOB(fd,10) = 1; + WFIFOL(fd,11) = 0; + memset(WFIFOP(fd,15), 0, NAME_LENGTH); + } + WFIFOSET(fd,39); + return 0; +} + +// パ?ティ情報見つからず +int mapif_party_noinfo(int fd, int party_id) { + WFIFOHEAD(fd, 8); + WFIFOW(fd,0) = 0x3821; + WFIFOW(fd,2) = 8; + WFIFOL(fd,4) = party_id; + WFIFOSET(fd,8); + ShowWarning("int_party: info not found %d\n", party_id); + + return 0; +} + +// パ?ティ情報まとめ送り +int mapif_party_info(int fd, struct party *p) { + unsigned char buf[2048]; + + WBUFW(buf,0) = 0x3821; + memcpy(buf + 4, p, sizeof(struct party)); + WBUFW(buf,2) = 4 + sizeof(struct party); + if (fd < 0) + mapif_sendall(buf, WBUFW(buf,2)); + else + mapif_send(fd, buf, WBUFW(buf,2)); + return 0; +} + +// パ?ティメンバ追加可否 +int mapif_party_memberadded(int fd, int party_id, int account_id, int char_id, int flag) { + WFIFOHEAD(fd, 15); + WFIFOW(fd,0) = 0x3822; + WFIFOL(fd,2) = party_id; + WFIFOL(fd,6) = account_id; + WFIFOL(fd,10) = char_id; + WFIFOB(fd,14) = flag; + WFIFOSET(fd,15); + + return 0; +} + +// パ?ティ設定?更通知 +int mapif_party_optionchanged(int fd,struct party *p, int account_id, int flag) { + unsigned char buf[15]; + + WBUFW(buf,0) = 0x3823; + WBUFL(buf,2) = p->party_id; + WBUFL(buf,6) = account_id; + WBUFW(buf,10) = p->exp; + WBUFW(buf,12) = p->item; + WBUFB(buf,14) = flag; + if (flag == 0) + mapif_sendall(buf, 15); + else + mapif_send(fd, buf, 15); + return 0; +} + +// パ?ティ?退通知 +int mapif_party_leaved(int party_id,int account_id, int char_id) { + unsigned char buf[16]; + + WBUFW(buf,0) = 0x3824; + WBUFL(buf,2) = party_id; + WBUFL(buf,6) = account_id; + WBUFL(buf,10) = char_id; + mapif_sendall(buf, 14); + return 0; +} + +// パ?ティマップ更新通知 +int mapif_party_membermoved(struct party *p, int idx) { + unsigned char buf[20]; + + WBUFW(buf,0) = 0x3825; + WBUFL(buf,2) = p->party_id; + WBUFL(buf,6) = p->member[idx].account_id; + WBUFL(buf,10) = p->member[idx].char_id; + WBUFW(buf,14) = p->member[idx].map; + WBUFB(buf,16) = p->member[idx].online; + WBUFW(buf,17) = p->member[idx].lv; + mapif_sendall(buf, 19); + return 0; +} + +// パ?ティ解散通知 +int mapif_party_broken(int party_id, int flag) { + unsigned char buf[7]; + WBUFW(buf,0) = 0x3826; + WBUFL(buf,2) = party_id; + WBUFB(buf,6) = flag; + mapif_sendall(buf, 7); + ShowInfo("Party broken (%d)\n", party_id); + + return 0; +} + +// パ?ティ??言 +int mapif_party_message(int party_id, int account_id, char *mes, int len, int sfd) { + unsigned char buf[2048]; + + WBUFW(buf,0) = 0x3827; + WBUFW(buf,2) = len + 12; + WBUFL(buf,4) = party_id; + WBUFL(buf,8) = account_id; + memcpy(WBUFP(buf,12), mes, len); + mapif_sendallwos(sfd, buf,len + 12); + + return 0; +} + +//------------------------------------------------------------------- +// map serverからの通信 + + +// パ?ティ +int mapif_parse_CreateParty(int fd, char *name, int item, int item2, struct party_member *leader) { + struct party_data *p; + int i; + + for(i = 0; i < NAME_LENGTH && name[i]; i++) { + if (!(name[i] & 0xe0) || name[i] == 0x7f) { + ShowInfo("int_party: illegal party name [%s]\n", name); + mapif_party_created(fd, leader->account_id, leader->char_id, NULL); + return 0; + } + } + + if ((p = search_partyname(name)) != NULL) { + ShowInfo("int_party: same name party exists [%s]\n", name); + mapif_party_created(fd, leader->account_id, leader->char_id, NULL); + return 0; + } + + // Check Authorised letters/symbols in the name of the character + if (char_name_option == 1) { // only letters/symbols in char_name_letters are authorised + for (i = 0; i < NAME_LENGTH && name[i]; i++) + if (strchr(char_name_letters, name[i]) == NULL) { + mapif_party_created(fd, leader->account_id, leader->char_id, NULL); + return 0; + } + } else if (char_name_option == 2) { // letters/symbols in char_name_letters are forbidden + for (i = 0; i < NAME_LENGTH && name[i]; i++) + if (strchr(char_name_letters, name[i]) != NULL) { + mapif_party_created(fd, leader->account_id, leader->char_id, NULL); + return 0; + } + } + + p = (struct party_data *) aCalloc(sizeof(struct party_data), 1); + if (p == NULL) { + ShowFatalError("int_party: out of memory !\n"); + mapif_party_created(fd,leader->account_id,leader->char_id,NULL); + return 0; + } + p->party.party_id = party_newid++; + memcpy(p->party.name, name, NAME_LENGTH); + p->party.exp = 0; + p->party.item=(item?1:0)|(item2?2:0); + memcpy(&p->party.member[0], leader, sizeof(struct party_member)); + p->party.member[0].leader = 1; + int_party_calc_state(p); + idb_put(party_db, p->party.party_id, p); + + mapif_party_created(fd, leader->account_id, leader->char_id, &p->party); + mapif_party_info(fd, &p->party); + + return 0; +} + +// パ?ティ情報要求 +int mapif_parse_PartyInfo(int fd, int party_id) +{ + struct party_data *p; + + p = (struct party_data*)idb_get(party_db, party_id); + if (p != NULL) + mapif_party_info(fd, &p->party); + else { + mapif_party_noinfo(fd, party_id); + char_clearparty(party_id); + } + + return 0; +} + +// パーティ追加要求 +int mapif_parse_PartyAddMember(int fd, int party_id, struct party_member *member) +{ + struct party_data *p; + int i; + + p = (struct party_data*)idb_get(party_db, party_id); + if( p == NULL || p->size == MAX_PARTY ) { + mapif_party_memberadded(fd, party_id, member->account_id, member->char_id, 1); + return 0; + } + + ARR_FIND( 0, MAX_PARTY, i, p->party.member[i].account_id == 0 ); + if( i == MAX_PARTY ) + {// Party full + mapif_party_memberadded(fd, party_id, member->account_id, member->char_id, 1); + return 0; + } + + memcpy(&p->party.member[i], member, sizeof(struct party_member)); + p->party.member[i].leader = 0; + if (p->party.member[i].online) p->party.count++; + p->size++; + if (p->size == 3) //Check family state. + int_party_calc_state(p); + else //Check even share range. + if (member->lv < p->min_lv || member->lv > p->max_lv || p->family) { + if (p->family) p->family = 0; //Family state broken. + int_party_check_lv(p); + } + + mapif_party_memberadded(fd, party_id, member->account_id, member->char_id, 0); + mapif_party_info(-1, &p->party); + + return 0; +} + +// パ?ティ?設定?更要求 +int mapif_parse_PartyChangeOption(int fd, int party_id, int account_id, int exp, int item) +{ + struct party_data *p; + int flag = 0; + + p = (struct party_data*)idb_get(party_db, party_id); + if (p == NULL) + return 0; + + p->party.exp = exp; + if (exp>0 && !party_check_exp_share(p)) { + flag |= 0x01; + p->party.exp = 0; + } + p->party.item = item&0x3; + mapif_party_optionchanged(fd, &p->party, account_id, flag); + return 0; +} + +// パ?ティ?退要求 +int mapif_parse_PartyLeave(int fd, int party_id, int account_id, int char_id) +{ + struct party_data *p; + int i,lv; + + p = (struct party_data*)idb_get(party_db, party_id); + if (!p) return 0; + + for(i = 0; i < MAX_PARTY; i++) { + if(p->party.member[i].account_id == account_id && + p->party.member[i].char_id == char_id) + { + mapif_party_leaved(party_id, account_id, char_id); + lv = p->party.member[i].lv; + if(p->party.member[i].online) p->party.count--; + memset(&p->party.member[i], 0, sizeof(struct party_member)); + p->size--; + if (lv == p->min_lv || lv == p->max_lv || p->family) + { + if(p->family) p->family = 0; //Family state broken. + int_party_check_lv(p); + } + if (party_check_empty(&p->party) == 0) + mapif_party_info(-1, &p->party); + return 0; + } + } + return 0; +} + +int mapif_parse_PartyChangeMap(int fd, int party_id, int account_id, int char_id, unsigned short map, int online, unsigned int lv) +{ + struct party_data *p; + int i; + + p = (struct party_data*)idb_get(party_db, party_id); + if (p == NULL) + return 0; + + for(i = 0; i < MAX_PARTY && + (p->party.member[i].account_id != account_id || + p->party.member[i].char_id != char_id); i++); + + if (i == MAX_PARTY) return 0; + + if (p->party.member[i].online != online) + { + p->party.member[i].online = online; + if (online) + p->party.count++; + else + p->party.count--; + // Even share check situations: Family state (always breaks) + // character logging on/off is max/min level (update level range) + // or character logging on/off has a different level (update level range using new level) + if (p->family || + (p->party.member[i].lv <= p->min_lv || p->party.member[i].lv >= p->max_lv) || + (p->party.member[i].lv != lv && (lv <= p->min_lv || lv >= p->max_lv)) + ) + { + p->party.member[i].lv = lv; + int_party_check_lv(p); + } + //Send online/offline update. + mapif_party_membermoved(&p->party, i); + } + if (p->party.member[i].lv != lv) { + if(p->party.member[i].lv == p->min_lv || + p->party.member[i].lv == p->max_lv) + { + p->party.member[i].lv = lv; + int_party_check_lv(p); + } else + p->party.member[i].lv = lv; + //There is no need to send level update to map servers + //since they do nothing with it. + } + if (p->party.member[i].map != map) { + p->party.member[i].map = map; + mapif_party_membermoved(&p->party, i); + } + return 0; +} + +// パ?ティ解散要求 +int mapif_parse_BreakParty(int fd, int party_id) { + + idb_remove(party_db, party_id); + mapif_party_broken(fd, party_id); + + return 0; +} + +// パ?ティメッセ?ジ送信 +int mapif_parse_PartyMessage(int fd, int party_id, int account_id, char *mes, int len) { + return mapif_party_message(party_id, account_id, mes, len, fd); +} +// パ?ティチェック要求 +int mapif_parse_PartyCheck(int fd, int party_id, int account_id, int char_id) { + return party_check_conflict(party_id, account_id, char_id); +} + +int mapif_parse_PartyLeaderChange(int fd,int party_id,int account_id,int char_id) +{ + struct party_data *p; + int i; + + p = (struct party_data*)idb_get(party_db, party_id); + if (p == NULL) + return 0; + + for (i = 0; i < MAX_PARTY; i++) + { + if(p->party.member[i].leader) + p->party.member[i].leader = 0; + if(p->party.member[i].account_id == account_id && + p->party.member[i].char_id == char_id) + p->party.member[i].leader = 1; + } + return 1; +} + +// map server からの通信 +// ?1パケットのみ解析すること +// ?パケット長デ?タはinter.cにセットしておくこと +// ?パケット長チェックや、RFIFOSKIPは呼び出し元で行われるので行ってはならない +// ?エラ?なら0(false)、そうでないなら1(true)をかえさなければならない +int inter_party_parse_frommap(int fd) { + RFIFOHEAD(fd); + switch(RFIFOW(fd,0)) { + case 0x3020: mapif_parse_CreateParty(fd, (char*)RFIFOP(fd,4), RFIFOB(fd,28), RFIFOB(fd,29), (struct party_member*)RFIFOP(fd,30)); break; + case 0x3021: mapif_parse_PartyInfo(fd, RFIFOL(fd,2)); break; + case 0x3022: mapif_parse_PartyAddMember(fd, RFIFOL(fd,4), (struct party_member*)RFIFOP(fd,8)); break; + case 0x3023: mapif_parse_PartyChangeOption(fd, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOW(fd,10), RFIFOW(fd,12)); break; + case 0x3024: mapif_parse_PartyLeave(fd, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10)); break; + case 0x3025: mapif_parse_PartyChangeMap(fd, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10), RFIFOW(fd,14), RFIFOB(fd,16), RFIFOW(fd,17)); break; + case 0x3026: mapif_parse_BreakParty(fd, RFIFOL(fd,2)); break; + case 0x3027: mapif_parse_PartyMessage(fd, RFIFOL(fd,4), RFIFOL(fd,8), (char*)RFIFOP(fd,12), RFIFOW(fd,2)-12); break; + case 0x3028: mapif_parse_PartyCheck(fd, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10)); break; + case 0x3029: mapif_parse_PartyLeaderChange(fd, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10)); break; + default: + return 0; + } + + return 1; +} + +// サ?バ?から?退要求(キャラ削除用) +int inter_party_leave(int party_id, int account_id, int char_id) { + return mapif_parse_PartyLeave(-1, party_id, account_id, char_id); +} +#endif //TXT_SQL_CONVERT diff --git a/src/char/int_party.h b/src/char/int_party.h new file mode 100644 index 000000000..ad724e475 --- /dev/null +++ b/src/char/int_party.h @@ -0,0 +1,20 @@ +// Copyright (c) Athena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + +#ifndef _INT_PARTY_H_ +#define _INT_PARTY_H_ + +struct party; + +int inter_party_init(void); +void inter_party_final(void); +int inter_party_save(void); +int inter_party_parse_frommap(int fd); +int inter_party_leave(int party_id,int account_id, int char_id); + +extern char party_txt[1024]; + +//For the TXT->SQL converter +int inter_party_fromstr(char *str, struct party *p); + +#endif /* _INT_PARTY_H_ */ diff --git a/src/char/int_pet.c b/src/char/int_pet.c new file mode 100644 index 000000000..41d61fbc3 --- /dev/null +++ b/src/char/int_pet.c @@ -0,0 +1,380 @@ +// Copyright (c) Athena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + +#include "../common/mmo.h" +#include "../common/malloc.h" +#include "../common/socket.h" +#include "../common/db.h" +#include "../common/lock.h" +#include "../common/showmsg.h" +#include "char.h" +#include "inter.h" +#include "int_pet.h" + +#include +#include +#include + +char pet_txt[1024]="save/pet.txt"; + +#ifndef TXT_SQL_CONVERT +static DBMap* pet_db; // int pet_id -> struct s_pet* +static int pet_newid = 100; + +int inter_pet_tostr(char *str,struct s_pet *p) +{ + int len; + + if(p->hungry < 0) + p->hungry = 0; + else if(p->hungry > 100) + p->hungry = 100; + if(p->intimate < 0) + p->intimate = 0; + else if(p->intimate > 1000) + p->intimate = 1000; + + len=sprintf(str,"%d,%d,%s\t%d,%d,%d,%d,%d,%d,%d,%d,%d", + p->pet_id,p->class_,p->name,p->account_id,p->char_id,p->level,p->egg_id, + p->equip,p->intimate,p->hungry,p->rename_flag,p->incuvate); + + return 0; +} +#endif //TXT_SQL_CONVERT +int inter_pet_fromstr(char *str,struct s_pet *p) +{ + int s; + int tmp_int[16]; + char tmp_str[256]; + + memset(p,0,sizeof(struct s_pet)); + + s=sscanf(str,"%d,%d,%[^\t]\t%d,%d,%d,%d,%d,%d,%d,%d,%d",&tmp_int[0],&tmp_int[1],tmp_str,&tmp_int[2], + &tmp_int[3],&tmp_int[4],&tmp_int[5],&tmp_int[6],&tmp_int[7],&tmp_int[8],&tmp_int[9],&tmp_int[10]); + + if(s!=12) + return 1; + + p->pet_id = tmp_int[0]; + p->class_ = tmp_int[1]; + memcpy(p->name,tmp_str,NAME_LENGTH); + p->account_id = tmp_int[2]; + p->char_id = tmp_int[3]; + p->level = tmp_int[4]; + p->egg_id = tmp_int[5]; + p->equip = tmp_int[6]; + p->intimate = tmp_int[7]; + p->hungry = tmp_int[8]; + p->rename_flag = tmp_int[9]; + p->incuvate = tmp_int[10]; + + if(p->hungry < 0) + p->hungry = 0; + else if(p->hungry > 100) + p->hungry = 100; + if(p->intimate < 0) + p->intimate = 0; + else if(p->intimate > 1000) + p->intimate = 1000; + + return 0; +} +#ifndef TXT_SQL_CONVERT +int inter_pet_init() +{ + char line[8192]; + struct s_pet *p; + FILE *fp; + int c=0; + + pet_db= idb_alloc(DB_OPT_RELEASE_DATA); + + if( (fp=fopen(pet_txt,"r"))==NULL ) + return 1; + while(fgets(line, sizeof(line), fp)) + { + p = (struct s_pet*)aCalloc(sizeof(struct s_pet), 1); + if(p==NULL){ + ShowFatalError("int_pet: out of memory!\n"); + exit(EXIT_FAILURE); + } + memset(p,0,sizeof(struct s_pet)); + if(inter_pet_fromstr(line,p)==0 && p->pet_id>0){ + if( p->pet_id >= pet_newid) + pet_newid=p->pet_id+1; + idb_put(pet_db,p->pet_id,p); + }else{ + ShowError("int_pet: broken data [%s] line %d\n",pet_txt,c); + aFree(p); + } + c++; + } + fclose(fp); + return 0; +} + +void inter_pet_final() +{ + pet_db->destroy(pet_db, NULL); + return; +} + +int inter_pet_save_sub(DBKey key,void *data,va_list ap) +{ + char line[8192]; + FILE *fp; + inter_pet_tostr(line,(struct s_pet *)data); + fp=va_arg(ap,FILE *); + fprintf(fp,"%s\n",line); + return 0; +} + +int inter_pet_save() +{ + FILE *fp; + int lock; + if( (fp=lock_fopen(pet_txt,&lock))==NULL ){ + ShowError("int_pet: can't write [%s] !!! data is lost !!!\n",pet_txt); + return 1; + } + pet_db->foreach(pet_db,inter_pet_save_sub,fp); + lock_fclose(fp,pet_txt,&lock); + return 0; +} + +int inter_pet_delete(int pet_id) +{ + struct s_pet *p; + p = (struct s_pet*)idb_get(pet_db,pet_id); + if( p == NULL) + return 1; + else { + idb_remove(pet_db,pet_id); + ShowInfo("Deleted pet (pet_id: %d)\n",pet_id); + } + return 0; +} + +int mapif_pet_created(int fd,int account_id,struct s_pet *p) +{ + WFIFOHEAD(fd, 11); + WFIFOW(fd,0)=0x3880; + WFIFOL(fd,2)=account_id; + if(p!=NULL){ + WFIFOB(fd,6)=0; + WFIFOL(fd,7)=p->pet_id; + ShowInfo("Created pet (%d - %s)\n",p->pet_id,p->name); + }else{ + WFIFOB(fd,6)=1; + WFIFOL(fd,7)=0; + } + WFIFOSET(fd,11); + + return 0; +} + +int mapif_pet_info(int fd,int account_id,struct s_pet *p) +{ + WFIFOHEAD(fd, sizeof(struct s_pet) + 9); + WFIFOW(fd,0)=0x3881; + WFIFOW(fd,2)=sizeof(struct s_pet) + 9; + WFIFOL(fd,4)=account_id; + WFIFOB(fd,8)=0; + memcpy(WFIFOP(fd,9),p,sizeof(struct s_pet)); + WFIFOSET(fd,WFIFOW(fd,2)); + + return 0; +} + +int mapif_pet_noinfo(int fd,int account_id) +{ + WFIFOHEAD(fd, sizeof(struct s_pet) + 9); + WFIFOW(fd,0)=0x3881; + WFIFOW(fd,2)=sizeof(struct s_pet) + 9; + WFIFOL(fd,4)=account_id; + WFIFOB(fd,8)=1; + memset(WFIFOP(fd,9),0,sizeof(struct s_pet)); + WFIFOSET(fd,WFIFOW(fd,2)); + + return 0; +} + +int mapif_save_pet_ack(int fd,int account_id,int flag) +{ + WFIFOHEAD(fd, 7); + WFIFOW(fd,0)=0x3882; + WFIFOL(fd,2)=account_id; + WFIFOB(fd,6)=flag; + WFIFOSET(fd,7); + + return 0; +} + +int mapif_delete_pet_ack(int fd,int flag) +{ + WFIFOHEAD(fd, 3); + WFIFOW(fd,0)=0x3883; + WFIFOB(fd,2)=flag; + WFIFOSET(fd,3); + + return 0; +} + +int mapif_create_pet(int fd,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) +{ + struct s_pet *p; + p= (struct s_pet *) aCalloc(sizeof(struct s_pet), 1); + if(p==NULL){ + ShowFatalError("int_pet: out of memory !\n"); + mapif_pet_created(fd,account_id,NULL); + return 0; + } +// memset(p,0,sizeof(struct s_pet)); unnecessary after aCalloc [Skotlex] + p->pet_id = pet_newid++; + memcpy(p->name,pet_name,NAME_LENGTH); + if(incuvate == 1) + p->account_id = p->char_id = 0; + else { + p->account_id = account_id; + p->char_id = char_id; + } + p->class_ = pet_class; + p->level = pet_lv; + p->egg_id = pet_egg_id; + p->equip = pet_equip; + p->intimate = intimate; + p->hungry = hungry; + p->rename_flag = rename_flag; + p->incuvate = incuvate; + + if(p->hungry < 0) + p->hungry = 0; + else if(p->hungry > 100) + p->hungry = 100; + if(p->intimate < 0) + p->intimate = 0; + else if(p->intimate > 1000) + p->intimate = 1000; + + idb_put(pet_db,p->pet_id,p); + + mapif_pet_created(fd,account_id,p); + + return 0; +} + +int mapif_load_pet(int fd,int account_id,int char_id,int pet_id) +{ + struct s_pet *p; + p = (struct s_pet*)idb_get(pet_db,pet_id); + if(p!=NULL) { + if(p->incuvate == 1) { + p->account_id = p->char_id = 0; + mapif_pet_info(fd,account_id,p); + } + else if(account_id == p->account_id && char_id == p->char_id) + mapif_pet_info(fd,account_id,p); + else + mapif_pet_noinfo(fd,account_id); + } + else + mapif_pet_noinfo(fd,account_id); + + return 0; +} + +static void* create_pet(DBKey key, va_list args) { + struct s_pet *p; + p=(struct s_pet *)aCalloc(sizeof(struct s_pet),1); + p->pet_id = key.i; + return p; +} +int mapif_save_pet(int fd,int account_id,struct s_pet *data) +{ + struct s_pet *p; + int pet_id, len; + RFIFOHEAD(fd); + len=RFIFOW(fd,2); + + if(sizeof(struct s_pet)!=len-8) { + ShowError("inter pet: data size error %d %d\n",sizeof(struct s_pet),len-8); + } + else{ + pet_id = data->pet_id; + if (pet_id == 0) + pet_id = data->pet_id = pet_newid++; + p = (struct s_pet*)idb_ensure(pet_db,pet_id,create_pet); + if(data->hungry < 0) + data->hungry = 0; + else if(data->hungry > 100) + data->hungry = 100; + if(data->intimate < 0) + data->intimate = 0; + else if(data->intimate > 1000) + data->intimate = 1000; + memcpy(p,data,sizeof(struct s_pet)); + if(p->incuvate == 1) + p->account_id = p->char_id = 0; + + mapif_save_pet_ack(fd,account_id,0); + } + + return 0; +} + +int mapif_delete_pet(int fd,int pet_id) +{ + mapif_delete_pet_ack(fd,inter_pet_delete(pet_id)); + + return 0; +} + +int mapif_parse_CreatePet(int fd) +{ + RFIFOHEAD(fd); + mapif_create_pet(fd,RFIFOL(fd,2),RFIFOL(fd,6),RFIFOW(fd,10),RFIFOW(fd,12),RFIFOW(fd,14),RFIFOW(fd,16),RFIFOW(fd,18), + RFIFOW(fd,20),RFIFOB(fd,22),RFIFOB(fd,23),(char*)RFIFOP(fd,24)); + return 0; +} + +int mapif_parse_LoadPet(int fd) +{ + RFIFOHEAD(fd); + mapif_load_pet(fd,RFIFOL(fd,2),RFIFOL(fd,6),RFIFOL(fd,10)); + return 0; +} + +int mapif_parse_SavePet(int fd) +{ + RFIFOHEAD(fd); + mapif_save_pet(fd,RFIFOL(fd,4),(struct s_pet *)RFIFOP(fd,8)); + return 0; +} + +int mapif_parse_DeletePet(int fd) +{ + RFIFOHEAD(fd); + mapif_delete_pet(fd,RFIFOL(fd,2)); + return 0; +} + +// map server からの通信 +// ・1パケットのみ解析すること +// ・パケット長データはinter.cにセットしておくこと +// ・パケット長チェックや、RFIFOSKIPは呼び出し元で行われるので行ってはならない +// ・エラーなら0(false)、そうでないなら1(true)をかえさなければならない +int inter_pet_parse_frommap(int fd) +{ + RFIFOHEAD(fd); + switch(RFIFOW(fd,0)){ + case 0x3080: mapif_parse_CreatePet(fd); break; + case 0x3081: mapif_parse_LoadPet(fd); break; + case 0x3082: mapif_parse_SavePet(fd); break; + case 0x3083: mapif_parse_DeletePet(fd); break; + default: + return 0; + } + return 1; +} +#endif //TXT_SQL_CONVERT diff --git a/src/char/int_pet.h b/src/char/int_pet.h new file mode 100644 index 000000000..9234af109 --- /dev/null +++ b/src/char/int_pet.h @@ -0,0 +1,21 @@ +// Copyright (c) Athena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + +#ifndef _INT_PET_H_ +#define _INT_PET_H_ + +struct s_pet; + +int inter_pet_init(void); +void inter_pet_final(void); +int inter_pet_save(void); +int inter_pet_delete(int pet_id); + +int inter_pet_parse_frommap(int fd); + +extern char pet_txt[1024]; + +//Exported for use in the TXT-SQL converter. +int inter_pet_fromstr(char *str,struct s_pet *p); + +#endif /* _INT_PET_H_ */ diff --git a/src/char/int_status.c b/src/char/int_status.c new file mode 100644 index 000000000..bf5d94155 --- /dev/null +++ b/src/char/int_status.c @@ -0,0 +1,183 @@ +// Copyright (c) Athena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + +#include "../common/mmo.h" +#include "../common/db.h" +#include "../common/lock.h" +#include "../common/malloc.h" +#include "../common/showmsg.h" +#include "int_status.h" + +#include + +// Contains all the status change data in-memory. [Skotlex] +static DBMap* scdata_db = NULL; // int char_id -> struct scdata* +char scdata_txt[1024]="save/scdata.txt"; //By [Skotlex] + +#ifdef ENABLE_SC_SAVING +static void* create_scdata(DBKey key, va_list args) +{ + struct scdata *data; + data = (struct scdata*)aCalloc(1, sizeof(struct scdata)); + data->account_id = va_arg(args, int); + data->char_id = key.i; + return data; +} + +/*========================================== + * Loads status change data of the player given. [Skotlex] + *------------------------------------------*/ +struct scdata* status_search_scdata(int aid, int cid) +{ + return (struct scdata*)scdata_db->ensure(scdata_db, i2key(cid), create_scdata, aid); +} + +/*========================================== + * Deletes status change data of the player given. [Skotlex] + * Should be invoked after the data of said player was successfully loaded. + *------------------------------------------*/ +void status_delete_scdata(int aid, int cid) +{ + struct scdata* scdata = (struct scdata*)idb_remove(scdata_db, cid); + if (scdata) + { + if (scdata->data) + aFree(scdata->data); + aFree(scdata); + } +} + + +static void inter_status_tostr(char* line, struct scdata *sc_data) +{ + int i, len; + + len = sprintf(line, "%d,%d,%d\t", sc_data->account_id, sc_data->char_id, sc_data->count); + for(i = 0; i < sc_data->count; i++) { + len += sprintf(line + len, "%d,%d,%d,%d,%d,%d\t", sc_data->data[i].type, sc_data->data[i].tick, + sc_data->data[i].val1, sc_data->data[i].val2, sc_data->data[i].val3, sc_data->data[i].val4); + } + return; +} + +static int inter_scdata_fromstr(char *line, struct scdata *sc_data) +{ + int i, len, next; + + if (sscanf(line,"%d,%d,%d\t%n",&sc_data->account_id, &sc_data->char_id, &sc_data->count, &next) < 3) + return 0; + + if (sc_data->count < 1) + return 0; + + sc_data->data = (struct status_change_data*)aCalloc(sc_data->count, sizeof (struct status_change_data)); + + for (i = 0; i < sc_data->count; i++) + { + if (sscanf(line + next, "%hu,%d,%d,%d,%d,%d\t%n", &sc_data->data[i].type, &sc_data->data[i].tick, + &sc_data->data[i].val1, &sc_data->data[i].val2, &sc_data->data[i].val3, &sc_data->data[i].val4, &len) < 6) + { + aFree(sc_data->data); + return 0; + } + next+=len; + } + return 1; +} +/*========================================== + * Loads all scdata from the given filename. + *------------------------------------------*/ +void status_load_scdata(const char* filename) +{ + FILE *fp; + int sd_count=0, sc_count=0; + char line[8192]; + struct scdata *sc; + + if ((fp = fopen(filename, "r")) == NULL) { + ShowError("status_load_scdata: Cannot open file %s!\n", filename); + return; + } + + while(fgets(line, sizeof(line), fp)) + { + sc = (struct scdata*)aCalloc(1, sizeof(struct scdata)); + if (inter_scdata_fromstr(line, sc)) { + sd_count++; + sc_count+= sc->count; + sc = (struct scdata*)idb_put(scdata_db, sc->char_id, sc); + if (sc) { + ShowError("Duplicate entry in %s for character %d\n", filename, sc->char_id); + if (sc->data) aFree(sc->data); + aFree(sc); + } + } else { + ShowError("status_load_scdata: Broken line data: %s\n", line); + aFree(sc); + } + } + fclose(fp); + ShowStatus("Loaded %d saved status changes for %d characters.\n", sc_count, sd_count); +} + +static int inter_status_save_sub(DBKey key, void *data, va_list ap) { + char line[8192]; + struct scdata * sc_data; + FILE *fp; + + sc_data = (struct scdata *)data; + if (sc_data->count < 1) + return 0; + + fp = va_arg(ap, FILE *); + inter_status_tostr(line, sc_data); + fprintf(fp, "%s\n", line); + return 0; +} + +/*========================================== + * Saves all scdata to the given filename. + *------------------------------------------*/ +void inter_status_save() +{ + FILE *fp; + int lock; + + if ((fp = lock_fopen(scdata_txt, &lock)) == NULL) { + ShowError("int_status: can't write [%s] !!! data is lost !!!\n", scdata_txt); + return; + } + scdata_db->foreach(scdata_db, inter_status_save_sub, fp); + lock_fclose(fp,scdata_txt, &lock); +} + +/*========================================== + * Initializes db. + *------------------------------------------*/ +void status_init() +{ + scdata_db = idb_alloc(DB_OPT_BASE); + status_load_scdata(scdata_txt); +} + +/*========================================== + * Frees up memory. + *------------------------------------------*/ +static int scdata_db_final(DBKey k,void *d,va_list ap) +{ + struct scdata *data = (struct scdata*)d; + if (data->data) + aFree(data->data); + aFree(data); + return 0; +} + +/*========================================== + * Final cleanup. + *------------------------------------------*/ +void status_final(void) +{ + scdata_db->destroy(scdata_db, scdata_db_final); +} + +#endif //ENABLE_SC_SAVING diff --git a/src/char/int_status.h b/src/char/int_status.h new file mode 100644 index 000000000..3202cd88e --- /dev/null +++ b/src/char/int_status.h @@ -0,0 +1,23 @@ +// Copyright (c) Athena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + +#ifndef _INT_STATUS_H_ +#define _INT_STATUS_H_ + +struct status_change_data; + +struct scdata { + int account_id, char_id; + int count; + struct status_change_data* data; +}; + +extern char scdata_txt[1024]; + +struct scdata* status_search_scdata(int aid, int cid); +void status_delete_scdata(int aid, int cid); +void inter_status_save(void); +void status_init(void); +void status_final(void); + +#endif /* _INT_STATUS_H_ */ diff --git a/src/char/int_storage.c b/src/char/int_storage.c new file mode 100644 index 000000000..5ae51b833 --- /dev/null +++ b/src/char/int_storage.c @@ -0,0 +1,481 @@ +// Copyright (c) Athena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + +#include "../common/mmo.h" +#include "../common/malloc.h" +#include "../common/socket.h" +#include "../common/db.h" +#include "../common/lock.h" +#include "../common/showmsg.h" +#include "../common/utils.h" +#include "char.h" +#include "inter.h" +#include "int_storage.h" +#include "int_pet.h" +#include "int_guild.h" + +#include +#include +#include + +// ファイル名のデフォルト +// inter_config_read()で再設定される +char storage_txt[1024]="save/storage.txt"; +char guild_storage_txt[1024]="save/g_storage.txt"; + +#ifndef TXT_SQL_CONVERT +static DBMap* storage_db; // int account_id -> struct storage* +static DBMap* guild_storage_db; // int guild_id -> struct guild_storage* + +// 倉庫データを文字列に変換 +int storage_tostr(char *str,struct storage *p) +{ + int i,j,f=0; + char *str_p = str; + str_p += sprintf(str_p,"%d,%d\t",p->account_id,p->storage_amount); + + for(i=0;istorage_[i].nameid) && (p->storage_[i].amount) ){ + str_p += sprintf(str_p,"%d,%d,%d,%d,%d,%d,%d", + p->storage_[i].id,p->storage_[i].nameid,p->storage_[i].amount,p->storage_[i].equip, + p->storage_[i].identify,p->storage_[i].refine,p->storage_[i].attribute); + for(j=0; jstorage_[i].card[j]); + str_p += sprintf(str_p," "); + f++; + } + + *(str_p++)='\t'; + + *str_p='\0'; + if(!f) + str[0]=0; + return 0; +} +#endif //TXT_SQL_CONVERT +// 文字列を倉庫データに変換 +int storage_fromstr(char *str,struct storage *p) +{ + int tmp_int[256]; + char tmp_str[256]; + int set,next,len,i,j; + + set=sscanf(str,"%d,%d%n",&tmp_int[0],&tmp_int[1],&next); + p->storage_amount=tmp_int[1]; + + if(set!=2) + return 1; + if(str[next]=='\n' || str[next]=='\r') + return 0; + next++; + for(i=0;str[next] && str[next]!='\t' && i < MAX_STORAGE;i++){ + if(sscanf(str + next, "%d,%d,%d,%d,%d,%d,%d%[0-9,-]%n", + &tmp_int[0], &tmp_int[1], &tmp_int[2], &tmp_int[3], + &tmp_int[4], &tmp_int[5], &tmp_int[6], tmp_str, &len) == 8) { + p->storage_[i].id = tmp_int[0]; + p->storage_[i].nameid = tmp_int[1]; + p->storage_[i].amount = tmp_int[2]; + p->storage_[i].equip = tmp_int[3]; + p->storage_[i].identify = tmp_int[4]; + p->storage_[i].refine = tmp_int[5]; + p->storage_[i].attribute = tmp_int[6]; + + for(j = 0; j < MAX_SLOTS && tmp_str && sscanf(tmp_str, ",%d%[0-9,-]",&tmp_int[0], tmp_str) > 0; j++) + p->storage_[i].card[j] = tmp_int[0]; + + next += len; + if (str[next] == ' ') + next++; + } + else return 1; + } + if (i >= MAX_STORAGE && str[next] && str[next]!='\t') + ShowWarning("storage_fromstr: Found a storage line with more items than MAX_STORAGE (%d), remaining items have been discarded!\n", MAX_STORAGE); + return 0; +} +#ifndef TXT_SQL_CONVERT +int guild_storage_tostr(char *str,struct guild_storage *p) +{ + int i,j,f=0; + char *str_p = str; + str_p+=sprintf(str,"%d,%d\t",p->guild_id,p->storage_amount); + + for(i=0;istorage_[i].nameid) && (p->storage_[i].amount) ){ + str_p += sprintf(str_p,"%d,%d,%d,%d,%d,%d,%d", + p->storage_[i].id,p->storage_[i].nameid,p->storage_[i].amount,p->storage_[i].equip, + p->storage_[i].identify,p->storage_[i].refine,p->storage_[i].attribute); + for(j=0; jstorage_[i].card[j]); + str_p += sprintf(str_p," "); + f++; + } + + *(str_p++)='\t'; + + *str_p='\0'; + if(!f) + str[0]=0; + return 0; +} +#endif //TXT_SQL_CONVERT +int guild_storage_fromstr(char *str,struct guild_storage *p) +{ + int tmp_int[256]; + char tmp_str[256]; + int set,next,len,i,j; + + set=sscanf(str,"%d,%d%n",&tmp_int[0],&tmp_int[1],&next); + p->storage_amount=tmp_int[1]; + + if(set!=2) + return 1; + if(str[next]=='\n' || str[next]=='\r') + return 0; + next++; + for(i=0;str[next] && str[next]!='\t' && i < MAX_GUILD_STORAGE;i++){ + if(sscanf(str + next, "%d,%d,%d,%d,%d,%d,%d%[0-9,-]%n", + &tmp_int[0], &tmp_int[1], &tmp_int[2], &tmp_int[3], + &tmp_int[4], &tmp_int[5], &tmp_int[6], tmp_str, &len) == 8) + { + p->storage_[i].id = tmp_int[0]; + p->storage_[i].nameid = tmp_int[1]; + p->storage_[i].amount = tmp_int[2]; + p->storage_[i].equip = tmp_int[3]; + p->storage_[i].identify = tmp_int[4]; + p->storage_[i].refine = tmp_int[5]; + p->storage_[i].attribute = tmp_int[6]; + for(j = 0; j < MAX_SLOTS && tmp_str && sscanf(tmp_str, ",%d%[0-9,-]",&tmp_int[0], tmp_str) > 0; j++) + p->storage_[i].card[j] = tmp_int[0]; + next += len; + if (str[next] == ' ') + next++; + } + else return 1; + } + if (i >= MAX_GUILD_STORAGE && str[next] && str[next]!='\t') + ShowWarning("guild_storage_fromstr: Found a storage line with more items than MAX_GUILD_STORAGE (%d), remaining items have been discarded!\n", MAX_GUILD_STORAGE); + return 0; +} +#ifndef TXT_SQL_CONVERT +static void* create_storage(DBKey key, va_list args) { + struct storage *s; + s = (struct storage *) aCalloc(sizeof(struct storage), 1); + s->account_id=key.i; + return s; +} + +// アカウントから倉庫データインデックスを得る(新規倉庫追加可能) +struct storage *account2storage(int account_id) +{ + struct storage *s; + s = (struct storage*)idb_ensure(storage_db, account_id, create_storage); + return s; +} + +static void* create_guildstorage(DBKey key, va_list args) { + struct guild_storage *gs = NULL; + gs = (struct guild_storage *) aCalloc(sizeof(struct guild_storage), 1); + gs->guild_id=key.i; + return gs; +} + +struct guild_storage *guild2storage(int guild_id) +{ + struct guild_storage *gs = NULL; + if(inter_guild_search(guild_id) != NULL) + gs = (struct guild_storage*)idb_ensure(guild_storage_db, guild_id, create_guildstorage); + return gs; +} + +//--------------------------------------------------------- +// 倉庫データを読み込む +int inter_storage_init() +{ + char line[65536]; + int c=0,tmp_int; + struct storage *s; + struct guild_storage *gs; + FILE *fp; + + storage_db = idb_alloc(DB_OPT_RELEASE_DATA); + + fp=fopen(storage_txt,"r"); + if(fp==NULL){ + ShowError("can't read : %s\n",storage_txt); + return 1; + } + while(fgets(line, sizeof(line), fp)) + { + sscanf(line,"%d",&tmp_int); + s = (struct storage*)aCalloc(sizeof(struct storage), 1); + if(s==NULL){ + ShowFatalError("int_storage: out of memory!\n"); + exit(EXIT_FAILURE); + } +// memset(s,0,sizeof(struct storage)); aCalloc does this... + s->account_id=tmp_int; + if(s->account_id > 0 && storage_fromstr(line,s) == 0) { + idb_put(storage_db,s->account_id,s); + } + else{ + ShowError("int_storage: broken data [%s] line %d\n",storage_txt,c); + aFree(s); + } + c++; + } + fclose(fp); + + c = 0; + guild_storage_db = idb_alloc(DB_OPT_RELEASE_DATA); + + fp=fopen(guild_storage_txt,"r"); + if(fp==NULL){ + ShowError("can't read : %s\n",guild_storage_txt); + return 1; + } + while(fgets(line, sizeof(line), fp)) + { + sscanf(line,"%d",&tmp_int); + gs = (struct guild_storage*)aCalloc(sizeof(struct guild_storage), 1); + if(gs==NULL){ + ShowFatalError("int_storage: out of memory!\n"); + exit(EXIT_FAILURE); + } +// memset(gs,0,sizeof(struct guild_storage)); aCalloc... + gs->guild_id=tmp_int; + if(gs->guild_id > 0 && guild_storage_fromstr(line,gs) == 0) { + idb_put(guild_storage_db,gs->guild_id,gs); + } + else{ + ShowError("int_storage: broken data [%s] line %d\n",guild_storage_txt,c); + aFree(gs); + } + c++; + } + fclose(fp); + + return 0; +} + +void inter_storage_final() { + storage_db->destroy(storage_db, NULL); + guild_storage_db->destroy(guild_storage_db, NULL); + return; +} + +int inter_storage_save_sub(DBKey key,void *data,va_list ap) +{ + char line[65536]; + FILE *fp; + storage_tostr(line,(struct storage *)data); + fp=va_arg(ap,FILE *); + if(*line) + fprintf(fp,"%s\n",line); + return 0; +} +//--------------------------------------------------------- +// 倉庫データを書き込む +int inter_storage_save() +{ + FILE *fp; + int lock; + if( (fp=lock_fopen(storage_txt,&lock))==NULL ){ + ShowError("int_storage: can't write [%s] !!! data is lost !!!\n",storage_txt); + return 1; + } + storage_db->foreach(storage_db,inter_storage_save_sub,fp); + lock_fclose(fp,storage_txt,&lock); + return 0; +} + +int inter_guild_storage_save_sub(DBKey key,void *data,va_list ap) +{ + char line[65536]; + FILE *fp; + if(inter_guild_search(((struct guild_storage *)data)->guild_id) != NULL) { + guild_storage_tostr(line,(struct guild_storage *)data); + fp=va_arg(ap,FILE *); + if(*line) + fprintf(fp,"%s\n",line); + } + return 0; +} +//--------------------------------------------------------- +// 倉庫データを書き込む +int inter_guild_storage_save() +{ + FILE *fp; + int lock; + if( (fp=lock_fopen(guild_storage_txt,&lock))==NULL ){ + ShowError("int_storage: can't write [%s] !!! data is lost !!!\n",guild_storage_txt); + return 1; + } + guild_storage_db->foreach(guild_storage_db,inter_guild_storage_save_sub,fp); + lock_fclose(fp,guild_storage_txt,&lock); + return 0; +} + +// 倉庫データ削除 +int inter_storage_delete(int account_id) +{ + struct storage *s = (struct storage*)idb_get(storage_db,account_id); + if(s) { + int i; + for(i=0;istorage_amount;i++){ + if(s->storage_[i].card[0] == (short)0xff00) + inter_pet_delete( MakeDWord(s->storage_[i].card[1],s->storage_[i].card[2]) ); + } + idb_remove(storage_db,account_id); + } + return 0; +} + +// ギルド倉庫データ削除 +int inter_guild_storage_delete(int guild_id) +{ + struct guild_storage *gs = (struct guild_storage*)idb_get(guild_storage_db,guild_id); + if(gs) { + int i; + for(i=0;istorage_amount;i++){ + if(gs->storage_[i].card[0] == (short)0xff00) + inter_pet_delete( MakeDWord(gs->storage_[i].card[1],gs->storage_[i].card[2]) ); + } + idb_remove(guild_storage_db,guild_id); + } + return 0; +} + +//--------------------------------------------------------- +// map serverへの通信 + +// 倉庫データの送信 +int mapif_load_storage(int fd,int account_id) +{ + struct storage *s=account2storage(account_id); + WFIFOHEAD(fd, sizeof(struct storage)+8); + WFIFOW(fd,0)=0x3810; + WFIFOW(fd,2)=sizeof(struct storage)+8; + WFIFOL(fd,4)=account_id; + memcpy(WFIFOP(fd,8),s,sizeof(struct storage)); + WFIFOSET(fd,WFIFOW(fd,2)); + return 0; +} +// 倉庫データ保存完了送信 +int mapif_save_storage_ack(int fd,int account_id) +{ + WFIFOHEAD(fd, 7); + WFIFOW(fd,0)=0x3811; + WFIFOL(fd,2)=account_id; + WFIFOB(fd,6)=0; + WFIFOSET(fd,7); + return 0; +} + +int mapif_load_guild_storage(int fd,int account_id,int guild_id) +{ + struct guild_storage *gs=guild2storage(guild_id); + WFIFOHEAD(fd, sizeof(struct guild_storage)+12); + WFIFOW(fd,0)=0x3818; + if(gs) { + WFIFOW(fd,2)=sizeof(struct guild_storage)+12; + WFIFOL(fd,4)=account_id; + WFIFOL(fd,8)=guild_id; + memcpy(WFIFOP(fd,12),gs,sizeof(struct guild_storage)); + } + else { + WFIFOW(fd,2)=12; + WFIFOL(fd,4)=account_id; + WFIFOL(fd,8)=0; + } + WFIFOSET(fd,WFIFOW(fd,2)); + + return 0; +} +int mapif_save_guild_storage_ack(int fd,int account_id,int guild_id,int fail) +{ + WFIFOHEAD(fd, 11); + WFIFOW(fd,0)=0x3819; + WFIFOL(fd,2)=account_id; + WFIFOL(fd,6)=guild_id; + WFIFOB(fd,10)=fail; + WFIFOSET(fd,11); + return 0; +} + +//--------------------------------------------------------- +// map serverからの通信 + +// 倉庫データ要求受信 +int mapif_parse_LoadStorage(int fd) +{ + RFIFOHEAD(fd); + mapif_load_storage(fd,RFIFOL(fd,2)); + return 0; +} +// 倉庫データ受信&保存 +int mapif_parse_SaveStorage(int fd) +{ + struct storage *s; + int account_id, len; + RFIFOHEAD(fd); + account_id=RFIFOL(fd,4); + len=RFIFOW(fd,2); + if(sizeof(struct storage)!=len-8){ + ShowError("inter storage: data size error %d %d\n",sizeof(struct storage),len-8); + } + else { + s=account2storage(account_id); + memcpy(s,RFIFOP(fd,8),sizeof(struct storage)); + mapif_save_storage_ack(fd,account_id); + } + return 0; +} + +int mapif_parse_LoadGuildStorage(int fd) +{ + RFIFOHEAD(fd); + mapif_load_guild_storage(fd,RFIFOL(fd,2),RFIFOL(fd,6)); + return 0; +} +int mapif_parse_SaveGuildStorage(int fd) +{ + struct guild_storage *gs; + int guild_id, len; + RFIFOHEAD(fd); + guild_id=RFIFOL(fd,8); + len=RFIFOW(fd,2); + if(sizeof(struct guild_storage)!=len-12){ + ShowError("inter storage: data size error %d %d\n",sizeof(struct guild_storage),len-12); + } + else { + gs=guild2storage(guild_id); + if(gs) { + memcpy(gs,RFIFOP(fd,12),sizeof(struct guild_storage)); + mapif_save_guild_storage_ack(fd,RFIFOL(fd,4),guild_id,0); + } + else + mapif_save_guild_storage_ack(fd,RFIFOL(fd,4),guild_id,1); + } + return 0; +} + +// map server からの通信 +// ・1パケットのみ解析すること +// ・パケット長データはinter.cにセットしておくこと +// ・パケット長チェックや、RFIFOSKIPは呼び出し元で行われるので行ってはならない +// ・エラーなら0(false)、そうでないなら1(true)をかえさなければならない +int inter_storage_parse_frommap(int fd) +{ + RFIFOHEAD(fd); + switch(RFIFOW(fd,0)){ + case 0x3010: mapif_parse_LoadStorage(fd); break; + case 0x3011: mapif_parse_SaveStorage(fd); break; + case 0x3018: mapif_parse_LoadGuildStorage(fd); break; + case 0x3019: mapif_parse_SaveGuildStorage(fd); break; + default: + return 0; + } + return 1; +} +#endif //TXT_SQL_CONVERT diff --git a/src/char/int_storage.h b/src/char/int_storage.h new file mode 100644 index 000000000..dbc487c4c --- /dev/null +++ b/src/char/int_storage.h @@ -0,0 +1,25 @@ +// Copyright (c) Athena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + +#ifndef _INT_STORAGE_H_ +#define _INT_STORAGE_H_ + +struct storage; +struct guild_storage; + +int inter_storage_init(void); +void inter_storage_final(void); +int inter_storage_save(void); +int inter_guild_storage_save(void); +int inter_storage_delete(int account_id); +int inter_guild_storage_delete(int guild_id); +int inter_storage_parse_frommap(int fd); + +extern char storage_txt[1024]; +extern char guild_storage_txt[1024]; + +//Exported for use in the TXT-SQL converter. +int storage_fromstr(char *str,struct storage *p); +int guild_storage_fromstr(char *str,struct guild_storage *p); + +#endif /* _INT_STORAGE_H_ */ diff --git a/src/char/inter.c b/src/char/inter.c new file mode 100644 index 000000000..c987ce8f2 --- /dev/null +++ b/src/char/inter.c @@ -0,0 +1,711 @@ +// Copyright (c) Athena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + +#include "../common/db.h" +#include "../common/mmo.h" +#include "../common/socket.h" +#include "../common/timer.h" +#include "../common/malloc.h" +#include "../common/lock.h" +#include "../common/showmsg.h" +#include "../common/strlib.h" +#include "char.h" +#include "inter.h" +#include "int_party.h" +#include "int_guild.h" +#include "int_status.h" +#include "int_storage.h" +#include "int_pet.h" +#include "int_homun.h" + +#include +#include +#include + +#define WISDATA_TTL (60*1000) // Existence time of Wisp/page data (60 seconds) + // that is the waiting time of answers of all map-servers +#define WISDELLIST_MAX 256 // Number of elements of Wisp/page data deletion list + +char accreg_txt[1024] = "save/accreg.txt"; +#ifndef TXT_SQL_CONVERT +char inter_log_filename[1024] = "log/inter.log"; +char main_chat_nick[16] = "Main"; + +static DBMap* accreg_db = NULL; // int account_id -> struct accreg* + +unsigned int party_share_level = 10; + +// sending packet list +// NOTE: This variable ain't used at all! And it's confusing.. where do I add that the length of packet 0x2b07 is 10? x.x [Skotlex] +int inter_send_packet_length[]={ + -1,-1,27,-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3000-0x300f + -1, 7, 0, 0, 0, 0, 0, 0, -1,11, 0, 0, 0, 0, 0, 0, + 35,-1,11,15, 34,29, 7,-1, 0, 0, 0, 0, 0, 0, 0, 0, + 10,-1,15, 0, 79,19, 7,-1, 0,-1,-1,-1, 14,67,186,-1, + 9, 9,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 11,-1, 7, 3, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; +// recv. packet list +int inter_recv_packet_length[]={ + -1,-1, 7,-1, -1,13,36, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3000-0x300f + 6,-1, 0, 0, 0, 0, 0, 0, 10,-1, 0, 0, 0, 0, 0, 0, //0x3010-0x301f + -1, 6,-1,14, 14,19, 6,-1, 14,14, 0, 0, 0, 0, 0, 0, //0x3020-0x302f + -1, 6,-1,-1, 55,19, 6,-1, 14,-1,-1,-1, 14,19,186,-1, //0x3030-0x303f + 5, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3040-0x304f + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3050-0x305f + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3060-0x306f + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3070-0x307f + 48,14,-1, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3080-0x308f + -1,10,-1, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3090-0x309f Homunculus packets [albator] +}; + +struct WisData { + int id, fd, count, len; + unsigned long tick; + unsigned char src[24], dst[24], msg[1024]; +}; +static DBMap* wis_db = NULL; // int wis_id -> struct WisData* +static int wis_dellist[WISDELLIST_MAX], wis_delnum; + + +//-------------------------------------------------------- + +// アカウント変数を文字列へ変換 +int inter_accreg_tostr(char *str, struct accreg *reg) { + int j; + char *p = str; + + p += sprintf(p, "%d\t", reg->account_id); + for(j = 0; j < reg->reg_num; j++) { + p += sprintf(p,"%s,%s ", reg->reg[j].str, reg->reg[j].value); + } + + return 0; +} +#endif //TXT_SQL_CONVERT +// アカウント変数を文字列から変換 +int inter_accreg_fromstr(const char *str, struct accreg *reg) { + int j, n; + const char *p = str; + + if (sscanf(p, "%d\t%n", ®->account_id, &n ) != 1 || reg->account_id <= 0) + return 1; + + for(j = 0, p += n; j < ACCOUNT_REG_NUM; j++, p += n) { + if (sscanf(p, "%[^,],%[^ ] %n", reg->reg[j].str, reg->reg[j].value, &n) != 2) + break; + } + reg->reg_num = j; + + return 0; +} +#ifndef TXT_SQL_CONVERT +// アカウント変数の読み込み +int inter_accreg_init(void) { + char line[8192]; + FILE *fp; + int c = 0; + struct accreg *reg; + + accreg_db = idb_alloc(DB_OPT_RELEASE_DATA); + + if( (fp = fopen(accreg_txt, "r")) == NULL) + return 1; + while(fgets(line, sizeof(line), fp)) + { + reg = (struct accreg*)aCalloc(sizeof(struct accreg), 1); + if (reg == NULL) { + ShowFatalError("inter: accreg: out of memory!\n"); + exit(EXIT_FAILURE); + } + if (inter_accreg_fromstr(line, reg) == 0 && reg->account_id > 0) { + idb_put(accreg_db, reg->account_id, reg); + } else { + ShowError("inter: accreg: broken data [%s] line %d\n", accreg_txt, c); + aFree(reg); + } + c++; + } + fclose(fp); + + return 0; +} + +// アカウント変数のセーブ用 +int inter_accreg_save_sub(DBKey key, void *data, va_list ap) { + char line[8192]; + FILE *fp; + struct accreg *reg = (struct accreg *)data; + + if (reg->reg_num > 0) { + inter_accreg_tostr(line,reg); + fp = va_arg(ap, FILE *); + fprintf(fp, "%s\n", line); + } + + return 0; +} + +// アカウント変数のセーブ +int inter_accreg_save(void) { + FILE *fp; + int lock; + + if ((fp = lock_fopen(accreg_txt,&lock)) == NULL) { + ShowError("int_accreg: can't write [%s] !!! data is lost !!!\n", accreg_txt); + return 1; + } + accreg_db->foreach(accreg_db, inter_accreg_save_sub,fp); + lock_fclose(fp, accreg_txt, &lock); + + return 0; +} + +//-------------------------------------------------------- +#endif //TXT_SQL_CONVERT +/*========================================== + * 設定ファイルを読み込む + *------------------------------------------*/ +static int inter_config_read(const char *cfgName) { + char line[1024], w1[1024], w2[1024]; + FILE *fp; + + fp = fopen(cfgName, "r"); + if (fp == NULL) { + ShowError("file not found: %s\n", cfgName); + return 1; + } + while(fgets(line, sizeof(line), fp)) + { + if (line[0] == '/' && line[1] == '/') + continue; + + if (sscanf(line,"%[^:]: %[^\r\n]", w1, w2) != 2) + continue; + + if (strcmpi(w1, "storage_txt") == 0) { + strncpy(storage_txt, w2, sizeof(storage_txt)); + } else if (strcmpi(w1, "party_txt") == 0) { + strncpy(party_txt, w2, sizeof(party_txt)); + } else if (strcmpi(w1, "pet_txt") == 0) { + strncpy(pet_txt, w2, sizeof(pet_txt)); + } else if (strcmpi(w1, "accreg_txt") == 0) { + strncpy(accreg_txt, w2, sizeof(accreg_txt)); + } else if (strcmpi(w1, "guild_txt") == 0) { + strncpy(guild_txt, w2, sizeof(guild_txt)); + } else if (strcmpi(w1, "castle_txt") == 0) { + strncpy(castle_txt, w2, sizeof(castle_txt)); + } else if (strcmpi(w1, "guild_storage_txt") == 0) { + strncpy(guild_storage_txt, w2, sizeof(guild_storage_txt)); +#ifndef TXT_SQL_CONVERT + } else if (strcmpi(w1, "homun_txt") == 0) { + strncpy(homun_txt, w2, sizeof(homun_txt)); + } else if (strcmpi(w1, "party_share_level") == 0) { + party_share_level = (unsigned int)atof(w2); + } else if (strcmpi(w1, "inter_log_filename") == 0) { + strncpy(inter_log_filename, w2, sizeof(inter_log_filename)); + } else if(strcmpi(w1,"log_inter")==0) { + log_inter = atoi(w2); + } else if(strcmpi(w1, "main_chat_nick")==0){ // Main chat nick [LuzZza] + strcpy(main_chat_nick, w2); +#endif //TXT_SQL_CONVERT + } else if (strcmpi(w1, "import") == 0) { + inter_config_read(w2); + } + } + fclose(fp); + + return 0; +} +#ifndef TXT_SQL_CONVERT +// ログ書き出し +int inter_log(char *fmt,...) { + FILE *logfp; + va_list ap; + + va_start(ap,fmt); + logfp = fopen(inter_log_filename, "a"); + if (logfp) { + vfprintf(logfp, fmt, ap); + fclose(logfp); + } + va_end(ap); + + return 0; +} + +// セーブ +int inter_save(void) { +#ifdef ENABLE_SC_SAVING + inter_status_save(); +#endif + inter_party_save(); + inter_guild_save(); + inter_storage_save(); + inter_guild_storage_save(); + inter_pet_save(); + inter_homun_save(); + inter_accreg_save(); + + return 0; +} +#endif //TXT_SQL_CONVERT +// 初期化 +int inter_init_txt(const char *file) { + inter_config_read(file); + +#ifndef TXT_SQL_CONVERT + wis_db = idb_alloc(DB_OPT_RELEASE_DATA); + + inter_party_init(); + inter_guild_init(); + inter_storage_init(); + inter_pet_init(); + inter_homun_init(); + inter_accreg_init(); +#endif //TXT_SQL_CONVERT + return 0; +} +#ifndef TXT_SQL_CONVERT +// finalize +void inter_final(void) { + accreg_db->destroy(accreg_db, NULL); + wis_db->destroy(wis_db, NULL); + + inter_party_final(); + inter_guild_final(); + inter_storage_final(); + inter_pet_final(); + inter_homun_final(); + + return; +} + +// マップサーバー接続 +int inter_mapif_init(int fd) { + inter_guild_mapif_init(fd); + + return 0; +} + +//-------------------------------------------------------- +// sended packets to map-server + +// GMメッセージ送信 +int mapif_GMmessage(unsigned char *mes, int len, unsigned long color, int sfd) { + unsigned char buf[2048]; + + if (len > 2048) len = 2047; //Make it fit to avoid crashes. [Skotlex] + WBUFW(buf,0) = 0x3800; + WBUFW(buf,2) = len; + WBUFL(buf,4) = color; + memcpy(WBUFP(buf,8), mes, len - 8); + mapif_sendallwos(sfd, buf, len); + + return 0; +} + +// Wisp/page transmission to one map-server +int mapif_wis_message2(struct WisData *wd, int fd) { + WFIFOHEAD(fd, 56+wd->len); + WFIFOW(fd, 0) = 0x3801; + WFIFOW(fd, 2) = 56 + wd->len; + WFIFOL(fd, 4) = wd->id; + memcpy(WFIFOP(fd, 8), wd->src, NAME_LENGTH); + memcpy(WFIFOP(fd,32), wd->dst, NAME_LENGTH); + memcpy(WFIFOP(fd,56), wd->msg, wd->len); + wd->count = 1; + WFIFOSET(fd,WFIFOW(fd,2)); + return 1; +} + +// Wisp/page transmission to all map-server +int mapif_wis_message(struct WisData *wd) { + unsigned char buf[2048]; + if (wd->len > 2047-56) wd->len = 2047-56; //Force it to fit to avoid crashes. [Skotlex] + + WBUFW(buf, 0) = 0x3801; + WBUFW(buf, 2) = 56 + wd->len; + WBUFL(buf, 4) = wd->id; + memcpy(WBUFP(buf, 8), wd->src, NAME_LENGTH); + memcpy(WBUFP(buf,32), wd->dst, NAME_LENGTH); + memcpy(WBUFP(buf,56), wd->msg, wd->len); + wd->count = mapif_sendall(buf, WBUFW(buf,2)); + + return 0; +} + +int mapif_wis_fail(int fd, char *src) { + unsigned char buf[27]; + WBUFW(buf, 0) = 0x3802; + memcpy(WBUFP(buf, 2), src, NAME_LENGTH); + WBUFB(buf,26) = 1; // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target + mapif_send(fd, buf, 27); + return 0; + +} + +// Wisp/page transmission result to map-server +int mapif_wis_end(struct WisData *wd, int flag) +{ + unsigned char buf[27]; + + WBUFW(buf, 0) = 0x3802; + memcpy(WBUFP(buf, 2), wd->src, 24); + WBUFB(buf,26) = flag; // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target + mapif_send(wd->fd, buf, 27); + + return 0; +} + +// Account registry transfer to map-server +static void mapif_account_reg(int fd, unsigned char *src) +{ + WBUFW(src,0)=0x3804; //NOTE: writing to RFIFO + mapif_sendallwos(fd, src, WBUFW(src,2)); +} + +// アカウント変数要求返信 +int mapif_account_reg_reply(int fd,int account_id, int char_id) +{ + struct accreg *reg = (struct accreg*)idb_get(accreg_db,account_id); + + WFIFOHEAD(fd, ACCOUNT_REG_NUM * 288+ 13); + WFIFOW(fd,0) = 0x3804; + WFIFOL(fd,4) = account_id; + WFIFOL(fd,8) = char_id; + WFIFOB(fd,12) = 2; //Acc Reg + if (reg == NULL) { + WFIFOW(fd,2) = 13; + } else { + int i, p; + for (p=13,i = 0; i < reg->reg_num; i++) { + p+= sprintf((char*)WFIFOP(fd,p), "%s", reg->reg[i].str)+1; //We add 1 to consider the '\0' in place. + p+= sprintf((char*)WFIFOP(fd,p), "%s", reg->reg[i].value)+1; + } + WFIFOW(fd,2)=p; + } + WFIFOSET(fd,WFIFOW(fd,2)); + return 0; +} + +//Request to kick char from a certain map server. [Skotlex] +int mapif_disconnectplayer(int fd, int account_id, int char_id, int reason) +{ + if (fd < 0) + return -1; + + WFIFOHEAD(fd, 7); + WFIFOW(fd,0) = 0x2b1f; + WFIFOL(fd,2) = account_id; + WFIFOB(fd,6) = reason; + WFIFOSET(fd,7); + + return 0; +} + +//-------------------------------------------------------- + +// Existence check of WISP data +int check_ttl_wisdata_sub(DBKey key, void *data, va_list ap) { + unsigned long tick; + struct WisData *wd = (struct WisData *)data; + tick = va_arg(ap, unsigned long); + + if (DIFF_TICK(tick, wd->tick) > WISDATA_TTL && wis_delnum < WISDELLIST_MAX) + wis_dellist[wis_delnum++] = wd->id; + + return 0; +} + +int check_ttl_wisdata(void) { + unsigned long tick = gettick(); + int i; + + do { + wis_delnum = 0; + wis_db->foreach(wis_db, check_ttl_wisdata_sub, tick); + for(i = 0; i < wis_delnum; i++) { + struct WisData *wd = (struct WisData*)idb_get(wis_db, wis_dellist[i]); + ShowWarning("inter: wis data id=%d time out : from %s to %s\n", wd->id, wd->src, wd->dst); + // removed. not send information after a timeout. Just no answer for the player + //mapif_wis_end(wd, 1); // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target + idb_remove(wis_db, wd->id); + } + } while(wis_delnum >= WISDELLIST_MAX); + + return 0; +} + +//-------------------------------------------------------- +// received packets from map-server + +// GMメッセージ送信 +int mapif_parse_GMmessage(int fd) { + RFIFOHEAD(fd); + mapif_GMmessage(RFIFOP(fd,8), RFIFOW(fd,2), RFIFOL(fd,4), fd); + + return 0; +} + +static struct WisData* mapif_create_whisper(int fd, char* src, char* dst, char* mes, int meslen) +{ + static int wisid = 0; + struct WisData* wd = (struct WisData *)aCalloc(sizeof(struct WisData), 1); + if (wd == NULL){ + ShowFatalError("inter: WisRequest: out of memory !\n"); + return NULL; + } + wd->id = ++wisid; + wd->fd = fd; + wd->len= meslen; + memcpy(wd->src, src, NAME_LENGTH); + memcpy(wd->dst, dst, NAME_LENGTH); + memcpy(wd->msg, mes, meslen); + wd->tick = gettick(); + return wd; +} + +// Wisp/page request to send +int mapif_parse_WisRequest(int fd) +{ + struct mmo_charstatus* char_status; + struct WisData* wd; + char name[NAME_LENGTH]; + int fd2; + + if (RFIFOW(fd,2)-52 >= sizeof(wd->msg)) { + ShowWarning("inter: Wis message size too long.\n"); + return 0; + } else if (RFIFOW(fd,2)-52 <= 0) { // normaly, impossible, but who knows... + ShowError("inter: Wis message doesn't exist.\n"); + return 0; + } + + safestrncpy(name, (char*)RFIFOP(fd,28), NAME_LENGTH); //Received name may be too large and not contain \0! [Skotlex] + + // search if character exists before to ask all map-servers + char_status = search_character_byname(name); + if (char_status == NULL) + return mapif_wis_fail(fd, (char*)RFIFOP(fd, 4)); + + // Character exists. + // to be sure of the correct name, rewrite it + memset(name, 0, NAME_LENGTH); + strncpy(name, char_status->name, NAME_LENGTH); + // if source is destination, don't ask other servers. + if (strcmp((char*)RFIFOP(fd,4),name) == 0) + return mapif_wis_fail(fd, (char*)RFIFOP(fd, 4)); + + //Look for online character. + fd2 = search_character_online(char_status->account_id, char_status->char_id); + if (fd2 >= 0) { //Character online, send whisper. + wd = mapif_create_whisper(fd, (char*)RFIFOP(fd, 4), (char*)RFIFOP(fd,28), (char*)RFIFOP(fd,52), RFIFOW(fd,2)-52); + if (!wd) return 1; + idb_put(wis_db, wd->id, wd); + mapif_wis_message2(wd, fd2); + return 0; + } + //Not found. + return mapif_wis_fail(fd, (char*)RFIFOP(fd,4)); +} + +// Wisp/page transmission result +int mapif_parse_WisReply(int fd) { + int id, flag; + struct WisData *wd; + RFIFOHEAD(fd); + id = RFIFOL(fd,2); + flag = RFIFOB(fd,6); + wd = (struct WisData*)idb_get(wis_db, id); + + if (wd == NULL) + return 0; // This wisp was probably suppress before, because it was timeout or because of target was found on another map-server + + if ((--wd->count) <= 0 || flag != 1) { + mapif_wis_end(wd, flag); // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target + idb_remove(wis_db, id); + } + + return 0; +} + +// Received wisp message from map-server for ALL gm (just copy the message and resends it to ALL map-servers) +int mapif_parse_WisToGM(int fd) { + unsigned char buf[2048]; // 0x3003/0x3803 .w .24B .w .?B + + ShowDebug("Sent packet back!\n"); + memcpy(WBUFP(buf,0), RFIFOP(fd,0), RFIFOW(fd,2)); + WBUFW(buf, 0) = 0x3803; + mapif_sendall(buf, RFIFOW(fd,2)); + + return 0; +} + +static void* create_accreg(DBKey key, va_list args) { + struct accreg *reg; + reg = (struct accreg*)aCalloc(sizeof(struct accreg), 1); + reg->account_id = key.i; + return reg; +} + +// アカウント変数保存要求 +int mapif_parse_Registry(int fd) { + int j, p, len; + struct accreg *reg; + RFIFOHEAD(fd); + + switch (RFIFOB(fd,12)) { + case 3: //Character registry + return char_parse_Registry(RFIFOL(fd,4), RFIFOL(fd,8), RFIFOP(fd,13), RFIFOW(fd,2)-13); + case 2: //Acc Reg + break; + case 1: //Acc Reg2, forward to login + return save_accreg2(RFIFOP(fd,4), RFIFOW(fd,2)-4); + default: //Error? + return 1; + } + reg = (struct accreg*)idb_ensure(accreg_db, RFIFOL(fd,4), create_accreg); + + for(j=0,p=13;jreg[j].str,&len); + reg->reg[j].str[len]='\0'; + p +=len+1; //+1 to skip the '\0' between strings. + sscanf((char*)RFIFOP(fd,p), "%255c%n",reg->reg[j].value,&len); + reg->reg[j].value[len]='\0'; + p +=len+1; + } + reg->reg_num=j; + mapif_account_reg(fd, RFIFOP(fd,0)); // 他のMAPサーバーに送信 + + return 0; +} + +// Request the value of all registries. +int mapif_parse_RegistryRequest(int fd) +{ + RFIFOHEAD(fd); + //Load Char Registry + if (RFIFOB(fd,12)) + char_account_reg_reply(fd,RFIFOL(fd,2),RFIFOL(fd,6)); + //Load Account Registry + if (RFIFOB(fd,11)) + mapif_account_reg_reply(fd,RFIFOL(fd,2),RFIFOL(fd,6)); + //Ask Login Server for Account2 values. + if (RFIFOB(fd,10)) + request_accreg2(RFIFOL(fd,2),RFIFOL(fd,6)); + return 1; +} + +static void mapif_namechange_ack(int fd, int account_id, int char_id, int type, int flag, char *name){ + WFIFOHEAD(fd, NAME_LENGTH+13); + WFIFOW(fd, 0) =0x3806; + WFIFOL(fd, 2) =account_id; + WFIFOL(fd, 6) =char_id; + WFIFOB(fd,10) =type; + WFIFOB(fd,11) =flag; + memcpy(WFIFOP(fd, 12), name, NAME_LENGTH); + WFIFOSET(fd, NAME_LENGTH+13); +} + +int mapif_parse_NameChangeRequest(int fd) +{ + int account_id, char_id, type; + char* name; + int i; + + RFIFOHEAD(fd); + account_id = RFIFOL(fd, 2); + char_id = RFIFOL(fd, 6); + type = RFIFOB(fd, 10); + name = (char*)RFIFOP(fd, 11); + + // Check Authorised letters/symbols in the name + if (char_name_option == 1) { // only letters/symbols in char_name_letters are authorised + for (i = 0; i < NAME_LENGTH && name[i]; i++) + if (strchr(char_name_letters, name[i]) == NULL) { + mapif_namechange_ack(fd, account_id, char_id, type, 0, name); + return 0; + } + } else if (char_name_option == 2) { // letters/symbols in char_name_letters are forbidden + for (i = 0; i < NAME_LENGTH && name[i]; i++) + if (strchr(char_name_letters, name[i]) != NULL) { + mapif_namechange_ack(fd, account_id, char_id, type, 0, name); + return 0; + } + } + //TODO: type holds the type of object to rename. + //If it were a player, it needs to have the guild information and db information + //updated here, because changing it on the map won't make it be saved [Skotlex] + + //name allowed. + mapif_namechange_ack(fd, account_id, char_id, type, 1, name); + return 0; +} + +//-------------------------------------------------------- + +// map server からの通信(1パケットのみ解析すること) +// エラーなら0(false)、処理できたなら1、 +// パケット長が足りなければ2をかえさなければならない +int inter_parse_frommap(int fd) { + int cmd, len; + RFIFOHEAD(fd); + cmd = RFIFOW(fd,0); + len = 0; + + // inter鯖管轄かを調べる + if (cmd < 0x3000 || cmd >= 0x3000 + ARRAYLENGTH(inter_recv_packet_length)) + return 0; + + if (inter_recv_packet_length[cmd-0x3000] == 0) //This is necessary, because otherwise we return 2 and the char server will just hang waiting for packets! [Skotlex] + return 0; + + // パケット長を調べる + if ((len = inter_check_length(fd, inter_recv_packet_length[cmd - 0x3000])) == 0) + return 2; + + switch(cmd) { + case 0x3000: mapif_parse_GMmessage(fd); break; + case 0x3001: mapif_parse_WisRequest(fd); break; + case 0x3002: mapif_parse_WisReply(fd); break; + case 0x3003: mapif_parse_WisToGM(fd); break; + case 0x3004: mapif_parse_Registry(fd); break; + case 0x3005: mapif_parse_RegistryRequest(fd); break; + case 0x3006: mapif_parse_NameChangeRequest(fd); break; + default: + if (inter_party_parse_frommap(fd)) + break; + if (inter_guild_parse_frommap(fd)) + break; + if (inter_storage_parse_frommap(fd)) + break; + if (inter_pet_parse_frommap(fd)) + break; + if (inter_homun_parse_frommap(fd)) + break; + return 0; + } + RFIFOSKIP(fd, len); + return 1; +} + +// RFIFOのパケット長確認 +// 必要パケット長があればパケット長、まだ足りなければ0 +int inter_check_length(int fd, int length) { + if (length == -1) { // 可変パケット長 + RFIFOHEAD(fd); + if (RFIFOREST(fd) < 4) // パケット長が未着 + return 0; + length = RFIFOW(fd,2); + } + + if ((int)RFIFOREST(fd) < length) // パケットが未着 + return 0; + + return length; +} +#endif //TXT_SQL_CONVERT diff --git a/src/char/inter.h b/src/char/inter.h new file mode 100644 index 000000000..4752f600c --- /dev/null +++ b/src/char/inter.h @@ -0,0 +1,30 @@ +// Copyright (c) Athena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + +#ifndef _INTER_H_ +#define _INTER_H_ + +struct accreg; + +int inter_init_txt(const char *file); +void inter_final(void); +int inter_save(void); +int inter_parse_frommap(int fd); +int inter_mapif_init(int fd); +int mapif_disconnectplayer(int fd, int account_id, int char_id, int reason); + +int inter_check_length(int fd,int length); + +int inter_log(char *fmt,...); + +#define inter_cfgName "conf/inter_athena.conf" + +extern unsigned int party_share_level; +extern char inter_log_filename[1024]; +extern char main_chat_nick[16]; + +//For TXT->SQL conversion +extern char accreg_txt[]; +int inter_accreg_fromstr(const char *str, struct accreg *reg); + +#endif /* _INTER_H_ */ diff --git a/src/login/Makefile.in b/src/login/Makefile.in new file mode 100644 index 000000000..b87bd9e70 --- /dev/null +++ b/src/login/Makefile.in @@ -0,0 +1,46 @@ + +COMMON_OBJ = ../common/obj_all/core.o ../common/obj_all/socket.o ../common/obj_all/timer.o \ + ../common/obj_all/db.o ../common/obj_all/plugins.o ../common/obj_all/lock.o \ + ../common/obj_all/malloc.o ../common/obj_all/showmsg.o ../common/obj_all/utils.o \ + ../common/obj_all/strlib.o ../common/obj_all/grfio.o ../common/obj_all/mapindex.o \ + ../common/obj_all/ers.o ../common/obj_all/md5calc.o +COMMON_H = ../common/core.h ../common/socket.h ../common/timer.h ../common/mmo.h \ + ../common/version.h ../common/db.h ../common/plugins.h ../common/lock.h \ + ../common/malloc.h ../common/showmsg.h ../common/utils.h ../common/strlib.h \ + ../common/grfio.h ../common/mapindex.h \ + ../common/ers.h ../common/md5calc.h + +LOGIN_OBJ = obj_txt/login.o obj_txt/admin.o +LOGIN_H = login.h + +@SET_MAKE@ + +##################################################################### +.PHONY : all login-server clean help + +all: login-server + +login-server: obj_txt $(LOGIN_OBJ) $(COMMON_OBJ) + @CC@ @LDFLAGS@ -o ../../login-server@EXEEXT@ $(LOGIN_OBJ) $(COMMON_OBJ) @LIBS@ + +clean: + rm -rf *.o obj_txt ../../login-server@EXEEXT@ + +help: + @echo "possible targets are 'login-server' 'all' 'clean' 'help'" + @echo "'login-server' - login server (TXT version)" + @echo "'all' - builds all above targets" + @echo "'clean' - cleans builds and objects" + @echo "'help' - outputs this message" + +##################################################################### + +obj_txt: + -mkdir obj_txt + +obj_txt/%.o: %.c $(LOGIN_H) $(COMMON_H) + @CC@ @CFLAGS@ $(CUSTOM_CFLAGS) -DTXT_ONLY @CPPFLAGS@ -c $(OUTPUT_OPTION) $< + +# missing common object files +../common/obj_all/%.o: + @$(MAKE) -C ../common sql diff --git a/src/login/admin.c b/src/login/admin.c new file mode 100644 index 000000000..9bce1a02f --- /dev/null +++ b/src/login/admin.c @@ -0,0 +1,879 @@ +#include "../common/cbasetypes.h" +#include "../common/mmo.h" +#include "../common/core.h" +#include "../common/socket.h" +#include "../common/db.h" +#include "../common/timer.h" +#include "../common/malloc.h" +#include "../common/strlib.h" +#include "../common/showmsg.h" +#include "../common/version.h" +#include "../common/md5calc.h" +#include "../common/lock.h" +#include "login.h" + +#include +#include +#include +#include // for stat/lstat/fstat + +extern struct Login_Config login_config; + +#define MAX_SERVERS 30 +extern struct mmo_char_server server[MAX_SERVERS]; +extern struct mmo_account* auth_dat; +extern uint32 auth_num; +extern int account_id_count; +extern char GM_account_filename[1024]; + +int charif_sendallwos(int sfd, unsigned char *buf, unsigned int len); +int search_account_index(char* account_name); +int mmo_auth_new(struct mmo_account* account); +void mmo_auth_sync(void); +int mmo_auth_tostr(char* str, struct mmo_account* p); +int read_gm_account(void); +void send_GM_accounts(int fd); +int isGM(int account_id); + +//--------------------------------------- +// Packet parsing for administation login +//--------------------------------------- +int parse_admin(int fd) +{ + unsigned int i, j; + char* account_name; + + uint32 ipl = session[fd]->client_addr; + char ip[16]; + ip2str(ipl, ip); + + if( session[fd]->flag.eof ) + { + do_close(fd); + ShowInfo("Remote administration has disconnected (session #%d).\n", fd); + return 0; + } + + while( RFIFOREST(fd) >= 2 ) + { + uint16 command = RFIFOW(fd,0); + + switch( command ) + { + + case 0x7530: // Request of the server version + ShowStatus("'ladmin': Sending of the server version (ip: %s)\n", ip); + WFIFOHEAD(fd,10); + WFIFOW(fd,0) = 0x7531; + WFIFOB(fd,2) = ATHENA_MAJOR_VERSION; + WFIFOB(fd,3) = ATHENA_MINOR_VERSION; + WFIFOB(fd,4) = ATHENA_REVISION; + WFIFOB(fd,5) = ATHENA_RELEASE_FLAG; + WFIFOB(fd,6) = ATHENA_OFFICIAL_FLAG; + WFIFOB(fd,7) = ATHENA_SERVER_LOGIN; + WFIFOW(fd,8) = ATHENA_MOD_VERSION; + WFIFOSET(fd,10); + RFIFOSKIP(fd,2); + break; + + case 0x7920: // Request of an accounts list + if (RFIFOREST(fd) < 10) + return 0; + { + int st, ed; + uint16 len; + CREATE_BUFFER(id, int, auth_num); + st = RFIFOL(fd,2); + ed = RFIFOL(fd,6); + RFIFOSKIP(fd,10); + WFIFOW(fd,0) = 0x7921; + if (st < 0) + st = 0; + if (ed > END_ACCOUNT_NUM || ed < st || ed <= 0) + ed = END_ACCOUNT_NUM; + ShowStatus("'ladmin': Sending an accounts list (ask: from %d to %d, ip: %s)\n", st, ed, ip); + // Sort before send + for(i = 0; i < auth_num; i++) { + unsigned int k; + id[i] = i; + for(j = 0; j < i; j++) { + if (auth_dat[id[i]].account_id < auth_dat[id[j]].account_id) { + for(k = i; k > j; k--) { + id[k] = id[k-1]; + } + id[j] = i; // id[i] + break; + } + } + } + // Sending accounts information + len = 4; + for(i = 0; i < auth_num && len < 30000; i++) { + int account_id = auth_dat[id[i]].account_id; // use sorted index + if (account_id >= st && account_id <= ed) { + j = id[i]; + WFIFOL(fd,len) = account_id; + WFIFOB(fd,len+4) = (unsigned char)isGM(account_id); + memcpy(WFIFOP(fd,len+5), auth_dat[j].userid, 24); + WFIFOB(fd,len+29) = auth_dat[j].sex; + WFIFOL(fd,len+30) = auth_dat[j].logincount; + if (auth_dat[j].state == 0 && auth_dat[j].unban_time != 0) // if no state and banished + WFIFOL(fd,len+34) = 7; // 6 = Your are Prohibited to log in until %s + else + WFIFOL(fd,len+34) = auth_dat[j].state; + len += 38; + } + } + WFIFOW(fd,2) = len; + WFIFOSET(fd,len); + //if (id) free(id); + DELETE_BUFFER(id); + } + break; + + case 0x7930: // Request for an account creation + if (RFIFOREST(fd) < 91) + return 0; + { + struct mmo_account ma; + safestrncpy(ma.userid, (char*)RFIFOP(fd, 2), NAME_LENGTH); + safestrncpy(ma.pass, (char*)RFIFOP(fd,26), NAME_LENGTH); + safestrncpy(ma.email, (char*)RFIFOP(fd,51), 40); + memcpy(ma.lastlogin, "-", 2); + ma.sex = RFIFOB(fd,50); + RFIFOSKIP(fd,91); + + WFIFOW(fd,0) = 0x7931; + WFIFOL(fd,2) = 0xffffffff; // invalid account id + safestrncpy((char*)WFIFOP(fd,6), ma.userid, 24); + if (strlen(ma.userid) < 4 || strlen(ma.pass) < 4) { + ShowNotice("'ladmin': Attempt to create an invalid account (account or pass is too short, ip: %s)\n", ip); + } else if (ma.sex != 'F' && ma.sex != 'M') { + ShowNotice("'ladmin': Attempt to create an invalid account (account: %s, received pass: %s, invalid sex, ip: %s)\n", ma.userid, ma.pass, ip); + } else if (account_id_count > END_ACCOUNT_NUM) { + ShowNotice("'ladmin': Attempt to create an account, but there is no more available id number (account: %s, pass: %s, sex: %c, ip: %s)\n", ma.userid, ma.pass, ma.sex, ip); + } else { + remove_control_chars(ma.userid); + remove_control_chars(ma.pass); + remove_control_chars(ma.email); + ARR_FIND( 0, auth_num, i, strncmp(auth_dat[i].userid, ma.userid, 24) == 0 ); + if( i < auth_num ) + ShowNotice("'ladmin': Attempt to create an already existing account (account: %s, pass: %s, received pass: %s, ip: %s)\n", auth_dat[i].userid, auth_dat[i].pass, ma.pass, ip); + else + { + int new_id; + new_id = mmo_auth_new(&ma); + ShowNotice("'ladmin': Account creation (account: %s (id: %d), pass: %s, sex: %c, email: %s, ip: %s)\n", ma.userid, new_id, ma.pass, ma.sex, auth_dat[i].email, ip); + WFIFOL(fd,2) = new_id; + mmo_auth_sync(); + } + } + WFIFOSET(fd,30); + } + break; + + case 0x7932: // Request for an account deletion + if (RFIFOREST(fd) < 26) + return 0; + WFIFOW(fd,0) = 0x7933; + WFIFOL(fd,2) = 0xFFFFFFFF; + account_name = (char*)RFIFOP(fd,2); + account_name[23] = '\0'; + remove_control_chars(account_name); + i = search_account_index(account_name); + if (i != -1) { + // Char-server is notified of deletion (for characters deletion). + unsigned char buf[65535]; + WBUFW(buf,0) = 0x2730; + WBUFL(buf,2) = auth_dat[i].account_id; + charif_sendallwos(-1, buf, 6); + // send answer + memcpy(WFIFOP(fd,6), auth_dat[i].userid, 24); + WFIFOL(fd,2) = auth_dat[i].account_id; + // save deleted account in log file + ShowNotice("'ladmin': Account deletion (account: %s, id: %d, ip: %s) - saved in next line:\n", auth_dat[i].userid, auth_dat[i].account_id, ip); + mmo_auth_tostr((char*)buf, &auth_dat[i]); + ShowNotice("%s\n", buf); + // delete account + memset(auth_dat[i].userid, '\0', sizeof(auth_dat[i].userid)); + auth_dat[i].account_id = -1; + mmo_auth_sync(); + } else { + memcpy(WFIFOP(fd,6), account_name, 24); + ShowNotice("'ladmin': Attempt to delete an unknown account (account: %s, ip: %s)\n", account_name, ip); + } + WFIFOSET(fd,30); + RFIFOSKIP(fd,26); + break; + + case 0x7934: // Request to change a password + if (RFIFOREST(fd) < 50) + return 0; + WFIFOW(fd,0) = 0x7935; + WFIFOL(fd,2) = 0xFFFFFFFF; /// WTF??? an unsigned being set to a -1 + account_name = (char*)RFIFOP(fd,2); + account_name[23] = '\0'; + remove_control_chars(account_name); + i = search_account_index(account_name); + if (i != -1) { + memcpy(WFIFOP(fd,6), auth_dat[i].userid, 24); + memcpy(auth_dat[i].pass, RFIFOP(fd,26), 24); + auth_dat[i].pass[23] = '\0'; + remove_control_chars(auth_dat[i].pass); + WFIFOL(fd,2) = auth_dat[i].account_id; + ShowNotice("'ladmin': Modification of a password (account: %s, new password: %s, ip: %s)\n", auth_dat[i].userid, auth_dat[i].pass, ip); + mmo_auth_sync(); + } else { + memcpy(WFIFOP(fd,6), account_name, 24); + ShowNotice("'ladmin': Attempt to modify the password of an unknown account (account: %s, ip: %s)\n", account_name, ip); + } + WFIFOSET(fd,30); + RFIFOSKIP(fd,50); + break; + + case 0x7936: // Request to modify a state + if (RFIFOREST(fd) < 50) + return 0; + { + char error_message[20]; + uint32 statut; + WFIFOW(fd,0) = 0x7937; + WFIFOL(fd,2) = 0xFFFFFFFF; // WTF??? + account_name = (char*)RFIFOP(fd,2); + account_name[23] = '\0'; + remove_control_chars(account_name); + statut = RFIFOL(fd,26); + memcpy(error_message, RFIFOP(fd,30), 20); + error_message[19] = '\0'; + remove_control_chars(error_message); + if (statut != 7 || error_message[0] == '\0') { // 7: // 6 = Your are Prohibited to log in until %s + strcpy(error_message, "-"); + } + i = search_account_index(account_name); + if (i != -1) { + memcpy(WFIFOP(fd,6), auth_dat[i].userid, 24); + WFIFOL(fd,2) = auth_dat[i].account_id; + if (auth_dat[i].state == statut && strcmp(auth_dat[i].error_message, error_message) == 0) + ShowNotice("'ladmin': Modification of a state, but the state of the account is already the good state (account: %s, received state: %d, ip: %s)\n", account_name, statut, ip); + else { + if (statut == 7) + ShowNotice("'ladmin': Modification of a state (account: %s, new state: %d - prohibited to login until '%s', ip: %s)\n", auth_dat[i].userid, statut, error_message, ip); + else + ShowNotice("'ladmin': Modification of a state (account: %s, new state: %d, ip: %s)\n", auth_dat[i].userid, statut, ip); + if (auth_dat[i].state == 0) { + unsigned char buf[16]; + WBUFW(buf,0) = 0x2731; + WBUFL(buf,2) = auth_dat[i].account_id; + WBUFB(buf,6) = 0; // 0: change of statut, 1: ban + WBUFL(buf,7) = statut; // status or final date of a banishment + charif_sendallwos(-1, buf, 11); + } + auth_dat[i].state = statut; + memcpy(auth_dat[i].error_message, error_message, 20); + mmo_auth_sync(); + } + } else { + memcpy(WFIFOP(fd,6), account_name, 24); + ShowNotice("'ladmin': Attempt to modify the state of an unknown account (account: %s, received state: %d, ip: %s)\n", account_name, statut, ip); + } + WFIFOL(fd,30) = statut; + } + WFIFOSET(fd,34); + RFIFOSKIP(fd,50); + break; + + case 0x7938: // Request for servers list and # of online players + { + uint8 server_num = 0; + ShowStatus("'ladmin': Sending of servers list (ip: %s)\n", ip); + for(i = 0; i < MAX_SERVERS; i++) { + if (server[i].fd >= 0) { + WFIFOL(fd,4+server_num*32) = htonl(server[i].ip); + WFIFOW(fd,4+server_num*32+4) = htons(server[i].port); + memcpy(WFIFOP(fd,4+server_num*32+6), server[i].name, 20); + WFIFOW(fd,4+server_num*32+26) = server[i].users; + WFIFOW(fd,4+server_num*32+28) = server[i].maintenance; + WFIFOW(fd,4+server_num*32+30) = server[i].new_; + server_num++; + } + } + WFIFOW(fd,0) = 0x7939; + WFIFOW(fd,2) = 4 + 32 * server_num; + WFIFOSET(fd,4+32*server_num); + RFIFOSKIP(fd,2); + break; + } + + case 0x793a: // Request to password check + if (RFIFOREST(fd) < 50) + return 0; + WFIFOW(fd,0) = 0x793b; + WFIFOL(fd,2) = 0xFFFFFFFF; // WTF??? + account_name = (char*)RFIFOP(fd,2); + account_name[23] = '\0'; + remove_control_chars(account_name); + i = search_account_index(account_name); + if (i != -1) { + char pass[25]; + memcpy(WFIFOP(fd,6), auth_dat[i].userid, 24); + memcpy(pass, RFIFOP(fd,26), 24); + pass[24] = '\0'; + remove_control_chars(pass); + if (strcmp(auth_dat[i].pass, pass) == 0) { + WFIFOL(fd,2) = auth_dat[i].account_id; + ShowNotice("'ladmin': Check of password OK (account: %s, password: %s, ip: %s)\n", auth_dat[i].userid, auth_dat[i].pass, ip); + } else { + ShowNotice("'ladmin': Failure of password check (account: %s, proposed pass: %s, ip: %s)\n", auth_dat[i].userid, pass, ip); + } + } else { + memcpy(WFIFOP(fd,6), account_name, 24); + ShowNotice("'ladmin': Attempt to check the password of an unknown account (account: %s, ip: %s)\n", account_name, ip); + } + WFIFOSET(fd,30); + RFIFOSKIP(fd,50); + break; + + case 0x793c: // Request to modify sex + if (RFIFOREST(fd) < 27) + return 0; + WFIFOW(fd,0) = 0x793d; + WFIFOL(fd,2) = 0xFFFFFFFF; // WTF??? + account_name = (char*)RFIFOP(fd,2); + account_name[23] = '\0'; + remove_control_chars(account_name); + memcpy(WFIFOP(fd,6), account_name, 24); + { + char sex; + sex = RFIFOB(fd,26); + if (sex != 'F' && sex != 'M') { + if (sex > 31) + ShowNotice("'ladmin': Attempt to give an invalid sex (account: %s, received sex: %c, ip: %s)\n", account_name, sex, ip); + else + ShowNotice("'ladmin': Attempt to give an invalid sex (account: %s, received sex: 'control char', ip: %s)\n", account_name, ip); + } else { + i = search_account_index(account_name); + if (i != -1) { + memcpy(WFIFOP(fd,6), auth_dat[i].userid, 24); + if (auth_dat[i].sex != ((sex == 'S' || sex == 's') ? 2 : (sex == 'M' || sex == 'm'))) { + unsigned char buf[16]; + WFIFOL(fd,2) = auth_dat[i].account_id; + auth_dat[i].sex = (sex == 'S' || sex == 's') ? 2 : (sex == 'M' || sex == 'm'); + ShowNotice("'ladmin': Modification of a sex (account: %s, new sex: %c, ip: %s)\n", auth_dat[i].userid, sex, ip); + mmo_auth_sync(); + // send to all char-server the change + WBUFW(buf,0) = 0x2723; + WBUFL(buf,2) = auth_dat[i].account_id; + WBUFB(buf,6) = auth_dat[i].sex; + charif_sendallwos(-1, buf, 7); + } else { + ShowNotice("'ladmin': Modification of a sex, but the sex is already the good sex (account: %s, sex: %c, ip: %s)\n", auth_dat[i].userid, sex, ip); + } + } else { + ShowNotice("'ladmin': Attempt to modify the sex of an unknown account (account: %s, received sex: %c, ip: %s)\n", account_name, sex, ip); + } + } + } + WFIFOSET(fd,30); + RFIFOSKIP(fd,27); + break; + + case 0x793e: // Request to modify GM level + if (RFIFOREST(fd) < 27) + return 0; + WFIFOW(fd,0) = 0x793f; + WFIFOL(fd,2) = 0xFFFFFFFF; // WTF??? + account_name = (char*)RFIFOP(fd,2); + account_name[23] = '\0'; + remove_control_chars(account_name); + memcpy(WFIFOP(fd,6), account_name, 24); + { + char new_gm_level; + new_gm_level = RFIFOB(fd,26); + if (new_gm_level < 0 || new_gm_level > 99) { + ShowNotice("'ladmin': Attempt to give an invalid GM level (account: %s, received GM level: %d, ip: %s)\n", account_name, (int)new_gm_level, ip); + } else { + i = search_account_index(account_name); + if (i != -1) { + int acc = auth_dat[i].account_id; + memcpy(WFIFOP(fd,6), auth_dat[i].userid, 24); + if (isGM(acc) != new_gm_level) { + // modification of the file + FILE *fp, *fp2; + int lock; + char line[512]; + int GM_account, GM_level; + int modify_flag; + char tmpstr[24]; + time_t raw_time; + if ((fp2 = lock_fopen(GM_account_filename, &lock)) != NULL) { + if ((fp = fopen(GM_account_filename, "r")) != NULL) { + time(&raw_time); + strftime(tmpstr, 23, login_config.date_format, localtime(&raw_time)); + modify_flag = 0; + // read/write GM file + while(fgets(line, sizeof(line), fp)) + { + while(line[0] != '\0' && (line[strlen(line)-1] == '\n' || line[strlen(line)-1] == '\r')) + line[strlen(line)-1] = '\0'; // TODO: remove this + if ((line[0] == '/' && line[1] == '/') || line[0] == '\0') + fprintf(fp2, "%s\n", line); + else { + if (sscanf(line, "%d %d", &GM_account, &GM_level) != 2 && sscanf(line, "%d: %d", &GM_account, &GM_level) != 2) + fprintf(fp2, "%s\n", line); + else if (GM_account != acc) + fprintf(fp2, "%s\n", line); + else if (new_gm_level < 1) { + fprintf(fp2, "// %s: 'ladmin' GM level removed on account %d '%s' (previous level: %d)\n//%d %d\n", tmpstr, acc, auth_dat[i].userid, GM_level, acc, new_gm_level); + modify_flag = 1; + } else { + fprintf(fp2, "// %s: 'ladmin' GM level on account %d '%s' (previous level: %d)\n%d %d\n", tmpstr, acc, auth_dat[i].userid, GM_level, acc, new_gm_level); + modify_flag = 1; + } + } + } + if (modify_flag == 0) + fprintf(fp2, "// %s: 'ladmin' GM level on account %d '%s' (previous level: 0)\n%d %d\n", tmpstr, acc, auth_dat[i].userid, acc, new_gm_level); + fclose(fp); + } else { + ShowNotice("'ladmin': Attempt to modify of a GM level - impossible to read GM accounts file (account: %s (%d), received GM level: %d, ip: %s)\n", auth_dat[i].userid, acc, (int)new_gm_level, ip); + } + if (lock_fclose(fp2, GM_account_filename, &lock) == 0) { + WFIFOL(fd,2) = acc; + ShowNotice("'ladmin': Modification of a GM level (account: %s (%d), new GM level: %d, ip: %s)\n", auth_dat[i].userid, acc, (int)new_gm_level, ip); + // read and send new GM informations + read_gm_account(); + send_GM_accounts(-1); + } else { + ShowNotice("'ladmin': Attempt to modify of a GM level - impossible to write GM accounts file (account: %s (%d), received GM level: %d, ip: %s)\n", auth_dat[i].userid, acc, (int)new_gm_level, ip); + } + } else { + ShowNotice("'ladmin': Attempt to modify of a GM level - impossible to write GM accounts file (account: %s (%d), received GM level: %d, ip: %s)\n", auth_dat[i].userid, acc, (int)new_gm_level, ip); + } + } else { + ShowNotice("'ladmin': Attempt to modify of a GM level, but the GM level is already the good GM level (account: %s (%d), GM level: %d, ip: %s)\n", auth_dat[i].userid, acc, (int)new_gm_level, ip); + } + } else { + ShowNotice("'ladmin': Attempt to modify the GM level of an unknown account (account: %s, received GM level: %d, ip: %s)\n", account_name, (int)new_gm_level, ip); + } + } + } + WFIFOSET(fd,30); + RFIFOSKIP(fd,27); + break; + + case 0x7940: // Request to modify e-mail + if (RFIFOREST(fd) < 66) + return 0; + WFIFOW(fd,0) = 0x7941; + WFIFOL(fd,2) = 0xFFFFFFFF; // WTF??? + account_name = (char*)RFIFOP(fd,2); + account_name[23] = '\0'; + remove_control_chars(account_name); + memcpy(WFIFOP(fd,6), account_name, 24); + { + char email[40]; + memcpy(email, RFIFOP(fd,26), 40); + if (e_mail_check(email) == 0) { + ShowNotice("'ladmin': Attempt to give an invalid e-mail (account: %s, ip: %s)\n", account_name, ip); + } else { + remove_control_chars(email); + i = search_account_index(account_name); + if (i != -1) { + memcpy(WFIFOP(fd,6), auth_dat[i].userid, 24); + memcpy(auth_dat[i].email, email, 40); + WFIFOL(fd,2) = auth_dat[i].account_id; + ShowNotice("'ladmin': Modification of an email (account: %s, new e-mail: %s, ip: %s)\n", auth_dat[i].userid, email, ip); + mmo_auth_sync(); + } else { + ShowNotice("'ladmin': Attempt to modify the e-mail of an unknown account (account: %s, received e-mail: %s, ip: %s)\n", account_name, email, ip); + } + } + } + WFIFOSET(fd,30); + RFIFOSKIP(fd,66); + break; + + case 0x7942: // Request to modify memo field + if ((int)RFIFOREST(fd) < 28 || (int)RFIFOREST(fd) < (28 + RFIFOW(fd,26))) + return 0; + WFIFOW(fd,0) = 0x7943; + WFIFOL(fd,2) = 0xFFFFFFFF; // WTF??? + account_name = (char*)RFIFOP(fd,2); + account_name[23] = '\0'; + remove_control_chars(account_name); + i = search_account_index(account_name); + if (i != -1) { + int size_of_memo = sizeof(auth_dat[i].memo); + memcpy(WFIFOP(fd,6), auth_dat[i].userid, 24); + memset(auth_dat[i].memo, '\0', size_of_memo); + if (RFIFOW(fd,26) == 0) { + strncpy(auth_dat[i].memo, "-", size_of_memo); + } else if (RFIFOW(fd,26) > size_of_memo - 1) { + memcpy(auth_dat[i].memo, RFIFOP(fd,28), size_of_memo - 1); + } else { + memcpy(auth_dat[i].memo, RFIFOP(fd,28), RFIFOW(fd,26)); + } + auth_dat[i].memo[size_of_memo - 1] = '\0'; + remove_control_chars(auth_dat[i].memo); + WFIFOL(fd,2) = auth_dat[i].account_id; + ShowNotice("'ladmin': Modification of a memo field (account: %s, new memo: %s, ip: %s)\n", auth_dat[i].userid, auth_dat[i].memo, ip); + mmo_auth_sync(); + } else { + memcpy(WFIFOP(fd,6), account_name, 24); + ShowNotice("'ladmin': Attempt to modify the memo field of an unknown account (account: %s, ip: %s)\n", account_name, ip); + } + WFIFOSET(fd,30); + RFIFOSKIP(fd,28 + RFIFOW(fd,26)); + break; + + case 0x7944: // Request to found an account id + if (RFIFOREST(fd) < 26) + return 0; + WFIFOW(fd,0) = 0x7945; + WFIFOL(fd,2) = 0xFFFFFFFF; // WTF??? + account_name = (char*)RFIFOP(fd,2); + account_name[23] = '\0'; + remove_control_chars(account_name); + i = search_account_index(account_name); + if (i != -1) { + memcpy(WFIFOP(fd,6), auth_dat[i].userid, 24); + WFIFOL(fd,2) = auth_dat[i].account_id; + ShowNotice("'ladmin': Request (by the name) of an account id (account: %s, id: %d, ip: %s)\n", auth_dat[i].userid, auth_dat[i].account_id, ip); + } else { + memcpy(WFIFOP(fd,6), account_name, 24); + ShowNotice("'ladmin': ID request (by the name) of an unknown account (account: %s, ip: %s)\n", account_name, ip); + } + WFIFOSET(fd,30); + RFIFOSKIP(fd,26); + break; + + case 0x7946: // Request to found an account name + if (RFIFOREST(fd) < 6) + return 0; + WFIFOW(fd,0) = 0x7947; + WFIFOL(fd,2) = RFIFOL(fd,2); + memset(WFIFOP(fd,6), '\0', 24); + for(i = 0; i < auth_num; i++) { + if (auth_dat[i].account_id == (int)RFIFOL(fd,2)) { + strncpy((char*)WFIFOP(fd,6), auth_dat[i].userid, 24); + ShowNotice("'ladmin': Request (by id) of an account name (account: %s, id: %d, ip: %s)\n", auth_dat[i].userid, RFIFOL(fd,2), ip); + break; + } + } + if (i == auth_num) { + ShowNotice("'ladmin': Name request (by id) of an unknown account (id: %d, ip: %s)\n", RFIFOL(fd,2), ip); + strncpy((char*)WFIFOP(fd,6), "", 24); + } + WFIFOSET(fd,30); + RFIFOSKIP(fd,6); + break; + + case 0x7948: // Request to change the validity limit (timestamp) (absolute value) + if (RFIFOREST(fd) < 30) + return 0; + { + time_t timestamp; + char tmpstr[2048]; + WFIFOW(fd,0) = 0x7949; + WFIFOL(fd,2) = 0xFFFFFFFF; // WTF??? + account_name = (char*)RFIFOP(fd,2); + account_name[23] = '\0'; + remove_control_chars(account_name); + timestamp = (time_t)RFIFOL(fd,26); + strftime(tmpstr, 24, login_config.date_format, localtime(×tamp)); + i = search_account_index(account_name); + if (i != -1) { + memcpy(WFIFOP(fd,6), auth_dat[i].userid, 24); + ShowNotice("'ladmin': Change of a validity limit (account: %s, new validity: %d (%s), ip: %s)\n", auth_dat[i].userid, timestamp, (timestamp == 0 ? "unlimited" : tmpstr), ip); + auth_dat[i].expiration_time = timestamp; + WFIFOL(fd,2) = auth_dat[i].account_id; + mmo_auth_sync(); + } else { + memcpy(WFIFOP(fd,6), account_name, 24); + ShowNotice("'ladmin': Attempt to change the validity limit of an unknown account (account: %s, received validity: %d (%s), ip: %s)\n", account_name, timestamp, (timestamp == 0 ? "unlimited" : tmpstr), ip); + } + WFIFOL(fd,30) = (unsigned int)timestamp; + } + WFIFOSET(fd,34); + RFIFOSKIP(fd,30); + break; + + case 0x794a: // Request to change the final date of a banishment (timestamp) (absolute value) + if (RFIFOREST(fd) < 30) + return 0; + { + time_t timestamp; + char tmpstr[2048]; + WFIFOW(fd,0) = 0x794b; + WFIFOL(fd,2) = 0xFFFFFFFF; // WTF??? + account_name = (char*)RFIFOP(fd,2); + account_name[23] = '\0'; + remove_control_chars(account_name); + timestamp = (time_t)RFIFOL(fd,26); + if (timestamp <= time(NULL)) + timestamp = 0; + strftime(tmpstr, 24, login_config.date_format, localtime(×tamp)); + i = search_account_index(account_name); + if (i != -1) { + memcpy(WFIFOP(fd,6), auth_dat[i].userid, 24); + WFIFOL(fd,2) = auth_dat[i].account_id; + ShowNotice("'ladmin': Change of the final date of a banishment (account: %s, new final date of banishment: %d (%s), ip: %s)\n", auth_dat[i].userid, timestamp, (timestamp == 0 ? "no banishment" : tmpstr), ip); + if (auth_dat[i].unban_time != timestamp) { + if (timestamp != 0) { + unsigned char buf[16]; + WBUFW(buf,0) = 0x2731; + WBUFL(buf,2) = auth_dat[i].account_id; + WBUFB(buf,6) = 1; // 0: change of statut, 1: ban + WBUFL(buf,7) = (unsigned int)timestamp; // status or final date of a banishment + charif_sendallwos(-1, buf, 11); + } + auth_dat[i].unban_time = timestamp; + mmo_auth_sync(); + } + } else { + memcpy(WFIFOP(fd,6), account_name, 24); + ShowNotice("'ladmin': Attempt to change the final date of a banishment of an unknown account (account: %s, received final date of banishment: %d (%s), ip: %s)\n", account_name, timestamp, (timestamp == 0 ? "no banishment" : tmpstr), ip); + } + WFIFOL(fd,30) = (unsigned int)timestamp; + } + WFIFOSET(fd,34); + RFIFOSKIP(fd,30); + break; + + case 0x794c: // Request to change the final date of a banishment (timestamp) (relative change) + if (RFIFOREST(fd) < 38) + return 0; + { + time_t timestamp; + struct tm *tmtime; + char tmpstr[2048]; + WFIFOW(fd,0) = 0x794d; + WFIFOL(fd,2) = 0xFFFFFFFF; // WTF??? + account_name = (char*)RFIFOP(fd,2); + account_name[23] = '\0'; + remove_control_chars(account_name); + i = search_account_index(account_name); + if (i != -1) { + WFIFOL(fd,2) = auth_dat[i].account_id; + memcpy(WFIFOP(fd,6), auth_dat[i].userid, 24); + if (auth_dat[i].unban_time == 0 || auth_dat[i].unban_time < time(NULL)) + timestamp = time(NULL); + else + timestamp = auth_dat[i].unban_time; + tmtime = localtime(×tamp); + tmtime->tm_year = tmtime->tm_year + (short)RFIFOW(fd,26); + tmtime->tm_mon = tmtime->tm_mon + (short)RFIFOW(fd,28); + tmtime->tm_mday = tmtime->tm_mday + (short)RFIFOW(fd,30); + tmtime->tm_hour = tmtime->tm_hour + (short)RFIFOW(fd,32); + tmtime->tm_min = tmtime->tm_min + (short)RFIFOW(fd,34); + tmtime->tm_sec = tmtime->tm_sec + (short)RFIFOW(fd,36); + timestamp = mktime(tmtime); + if (timestamp != -1) { + if (timestamp <= time(NULL)) + timestamp = 0; + strftime(tmpstr, 24, login_config.date_format, localtime(×tamp)); + ShowNotice("'ladmin': Adjustment of a final date of a banishment (account: %s, (%+d y %+d m %+d d %+d h %+d mn %+d s) -> new validity: %d (%s), ip: %s)\n", auth_dat[i].userid, (short)RFIFOW(fd,26), (short)RFIFOW(fd,28), (short)RFIFOW(fd,30), (short)RFIFOW(fd,32), (short)RFIFOW(fd,34), (short)RFIFOW(fd,36), timestamp, (timestamp == 0 ? "no banishment" : tmpstr), ip); + if (auth_dat[i].unban_time != timestamp) { + if (timestamp != 0) { + unsigned char buf[16]; + WBUFW(buf,0) = 0x2731; + WBUFL(buf,2) = auth_dat[i].account_id; + WBUFB(buf,6) = 1; // 0: change of statut, 1: ban + WBUFL(buf,7) = (unsigned int)timestamp; // status or final date of a banishment + charif_sendallwos(-1, buf, 11); + } + auth_dat[i].unban_time = timestamp; + mmo_auth_sync(); + } + } else { + strftime(tmpstr, 24, login_config.date_format, localtime(&auth_dat[i].unban_time)); + ShowNotice("'ladmin': Impossible to adjust the final date of a banishment (account: %s, %d (%s) + (%+d y %+d m %+d d %+d h %+d mn %+d s) -> ???, ip: %s)\n", auth_dat[i].userid, auth_dat[i].unban_time, (auth_dat[i].unban_time == 0 ? "no banishment" : tmpstr), (short)RFIFOW(fd,26), (short)RFIFOW(fd,28), (short)RFIFOW(fd,30), (short)RFIFOW(fd,32), (short)RFIFOW(fd,34), (short)RFIFOW(fd,36), ip); + } + WFIFOL(fd,30) = (unsigned long)auth_dat[i].unban_time; + } else { + memcpy(WFIFOP(fd,6), account_name, 24); + ShowNotice("'ladmin': Attempt to adjust the final date of a banishment of an unknown account (account: %s, ip: %s)\n", account_name, ip); + WFIFOL(fd,30) = 0; + } + } + WFIFOSET(fd,34); + RFIFOSKIP(fd,38); + break; + + case 0x794e: // Request to send a broadcast message + if (RFIFOREST(fd) < 8 || RFIFOREST(fd) < (8 + RFIFOL(fd,4))) + return 0; + WFIFOW(fd,0) = 0x794f; + WFIFOW(fd,2) = 0xFFFF; // WTF??? + if (RFIFOL(fd,4) < 1) { + ShowNotice("'ladmin': Receiving a message for broadcast, but message is void (ip: %s)\n", ip); + } else { + // at least 1 char-server + for(i = 0; i < MAX_SERVERS; i++) + if (server[i].fd >= 0) + break; + if (i == MAX_SERVERS) { + ShowNotice("'ladmin': Receiving a message for broadcast, but no char-server is online (ip: %s)\n", ip); + } else { + unsigned char buf[32000]; + char message[32000]; + WFIFOW(fd,2) = 0; + memset(message, '\0', sizeof(message)); + memcpy(message, RFIFOP(fd,8), RFIFOL(fd,4)); + message[sizeof(message)-1] = '\0'; + remove_control_chars(message); + if (RFIFOW(fd,2) == 0) + ShowNotice("'ladmin': Receiving a message for broadcast (message (in yellow): %s, ip: %s)\n", message, ip); + else + ShowNotice("'ladmin': Receiving a message for broadcast (message (in blue): %s, ip: %s)\n", message, ip); + // send same message to all char-servers (no answer) + memcpy(WBUFP(buf,0), RFIFOP(fd,0), 8 + RFIFOL(fd,4)); + WBUFW(buf,0) = 0x2726; + charif_sendallwos(-1, buf, 8 + RFIFOL(fd,4)); + } + } + WFIFOSET(fd,4); + RFIFOSKIP(fd,8 + RFIFOL(fd,4)); + break; + + case 0x7950: // Request to change the validity limite (timestamp) (relative change) + if (RFIFOREST(fd) < 38) + return 0; + { + time_t timestamp; + struct tm *tmtime; + char tmpstr[2048]; + char tmpstr2[2048]; + WFIFOW(fd,0) = 0x7951; + WFIFOL(fd,2) = 0xFFFFFFFF; // WTF??? + account_name = (char*)RFIFOP(fd,2); + account_name[23] = '\0'; + remove_control_chars(account_name); + i = search_account_index(account_name); + if (i != -1) { + WFIFOL(fd,2) = auth_dat[i].account_id; + memcpy(WFIFOP(fd,6), auth_dat[i].userid, 24); + timestamp = auth_dat[i].expiration_time; + if (timestamp == 0 || timestamp < time(NULL)) + timestamp = time(NULL); + tmtime = localtime(×tamp); + tmtime->tm_year = tmtime->tm_year + (short)RFIFOW(fd,26); + tmtime->tm_mon = tmtime->tm_mon + (short)RFIFOW(fd,28); + tmtime->tm_mday = tmtime->tm_mday + (short)RFIFOW(fd,30); + tmtime->tm_hour = tmtime->tm_hour + (short)RFIFOW(fd,32); + tmtime->tm_min = tmtime->tm_min + (short)RFIFOW(fd,34); + tmtime->tm_sec = tmtime->tm_sec + (short)RFIFOW(fd,36); + timestamp = mktime(tmtime); + if (timestamp != -1) { + strftime(tmpstr, 24, login_config.date_format, localtime(&auth_dat[i].expiration_time)); + strftime(tmpstr2, 24, login_config.date_format, localtime(×tamp)); + ShowNotice("'ladmin': Adjustment of a validity limit (account: %s, %d (%s) + (%+d y %+d m %+d d %+d h %+d mn %+d s) -> new validity: %d (%s), ip: %s)\n", auth_dat[i].userid, auth_dat[i].expiration_time, (auth_dat[i].expiration_time == 0 ? "unlimited" : tmpstr), (short)RFIFOW(fd,26), (short)RFIFOW(fd,28), (short)RFIFOW(fd,30), (short)RFIFOW(fd,32), (short)RFIFOW(fd,34), (short)RFIFOW(fd,36), timestamp, (timestamp == 0 ? "unlimited" : tmpstr2), ip); + auth_dat[i].expiration_time = timestamp; + mmo_auth_sync(); + WFIFOL(fd,30) = (unsigned long)auth_dat[i].expiration_time; + } else { + strftime(tmpstr, 24, login_config.date_format, localtime(&auth_dat[i].expiration_time)); + ShowNotice("'ladmin': Impossible to adjust a validity limit (account: %s, %d (%s) + (%+d y %+d m %+d d %+d h %+d mn %+d s) -> ???, ip: %s)\n", auth_dat[i].userid, auth_dat[i].expiration_time, (auth_dat[i].expiration_time == 0 ? "unlimited" : tmpstr), (short)RFIFOW(fd,26), (short)RFIFOW(fd,28), (short)RFIFOW(fd,30), (short)RFIFOW(fd,32), (short)RFIFOW(fd,34), (short)RFIFOW(fd,36), ip); + WFIFOL(fd,30) = 0; + } + } else { + memcpy(WFIFOP(fd,6), account_name, 24); + ShowNotice("'ladmin': Attempt to adjust the validity limit of an unknown account (account: %s, ip: %s)\n", account_name, ip); + WFIFOL(fd,30) = 0; + } + } + WFIFOSET(fd,34); + RFIFOSKIP(fd,38); + break; + + case 0x7952: // Request about informations of an account (by account name) + if (RFIFOREST(fd) < 26) + return 0; + WFIFOW(fd,0) = 0x7953; + WFIFOL(fd,2) = 0xFFFFFFFF; // WTF??? + account_name = (char*)RFIFOP(fd,2); + account_name[23] = '\0'; + remove_control_chars(account_name); + i = search_account_index(account_name); + if (i != -1) { + WFIFOL(fd,2) = auth_dat[i].account_id; + WFIFOB(fd,6) = (unsigned char)isGM(auth_dat[i].account_id); + memcpy(WFIFOP(fd,7), auth_dat[i].userid, 24); + WFIFOB(fd,31) = auth_dat[i].sex; + WFIFOL(fd,32) = auth_dat[i].logincount; + WFIFOL(fd,36) = auth_dat[i].state; + memcpy(WFIFOP(fd,40), auth_dat[i].error_message, 20); + memcpy(WFIFOP(fd,60), auth_dat[i].lastlogin, 24); + memcpy(WFIFOP(fd,84), auth_dat[i].last_ip, 16); + memcpy(WFIFOP(fd,100), auth_dat[i].email, 40); + WFIFOL(fd,140) = (unsigned long)auth_dat[i].expiration_time; + WFIFOL(fd,144) = (unsigned long)auth_dat[i].unban_time; + WFIFOW(fd,148) = (uint16)strlen(auth_dat[i].memo); + if (auth_dat[i].memo[0]) { + memcpy(WFIFOP(fd,150), auth_dat[i].memo, strlen(auth_dat[i].memo)); + } + ShowNotice("'ladmin': Sending information of an account (request by the name; account: %s, id: %d, ip: %s)\n", auth_dat[i].userid, auth_dat[i].account_id, ip); + WFIFOSET(fd,150+strlen(auth_dat[i].memo)); + } else { + memcpy(WFIFOP(fd,7), account_name, 24); + WFIFOW(fd,148) = 0; + ShowNotice("'ladmin': Attempt to obtain information (by the name) of an unknown account (account: %s, ip: %s)\n", account_name, ip); + WFIFOSET(fd,150); + } + RFIFOSKIP(fd,26); + break; + + case 0x7954: // Request about information of an account (by account id) + if (RFIFOREST(fd) < 6) + return 0; + WFIFOW(fd,0) = 0x7953; + WFIFOL(fd,2) = RFIFOL(fd,2); + memset(WFIFOP(fd,7), '\0', 24); + for(i = 0; i < auth_num; i++) { + if (auth_dat[i].account_id == (int)RFIFOL(fd,2)) { + ShowNotice("'ladmin': Sending information of an account (request by the id; account: %s, id: %d, ip: %s)\n", auth_dat[i].userid, RFIFOL(fd,2), ip); + WFIFOB(fd,6) = (unsigned char)isGM(auth_dat[i].account_id); + memcpy(WFIFOP(fd,7), auth_dat[i].userid, 24); + WFIFOB(fd,31) = auth_dat[i].sex; + WFIFOL(fd,32) = auth_dat[i].logincount; + WFIFOL(fd,36) = auth_dat[i].state; + memcpy(WFIFOP(fd,40), auth_dat[i].error_message, 20); + memcpy(WFIFOP(fd,60), auth_dat[i].lastlogin, 24); + memcpy(WFIFOP(fd,84), auth_dat[i].last_ip, 16); + memcpy(WFIFOP(fd,100), auth_dat[i].email, 40); + WFIFOL(fd,140) = (unsigned long)auth_dat[i].expiration_time; + WFIFOL(fd,144) = (unsigned long)auth_dat[i].unban_time; + WFIFOW(fd,148) = (uint16)strlen(auth_dat[i].memo); + if (auth_dat[i].memo[0]) { + memcpy(WFIFOP(fd,150), auth_dat[i].memo, strlen(auth_dat[i].memo)); + } + WFIFOSET(fd,150+strlen(auth_dat[i].memo)); + break; + } + } + if (i == auth_num) { + ShowNotice("'ladmin': Attempt to obtain information (by the id) of an unknown account (id: %d, ip: %s)\n", RFIFOL(fd,2), ip); + strncpy((char*)WFIFOP(fd,7), "", 24); + WFIFOW(fd,148) = 0; + WFIFOSET(fd,150); + } + RFIFOSKIP(fd,6); + break; + + case 0x7955: // Request to reload GM file (no answer) + ShowStatus("'ladmin': Request to re-load GM configuration file (ip: %s).\n", ip); + read_gm_account(); + // send GM accounts to all char-servers + send_GM_accounts(-1); + RFIFOSKIP(fd,2); + break; + + default: + ShowStatus("'ladmin': End of connection, unknown packet (ip: %s)\n", ip); + set_eof(fd); + return 0; + } + } + RFIFOSKIP(fd,RFIFOREST(fd)); + return 0; +} diff --git a/src/login/login.c b/src/login/login.c new file mode 100644 index 000000000..9bb77e093 --- /dev/null +++ b/src/login/login.c @@ -0,0 +1,2362 @@ +// Copyright (c) Athena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + +#include "../common/cbasetypes.h" +#include "../common/mmo.h" +#include "../common/core.h" +#include "../common/socket.h" +#include "../common/db.h" +#include "../common/timer.h" +#include "../common/malloc.h" +#include "../common/strlib.h" +#include "../common/showmsg.h" +#include "../common/version.h" +#include "../common/md5calc.h" +#include "../common/lock.h" +#include "login.h" + +#include +#include +#include +#include // for stat/lstat/fstat + +struct Login_Config login_config; + +int login_fd; // login server socket +#define MAX_SERVERS 30 +struct mmo_char_server server[MAX_SERVERS]; // char server data + +#define sex_num2str(num) ( (num == 0 ) ? 'F' : (num == 1 ) ? 'M' : 'S' ) +#define sex_str2num(str) ( (str == 'F' ) ? 0 : (str == 'M' ) ? 1 : 2 ) + +// Advanced subnet check [LuzZza] +struct s_subnet { + uint32 mask; + uint32 char_ip; + uint32 map_ip; +} subnet[16]; + +int subnet_count = 0; + +// GM account management +struct gm_account* gm_account_db = NULL; +unsigned int GM_num = 0; // number of gm accounts +char GM_account_filename[1024] = "conf/GM_account.txt"; +long creation_time_GM_account_file; // tracks the last-changed timestamp of the gm accounts file +int gm_account_filename_check_timer = 15; // Timer to check if GM_account file has been changed and reload GM account automaticaly (in seconds; default: 15) + +//Account registration flood protection [Kevin] +int allowed_regs = 1; +int time_allowed = 10; //in seconds +unsigned int new_reg_tick = 0; + + +// data handling (TXT) +char account_filename[1024] = "save/account.txt"; + +// account database +struct mmo_account* auth_dat = NULL; +unsigned int auth_num = 0, auth_max = 0; + +int account_id_count = START_ACCOUNT_NUM; + +// define the number of times that some players must authentify them before to save account file. +// it's just about normal authentication. If an account is created or modified, save is immediatly done. +// An authentication just change last connected IP and date. It already save in log file. +// set minimum auth change before save: +#define AUTH_BEFORE_SAVE_FILE 10 +// set divider of auth_num to found number of change before save +#define AUTH_SAVE_FILE_DIVIDER 50 +int auth_before_save_file = 0; // Counter. First save when 1st char-server do connection. + + +// ladmin configuration +bool admin_state = false; +char admin_pass[24] = ""; +uint32 admin_allowed_ip = 0; + +int parse_admin(int fd); + + +//----------------------------------------------------- +// Auth database +//----------------------------------------------------- +#define AUTH_TIMEOUT 30000 + +struct auth_node { + int account_id; + uint32 login_id1; + uint32 login_id2; + uint32 ip; + char sex; +}; + +static DBMap* auth_db; // int account_id -> struct auth_node* + +//----------------------------------------------------- +// Online User Database [Wizputer] +//----------------------------------------------------- + +struct online_login_data { + int account_id; + int waiting_disconnect; + int char_server; +}; + +static DBMap* online_db; // int account_id -> struct online_login_data* +static int waiting_disconnect_timer(int tid, unsigned int tick, int id, int data); + +static void* create_online_user(DBKey key, va_list args) +{ + struct online_login_data* p; + CREATE(p, struct online_login_data, 1); + p->account_id = key.i; + p->char_server = -1; + p->waiting_disconnect = -1; + return p; +} + +struct online_login_data* add_online_user(int char_server, int account_id) +{ + struct online_login_data* p; + if( !login_config.online_check ) + return NULL; + p = (struct online_login_data*)idb_ensure(online_db, account_id, create_online_user); + p->char_server = char_server; + if( p->waiting_disconnect != -1 ) + { + delete_timer(p->waiting_disconnect, waiting_disconnect_timer); + p->waiting_disconnect = -1; + } + return p; +} + +void remove_online_user(int account_id) +{ + struct online_login_data* p; + if( !login_config.online_check ) + return; + p = (struct online_login_data*)idb_get(online_db, account_id); + if( p == NULL ) + return; + if( p->waiting_disconnect != -1 ) + delete_timer(p->waiting_disconnect, waiting_disconnect_timer); + + idb_remove(online_db, account_id); +} + +static int waiting_disconnect_timer(int tid, unsigned int tick, int id, int data) +{ + struct online_login_data* p = (struct online_login_data*)idb_get(online_db, id); + if( p != NULL && p->waiting_disconnect == tid && p->account_id == id ) + { + p->waiting_disconnect = -1; + remove_online_user(id); + idb_remove(auth_db, id); + } + return 0; +} + +//-------------------------------------------------------------------- +// Packet send to all char-servers, except one (wos: without our self) +//-------------------------------------------------------------------- +int charif_sendallwos(int sfd, uint8* buf, size_t len) +{ + int i, c; + + for( i = 0, c = 0; i < MAX_SERVERS; ++i ) + { + int fd = server[i].fd; + if( session_isValid(fd) && fd != sfd ) + { + WFIFOHEAD(fd,len); + memcpy(WFIFOP(fd,0), buf, len); + WFIFOSET(fd,len); + ++c; + } + } + + return c; +} + +//---------------------------------------------------------------------- +// Determine if an account (id) is a GM account +// and returns its level (or 0 if it isn't a GM account or if not found) +//---------------------------------------------------------------------- +int isGM(int account_id) +{ + unsigned int i; + ARR_FIND( 0, GM_num, i, gm_account_db[i].account_id == account_id ); + return ( i < GM_num ) ? gm_account_db[i].level : 0; +} + +//---------------------------------------------------------------------- +// Adds a new GM using acc id and level +//---------------------------------------------------------------------- +void addGM(int account_id, int level) +{ + static unsigned int GM_max = 0; + unsigned int i; + + ARR_FIND( 0, auth_num, i, auth_dat[i].account_id == account_id ); + if( i == auth_num ) + return; // no such account + + ARR_FIND( 0, GM_num, i, gm_account_db[i].account_id == account_id ); + if( i < GM_num ) + { + if (gm_account_db[i].level == level) + ShowWarning("addGM: GM account %d defined twice (same level: %d).\n", account_id, level); + else { + ShowWarning("addGM: GM account %d defined twice (levels: %d and %d).\n", account_id, gm_account_db[i].level, level); + gm_account_db[i].level = level; + } + return; // entry already present + } + + // new account + if (GM_num >= GM_max) { + GM_max += 256; + RECREATE(gm_account_db, struct gm_account, GM_max); + } + gm_account_db[GM_num].account_id = account_id; + gm_account_db[GM_num].level = level; + GM_num++; + if (GM_num >= 4000) + ShowWarning("4000 GM accounts found. Next GM accounts are not read.\n"); +} + +//------------------------------------------------------- +// Reading function of GM accounts file (and their level) +//------------------------------------------------------- +int read_gm_account(void) +{ + char line[512]; + FILE *fp; + int account_id, level; + int line_counter; + struct stat file_stat; + int start_range = 0, end_range = 0, is_range = 0, current_id = 0; + + if(gm_account_db) aFree(gm_account_db); + CREATE(gm_account_db, struct gm_account, 1); + GM_num = 0; + + // get last modify time/date + if (stat(GM_account_filename, &file_stat)) + creation_time_GM_account_file = 0; // error + else + creation_time_GM_account_file = (long)file_stat.st_mtime; + + if ((fp = fopen(GM_account_filename, "r")) == NULL) { + ShowError("read_gm_account: GM accounts file [%s] not found.\n", GM_account_filename); + return 1; + } + + line_counter = 0; + // limited to 4000, because we send information to char-servers (more than 4000 GM accounts???) + // int (id) + int (level) = 8 bytes * 4000 = 32k (limit of packets in windows) + while(fgets(line, sizeof(line), fp) && GM_num < 4000) + { + line_counter++; + if ((line[0] == '/' && line[1] == '/') || line[0] == '\0' || line[0] == '\n' || line[0] == '\r') + continue; + is_range = (sscanf(line, "%d%*[-~]%d %d",&start_range,&end_range,&level)==3); // ID Range [MC Cameri] + if (!is_range && sscanf(line, "%d %d", &account_id, &level) != 2 && sscanf(line, "%d: %d", &account_id, &level) != 2) + ShowError("read_gm_account: file [%s], invalid 'acount_id|range level' format (line #%d).\n", GM_account_filename, line_counter); + else if (level <= 0) + ShowError("read_gm_account: file [%s] %dth account (line #%d) (invalid level [0 or negative]: %d).\n", GM_account_filename, GM_num+1, line_counter, level); + else { + if (level > 99) { + ShowNotice("read_gm_account: file [%s] %dth account (invalid level, but corrected: %d->99).\n", GM_account_filename, GM_num+1, level); + level = 99; + } + if (is_range) { + if (start_range==end_range) + ShowError("read_gm_account: file [%s] invalid range, beginning of range is equal to end of range (line #%d).\n", GM_account_filename, line_counter); + else if (start_range>end_range) + ShowError("read_gm_account: file [%s] invalid range, beginning of range must be lower than end of range (line #%d).\n", GM_account_filename, line_counter); + else + for (current_id = start_range;current_id<=end_range;current_id++) + addGM(current_id,level); + } else { + addGM(account_id,level); + } + } + } + fclose(fp); + + ShowStatus("read_gm_account: file '%s' read (%d GM accounts found).\n", GM_account_filename, GM_num); + + return 0; +} + + +//----------------------------------------------- +// Search an account id +// (return account index or -1 (if not found)) +// If exact account name is not found, +// the function checks without case sensitive +// and returns index if only 1 account is found +// and similar to the searched name. +//----------------------------------------------- +int search_account_index(char* account_name) +{ + unsigned int i, quantity; + int index; + + quantity = 0; + index = -1; + + for(i = 0; i < auth_num; i++) { + // Without case sensitive check (increase the number of similar account names found) + if (stricmp(auth_dat[i].userid, account_name) == 0) { + // Strict comparison (if found, we finish the function immediatly with correct value) + if (strcmp(auth_dat[i].userid, account_name) == 0) + return i; + quantity++; + index = i; + } + } + // Here, the exact account name is not found + // We return the found index of a similar account ONLY if there is 1 similar account + if (quantity == 1) + return index; + + // Exact account name is not found and 0 or more than 1 similar accounts have been found ==> we say not found + return -1; +} + +//-------------------------------------------------------- +// Create a string to save the account in the account file +//-------------------------------------------------------- +int mmo_auth_tostr(char* str, struct mmo_account* p) +{ + int i; + char *str_p = str; + + str_p += sprintf(str_p, "%d\t%s\t%s\t%s\t%c\t%d\t%u\t%s\t%s\t%ld\t%s\t%s\t%ld\t", + p->account_id, p->userid, p->pass, p->lastlogin, p->sex, + p->logincount, p->state, p->email, p->error_message, + (long)p->expiration_time, p->last_ip, p->memo, (long)p->unban_time); + + for(i = 0; i < p->account_reg2_num; i++) + if (p->account_reg2[i].str[0]) + str_p += sprintf(str_p, "%s,%s ", p->account_reg2[i].str, p->account_reg2[i].value); + + return 0; +} + +//--------------------------------- +// Reading of the accounts database +//--------------------------------- +int mmo_auth_init(void) +{ + FILE *fp; + int account_id; + uint32 state; + int logincount, n; + uint32 i, j; + char line[2048], *p, userid[2048], pass[2048], lastlogin[2048], sex, email[2048], error_message[2048], last_ip[2048], memo[2048]; + long unban_time; + long expiration_time; + char str[2048]; + char v[2048]; + int GM_count = 0; + int server_count = 0; + + auth_max = 256; + CREATE(auth_dat, struct mmo_account, auth_max); + + if ((fp = fopen(account_filename, "r")) == NULL) { + // no account file -> no account -> no login, including char-server (ERROR) + ShowError(CL_RED"mmmo_auth_init: Accounts file [%s] not found."CL_RESET"\n", account_filename); + return 0; + } + + while(fgets(line, sizeof(line), fp) != NULL) + { + if (line[0] == '/' && line[1] == '/') + continue; + + p = line; + + memset(userid, 0, sizeof(userid)); + memset(pass, 0, sizeof(pass)); + memset(lastlogin, 0, sizeof(lastlogin)); + memset(email, 0, sizeof(email)); + memset(error_message, 0, sizeof(error_message)); + memset(last_ip, 0, sizeof(last_ip)); + memset(memo, 0, sizeof(memo)); + + // database version reading (v2) + if (((i = sscanf(line, "%d\t%[^\t]\t%[^\t]\t%[^\t]\t%c\t%d\t%u\t" + "%[^\t]\t%[^\t]\t%ld\t%[^\t]\t%[^\t]\t%ld%n", + &account_id, userid, pass, lastlogin, &sex, &logincount, &state, + email, error_message, &expiration_time, last_ip, memo, &unban_time, &n)) == 13 && line[n] == '\t') || + ((i = sscanf(line, "%d\t%[^\t]\t%[^\t]\t%[^\t]\t%c\t%d\t%u\t" + "%[^\t]\t%[^\t]\t%ld\t%[^\t]\t%[^\t]%n", + &account_id, userid, pass, lastlogin, &sex, &logincount, &state, + email, error_message, &expiration_time, last_ip, memo, &n)) == 12 && line[n] == '\t')) { + n = n + 1; + + // Some checks + if (account_id > END_ACCOUNT_NUM) { + ShowError(CL_RED"mmmo_auth_init: an account has an id higher than %d\n", END_ACCOUNT_NUM); + ShowError(" account id #%d -> account not read (data is lost!)."CL_RESET"\n", account_id); + continue; + } + userid[23] = '\0'; + remove_control_chars(userid); + for(j = 0; j < auth_num; j++) { + if (auth_dat[j].account_id == account_id) { + ShowError(CL_RED"mmmo_auth_init: an account has an identical id to another.\n"); + ShowError(" account id #%d -> new account not read (data is lost!)."CL_RED"\n", account_id); + break; + } else if (strcmp(auth_dat[j].userid, userid) == 0) { + ShowError(CL_RED"mmmo_auth_init: account name already exists.\n"); + ShowError(" account name '%s' -> new account not read (data is lost!)."CL_RESET"\n", userid); // 2 lines, account name can be long. + break; + } + } + if (j != auth_num) + continue; + + if (auth_num >= auth_max) { + auth_max += 256; + auth_dat = (struct mmo_account*)aRealloc(auth_dat, sizeof(struct mmo_account) * auth_max); + } + + memset(&auth_dat[auth_num], '\0', sizeof(struct mmo_account)); + + auth_dat[auth_num].account_id = account_id; + + strncpy(auth_dat[auth_num].userid, userid, 24); + + pass[32] = '\0'; + remove_control_chars(pass); + strncpy(auth_dat[auth_num].pass, pass, 32); + + lastlogin[23] = '\0'; + remove_control_chars(lastlogin); + strncpy(auth_dat[auth_num].lastlogin, lastlogin, 24); + + auth_dat[auth_num].sex = sex; + + if (logincount >= 0) + auth_dat[auth_num].logincount = logincount; + else + auth_dat[auth_num].logincount = 0; + + if (state > 255) + auth_dat[auth_num].state = 100; + else + auth_dat[auth_num].state = state; + + if (e_mail_check(email) == 0) { + ShowNotice("Account %s (%d): invalid e-mail (replaced par a@a.com).\n", auth_dat[auth_num].userid, auth_dat[auth_num].account_id); + strncpy(auth_dat[auth_num].email, "a@a.com", 40); + } else { + remove_control_chars(email); + strncpy(auth_dat[auth_num].email, email, 40); + } + + error_message[19] = '\0'; + remove_control_chars(error_message); + if (error_message[0] == '\0' || state != 7) { // 7, because state is packet 0x006a value + 1 + strncpy(auth_dat[auth_num].error_message, "-", 20); + } else { + strncpy(auth_dat[auth_num].error_message, error_message, 20); + } + + if (i == 13) + auth_dat[auth_num].unban_time = (time_t)unban_time; + else + auth_dat[auth_num].unban_time = 0; + + auth_dat[auth_num].expiration_time = (time_t)expiration_time; + + last_ip[15] = '\0'; + remove_control_chars(last_ip); + strncpy(auth_dat[auth_num].last_ip, last_ip, 16); + + memo[254] = '\0'; + remove_control_chars(memo); + strncpy(auth_dat[auth_num].memo, memo, 255); + + for(j = 0; j < ACCOUNT_REG2_NUM; j++) { + p += n; + if (sscanf(p, "%[^\t,],%[^\t ] %n", str, v, &n) != 2) { + // We must check if a str is void. If it's, we can continue to read other REG2. + // Account line will have something like: str2,9 ,9 str3,1 (here, ,9 is not good) + if (p[0] == ',' && sscanf(p, ",%[^\t ] %n", v, &n) == 1) { + j--; + continue; + } else + break; + } + str[31] = '\0'; + remove_control_chars(str); + strncpy(auth_dat[auth_num].account_reg2[j].str, str, 32); + strncpy(auth_dat[auth_num].account_reg2[j].value,v,256); + } + auth_dat[auth_num].account_reg2_num = j; + + if (isGM(account_id) > 0) + GM_count++; + if (auth_dat[auth_num].sex == 'S') + server_count++; + + auth_num++; + if (account_id >= account_id_count) + account_id_count = account_id + 1; + + // Old athena database version reading (v1) + } else if ((i = sscanf(line, "%d\t%[^\t]\t%[^\t]\t%[^\t]\t%c\t%d\t%u\t%n", + &account_id, userid, pass, lastlogin, &sex, &logincount, &state, &n)) >= 5) { + if (account_id > END_ACCOUNT_NUM) { + ShowError(CL_RED"mmmo_auth_init: an account has an id higher than %d\n", END_ACCOUNT_NUM); + ShowError(" account id #%d -> account not read (data is lost!)."CL_RESET"\n", account_id); + continue; + } + userid[23] = '\0'; + remove_control_chars(userid); + for(j = 0; j < auth_num; j++) { + if (auth_dat[j].account_id == account_id) { + ShowError(CL_RED"mmo_auth_init: an account has an identical id to another.\n"); + ShowError(" account id #%d -> new account not read (data is lost!)."CL_RESET"\n", account_id); + break; + } else if (strcmp(auth_dat[j].userid, userid) == 0) { + ShowError(CL_RED"mmo_auth_init: account name already exists.\n"); + ShowError(" account name '%s' -> new account not read (data is lost!)."CL_RESET"\n", userid); + break; + } + } + if (j != auth_num) + continue; + + if (auth_num >= auth_max) { + auth_max += 256; + RECREATE(auth_dat, struct mmo_account, auth_max); + } + + memset(&auth_dat[auth_num], '\0', sizeof(struct mmo_account)); + + auth_dat[auth_num].account_id = account_id; + + strncpy(auth_dat[auth_num].userid, userid, 24); + + pass[23] = '\0'; + remove_control_chars(pass); + strncpy(auth_dat[auth_num].pass, pass, 24); + + lastlogin[23] = '\0'; + remove_control_chars(lastlogin); + strncpy(auth_dat[auth_num].lastlogin, lastlogin, 24); + + auth_dat[auth_num].sex = sex; + + if (i >= 6) { + if (logincount >= 0) + auth_dat[auth_num].logincount = logincount; + else + auth_dat[auth_num].logincount = 0; + } else + auth_dat[auth_num].logincount = 0; + + if (i >= 7) { + if (state > 255) + auth_dat[auth_num].state = 100; + else + auth_dat[auth_num].state = state; + } else + auth_dat[auth_num].state = 0; + + // Initialization of new data + strncpy(auth_dat[auth_num].email, "a@a.com", 40); + strncpy(auth_dat[auth_num].error_message, "-", 20); + auth_dat[auth_num].unban_time = 0; + auth_dat[auth_num].expiration_time = 0; + strncpy(auth_dat[auth_num].last_ip, "-", 16); + strncpy(auth_dat[auth_num].memo, "-", 255); + + for(j = 0; j < ACCOUNT_REG2_NUM; j++) { + p += n; + if (sscanf(p, "%[^\t,],%[^\t ] %n", str, v, &n) != 2) { + // We must check if a str is void. If it's, we can continue to read other REG2. + // Account line will have something like: str2,9 ,9 str3,1 (here, ,9 is not good) + if (p[0] == ',' && sscanf(p, ",%[^\t ] %n", v, &n) == 1) { + j--; + continue; + } else + break; + } + str[31] = '\0'; + remove_control_chars(str); + strncpy(auth_dat[auth_num].account_reg2[j].str, str, 32); + strncpy(auth_dat[auth_num].account_reg2[j].value,v,256); + } + auth_dat[auth_num].account_reg2_num = j; + + if (isGM(account_id) > 0) + GM_count++; + if (auth_dat[auth_num].sex == 'S') + server_count++; + + auth_num++; + if (account_id >= account_id_count) + account_id_count = account_id + 1; + + } else { + int i = 0; + if (sscanf(line, "%d\t%%newid%%\n%n", &account_id, &i) == 1 && + i > 0 && account_id > account_id_count) + account_id_count = account_id; + } + } + fclose(fp); + + if( auth_num == 0 ) + ShowNotice("mmo_auth_init: No account found in %s.\n", account_filename); + else + if( auth_num == 1 ) + ShowStatus("mmo_auth_init: 1 account read in %s,\n", account_filename); + else + ShowStatus("mmo_auth_init: %d accounts read in %s,\n", auth_num, account_filename); + + if( GM_count == 0 ) + ShowStatus(" of which is no GM account, and \n"); + else + if( GM_count == 1 ) + ShowStatus(" of which is 1 GM account, and \n"); + else + ShowStatus(" of which is %d GM accounts, and \n", GM_count); + + if( server_count == 0 ) + ShowStatus(" no server account ('S').\n"); + else + if( server_count == 1 ) + ShowStatus(" 1 server account ('S').\n"); + else + ShowStatus(" %d server accounts ('S').\n", server_count); + + return 0; +} + +//------------------------------------------ +// Writing of the accounts database file +// (accounts are sorted by id before save) +//------------------------------------------ +void mmo_auth_sync(void) +{ + FILE *fp; + unsigned int i, j, k; + int lock; + int account_id; + CREATE_BUFFER(id, int, auth_num); + char line[65536]; + + // Sorting before save + for(i = 0; i < auth_num; i++) { + id[i] = i; + account_id = auth_dat[i].account_id; + for(j = 0; j < i; j++) { + if (account_id < auth_dat[id[j]].account_id) { + for(k = i; k > j; k--) + id[k] = id[k-1]; + id[j] = i; // id[i] + break; + } + } + } + + // Data save + if ((fp = lock_fopen(account_filename, &lock)) == NULL) { + //if (id) aFree(id); + DELETE_BUFFER(id); + return; + } + + fprintf(fp, "// Accounts file: here are saved all information about the accounts.\n"); + fprintf(fp, "// Structure: ID, account name, password, last login time, sex, # of logins, state, email, error message for state 7, validity time, last (accepted) login ip, memo field, ban timestamp, repeated(register text, register value)\n"); + fprintf(fp, "// Some explanations:\n"); + fprintf(fp, "// account name : between 4 to 23 char for a normal account (standard client can't send less than 4 char).\n"); + fprintf(fp, "// account password: between 4 to 23 char\n"); + fprintf(fp, "// sex : M or F for normal accounts, S for server accounts\n"); + fprintf(fp, "// state : 0: account is ok, 1 to 256: error code of packet 0x006a + 1\n"); + fprintf(fp, "// email : between 3 to 39 char (a@a.com is like no email)\n"); + fprintf(fp, "// error message : text for the state 7: 'Your are Prohibited to login until '. Max 19 char\n"); + fprintf(fp, "// valitidy time : 0: unlimited account, : date calculated by addition of 1/1/1970 + value (number of seconds since the 1/1/1970)\n"); + fprintf(fp, "// memo field : max 254 char\n"); + fprintf(fp, "// ban time : 0: no ban, : banned until the date: date calculated by addition of 1/1/1970 + value (number of seconds since the 1/1/1970)\n"); + for(i = 0; i < auth_num; i++) { + k = id[i]; // use of sorted index + if (auth_dat[k].account_id == -1) + continue; + + mmo_auth_tostr(line, &auth_dat[k]); + fprintf(fp, "%s\n", line); + } + fprintf(fp, "%d\t%%newid%%\n", account_id_count); + + lock_fclose(fp, account_filename, &lock); + + // set new counter to minimum number of auth before save + auth_before_save_file = auth_num / AUTH_SAVE_FILE_DIVIDER; // Re-initialise counter. We have save. + if (auth_before_save_file < AUTH_BEFORE_SAVE_FILE) + auth_before_save_file = AUTH_BEFORE_SAVE_FILE; + + //if (id) aFree(id); + DELETE_BUFFER(id); + + return; +} + +//----------------------------------------------------- +// Check if we must save accounts file or not +// every minute, we check if we must save because we +// have do some authentications without arrive to +// the minimum of authentications for the save. +// Note: all other modification of accounts (deletion, +// change of some informations excepted lastip/ +// lastlogintime, creation) are always save +// immediatly and set the minimum of +// authentications to its initialization value. +//----------------------------------------------------- +int check_auth_sync(int tid, unsigned int tick, int id, int data) +{ + // we only save if necessary: + // we have do some authentications without do saving + if (auth_before_save_file < AUTH_BEFORE_SAVE_FILE || + auth_before_save_file < (int)(auth_num / AUTH_SAVE_FILE_DIVIDER)) + mmo_auth_sync(); + + return 0; +} + +//----------------------------------------------------- +// periodic ip address synchronization +//----------------------------------------------------- +static int sync_ip_addresses(int tid, unsigned int tick, int id, int data) +{ + uint8 buf[2]; + ShowInfo("IP Sync in progress...\n"); + WBUFW(buf,0) = 0x2735; + charif_sendallwos(-1, buf, 2); + return 0; +} + +//----------------------------------------------------- +// Send GM accounts to one or all char-servers +//----------------------------------------------------- +void send_GM_accounts(int fd) +{ + unsigned int i; + uint8 buf[32767]; + uint16 len; + + len = 4; + WBUFW(buf,0) = 0x2732; + for(i = 0; i < GM_num; i++) + // send only existing accounts. We can not create a GM account when server is online. + if (gm_account_db[i].level > 0) { + WBUFL(buf,len) = gm_account_db[i].account_id; + WBUFB(buf,len+4) = (uint8)gm_account_db[i].level; + len += 5; + if (len >= 32000) { + ShowWarning("send_GM_accounts: Too many accounts! Only %d out of %d were sent.\n", i, GM_num); + break; + } + } + + WBUFW(buf,2) = len; + if (fd == -1) // send to all charservers + charif_sendallwos(-1, buf, len); + else { // send only to target + WFIFOHEAD(fd,len); + memcpy(WFIFOP(fd,0), buf, len); + WFIFOSET(fd,len); + } + + return; +} + +//----------------------------------------------------- +// Check if GM file account have been changed +//----------------------------------------------------- +int check_GM_file(int tid, unsigned int tick, int id, int data) +{ + struct stat file_stat; + long new_time; + + // if we would not check + if (gm_account_filename_check_timer < 1) + return 0; + + // get last modify time/date + if (stat(GM_account_filename, &file_stat)) + new_time = 0; // error + else + new_time = (long)file_stat.st_mtime; + + if (new_time != creation_time_GM_account_file) { + read_gm_account(); + send_GM_accounts(-1); + } + + return 0; +} + + +//----------------------------------------------------- +// encrypted/unencrypted password check +//----------------------------------------------------- +bool check_encrypted(const char* str1, const char* str2, const char* passwd) +{ + char md5str[64], md5bin[32]; + + snprintf(md5str, sizeof(md5str), "%s%s", str1, str2); + md5str[sizeof(md5str)-1] = '\0'; + MD5_String2binary(md5str, md5bin); + + return (0==memcmp(passwd, md5bin, 16)); +} + +bool check_password(struct login_session_data* sd, int passwdenc, const char* passwd, const char* refpass) +{ + if(passwdenc == 0) + { + return (0==strcmp(passwd, refpass)); + } + else if(sd != NULL) + { + // password mode set to 1 -> (md5key, refpass) enable with + // password mode set to 2 -> (refpass, md5key) enable with + + return ((passwdenc&0x01) && check_encrypted(sd->md5key, refpass, passwd)) || + ((passwdenc&0x02) && check_encrypted(refpass, sd->md5key, passwd)); + } + return false; +} + + +//------------------------------------- +// Make new account +//------------------------------------- +int mmo_auth_new(struct mmo_account* account) +{ + static int num_regs = 0; // registration counter + unsigned int tick = gettick(); + + time_t expiration_time = 0; + unsigned int i = auth_num; + + // check if the account doesn't exist already + ARR_FIND( 0, auth_num, i, strcmp(account->userid, auth_dat[i].userid) == 0 ); + if( i < auth_num ) + { + ShowNotice("Attempt of creation of an already existant account (account: %s_%c, pass: %s, received pass: %s)\n", account->userid, account->sex, auth_dat[i].pass, account->pass); + return 1; // 1 = Incorrect Password + } + + //Account Registration Flood Protection by [Kevin] + if( DIFF_TICK(tick, new_reg_tick) < 0 && num_regs >= allowed_regs ) + { + ShowNotice("Account registration denied (registration limit exceeded)\n"); + return 3; + } + + if (auth_num >= auth_max) { + auth_max += 256; + auth_dat = (struct mmo_account*)aRealloc(auth_dat, sizeof(struct mmo_account) * auth_max); + } + + memset(&auth_dat[i], '\0', sizeof(struct mmo_account)); + + // find a suitable non-gm account id + while (isGM(account_id_count) > 0) + account_id_count++; + + auth_dat[i].account_id = account_id_count++; + safestrncpy(auth_dat[i].userid, account->userid, NAME_LENGTH); + if( login_config.use_md5_passwds ) + MD5_String(account->pass, auth_dat[i].pass); + else + safestrncpy(auth_dat[i].pass, account->pass, NAME_LENGTH); + safestrncpy(auth_dat[i].lastlogin, "-", sizeof(auth_dat[i].lastlogin)); + auth_dat[i].sex = account->sex; + auth_dat[i].logincount = 0; + auth_dat[i].state = 0; + safestrncpy(auth_dat[i].email, e_mail_check(account->email) ? account->email : "a@a.com", sizeof(auth_dat[i].email)); + safestrncpy(auth_dat[i].error_message, "-", sizeof(auth_dat[i].error_message)); + auth_dat[i].unban_time = 0; + if( login_config.start_limited_time != -1 ) + expiration_time = time(NULL) + login_config.start_limited_time; + auth_dat[i].expiration_time = expiration_time; + strncpy(auth_dat[i].last_ip, "-", 16); + strncpy(auth_dat[i].memo, "-", 255); + auth_dat[i].account_reg2_num = 0; + + ShowNotice("Account creation (account %s, id: %d, pass: %s, sex: %c)\n", account->userid, auth_num, account->pass, account->sex); + auth_num++; + + if( DIFF_TICK(tick, new_reg_tick) > 0 ) + {// Update the registration check. + num_regs = 0; + new_reg_tick = tick + time_allowed*1000; + } + ++num_regs; + + return 0; +} + +//----------------------------------------------------- +// Check/authentication of a connection +//----------------------------------------------------- +int mmo_auth(struct login_session_data* sd) +{ + unsigned int i; + time_t raw_time; + char tmpstr[256]; + int len; + char user_password[32+1]; // reserve for md5-ed pw + + char ip[16]; + ip2str(session[sd->fd]->client_addr, ip); + + // DNS Blacklist check + if( login_config.use_dnsbl ) + { + char r_ip[16]; + char ip_dnsbl[256]; + char* dnsbl_serv; + bool matched = false; + uint8* sin_addr = (uint8*)&session[sd->fd]->client_addr; + + sprintf(r_ip, "%u.%u.%u.%u", sin_addr[0], sin_addr[1], sin_addr[2], sin_addr[3]); + + for( dnsbl_serv = strtok(login_config.dnsbl_servs,","); !matched && dnsbl_serv != NULL; dnsbl_serv = strtok(NULL,",") ) + { + sprintf(ip_dnsbl, "%s.%s", r_ip, dnsbl_serv); + if( host2ip(ip_dnsbl) ) + matched = true; + } + + if( matched ) + { + ShowInfo("DNSBL: (%s) Blacklisted. User Kicked.\n", r_ip); + return 3; + } + } + + //Client Version check + if( login_config.check_client_version && sd->version != login_config.client_version_to_connect ) + return 5; + + len = strnlen(sd->userid, NAME_LENGTH); + + // Account creation with _M/_F + if( login_config.new_account_flag ) + { + if( len > 2 && strnlen(sd->passwd, NAME_LENGTH) > 0 && // valid user and password lengths + sd->passwdenc == 0 && // unencoded password + sd->userid[len-2] == '_' && memchr("FfMm", sd->userid[len-1], 4) && // _M/_F suffix + account_id_count <= END_ACCOUNT_NUM ) + { + struct mmo_account acc; + int result; + + len -= 2; + sd->userid[len] = '\0'; + + memset(&acc, '\0', sizeof(acc)); + safestrncpy(acc.userid, sd->userid, NAME_LENGTH); + safestrncpy(acc.pass, sd->passwd, NAME_LENGTH); + safestrncpy(acc.email, "a@a.com", sizeof(acc.email)); + acc.sex = TOUPPER(sd->userid[len+1]); + + result = mmo_auth_new(&acc); + if( result ) + return result;// Failed to make account. [Skotlex]. + + auth_before_save_file = 0; // Creation of an account -> save accounts file immediatly + } + } + + // Strict account search + ARR_FIND( 0, auth_num, i, strcmp(sd->userid, auth_dat[i].userid) == 0 ); + + // if strict account search fails, we do a no sensitive case research for index + if( i < auth_num ) + { + i = search_account_index(sd->userid); + if( i == -1 ) + i = auth_num; + else + memcpy(sd->userid, auth_dat[i].userid, NAME_LENGTH); // for the possible tests/checks afterwards (copy correcte sensitive case). + } + + if( i == auth_num ) + { + ShowNotice("Unknown account (account: %s, received pass: %s, ip: %s)\n", sd->userid, sd->passwd, ip); + return 0; // 0 = Unregistered ID + } + + if( login_config.use_md5_passwds ) + MD5_String(sd->passwd, user_password); + else + safestrncpy(user_password, sd->passwd, NAME_LENGTH); + + if( !check_password(sd, sd->passwdenc, user_password, auth_dat[i].pass) ) + { + ShowNotice("Invalid password (account: %s, pass: %s, received pass: %s, ip: %s)\n", sd->userid, auth_dat[i].pass, (sd->passwdenc) ? "[MD5]" : sd->passwd, ip); + return 1; // 1 = Incorrect Password + } + + if( auth_dat[i].expiration_time != 0 && auth_dat[i].expiration_time < time(NULL) ) + { + ShowNotice("Connection refused (account: %s, pass: %s, expired ID, ip: %s)\n", sd->userid, sd->passwd, ip); + return 2; // 2 = This ID is expired + } + + if( auth_dat[i].unban_time != 0 && auth_dat[i].unban_time > time(NULL) ) + { + strftime(tmpstr, 20, login_config.date_format, localtime(&auth_dat[i].unban_time)); + tmpstr[19] = '\0'; + ShowNotice("Connection refused (account: %s, pass: %s, banned until %s, ip: %s)\n", sd->userid, sd->passwd, tmpstr, ip); + return 6; // 6 = Your are Prohibited to log in until %s + } + + if( auth_dat[i].state ) + { + ShowNotice("Connection refused (account: %s, pass: %s, state: %d, ip: %s)\n", sd->userid, sd->passwd, auth_dat[i].state, ip); + return auth_dat[i].state - 1; + } + + ShowNotice("Authentication accepted (account: %s, id: %d, ip: %s)\n", sd->userid, auth_dat[i].account_id, ip); + + // auth start : time seed + time(&raw_time); + strftime(tmpstr, 24, "%Y-%m-%d %H:%M:%S",localtime(&raw_time)); + + sd->account_id = auth_dat[i].account_id; + sd->login_id1 = rand(); + sd->login_id2 = rand(); + safestrncpy(sd->lastlogin, auth_dat[i].lastlogin, 24); + sd->sex = auth_dat[i].sex; + + if( sd->sex != 'S' && sd->account_id < START_ACCOUNT_NUM ) + ShowWarning("Account %s has account id %d! Account IDs must be over %d to work properly!\n", sd->userid, sd->account_id, START_ACCOUNT_NUM); + + safestrncpy(auth_dat[i].lastlogin, tmpstr, sizeof(auth_dat[i].lastlogin)); + safestrncpy(auth_dat[i].last_ip, ip, sizeof(auth_dat[i].last_ip)); + auth_dat[i].unban_time = 0; + auth_dat[i].logincount++; + + // Save until for change ip/time of auth is not very useful => limited save for that + // Save there informations isnot necessary, because they are saved in log file. + if (--auth_before_save_file <= 0) // Reduce counter. 0 or less, we save + mmo_auth_sync(); + + return -1; // account OK +} + +static int online_db_setoffline(DBKey key, void* data, va_list ap) +{ + struct online_login_data* p = (struct online_login_data*)data; + int server = va_arg(ap, int); + if( server == -1 ) + { + p->char_server = -1; + if( p->waiting_disconnect != -1 ) + { + delete_timer(p->waiting_disconnect, waiting_disconnect_timer); + p->waiting_disconnect = -1; + } + } + else if( p->char_server == server ) + p->char_server = -2; //Char server disconnected. + return 0; +} + +//-------------------------------- +// Packet parsing for char-servers +//-------------------------------- +int parse_fromchar(int fd) +{ + unsigned int i; + int j, id; + uint32 ipl; + char ip[16]; + + ARR_FIND( 0, MAX_SERVERS, id, server[id].fd == fd ); + if( id == MAX_SERVERS ) + {// not a char server + set_eof(fd); + do_close(fd); + return 0; + } + + if( session[fd]->flag.eof ) + { + ShowStatus("Char-server '%s' has disconnected.\n", server[id].name); + online_db->foreach(online_db, online_db_setoffline, id); //Set all chars from this char server to offline. + memset(&server[id], 0, sizeof(struct mmo_char_server)); + server[id].fd = -1; + do_close(fd); + return 0; + } + + ipl = server[id].ip; + ip2str(ipl, ip); + + while( RFIFOREST(fd) >= 2 ) + { + uint16 command = RFIFOW(fd,0); + + switch( command ) + { + + case 0x2709: // request from map-server via char-server to reload GM accounts + RFIFOSKIP(fd,2); + ShowStatus("Char-server '%s': Request to re-load GM configuration file (ip: %s).\n", server[id].name, ip); + read_gm_account(); + // send GM accounts to all char-servers + send_GM_accounts(-1); + break; + + case 0x2712: // request from char-server to authenticate an account + if( RFIFOREST(fd) < 19 ) + return 0; + { + struct auth_node* node; + + int account_id = RFIFOL(fd,2); + int login_id1 = RFIFOL(fd,6); + int login_id2 = RFIFOL(fd,10); + char sex = sex_num2str(RFIFOB(fd,14)); + uint32 ip_ = ntohl(RFIFOL(fd,15)); + RFIFOSKIP(fd,19); + + node = (struct auth_node*)idb_get(auth_db, account_id); + if( node != NULL && + node->account_id == account_id && + node->login_id1 == login_id1 && + node->login_id2 == login_id2 && + node->sex == sex && + node->ip == ip_ ) + {// found + uint32 expiration_time; + char email[40]; + unsigned int k; + + //ShowStatus("Char-server '%s': authentication of the account %d accepted (ip: %s).\n", server[id].name, account_id, ip); + + // each auth entry can only be used once + idb_remove(auth_db, account_id); + + // retrieve email and account expiration time + ARR_FIND( 0, auth_num, k, auth_dat[k].account_id == account_id ); + if( k < auth_num ) + { + strcpy(email, auth_dat[k].email); + expiration_time = (uint32)auth_dat[k].expiration_time; + } + else + { + memset(email, 0, sizeof(email)); + expiration_time = 0; + } + + // send ack + WFIFOHEAD(fd,59); + WFIFOW(fd,0) = 0x2713; + WFIFOL(fd,2) = account_id; + WFIFOL(fd,6) = login_id1; + WFIFOL(fd,10) = login_id2; + WFIFOB(fd,14) = 0; + memcpy(WFIFOP(fd,15), email, 40); + WFIFOL(fd,55) = expiration_time; + WFIFOSET(fd,59); + } + else + {// authentication not found + ShowStatus("Char-server '%s': authentication of the account %d REFUSED (ip: %s).\n", server[id].name, account_id, ip); + WFIFOHEAD(fd,59); + WFIFOW(fd,0) = 0x2713; + WFIFOL(fd,2) = account_id; + WFIFOL(fd,6) = login_id1; + WFIFOL(fd,10) = login_id2; + WFIFOB(fd,14) = 1; + // It is unnecessary to send email + // It is unnecessary to send validity date of the account + WFIFOSET(fd,59); + } + } + break; + + case 0x2714: + if( RFIFOREST(fd) < 6 ) + return 0; + { + int users = RFIFOL(fd,2); + RFIFOSKIP(fd,6); + + // how many users on world? (update) + if( server[id].users != users ) + { + ShowStatus("set users %s : %d\n", server[id].name, users); + + server[id].users = users; + } + } + break; + + case 0x2715: // request from char server to change e-email from default "a@a.com" + if (RFIFOREST(fd) < 46) + return 0; + { + char email[40]; + int acc = RFIFOL(fd,2); + safestrncpy(email, (char*)RFIFOP(fd,6), 40); remove_control_chars(email); + RFIFOSKIP(fd,46); + + if( e_mail_check(email) == 0 ) + ShowNotice("Char-server '%s': Attempt to create an e-mail on an account with a default e-mail REFUSED - e-mail is invalid (account: %d, ip: %s)\n", server[id].name, acc, ip); + else + { + ARR_FIND( 0, auth_num, i, auth_dat[i].account_id == acc && (strcmp(auth_dat[i].email, "a@a.com") == 0 || auth_dat[i].email[0] == '\0') ); + if( i == auth_num ) + ShowNotice("Char-server '%s': Attempt to create an e-mail on an account with a default e-mail REFUSED - account doesn't exist or e-mail of account isn't default e-mail (account: %d, ip: %s).\n", server[id].name, acc, ip); + else + { + memcpy(auth_dat[i].email, email, 40); + ShowNotice("Char-server '%s': Create an e-mail on an account with a default e-mail (account: %d, new e-mail: %s, ip: %s).\n", server[id].name, acc, email, ip); + // Save + mmo_auth_sync(); + } + } + } + break; + + case 0x2716: // received an e-mail/limited time request, because a player comes back from a map-server to the char-server + if( RFIFOREST(fd) < 6 ) + return 0; + { + uint32 expiration_time = 0; + char email[40] = ""; + + int account_id = RFIFOL(fd,2); + RFIFOSKIP(fd,6); + + ARR_FIND( 0, auth_num, i, auth_dat[i].account_id == account_id ); + if( i == auth_num ) + ShowNotice("Char-server '%s': e-mail of the account %d NOT found (ip: %s).\n", server[id].name, RFIFOL(fd,2), ip); + else + { + safestrncpy(email, auth_dat[i].email, sizeof(email)); + expiration_time = (uint32)auth_dat[i].expiration_time; + } + + WFIFOHEAD(fd,50); + WFIFOW(fd,0) = 0x2717; + WFIFOL(fd,2) = account_id; + safestrncpy((char*)WFIFOP(fd,6), email, 40); + WFIFOL(fd,46) = expiration_time; + WFIFOSET(fd,50); + } + break; + + case 0x2719: // ping request from charserver + if( RFIFOREST(fd) < 2 ) + return 0; + RFIFOSKIP(fd,2); + + WFIFOHEAD(fd,2); + WFIFOW(fd,0) = 0x2718; + WFIFOSET(fd,2); + break; + + // Map server send information to change an email of an account via char-server + case 0x2722: // 0x2722 .L .40B .40B + if (RFIFOREST(fd) < 86) + return 0; + { + char actual_email[40]; + char new_email[40]; + int account_id = RFIFOL(fd,2); + safestrncpy(actual_email, (char*)RFIFOP(fd,6), 40); remove_control_chars(actual_email); + safestrncpy(new_email, (char*)RFIFOP(fd,46), 40); remove_control_chars(new_email); + RFIFOSKIP(fd, 86); + + if( e_mail_check(actual_email) == 0 ) + ShowNotice("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command), but actual email is invalid (account: %d, ip: %s)\n", server[id].name, account_id, ip); + else if( e_mail_check(new_email) == 0 ) + ShowNotice("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command) with a invalid new e-mail (account: %d, ip: %s)\n", server[id].name, account_id, ip); + else if( strcmpi(new_email, "a@a.com") == 0 ) + ShowNotice("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command) with a default e-mail (account: %d, ip: %s)\n", server[id].name, account_id, ip); + else { + ARR_FIND( 0, auth_num, i, auth_dat[i].account_id == account_id ); + if( i == auth_num ) + ShowNotice("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command), but account doesn't exist (account: %d, ip: %s).\n", server[id].name, account_id, ip); + else + if( strcmpi(auth_dat[i].email, actual_email) != 0 ) + ShowNotice("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command), but actual e-mail is incorrect (account: %d (%s), actual e-mail: %s, proposed e-mail: %s, ip: %s).\n", server[id].name, account_id, auth_dat[i].userid, auth_dat[i].email, actual_email, ip); + else { + safestrncpy(auth_dat[i].email, new_email, 40); + ShowNotice("Char-server '%s': Modify an e-mail on an account (@email GM command) (account: %d (%s), new e-mail: %s, ip: %s).\n", server[id].name, account_id, auth_dat[i].userid, new_email, ip); + // Save + mmo_auth_sync(); + } + } + } + break; + + case 0x2724: // Receiving an account state update request from a map-server (relayed via char-server) + if (RFIFOREST(fd) < 10) + return 0; + { + int account_id = RFIFOL(fd,2); + uint32 state = RFIFOL(fd,6); + RFIFOSKIP(fd,10); + + ARR_FIND( 0, auth_num, i, auth_dat[i].account_id == account_id ); + if( i == auth_num ) + ShowNotice("Char-server '%s': Error of Status change (account: %d not found, suggested status %d, ip: %s).\n", server[id].name, account_id, state, ip); + else + if( auth_dat[i].state == state ) + ShowNotice("Char-server '%s': Error of Status change - actual status is already the good status (account: %d, status %d, ip: %s).\n", server[id].name, account_id, state, ip); + else { + ShowNotice("Char-server '%s': Status change (account: %d, new status %d, ip: %s).\n", server[id].name, account_id, state, ip); + if (state != 0) { + uint8 buf[11]; + WBUFW(buf,0) = 0x2731; + WBUFL(buf,2) = account_id; + WBUFB(buf,6) = 0; // 0: change of state, 1: ban + WBUFL(buf,7) = state; // status or final date of a banishment + charif_sendallwos(-1, buf, 11); + } + auth_dat[i].state = state; + // Save + mmo_auth_sync(); + } + } + break; + + case 0x2725: // Receiving of map-server via char-server a ban request + if (RFIFOREST(fd) < 18) + return 0; + { + int account_id = RFIFOL(fd,2); + int year = (short)RFIFOW(fd,6); + int month = (short)RFIFOW(fd,8); + int mday = (short)RFIFOW(fd,10); + int hour = (short)RFIFOW(fd,12); + int min = (short)RFIFOW(fd,14); + int sec = (short)RFIFOW(fd,16); + RFIFOSKIP(fd,18); + + ARR_FIND( 0, auth_num, i, auth_dat[i].account_id == account_id ); + if( i == auth_num ) + ShowNotice("Char-server '%s': Error of ban request (account: %d not found, ip: %s).\n", server[id].name, account_id, ip); + else + { + time_t timestamp; + struct tm *tmtime; + if (auth_dat[i].unban_time == 0 || auth_dat[i].unban_time < time(NULL)) + timestamp = time(NULL); + else + timestamp = auth_dat[i].unban_time; + tmtime = localtime(×tamp); + tmtime->tm_year = tmtime->tm_year + year; + tmtime->tm_mon = tmtime->tm_mon + month; + tmtime->tm_mday = tmtime->tm_mday + mday; + tmtime->tm_hour = tmtime->tm_hour + hour; + tmtime->tm_min = tmtime->tm_min + min; + tmtime->tm_sec = tmtime->tm_sec + sec; + timestamp = mktime(tmtime); + if (timestamp == -1) + ShowNotice("Char-server '%s': Error of ban request (account: %d, invalid date, ip: %s).\n", server[id].name, account_id, ip); + else + if( timestamp <= time(NULL) || timestamp == 0 ) + ShowNotice("Char-server '%s': Error of ban request (account: %d, new date unbans the account, ip: %s).\n", server[id].name, account_id, ip); + else + { + unsigned char buf[16]; + char tmpstr[2048]; + strftime(tmpstr, 24, login_config.date_format, localtime(×tamp)); + ShowNotice("Char-server '%s': Ban request (account: %d, new final date of banishment: %d (%s), ip: %s).\n", server[id].name, account_id, timestamp, tmpstr, ip); + WBUFW(buf,0) = 0x2731; + WBUFL(buf,2) = auth_dat[i].account_id; + WBUFB(buf,6) = 1; // 0: change of status, 1: ban + WBUFL(buf,7) = (unsigned int)timestamp; // status or final date of a banishment + charif_sendallwos(-1, buf, 11); + auth_dat[i].unban_time = timestamp; + // Save + mmo_auth_sync(); + } + } + } + break; + + case 0x2727: // Change of sex (sex is reversed) + if( RFIFOREST(fd) < 6 ) + return 0; + { + int account_id = RFIFOL(fd,2); + RFIFOSKIP(fd,6); + + ARR_FIND( 0, auth_num, i, auth_dat[i].account_id == account_id ); + if( i == auth_num ) + ShowNotice("Char-server '%s': Error of sex change (account: %d not found, ip: %s).\n", server[id].name, account_id, ip); + else + if( auth_dat[i].sex == 'S' ) + ShowNotice("Char-server '%s': Error of sex change - account to change is a Server account (account: %d, ip: %s).\n", server[id].name, account_id, ip); + else + { + unsigned char buf[7]; + char sex = ( auth_dat[i].sex == 'M' ) ? 'F' : 'M'; //Change gender + + auth_dat[i].sex = sex; + + ShowNotice("Char-server '%s': Sex change (account: %d, new sex %c, ip: %s).\n", server[id].name, account_id, sex, ip); + WBUFW(buf,0) = 0x2723; + WBUFL(buf,2) = account_id; + WBUFB(buf,6) = sex_str2num(sex); + charif_sendallwos(-1, buf, 7); + // Save + mmo_auth_sync(); + } + } + break; + + case 0x2728: // We receive account_reg2 from a char-server, and we send them to other map-servers. + if( RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2) ) + return 0; + { + int acc = RFIFOL(fd,4); + + ARR_FIND( 0, auth_num, i, auth_dat[i].account_id == acc ); + if( i == auth_num ) + ShowStatus("Char-server '%s': receiving (from the char-server) of account_reg2 (account: %d not found, ip: %s).\n", server[id].name, acc, ip); + else + { + int len; + int p; + ShowNotice("char-server '%s': receiving (from the char-server) of account_reg2 (account: %d, ip: %s).\n", server[id].name, acc, ip); + for(j=0,p=13;jforeach(online_db, online_db_setoffline, id); //Set all chars from this char-server offline first + users = RFIFOW(fd,4); + for (i = 0; i < users; i++) { + aid = RFIFOL(fd,6+i*4); + p = (struct online_login_data*)idb_ensure(online_db, aid, create_online_user); + p->char_server = id; + if (p->waiting_disconnect != -1) + { + delete_timer(p->waiting_disconnect, waiting_disconnect_timer); + p->waiting_disconnect = -1; + } + } + } + RFIFOSKIP(fd,RFIFOW(fd,2)); + break; + + case 0x272e: //Request account_reg2 for a character. + if (RFIFOREST(fd) < 10) + return 0; + { + size_t off; + + int account_id = RFIFOL(fd,2); + int char_id = RFIFOL(fd,6); + RFIFOSKIP(fd,10); + + WFIFOHEAD(fd,10000); + WFIFOW(fd,0) = 0x2729; + WFIFOL(fd,4) = account_id; + WFIFOL(fd,8) = char_id; + WFIFOB(fd,12) = 1; //Type 1 for Account2 registry + + ARR_FIND( 0, auth_num, i, auth_dat[i].account_id == account_id ); + if( i == auth_num ) + { + //Account not found? Send at least empty data, map servers need a reply! + WFIFOW(fd,2) = 13; + WFIFOSET(fd,WFIFOW(fd,2)); + break; + } + + for( off = 13, j = 0; j < auth_dat[i].account_reg2_num && off < 9000; j++ ) + { + if( auth_dat[i].account_reg2[j].str[0] != '\0' ) + { + off += sprintf((char*)WFIFOP(fd,off), "%s", auth_dat[i].account_reg2[j].str)+1; //We add 1 to consider the '\0' in place. + off += sprintf((char*)WFIFOP(fd,off), "%s", auth_dat[i].account_reg2[j].value)+1; + } + } + + if( off >= 9000 ) + ShowWarning("Too many account2 registries for AID %d. Some registries were not sent.\n", account_id); + + WFIFOW(fd,2) = (uint16)off; + WFIFOSET(fd,WFIFOW(fd,2)); + } + break; + + case 0x2736: // WAN IP update from char-server + if( RFIFOREST(fd) < 6 ) + return 0; + server[id].ip = ntohl(RFIFOL(fd,2)); + ShowInfo("Updated IP of Server #%d to %d.%d.%d.%d.\n",id, CONVIP(server[id].ip)); + RFIFOSKIP(fd,6); + break; + + case 0x2737: //Request to set all offline. + ShowInfo("Setting accounts from char-server %d offline.\n", id); + online_db->foreach(online_db, online_db_setoffline, id); + RFIFOSKIP(fd,2); + break; + + default: + ShowError("parse_fromchar: Unknown packet 0x%x from a char-server! Disconnecting!\n", command); + set_eof(fd); + return 0; + } // switch + } // while + + RFIFOSKIP(fd,RFIFOREST(fd)); + return 0; +} + +//-------------------------------------------- +// Test to know if an IP come from LAN or WAN. +//-------------------------------------------- +int lan_subnetcheck(uint32 ip) +{ + int i; + ARR_FIND( 0, subnet_count, i, (subnet[i].char_ip & subnet[i].mask) == (ip & subnet[i].mask) ); + return ( i < subnet_count ) ? subnet[i].char_ip : 0; +} + +void login_auth_ok(struct login_session_data* sd) +{ + int fd = sd->fd; + uint32 ip = session[fd]->client_addr; + + uint8 server_num, n; + uint32 subnet_char_ip; + struct auth_node* node; + int i; + + sd->level = isGM(sd->account_id); + + if( sd->level < login_config.min_level_to_connect ) + { + ShowStatus("Connection refused: the minimum GM level for connection is %d (account: %s, GM level: %d).\n", login_config.min_level_to_connect, sd->userid, sd->level); + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x81; + WFIFOB(fd,2) = 1; // 01 = Server closed + WFIFOSET(fd,3); + return; + } + + server_num = 0; + for( i = 0; i < MAX_SERVERS; ++i ) + if( session_isValid(server[i].fd) ) + server_num++; + + if( server_num == 0 ) + {// if no char-server, don't send void list of servers, just disconnect the player with proper message + ShowStatus("Connection refused: there is no char-server online (account: %s).\n", sd->userid); + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x81; + WFIFOB(fd,2) = 1; // 01 = Server closed + WFIFOSET(fd,3); + return; + } + + if( login_config.online_check ) + { + struct online_login_data* data = (struct online_login_data*)idb_get(online_db, sd->account_id); + if( data ) + {// account is already marked as online! + if( data->char_server > -1 ) + {// Request char servers to kick this account out. [Skotlex] + uint8 buf[6]; + ShowNotice("User '%s' is already online - Rejected.\n", sd->userid); + WBUFW(buf,0) = 0x2734; + WBUFL(buf,2) = sd->account_id; + charif_sendallwos(-1, buf, 6); + if( data->waiting_disconnect == -1 ) + data->waiting_disconnect = add_timer(gettick()+AUTH_TIMEOUT, waiting_disconnect_timer, sd->account_id, 0); + + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x81; + WFIFOB(fd,2) = 8; // 08 = Server still recognizes your last login + WFIFOSET(fd,3); + return; + } + else + if( data->char_server == -1 ) + {// client has authed but did not access char-server yet + // wipe previous session + idb_remove(auth_db, sd->account_id); + remove_online_user(sd->account_id); + data = NULL; + } + } + } + + if( sd->level > 0 ) + ShowStatus("Connection of the GM (level:%d) account '%s' accepted.\n", sd->level, sd->userid); + else + ShowStatus("Connection of the account '%s' accepted.\n", sd->userid); + + WFIFOHEAD(fd,47+32*server_num); + WFIFOW(fd,0) = 0x69; + WFIFOW(fd,2) = 47+32*server_num; + WFIFOL(fd,4) = sd->login_id1; + WFIFOL(fd,8) = sd->account_id; + WFIFOL(fd,12) = sd->login_id2; + WFIFOL(fd,16) = 0; // in old version, that was for ip (not more used) + //memcpy(WFIFOP(fd,20), sd->lastlogin, 24); // in old version, that was for name (not more used) + WFIFOW(fd,44) = 0; // unknown + WFIFOB(fd,46) = sex_str2num(sd->sex); + for( i = 0, n = 0; i < MAX_SERVERS; ++i ) + { + if( !session_isValid(server[i].fd) ) + continue; + + subnet_char_ip = lan_subnetcheck(ip); // Advanced subnet check [LuzZza] + WFIFOL(fd,47+n*32) = htonl((subnet_char_ip) ? subnet_char_ip : server[i].ip); + WFIFOW(fd,47+n*32+4) = ntows(htons(server[i].port)); // [!] LE byte order here [!] + memcpy(WFIFOP(fd,47+n*32+6), server[i].name, 20); + WFIFOW(fd,47+n*32+26) = server[i].users; + WFIFOW(fd,47+n*32+28) = server[i].maintenance; + WFIFOW(fd,47+n*32+30) = server[i].new_; + n++; + } + WFIFOSET(fd,47+32*server_num); + + // create temporary auth entry + CREATE(node, struct auth_node, 1); + node->account_id = sd->account_id; + node->login_id1 = sd->login_id1; + node->login_id2 = sd->login_id2; + node->sex = sd->sex; + node->ip = ip; + idb_put(auth_db, sd->account_id, node); + + if( login_config.online_check ) + { + struct online_login_data* data; + + // mark client as 'online' + data = add_online_user(-1, sd->account_id); + + // schedule deletion of this node + data->waiting_disconnect = add_timer(gettick()+AUTH_TIMEOUT, waiting_disconnect_timer, sd->account_id, 0); + } +} + +void login_auth_failed(struct login_session_data* sd, int result) +{ + int fd = sd->fd; + + WFIFOHEAD(fd,23); + WFIFOW(fd,0) = 0x6a; + WFIFOB(fd,2) = (uint8)result; + if( result != 6 ) + memset(WFIFOP(fd,3), '\0', 20); + else + {// 6 = Your are Prohibited to log in until %s + char tmpstr[20]; + int i = search_account_index(sd->userid); + time_t unban_time = ( i >= 0 ) ? auth_dat[i].unban_time : 0; + strftime(tmpstr, 20, login_config.date_format, localtime(&unban_time)); + safestrncpy((char*)WFIFOP(fd,3), tmpstr, 20); // ban timestamp goes here + } + WFIFOSET(fd,23); +} + +//---------------------------------------------------------------------------------------- +// Default packet parsing (normal players or administation/char-server connection requests) +//---------------------------------------------------------------------------------------- +int parse_login(int fd) +{ + struct login_session_data* sd = session[fd]->session_data; + int result; + uint32 ipl; + char ip[16]; + + if( session[fd]->flag.eof ) + { + do_close(fd); + return 0; + } + + if( sd == NULL ) { + sd = CREATE(session[fd]->session_data, struct login_session_data, 1); + sd->fd = fd; + } + + ipl = session[fd]->client_addr; + ip2str(ipl, ip); + + while( RFIFOREST(fd) >= 2 ) + { + uint16 command = RFIFOW(fd,0); + + switch( command ) + { + + case 0x0200: // New alive packet: structure: 0x200 .24B. used to verify if client is always alive. + if (RFIFOREST(fd) < 26) + return 0; + RFIFOSKIP(fd,26); + break; + + case 0x0204: // New alive packet: structure: 0x204 .16B. (new ragexe from 22 june 2004) + if (RFIFOREST(fd) < 18) + return 0; + RFIFOSKIP(fd,18); + break; + + case 0x0064: // request client login + case 0x01dd: // request client login (encryption mode) + case 0x0277: // New login packet (kRO 2006-04-24aSakexe langtype 0) + case 0x02b0: // New login packet (kRO 2007-05-14aSakexe langtype 0) + { + size_t packet_len = RFIFOREST(fd); // assume no other packet was sent + + if( (command == 0x0064 && packet_len < 55) + || (command == 0x01dd && packet_len < 47) + || (command == 0x0277 && packet_len < 84) + || (command == 0x02b0 && packet_len < 85) ) + return 0; + + // S 0064 .l .24B .24B .B + // S 01dd .l .24B .16B .B + // S 0277 .l .24B .24B .29B .B + // S 02b0 .l .24B .24B .30B .B + + sd->version = RFIFOL(fd,2); + safestrncpy(sd->userid, (char*)RFIFOP(fd,6), NAME_LENGTH); remove_control_chars(sd->userid); + if (command != 0x01dd) { + ShowStatus("Request for connection of %s (ip: %s).\n", sd->userid, ip); + safestrncpy(sd->passwd, (char*)RFIFOP(fd,30), NAME_LENGTH); remove_control_chars(sd->passwd); + sd->passwdenc = 0; + } else { + ShowStatus("Request for connection (encryption mode) of %s (ip: %s).\n", sd->userid, ip); + memcpy(sd->passwd, RFIFOP(fd,30), 16); sd->passwd[16] = '\0'; // raw binary data here! + sd->passwdenc = PASSWORDENC; + } + RFIFOSKIP(fd,packet_len); + + result = mmo_auth(sd); + + if( result == -1 ) + login_auth_ok(sd); + else + login_auth_failed(sd, result); + } + break; + + case 0x01db: // Sending request of the coding key + case 0x791a: // Sending request of the coding key (administration packet) + RFIFOSKIP(fd,2); + { + unsigned int i; + + memset(sd->md5key, '\0', sizeof(sd->md5key)); + sd->md5keylen = (uint16)(12 + rand() % 4); + for( i = 0; i < sd->md5keylen; ++i ) + sd->md5key[i] = (char)(1 + rand() % 255); + + WFIFOHEAD(fd,4 + sd->md5keylen); + WFIFOW(fd,0) = 0x01dc; + WFIFOW(fd,2) = 4 + sd->md5keylen; + memcpy(WFIFOP(fd,4), sd->md5key, sd->md5keylen); + WFIFOSET(fd,WFIFOW(fd,2)); + } + break; + + case 0x2710: // Connection request of a char-server + if (RFIFOREST(fd) < 86) + return 0; + { + char server_name[20]; + uint32 server_ip; + uint16 server_port; + uint16 maintenance; + uint16 new_; + + safestrncpy(sd->userid, (char*)RFIFOP(fd,2), NAME_LENGTH); //remove_control_chars(account.userid); + safestrncpy(sd->passwd, (char*)RFIFOP(fd,26), NAME_LENGTH); //remove_control_chars(account.passwd); + sd->passwdenc = 0; + sd->version = login_config.client_version_to_connect; // hack to skip version check + + server_ip = ntohl(RFIFOL(fd,54)); + server_port = ntohs(RFIFOW(fd,58)); + + safestrncpy(server_name, (char*)RFIFOP(fd,60), 20); remove_control_chars(server_name); + maintenance = RFIFOW(fd,82); + new_ = RFIFOW(fd,84); + RFIFOSKIP(fd,86); + + ShowInfo("Connection request of the char-server '%s' @ %d.%d.%d.%d:%d (account: '%s', pass: '%s', ip: '%s')\n", server_name, CONVIP(server_ip), server_port, sd->userid, sd->passwd, ip); + + result = mmo_auth(sd); + if( result == -1 && sd->sex == 'S' && sd->account_id < MAX_SERVERS && server[sd->account_id].fd == -1 ) + { + ShowStatus("Connection of the char-server '%s' accepted.\n", server_name); + safestrncpy(server[sd->account_id].name, server_name, sizeof(server[sd->account_id].name)); + server[sd->account_id].fd = fd; + server[sd->account_id].ip = server_ip; + server[sd->account_id].port = server_port; + server[sd->account_id].users = 0; + server[sd->account_id].maintenance = maintenance; + server[sd->account_id].new_ = new_; + + session[fd]->func_parse = parse_fromchar; + session[fd]->flag.server = 1; + realloc_fifo(fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK); + + // send connection success + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x2711; + WFIFOB(fd,2) = 0; + WFIFOSET(fd,3); + + // send GM account to char-server + send_GM_accounts(fd); + } + else + { + ShowNotice("Connection of the char-server '%s' REFUSED.\n", server_name); + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x2711; + WFIFOB(fd,2) = 3; + WFIFOSET(fd,3); + } + } + return 0; // processing will continue elsewhere + + case 0x7530: // Server version information request + ShowStatus("Sending server version information to ip: %s\n", ip); + RFIFOSKIP(fd,2); + WFIFOHEAD(fd,10); + WFIFOW(fd,0) = 0x7531; + WFIFOB(fd,2) = ATHENA_MAJOR_VERSION; + WFIFOB(fd,3) = ATHENA_MINOR_VERSION; + WFIFOB(fd,4) = ATHENA_REVISION; + WFIFOB(fd,5) = ATHENA_RELEASE_FLAG; + WFIFOB(fd,6) = ATHENA_OFFICIAL_FLAG; + WFIFOB(fd,7) = ATHENA_SERVER_LOGIN; + WFIFOW(fd,8) = ATHENA_MOD_VERSION; + WFIFOSET(fd,10); + break; + + case 0x7918: // Request for administation login + if ((int)RFIFOREST(fd) < 4 || (int)RFIFOREST(fd) < ((RFIFOW(fd,2) == 0) ? 28 : 20)) + return 0; + WFIFOW(fd,0) = 0x7919; + WFIFOB(fd,2) = 1; + if( session[fd]->client_addr != admin_allowed_ip ) { + ShowNotice("'ladmin'-login: Connection in administration mode refused: IP isn't authorised (ladmin_allow, ip: %s).\n", ip); + } else { + struct login_session_data *ld = (struct login_session_data*)session[fd]->session_data; + if (RFIFOW(fd,2) == 0) { // non encrypted password + char password[25]; + memcpy(password, RFIFOP(fd,4), 24); + password[24] = '\0'; + remove_control_chars(password); + if( !admin_state ) + ShowNotice("'ladmin'-login: Connection in administration mode REFUSED - remote administration is disabled (non encrypted password: %s, ip: %s)\n", password, ip); + else + if( strcmp(password, admin_pass) != 0) + ShowNotice("'ladmin'-login: Connection in administration mode REFUSED - invalid password (non encrypted password: %s, ip: %s)\n", password, ip); + else { + // If remote administration is enabled and password sent by client matches password read from login server configuration file + ShowNotice("'ladmin'-login: Connection in administration mode accepted (non encrypted password: %s, ip: %s)\n", password, ip); + WFIFOB(fd,2) = 0; + session[fd]->func_parse = parse_admin; + } + } else { // encrypted password + if (!ld) + ShowError("'ladmin'-login: error! MD5 key not created/requested for an administration login.\n"); + else { + char md5str[64] = "", md5bin[32]; + if (RFIFOW(fd,2) == 1) { + sprintf(md5str, "%s%s", ld->md5key, admin_pass); // 20 24 + } else if (RFIFOW(fd,2) == 2) { + sprintf(md5str, "%s%s", admin_pass, ld->md5key); // 24 20 + } + MD5_String2binary(md5str, md5bin); + if( !admin_state ) + ShowNotice("'ladmin'-login: Connection in administration mode REFUSED - remote administration is disabled (encrypted password, ip: %s)\n", ip); + else + if( memcmp(md5bin, RFIFOP(fd,4), 16) != 0 ) + ShowNotice("'ladmin'-login: Connection in administration mode REFUSED - invalid password (encrypted password, ip: %s)\n", ip); + else { + // If remote administration is enabled and password hash sent by client matches hash of password read from login server configuration file + ShowNotice("'ladmin'-login: Connection in administration mode accepted (encrypted password, ip: %s)\n", ip); + ShowNotice("Connection of a remote administration accepted (encrypted password).\n"); + WFIFOB(fd,2) = 0; + session[fd]->func_parse = parse_admin; + } + } + } + } + WFIFOSET(fd,3); + + RFIFOSKIP(fd, (RFIFOW(fd,2) == 0) ? 28 : 20); + break; + + default: + ShowNotice("Abnormal end of connection (ip: %s): Unknown packet 0x%x\n", ip, command); + set_eof(fd); + return 0; + } + } + + RFIFOSKIP(fd,RFIFOREST(fd)); + return 0; +} + +//----------------------- +// Console Command Parser [Wizputer] +//----------------------- +int parse_console(char* buf) +{ + char command[256]; + + memset(command, 0, sizeof(command)); + + sscanf(buf, "%[^\n]", command); + + ShowInfo("Console command :%s", command); + + if( strcmpi("shutdown", command) == 0 || + strcmpi("exit", command) == 0 || + strcmpi("quit", command) == 0 || + strcmpi("end", command) == 0 ) + runflag = 0; + else + if( strcmpi("alive", command) == 0 || + strcmpi("status", command) == 0 ) + ShowInfo(CL_CYAN"Console: "CL_BOLD"I'm Alive."CL_RESET"\n"); + else + if( strcmpi("help", command) == 0 ) { + ShowInfo(CL_BOLD"Help of commands:"CL_RESET"\n"); + ShowInfo(" To shutdown the server:\n"); + ShowInfo(" 'shutdown|exit|quit|end'\n"); + ShowInfo(" To know if server is alive:\n"); + ShowInfo(" 'alive|status'\n"); + } + + return 0; +} + +static int online_data_cleanup_sub(DBKey key, void *data, va_list ap) +{ + struct online_login_data *character= (struct online_login_data*)data; + if (character->char_server == -2) //Unknown server.. set them offline + remove_online_user(character->account_id); + return 0; +} + +static int online_data_cleanup(int tid, unsigned int tick, int id, int data) +{ + online_db->foreach(online_db, online_data_cleanup_sub); + return 0; +} + +//---------------------------------- +// Reading Lan Support configuration +//---------------------------------- +int login_lan_config_read(const char *lancfgName) +{ + FILE *fp; + int line_num = 0; + char line[1024], w1[64], w2[64], w3[64], w4[64]; + + if((fp = fopen(lancfgName, "r")) == NULL) { + ShowWarning("LAN Support configuration file is not found: %s\n", lancfgName); + return 1; + } + + ShowInfo("Reading the configuration file %s...\n", lancfgName); + + while(fgets(line, sizeof(line), fp)) + { + line_num++; + if ((line[0] == '/' && line[1] == '/') || line[0] == '\n' || line[1] == '\n') + continue; + + if(sscanf(line,"%[^:]: %[^:]:%[^:]:%[^\r\n]", w1, w2, w3, w4) != 4) + { + ShowWarning("Error syntax of configuration file %s in line %d.\n", lancfgName, line_num); + continue; + } + + if( strcmpi(w1, "subnet") == 0 ) + { + subnet[subnet_count].mask = str2ip(w2); + subnet[subnet_count].char_ip = str2ip(w3); + subnet[subnet_count].map_ip = str2ip(w4); + + if( (subnet[subnet_count].char_ip & subnet[subnet_count].mask) != (subnet[subnet_count].map_ip & subnet[subnet_count].mask) ) + { + ShowError("%s: Configuration Error: The char server (%s) and map server (%s) belong to different subnetworks!\n", lancfgName, w3, w4); + continue; + } + + subnet_count++; + } + } + + ShowStatus("Read information about %d subnetworks.\n", subnet_count); + + fclose(fp); + return 0; +} + +//----------------------------------- +// Reading main configuration file +//----------------------------------- +int login_config_read(const char* cfgName) +{ + char line[1024], w1[1024], w2[1024]; + FILE* fp = fopen(cfgName, "r"); + if (fp == NULL) { + ShowError("Configuration file (%s) not found.\n", cfgName); + return 1; + } + ShowInfo("Reading configuration file %s...\n", cfgName); + while(fgets(line, sizeof(line), fp)) + { + if (line[0] == '/' && line[1] == '/') + continue; + + if (sscanf(line, "%[^:]: %[^\r\n]", w1, w2) < 2) + continue; + + if(!strcmpi(w1,"timestamp_format")) + strncpy(timestamp_format, w2, 20); + else if(!strcmpi(w1,"stdout_with_ansisequence")) + stdout_with_ansisequence = config_switch(w2); + else if(!strcmpi(w1,"console_silent")) { + ShowInfo("Console Silent Setting: %d\n", atoi(w2)); + msg_silent = atoi(w2); + } + else if( !strcmpi(w1, "bind_ip") ) { + char ip_str[16]; + login_config.login_ip = host2ip(w2); + if( login_config.login_ip ) + ShowStatus("Login server binding IP address : %s -> %s\n", w2, ip2str(login_config.login_ip, ip_str)); + } + else if( !strcmpi(w1, "login_port") ) { + login_config.login_port = (uint16)atoi(w2); + ShowStatus("set login_port : %s\n",w2); + } + else if(!strcmpi(w1, "log_login")) + login_config.log_login = (bool)config_switch(w2); + + else if (strcmpi(w1, "admin_state") == 0) { + admin_state = (bool)config_switch(w2); + } else if (strcmpi(w1, "admin_pass") == 0) { + memset(admin_pass, 0, sizeof(admin_pass)); + strncpy(admin_pass, w2, sizeof(admin_pass)); + admin_pass[sizeof(admin_pass)-1] = '\0'; + } else if (strcmpi(w1, "admin_allowed_ip") == 0) + admin_allowed_ip = host2ip(w2); + else if (strcmpi(w1, "account_filename") == 0) { + memset(account_filename, 0, sizeof(account_filename)); + strncpy(account_filename, w2, sizeof(account_filename)); + account_filename[sizeof(account_filename)-1] = '\0'; + } else if (strcmpi(w1, "gm_account_filename") == 0) { + memset(GM_account_filename, 0, sizeof(GM_account_filename)); + strncpy(GM_account_filename, w2, sizeof(GM_account_filename)); + GM_account_filename[sizeof(GM_account_filename)-1] = '\0'; + } + else if (strcmpi(w1, "gm_account_filename_check_timer") == 0) + gm_account_filename_check_timer = atoi(w2); + + else if(!strcmpi(w1, "new_account")) + login_config.new_account_flag = (bool)config_switch(w2); + else if(!strcmpi(w1, "start_limited_time")) + login_config.start_limited_time = atoi(w2); + else if(!strcmpi(w1, "check_client_version")) + login_config.check_client_version = (bool)config_switch(w2); + else if(!strcmpi(w1, "client_version_to_connect")) + login_config.client_version_to_connect = atoi(w2); + else if(!strcmpi(w1, "use_MD5_passwords")) + login_config.use_md5_passwds = (bool)config_switch(w2); + else if(!strcmpi(w1, "min_level_to_connect")) + login_config.min_level_to_connect = atoi(w2); + else if(!strcmpi(w1, "date_format")) + safestrncpy(login_config.date_format, w2, sizeof(login_config.date_format)); + else if(!strcmpi(w1, "console")) + login_config.console = (bool)config_switch(w2); +// else if(!strcmpi(w1, "case_sensitive")) +// login_config.case_sensitive = config_switch(w2); + else if(!strcmpi(w1, "allowed_regs")) //account flood protection system + allowed_regs = atoi(w2); + else if(!strcmpi(w1, "time_allowed")) + time_allowed = atoi(w2); + else if(!strcmpi(w1, "online_check")) + login_config.online_check = (bool)config_switch(w2); + else if(!strcmpi(w1, "use_dnsbl")) + login_config.use_dnsbl = (bool)config_switch(w2); + else if(!strcmpi(w1, "dnsbl_servers")) + safestrncpy(login_config.dnsbl_servs, w2, sizeof(login_config.dnsbl_servs)); + else if(!strcmpi(w1, "ip_sync_interval")) + login_config.ip_sync_interval = (unsigned int)1000*60*atoi(w2); //w2 comes in minutes. + else if(!strcmpi(w1, "import")) + login_config_read(w2); + } + fclose(fp); + ShowInfo("Finished reading %s.\n", cfgName); + return 0; +} + +//------------------------------------- +// Displaying of configuration warnings +//------------------------------------- +void display_conf_warnings(void) +{ + if( admin_state ) { + if (admin_pass[0] == '\0') { + ShowWarning("Administrator password is void (admin_pass).\n"); + } else if (strcmp(admin_pass, "admin") == 0) { + ShowWarning("You are using the default administrator password (admin_pass).\n"); + ShowWarning(" We highly recommend that you change it.\n"); + } + } + + if (gm_account_filename_check_timer < 0) { + ShowWarning("Invalid value for gm_account_filename_check_timer parameter. Setting to 15 sec (default).\n"); + gm_account_filename_check_timer = 15; + } else if (gm_account_filename_check_timer == 1) { + ShowWarning("Invalid value for gm_account_filename_check_timer parameter. Setting to 2 sec (minimum value).\n"); + gm_account_filename_check_timer = 2; + } + + if (login_config.min_level_to_connect < 0) { // 0: all players, 1-99 at least gm level x + ShowWarning("Invalid value for min_level_to_connect (%d) parameter -> setting 0 (any player).\n", login_config.min_level_to_connect); + login_config.min_level_to_connect = 0; + } else if (login_config.min_level_to_connect > 99) { // 0: all players, 1-99 at least gm level x + ShowWarning("Invalid value for min_level_to_connect (%d) parameter -> setting to 99 (only GM level 99)\n", login_config.min_level_to_connect); + login_config.min_level_to_connect = 99; + } + + if (login_config.start_limited_time < -1) { // -1: create unlimited account, 0 or more: additionnal sec from now to create limited time + ShowWarning("Invalid value for start_limited_time parameter\n"); + ShowWarning(" -> setting to -1 (new accounts are created with unlimited time).\n"); + login_config.start_limited_time = -1; + } + + return; +} + +void login_set_defaults() +{ + login_config.login_ip = INADDR_ANY; + login_config.login_port = 6900; + login_config.ip_sync_interval = 0; + login_config.log_login = true; + safestrncpy(login_config.date_format, "%Y-%m-%d %H:%M:%S", sizeof(login_config.date_format)); + login_config.console = false; + login_config.new_account_flag = true; +// login_config.case_sensitive = true; + login_config.use_md5_passwds = false; +// login_config.login_gm_read = true; + login_config.min_level_to_connect = 0; + login_config.online_check = true; + login_config.check_client_version = false; + login_config.client_version_to_connect = 20; + +// login_config.ipban = true; +// login_config.dynamic_pass_failure_ban = true; +// login_config.dynamic_pass_failure_ban_interval = 5; +// login_config.dynamic_pass_failure_ban_limit = 7; +// login_config.dynamic_pass_failure_ban_duration = 5; + login_config.use_dnsbl = false; + safestrncpy(login_config.dnsbl_servs, "", sizeof(login_config.dnsbl_servs)); +} + +//-------------------------------------- +// Function called at exit of the server +//-------------------------------------- +void do_final(void) +{ + int i, fd; + ShowStatus("Terminating...\n"); + + mmo_auth_sync(); + online_db->destroy(online_db, NULL); + auth_db->destroy(auth_db, NULL); + + if(auth_dat) aFree(auth_dat); + if(gm_account_db) aFree(gm_account_db); + + for (i = 0; i < MAX_SERVERS; i++) { + if ((fd = server[i].fd) >= 0) { + memset(&server[i], 0, sizeof(struct mmo_char_server)); + server[i].fd = -1; + do_close(fd); + } + } + do_close(login_fd); + + ShowStatus("Finished.\n"); +} + +//------------------------------ +// Function called when the server +// has received a crash signal. +//------------------------------ +void do_abort(void) +{ +} + +void set_server_type(void) +{ + SERVER_TYPE = ATHENA_SERVER_LOGIN; +} + +//------------------------------ +// Login server initialization +//------------------------------ +int do_init(int argc, char** argv) +{ + int i; + + login_set_defaults(); + + // read login-server configuration + login_config_read((argc > 1) ? argv[1] : LOGIN_CONF_NAME); + display_conf_warnings(); // not in login_config_read, because we can use 'import' option, and display same message twice or more + login_lan_config_read((argc > 2) ? argv[2] : LAN_CONF_NAME); + + srand((unsigned int)time(NULL)); + + for( i = 0; i < MAX_SERVERS; i++ ) + server[i].fd = -1; + + // Accounts database init + mmo_auth_init(); + + // Online user database init + online_db = idb_alloc(DB_OPT_RELEASE_DATA); + add_timer_func_list(waiting_disconnect_timer, "waiting_disconnect_timer"); + + // Interserver auth init + auth_db = idb_alloc(DB_OPT_RELEASE_DATA); + + // Read account information. + read_gm_account(); + + // set default parser as parse_login function + set_defaultparse(parse_login); + + add_timer_func_list(check_auth_sync, "check_auth_sync"); + add_timer_interval(gettick() + 60000, check_auth_sync, 0, 0, 60000); // every 60 sec we check if we must save accounts file (only if necessary to save) + + // every x sec we check if gm file has been changed + if( gm_account_filename_check_timer ) { + add_timer_func_list(check_GM_file, "check_GM_file"); + add_timer_interval(gettick() + gm_account_filename_check_timer * 1000, check_GM_file, 0, 0, gm_account_filename_check_timer * 1000); + } + + // every 10 minutes cleanup online account db. + add_timer_func_list(online_data_cleanup, "online_data_cleanup"); + add_timer_interval(gettick() + 600*1000, online_data_cleanup, 0, 0, 600*1000); + + // add timer to detect ip address change and perform update + if (login_config.ip_sync_interval) { + add_timer_func_list(sync_ip_addresses, "sync_ip_addresses"); + add_timer_interval(gettick() + login_config.ip_sync_interval, sync_ip_addresses, 0, 0, login_config.ip_sync_interval); + } + + if( login_config.console ) + { + //##TODO invoke a CONSOLE_START plugin event + } + + new_reg_tick = gettick(); + + // server port open & binding + login_fd = make_listen_bind(login_config.login_ip, login_config.login_port); + + ShowStatus("The login-server is "CL_GREEN"ready"CL_RESET" (Server is listening on the port %u).\n\n", login_config.login_port); + + return 0; +} diff --git a/src/login/login.h b/src/login/login.h new file mode 100644 index 000000000..1147d6bb6 --- /dev/null +++ b/src/login/login.h @@ -0,0 +1,94 @@ +// Copyright (c) Athena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + +#ifndef _LOGIN_H_ +#define _LOGIN_H_ + +#include "../common/mmo.h" // NAME_LENGTH + +#define LOGIN_CONF_NAME "conf/login_athena.conf" +#define LAN_CONF_NAME "conf/subnet_athena.conf" + +// supported encryption types: 1- passwordencrypt, 2- passwordencrypt2, 3- both +#define PASSWORDENC 3 + +struct login_session_data { + + int account_id; + long login_id1; + long login_id2; + char sex; + + char userid[NAME_LENGTH]; + char passwd[NAME_LENGTH]; + int passwdenc; + char md5key[20]; + uint16 md5keylen; + + char lastlogin[24]; + uint8 level; + int version; + + int fd; +}; + +struct mmo_char_server { + + char name[20]; + int fd; + uint32 ip; + uint16 port; + uint16 users; // user count on this server + uint16 maintenance; // in maintenance mode? + uint16 new_; // allows creating new chars? +}; + +struct Login_Config { + + uint32 login_ip; // the address to bind to + uint16 login_port; // the port to bind to + unsigned int ip_sync_interval; // interval (in minutes) to execute a DNS/IP update (for dynamic IPs) + bool log_login; // whether to log login server actions or not + char date_format[32]; // date format used in messages + bool console; // console input system enabled? + bool new_account_flag; // autoregistration via _M/_F ? + int start_limited_time; // new account expiration time (-1: unlimited) +// bool case_sensitive; // are logins case sensitive ? + bool use_md5_passwds; // work with password hashes instead of plaintext passwords? +// bool login_gm_read; // should the login server handle info about gm accounts? + int min_level_to_connect; // minimum level of player/GM (0: player, 1-99: GM) to connect + bool online_check; // reject incoming players that are already registered as online ? + bool check_client_version; // check the clientversion set in the clientinfo ? + int client_version_to_connect; // the client version needed to connect (if checking is enabled) + +// bool ipban; // perform IP blocking (via contents of `ipbanlist`) ? +// bool dynamic_pass_failure_ban; // automatic IP blocking due to failed login attemps ? +// unsigned int dynamic_pass_failure_ban_interval; // how far to scan the loginlog for password failures +// unsigned int dynamic_pass_failure_ban_limit; // number of failures needed to trigger the ipban +// unsigned int dynamic_pass_failure_ban_duration; // duration of the ipban + bool use_dnsbl; // dns blacklist blocking ? + char dnsbl_servs[1024]; // comma-separated list of dnsbl servers + +}; + +struct mmo_account { + + int account_id; + char sex; + char userid[24]; + char pass[32+1]; // 23+1 for normal, 32+1 for md5-ed passwords + char lastlogin[24]; + int logincount; + uint32 state; // packet 0x006a value + 1 (0: compte OK) + char email[40]; // e-mail (by default: a@a.com) + char error_message[20]; // Message of error code #6 = Your are Prohibited to log in until %s (packet 0x006a) + time_t unban_time; // # of seconds 1/1/1970 (timestamp): ban time limit of the account (0 = no ban) + time_t expiration_time; // # of seconds 1/1/1970 (timestamp): Validity limit of the account (0 = unlimited) + char last_ip[16]; // save of last IP of connection + char memo[255]; // a memo field + int account_reg2_num; + struct global_reg account_reg2[ACCOUNT_REG2_NUM]; // account script variables (stored on login server) +}; + + +#endif /* _LOGIN_H_ */ -- cgit v1.2.3-70-g09d2 From 5156c90c4d5fccf52fe42f72d143623bcd025c33 Mon Sep 17 00:00:00 2001 From: ultramage Date: Sat, 12 Apr 2008 09:19:31 +0000 Subject: ... but not with a buggy tool (missing svn:props) git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@12574 54d463be-8e91-2dee-dedb-b68131a5f0ec --- src/char/Makefile.in | 94 +++++++++++++++++++++++++-------------------------- src/login/Makefile.in | 92 ++++++++++++++++++++++++------------------------- 2 files changed, 93 insertions(+), 93 deletions(-) (limited to 'src/char/Makefile.in') diff --git a/src/char/Makefile.in b/src/char/Makefile.in index 7835daa7f..37b464991 100644 --- a/src/char/Makefile.in +++ b/src/char/Makefile.in @@ -1,47 +1,47 @@ - -COMMON_OBJ = ../common/obj_all/core.o ../common/obj_all/socket.o ../common/obj_all/timer.o \ - ../common/obj_all/db.o ../common/obj_all/plugins.o ../common/obj_all/lock.o \ - ../common/obj_all/malloc.o ../common/obj_all/showmsg.o ../common/obj_all/utils.o \ - ../common/obj_all/strlib.o ../common/obj_all/grfio.o \ - ../common/obj_all/mapindex.o ../common/obj_all/ers.o -COMMON_H = ../common/core.h ../common/socket.h ../common/timer.h ../common/mmo.h \ - ../common/version.h ../common/db.h ../common/plugins.h ../common/lock.h \ - ../common/malloc.h ../common/showmsg.h ../common/utils.h \ - ../common/strlib.h ../common/grfio.h \ - ../common/mapindex.h ../common/ers.h - -CHAR_OBJ = obj_txt/char.o obj_txt/inter.o obj_txt/int_party.o obj_txt/int_guild.o \ - obj_txt/int_storage.o obj_txt/int_status.o obj_txt/int_pet.o obj_txt/int_homun.o -CHAR_H = char.h inter.h int_party.h int_guild.h int_storage.h int_status.h int_pet.h int_homun.h - -@SET_MAKE@ - -##################################################################### -.PHONY : all char-server clean help - -all: char-server - -char-server: obj_txt $(CHAR_OBJ) $(COMMON_OBJ) - @CC@ @LDFLAGS@ -o ../../char-server@EXEEXT@ $(CHAR_OBJ) $(COMMON_OBJ) @LIBS@ - -clean: - rm -rf *.o obj_txt ../../char-server@EXEEXT@ - -help: - @echo "possible targets are 'char-server' 'all' 'clean' 'help'" - @echo "'char-server' - char server (TXT version)" - @echo "'all' - builds all above targets" - @echo "'clean' - cleans builds and objects" - @echo "'help' - outputs this message" - -##################################################################### - -obj_txt: - -mkdir obj_txt - -obj_txt/%.o: %.c $(CHAR_H) $(COMMON_H) - @CC@ @CFLAGS@ $(CUSTOM_CFLAGS) -DTXT_ONLY @CPPFLAGS@ -c $(OUTPUT_OPTION) $< - -# missing common object files -../common/obj_all/%.o: - @$(MAKE) -C ../common txt + +COMMON_OBJ = ../common/obj_all/core.o ../common/obj_all/socket.o ../common/obj_all/timer.o \ + ../common/obj_all/db.o ../common/obj_all/plugins.o ../common/obj_all/lock.o \ + ../common/obj_all/malloc.o ../common/obj_all/showmsg.o ../common/obj_all/utils.o \ + ../common/obj_all/strlib.o ../common/obj_all/grfio.o \ + ../common/obj_all/mapindex.o ../common/obj_all/ers.o +COMMON_H = ../common/core.h ../common/socket.h ../common/timer.h ../common/mmo.h \ + ../common/version.h ../common/db.h ../common/plugins.h ../common/lock.h \ + ../common/malloc.h ../common/showmsg.h ../common/utils.h \ + ../common/strlib.h ../common/grfio.h \ + ../common/mapindex.h ../common/ers.h + +CHAR_OBJ = obj_txt/char.o obj_txt/inter.o obj_txt/int_party.o obj_txt/int_guild.o \ + obj_txt/int_storage.o obj_txt/int_status.o obj_txt/int_pet.o obj_txt/int_homun.o +CHAR_H = char.h inter.h int_party.h int_guild.h int_storage.h int_status.h int_pet.h int_homun.h + +@SET_MAKE@ + +##################################################################### +.PHONY : all char-server clean help + +all: char-server + +char-server: obj_txt $(CHAR_OBJ) $(COMMON_OBJ) + @CC@ @LDFLAGS@ -o ../../char-server@EXEEXT@ $(CHAR_OBJ) $(COMMON_OBJ) @LIBS@ + +clean: + rm -rf *.o obj_txt ../../char-server@EXEEXT@ + +help: + @echo "possible targets are 'char-server' 'all' 'clean' 'help'" + @echo "'char-server' - char server (TXT version)" + @echo "'all' - builds all above targets" + @echo "'clean' - cleans builds and objects" + @echo "'help' - outputs this message" + +##################################################################### + +obj_txt: + -mkdir obj_txt + +obj_txt/%.o: %.c $(CHAR_H) $(COMMON_H) + @CC@ @CFLAGS@ $(CUSTOM_CFLAGS) -DTXT_ONLY @CPPFLAGS@ -c $(OUTPUT_OPTION) $< + +# missing common object files +../common/obj_all/%.o: + @$(MAKE) -C ../common txt diff --git a/src/login/Makefile.in b/src/login/Makefile.in index b87bd9e70..aeb41b667 100644 --- a/src/login/Makefile.in +++ b/src/login/Makefile.in @@ -1,46 +1,46 @@ - -COMMON_OBJ = ../common/obj_all/core.o ../common/obj_all/socket.o ../common/obj_all/timer.o \ - ../common/obj_all/db.o ../common/obj_all/plugins.o ../common/obj_all/lock.o \ - ../common/obj_all/malloc.o ../common/obj_all/showmsg.o ../common/obj_all/utils.o \ - ../common/obj_all/strlib.o ../common/obj_all/grfio.o ../common/obj_all/mapindex.o \ - ../common/obj_all/ers.o ../common/obj_all/md5calc.o -COMMON_H = ../common/core.h ../common/socket.h ../common/timer.h ../common/mmo.h \ - ../common/version.h ../common/db.h ../common/plugins.h ../common/lock.h \ - ../common/malloc.h ../common/showmsg.h ../common/utils.h ../common/strlib.h \ - ../common/grfio.h ../common/mapindex.h \ - ../common/ers.h ../common/md5calc.h - -LOGIN_OBJ = obj_txt/login.o obj_txt/admin.o -LOGIN_H = login.h - -@SET_MAKE@ - -##################################################################### -.PHONY : all login-server clean help - -all: login-server - -login-server: obj_txt $(LOGIN_OBJ) $(COMMON_OBJ) - @CC@ @LDFLAGS@ -o ../../login-server@EXEEXT@ $(LOGIN_OBJ) $(COMMON_OBJ) @LIBS@ - -clean: - rm -rf *.o obj_txt ../../login-server@EXEEXT@ - -help: - @echo "possible targets are 'login-server' 'all' 'clean' 'help'" - @echo "'login-server' - login server (TXT version)" - @echo "'all' - builds all above targets" - @echo "'clean' - cleans builds and objects" - @echo "'help' - outputs this message" - -##################################################################### - -obj_txt: - -mkdir obj_txt - -obj_txt/%.o: %.c $(LOGIN_H) $(COMMON_H) - @CC@ @CFLAGS@ $(CUSTOM_CFLAGS) -DTXT_ONLY @CPPFLAGS@ -c $(OUTPUT_OPTION) $< - -# missing common object files -../common/obj_all/%.o: - @$(MAKE) -C ../common sql + +COMMON_OBJ = ../common/obj_all/core.o ../common/obj_all/socket.o ../common/obj_all/timer.o \ + ../common/obj_all/db.o ../common/obj_all/plugins.o ../common/obj_all/lock.o \ + ../common/obj_all/malloc.o ../common/obj_all/showmsg.o ../common/obj_all/utils.o \ + ../common/obj_all/strlib.o ../common/obj_all/grfio.o ../common/obj_all/mapindex.o \ + ../common/obj_all/ers.o ../common/obj_all/md5calc.o +COMMON_H = ../common/core.h ../common/socket.h ../common/timer.h ../common/mmo.h \ + ../common/version.h ../common/db.h ../common/plugins.h ../common/lock.h \ + ../common/malloc.h ../common/showmsg.h ../common/utils.h ../common/strlib.h \ + ../common/grfio.h ../common/mapindex.h \ + ../common/ers.h ../common/md5calc.h + +LOGIN_OBJ = obj_txt/login.o obj_txt/admin.o +LOGIN_H = login.h + +@SET_MAKE@ + +##################################################################### +.PHONY : all login-server clean help + +all: login-server + +login-server: obj_txt $(LOGIN_OBJ) $(COMMON_OBJ) + @CC@ @LDFLAGS@ -o ../../login-server@EXEEXT@ $(LOGIN_OBJ) $(COMMON_OBJ) @LIBS@ + +clean: + rm -rf *.o obj_txt ../../login-server@EXEEXT@ + +help: + @echo "possible targets are 'login-server' 'all' 'clean' 'help'" + @echo "'login-server' - login server (TXT version)" + @echo "'all' - builds all above targets" + @echo "'clean' - cleans builds and objects" + @echo "'help' - outputs this message" + +##################################################################### + +obj_txt: + -mkdir obj_txt + +obj_txt/%.o: %.c $(LOGIN_H) $(COMMON_H) + @CC@ @CFLAGS@ $(CUSTOM_CFLAGS) -DTXT_ONLY @CPPFLAGS@ -c $(OUTPUT_OPTION) $< + +# missing common object files +../common/obj_all/%.o: + @$(MAKE) -C ../common sql -- cgit v1.2.3-70-g09d2 From c3c74c3bcbb9792ec60106443adc6bd790cfec1f Mon Sep 17 00:00:00 2001 From: ultramage Date: Thu, 31 Jul 2008 06:08:07 +0000 Subject: Reverted r12230. cUSTOM_CFLAGS is redundant since you can achieve the same result by setting CFLAGS. git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@13022 54d463be-8e91-2dee-dedb-b68131a5f0ec --- src/char/Makefile.in | 2 +- src/char_sql/Makefile.in | 2 +- src/common/Makefile.in | 6 +++--- src/ladmin/Makefile.in | 2 +- src/login/Makefile.in | 4 ++-- src/map/Makefile.in | 4 ++-- src/plugins/Makefile.in | 2 +- 7 files changed, 11 insertions(+), 11 deletions(-) (limited to 'src/char/Makefile.in') diff --git a/src/char/Makefile.in b/src/char/Makefile.in index 37b464991..359e19b01 100644 --- a/src/char/Makefile.in +++ b/src/char/Makefile.in @@ -40,7 +40,7 @@ obj_txt: -mkdir obj_txt obj_txt/%.o: %.c $(CHAR_H) $(COMMON_H) - @CC@ @CFLAGS@ $(CUSTOM_CFLAGS) -DTXT_ONLY @CPPFLAGS@ -c $(OUTPUT_OPTION) $< + @CC@ @CFLAGS@ -DTXT_ONLY @CPPFLAGS@ -c $(OUTPUT_OPTION) $< # missing common object files ../common/obj_all/%.o: diff --git a/src/char_sql/Makefile.in b/src/char_sql/Makefile.in index 63a53e9af..a36dcd14b 100644 --- a/src/char_sql/Makefile.in +++ b/src/char_sql/Makefile.in @@ -54,7 +54,7 @@ obj_sql: -mkdir obj_sql obj_sql/%.o: %.c $(CHAR_H) $(COMMON_H) $(COMMON_SQL_H) - @CC@ @CFLAGS@ $(CUSTOM_CFLAGS) @MYSQL_CFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $< + @CC@ @CFLAGS@ @MYSQL_CFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $< # missing common object files ../common/obj_all/%.o: diff --git a/src/common/Makefile.in b/src/common/Makefile.in index 75450f46a..bda9e1911 100644 --- a/src/common/Makefile.in +++ b/src/common/Makefile.in @@ -60,13 +60,13 @@ common_sql: obj_sql $(COMMON_SQL_OBJ) obj_all/%.o: %.c $(COMMON_H) - @CC@ @CFLAGS@ $(CUSTOM_CFLAGS) @LDFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $< + @CC@ @CFLAGS@ @LDFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $< obj_all/mini%.o: %.c $(COMMON_H) - @CC@ @CFLAGS@ $(CUSTOM_CFLAGS) -DMINICORE @LDFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $< + @CC@ @CFLAGS@ -DMINICORE @LDFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $< obj_sql/%.o: %.c $(COMMON_H) $(COMMON_SQL_H) - @CC@ @CFLAGS@ $(CUSTOM_CFLAGS) @MYSQL_CFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $< + @CC@ @CFLAGS@ @MYSQL_CFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $< HAVESVN = $(shell which svnversion) diff --git a/src/ladmin/Makefile.in b/src/ladmin/Makefile.in index 365252f63..4703dded1 100644 --- a/src/ladmin/Makefile.in +++ b/src/ladmin/Makefile.in @@ -35,7 +35,7 @@ obj_all: -mkdir obj_all obj_all/%.o: %.c $(LADMIN_H) $(COMMON_H) - @CC@ @CFLAGS@ $(CUSTOM_CFLAGS) @LDFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $< + @CC@ @CFLAGS@ @LDFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $< # missing common object files ../common/obj_all/%.o: diff --git a/src/login/Makefile.in b/src/login/Makefile.in index 1f6080746..611ca385b 100644 --- a/src/login/Makefile.in +++ b/src/login/Makefile.in @@ -71,10 +71,10 @@ login-server_sql: $(LOGIN_SERVER_SQL_DEPENDS) # login object files obj_txt/%.o: %.c $(LOGIN_H) $(COMMON_H) - @CC@ @CFLAGS@ $(CUSTOM_CFLAGS) -DWITH_TXT @CPPFLAGS@ -c $(OUTPUT_OPTION) $< + @CC@ @CFLAGS@ -DWITH_TXT @CPPFLAGS@ -c $(OUTPUT_OPTION) $< obj_sql/%.o: %.c $(LOGIN_H) $(COMMON_H) - @CC@ @CFLAGS@ $(CUSTOM_CFLAGS) -DWITH_SQL @MYSQL_CFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $< + @CC@ @CFLAGS@ -DWITH_SQL @MYSQL_CFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $< # missing common object files ../common/obj_all/%.o: diff --git a/src/map/Makefile.in b/src/map/Makefile.in index ba2f3effd..61e41797e 100644 --- a/src/map/Makefile.in +++ b/src/map/Makefile.in @@ -90,10 +90,10 @@ map-server_sql: obj_sql $(MAP_SQL_OBJ) $(COMMON_OBJ) $(COMMON_SQL_OBJ) # map object files obj_txt/%.o: %.c $(MAP_H) $(COMMON_H) - @CC@ @CFLAGS@ $(PCRE_CFLAGS) $(CUSTOM_CFLAGS) -DTXT_ONLY @CPPFLAGS@ -c $(OUTPUT_OPTION) $< + @CC@ @CFLAGS@ $(PCRE_CFLAGS) -DTXT_ONLY @CPPFLAGS@ -c $(OUTPUT_OPTION) $< obj_sql/%.o: %.c $(MAP_H) $(COMMON_H) $(COMMON_SQL_H) - @CC@ @CFLAGS@ $(PCRE_CFLAGS) $(CUSTOM_CFLAGS) @MYSQL_CFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $< + @CC@ @CFLAGS@ $(PCRE_CFLAGS) @MYSQL_CFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $< # missing common object files ../common/obj_all/%.o: diff --git a/src/plugins/Makefile.in b/src/plugins/Makefile.in index 6a902e1d7..c21bcd7d9 100644 --- a/src/plugins/Makefile.in +++ b/src/plugins/Makefile.in @@ -50,7 +50,7 @@ gui@DLLEXT@: ../../plugins/gui.conf upnp@DLLEXT@: ../../plugins/upnp.conf sig@DLLEXT@: sig.c $(COMMON_OBJ) - @CC@ @CFLAGS@ $(CUSTOM_CFLAGS) @CPPFLAGS@ @LDFLAGS@ -shared -o ../../plugins/$@ $< $(COMMON_OBJ) + @CC@ @CFLAGS@ @CPPFLAGS@ @LDFLAGS@ -shared -o ../../plugins/$@ $< $(COMMON_OBJ) ../../plugins/%.conf: %.txt cp -r $< $@ -- cgit v1.2.3-70-g09d2 From a9492cf82f696af37f3258e19d7767f705708e63 Mon Sep 17 00:00:00 2001 From: flaviojs Date: Mon, 27 Jun 2011 01:47:06 +0000 Subject: * Added common/random and 3rdparty/mt19937ar to project files, makefiles and configure script. git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@14870 54d463be-8e91-2dee-dedb-b68131a5f0ec --- 3rdparty/mt19937ar/Makefile.in | 24 ++++++++++++++++++++++++ Changelog-Trunk.txt | 2 ++ Makefile.in | 32 +++++++++++++++++++++----------- configure | 4 +++- configure.in | 1 + src/char/Makefile.in | 21 ++++++++++++++------- src/char_sql/Makefile.in | 21 ++++++++++++++------- src/common/Makefile.in | 25 +++++++++++++++++-------- src/login/Makefile.in | 33 ++++++++++++++++++++++----------- src/map/Makefile.in | 30 ++++++++++++++++++++---------- vcproj-10/char-server_sql.vcxproj | 8 ++++++-- vcproj-10/char-server_txt.vcxproj | 8 ++++++-- vcproj-10/login-server_sql.vcxproj | 8 ++++++-- vcproj-10/login-server_txt.vcxproj | 8 ++++++-- vcproj-10/map-server_sql.vcxproj | 8 ++++++-- vcproj-10/map-server_txt.vcxproj | 8 ++++++-- vcproj-6/char-server_sql.dsp | 24 ++++++++++++++++++++++-- vcproj-6/char-server_txt.dsp | 24 ++++++++++++++++++++++-- vcproj-6/login-server_sql.dsp | 24 ++++++++++++++++++++++-- vcproj-6/login-server_txt.dsp | 24 ++++++++++++++++++++++-- vcproj-6/map-server_sql.dsp | 24 ++++++++++++++++++++++-- vcproj-6/map-server_txt.dsp | 24 ++++++++++++++++++++++-- vcproj-7.1/char-server_sql.vcproj | 20 ++++++++++++++++++-- vcproj-7.1/char-server_txt.vcproj | 20 ++++++++++++++++++-- vcproj-7.1/login-server_sql.vcproj | 20 ++++++++++++++++++-- vcproj-7.1/login-server_txt.vcproj | 20 ++++++++++++++++++-- vcproj-7.1/map-server_sql.vcproj | 20 ++++++++++++++++++-- vcproj-7.1/map-server_txt.vcproj | 20 ++++++++++++++++++-- vcproj-8/char-server_sql.vcproj | 24 ++++++++++++++++++++++-- vcproj-8/char-server_txt.vcproj | 24 ++++++++++++++++++++++-- vcproj-8/login-server_sql.vcproj | 24 ++++++++++++++++++++++-- vcproj-8/login-server_txt.vcproj | 24 ++++++++++++++++++++++-- vcproj-8/map-server_sql.vcproj | 24 ++++++++++++++++++++++-- vcproj-8/map-server_txt.vcproj | 24 ++++++++++++++++++++++-- vcproj-9/char-server_sql.vcproj | 24 ++++++++++++++++++++++-- vcproj-9/char-server_txt.vcproj | 24 ++++++++++++++++++++++-- vcproj-9/login-server_sql.vcproj | 24 ++++++++++++++++++++++-- vcproj-9/login-server_txt.vcproj | 24 ++++++++++++++++++++++-- vcproj-9/map-server_sql.vcproj | 24 ++++++++++++++++++++++-- vcproj-9/map-server_txt.vcproj | 24 ++++++++++++++++++++++-- 40 files changed, 678 insertions(+), 115 deletions(-) create mode 100644 3rdparty/mt19937ar/Makefile.in (limited to 'src/char/Makefile.in') diff --git a/3rdparty/mt19937ar/Makefile.in b/3rdparty/mt19937ar/Makefile.in new file mode 100644 index 000000000..7cae3140b --- /dev/null +++ b/3rdparty/mt19937ar/Makefile.in @@ -0,0 +1,24 @@ + +MT19937AR_OBJ = mt19937ar.o +MT19937AR_H = mt19937ar.h + +@SET_MAKE@ + +##################################################################### +.PHONY : all clean help + +all: $(MT19937AR_OBJ) + +clean: + rm -rf *.o + +help: + @echo "possible targets are 'all' 'clean' 'help'" + @echo "'all' - builds $(MT19937AR_OBJ)" + @echo "'clean' - deletes $(MT19937AR_OBJ)" + @echo "'help' - outputs this message" + +##################################################################### + +%.o: %.c $(MT19937AR_H) + @CC@ @CFLAGS@ @LDFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $< diff --git a/Changelog-Trunk.txt b/Changelog-Trunk.txt index 65cc02c9d..02b9688fd 100644 --- a/Changelog-Trunk.txt +++ b/Changelog-Trunk.txt @@ -1,5 +1,7 @@ Date Added +2011/06/27 + *Added common/random and 3rdparty/mt19937ar to project files, makefiles and configure script. [FlavioJS] 2011/06/26 * Fixed a signed literal being assigned to an unsigned variable and other minor cleanups in malloc (bugreport:4765). [Ai4rei] * Fixed @mobinfo displaying mvp rewards with 'AegisName' although normal drops use 'Name' item db column (bugreport:4981, follow up to r6346). [Ai4rei] diff --git a/Makefile.in b/Makefile.in index 667b79fbc..ea3106317 100644 --- a/Makefile.in +++ b/Makefile.in @@ -2,15 +2,15 @@ HAVE_MYSQL=@HAVE_MYSQL@ ifeq ($(HAVE_MYSQL),yes) - ALL_DEPENDS=common common_sql login login_sql char char_sql map map_sql tools converters import save - SQL_DEPENDS=common_sql login_sql char_sql map_sql import save - COMMON_SQL_DEPENDS= - LOGIN_SQL_DEPENDS=common_sql - CHAR_SQL_DEPENDS=common_sql - MAP_SQL_DEPENDS=common_sql + ALL_DEPENDS=mt19937ar common common_sql login login_sql char char_sql map map_sql tools converters import save + SQL_DEPENDS=mt19937ar common_sql login_sql char_sql map_sql import save + COMMON_SQL_DEPENDS=mt19937ar + LOGIN_SQL_DEPENDS=mt19937ar common_sql + CHAR_SQL_DEPENDS=mt19937ar common_sql + MAP_SQL_DEPENDS=mt19937ar common_sql CONVERTERS_DEPENDS=common_sql else - ALL_DEPENDS=common login char map tools import save + ALL_DEPENDS=mt19937ar common login char map tools import save SQL_DEPENDS=needs_mysql COMMON_SQL_DEPENDS=needs_mysql LOGIN_SQL_DEPENDS=needs_mysql @@ -18,6 +18,10 @@ else MAP_SQL_DEPENDS=needs_mysql CONVERTERS_DEPENDS=needs_mysql endif +COMMON_TXT_DEPENDS=mt19937ar +LOGIN_TXT_DEPENDS=mt19937ar common +CHAR_TXT_DEPENDS=mt19937ar common +MAP_TXT_DEPENDS=mt19937ar common WITH_PLUGINS=@WITH_PLUGINS@ ifeq ($(WITH_PLUGINS),yes) @@ -30,6 +34,7 @@ endif ##################################################################### .PHONY: txt sql conf \ common common_sql \ + mt19937ar \ login login_sql \ char char_sql \ map map_sql \ @@ -44,25 +49,28 @@ sql: $(SQL_DEPENDS) conf: import save -common: +common: $(COMMON_TXT_DEPENDS) @$(MAKE) -C src/common txt common_sql: $(COMMON_SQL_DEPENDS) @$(MAKE) -C src/common sql -login: common +mt19937ar: + @$(MAKE) -C 3rdparty/mt19937ar + +login: $(LOGIN_TXT_DEPENDS) @$(MAKE) -C src/login txt login_sql: $(LOGIN_SQL_DEPENDS) @$(MAKE) -C src/login sql -char: common +char: $(CHAR_TXT_DEPENDS) @$(MAKE) -C src/char char_sql: $(CHAR_SQL_DEPENDS) @$(MAKE) -C src/char_sql -map: common +map: $(MAP_TXT_DEPENDS) @$(MAKE) -C src/map txt map_sql: $(MAP_SQL_DEPENDS) @@ -97,6 +105,7 @@ save: clean: @$(MAKE) -C src/common $@ + @$(MAKE) -C 3rdparty/mt19937ar $@ @$(MAKE) -C src/login $@ @$(MAKE) -C src/char $@ @$(MAKE) -C src/char_sql $@ @@ -110,6 +119,7 @@ help: @echo "possible targets are:" @echo "'common' - builds object files used in TXT servers" @echo "'common_sql' - builds object files used in SQL servers" + @echo "'mt19937ar' - builds object file of Mersenne Twister MT19937" @echo "'login' - builds login server (TXT version)" @echo "'login_sql' - builds login server (SQL version)" @echo "'char' - builds char server (TXT version)" diff --git a/configure b/configure index 9200993f7..fbc5e3a11 100755 --- a/configure +++ b/configure @@ -1,5 +1,5 @@ #! /bin/sh -# From configure.in Revision: 14767 . +# From configure.in Revision: 14870 . # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.59. # @@ -1333,6 +1333,8 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_config_files="$ac_config_files Makefile src/common/Makefile" + ac_config_files="$ac_config_files 3rdparty/mt19937ar/Makefile" + ac_config_files="$ac_config_files src/char/Makefile src/login/Makefile" ac_config_files="$ac_config_files src/char_sql/Makefile src/txt-converter/Makefile" diff --git a/configure.in b/configure.in index 6407cda1b..197a4a4ed 100644 --- a/configure.in +++ b/configure.in @@ -6,6 +6,7 @@ AC_REVISION($Revision$) AC_PREREQ([2.59]) AC_CONFIG_SRCDIR([src/common/cbasetypes.h]) AC_CONFIG_FILES([Makefile src/common/Makefile]) +AC_CONFIG_FILES([3rdparty/mt19937ar/Makefile]) AC_CONFIG_FILES([src/char/Makefile src/login/Makefile]) AC_CONFIG_FILES([src/char_sql/Makefile src/txt-converter/Makefile]) AC_CONFIG_FILES([src/map/Makefile src/plugins/Makefile src/tool/Makefile]) diff --git a/src/char/Makefile.in b/src/char/Makefile.in index 359e19b01..ba8f4fe64 100644 --- a/src/char/Makefile.in +++ b/src/char/Makefile.in @@ -3,12 +3,16 @@ COMMON_OBJ = ../common/obj_all/core.o ../common/obj_all/socket.o ../common/obj_a ../common/obj_all/db.o ../common/obj_all/plugins.o ../common/obj_all/lock.o \ ../common/obj_all/malloc.o ../common/obj_all/showmsg.o ../common/obj_all/utils.o \ ../common/obj_all/strlib.o ../common/obj_all/grfio.o \ - ../common/obj_all/mapindex.o ../common/obj_all/ers.o + ../common/obj_all/mapindex.o ../common/obj_all/ers.o ../common/obj_all/random.o COMMON_H = ../common/core.h ../common/socket.h ../common/timer.h ../common/mmo.h \ ../common/version.h ../common/db.h ../common/plugins.h ../common/lock.h \ ../common/malloc.h ../common/showmsg.h ../common/utils.h \ ../common/strlib.h ../common/grfio.h \ - ../common/mapindex.h ../common/ers.h + ../common/mapindex.h ../common/ers.h ../common/random.h + +MT19937AR_OBJ = ../../3rdparty/mt19937ar/mt19937ar.o +MT19937AR_H = ../../3rdparty/mt19937ar/mt19937ar.h +MT19937AR_INCLUDE = -I../../3rdparty/mt19937ar CHAR_OBJ = obj_txt/char.o obj_txt/inter.o obj_txt/int_party.o obj_txt/int_guild.o \ obj_txt/int_storage.o obj_txt/int_status.o obj_txt/int_pet.o obj_txt/int_homun.o @@ -21,8 +25,8 @@ CHAR_H = char.h inter.h int_party.h int_guild.h int_storage.h int_status.h int_p all: char-server -char-server: obj_txt $(CHAR_OBJ) $(COMMON_OBJ) - @CC@ @LDFLAGS@ -o ../../char-server@EXEEXT@ $(CHAR_OBJ) $(COMMON_OBJ) @LIBS@ +char-server: obj_txt $(CHAR_OBJ) $(COMMON_OBJ) $(MT19937AR_OBJ) + @CC@ @LDFLAGS@ -o ../../char-server@EXEEXT@ $(CHAR_OBJ) $(COMMON_OBJ) $(MT19937AR_OBJ) @LIBS@ clean: rm -rf *.o obj_txt ../../char-server@EXEEXT@ @@ -39,9 +43,12 @@ help: obj_txt: -mkdir obj_txt -obj_txt/%.o: %.c $(CHAR_H) $(COMMON_H) - @CC@ @CFLAGS@ -DTXT_ONLY @CPPFLAGS@ -c $(OUTPUT_OPTION) $< +obj_txt/%.o: %.c $(CHAR_H) $(COMMON_H) $(MT19937AR_H) + @CC@ @CFLAGS@ $(MT19937AR_INCLUDE) -DTXT_ONLY @CPPFLAGS@ -c $(OUTPUT_OPTION) $< -# missing common object files +# missing object files ../common/obj_all/%.o: @$(MAKE) -C ../common txt + +MT19937AR_OBJ: + @$(MAKE) -C ../../3rdparty/mt19937ar diff --git a/src/char_sql/Makefile.in b/src/char_sql/Makefile.in index 82c0a7c3f..a8cf8e08c 100644 --- a/src/char_sql/Makefile.in +++ b/src/char_sql/Makefile.in @@ -3,12 +3,16 @@ COMMON_OBJ = ../common/obj_all/core.o ../common/obj_all/socket.o ../common/obj_a ../common/obj_all/db.o ../common/obj_all/plugins.o ../common/obj_all/lock.o \ ../common/obj_all/malloc.o ../common/obj_all/showmsg.o ../common/obj_all/utils.o \ ../common/obj_all/strlib.o ../common/obj_all/grfio.o \ - ../common/obj_all/mapindex.o ../common/obj_all/ers.o + ../common/obj_all/mapindex.o ../common/obj_all/ers.o ../common/obj_all/random.o COMMON_H = ../common/core.h ../common/socket.h ../common/timer.h ../common/mmo.h \ ../common/version.h ../common/db.h ../common/plugins.h ../common/lock.h \ ../common/malloc.h ../common/showmsg.h ../common/utils.h \ ../common/strlib.h ../common/grfio.h \ - ../common/mapindex.h ../common/ers.h + ../common/mapindex.h ../common/ers.h ../common/random.h + +MT19937AR_OBJ = ../../3rdparty/mt19937ar/mt19937ar.o +MT19937AR_H = ../../3rdparty/mt19937ar/mt19937ar.h +MT19937AR_INCLUDE = -I../../3rdparty/mt19937ar COMMON_SQL_OBJ = ../common/obj_sql/sql.o COMMON_H = ../common/sql.h @@ -19,7 +23,7 @@ CHAR_H = char.h inter.h int_party.h int_guild.h int_storage.h int_pet.h int_homu HAVE_MYSQL=@HAVE_MYSQL@ ifeq ($(HAVE_MYSQL),yes) - CHAR_SERVER_SQL_DEPENDS=obj_sql $(CHAR_OBJ) $(COMMON_OBJ) $(COMMON_SQL_OBJ) + CHAR_SERVER_SQL_DEPENDS=obj_sql $(CHAR_OBJ) $(COMMON_OBJ) $(COMMON_SQL_OBJ) $(MT19937AR_OBJ) else CHAR_SERVER_SQL_DEPENDS=needs_mysql endif @@ -32,7 +36,7 @@ endif all: char-server_sql char-server_sql: $(CHAR_SERVER_SQL_DEPENDS) - @CC@ @LDFLAGS@ -o ../../char-server_sql@EXEEXT@ $(CHAR_OBJ) $(COMMON_OBJ) $(COMMON_SQL_OBJ) @LIBS@ @MYSQL_LIBS@ + @CC@ @LDFLAGS@ -o ../../char-server_sql@EXEEXT@ $(CHAR_OBJ) $(COMMON_OBJ) $(COMMON_SQL_OBJ) $(MT19937AR_OBJ) @LIBS@ @MYSQL_LIBS@ clean: rm -rf *.o obj_sql ../../char-server_sql@EXEEXT@ @@ -53,12 +57,15 @@ needs_mysql: obj_sql: -mkdir obj_sql -obj_sql/%.o: %.c $(CHAR_H) $(COMMON_H) $(COMMON_SQL_H) - @CC@ @CFLAGS@ @MYSQL_CFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $< +obj_sql/%.o: %.c $(CHAR_H) $(COMMON_H) $(COMMON_SQL_H) $(MT19937AR_H) + @CC@ @CFLAGS@ $(MT19937AR_INCLUDE) @MYSQL_CFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $< -# missing common object files +# missing object files ../common/obj_all/%.o: @$(MAKE) -C ../common sql ../common/obj_sql/%.o: @$(MAKE) -C ../common sql + +MT19937AR_OBJ: + @$(MAKE) -C ../../3rdparty/mt19937ar diff --git a/src/common/Makefile.in b/src/common/Makefile.in index bda9e1911..37606dde2 100644 --- a/src/common/Makefile.in +++ b/src/common/Makefile.in @@ -2,15 +2,19 @@ COMMON_OBJ = obj_all/core.o obj_all/socket.o obj_all/timer.o obj_all/db.o obj_all/plugins.o obj_all/lock.o \ obj_all/nullpo.o obj_all/malloc.o obj_all/showmsg.o obj_all/strlib.o obj_all/utils.o \ obj_all/grfio.o obj_all/mapindex.o obj_all/ers.o obj_all/md5calc.o \ - obj_all/minicore.o obj_all/minisocket.o obj_all/minimalloc.o + obj_all/minicore.o obj_all/minisocket.o obj_all/minimalloc.o obj_all/random.o COMMON_H = svnversion.h mmo.h plugin.h version.h \ core.h socket.h timer.h db.h plugins.h lock.h \ nullpo.h malloc.h showmsg.h strlib.h utils.h \ - grfio.h mapindex.h ers.h md5calc.h + grfio.h mapindex.h ers.h md5calc.h random.h COMMON_SQL_OBJ = obj_sql/sql.o COMMON_SQL_H = sql.h +MT19937AR_OBJ = ../../3rdparty/mt19937ar/mt19937ar.o +MT19937AR_H = ../../3rdparty/mt19937ar/mt19937ar.h +MT19937AR_INCLUDE = -I../../3rdparty/mt19937ar + HAVE_MYSQL=@HAVE_MYSQL@ ifeq ($(HAVE_MYSQL),yes) ALL_DEPENDS=txt sql @@ -19,6 +23,7 @@ else ALL_TARGET=txt SQL_DEPENDS=needs_mysql endif +TXT_DEPENDS=common @SET_MAKE@ @@ -27,7 +32,7 @@ endif all: $(ALL_DEPENDS) -txt: common +txt: $(TXT_DEPENDS) sql: $(SQL_DEPENDS) @@ -54,16 +59,16 @@ obj_all: obj_sql: -mkdir obj_sql -common: obj_all $(COMMON_OBJ) +common: obj_all $(COMMON_OBJ) $(MT19937AR_OBJ) common_sql: obj_sql $(COMMON_SQL_OBJ) -obj_all/%.o: %.c $(COMMON_H) - @CC@ @CFLAGS@ @LDFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $< +obj_all/%.o: %.c $(COMMON_H) $(MT19937AR_H) + @CC@ @CFLAGS@ $(MT19937AR_INCLUDE) @LDFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $< -obj_all/mini%.o: %.c $(COMMON_H) - @CC@ @CFLAGS@ -DMINICORE @LDFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $< +obj_all/mini%.o: %.c $(COMMON_H) $(MT19937AR_H) + @CC@ @CFLAGS@ $(MT19937AR_INCLUDE) -DMINICORE @LDFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $< obj_sql/%.o: %.c $(COMMON_H) $(COMMON_SQL_H) @CC@ @CFLAGS@ @MYSQL_CFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $< @@ -80,3 +85,7 @@ else svnversion.h: @printf "\n" > svnversion.h endif + +# missing object files +MT19937AR_OBJ: + @$(MAKE) -C ../../3rdparty/mt19937ar diff --git a/src/login/Makefile.in b/src/login/Makefile.in index c153d95b3..fa1933964 100644 --- a/src/login/Makefile.in +++ b/src/login/Makefile.in @@ -3,16 +3,20 @@ COMMON_OBJ = ../common/obj_all/core.o ../common/obj_all/socket.o ../common/obj_a ../common/obj_all/db.o ../common/obj_all/plugins.o ../common/obj_all/lock.o \ ../common/obj_all/malloc.o ../common/obj_all/showmsg.o ../common/obj_all/utils.o \ ../common/obj_all/strlib.o ../common/obj_all/grfio.o ../common/obj_all/mapindex.o \ - ../common/obj_all/ers.o ../common/obj_all/md5calc.o + ../common/obj_all/ers.o ../common/obj_all/md5calc.o ../common/obj_all/random.o COMMON_H = ../common/core.h ../common/socket.h ../common/timer.h ../common/mmo.h \ ../common/version.h ../common/db.h ../common/plugins.h ../common/lock.h \ ../common/malloc.h ../common/showmsg.h ../common/utils.h ../common/strlib.h \ ../common/grfio.h ../common/mapindex.h \ - ../common/ers.h ../common/md5calc.h + ../common/ers.h ../common/md5calc.h ../common/random.h COMMON_SQL_OBJ = ../common/obj_sql/sql.o COMMON_SQL_H = ../common/sql.h +MT19937AR_OBJ = ../../3rdparty/mt19937ar/mt19937ar.o +MT19937AR_H = ../../3rdparty/mt19937ar/mt19937ar.h +MT19937AR_INCLUDE = -I../../3rdparty/mt19937ar + LOGIN_OBJ = login.o LOGIN_TXT_OBJ = $(LOGIN_OBJ:%=obj_txt/%) \ obj_txt/account_txt.o obj_txt/ipban_txt.o obj_txt/loginlog_txt.o @@ -22,10 +26,11 @@ LOGIN_H = login.h account.h ipban.h loginlog.h HAVE_MYSQL=@HAVE_MYSQL@ ifeq ($(HAVE_MYSQL),yes) - LOGIN_SERVER_SQL_DEPENDS=obj_sql $(LOGIN_SQL_OBJ) $(COMMON_OBJ) $(COMMON_SQL_OBJ) + LOGIN_SERVER_SQL_DEPENDS=obj_sql $(LOGIN_SQL_OBJ) $(COMMON_OBJ) $(COMMON_SQL_OBJ) $(MT19937AR_OBJ) else LOGIN_SERVER_SQL_DEPENDS=needs_mysql endif +LOGIN_SERVER_TXT_DEPENDS=obj_txt $(LOGIN_TXT_OBJ) $(COMMON_OBJ) $(MT19937AR_OBJ) @SET_MAKE@ @@ -63,19 +68,25 @@ obj_sql: test -d obj_sql || mkdir obj_sql #executables -login-server: $(LOGIN_TXT_OBJ) $(COMMON_OBJ) - @CC@ @LDFLAGS@ -o ../../login-server@EXEEXT@ $(LOGIN_TXT_OBJ) $(COMMON_OBJ) @LIBS@ +login-server: $(LOGIN_SERVER_TXT_DEPENDS) + @CC@ @LDFLAGS@ -o ../../login-server@EXEEXT@ $(LOGIN_TXT_OBJ) $(COMMON_OBJ) $(MT19937AR_OBJ) @LIBS@ login-server_sql: $(LOGIN_SERVER_SQL_DEPENDS) - @CC@ @LDFLAGS@ -o ../../login-server_sql@EXEEXT@ $(LOGIN_SQL_OBJ) $(COMMON_OBJ) $(COMMON_SQL_OBJ) @LIBS@ @MYSQL_LIBS@ + @CC@ @LDFLAGS@ -o ../../login-server_sql@EXEEXT@ $(LOGIN_SQL_OBJ) $(COMMON_OBJ) $(COMMON_SQL_OBJ) $(MT19937AR_OBJ) @LIBS@ @MYSQL_LIBS@ # login object files -obj_txt/%.o: %.c $(LOGIN_H) $(COMMON_H) - @CC@ @CFLAGS@ -DWITH_TXT @CPPFLAGS@ -c $(OUTPUT_OPTION) $< +obj_txt/%.o: %.c $(LOGIN_H) $(COMMON_H) $(MT19937AR_H) + @CC@ @CFLAGS@ $(MT19937AR_INCLUDE) -DWITH_TXT @CPPFLAGS@ -c $(OUTPUT_OPTION) $< -obj_sql/%.o: %.c $(LOGIN_H) $(COMMON_H) - @CC@ @CFLAGS@ -DWITH_SQL @MYSQL_CFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $< +obj_sql/%.o: %.c $(LOGIN_H) $(COMMON_H) $(MT19937AR_H) + @CC@ @CFLAGS@ $(MT19937AR_INCLUDE) -DWITH_SQL @MYSQL_CFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $< -# missing common object files +# missing object files ../common/obj_all/%.o: + @$(MAKE) -C ../common txt + +../common/obj_sql/%.o: @$(MAKE) -C ../common sql + +MT19937AR_OBJ: + @$(MAKE) -C ../../3rdparty/mt19937ar diff --git a/src/map/Makefile.in b/src/map/Makefile.in index 7070a0a9d..09e92dde2 100644 --- a/src/map/Makefile.in +++ b/src/map/Makefile.in @@ -3,16 +3,22 @@ COMMON_OBJ = ../common/obj_all/core.o ../common/obj_all/socket.o ../common/obj_a ../common/obj_all/db.o ../common/obj_all/plugins.o ../common/obj_all/lock.o \ ../common/obj_all/nullpo.o ../common/obj_all/malloc.o ../common/obj_all/showmsg.o \ ../common/obj_all/utils.o ../common/obj_all/strlib.o ../common/obj_all/grfio.o \ - ../common/obj_all/mapindex.o ../common/obj_all/ers.o ../common/obj_all/md5calc.o + ../common/obj_all/mapindex.o ../common/obj_all/ers.o ../common/obj_all/md5calc.o \ + ../common/obj_all/random.o COMMON_H = ../common/core.h ../common/socket.h ../common/timer.h \ ../common/db.h ../common/plugins.h ../common/lock.h \ ../common/nullpo.h ../common/malloc.h ../common/showmsg.h \ ../common/utils.h ../common/strlib.h ../common/grfio.h \ - ../common/mapindex.h ../common/ers.h ../common/md5calc.h + ../common/mapindex.h ../common/ers.h ../common/md5calc.h \ + ../common/random.h COMMON_SQL_OBJ = ../common/obj_sql/sql.o COMMON_SQL_H = ../common/sql.h +MT19937AR_OBJ = ../../3rdparty/mt19937ar/mt19937ar.o +MT19937AR_H = ../../3rdparty/mt19937ar/mt19937ar.h +MT19937AR_INCLUDE = -I../../3rdparty/mt19937ar + 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 \ @@ -38,6 +44,7 @@ else ALL_TARGET=txt SQL_DEPENDS=needs_mysql endif +TXT_DEPENDS=map-server HAVE_PCRE=@HAVE_PCRE@ ifeq ($(HAVE_PCRE),yes) @@ -53,7 +60,7 @@ endif all: $(ALL_DEPENDS) -txt: map-server +txt: $(TXT_DEPENDS) sql: $(SQL_DEPENDS) @@ -87,21 +94,24 @@ obj_sql: # executables map-server: obj_txt $(MAP_TXT_OBJ) $(COMMON_OBJ) - @CC@ @LDFLAGS@ -o ../../map-server@EXEEXT@ $(MAP_TXT_OBJ) $(COMMON_OBJ) @LIBS@ @PCRE_LIBS@ + @CC@ @LDFLAGS@ -o ../../map-server@EXEEXT@ $(MAP_TXT_OBJ) $(COMMON_OBJ) $(MT19937AR_OBJ) @LIBS@ @PCRE_LIBS@ map-server_sql: obj_sql $(MAP_SQL_OBJ) $(COMMON_OBJ) $(COMMON_SQL_OBJ) - @CC@ @LDFLAGS@ -o ../../map-server_sql@EXEEXT@ $(MAP_SQL_OBJ) $(COMMON_OBJ) $(COMMON_SQL_OBJ) @LIBS@ @PCRE_LIBS@ @MYSQL_LIBS@ + @CC@ @LDFLAGS@ -o ../../map-server_sql@EXEEXT@ $(MAP_SQL_OBJ) $(COMMON_OBJ) $(COMMON_SQL_OBJ) $(MT19937AR_OBJ) @LIBS@ @PCRE_LIBS@ @MYSQL_LIBS@ # map object files -obj_txt/%.o: %.c $(MAP_H) $(COMMON_H) - @CC@ @CFLAGS@ $(PCRE_CFLAGS) -DTXT_ONLY @CPPFLAGS@ -c $(OUTPUT_OPTION) $< +obj_txt/%.o: %.c $(MAP_H) $(COMMON_H) $(MT19937AR_H) + @CC@ @CFLAGS@ $(MT19937AR_INCLUDE) $(PCRE_CFLAGS) -DTXT_ONLY @CPPFLAGS@ -c $(OUTPUT_OPTION) $< -obj_sql/%.o: %.c $(MAP_H) $(COMMON_H) $(COMMON_SQL_H) - @CC@ @CFLAGS@ $(PCRE_CFLAGS) @MYSQL_CFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $< +obj_sql/%.o: %.c $(MAP_H) $(COMMON_H) $(COMMON_SQL_H) $(MT19937AR_H) + @CC@ @CFLAGS@ $(MT19937AR_INCLUDE) $(PCRE_CFLAGS) @MYSQL_CFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $< -# missing common object files +# missing object files ../common/obj_all/%.o: @$(MAKE) -C ../common txt ../common/obj_sql/%.o: @$(MAKE) -C ../common sql + +MT19937AR_OBJ: + @$(MAKE) -C ../../3rdparty/mt19937ar diff --git a/vcproj-10/char-server_sql.vcxproj b/vcproj-10/char-server_sql.vcxproj index aa3b130ba..f1a8e5363 100644 --- a/vcproj-10/char-server_sql.vcxproj +++ b/vcproj-10/char-server_sql.vcxproj @@ -51,7 +51,7 @@ Disabled - ..\3rdparty\mysql\include;..\3rdparty\msinttypes\include;%(AdditionalIncludeDirectories) + ..\3rdparty\mysql\include;..\3rdparty\msinttypes\include;..\3rdparty\mt19937ar;%(AdditionalIncludeDirectories) WIN32;_WIN32;__WIN32;_DEBUG;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;FD_SETSIZE=4096;DB_MANUAL_CAST_TO_UNION;%(PreprocessorDefinitions) false false @@ -94,7 +94,7 @@ true true true - ..\3rdparty\mysql\include;..\3rdparty\msinttypes\include;%(AdditionalIncludeDirectories) + ..\3rdparty\mysql\include;..\3rdparty\msinttypes\include;..\3rdparty\mt19937ar;%(AdditionalIncludeDirectories) WIN32;_WIN32;__WIN32;NDEBUG;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;FD_SETSIZE=4096;DB_MANUAL_CAST_TO_UNION;%(PreprocessorDefinitions) true MultiThreaded @@ -126,6 +126,7 @@ + @@ -137,6 +138,7 @@ + @@ -157,6 +159,7 @@ + @@ -165,6 +168,7 @@ + diff --git a/vcproj-10/char-server_txt.vcxproj b/vcproj-10/char-server_txt.vcxproj index 2ecbb6ba5..3d73a14ae 100644 --- a/vcproj-10/char-server_txt.vcxproj +++ b/vcproj-10/char-server_txt.vcxproj @@ -51,7 +51,7 @@ Disabled - ..\3rdparty\msinttypes\include;%(AdditionalIncludeDirectories) + ..\3rdparty\msinttypes\include;..\3rdparty\mt19937ar;%(AdditionalIncludeDirectories) WIN32;_WIN32;__WIN32;_DEBUG;TXT_ONLY;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;FD_SETSIZE=4096;DB_MANUAL_CAST_TO_UNION;%(PreprocessorDefinitions) false false @@ -93,7 +93,7 @@ true true true - ..\3rdparty\msinttypes\include;%(AdditionalIncludeDirectories) + ..\3rdparty\msinttypes\include;..\3rdparty\mt19937ar;%(AdditionalIncludeDirectories) WIN32;_WIN32;__WIN32;NDEBUG;TXT_ONLY;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;FD_SETSIZE=4096;DB_MANUAL_CAST_TO_UNION;%(PreprocessorDefinitions) true MultiThreaded @@ -140,11 +140,13 @@ + + @@ -166,12 +168,14 @@ + + diff --git a/vcproj-10/login-server_sql.vcxproj b/vcproj-10/login-server_sql.vcxproj index 0bd2c5717..43dbeb351 100644 --- a/vcproj-10/login-server_sql.vcxproj +++ b/vcproj-10/login-server_sql.vcxproj @@ -51,7 +51,7 @@ Disabled - ..\3rdparty\mysql\include;..\3rdparty\msinttypes\include;%(AdditionalIncludeDirectories) + ..\3rdparty\mysql\include;..\3rdparty\msinttypes\include;..\3rdparty\mt19937ar;%(AdditionalIncludeDirectories) WIN32;_WIN32;__WIN32;_DEBUG;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;FD_SETSIZE=4096;DB_MANUAL_CAST_TO_UNION;WITH_SQL;%(PreprocessorDefinitions) false false @@ -94,7 +94,7 @@ true true true - ..\3rdparty\mysql\include;..\3rdparty\msinttypes\include;%(AdditionalIncludeDirectories) + ..\3rdparty\mysql\include;..\3rdparty\msinttypes\include;..\3rdparty\mt19937ar;%(AdditionalIncludeDirectories) WIN32;_WIN32;__WIN32;NDEBUG;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;FD_SETSIZE=4096;DB_MANUAL_CAST_TO_UNION;WITH_SQL;%(PreprocessorDefinitions) true MultiThreaded @@ -145,6 +145,7 @@ + @@ -152,6 +153,7 @@ + @@ -166,12 +168,14 @@ + + diff --git a/vcproj-10/login-server_txt.vcxproj b/vcproj-10/login-server_txt.vcxproj index 138e3ee5e..f121af46a 100644 --- a/vcproj-10/login-server_txt.vcxproj +++ b/vcproj-10/login-server_txt.vcxproj @@ -49,7 +49,7 @@ Disabled - ..\3rdparty\msinttypes\include;%(AdditionalIncludeDirectories) + ..\3rdparty\msinttypes\include;..\3rdparty\mt19937ar;%(AdditionalIncludeDirectories) WIN32;_WIN32;__WIN32;_DEBUG;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;FD_SETSIZE=4096;DB_MANUAL_CAST_TO_UNION;WITH_TXT;%(PreprocessorDefinitions) false false @@ -92,7 +92,7 @@ true true true - ..\3rdparty\msinttypes\include;%(AdditionalIncludeDirectories) + ..\3rdparty\msinttypes\include;..\3rdparty\mt19937ar;%(AdditionalIncludeDirectories) WIN32;_WIN32;__WIN32;NDEBUG;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;FD_SETSIZE=4096;DB_MANUAL_CAST_TO_UNION;WITH_TXT;%(PreprocessorDefinitions) true MultiThreaded @@ -137,12 +137,14 @@ + + @@ -157,11 +159,13 @@ + + diff --git a/vcproj-10/map-server_sql.vcxproj b/vcproj-10/map-server_sql.vcxproj index 555015166..6fcb16f0f 100644 --- a/vcproj-10/map-server_sql.vcxproj +++ b/vcproj-10/map-server_sql.vcxproj @@ -50,7 +50,7 @@ Disabled - ..\3rdparty\mysql\include;..\3rdparty\zlib\include;..\3rdparty\pcre\include;..\3rdparty\msinttypes\include;%(AdditionalIncludeDirectories) + ..\3rdparty\mysql\include;..\3rdparty\zlib\include;..\3rdparty\pcre\include;..\3rdparty\msinttypes\include;..\3rdparty\mt19937ar;%(AdditionalIncludeDirectories) WIN32;_WIN32;__WIN32;_DEBUG;PCRE_SUPPORT;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;FD_SETSIZE=4096;DB_MANUAL_CAST_TO_UNION;%(PreprocessorDefinitions) false false @@ -93,7 +93,7 @@ true true true - ..\3rdparty\mysql\include;..\3rdparty\zlib\include;..\3rdparty\pcre\include;..\3rdparty\msinttypes\include;%(AdditionalIncludeDirectories) + ..\3rdparty\mysql\include;..\3rdparty\zlib\include;..\3rdparty\pcre\include;..\3rdparty\msinttypes\include;..\3rdparty\mt19937ar;%(AdditionalIncludeDirectories) WIN32;_WIN32;__WIN32;NDEBUG;PCRE_SUPPORT;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;FD_SETSIZE=4096;DB_MANUAL_CAST_TO_UNION;%(PreprocessorDefinitions) true MultiThreaded @@ -125,6 +125,7 @@ + @@ -138,6 +139,7 @@ + @@ -181,6 +183,7 @@ + @@ -191,6 +194,7 @@ + diff --git a/vcproj-10/map-server_txt.vcxproj b/vcproj-10/map-server_txt.vcxproj index a20495591..dfdf549f2 100644 --- a/vcproj-10/map-server_txt.vcxproj +++ b/vcproj-10/map-server_txt.vcxproj @@ -49,7 +49,7 @@ Disabled - ..\3rdparty\zlib\include;..\3rdparty\pcre\include;..\3rdparty\msinttypes\include;%(AdditionalIncludeDirectories) + ..\3rdparty\zlib\include;..\3rdparty\pcre\include;..\3rdparty\msinttypes\include;..\3rdparty\mt19937ar;%(AdditionalIncludeDirectories) WIN32;_WIN32;__WIN32;_DEBUG;PCRE_SUPPORT;TXT_ONLY;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;FD_SETSIZE=4096;DB_MANUAL_CAST_TO_UNION;%(PreprocessorDefinitions) false false @@ -92,7 +92,7 @@ true true true - ..\3rdparty\zlib\include;..\3rdparty\pcre\include;..\3rdparty\msinttypes\include;%(AdditionalIncludeDirectories) + ..\3rdparty\zlib\include;..\3rdparty\pcre\include;..\3rdparty\msinttypes\include;..\3rdparty\mt19937ar;%(AdditionalIncludeDirectories) WIN32;_WIN32;__WIN32;NDEBUG;PCRE_SUPPORT;TXT_ONLY;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;FD_SETSIZE=4096;DB_MANUAL_CAST_TO_UNION;%(PreprocessorDefinitions) true MultiThreaded @@ -169,11 +169,13 @@ + + @@ -223,12 +225,14 @@ + + diff --git a/vcproj-6/char-server_sql.dsp b/vcproj-6/char-server_sql.dsp index c87298481..f64c8d67e 100644 --- a/vcproj-6/char-server_sql.dsp +++ b/vcproj-6/char-server_sql.dsp @@ -42,7 +42,7 @@ RSC=rc.exe # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /W3 /Zi /O2 /I "..\3rdparty\msinttypes\include" /I "..\3rdparty\mysql\include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "_WIN32" /D "__WIN32" /D FD_SETSIZE=4096 /D "DB_MANUAL_CAST_TO_UNION" /FD /GF /c +# ADD CPP /nologo /W3 /Zi /O2 /I "..\3rdparty\msinttypes\include" /I "..\3rdparty\mysql\include" /I "..\3rdparty\mt19937ar" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "_WIN32" /D "__WIN32" /D FD_SETSIZE=4096 /D "DB_MANUAL_CAST_TO_UNION" /FD /GF /c # SUBTRACT CPP /YX # ADD BASE RSC /l 0x405 /d "NDEBUG" # ADD RSC /l 0x417 /d "NDEBUG" @@ -67,7 +67,7 @@ LINK32=link.exe # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /W3 /Gm /Gi /ZI /Od /I "..\3rdparty\msinttypes\include" /I "..\3rdparty\mysql\include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "_WIN32" /D "__WIN32" /D FD_SETSIZE=4096 /D "DB_MANUAL_CAST_TO_UNION" /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /Gi /ZI /Od /I "..\3rdparty\msinttypes\include" /I "..\3rdparty\mysql\include" /I "..\3rdparty\mt19937ar" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "_WIN32" /D "__WIN32" /D FD_SETSIZE=4096 /D "DB_MANUAL_CAST_TO_UNION" /FD /GZ /c # SUBTRACT CPP /YX # ADD BASE RSC /l 0x405 /d "_DEBUG" # ADD RSC /l 0x417 /d "_DEBUG" @@ -84,6 +84,18 @@ LINK32=link.exe # Name "char_sql - Win32 Release" # Name "char_sql - Win32 Debug" +# Begin Group "3rdparty" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\3rdparty\mt19937ar\mt19937ar.c +# End Source File +# Begin Source File + +SOURCE=..\3rdparty\mt19937ar\mt19937ar.h +# End Source File +# End Group # Begin Group "common" # PROP Default_Filter "" @@ -157,6 +169,14 @@ SOURCE=..\src\common\plugins.h # End Source File # Begin Source File +SOURCE=..\src\common\random.c +# End Source File +# Begin Source File + +SOURCE=..\src\common\random.h +# End Source File +# Begin Source File + SOURCE=..\src\common\showmsg.c # End Source File # Begin Source File diff --git a/vcproj-6/char-server_txt.dsp b/vcproj-6/char-server_txt.dsp index bcd522b6e..e5d9db918 100644 --- a/vcproj-6/char-server_txt.dsp +++ b/vcproj-6/char-server_txt.dsp @@ -42,7 +42,7 @@ RSC=rc.exe # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /W3 /Zi /O2 /I "..\3rdparty\msinttypes\include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "_WIN32" /D "__WIN32" /D FD_SETSIZE=4096 /D "DB_MANUAL_CAST_TO_UNION" /D "TXT_ONLY" /FD /GF /c +# ADD CPP /nologo /W3 /Zi /O2 /I "..\3rdparty\msinttypes\include" /I "..\3rdparty\mt19937ar" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "_WIN32" /D "__WIN32" /D FD_SETSIZE=4096 /D "DB_MANUAL_CAST_TO_UNION" /D "TXT_ONLY" /FD /GF /c # SUBTRACT CPP /YX # ADD BASE RSC /l 0x405 /d "NDEBUG" # ADD RSC /l 0x417 /d "NDEBUG" @@ -67,7 +67,7 @@ LINK32=link.exe # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /W3 /Gm /Gi /ZI /Od /I "..\3rdparty\msinttypes\include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "_WIN32" /D "__WIN32" /D FD_SETSIZE=4096 /D "DB_MANUAL_CAST_TO_UNION" /D "TXT_ONLY" /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /Gi /ZI /Od /I "..\3rdparty\msinttypes\include" /I "..\3rdparty\mt19937ar" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "_WIN32" /D "__WIN32" /D FD_SETSIZE=4096 /D "DB_MANUAL_CAST_TO_UNION" /D "TXT_ONLY" /FD /GZ /c # SUBTRACT CPP /YX # ADD BASE RSC /l 0x405 /d "_DEBUG" # ADD RSC /l 0x417 /d "_DEBUG" @@ -84,6 +84,18 @@ LINK32=link.exe # Name "char_txt - Win32 Release" # Name "char_txt - Win32 Debug" +# Begin Group "3rdparty" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\3rdparty\mt19937ar\mt19937ar.c +# End Source File +# Begin Source File + +SOURCE=..\3rdparty\mt19937ar\mt19937ar.h +# End Source File +# End Group # Begin Group "common" # PROP Default_Filter "" @@ -165,6 +177,14 @@ SOURCE=..\src\common\plugins.h # End Source File # Begin Source File +SOURCE=..\src\common\random.c +# End Source File +# Begin Source File + +SOURCE=..\src\common\random.h +# End Source File +# Begin Source File + SOURCE=..\src\common\showmsg.c # End Source File # Begin Source File diff --git a/vcproj-6/login-server_sql.dsp b/vcproj-6/login-server_sql.dsp index 39bed2a9b..54c953466 100644 --- a/vcproj-6/login-server_sql.dsp +++ b/vcproj-6/login-server_sql.dsp @@ -42,7 +42,7 @@ RSC=rc.exe # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /W3 /Zi /O2 /I "..\3rdparty\msinttypes\include" /I "..\3rdparty\mysql\include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "_WIN32" /D "__WIN32" /D FD_SETSIZE=4096 /D "DB_MANUAL_CAST_TO_UNION" /D "WITH_SQL" /FD /GF /c +# ADD CPP /nologo /W3 /Zi /O2 /I "..\3rdparty\msinttypes\include" /I "..\3rdparty\mysql\include" /I "..\3rdparty\mt19937ar" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "_WIN32" /D "__WIN32" /D FD_SETSIZE=4096 /D "DB_MANUAL_CAST_TO_UNION" /D "WITH_SQL" /FD /GF /c # SUBTRACT CPP /YX # ADD BASE RSC /l 0x405 /d "NDEBUG" # ADD RSC /l 0x417 /d "NDEBUG" @@ -67,7 +67,7 @@ LINK32=link.exe # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /W3 /Gm /Gi /ZI /Od /I "..\3rdparty\msinttypes\include" /I "..\3rdparty\mysql\include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "_WIN32" /D "__WIN32" /D FD_SETSIZE=4096 /D "DB_MANUAL_CAST_TO_UNION" /D "WITH_SQL" /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /Gi /ZI /Od /I "..\3rdparty\msinttypes\include" /I "..\3rdparty\mysql\include" /I "..\3rdparty\mt19937ar" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "_WIN32" /D "__WIN32" /D FD_SETSIZE=4096 /D "DB_MANUAL_CAST_TO_UNION" /D "WITH_SQL" /FD /GZ /c # SUBTRACT CPP /YX # ADD BASE RSC /l 0x405 /d "_DEBUG" # ADD RSC /l 0x417 /d "_DEBUG" @@ -84,6 +84,18 @@ LINK32=link.exe # Name "login_sql - Win32 Release" # Name "login_sql - Win32 Debug" +# Begin Group "3rdparty" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\3rdparty\mt19937ar\mt19937ar.c +# End Source File +# Begin Source File + +SOURCE=..\3rdparty\mt19937ar\mt19937ar.h +# End Source File +# End Group # Begin Group "common" # PROP Default_Filter "" @@ -165,6 +177,14 @@ SOURCE=..\src\common\plugins.h # End Source File # Begin Source File +SOURCE=..\src\common\random.c +# End Source File +# Begin Source File + +SOURCE=..\src\common\random.h +# End Source File +# Begin Source File + SOURCE=..\src\common\showmsg.c # End Source File # Begin Source File diff --git a/vcproj-6/login-server_txt.dsp b/vcproj-6/login-server_txt.dsp index 0ed85373c..642375fb7 100644 --- a/vcproj-6/login-server_txt.dsp +++ b/vcproj-6/login-server_txt.dsp @@ -42,7 +42,7 @@ RSC=rc.exe # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /W3 /Zi /O2 /I "..\3rdparty\msinttypes\include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "_WIN32" /D "__WIN32" /D FD_SETSIZE=4096 /D "DB_MANUAL_CAST_TO_UNION" /D "WITH_TXT" /FD /GF /c +# ADD CPP /nologo /W3 /Zi /O2 /I "..\3rdparty\msinttypes\include" /I "..\3rdparty\mt19937ar" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "_WIN32" /D "__WIN32" /D FD_SETSIZE=4096 /D "DB_MANUAL_CAST_TO_UNION" /D "WITH_TXT" /FD /GF /c # SUBTRACT CPP /YX # ADD BASE RSC /l 0x405 /d "NDEBUG" # ADD RSC /l 0x417 /d "NDEBUG" @@ -67,7 +67,7 @@ LINK32=link.exe # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /W3 /Gm /Gi /ZI /Od /I "..\3rdparty\msinttypes\include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "_WIN32" /D "__WIN32" /D FD_SETSIZE=4096 /D "DB_MANUAL_CAST_TO_UNION" /D "WITH_TXT" /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /Gi /ZI /Od /I "..\3rdparty\msinttypes\include" /I "..\3rdparty\mt19937ar" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "_WIN32" /D "__WIN32" /D FD_SETSIZE=4096 /D "DB_MANUAL_CAST_TO_UNION" /D "WITH_TXT" /FD /GZ /c # SUBTRACT CPP /YX # ADD BASE RSC /l 0x405 /d "_DEBUG" # ADD RSC /l 0x417 /d "_DEBUG" @@ -84,6 +84,18 @@ LINK32=link.exe # Name "login_txt - Win32 Release" # Name "login_txt - Win32 Debug" +# Begin Group "3rdparty" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\3rdparty\mt19937ar\mt19937ar.c +# End Source File +# Begin Source File + +SOURCE=..\3rdparty\mt19937ar\mt19937ar.h +# End Source File +# End Group # Begin Group "common" # PROP Default_Filter "" @@ -173,6 +185,14 @@ SOURCE=..\src\common\plugins.h # End Source File # Begin Source File +SOURCE=..\src\common\random.c +# End Source File +# Begin Source File + +SOURCE=..\src\common\random.h +# End Source File +# Begin Source File + SOURCE=..\src\common\showmsg.c # End Source File # Begin Source File diff --git a/vcproj-6/map-server_sql.dsp b/vcproj-6/map-server_sql.dsp index bf4249972..9246c6b17 100644 --- a/vcproj-6/map-server_sql.dsp +++ b/vcproj-6/map-server_sql.dsp @@ -42,7 +42,7 @@ RSC=rc.exe # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /W3 /Zi /O2 /I "..\3rdparty\mysql\include" /I "..\3rdparty\msinttypes\include" /I "..\3rdparty\pcre\include" /I "..\3rdparty\zlib\include" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "_WIN32" /D "__WIN32" /D FD_SETSIZE=4096 /D "DB_MANUAL_CAST_TO_UNION" /D "PCRE_SUPPORT" /FD /GF /c +# ADD CPP /nologo /W3 /Zi /O2 /I "..\3rdparty\mysql\include" /I "..\3rdparty\msinttypes\include" /I "..\3rdparty\pcre\include" /I "..\3rdparty\zlib\include" /I "..\3rdparty\mt19937ar" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "_WIN32" /D "__WIN32" /D FD_SETSIZE=4096 /D "DB_MANUAL_CAST_TO_UNION" /D "PCRE_SUPPORT" /FD /GF /c # SUBTRACT CPP /YX # ADD BASE RSC /l 0x405 /d "NDEBUG" # ADD RSC /l 0x417 /d "NDEBUG" @@ -67,7 +67,7 @@ LINK32=link.exe # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /W3 /Gm /Gi /ZI /Od /I "..\3rdparty\mysql\include" /I "..\3rdparty\msinttypes\include" /I "..\3rdparty\pcre\include" /I "..\3rdparty\zlib\include" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "_WIN32" /D "__WIN32" /D FD_SETSIZE=4096 /D "DB_MANUAL_CAST_TO_UNION" /D "PCRE_SUPPORT" /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /Gi /ZI /Od /I "..\3rdparty\mysql\include" /I "..\3rdparty\msinttypes\include" /I "..\3rdparty\pcre\include" /I "..\3rdparty\zlib\include" /I "..\3rdparty\mt19937ar" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "_WIN32" /D "__WIN32" /D FD_SETSIZE=4096 /D "DB_MANUAL_CAST_TO_UNION" /D "PCRE_SUPPORT" /FD /GZ /c # SUBTRACT CPP /YX # ADD BASE RSC /l 0x405 /d "_DEBUG" # ADD RSC /l 0x417 /d "_DEBUG" @@ -84,6 +84,18 @@ LINK32=link.exe # Name "map_sql - Win32 Release" # Name "map_sql - Win32 Debug" +# Begin Group "3rdparty" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\3rdparty\mt19937ar\mt19937ar.c +# End Source File +# Begin Source File + +SOURCE=..\3rdparty\mt19937ar\mt19937ar.h +# End Source File +# End Group # Begin Group "common" # PROP Default_Filter "" @@ -173,6 +185,14 @@ SOURCE=..\src\common\plugins.h # End Source File # Begin Source File +SOURCE=..\src\common\random.c +# End Source File +# Begin Source File + +SOURCE=..\src\common\random.h +# End Source File +# Begin Source File + SOURCE=..\src\common\showmsg.c # End Source File # Begin Source File diff --git a/vcproj-6/map-server_txt.dsp b/vcproj-6/map-server_txt.dsp index a79b6dcdf..00e4cf716 100644 --- a/vcproj-6/map-server_txt.dsp +++ b/vcproj-6/map-server_txt.dsp @@ -42,7 +42,7 @@ RSC=rc.exe # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /W3 /Zi /O2 /I "..\3rdparty\msinttypes\include" /I "..\3rdparty\pcre\include" /I "..\3rdparty\zlib\include" /D "NDEBUG" /D "TXT_ONLY" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "_WIN32" /D "__WIN32" /D FD_SETSIZE=4096 /D "DB_MANUAL_CAST_TO_UNION" /D "PCRE_SUPPORT" /FD /GF /c +# ADD CPP /nologo /W3 /Zi /O2 /I "..\3rdparty\msinttypes\include" /I "..\3rdparty\pcre\include" /I "..\3rdparty\zlib\include" /I "..\3rdparty\mt19937ar" /D "NDEBUG" /D "TXT_ONLY" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "_WIN32" /D "__WIN32" /D FD_SETSIZE=4096 /D "DB_MANUAL_CAST_TO_UNION" /D "PCRE_SUPPORT" /FD /GF /c # SUBTRACT CPP /YX # ADD BASE RSC /l 0x405 /d "NDEBUG" # ADD RSC /l 0x417 /d "NDEBUG" @@ -67,7 +67,7 @@ LINK32=link.exe # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /W3 /Gm /Gi /ZI /Od /I "..\3rdparty\msinttypes\include" /I "..\3rdparty\pcre\include" /I "..\3rdparty\zlib\include" /D "_DEBUG" /D "TXT_ONLY" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "_WIN32" /D "__WIN32" /D FD_SETSIZE=4096 /D "DB_MANUAL_CAST_TO_UNION" /D "PCRE_SUPPORT" /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /Gi /ZI /Od /I "..\3rdparty\msinttypes\include" /I "..\3rdparty\pcre\include" /I "..\3rdparty\zlib\include" /I "..\3rdparty\mt19937ar" /D "_DEBUG" /D "TXT_ONLY" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "_WIN32" /D "__WIN32" /D FD_SETSIZE=4096 /D "DB_MANUAL_CAST_TO_UNION" /D "PCRE_SUPPORT" /FD /GZ /c # SUBTRACT CPP /YX # ADD BASE RSC /l 0x405 /d "_DEBUG" # ADD RSC /l 0x417 /d "_DEBUG" @@ -84,6 +84,18 @@ LINK32=link.exe # Name "map_txt - Win32 Release" # Name "map_txt - Win32 Debug" +# Begin Group "3rdparty" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\3rdparty\mt19937ar\mt19937ar.c +# End Source File +# Begin Source File + +SOURCE=..\3rdparty\mt19937ar\mt19937ar.h +# End Source File +# End Group # Begin Group "common" # PROP Default_Filter "" @@ -181,6 +193,14 @@ SOURCE=..\src\common\plugins.h # End Source File # Begin Source File +SOURCE=..\src\common\random.c +# End Source File +# Begin Source File + +SOURCE=..\src\common\random.h +# End Source File +# Begin Source File + SOURCE=..\src\common\showmsg.c # End Source File # Begin Source File diff --git a/vcproj-7.1/char-server_sql.vcproj b/vcproj-7.1/char-server_sql.vcproj index 67b4bcb87..02ad69ff8 100644 --- a/vcproj-7.1/char-server_sql.vcproj +++ b/vcproj-7.1/char-server_sql.vcproj @@ -20,7 +20,7 @@ + + + + @@ -310,6 +316,16 @@ RelativePath="..\src\common\version.h"> + + + + + + diff --git a/vcproj-7.1/char-server_txt.vcproj b/vcproj-7.1/char-server_txt.vcproj index 47b9b90b4..cf4606143 100644 --- a/vcproj-7.1/char-server_txt.vcproj +++ b/vcproj-7.1/char-server_txt.vcproj @@ -20,7 +20,7 @@ + + + + @@ -285,6 +291,16 @@ RelativePath="..\src\common\version.h"> + + + + + + diff --git a/vcproj-7.1/login-server_sql.vcproj b/vcproj-7.1/login-server_sql.vcproj index a86f8246b..6ffd56f8f 100644 --- a/vcproj-7.1/login-server_sql.vcproj +++ b/vcproj-7.1/login-server_sql.vcproj @@ -19,7 +19,7 @@ + + + + @@ -269,6 +275,16 @@ RelativePath="..\src\common\version.h"> + + + + + + diff --git a/vcproj-7.1/login-server_txt.vcproj b/vcproj-7.1/login-server_txt.vcproj index 24fc249d7..624bb39d7 100644 --- a/vcproj-7.1/login-server_txt.vcproj +++ b/vcproj-7.1/login-server_txt.vcproj @@ -19,7 +19,7 @@ + + + + @@ -266,6 +272,16 @@ RelativePath="..\src\common\version.h"> + + + + + + diff --git a/vcproj-7.1/map-server_sql.vcproj b/vcproj-7.1/map-server_sql.vcproj index 235b7ab7f..fa1b7f931 100644 --- a/vcproj-7.1/map-server_sql.vcproj +++ b/vcproj-7.1/map-server_sql.vcproj @@ -21,7 +21,7 @@ AdditionalOptions="/wd4018 /wd4100" Optimization="0" - AdditionalIncludeDirectories="..\3rdparty\mysql\include;..\3rdparty\zlib\include;..\3rdparty\pcre\include;..\3rdparty\msinttypes\include" + AdditionalIncludeDirectories="..\3rdparty\mysql\include;..\3rdparty\zlib\include;..\3rdparty\pcre\include;..\3rdparty\msinttypes\include;..\3rdparty\mt19937ar" PreprocessorDefinitions="WIN32;_WIN32;__WIN32;_DEBUG;PCRE_SUPPORT;FD_SETSIZE=4096;DB_MANUAL_CAST_TO_UNION" GeneratePreprocessedFile="0" MinimalRebuild="TRUE" @@ -93,7 +93,7 @@ EnableFiberSafeOptimizations="TRUE" OptimizeForProcessor="2" OptimizeForWindowsApplication="TRUE" - AdditionalIncludeDirectories="..\3rdparty\mysql\include;..\3rdparty\zlib\include;..\3rdparty\pcre\include;..\3rdparty\msinttypes\include" + AdditionalIncludeDirectories="..\3rdparty\mysql\include;..\3rdparty\zlib\include;..\3rdparty\pcre\include;..\3rdparty\msinttypes\include;..\3rdparty\mt19937ar" PreprocessorDefinitions="WIN32;_WIN32;__WIN32;NDEBUG;PCRE_SUPPORT;FD_SETSIZE=4096;DB_MANUAL_CAST_TO_UNION" StringPooling="TRUE" RuntimeLibrary="3" @@ -428,6 +428,12 @@ + + + + @@ -468,6 +474,16 @@ RelativePath="..\src\common\version.h"> + + + + + + diff --git a/vcproj-7.1/map-server_txt.vcproj b/vcproj-7.1/map-server_txt.vcproj index 44e0ee1a0..b78fe1759 100644 --- a/vcproj-7.1/map-server_txt.vcproj +++ b/vcproj-7.1/map-server_txt.vcproj @@ -21,7 +21,7 @@ AdditionalOptions="/wd4018 /wd4100" Optimization="0" - AdditionalIncludeDirectories="..\3rdparty\zlib\include;..\3rdparty\pcre\include;..\3rdparty\msinttypes\include" + AdditionalIncludeDirectories="..\3rdparty\zlib\include;..\3rdparty\pcre\include;..\3rdparty\msinttypes\include;..\3rdparty\mt19937ar" PreprocessorDefinitions="WIN32;_WIN32;__WIN32;_DEBUG;PCRE_SUPPORT;TXT_ONLY;FD_SETSIZE=4096;DB_MANUAL_CAST_TO_UNION" GeneratePreprocessedFile="0" MinimalRebuild="TRUE" @@ -93,7 +93,7 @@ EnableFiberSafeOptimizations="TRUE" OptimizeForProcessor="2" OptimizeForWindowsApplication="TRUE" - AdditionalIncludeDirectories="..\3rdparty\zlib\include;..\3rdparty\pcre\include;..\3rdparty\msinttypes\include" + AdditionalIncludeDirectories="..\3rdparty\zlib\include;..\3rdparty\pcre\include;..\3rdparty\msinttypes\include;..\3rdparty\mt19937ar" PreprocessorDefinitions="WIN32;_WIN32;__WIN32;NDEBUG;PCRE_SUPPORT;TXT_ONLY;FD_SETSIZE=4096;DB_MANUAL_CAST_TO_UNION" StringPooling="TRUE" RuntimeLibrary="3" @@ -428,6 +428,12 @@ + + + + @@ -462,6 +468,16 @@ RelativePath="..\src\common\version.h"> + + + + + + diff --git a/vcproj-8/char-server_sql.vcproj b/vcproj-8/char-server_sql.vcproj index eea599498..ecee855a8 100644 --- a/vcproj-8/char-server_sql.vcproj +++ b/vcproj-8/char-server_sql.vcproj @@ -41,7 +41,7 @@ + + + + + + @@ -274,6 +286,14 @@ RelativePath="..\src\common\plugins.h" > + + + + diff --git a/vcproj-8/char-server_txt.vcproj b/vcproj-8/char-server_txt.vcproj index 3600bb9c9..da689efe5 100644 --- a/vcproj-8/char-server_txt.vcproj +++ b/vcproj-8/char-server_txt.vcproj @@ -41,7 +41,7 @@ + + + + @@ -385,6 +393,18 @@ > + + + + + + diff --git a/vcproj-8/login-server_sql.vcproj b/vcproj-8/login-server_sql.vcproj index 2509f8f29..bf2526125 100644 --- a/vcproj-8/login-server_sql.vcproj +++ b/vcproj-8/login-server_sql.vcproj @@ -41,7 +41,7 @@ + + + + @@ -365,6 +373,18 @@ > + + + + + + diff --git a/vcproj-8/login-server_txt.vcproj b/vcproj-8/login-server_txt.vcproj index 35cf7639c..ba298908e 100644 --- a/vcproj-8/login-server_txt.vcproj +++ b/vcproj-8/login-server_txt.vcproj @@ -40,7 +40,7 @@ + + + + @@ -348,6 +356,18 @@ > + + + + + + diff --git a/vcproj-8/map-server_sql.vcproj b/vcproj-8/map-server_sql.vcproj index 8a2d262d5..1f68af297 100644 --- a/vcproj-8/map-server_sql.vcproj +++ b/vcproj-8/map-server_sql.vcproj @@ -40,7 +40,7 @@ + + + + + + @@ -295,6 +307,14 @@ RelativePath="..\src\common\plugins.h" > + + + + diff --git a/vcproj-8/map-server_txt.vcproj b/vcproj-8/map-server_txt.vcproj index 9701861d1..ab7f5ab24 100644 --- a/vcproj-8/map-server_txt.vcproj +++ b/vcproj-8/map-server_txt.vcproj @@ -40,7 +40,7 @@ + + + + @@ -619,6 +627,18 @@ > + + + + + + diff --git a/vcproj-9/char-server_sql.vcproj b/vcproj-9/char-server_sql.vcproj index 1090169e2..fd6aa7967 100644 --- a/vcproj-9/char-server_sql.vcproj +++ b/vcproj-9/char-server_sql.vcproj @@ -42,7 +42,7 @@ + + + + + + @@ -279,6 +291,14 @@ RelativePath="..\src\common\plugins.h" > + + + + diff --git a/vcproj-9/char-server_txt.vcproj b/vcproj-9/char-server_txt.vcproj index 7212baf6b..6eea7bbbd 100644 --- a/vcproj-9/char-server_txt.vcproj +++ b/vcproj-9/char-server_txt.vcproj @@ -42,7 +42,7 @@ + + + + @@ -390,6 +398,18 @@ > + + + + + + diff --git a/vcproj-9/login-server_sql.vcproj b/vcproj-9/login-server_sql.vcproj index 4adaa8d34..f1d1fa94e 100644 --- a/vcproj-9/login-server_sql.vcproj +++ b/vcproj-9/login-server_sql.vcproj @@ -42,7 +42,7 @@ + + + + @@ -370,6 +378,18 @@ > + + + + + + diff --git a/vcproj-9/login-server_txt.vcproj b/vcproj-9/login-server_txt.vcproj index 6c0faa66c..16cd02e84 100644 --- a/vcproj-9/login-server_txt.vcproj +++ b/vcproj-9/login-server_txt.vcproj @@ -41,7 +41,7 @@ + + + + @@ -353,6 +361,18 @@ > + + + + + + diff --git a/vcproj-9/map-server_sql.vcproj b/vcproj-9/map-server_sql.vcproj index e7382ccce..6d31f2340 100644 --- a/vcproj-9/map-server_sql.vcproj +++ b/vcproj-9/map-server_sql.vcproj @@ -41,7 +41,7 @@ + + + + + + @@ -294,6 +306,14 @@ RelativePath="..\src\common\plugins.h" > + + + + diff --git a/vcproj-9/map-server_txt.vcproj b/vcproj-9/map-server_txt.vcproj index bd5d6585d..41912c95c 100644 --- a/vcproj-9/map-server_txt.vcproj +++ b/vcproj-9/map-server_txt.vcproj @@ -41,7 +41,7 @@ + + + + @@ -618,6 +626,18 @@ > + + + + + + -- cgit v1.2.3-70-g09d2 From d187830a9f19239d7f43729a51198ed9dd8c176f Mon Sep 17 00:00:00 2001 From: eathenabot Date: Sun, 11 Dec 2011 20:50:17 +0000 Subject: * Merged changes up to eAthena 15024. git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@15064 54d463be-8e91-2dee-dedb-b68131a5f0ec --- src/char/Makefile.in | 4 +- src/char_sql/Makefile.in | 4 +- src/common/des.c | 10 +- src/common/grfio.c | 582 +++++++++++++++++++++------------------ src/common/grfio.h | 11 +- src/login/Makefile.in | 4 +- vcproj-10/map-server_sql.vcxproj | 2 + vcproj-10/map-server_txt.vcxproj | 2 + vcproj-10/mapcache.vcxproj | 2 + 9 files changed, 340 insertions(+), 281 deletions(-) (limited to 'src/char/Makefile.in') diff --git a/src/char/Makefile.in b/src/char/Makefile.in index ba8f4fe64..1fd54b20b 100644 --- a/src/char/Makefile.in +++ b/src/char/Makefile.in @@ -2,12 +2,12 @@ COMMON_OBJ = ../common/obj_all/core.o ../common/obj_all/socket.o ../common/obj_all/timer.o \ ../common/obj_all/db.o ../common/obj_all/plugins.o ../common/obj_all/lock.o \ ../common/obj_all/malloc.o ../common/obj_all/showmsg.o ../common/obj_all/utils.o \ - ../common/obj_all/strlib.o ../common/obj_all/grfio.o \ + ../common/obj_all/strlib.o \ ../common/obj_all/mapindex.o ../common/obj_all/ers.o ../common/obj_all/random.o COMMON_H = ../common/core.h ../common/socket.h ../common/timer.h ../common/mmo.h \ ../common/version.h ../common/db.h ../common/plugins.h ../common/lock.h \ ../common/malloc.h ../common/showmsg.h ../common/utils.h \ - ../common/strlib.h ../common/grfio.h \ + ../common/strlib.h \ ../common/mapindex.h ../common/ers.h ../common/random.h MT19937AR_OBJ = ../../3rdparty/mt19937ar/mt19937ar.o diff --git a/src/char_sql/Makefile.in b/src/char_sql/Makefile.in index a8cf8e08c..e96113f0e 100644 --- a/src/char_sql/Makefile.in +++ b/src/char_sql/Makefile.in @@ -2,12 +2,12 @@ COMMON_OBJ = ../common/obj_all/core.o ../common/obj_all/socket.o ../common/obj_all/timer.o \ ../common/obj_all/db.o ../common/obj_all/plugins.o ../common/obj_all/lock.o \ ../common/obj_all/malloc.o ../common/obj_all/showmsg.o ../common/obj_all/utils.o \ - ../common/obj_all/strlib.o ../common/obj_all/grfio.o \ + ../common/obj_all/strlib.o \ ../common/obj_all/mapindex.o ../common/obj_all/ers.o ../common/obj_all/random.o COMMON_H = ../common/core.h ../common/socket.h ../common/timer.h ../common/mmo.h \ ../common/version.h ../common/db.h ../common/plugins.h ../common/lock.h \ ../common/malloc.h ../common/showmsg.h ../common/utils.h \ - ../common/strlib.h ../common/grfio.h \ + ../common/strlib.h \ ../common/mapindex.h ../common/ers.h ../common/random.h MT19937AR_OBJ = ../../3rdparty/mt19937ar/mt19937ar.o diff --git a/src/common/des.c b/src/common/des.c index 67a3a38d1..917fc33e0 100644 --- a/src/common/des.c +++ b/src/common/des.c @@ -19,7 +19,7 @@ static const uint8_t mask[8] = { /// Initial permutation (IP). static void IP(BIT64* src) { - BIT64 tmp = {0}; + BIT64 tmp = {{0}}; static const uint8_t ip_table[64] = { 58, 50, 42, 34, 26, 18, 10, 2, @@ -47,7 +47,7 @@ static void IP(BIT64* src) /// Final permutation (IP^-1). static void FP(BIT64* src) { - BIT64 tmp = {0}; + BIT64 tmp = {{0}}; static const uint8_t fp_table[64] = { 40, 8, 48, 16, 56, 24, 64, 32, @@ -76,7 +76,7 @@ static void FP(BIT64* src) /// Expands upper four 8-bits (32b) into eight 6-bits (48b). static void E(BIT64* src) { - BIT64 tmp = {0}; + BIT64 tmp = {{0}}; if( false ) {// original @@ -118,7 +118,7 @@ else /// Transposition (P-BOX). static void TP(BIT64* src) { - BIT64 tmp = {0}; + BIT64 tmp = {{0}}; static const uint8_t tp_table[32] = { 16, 7, 20, 21, @@ -147,7 +147,7 @@ static void TP(BIT64* src) /// NOTE: This implementation was optimized to process two nibbles in one step (twice as fast). static void SBOX(BIT64* src) { - BIT64 tmp = {0}; + BIT64 tmp = {{0}}; static const uint8_t s_table[4][64] = { { diff --git a/src/common/grfio.c b/src/common/grfio.c index eefeb8296..856df6bb3 100644 --- a/src/common/grfio.c +++ b/src/common/grfio.c @@ -24,13 +24,16 @@ typedef struct _FILELIST { int declen; // original size int srcpos; // position of entry in grf int next; // index of next filelist entry with same hash (-1: end of entry chain) - int cycle; char type; char fn[128-4*5]; // file name char* fnd; // if the file was cloned, contains name of original file char gentry; // read grf file select } FILELIST; +#define FILELIST_TYPE_FILE 0x01 // entry is a file +#define FILELIST_TYPE_ENCRYPT_HEADER 0x04 // encryption mode 1 (header DES only) +#define FILELIST_TYPE_ENCRYPT_MIXED 0x02 // encryption mode 0 (header DES + periodic DES/shuffle) + //gentry ... > 0 : data read from a grf file (gentry_table[gentry-1]) //gentry ... 0 : data read from a local file (data directory) //gentry ... < 0 : entry "-(gentry)" is marked for a local file check @@ -40,6 +43,7 @@ typedef struct _FILELIST { // (NOTE: probably meant to be used to override grf contents by files in the data directory) //#define GRFIO_LOCAL + // stores info about every loaded file FILELIST* filelist = NULL; int filelist_entrys = 0; @@ -53,21 +57,21 @@ int gentry_maxentry = 0; // the path to the data directory char data_dir[1024] = ""; -//---------------------------- -// file list hash table -//---------------------------- -int filelist_hash[256]; // little endian char array to uint conversion static unsigned int getlong(unsigned char* p) { - return (p[0] | p[1] << 0x08 | p[2] << 0x10 | p[3] << 0x18); + return (p[0] << 0 | p[1] << 8 | p[2] << 16 | p[3] << 24); } -static void NibbleSwap(unsigned char* Src, int len) + +static void NibbleSwap(unsigned char* src, int len) { - for(;0>4) | (*Src<<4); + while( len > 0 ) + { + *src = (*src >> 4) | (*src << 4); + ++src; + --len; } } @@ -135,46 +139,118 @@ static void grf_shuffle_dec(BIT64* src) } -static void decode_des_etc(unsigned char* buf, size_t len, int type, int cycle) +static void grf_decode_header(unsigned char* buf, size_t len) +{ + BIT64* p = (BIT64*)buf; + size_t nblocks = len / sizeof(BIT64); + size_t i; + + // first 20 blocks are all des-encrypted + for( i = 0; i < 20 && i < nblocks; ++i ) + des_decrypt_block(&p[i]); + + // the rest is plaintext, done. +} + + +static void grf_decode_full(unsigned char* buf, size_t len, int cycle) { BIT64* p = (BIT64*)buf; + size_t nblocks = len / sizeof(BIT64); + int dcycle, scycle; + size_t i, j; + + // first 20 blocks are all des-encrypted + for( i = 0; i < 20 && i < nblocks; ++i ) + des_decrypt_block(&p[i]); - size_t lop,cnt=0; - if(cycle<3) cycle=3; - else if(cycle<5) cycle++; - else if(cycle<7) cycle+=9; - else cycle+=15; + // after that only one of every 'dcycle' blocks is des-encrypted + dcycle = cycle; - for(lop=0; lop*8gentry < 0) { // LocalFileCheck - char lfname[256], *p; - FILELIST lentry; - struct stat st; - - grfio_localpath_create(lfname, sizeof(lfname), fname); - - if (stat(lfname, &st) == 0) { - safestrncpy(lentry.fn, fname, sizeof(lentry.fn)); - lentry.fnd = NULL; - lentry.declen = st.st_size; - lentry.gentry = 0; // 0:LocalFile - entry = filelist_modify(&lentry); - } else if (entry == NULL) { - ShowError("%s not found (grfio_size)\n", fname); - return -1; - } - } - return entry->declen; -} -*/ - -// reads a file into a newly allocated buffer (from grf or data directory) -void* grfio_reads(char* fname, int* size) +/// Reads a file into a newly allocated buffer (from grf or data directory). +void* grfio_reads(const char* fname, int* size) { - FILE* in; - FILELIST* entry; unsigned char* buf2 = NULL; - entry = filelist_find(fname); - - if (entry == NULL || entry->gentry <= 0) { // LocalFileCheck + FILELIST* entry = filelist_find(fname); + if( entry == NULL || entry->gentry <= 0 ) + {// LocalFileCheck char lfname[256]; int declen; + FILE* in; grfio_localpath_create(lfname, sizeof(lfname), ( entry && entry->fnd ) ? entry->fnd : fname); in = fopen(lfname, "rb"); - if (in != NULL) { + if( in != NULL ) + { fseek(in,0,SEEK_END); declen = ftell(in); fseek(in,0,SEEK_SET); buf2 = (unsigned char *)aMallocA(declen+1); // +1 for resnametable zero-termination fread(buf2, 1, declen, in); fclose(in); + if( size ) - { - size[0] = declen; - } - } else { + *size = declen; + } + else + { if (entry != NULL && entry->gentry < 0) { entry->gentry = -entry->gentry; // local file checked } else { @@ -377,19 +423,23 @@ void* grfio_reads(char* fname, int* size) } } } - if (entry != NULL && entry->gentry > 0) { // Archive[GRF] File Read + + if( entry != NULL && entry->gentry > 0 ) + {// Archive[GRF] File Read char* grfname = gentry_table[entry->gentry - 1]; - in = fopen(grfname, "rb"); - if(in != NULL) { + FILE* in = fopen(grfname, "rb"); + if( in != NULL ) + { unsigned char *buf = (unsigned char *)aMallocA(entry->srclen_aligned); fseek(in, entry->srcpos, 0); fread(buf, 1, entry->srclen_aligned, in); fclose(in); + buf2 = (unsigned char *)aMallocA(entry->declen+1); // +1 for resnametable zero-termination - if (entry->type == 1 || entry->type == 3 || entry->type == 5) { + if( entry->type & FILELIST_TYPE_FILE ) + {// file uLongf len; - if (entry->cycle >= 0) - decode_des_etc(buf, entry->srclen_aligned, entry->cycle == 0, entry->cycle); + grf_decode(buf, entry->srclen_aligned, entry->type, entry->srclen); len = entry->declen; decode_zip(buf2, &len, buf, entry->srclen); if (len != (uLong)entry->declen) { @@ -398,15 +448,19 @@ void* grfio_reads(char* fname, int* size) aFree(buf2); return NULL; } - } else { + } + else + {// directory? memcpy(buf2, buf, entry->declen); } + if( size ) - { - size[0] = entry->declen; - } + *size = entry->declen; + aFree(buf); - } else { + } + else + { ShowError("grfio_reads: %s not found (GRF file: %s)\n", fname, grfname); return NULL; } @@ -415,9 +469,8 @@ void* grfio_reads(char* fname, int* size) return buf2; } -/*========================================== - * Resource filename decode - *------------------------------------------*/ + +/// Decodes encrypted filename from a version 01xx grf index. static char* decode_filename(unsigned char* buf, int len) { int lop; @@ -428,30 +481,49 @@ static char* decode_filename(unsigned char* buf, int len) return (char*)buf; } -// loads all entries in the specified grf file into the filelist -// gentry - index of the grf file name in the gentry_table -static int grfio_entryread(char* grfname, int gentry) + +/// Compares file extension against known large file types. +/// @return true if the file should undergo full mode 0 decryption, and true otherwise. +static bool isFullEncrypt(const char* fname) +{ + static const char extensions[4][5] = { ".gnd", ".gat", ".act", ".str" }; + size_t i; + + const char* ext = strrchr(fname, '.'); + if( ext != NULL ) + for( i = 0; i < ARRAYLENGTH(extensions); ++i ) + if( strcmpi(ext, extensions[i]) == 0 ) + return false; + + return true; +} + + +/// Loads all entries in the specified grf file into the filelist. +/// @param gentry index of the grf file name in the gentry_table +static int grfio_entryread(const char* grfname, int gentry) { - FILE* fp; long grf_size,list_size; unsigned char grf_header[0x2e]; - int lop,entry,entrys,ofs,grf_version; - char *fname; + int entry,entrys,ofs,grf_version; unsigned char *grf_filelist; - fp = fopen(grfname, "rb"); - if (fp == NULL) { + FILE* fp = fopen(grfname, "rb"); + if( fp == NULL ) + { ShowWarning("GRF data file not found: '%s'\n",grfname); return 1; // 1:not found error - } else + } + else ShowInfo("GRF data file found: '%s'\n",grfname); fseek(fp,0,SEEK_END); grf_size = ftell(fp); fseek(fp,0,SEEK_SET); + fread(grf_header,1,0x2e,fp); - if (strcmp((const char *) grf_header,"Master of Magic") || - fseek(fp,getlong(grf_header+0x1e),SEEK_CUR)) + if( strcmp((const char*)grf_header,"Master of Magic") != 0 || + fseek(fp,getlong(grf_header+0x1e),SEEK_CUR) != 0 ) { fclose(fp); ShowError("GRF %s read error\n", grfname); @@ -460,7 +532,8 @@ static int grfio_entryread(char* grfname, int gentry) grf_version = getlong(grf_header+0x2a) >> 8; - if (grf_version == 0x01) { //****** Grf version 01xx ****** + if( grf_version == 0x01 ) + {// ****** Grf version 01xx ****** list_size = grf_size - ftell(fp); grf_filelist = (unsigned char *) aMallocA(list_size); fread(grf_filelist,1,list_size,fp); @@ -469,42 +542,30 @@ static int grfio_entryread(char* grfname, int gentry) entrys = getlong(grf_header+0x26) - getlong(grf_header+0x22) - 7; // Get an entry - for (entry = 0,ofs = 0; entry < entrys; entry++) { - int ofs2, srclen, srccount; - unsigned char type; - char* period_ptr; + for( entry = 0, ofs = 0; entry < entrys; ++entry ) + { FILELIST aentry; - ofs2 = ofs+getlong(grf_filelist+ofs)+4; - type = grf_filelist[ofs2+12]; - if (type != 0) { // Directory Index ... skip - fname = decode_filename(grf_filelist+ofs+6, grf_filelist[ofs]-6); - if (strlen(fname) > sizeof(aentry.fn) - 1) { + int ofs2 = ofs+getlong(grf_filelist+ofs)+4; + unsigned char type = grf_filelist[ofs2+12]; + if( type & FILELIST_TYPE_FILE ) + { + char* fname = decode_filename(grf_filelist+ofs+6, grf_filelist[ofs]-6); + int srclen = getlong(grf_filelist+ofs2+0) - getlong(grf_filelist+ofs2+8) - 715; + + if( strlen(fname) > sizeof(aentry.fn) - 1 ) + { ShowFatalError("GRF file name %s is too long\n", fname); aFree(grf_filelist); exit(EXIT_FAILURE); } - srclen = 0; - if ((period_ptr = strrchr(fname, '.')) != NULL) { - for(lop = 0; lop < 4; lop++) { - if (strcmpi(period_ptr, ".gnd\0.gat\0.act\0.str"+lop*5) == 0) - break; - } - srclen = getlong(grf_filelist+ofs2) - getlong(grf_filelist+ofs2+8) - 715; - if(lop == 4) { - for(lop = 10, srccount = 1; srclen >= lop; lop = lop * 10, srccount++); - } else { - srccount = 0; - } - } else { - srccount = 0; - } + + type |= ( isFullEncrypt(fname) ) ? FILELIST_TYPE_ENCRYPT_MIXED : FILELIST_TYPE_ENCRYPT_HEADER; aentry.srclen = srclen; aentry.srclen_aligned = getlong(grf_filelist+ofs2+4)-37579; aentry.declen = getlong(grf_filelist+ofs2+8); aentry.srcpos = getlong(grf_filelist+ofs2+13)+0x2e; - aentry.cycle = srccount; aentry.type = type; safestrncpy(aentry.fn, fname, sizeof(aentry.fn)); aentry.fnd = NULL; @@ -515,11 +576,15 @@ static int grfio_entryread(char* grfname, int gentry) #endif filelist_modify(&aentry); } + ofs = ofs2 + 17; } - aFree(grf_filelist); - } else if (grf_version == 0x02) { //****** Grf version 02xx ****** + aFree(grf_filelist); + } + else + if( grf_version == 0x02 ) + {// ****** Grf version 02xx ****** unsigned char eheader[8]; unsigned char *rBuf; uLongf rSize, eSize; @@ -528,7 +593,8 @@ static int grfio_entryread(char* grfname, int gentry) rSize = getlong(eheader); // Read Size eSize = getlong(eheader+4); // Extend Size - if ((long)rSize > grf_size-ftell(fp)) { + if( (long)rSize > grf_size-ftell(fp) ) + { fclose(fp); ShowError("Illegal data format: GRF compress entry size\n"); return 4; @@ -545,33 +611,27 @@ static int grfio_entryread(char* grfname, int gentry) entrys = getlong(grf_header+0x26) - 7; // Get an entry - for(entry = 0, ofs = 0; entry < entrys; entry++) { - int ofs2, srclen, srccount, type; + for( entry = 0, ofs = 0; entry < entrys; ++entry ) + { FILELIST aentry; - fname = (char*)(grf_filelist+ofs); - if (strlen(fname) > sizeof(aentry.fn)-1) { + char* fname = (char*)(grf_filelist+ofs); + int ofs2 = ofs + (int)strlen(fname)+1; + int type = grf_filelist[ofs2+12]; + + if( strlen(fname) > sizeof(aentry.fn)-1 ) + { ShowFatalError("GRF file name %s is too long\n", fname); aFree(grf_filelist); exit(EXIT_FAILURE); } - ofs2 = ofs + (int)strlen(fname)+1; - type = grf_filelist[ofs2+12]; - if (type == 1 || type == 3 || type == 5) { - srclen = getlong(grf_filelist+ofs2); - if (grf_filelist[ofs2+12] == 3) { - for (lop = 10, srccount = 1; srclen >= lop; lop = lop * 10, srccount++); - } else if (grf_filelist[ofs2+12] == 5) { - srccount = 0; - } else { // if (grf_filelist[ofs2+12]==1) { - srccount = -1; - } - aentry.srclen = srclen; + if( type & FILELIST_TYPE_FILE ) + {// file + aentry.srclen = getlong(grf_filelist+ofs2+0); aentry.srclen_aligned = getlong(grf_filelist+ofs2+4); aentry.declen = getlong(grf_filelist+ofs2+8); aentry.srcpos = getlong(grf_filelist+ofs2+13)+0x2e; - aentry.cycle = srccount; aentry.type = type; safestrncpy(aentry.fn, fname, sizeof(aentry.fn)); aentry.fnd = NULL; @@ -582,30 +642,72 @@ static int grfio_entryread(char* grfname, int gentry) #endif filelist_modify(&aentry); } + ofs = ofs2 + 17; } - aFree(grf_filelist); - } else { //****** Grf Other version ****** + aFree(grf_filelist); + } + else + {// ****** Grf Other version ****** fclose(fp); ShowError("GRF version %04x not supported\n",getlong(grf_header+0x2a)); return 4; } - filelist_adjust(); // Unnecessary area release of filelist + filelist_compact(); // Unnecessary area release of filelist return 0; // 0:no error } -/*========================================== - * Grfio : Resource file check - *------------------------------------------*/ + +static bool grfio_parse_restable_row(const char* row) +{ + char w1[256], w2[256]; + char src[256], dst[256]; + char local[256]; + FILELIST* entry; + + if( sscanf(row, "%[^#]#%[^#]#", w1, w2) != 2 ) + return false; + + if( strstr(w2, ".gat") == NULL && strstr(w2, ".rsw") == NULL ) + return false; // we only need the maps' GAT and RSW files + + sprintf(src, "data\\%s", w1); + sprintf(dst, "data\\%s", w2); + + entry = filelist_find(dst); + if( entry != NULL ) + {// alias for GRF resource + FILELIST fentry; + memcpy(&fentry, entry, sizeof(FILELIST)); + safestrncpy(fentry.fn, src, sizeof(fentry.fn)); + fentry.fnd = aStrdup(dst); + filelist_modify(&fentry); + return true; + } + + grfio_localpath_create(local, sizeof(local), dst); + if( exists(local) ) + {// alias for local resource + FILELIST fentry; + memset(&fentry, 0, sizeof(fentry)); + safestrncpy(fentry.fn, src, sizeof(fentry.fn)); + fentry.fnd = aStrdup(dst); + filelist_modify(&fentry); + return true; + } + + return false; +} + + +/// Grfio Resource file check. static void grfio_resourcecheck(void) { - char w1[256], w2[256], src[256], dst[256], restable[256], line[256], local[256]; + char restable[256]; char *ptr, *buf; - FILELIST* entry; - FILELIST fentry; int size; FILE* fp; int i = 0; @@ -614,41 +716,15 @@ static void grfio_resourcecheck(void) grfio_localpath_create(restable, sizeof(restable), "data\\resnametable.txt"); fp = fopen(restable, "rb"); - if (fp) { - while(fgets(line, sizeof(line), fp)) + if( fp != NULL ) + { + char line[256]; + while( fgets(line, sizeof(line), fp) ) { - if (sscanf(line, "%[^#]#%[^#]#", w1, w2) == 2 && - // we only need the maps' GAT and RSW files - (strstr(w2, ".gat") || strstr(w2, ".rsw"))) - { - sprintf(src, "data\\%s", w1); - sprintf(dst, "data\\%s", w2); - entry = filelist_find(dst); - // create new entries reusing the original's info - if (entry != NULL) - {// alias for GRF resource - memcpy(&fentry, entry, sizeof(FILELIST)); - safestrncpy(fentry.fn, src, sizeof(fentry.fn)); - fentry.fnd = aStrdup(dst); - filelist_modify(&fentry); - i++; - } - else - { - grfio_localpath_create(local, sizeof(local), dst); - - if( exists(local) ) - {// alias for local resource - memset(&fentry, 0, sizeof(fentry)); - //fentry.gentry = 0; - safestrncpy(fentry.fn, src, sizeof(fentry.fn)); - fentry.fnd = aStrdup(dst); - filelist_modify(&fentry); - i++; - } - } - } + if( grfio_parse_restable_row(line) ) + ++i; } + fclose(fp); ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", i, "resnametable.txt"); return; // we're done here! @@ -656,57 +732,34 @@ static void grfio_resourcecheck(void) // read resnametable from loaded GRF's, only if it cannot be loaded from the data directory buf = (char *)grfio_reads("data\\resnametable.txt", &size); - if (buf) { - buf[size] = 0; + if( buf != NULL ) + { + buf[size] = '\0'; ptr = buf; - while (ptr - buf < size) { - if (sscanf(ptr, "%[^#]#%[^#]#", w1, w2) == 2 && - (strstr(w2, ".gat") || strstr(w2, ".rsw"))) - { - sprintf(src, "data\\%s", w1); - sprintf(dst, "data\\%s", w2); - entry = filelist_find(dst); - if (entry != NULL) - {// alias for GRF resource - memcpy(&fentry, entry, sizeof(FILELIST)); - safestrncpy(fentry.fn, src, sizeof(fentry.fn)); - fentry.fnd = aStrdup(dst); - filelist_modify(&fentry); - i++; - } - else - { - grfio_localpath_create(local, sizeof(local), dst); - - if( exists(local) ) - {// alias for local resource - memset(&fentry, 0, sizeof(fentry)); - //fentry.gentry = 0; - safestrncpy(fentry.fn, src, sizeof(fentry.fn)); - fentry.fnd = aStrdup(dst); - filelist_modify(&fentry); - i++; - } - } - } - ptr = strchr(ptr, '\n'); // Next line - if (!ptr) break; + while( ptr - buf < size ) + { + if( grfio_parse_restable_row(ptr) ) + ++i; + + ptr = strchr(ptr, '\n'); + if( ptr == NULL ) break; ptr++; } + aFree(buf); ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", i, "data\\resnametable.txt"); return; } - } -// reads a grf file and adds it to the list -static int grfio_add(char* fname) -{ - #define GENTRY_ADDS 4 // The number increment of gentry_table entries - if (gentry_entrys >= gentry_maxentry) { +/// Reads a grf file and adds it to the list. +static int grfio_add(const char* fname) +{ + if( gentry_entrys >= gentry_maxentry ) + { + #define GENTRY_ADDS 4 // The number increment of gentry_table entries gentry_maxentry += GENTRY_ADDS; gentry_table = (char**)aRealloc(gentry_table, gentry_maxentry * sizeof(char*)); memset(gentry_table + (gentry_maxentry - GENTRY_ADDS), 0, sizeof(char*) * GENTRY_ADDS); @@ -717,7 +770,8 @@ static int grfio_add(char* fname) return grfio_entryread(fname, gentry_entrys - 1); } -// removes all entries + +/// Finalizes grfio. void grfio_final(void) { if (filelist != NULL) { @@ -743,46 +797,48 @@ void grfio_final(void) gentry_entrys = gentry_maxentry = 0; } -/*========================================== - * Grfio : Initialize - *------------------------------------------*/ -void grfio_init(char* fname) + +/// Initializes grfio. +void grfio_init(const char* fname) { FILE* data_conf; - char line[1024], w1[1024], w2[1024]; int grf_num = 0; hashinit(); // hash table initialization data_conf = fopen(fname, "r"); - // It will read, if there is grf-files.txt. - if (data_conf) { - while(fgets(line, sizeof(line), data_conf)) + if( data_conf != NULL ) + { + char line[1024]; + while( fgets(line, sizeof(line), data_conf) ) { - if (line[0] == '/' && line[1] == '/') - continue; - if (sscanf(line, "%[^:]: %[^\r\n]", w1, w2) != 2) - continue; + char w1[1024], w2[1024]; + + if( line[0] == '/' && line[1] == '/' ) + continue; // skip comments + + if( sscanf(line, "%[^:]: %[^\r\n]", w1, w2) != 2 ) + continue; // skip unrecognized lines + // Entry table reading - if(strcmp(w1, "grf") == 0) // GRF file - grf_num += (grfio_add(w2) == 0); - else if(strcmp(w1,"data_dir") == 0) { // Data directory + if( strcmp(w1, "grf") == 0 ) // GRF file + if( grfio_add(w2) == 0 ) + ++grf_num; + else + if( strcmp(w1,"data_dir") == 0 ) // Data directory safestrncpy(data_dir, w2, sizeof(data_dir)); - } } + fclose(data_conf); ShowStatus("Done reading '"CL_WHITE"%s"CL_RESET"'.\n", fname); - } // end of reading grf-files.txt + } - if (grf_num == 0) { + if( grf_num == 0 ) ShowInfo("No GRF loaded, using default data directory\n"); - } // Unneccessary area release of filelist - filelist_adjust(); + filelist_compact(); // Resource check grfio_resourcecheck(); - - return; } diff --git a/src/common/grfio.h b/src/common/grfio.h index 0fc9f958d..c5a56a14e 100644 --- a/src/common/grfio.h +++ b/src/common/grfio.h @@ -4,16 +4,13 @@ #ifndef _GRFIO_H_ #define _GRFIO_H_ -void grfio_init(char*); // GRFIO Initialize -void grfio_final(void); // GRFIO Finalize -void* grfio_reads(char*,int*); // GRFIO data file read & size get -char *grfio_find_file(char *fname); - +void grfio_init(const char* fname); +void grfio_final(void); +void* grfio_reads(const char* fname, int* size); +char* grfio_find_file(const char* fname); #define grfio_read(fn) grfio_reads(fn, NULL) -int grfio_size(char*); // GRFIO data file size get unsigned long grfio_crc32(const unsigned char *buf, unsigned int len); - int decode_zip(void* dest, unsigned long* destLen, const void* source, unsigned long sourceLen); int encode_zip(void* dest, unsigned long* destLen, const void* source, unsigned long sourceLen); diff --git a/src/login/Makefile.in b/src/login/Makefile.in index fa1933964..dd7bc3b48 100644 --- a/src/login/Makefile.in +++ b/src/login/Makefile.in @@ -2,12 +2,12 @@ COMMON_OBJ = ../common/obj_all/core.o ../common/obj_all/socket.o ../common/obj_all/timer.o \ ../common/obj_all/db.o ../common/obj_all/plugins.o ../common/obj_all/lock.o \ ../common/obj_all/malloc.o ../common/obj_all/showmsg.o ../common/obj_all/utils.o \ - ../common/obj_all/strlib.o ../common/obj_all/grfio.o ../common/obj_all/mapindex.o \ + ../common/obj_all/strlib.o ../common/obj_all/mapindex.o \ ../common/obj_all/ers.o ../common/obj_all/md5calc.o ../common/obj_all/random.o COMMON_H = ../common/core.h ../common/socket.h ../common/timer.h ../common/mmo.h \ ../common/version.h ../common/db.h ../common/plugins.h ../common/lock.h \ ../common/malloc.h ../common/showmsg.h ../common/utils.h ../common/strlib.h \ - ../common/grfio.h ../common/mapindex.h \ + ../common/mapindex.h \ ../common/ers.h ../common/md5calc.h ../common/random.h COMMON_SQL_OBJ = ../common/obj_sql/sql.o diff --git a/vcproj-10/map-server_sql.vcxproj b/vcproj-10/map-server_sql.vcxproj index af05998dc..e6cbdcef4 100644 --- a/vcproj-10/map-server_sql.vcxproj +++ b/vcproj-10/map-server_sql.vcxproj @@ -130,6 +130,7 @@ + @@ -193,6 +194,7 @@ + diff --git a/vcproj-10/map-server_txt.vcxproj b/vcproj-10/map-server_txt.vcxproj index 8c31ae6d6..272e16c57 100644 --- a/vcproj-10/map-server_txt.vcxproj +++ b/vcproj-10/map-server_txt.vcxproj @@ -162,6 +162,7 @@ + @@ -223,6 +224,7 @@ + diff --git a/vcproj-10/mapcache.vcxproj b/vcproj-10/mapcache.vcxproj index a70f854f9..15a010c15 100644 --- a/vcproj-10/mapcache.vcxproj +++ b/vcproj-10/mapcache.vcxproj @@ -124,6 +124,7 @@ + @@ -134,6 +135,7 @@ + -- cgit v1.2.3-70-g09d2 From 44d7606656a650dc43018b5c63bb56ad1f70e77c Mon Sep 17 00:00:00 2001 From: gepard1984 Date: Fri, 20 Jan 2012 20:33:32 +0000 Subject: Merged TXT removal branch back to trunk. * TXT save engine is removed and no longer supported. * See also tid:53926, tid:57717. git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@15503 54d463be-8e91-2dee-dedb-b68131a5f0ec --- CMakeLists.txt | 6 - Makefile.in | 73 +- charserv.bat | 2 - conf/char_athena.conf | 6 - conf/inter_athena.conf | 31 - conf/login_athena.conf | 3 - configure | 99 +- configure.in | 88 +- logserv.bat | 2 - mapserv.bat | 2 - rAthena-10.sln | 90 - rAthena-9.sln | 90 - runserver.bat | 75 - save-tmpl/account.txt | 16 - save-tmpl/accreg.txt | 0 save-tmpl/athena.txt | 0 save-tmpl/athena_backup.txt | 0 save-tmpl/castle.txt | 34 - save-tmpl/friends.txt | 0 save-tmpl/g_storage.txt | 0 save-tmpl/guild.txt | 0 save-tmpl/homun.txt | 0 save-tmpl/mapreg.txt | 0 save-tmpl/party.txt | 0 save-tmpl/pet.txt | 0 save-tmpl/scdata.txt | 0 save-tmpl/storage.txt | 0 src/CMakeLists.txt | 7 - src/char/CMakeLists.txt | 79 +- src/char/Makefile.in | 53 +- src/char/char.c | 3477 +++++++++---------- src/char/char.h | 75 +- src/char/int_auction.c | 494 +++ src/char/int_auction.h | 12 + src/char/int_guild.c | 2377 +++++++------ src/char/int_guild.h | 40 +- src/char/int_homun.c | 526 ++- src/char/int_homun.h | 21 +- src/char/int_mail.c | 476 +++ src/char/int_mail.h | 16 + src/char/int_mercenary.c | 218 ++ src/char/int_mercenary.h | 20 + src/char/int_party.c | 761 ++-- src/char/int_party.h | 34 +- src/char/int_pet.c | 447 +-- src/char/int_pet.h | 14 +- src/char/int_quest.c | 184 + src/char/int_quest.h | 13 + src/char/int_status.c | 183 - src/char/int_status.h | 23 - src/char/int_storage.c | 501 +-- src/char/int_storage.h | 24 +- src/char/inter.c | 762 ++-- src/char/inter.h | 19 +- src/char_sql/CMakeLists.txt | 58 - src/char_sql/Makefile.in | 71 - src/char_sql/char.c | 4636 ------------------------- src/char_sql/char.h | 83 - src/char_sql/int_auction.c | 494 --- src/char_sql/int_auction.h | 12 - src/char_sql/int_guild.c | 2018 ----------- src/char_sql/int_guild.h | 40 - src/char_sql/int_homun.c | 313 -- src/char_sql/int_homun.h | 18 - src/char_sql/int_mail.c | 476 --- src/char_sql/int_mail.h | 16 - src/char_sql/int_mercenary.c | 221 -- src/char_sql/int_mercenary.h | 20 - src/char_sql/int_party.c | 870 ----- src/char_sql/int_party.h | 32 - src/char_sql/int_pet.c | 310 -- src/char_sql/int_pet.h | 21 - src/char_sql/int_quest.c | 184 - src/char_sql/int_quest.h | 13 - src/char_sql/int_storage.c | 250 -- src/char_sql/int_storage.h | 22 - src/char_sql/inter.c | 744 ---- src/char_sql/inter.h | 30 - src/login/CMakeLists.txt | 2 - src/login/Makefile.in | 22 +- src/login/account.h | 6 +- src/login/account_txt.c | 645 ---- src/login/ipban_txt.c | 50 - src/login/login.c | 5 - src/login/loginlog_txt.c | 81 - src/login/txt/CMakeLists.txt | 39 - src/map/CMakeLists.txt | 2 - src/map/Makefile.in | 8 +- src/map/atcommand.c | 10 +- src/map/chrif.c | 14 +- src/map/clif.c | 9 - src/map/clif.h | 2 - src/map/intif.c | 7 +- src/map/intif.h | 2 - src/map/itemdb.c | 4 - src/map/log.c | 23 - src/map/mail.c | 4 - src/map/map.c | 16 +- src/map/map.h | 4 - src/map/mapreg_txt.c | 202 -- src/map/mob.c | 6 - src/map/pc.c | 10 +- src/map/script.c | 26 +- src/map/txt/CMakeLists.txt | 108 - src/txt-converter/CMakeLists.txt | 17 - src/txt-converter/Makefile.in | 150 - src/txt-converter/char-converter.c | 303 -- src/txt-converter/char/CMakeLists.txt | 76 - src/txt-converter/login-converter.c | 108 - src/txt-converter/login/CMakeLists.txt | 60 - vcproj-10/char-server_sql.vcxproj | 44 +- vcproj-10/char-server_sql.vcxproj.filters | 44 +- vcproj-10/char-server_txt.vcxproj | 184 - vcproj-10/char-server_txt.vcxproj.filters | 168 - vcproj-10/login-server_txt.vcxproj | 175 - vcproj-10/login-server_txt.vcxproj.filters | 144 - vcproj-10/map-server_txt.vcxproj | 250 -- vcproj-10/map-server_txt.vcxproj.filters | 345 -- vcproj-10/txt-converter-char.vcxproj | 204 -- vcproj-10/txt-converter-char.vcxproj.filters | 156 - vcproj-10/txt-converter-login.vcxproj | 162 - vcproj-10/txt-converter-login.vcxproj.filters | 90 - vcproj-9/char-server_sql.vcproj | 44 +- vcproj-9/char-server_txt.vcproj | 417 --- vcproj-9/login-server_txt.vcproj | 380 -- vcproj-9/map-server_txt.vcproj | 681 ---- vcproj-9/txt-converter-char.vcproj | 513 --- vcproj-9/txt-converter-login.vcproj | 309 -- 128 files changed, 6263 insertions(+), 22493 deletions(-) delete mode 100755 charserv.bat delete mode 100755 logserv.bat delete mode 100755 mapserv.bat delete mode 100755 runserver.bat delete mode 100644 save-tmpl/account.txt delete mode 100644 save-tmpl/accreg.txt delete mode 100644 save-tmpl/athena.txt delete mode 100644 save-tmpl/athena_backup.txt delete mode 100644 save-tmpl/castle.txt delete mode 100644 save-tmpl/friends.txt delete mode 100644 save-tmpl/g_storage.txt delete mode 100644 save-tmpl/guild.txt delete mode 100644 save-tmpl/homun.txt delete mode 100644 save-tmpl/mapreg.txt delete mode 100644 save-tmpl/party.txt delete mode 100644 save-tmpl/pet.txt delete mode 100644 save-tmpl/scdata.txt delete mode 100644 save-tmpl/storage.txt create mode 100644 src/char/int_auction.c create mode 100644 src/char/int_auction.h create mode 100644 src/char/int_mail.c create mode 100644 src/char/int_mail.h create mode 100644 src/char/int_mercenary.c create mode 100644 src/char/int_mercenary.h create mode 100644 src/char/int_quest.c create mode 100644 src/char/int_quest.h delete mode 100644 src/char/int_status.c delete mode 100644 src/char/int_status.h delete mode 100644 src/char_sql/CMakeLists.txt delete mode 100644 src/char_sql/Makefile.in delete mode 100644 src/char_sql/char.c delete mode 100644 src/char_sql/char.h delete mode 100644 src/char_sql/int_auction.c delete mode 100644 src/char_sql/int_auction.h delete mode 100644 src/char_sql/int_guild.c delete mode 100644 src/char_sql/int_guild.h delete mode 100644 src/char_sql/int_homun.c delete mode 100644 src/char_sql/int_homun.h delete mode 100644 src/char_sql/int_mail.c delete mode 100644 src/char_sql/int_mail.h delete mode 100644 src/char_sql/int_mercenary.c delete mode 100644 src/char_sql/int_mercenary.h delete mode 100644 src/char_sql/int_party.c delete mode 100644 src/char_sql/int_party.h delete mode 100644 src/char_sql/int_pet.c delete mode 100644 src/char_sql/int_pet.h delete mode 100644 src/char_sql/int_quest.c delete mode 100644 src/char_sql/int_quest.h delete mode 100644 src/char_sql/int_storage.c delete mode 100644 src/char_sql/int_storage.h delete mode 100644 src/char_sql/inter.c delete mode 100644 src/char_sql/inter.h delete mode 100644 src/login/account_txt.c delete mode 100644 src/login/ipban_txt.c delete mode 100644 src/login/loginlog_txt.c delete mode 100644 src/login/txt/CMakeLists.txt delete mode 100644 src/map/mapreg_txt.c delete mode 100644 src/map/txt/CMakeLists.txt delete mode 100644 src/txt-converter/CMakeLists.txt delete mode 100644 src/txt-converter/Makefile.in delete mode 100644 src/txt-converter/char-converter.c delete mode 100644 src/txt-converter/char/CMakeLists.txt delete mode 100644 src/txt-converter/login-converter.c delete mode 100644 src/txt-converter/login/CMakeLists.txt delete mode 100644 vcproj-10/char-server_txt.vcxproj delete mode 100644 vcproj-10/char-server_txt.vcxproj.filters delete mode 100644 vcproj-10/login-server_txt.vcxproj delete mode 100644 vcproj-10/login-server_txt.vcxproj.filters delete mode 100644 vcproj-10/map-server_txt.vcxproj delete mode 100644 vcproj-10/map-server_txt.vcxproj.filters delete mode 100644 vcproj-10/txt-converter-char.vcxproj delete mode 100644 vcproj-10/txt-converter-char.vcxproj.filters delete mode 100644 vcproj-10/txt-converter-login.vcxproj delete mode 100644 vcproj-10/txt-converter-login.vcxproj.filters delete mode 100644 vcproj-9/char-server_txt.vcproj delete mode 100644 vcproj-9/login-server_txt.vcproj delete mode 100644 vcproj-9/map-server_txt.vcproj delete mode 100644 vcproj-9/txt-converter-char.vcproj delete mode 100644 vcproj-9/txt-converter-login.vcproj (limited to 'src/char/Makefile.in') diff --git a/CMakeLists.txt b/CMakeLists.txt index 14a244b82..b60a5de20 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -443,7 +443,6 @@ set( DEVELOPMENT_FILES set( DEVELOPMENT_DIRECTORIES "3rdparty" "conf/import-tmpl" - "save-tmpl" "src" "vcproj-9" "vcproj-10" @@ -452,21 +451,17 @@ set( RUNTIME_FILES "${CMAKE_CURRENT_SOURCE_DIR}/athena-start" "${CMAKE_CURRENT_SOURCE_DIR}/char-server.sh" "${CMAKE_CURRENT_SOURCE_DIR}/charserv-sql.bat" - "${CMAKE_CURRENT_SOURCE_DIR}/charserv.bat" "${CMAKE_CURRENT_SOURCE_DIR}/dbghelp.dll" "${CMAKE_CURRENT_SOURCE_DIR}/libmysql.dll" "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE" "${CMAKE_CURRENT_SOURCE_DIR}/login-server.sh" "${CMAKE_CURRENT_SOURCE_DIR}/logserv-sql.bat" - "${CMAKE_CURRENT_SOURCE_DIR}/logserv.bat" "${CMAKE_CURRENT_SOURCE_DIR}/map-server.sh" "${CMAKE_CURRENT_SOURCE_DIR}/mapserv-sql.bat" - "${CMAKE_CURRENT_SOURCE_DIR}/mapserv.bat" "${CMAKE_CURRENT_SOURCE_DIR}/notice.txt" "${CMAKE_CURRENT_SOURCE_DIR}/pcre3.dll" "${CMAKE_CURRENT_SOURCE_DIR}/readme.html" "${CMAKE_CURRENT_SOURCE_DIR}/runserver-sql.bat" - "${CMAKE_CURRENT_SOURCE_DIR}/runserver.bat" "${CMAKE_CURRENT_SOURCE_DIR}/serv.bat" "${CMAKE_CURRENT_SOURCE_DIR}/start" "${CMAKE_CURRENT_SOURCE_DIR}/zlib1.dll" @@ -511,7 +506,6 @@ endif() if( INSTALL_COMPONENT_RUNTIME ) # templates set( _TEMPLATES - "save-tmpl" "save" "conf/import-tmpl" "conf/import" ) set( INSTALL_TEMPLATES_FILE "${CMAKE_CURRENT_BINARY_DIR}/InstallTemplates.cmake" ) diff --git a/Makefile.in b/Makefile.in index ea3106317..02ca9b987 100644 --- a/Makefile.in +++ b/Makefile.in @@ -2,76 +2,56 @@ HAVE_MYSQL=@HAVE_MYSQL@ ifeq ($(HAVE_MYSQL),yes) - ALL_DEPENDS=mt19937ar common common_sql login login_sql char char_sql map map_sql tools converters import save - SQL_DEPENDS=mt19937ar common_sql login_sql char_sql map_sql import save + ALL_DEPENDS=common_sql login_sql char_sql map_sql tools import + SQL_DEPENDS=common_sql login_sql char_sql map_sql import COMMON_SQL_DEPENDS=mt19937ar LOGIN_SQL_DEPENDS=mt19937ar common_sql CHAR_SQL_DEPENDS=mt19937ar common_sql MAP_SQL_DEPENDS=mt19937ar common_sql CONVERTERS_DEPENDS=common_sql else - ALL_DEPENDS=mt19937ar common login char map tools import save + ALL_DEPENDS=needs_mysql SQL_DEPENDS=needs_mysql COMMON_SQL_DEPENDS=needs_mysql LOGIN_SQL_DEPENDS=needs_mysql CHAR_SQL_DEPENDS=needs_mysql MAP_SQL_DEPENDS=needs_mysql - CONVERTERS_DEPENDS=needs_mysql endif -COMMON_TXT_DEPENDS=mt19937ar -LOGIN_TXT_DEPENDS=mt19937ar common -CHAR_TXT_DEPENDS=mt19937ar common -MAP_TXT_DEPENDS=mt19937ar common WITH_PLUGINS=@WITH_PLUGINS@ ifeq ($(WITH_PLUGINS),yes) ALL_DEPENDS+=plugins - PLUGIN_DEPENDS=common + PLUGIN_DEPENDS=common_sql else PLUGIN_DEPENDS=no_plugins endif ##################################################################### -.PHONY: txt sql conf \ - common common_sql \ +.PHONY: sql \ + common_sql \ mt19937ar \ - login login_sql \ - char char_sql \ - map map_sql \ - tools converters plugins addons import save \ + login_sql \ + char_sql \ + map_sql \ + tools plugins addons \ + import \ clean help all: $(ALL_DEPENDS) -txt: common login char map import save - sql: $(SQL_DEPENDS) -conf: import save - -common: $(COMMON_TXT_DEPENDS) - @$(MAKE) -C src/common txt - common_sql: $(COMMON_SQL_DEPENDS) @$(MAKE) -C src/common sql mt19937ar: @$(MAKE) -C 3rdparty/mt19937ar -login: $(LOGIN_TXT_DEPENDS) - @$(MAKE) -C src/login txt - login_sql: $(LOGIN_SQL_DEPENDS) @$(MAKE) -C src/login sql -char: $(CHAR_TXT_DEPENDS) - @$(MAKE) -C src/char - char_sql: $(CHAR_SQL_DEPENDS) - @$(MAKE) -C src/char_sql - -map: $(MAP_TXT_DEPENDS) - @$(MAKE) -C src/map txt + @$(MAKE) -C src/char map_sql: $(MAP_SQL_DEPENDS) @$(MAKE) -C src/map sql @@ -79,12 +59,9 @@ map_sql: $(MAP_SQL_DEPENDS) tools: @$(MAKE) -C src/tool -converters: $(CONVERTERS_DEPENDS) - @$(MAKE) -C src/txt-converter - plugins addons: $(PLUGIN_DEPENDS) @$(MAKE) -C src/plugins - + import: # 1) create conf/import folder # 2) add missing files @@ -94,50 +71,30 @@ import: @for f in $$(ls conf/import-tmpl) ; do if test ! -e conf/import/$$f ; then cp conf/import-tmpl/$$f conf/import ; fi ; done @rm -rf conf/import/.svn -save: -# 1) create save folder -# 2) add missing files -# 3) remove remaining .svn folder - @echo "building save folder..." - @if test ! -d save ; then mkdir save ; fi - @for f in $$(ls save-tmpl) ; do if test ! -e save/$$f ; then cp save-tmpl/$$f save ; fi ; done - @rm -rf save/.svn - clean: @$(MAKE) -C src/common $@ @$(MAKE) -C 3rdparty/mt19937ar $@ @$(MAKE) -C src/login $@ @$(MAKE) -C src/char $@ - @$(MAKE) -C src/char_sql $@ @$(MAKE) -C src/map $@ @$(MAKE) -C src/plugins $@ @$(MAKE) -C src/tool $@ - @$(MAKE) -C src/txt-converter $@ help: - @echo "most common targets are 'all' 'txt' 'sql' 'conf' 'clean' 'help'" + @echo "most common targets are 'all' 'sql' 'conf' 'clean' 'help'" @echo "possible targets are:" - @echo "'common' - builds object files used in TXT servers" @echo "'common_sql' - builds object files used in SQL servers" @echo "'mt19937ar' - builds object file of Mersenne Twister MT19937" - @echo "'login' - builds login server (TXT version)" @echo "'login_sql' - builds login server (SQL version)" - @echo "'char' - builds char server (TXT version)" @echo "'char_sql' - builds char server (SQL version)" - @echo "'map' - builds map server (TXT version)" @echo "'map_sql' - builds map server (SQL version)" @echo "'tools' - builds all the tools in src/tools" - @echo "'converters' - builds the login/char converters" @echo "'plugins' - builds all the plugins in src/plugins" @echo "'addons'" @echo "'import' - builds conf/import folder from the template conf/import-tmpl" - @echo "'save' - builds save folder from the template save-tmpl" @echo "'all' - builds all the above targets" - @echo "'txt' - builds txt servers (targets 'common' 'login' 'char' 'map'" - @echo " 'import' and 'save')" @echo "'sql' - builds sql servers (targets 'common_sql' 'login_sql' 'char_sql'" - @echo " 'map_sql' 'import' and 'save')" - @echo "'conf' - builds templated folders/files (targets 'import' and 'save')" + @echo " 'map_sql' and 'import')" @echo "'clean' - cleans builds and objects" @echo "'help' - outputs this message" diff --git a/charserv.bat b/charserv.bat deleted file mode 100755 index b21efac35..000000000 --- a/charserv.bat +++ /dev/null @@ -1,2 +0,0 @@ -@ECHO OFF -CALL serv.bat char-server.exe Char-Server diff --git a/conf/char_athena.conf b/conf/char_athena.conf index 4ffd47783..bc9e1ab1c 100644 --- a/conf/char_athena.conf +++ b/conf/char_athena.conf @@ -104,12 +104,6 @@ autosave_time: 60 // Display information on the console whenever characters/guilds/parties/pets are loaded/saved? save_log: yes -// Character server flatfile database -char_txt: save/athena.txt - -// Friends list flatfile database -friends_txt: save/friends.txt - // Start point, Map name followed by coordinates (x,y) start_point: new_1-1,53,111 diff --git a/conf/inter_athena.conf b/conf/inter_athena.conf index 03e39b90d..bf6c4f417 100644 --- a/conf/inter_athena.conf +++ b/conf/inter_athena.conf @@ -11,37 +11,6 @@ inter_log_filename: log/inter.log // Level range for sharing within a party party_share_level: 15 - -// TXT version options only - -// Storage flatfile database, used for Karfa storage. -storage_txt: save/storage.txt - -// Party flatfile database, for party names, members and other party info. -party_txt: save/party.txt - -// Hotkeys flatfile database, where character skill shortcuts are stored. -hotkeys_txt: save/hotkeys.txt - -// Guild flatfile database, for guild names, members, and other guild info. -guild_txt: save/guild.txt - -// Pet flatfile database, for pet names, and other pet info. -pet_txt: save/pet.txt - -// Homunculus flatfile database, for homunculus information. -homun_txt: save/homun.txt - -// Castle flatfile database, for emperium war castles, etc. -castle_txt: save/castle.txt - -// Status change flatfile database, for status changes that are saved between sessions. -scdata_txt: save/scdata.txt - -// Mapserver permanent script variables ($-type) -mapreg_txt: save/mapreg.txt - - // SQL version options only // You can specify the codepage to use in your mySQL tables here. diff --git a/conf/login_athena.conf b/conf/login_athena.conf index 7ee08881b..aab2f854c 100644 --- a/conf/login_athena.conf +++ b/conf/login_athena.conf @@ -117,9 +117,6 @@ dnsbl_servers: dnsbl.deltaanime.net account.engine: auto // Account data storage configuration -// TXT -account.txt.account_db: save/account.txt -account.txt.case_sensitive: no // SQL //account.sql.db_hostname: 127.0.0.1 //account.sql.db_port: 3306 diff --git a/configure b/configure index cc3891e63..9494bacd5 100755 --- a/configure +++ b/configure @@ -868,9 +868,8 @@ Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-mysql[=ARG] - use MySQL client library, optionally specify the - path to the mysql_config executable (by default - mysql is used if found) + optionally specify the path to the mysql_config + executable --with-MYSQL_CFLAGS=ARG specify MYSQL_CFLAGS manually (instead of using "mysql_config --include") --with-MYSQL_LIBS=ARG specify MYSQL_LIBS manually (instead of using @@ -1339,8 +1338,6 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_config_files="$ac_config_files src/char/Makefile src/login/Makefile" - ac_config_files="$ac_config_files src/char_sql/Makefile src/txt-converter/Makefile" - ac_config_files="$ac_config_files src/map/Makefile src/plugins/Makefile src/tool/Makefile" @@ -1486,30 +1483,22 @@ fi; # -# Enable/disable MySql and optionally specify the path to mysql_config (optional library) +# Optionally specify the path to mysql_config # # Check whether --with-mysql or --without-mysql was given. if test "${with_mysql+set}" = set; then withval="$with_mysql" - if test "$withval" = "no" ; then - want_mysql="no" - else - want_mysql="yes" - require_mysql="yes" - if test "$withval" != "yes" ; then - if test ! -x "$withval" ; then - { { echo "$as_me:$LINENO: error: $withval is not an executable file" >&5 + if test "$withval" != "no" ; then + if test ! -x "$withval" ; then + { { echo "$as_me:$LINENO: error: $withval is not an executable file" >&5 echo "$as_me: error: $withval is not an executable file" >&2;} { (exit 1); exit 1; }; } - fi - MYSQL_CONFIG_HOME="$withval" fi + MYSQL_CONFIG_HOME="$withval" fi -else - want_mysql="yes" require_mysql="no" fi; @@ -5096,18 +5085,11 @@ fi # -# MySQL library (optional) +# MySQL library # -if test "$want_mysql" = "no" ; then - MYSQL_VERSION="" - MYSQL_CFLAGS="" - MYSQL_LIBS="" - { echo "$as_me:$LINENO: ignoring MySQL (optional)" >&5 -echo "$as_me: ignoring MySQL (optional)" >&6;} -else - if test -z "$MYSQL_CONFIG_HOME"; then - # Extract the first word of "mysql_config", so it can be a program name with args. +if test -z "$MYSQL_CONFIG_HOME"; then + # Extract the first word of "mysql_config", so it can be a program name with args. set dummy mysql_config; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 @@ -5147,23 +5129,23 @@ else echo "${ECHO_T}no" >&6 fi - fi +fi - if test "$MYSQL_CONFIG_HOME" != "no" ; then - MYSQL_VERSION="`$MYSQL_CONFIG_HOME --version`" - if test "$manual_MYSQL_CFLAGS" = "no" ; then - MYSQL_CFLAGS="`$MYSQL_CONFIG_HOME --include`" - fi - if test "$manual_MYSQL_LIBS" = "no" ; then - MYSQL_LIBS="`$MYSQL_CONFIG_HOME --libs`" - fi - else - MYSQL_VERSION="unknown" +if test "$MYSQL_CONFIG_HOME" != "no" ; then + MYSQL_VERSION="`$MYSQL_CONFIG_HOME --version`" + if test "$manual_MYSQL_CFLAGS" = "no" ; then + MYSQL_CFLAGS="`$MYSQL_CONFIG_HOME --include`" fi + if test "$manual_MYSQL_LIBS" = "no" ; then + MYSQL_LIBS="`$MYSQL_CONFIG_HOME --libs`" + fi +else + MYSQL_VERSION="unknown" +fi - MYSQL_OLD_LDFLAGS="$LDFLAGS" ; LDFLAGS="$LDFLAGS $MYSQL_LIBS" - MYSQL_OLD_CPPFLAGS="$CPPFLAGS" ; CPPFLAGS="$CPPFLAGS $MYSQL_CFLAGS" - echo "$as_me:$LINENO: checking for mysql_init in -lmysqlclient" >&5 +MYSQL_OLD_LDFLAGS="$LDFLAGS" ; LDFLAGS="$LDFLAGS $MYSQL_LIBS" +MYSQL_OLD_CPPFLAGS="$CPPFLAGS" ; CPPFLAGS="$CPPFLAGS $MYSQL_CFLAGS" +echo "$as_me:$LINENO: checking for mysql_init in -lmysqlclient" >&5 echo $ECHO_N "checking for mysql_init in -lmysqlclient... $ECHO_C" >&6 if test "${ac_cv_lib_mysqlclient_mysql_init+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 @@ -5231,7 +5213,7 @@ if test $ac_cv_lib_mysqlclient_mysql_init = yes; then HAVE_MYSQL="yes" fi - if test "${ac_cv_header_mysql_h+set}" = set; then +if test "${ac_cv_header_mysql_h+set}" = set; then echo "$as_me:$LINENO: checking for mysql.h" >&5 echo $ECHO_N "checking for mysql.h... $ECHO_C" >&6 if test "${ac_cv_header_mysql_h+set}" = set; then @@ -5375,29 +5357,20 @@ else fi - CPPFLAGS="$MYSQL_OLD_CPPFLAGS" - LDFLAGS="$MYSQL_OLD_LDFLAGS" +CPPFLAGS="$MYSQL_OLD_CPPFLAGS" +LDFLAGS="$MYSQL_OLD_LDFLAGS" - echo "$as_me:$LINENO: checking MySQL library (optional)" >&5 -echo $ECHO_N "checking MySQL library (optional)... $ECHO_C" >&6 - if test "$HAVE_MYSQL" = "yes" ; then - echo "$as_me:$LINENO: result: yes ($MYSQL_VERSION)" >&5 +echo "$as_me:$LINENO: checking MySQL library (required)" >&5 +echo $ECHO_N "checking MySQL library (required)... $ECHO_C" >&6 +if test "$HAVE_MYSQL" = "yes" ; then + echo "$as_me:$LINENO: result: yes ($MYSQL_VERSION)" >&5 echo "${ECHO_T}yes ($MYSQL_VERSION)" >&6 - else - echo "$as_me:$LINENO: result: no" >&5 +else + echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 - if test "$require_mysql" = "yes" ; then - { { echo "$as_me:$LINENO: error: MySQL not found or incompatible (requested)" >&5 -echo "$as_me: error: MySQL not found or incompatible (requested)" >&2;} + { { echo "$as_me:$LINENO: error: MySQL not found or incompatible" >&5 +echo "$as_me: error: MySQL not found or incompatible" >&2;} { (exit 1); exit 1; }; } - else - { echo "$as_me:$LINENO: disabling MySQL (optional)" >&5 -echo "$as_me: disabling MySQL (optional)" >&6;} - MYSQL_VERSION="" - MYSQL_CFLAGS="" - MYSQL_LIBS="" - fi - fi fi @@ -6195,8 +6168,6 @@ do "3rdparty/mt19937ar/Makefile" ) CONFIG_FILES="$CONFIG_FILES 3rdparty/mt19937ar/Makefile" ;; "src/char/Makefile" ) CONFIG_FILES="$CONFIG_FILES src/char/Makefile" ;; "src/login/Makefile" ) CONFIG_FILES="$CONFIG_FILES src/login/Makefile" ;; - "src/char_sql/Makefile" ) CONFIG_FILES="$CONFIG_FILES src/char_sql/Makefile" ;; - "src/txt-converter/Makefile" ) CONFIG_FILES="$CONFIG_FILES src/txt-converter/Makefile" ;; "src/map/Makefile" ) CONFIG_FILES="$CONFIG_FILES src/map/Makefile" ;; "src/plugins/Makefile" ) CONFIG_FILES="$CONFIG_FILES src/plugins/Makefile" ;; "src/tool/Makefile" ) CONFIG_FILES="$CONFIG_FILES src/tool/Makefile" ;; diff --git a/configure.in b/configure.in index 8872e7c8c..3269537b2 100644 --- a/configure.in +++ b/configure.in @@ -8,7 +8,6 @@ AC_CONFIG_SRCDIR([src/common/cbasetypes.h]) AC_CONFIG_FILES([Makefile src/common/Makefile]) AC_CONFIG_FILES([3rdparty/mt19937ar/Makefile]) AC_CONFIG_FILES([src/char/Makefile src/login/Makefile]) -AC_CONFIG_FILES([src/char_sql/Makefile src/txt-converter/Makefile]) AC_CONFIG_FILES([src/map/Makefile src/plugins/Makefile src/tool/Makefile]) @@ -166,29 +165,22 @@ AC_ARG_ENABLE( # -# Enable/disable MySql and optionally specify the path to mysql_config (optional library) +# Optionally specify the path to mysql_config # AC_ARG_WITH( [mysql], AC_HELP_STRING( [--with-mysql@<:@=ARG@:>@], - [use MySQL client library, optionally specify the path to the mysql_config executable (by default mysql is used if found)] + [optionally specify the path to the mysql_config executable] ), [ - if test "$withval" = "no" ; then - want_mysql="no" - else - want_mysql="yes" - require_mysql="yes" - if test "$withval" != "yes" ; then - if test ! -x "$withval" ; then - AC_MSG_ERROR([$withval is not an executable file]) - fi - MYSQL_CONFIG_HOME="$withval" + if test "$withval" != "no" ; then + if test ! -x "$withval" ; then + AC_MSG_ERROR([$withval is not an executable file]) fi + MYSQL_CONFIG_HOME="$withval" fi - ], - [want_mysql="yes" require_mysql="no"] + ] ) @@ -632,52 +624,38 @@ fi # -# MySQL library (optional) +# MySQL library # -if test "$want_mysql" = "no" ; then - MYSQL_VERSION="" - MYSQL_CFLAGS="" - MYSQL_LIBS="" - AC_MSG_NOTICE([ignoring MySQL (optional)]) -else - if test -z "$MYSQL_CONFIG_HOME"; then - AC_PATH_PROG([MYSQL_CONFIG_HOME], [mysql_config], [no]) - fi +if test -z "$MYSQL_CONFIG_HOME"; then + AC_PATH_PROG([MYSQL_CONFIG_HOME], [mysql_config], [no]) +fi - if test "$MYSQL_CONFIG_HOME" != "no" ; then - MYSQL_VERSION="`$MYSQL_CONFIG_HOME --version`" - if test "$manual_MYSQL_CFLAGS" = "no" ; then - MYSQL_CFLAGS="`$MYSQL_CONFIG_HOME --include`" - fi - if test "$manual_MYSQL_LIBS" = "no" ; then - MYSQL_LIBS="`$MYSQL_CONFIG_HOME --libs`" - fi - else - MYSQL_VERSION="unknown" +if test "$MYSQL_CONFIG_HOME" != "no" ; then + MYSQL_VERSION="`$MYSQL_CONFIG_HOME --version`" + if test "$manual_MYSQL_CFLAGS" = "no" ; then + MYSQL_CFLAGS="`$MYSQL_CONFIG_HOME --include`" + fi + if test "$manual_MYSQL_LIBS" = "no" ; then + MYSQL_LIBS="`$MYSQL_CONFIG_HOME --libs`" fi +else + MYSQL_VERSION="unknown" +fi - MYSQL_OLD_LDFLAGS="$LDFLAGS" ; LDFLAGS="$LDFLAGS $MYSQL_LIBS" - MYSQL_OLD_CPPFLAGS="$CPPFLAGS" ; CPPFLAGS="$CPPFLAGS $MYSQL_CFLAGS" - AC_CHECK_LIB([mysqlclient], [mysql_init], [HAVE_MYSQL="yes"], []) - AC_CHECK_HEADER([mysql.h], [], [HAVE_MYSQL=""]) - CPPFLAGS="$MYSQL_OLD_CPPFLAGS" - LDFLAGS="$MYSQL_OLD_LDFLAGS" +MYSQL_OLD_LDFLAGS="$LDFLAGS" ; LDFLAGS="$LDFLAGS $MYSQL_LIBS" +MYSQL_OLD_CPPFLAGS="$CPPFLAGS" ; CPPFLAGS="$CPPFLAGS $MYSQL_CFLAGS" +AC_CHECK_LIB([mysqlclient], [mysql_init], [HAVE_MYSQL="yes"], []) +AC_CHECK_HEADER([mysql.h], [], [HAVE_MYSQL=""]) +CPPFLAGS="$MYSQL_OLD_CPPFLAGS" +LDFLAGS="$MYSQL_OLD_LDFLAGS" - AC_MSG_CHECKING([MySQL library (optional)]) - if test "$HAVE_MYSQL" = "yes" ; then - AC_MSG_RESULT([yes ($MYSQL_VERSION)]) - else - AC_MSG_RESULT([no]) - if test "$require_mysql" = "yes" ; then - AC_MSG_ERROR([MySQL not found or incompatible (requested)]) - else - AC_MSG_NOTICE([disabling MySQL (optional)]) - MYSQL_VERSION="" - MYSQL_CFLAGS="" - MYSQL_LIBS="" - fi - fi +AC_MSG_CHECKING([MySQL library (required)]) +if test "$HAVE_MYSQL" = "yes" ; then + AC_MSG_RESULT([yes ($MYSQL_VERSION)]) +else + AC_MSG_RESULT([no]) + AC_MSG_ERROR([MySQL not found or incompatible]) fi AC_SUBST([HAVE_MYSQL]) diff --git a/logserv.bat b/logserv.bat deleted file mode 100755 index a36e07f17..000000000 --- a/logserv.bat +++ /dev/null @@ -1,2 +0,0 @@ -@ECHO OFF -CALL serv.bat login-server.exe Login-Server diff --git a/mapserv.bat b/mapserv.bat deleted file mode 100755 index fc6235092..000000000 --- a/mapserv.bat +++ /dev/null @@ -1,2 +0,0 @@ -@ECHO OFF -CALL serv.bat map-server.exe Map-Server diff --git a/rAthena-10.sln b/rAthena-10.sln index 991395305..ea8847037 100644 --- a/rAthena-10.sln +++ b/rAthena-10.sln @@ -1,11 +1,5 @@ Microsoft Visual Studio Solution File, Format Version 11.00 # Visual Studio 2010 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "map-server_txt", "vcproj-10\map-server_txt.vcxproj", "{D356871D-58E1-450B-967A-E1E9646175AF}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "login-server_txt", "vcproj-10\login-server_txt.vcxproj", "{D356871D-58E1-450B-967A-E2E9646175AF}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "char-server_txt", "vcproj-10\char-server_txt.vcxproj", "{D356871D-58E1-450B-967A-E3E9646175AF}" -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "char-server_sql", "vcproj-10\char-server_sql.vcxproj", "{D356871D-58E1-450B-967A-E4E9646175AF}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "login-server_sql", "vcproj-10\login-server_sql.vcxproj", "{D356871D-58E1-450B-967A-E5E9646175AF}" @@ -14,112 +8,28 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "map-server_sql", "vcproj-10 EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mapcache", "vcproj-10\mapcache.vcxproj", "{D356871D-58E1-450B-967A-E7E9646175AF}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "txt-converter-login", "vcproj-10\txt-converter-login.vcxproj", "{D356871D-58E1-450B-967A-E9E9646175AF}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "txt-converter-char", "vcproj-10\txt-converter-char.vcxproj", "{D356871D-58E1-450B-967A-EAE9646175AF}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 - Debug-sql|Win32 = Debug-sql|Win32 - Debug-txt|Win32 = Debug-txt|Win32 Release|Win32 = Release|Win32 - Release-sql|Win32 = Release-sql|Win32 - Release-txt|Win32 = Release-txt|Win32 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {D356871D-58E1-450B-967A-E1E9646175AF}.Debug|Win32.ActiveCfg = Debug|Win32 - {D356871D-58E1-450B-967A-E1E9646175AF}.Debug|Win32.Build.0 = Debug|Win32 - {D356871D-58E1-450B-967A-E1E9646175AF}.Debug-sql|Win32.ActiveCfg = Debug|Win32 - {D356871D-58E1-450B-967A-E1E9646175AF}.Debug-txt|Win32.ActiveCfg = Debug|Win32 - {D356871D-58E1-450B-967A-E1E9646175AF}.Debug-txt|Win32.Build.0 = Debug|Win32 - {D356871D-58E1-450B-967A-E1E9646175AF}.Release|Win32.ActiveCfg = Release|Win32 - {D356871D-58E1-450B-967A-E1E9646175AF}.Release|Win32.Build.0 = Release|Win32 - {D356871D-58E1-450B-967A-E1E9646175AF}.Release-sql|Win32.ActiveCfg = Release|Win32 - {D356871D-58E1-450B-967A-E1E9646175AF}.Release-txt|Win32.ActiveCfg = Release|Win32 - {D356871D-58E1-450B-967A-E1E9646175AF}.Release-txt|Win32.Build.0 = Release|Win32 - {D356871D-58E1-450B-967A-E2E9646175AF}.Debug|Win32.ActiveCfg = Debug|Win32 - {D356871D-58E1-450B-967A-E2E9646175AF}.Debug|Win32.Build.0 = Debug|Win32 - {D356871D-58E1-450B-967A-E2E9646175AF}.Debug-sql|Win32.ActiveCfg = Debug|Win32 - {D356871D-58E1-450B-967A-E2E9646175AF}.Debug-txt|Win32.ActiveCfg = Debug|Win32 - {D356871D-58E1-450B-967A-E2E9646175AF}.Debug-txt|Win32.Build.0 = Debug|Win32 - {D356871D-58E1-450B-967A-E2E9646175AF}.Release|Win32.ActiveCfg = Release|Win32 - {D356871D-58E1-450B-967A-E2E9646175AF}.Release|Win32.Build.0 = Release|Win32 - {D356871D-58E1-450B-967A-E2E9646175AF}.Release-sql|Win32.ActiveCfg = Release|Win32 - {D356871D-58E1-450B-967A-E2E9646175AF}.Release-txt|Win32.ActiveCfg = Release|Win32 - {D356871D-58E1-450B-967A-E2E9646175AF}.Release-txt|Win32.Build.0 = Release|Win32 - {D356871D-58E1-450B-967A-E3E9646175AF}.Debug|Win32.ActiveCfg = Debug|Win32 - {D356871D-58E1-450B-967A-E3E9646175AF}.Debug|Win32.Build.0 = Debug|Win32 - {D356871D-58E1-450B-967A-E3E9646175AF}.Debug-sql|Win32.ActiveCfg = Debug|Win32 - {D356871D-58E1-450B-967A-E3E9646175AF}.Debug-txt|Win32.ActiveCfg = Debug|Win32 - {D356871D-58E1-450B-967A-E3E9646175AF}.Debug-txt|Win32.Build.0 = Debug|Win32 - {D356871D-58E1-450B-967A-E3E9646175AF}.Release|Win32.ActiveCfg = Release|Win32 - {D356871D-58E1-450B-967A-E3E9646175AF}.Release|Win32.Build.0 = Release|Win32 - {D356871D-58E1-450B-967A-E3E9646175AF}.Release-sql|Win32.ActiveCfg = Release|Win32 - {D356871D-58E1-450B-967A-E3E9646175AF}.Release-txt|Win32.ActiveCfg = Release|Win32 - {D356871D-58E1-450B-967A-E3E9646175AF}.Release-txt|Win32.Build.0 = Release|Win32 {D356871D-58E1-450B-967A-E4E9646175AF}.Debug|Win32.ActiveCfg = Debug|Win32 {D356871D-58E1-450B-967A-E4E9646175AF}.Debug|Win32.Build.0 = Debug|Win32 - {D356871D-58E1-450B-967A-E4E9646175AF}.Debug-sql|Win32.ActiveCfg = Debug|Win32 - {D356871D-58E1-450B-967A-E4E9646175AF}.Debug-sql|Win32.Build.0 = Debug|Win32 - {D356871D-58E1-450B-967A-E4E9646175AF}.Debug-txt|Win32.ActiveCfg = Debug|Win32 {D356871D-58E1-450B-967A-E4E9646175AF}.Release|Win32.ActiveCfg = Release|Win32 {D356871D-58E1-450B-967A-E4E9646175AF}.Release|Win32.Build.0 = Release|Win32 - {D356871D-58E1-450B-967A-E4E9646175AF}.Release-sql|Win32.ActiveCfg = Release|Win32 - {D356871D-58E1-450B-967A-E4E9646175AF}.Release-sql|Win32.Build.0 = Release|Win32 - {D356871D-58E1-450B-967A-E4E9646175AF}.Release-txt|Win32.ActiveCfg = Release|Win32 {D356871D-58E1-450B-967A-E5E9646175AF}.Debug|Win32.ActiveCfg = Debug|Win32 {D356871D-58E1-450B-967A-E5E9646175AF}.Debug|Win32.Build.0 = Debug|Win32 - {D356871D-58E1-450B-967A-E5E9646175AF}.Debug-sql|Win32.ActiveCfg = Debug|Win32 - {D356871D-58E1-450B-967A-E5E9646175AF}.Debug-sql|Win32.Build.0 = Debug|Win32 - {D356871D-58E1-450B-967A-E5E9646175AF}.Debug-txt|Win32.ActiveCfg = Debug|Win32 {D356871D-58E1-450B-967A-E5E9646175AF}.Release|Win32.ActiveCfg = Release|Win32 {D356871D-58E1-450B-967A-E5E9646175AF}.Release|Win32.Build.0 = Release|Win32 - {D356871D-58E1-450B-967A-E5E9646175AF}.Release-sql|Win32.ActiveCfg = Release|Win32 - {D356871D-58E1-450B-967A-E5E9646175AF}.Release-sql|Win32.Build.0 = Release|Win32 - {D356871D-58E1-450B-967A-E5E9646175AF}.Release-txt|Win32.ActiveCfg = Release|Win32 {D356871D-58E1-450B-967A-E6E9646175AF}.Debug|Win32.ActiveCfg = Debug|Win32 {D356871D-58E1-450B-967A-E6E9646175AF}.Debug|Win32.Build.0 = Debug|Win32 - {D356871D-58E1-450B-967A-E6E9646175AF}.Debug-sql|Win32.ActiveCfg = Debug|Win32 - {D356871D-58E1-450B-967A-E6E9646175AF}.Debug-sql|Win32.Build.0 = Debug|Win32 - {D356871D-58E1-450B-967A-E6E9646175AF}.Debug-txt|Win32.ActiveCfg = Debug|Win32 {D356871D-58E1-450B-967A-E6E9646175AF}.Release|Win32.ActiveCfg = Release|Win32 {D356871D-58E1-450B-967A-E6E9646175AF}.Release|Win32.Build.0 = Release|Win32 - {D356871D-58E1-450B-967A-E6E9646175AF}.Release-sql|Win32.ActiveCfg = Release|Win32 - {D356871D-58E1-450B-967A-E6E9646175AF}.Release-sql|Win32.Build.0 = Release|Win32 - {D356871D-58E1-450B-967A-E6E9646175AF}.Release-txt|Win32.ActiveCfg = Release|Win32 {D356871D-58E1-450B-967A-E7E9646175AF}.Debug|Win32.ActiveCfg = Debug|Win32 {D356871D-58E1-450B-967A-E7E9646175AF}.Debug|Win32.Build.0 = Debug|Win32 - {D356871D-58E1-450B-967A-E7E9646175AF}.Debug-sql|Win32.ActiveCfg = Debug|Win32 - {D356871D-58E1-450B-967A-E7E9646175AF}.Debug-sql|Win32.Build.0 = Debug|Win32 - {D356871D-58E1-450B-967A-E7E9646175AF}.Debug-txt|Win32.ActiveCfg = Debug|Win32 - {D356871D-58E1-450B-967A-E7E9646175AF}.Debug-txt|Win32.Build.0 = Debug|Win32 {D356871D-58E1-450B-967A-E7E9646175AF}.Release|Win32.ActiveCfg = Release|Win32 {D356871D-58E1-450B-967A-E7E9646175AF}.Release|Win32.Build.0 = Release|Win32 - {D356871D-58E1-450B-967A-E7E9646175AF}.Release-sql|Win32.ActiveCfg = Release|Win32 - {D356871D-58E1-450B-967A-E7E9646175AF}.Release-sql|Win32.Build.0 = Release|Win32 - {D356871D-58E1-450B-967A-E7E9646175AF}.Release-txt|Win32.ActiveCfg = Release|Win32 - {D356871D-58E1-450B-967A-E7E9646175AF}.Release-txt|Win32.Build.0 = Release|Win32 - {D356871D-58E1-450B-967A-E9E9646175AF}.Debug|Win32.ActiveCfg = Debug|Win32 - {D356871D-58E1-450B-967A-E9E9646175AF}.Debug|Win32.Build.0 = Debug|Win32 - {D356871D-58E1-450B-967A-E9E9646175AF}.Debug-sql|Win32.ActiveCfg = Debug|Win32 - {D356871D-58E1-450B-967A-E9E9646175AF}.Debug-txt|Win32.ActiveCfg = Debug|Win32 - {D356871D-58E1-450B-967A-E9E9646175AF}.Debug-txt|Win32.Build.0 = Debug|Win32 - {D356871D-58E1-450B-967A-E9E9646175AF}.Release|Win32.ActiveCfg = Release|Win32 - {D356871D-58E1-450B-967A-E9E9646175AF}.Release|Win32.Build.0 = Release|Win32 - {D356871D-58E1-450B-967A-E9E9646175AF}.Release-sql|Win32.ActiveCfg = Release|Win32 - {D356871D-58E1-450B-967A-E9E9646175AF}.Release-txt|Win32.ActiveCfg = Release|Win32 - {D356871D-58E1-450B-967A-E9E9646175AF}.Release-txt|Win32.Build.0 = Release|Win32 - {D356871D-58E1-450B-967A-EAE9646175AF}.Debug|Win32.ActiveCfg = Debug|Win32 - {D356871D-58E1-450B-967A-EAE9646175AF}.Debug|Win32.Build.0 = Debug|Win32 - {D356871D-58E1-450B-967A-EAE9646175AF}.Debug-sql|Win32.ActiveCfg = Debug|Win32 - {D356871D-58E1-450B-967A-EAE9646175AF}.Debug-txt|Win32.ActiveCfg = Debug|Win32 - {D356871D-58E1-450B-967A-EAE9646175AF}.Debug-txt|Win32.Build.0 = Debug|Win32 - {D356871D-58E1-450B-967A-EAE9646175AF}.Release|Win32.ActiveCfg = Release|Win32 - {D356871D-58E1-450B-967A-EAE9646175AF}.Release|Win32.Build.0 = Release|Win32 - {D356871D-58E1-450B-967A-EAE9646175AF}.Release-sql|Win32.ActiveCfg = Release|Win32 - {D356871D-58E1-450B-967A-EAE9646175AF}.Release-txt|Win32.ActiveCfg = Release|Win32 - {D356871D-58E1-450B-967A-EAE9646175AF}.Release-txt|Win32.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/rAthena-9.sln b/rAthena-9.sln index 7a1f69c67..7d8588f07 100644 --- a/rAthena-9.sln +++ b/rAthena-9.sln @@ -1,11 +1,5 @@ Microsoft Visual Studio Solution File, Format Version 10.00 # Visual Studio 2008 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "map-server_txt", "vcproj-9\map-server_txt.vcproj", "{D356871D-58E1-450B-967A-E1E9646175AF}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "login-server_txt", "vcproj-9\login-server_txt.vcproj", "{D356871D-58E1-450B-967A-E2E9646175AF}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "char-server_txt", "vcproj-9\char-server_txt.vcproj", "{D356871D-58E1-450B-967A-E3E9646175AF}" -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "char-server_sql", "vcproj-9\char-server_sql.vcproj", "{D356871D-58E1-450B-967A-E4E9646175AF}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "login-server_sql", "vcproj-9\login-server_sql.vcproj", "{D356871D-58E1-450B-967A-E5E9646175AF}" @@ -14,10 +8,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "map-server_sql", "vcproj-9\ EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mapcache", "vcproj-9\mapcache.vcproj", "{D356871D-58E1-450B-967A-E7E9646175AF}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "txt-converter-login", "vcproj-9\txt-converter-login.vcproj", "{D356871D-58E1-450B-967A-E9E9646175AF}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "txt-converter-char", "vcproj-9\txt-converter-char.vcproj", "{D356871D-58E1-450B-967A-EAE9646175AF}" -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "plugin-console", "vcproj-9\plugin-console.vcproj", "{73E1101A-310C-4453-8F45-FD2795ABEF15}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "plugin-pid", "vcproj-9\plugin-pid.vcproj", "{9509E1B9-DA2B-4153-9EE0-CBCA6597F198}" @@ -25,105 +15,25 @@ EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 - Debug-sql|Win32 = Debug-sql|Win32 - Debug-txt|Win32 = Debug-txt|Win32 Release|Win32 = Release|Win32 - Release-sql|Win32 = Release-sql|Win32 - Release-txt|Win32 = Release-txt|Win32 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {D356871D-58E1-450B-967A-E1E9646175AF}.Debug|Win32.ActiveCfg = Debug|Win32 - {D356871D-58E1-450B-967A-E1E9646175AF}.Debug|Win32.Build.0 = Debug|Win32 - {D356871D-58E1-450B-967A-E1E9646175AF}.Debug-sql|Win32.ActiveCfg = Debug|Win32 - {D356871D-58E1-450B-967A-E1E9646175AF}.Debug-txt|Win32.ActiveCfg = Debug|Win32 - {D356871D-58E1-450B-967A-E1E9646175AF}.Debug-txt|Win32.Build.0 = Debug|Win32 - {D356871D-58E1-450B-967A-E1E9646175AF}.Release|Win32.ActiveCfg = Release|Win32 - {D356871D-58E1-450B-967A-E1E9646175AF}.Release|Win32.Build.0 = Release|Win32 - {D356871D-58E1-450B-967A-E1E9646175AF}.Release-sql|Win32.ActiveCfg = Release|Win32 - {D356871D-58E1-450B-967A-E1E9646175AF}.Release-txt|Win32.ActiveCfg = Release|Win32 - {D356871D-58E1-450B-967A-E1E9646175AF}.Release-txt|Win32.Build.0 = Release|Win32 - {D356871D-58E1-450B-967A-E2E9646175AF}.Debug|Win32.ActiveCfg = Debug|Win32 - {D356871D-58E1-450B-967A-E2E9646175AF}.Debug|Win32.Build.0 = Debug|Win32 - {D356871D-58E1-450B-967A-E2E9646175AF}.Debug-sql|Win32.ActiveCfg = Debug|Win32 - {D356871D-58E1-450B-967A-E2E9646175AF}.Debug-txt|Win32.ActiveCfg = Debug|Win32 - {D356871D-58E1-450B-967A-E2E9646175AF}.Debug-txt|Win32.Build.0 = Debug|Win32 - {D356871D-58E1-450B-967A-E2E9646175AF}.Release|Win32.ActiveCfg = Release|Win32 - {D356871D-58E1-450B-967A-E2E9646175AF}.Release|Win32.Build.0 = Release|Win32 - {D356871D-58E1-450B-967A-E2E9646175AF}.Release-sql|Win32.ActiveCfg = Release|Win32 - {D356871D-58E1-450B-967A-E2E9646175AF}.Release-txt|Win32.ActiveCfg = Release|Win32 - {D356871D-58E1-450B-967A-E2E9646175AF}.Release-txt|Win32.Build.0 = Release|Win32 - {D356871D-58E1-450B-967A-E3E9646175AF}.Debug|Win32.ActiveCfg = Debug|Win32 - {D356871D-58E1-450B-967A-E3E9646175AF}.Debug|Win32.Build.0 = Debug|Win32 - {D356871D-58E1-450B-967A-E3E9646175AF}.Debug-sql|Win32.ActiveCfg = Debug|Win32 - {D356871D-58E1-450B-967A-E3E9646175AF}.Debug-txt|Win32.ActiveCfg = Debug|Win32 - {D356871D-58E1-450B-967A-E3E9646175AF}.Debug-txt|Win32.Build.0 = Debug|Win32 - {D356871D-58E1-450B-967A-E3E9646175AF}.Release|Win32.ActiveCfg = Release|Win32 - {D356871D-58E1-450B-967A-E3E9646175AF}.Release|Win32.Build.0 = Release|Win32 - {D356871D-58E1-450B-967A-E3E9646175AF}.Release-sql|Win32.ActiveCfg = Release|Win32 - {D356871D-58E1-450B-967A-E3E9646175AF}.Release-txt|Win32.ActiveCfg = Release|Win32 - {D356871D-58E1-450B-967A-E3E9646175AF}.Release-txt|Win32.Build.0 = Release|Win32 {D356871D-58E1-450B-967A-E4E9646175AF}.Debug|Win32.ActiveCfg = Debug|Win32 {D356871D-58E1-450B-967A-E4E9646175AF}.Debug|Win32.Build.0 = Debug|Win32 - {D356871D-58E1-450B-967A-E4E9646175AF}.Debug-sql|Win32.ActiveCfg = Debug|Win32 - {D356871D-58E1-450B-967A-E4E9646175AF}.Debug-sql|Win32.Build.0 = Debug|Win32 - {D356871D-58E1-450B-967A-E4E9646175AF}.Debug-txt|Win32.ActiveCfg = Debug|Win32 {D356871D-58E1-450B-967A-E4E9646175AF}.Release|Win32.ActiveCfg = Release|Win32 {D356871D-58E1-450B-967A-E4E9646175AF}.Release|Win32.Build.0 = Release|Win32 - {D356871D-58E1-450B-967A-E4E9646175AF}.Release-sql|Win32.ActiveCfg = Release|Win32 - {D356871D-58E1-450B-967A-E4E9646175AF}.Release-sql|Win32.Build.0 = Release|Win32 - {D356871D-58E1-450B-967A-E4E9646175AF}.Release-txt|Win32.ActiveCfg = Release|Win32 {D356871D-58E1-450B-967A-E5E9646175AF}.Debug|Win32.ActiveCfg = Debug|Win32 {D356871D-58E1-450B-967A-E5E9646175AF}.Debug|Win32.Build.0 = Debug|Win32 - {D356871D-58E1-450B-967A-E5E9646175AF}.Debug-sql|Win32.ActiveCfg = Debug|Win32 - {D356871D-58E1-450B-967A-E5E9646175AF}.Debug-sql|Win32.Build.0 = Debug|Win32 - {D356871D-58E1-450B-967A-E5E9646175AF}.Debug-txt|Win32.ActiveCfg = Debug|Win32 {D356871D-58E1-450B-967A-E5E9646175AF}.Release|Win32.ActiveCfg = Release|Win32 {D356871D-58E1-450B-967A-E5E9646175AF}.Release|Win32.Build.0 = Release|Win32 - {D356871D-58E1-450B-967A-E5E9646175AF}.Release-sql|Win32.ActiveCfg = Release|Win32 - {D356871D-58E1-450B-967A-E5E9646175AF}.Release-sql|Win32.Build.0 = Release|Win32 - {D356871D-58E1-450B-967A-E5E9646175AF}.Release-txt|Win32.ActiveCfg = Release|Win32 {D356871D-58E1-450B-967A-E6E9646175AF}.Debug|Win32.ActiveCfg = Debug|Win32 {D356871D-58E1-450B-967A-E6E9646175AF}.Debug|Win32.Build.0 = Debug|Win32 - {D356871D-58E1-450B-967A-E6E9646175AF}.Debug-sql|Win32.ActiveCfg = Debug|Win32 - {D356871D-58E1-450B-967A-E6E9646175AF}.Debug-sql|Win32.Build.0 = Debug|Win32 - {D356871D-58E1-450B-967A-E6E9646175AF}.Debug-txt|Win32.ActiveCfg = Debug|Win32 {D356871D-58E1-450B-967A-E6E9646175AF}.Release|Win32.ActiveCfg = Release|Win32 {D356871D-58E1-450B-967A-E6E9646175AF}.Release|Win32.Build.0 = Release|Win32 - {D356871D-58E1-450B-967A-E6E9646175AF}.Release-sql|Win32.ActiveCfg = Release|Win32 - {D356871D-58E1-450B-967A-E6E9646175AF}.Release-sql|Win32.Build.0 = Release|Win32 - {D356871D-58E1-450B-967A-E6E9646175AF}.Release-txt|Win32.ActiveCfg = Release|Win32 {D356871D-58E1-450B-967A-E7E9646175AF}.Debug|Win32.ActiveCfg = Debug|Win32 {D356871D-58E1-450B-967A-E7E9646175AF}.Debug|Win32.Build.0 = Debug|Win32 - {D356871D-58E1-450B-967A-E7E9646175AF}.Debug-sql|Win32.ActiveCfg = Debug|Win32 - {D356871D-58E1-450B-967A-E7E9646175AF}.Debug-sql|Win32.Build.0 = Debug|Win32 - {D356871D-58E1-450B-967A-E7E9646175AF}.Debug-txt|Win32.ActiveCfg = Debug|Win32 - {D356871D-58E1-450B-967A-E7E9646175AF}.Debug-txt|Win32.Build.0 = Debug|Win32 {D356871D-58E1-450B-967A-E7E9646175AF}.Release|Win32.ActiveCfg = Release|Win32 {D356871D-58E1-450B-967A-E7E9646175AF}.Release|Win32.Build.0 = Release|Win32 - {D356871D-58E1-450B-967A-E7E9646175AF}.Release-sql|Win32.ActiveCfg = Release|Win32 - {D356871D-58E1-450B-967A-E7E9646175AF}.Release-sql|Win32.Build.0 = Release|Win32 - {D356871D-58E1-450B-967A-E7E9646175AF}.Release-txt|Win32.ActiveCfg = Release|Win32 - {D356871D-58E1-450B-967A-E7E9646175AF}.Release-txt|Win32.Build.0 = Release|Win32 - {D356871D-58E1-450B-967A-E9E9646175AF}.Debug|Win32.ActiveCfg = Debug|Win32 - {D356871D-58E1-450B-967A-E9E9646175AF}.Debug|Win32.Build.0 = Debug|Win32 - {D356871D-58E1-450B-967A-E9E9646175AF}.Debug-sql|Win32.ActiveCfg = Debug|Win32 - {D356871D-58E1-450B-967A-E9E9646175AF}.Debug-txt|Win32.ActiveCfg = Debug|Win32 - {D356871D-58E1-450B-967A-E9E9646175AF}.Debug-txt|Win32.Build.0 = Debug|Win32 - {D356871D-58E1-450B-967A-E9E9646175AF}.Release|Win32.ActiveCfg = Release|Win32 - {D356871D-58E1-450B-967A-E9E9646175AF}.Release|Win32.Build.0 = Release|Win32 - {D356871D-58E1-450B-967A-E9E9646175AF}.Release-sql|Win32.ActiveCfg = Release|Win32 - {D356871D-58E1-450B-967A-E9E9646175AF}.Release-txt|Win32.ActiveCfg = Release|Win32 - {D356871D-58E1-450B-967A-E9E9646175AF}.Release-txt|Win32.Build.0 = Release|Win32 - {D356871D-58E1-450B-967A-EAE9646175AF}.Debug|Win32.ActiveCfg = Debug|Win32 - {D356871D-58E1-450B-967A-EAE9646175AF}.Debug|Win32.Build.0 = Debug|Win32 - {D356871D-58E1-450B-967A-EAE9646175AF}.Debug-sql|Win32.ActiveCfg = Debug|Win32 - {D356871D-58E1-450B-967A-EAE9646175AF}.Debug-txt|Win32.ActiveCfg = Debug|Win32 - {D356871D-58E1-450B-967A-EAE9646175AF}.Debug-txt|Win32.Build.0 = Debug|Win32 - {D356871D-58E1-450B-967A-EAE9646175AF}.Release|Win32.ActiveCfg = Release|Win32 - {D356871D-58E1-450B-967A-EAE9646175AF}.Release|Win32.Build.0 = Release|Win32 - {D356871D-58E1-450B-967A-EAE9646175AF}.Release-sql|Win32.ActiveCfg = Release|Win32 - {D356871D-58E1-450B-967A-EAE9646175AF}.Release-txt|Win32.ActiveCfg = Release|Win32 - {D356871D-58E1-450B-967A-EAE9646175AF}.Release-txt|Win32.Build.0 = Release|Win32 {73E1101A-310C-4453-8F45-FD2795ABEF15}.Debug|Win32.ActiveCfg = Debug|Win32 {73E1101A-310C-4453-8F45-FD2795ABEF15}.Debug|Win32.Build.0 = Debug|Win32 {73E1101A-310C-4453-8F45-FD2795ABEF15}.Release|Win32.ActiveCfg = Release|Win32 diff --git a/runserver.bat b/runserver.bat deleted file mode 100755 index 553274013..000000000 --- a/runserver.bat +++ /dev/null @@ -1,75 +0,0 @@ -@echo off - -rem ----- Configuration ----- - rem Defines the server type (txt or sql). - set SERVER_TYPE=txt - rem Defines how long to wait before restarting (in seconds). - set SLEEP_TIME=15 - rem Defines whether to run all servers in one window (yes or no). - set SINGLE_WINDOW=no -rem ----- ------------- ----- - -:L_Init - set this=%0 - if %SERVER_TYPE% == txt set suffix= - if %SERVER_TYPE% == sql set suffix=_sql - if %SINGLE_WINDOW% == yes set wndswitch=/B - -:L_Main - set command=%1 - if "%command%" == "" goto L_DefaultAction - - if %command% == exec goto L_ExecServerExe - if %command% == start goto L_StartServerExe - if %command% == stop goto L_StopServerExe - if %command% == restart echo "TODO" - goto L_EOF - -:L_DefaultAction -:L_StartServer - call %this% start login-server%suffix%.exe - call %this% start char-server%suffix%.exe - call %this% start map-server%suffix%.exe - goto L_EOF - -:L_StopServer - call %this% stop login-server%suffix%.exe - call %this% stop char-server%suffix%.exe - call %this% stop map-server%suffix%.exe - goto L_EOF - -:L_StartServerExe - set filename=%2 - if "%filename%" == "" goto L_StartServer - if exist %filename% goto L_HaveExe - echo Cannot start '%filename%' because the file is missing! - goto L_EOF - - :L_HaveExe - echo Starting %filename%... - start "%filename%" %wndswitch% %this% exec %filename% - goto L_EOF - -:L_StopServerExe - set filename=%2 - if "%filename%" == "" goto L_StopServer - if exist %windir%\system32\taskkill.exe goto L_HaveTaskKill - echo The 'stop' command is not available on your system. - exit - - :L_HaveTaskKill - rem CAUTION! This will kill all processes called %filename%. - echo Stopping '%filename%'... - taskkill /F /FI "WINDOWTITLE eq %filename% - %this% exec %filename%" - taskkill /F /IM "%filename%" - goto L_EOF - -:L_ExecServerExe - %filename% - echo . - echo . - echo Server exited, restarting in %SLEEP_TIME% seconds! Press CTRL+C to abort! - ping.exe -n %SLEEP_TIME% 127.0.0.1 > nul - goto L_ExecServerExe - -:L_EOF diff --git a/save-tmpl/account.txt b/save-tmpl/account.txt deleted file mode 100644 index eadbc4c4f..000000000 --- a/save-tmpl/account.txt +++ /dev/null @@ -1,16 +0,0 @@ -20110114 -// Accounts file: here are saved all information about the accounts. -// Structure: account ID, username, password, sex, email, level, state, unban time, expiration time, # of logins, last login time, last (accepted) login ip, birth date, repeated(register key, register value) -// where: -// sex : M or F for normal accounts, S for server accounts -// level : this account's gm level -// state : 0: account is ok, 1 to 256: error code of packet 0x006a + 1 -// unban time : 0: no ban, : banned until the date (unix timestamp) -// expiration time : 0: unlimited account, : account expires on the date (unix timestamp) -1 s1 p1 S a@a.com 0 0 0 0 0 0000-00-00 00:00:00 - 0000-00-00 -2 s2 p2 S a@a.com 0 0 0 0 0 0000-00-00 00:00:00 - 0000-00-00 -3 s3 p3 S a@a.com 0 0 0 0 0 0000-00-00 00:00:00 - 0000-00-00 -4 s4 p4 S a@a.com 0 0 0 0 0 0000-00-00 00:00:00 - 0000-00-00 -5 s5 p5 S a@a.com 0 0 0 0 0 0000-00-00 00:00:00 - 0000-00-00 -2000001 Test Test M a@a.com 0 0 0 0 0 0000-00-00 00:00:00 - 0000-00-00 -2000002 %newid% diff --git a/save-tmpl/accreg.txt b/save-tmpl/accreg.txt deleted file mode 100644 index e69de29bb..000000000 diff --git a/save-tmpl/athena.txt b/save-tmpl/athena.txt deleted file mode 100644 index e69de29bb..000000000 diff --git a/save-tmpl/athena_backup.txt b/save-tmpl/athena_backup.txt deleted file mode 100644 index e69de29bb..000000000 diff --git a/save-tmpl/castle.txt b/save-tmpl/castle.txt deleted file mode 100644 index 5270d976b..000000000 --- a/save-tmpl/castle.txt +++ /dev/null @@ -1,34 +0,0 @@ -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -10,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -13,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -17,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -18,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -19,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -21,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -22,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -24,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -25,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -26,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -27,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -29,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -30,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -33,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 diff --git a/save-tmpl/friends.txt b/save-tmpl/friends.txt deleted file mode 100644 index e69de29bb..000000000 diff --git a/save-tmpl/g_storage.txt b/save-tmpl/g_storage.txt deleted file mode 100644 index e69de29bb..000000000 diff --git a/save-tmpl/guild.txt b/save-tmpl/guild.txt deleted file mode 100644 index e69de29bb..000000000 diff --git a/save-tmpl/homun.txt b/save-tmpl/homun.txt deleted file mode 100644 index e69de29bb..000000000 diff --git a/save-tmpl/mapreg.txt b/save-tmpl/mapreg.txt deleted file mode 100644 index e69de29bb..000000000 diff --git a/save-tmpl/party.txt b/save-tmpl/party.txt deleted file mode 100644 index e69de29bb..000000000 diff --git a/save-tmpl/pet.txt b/save-tmpl/pet.txt deleted file mode 100644 index e69de29bb..000000000 diff --git a/save-tmpl/scdata.txt b/save-tmpl/scdata.txt deleted file mode 100644 index e69de29bb..000000000 diff --git a/save-tmpl/storage.txt b/save-tmpl/storage.txt deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7ec05e405..0c120f99a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -3,11 +3,6 @@ # setup and static libraries # add_subdirectory( common ) -if( HAVE_common_base ) - option( BUILD_TXT_SERVERS "build txt server executables" ON ) -else() - message( STATUS "Disabled txt server targets (requires common_base)" ) -endif() if( HAVE_common_sql ) option( BUILD_SQL_SERVERS "build sql server executables" ON ) else() @@ -20,8 +15,6 @@ endif() # add_subdirectory( login ) add_subdirectory( char ) -add_subdirectory( char_sql ) add_subdirectory( map ) add_subdirectory( tool ) -add_subdirectory( txt-converter ) add_subdirectory( plugins ) diff --git a/src/char/CMakeLists.txt b/src/char/CMakeLists.txt index fa1c3f366..823939393 100644 --- a/src/char/CMakeLists.txt +++ b/src/char/CMakeLists.txt @@ -2,52 +2,57 @@ # # setup # -set( TXT_CHAR_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR} CACHE INTERNAL "" ) +set( SQL_CHAR_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR} CACHE INTERNAL "" ) # -# char txt +# char sql # -if( BUILD_TXT_SERVERS ) -message( STATUS "Creating target char-server" ) -set( TXT_CHAR_HEADERS - "${TXT_CHAR_SOURCE_DIR}/char.h" - "${TXT_CHAR_SOURCE_DIR}/int_guild.h" - "${TXT_CHAR_SOURCE_DIR}/int_homun.h" - "${TXT_CHAR_SOURCE_DIR}/int_party.h" - "${TXT_CHAR_SOURCE_DIR}/int_pet.h" - "${TXT_CHAR_SOURCE_DIR}/int_status.h" - "${TXT_CHAR_SOURCE_DIR}/int_storage.h" - "${TXT_CHAR_SOURCE_DIR}/inter.h" +if( BUILD_SQL_SERVERS ) +message( STATUS "Creating target char-server_sql" ) +set( SQL_CHAR_HEADERS + "${CMAKE_CURRENT_SOURCE_DIR}/char.h" + "${CMAKE_CURRENT_SOURCE_DIR}/int_auction.h" + "${CMAKE_CURRENT_SOURCE_DIR}/int_guild.h" + "${CMAKE_CURRENT_SOURCE_DIR}/int_homun.h" + "${CMAKE_CURRENT_SOURCE_DIR}/int_mail.h" + "${CMAKE_CURRENT_SOURCE_DIR}/int_mercenary.h" + "${CMAKE_CURRENT_SOURCE_DIR}/int_party.h" + "${CMAKE_CURRENT_SOURCE_DIR}/int_pet.h" + "${CMAKE_CURRENT_SOURCE_DIR}/int_quest.h" + "${CMAKE_CURRENT_SOURCE_DIR}/int_storage.h" + "${CMAKE_CURRENT_SOURCE_DIR}/inter.h" ) -set( TXT_CHAR_SOURCES - "${TXT_CHAR_SOURCE_DIR}/char.c" - "${TXT_CHAR_SOURCE_DIR}/int_guild.c" - "${TXT_CHAR_SOURCE_DIR}/int_homun.c" - "${TXT_CHAR_SOURCE_DIR}/int_party.c" - "${TXT_CHAR_SOURCE_DIR}/int_pet.c" - "${TXT_CHAR_SOURCE_DIR}/int_status.c" - "${TXT_CHAR_SOURCE_DIR}/int_storage.c" - "${TXT_CHAR_SOURCE_DIR}/inter.c" +set( SQL_CHAR_SOURCES + "${CMAKE_CURRENT_SOURCE_DIR}/char.c" + "${CMAKE_CURRENT_SOURCE_DIR}/int_auction.c" + "${CMAKE_CURRENT_SOURCE_DIR}/int_guild.c" + "${CMAKE_CURRENT_SOURCE_DIR}/int_homun.c" + "${CMAKE_CURRENT_SOURCE_DIR}/int_mail.c" + "${CMAKE_CURRENT_SOURCE_DIR}/int_mercenary.c" + "${CMAKE_CURRENT_SOURCE_DIR}/int_party.c" + "${CMAKE_CURRENT_SOURCE_DIR}/int_pet.c" + "${CMAKE_CURRENT_SOURCE_DIR}/int_quest.c" + "${CMAKE_CURRENT_SOURCE_DIR}/int_storage.c" + "${CMAKE_CURRENT_SOURCE_DIR}/inter.c" ) -set( DEPENDENCIES common_base ) +set( DEPENDENCIES common_sql ) set( LIBRARIES ${GLOBAL_LIBRARIES} ) set( INCLUDE_DIRS ${GLOBAL_INCLUDE_DIRS} ) -set( DEFINITIONS "${GLOBAL_DEFINITIONS} -DTXT_ONLY" ) -set( SOURCE_FILES ${COMMON_BASE_HEADERS} ${TXT_CHAR_HEADERS} ${TXT_CHAR_SOURCES} ) -source_group( common FILES ${COMMON_BASE_HEADERS} ) -source_group( char FILES ${TXT_CHAR_HEADERS} ${TXT_CHAR_SOURCES} ) +set( DEFINITIONS "${GLOBAL_DEFINITIONS}" ) +set( SOURCE_FILES ${COMMON_BASE_HEADERS} ${COMMON_SQL_HEADERS} ${SQL_CHAR_HEADERS} ${SQL_CHAR_SOURCES} ) +source_group( common FILES ${COMMON_BASE_HEADERS} ${COMMON_SQL_HEADERS} ) +source_group( char FILES ${SQL_CHAR_HEADERS} ${SQL_CHAR_SOURCES} ) include_directories( ${INCLUDE_DIRS} ) -add_executable( char-server ${SOURCE_FILES} ) -add_dependencies( char-server ${DEPENDENCIES} ) -target_link_libraries( char-server ${LIBRARIES} ${DEPENDENCIES} ) -set_target_properties( char-server PROPERTIES COMPILE_FLAGS "${DEFINITIONS}" ) +add_executable( char-server_sql ${SOURCE_FILES} ) +add_dependencies( char-server_sql ${DEPENDENCIES} ) +target_link_libraries( char-server_sql ${LIBRARIES} ${DEPENDENCIES} ) +set_target_properties( char-server_sql PROPERTIES COMPILE_FLAGS "${DEFINITIONS}" ) if( INSTALL_COMPONENT_RUNTIME ) - cpack_add_component( Runtime_charserver_txt DESCRIPTION "char-server (txt version)" DISPLAY_NAME "char-server" GROUP Runtime ) - install( TARGETS char-server + cpack_add_component( Runtime_charserver_sql DESCRIPTION "char-server (sql version)" DISPLAY_NAME "char-server_sql" GROUP Runtime ) + install( TARGETS char-server_sql DESTINATION "." - COMPONENT Runtime_charserver_txt ) + COMPONENT Runtime_charserver_sql ) endif( INSTALL_COMPONENT_RUNTIME ) -set( TARGET_LIST ${TARGET_LIST} char-server CACHE INTERNAL "" ) -message( STATUS "Creating target char-server - done" ) -endif( BUILD_TXT_SERVERS ) +message( STATUS "Creating target char-server_sql - done" ) +endif( BUILD_SQL_SERVERS ) diff --git a/src/char/Makefile.in b/src/char/Makefile.in index 1fd54b20b..e96113f0e 100644 --- a/src/char/Makefile.in +++ b/src/char/Makefile.in @@ -14,41 +14,58 @@ MT19937AR_OBJ = ../../3rdparty/mt19937ar/mt19937ar.o MT19937AR_H = ../../3rdparty/mt19937ar/mt19937ar.h MT19937AR_INCLUDE = -I../../3rdparty/mt19937ar -CHAR_OBJ = obj_txt/char.o obj_txt/inter.o obj_txt/int_party.o obj_txt/int_guild.o \ - obj_txt/int_storage.o obj_txt/int_status.o obj_txt/int_pet.o obj_txt/int_homun.o -CHAR_H = char.h inter.h int_party.h int_guild.h int_storage.h int_status.h int_pet.h int_homun.h +COMMON_SQL_OBJ = ../common/obj_sql/sql.o +COMMON_H = ../common/sql.h + +CHAR_OBJ = obj_sql/char.o obj_sql/inter.o obj_sql/int_party.o obj_sql/int_guild.o \ + obj_sql/int_storage.o obj_sql/int_pet.o obj_sql/int_homun.o obj_sql/int_mail.o obj_sql/int_auction.o obj_sql/int_quest.o obj_sql/int_mercenary.o +CHAR_H = char.h inter.h int_party.h int_guild.h int_storage.h int_pet.h int_homun.h int_mail.h int_auction.h int_quest.h int_mercenary.h + +HAVE_MYSQL=@HAVE_MYSQL@ +ifeq ($(HAVE_MYSQL),yes) + CHAR_SERVER_SQL_DEPENDS=obj_sql $(CHAR_OBJ) $(COMMON_OBJ) $(COMMON_SQL_OBJ) $(MT19937AR_OBJ) +else + CHAR_SERVER_SQL_DEPENDS=needs_mysql +endif @SET_MAKE@ ##################################################################### -.PHONY : all char-server clean help +.PHONY : all char-server_sql clean help -all: char-server +all: char-server_sql -char-server: obj_txt $(CHAR_OBJ) $(COMMON_OBJ) $(MT19937AR_OBJ) - @CC@ @LDFLAGS@ -o ../../char-server@EXEEXT@ $(CHAR_OBJ) $(COMMON_OBJ) $(MT19937AR_OBJ) @LIBS@ +char-server_sql: $(CHAR_SERVER_SQL_DEPENDS) + @CC@ @LDFLAGS@ -o ../../char-server_sql@EXEEXT@ $(CHAR_OBJ) $(COMMON_OBJ) $(COMMON_SQL_OBJ) $(MT19937AR_OBJ) @LIBS@ @MYSQL_LIBS@ clean: - rm -rf *.o obj_txt ../../char-server@EXEEXT@ + rm -rf *.o obj_sql ../../char-server_sql@EXEEXT@ help: - @echo "possible targets are 'char-server' 'all' 'clean' 'help'" - @echo "'char-server' - char server (TXT version)" - @echo "'all' - builds all above targets" - @echo "'clean' - cleans builds and objects" - @echo "'help' - outputs this message" + @echo "possible targets are 'char-server_sql' 'all' 'clean' 'help'" + @echo "'char-server_sql' - char server (SQL version)" + @echo "'all' - builds all above targets" + @echo "'clean' - cleans builds and objects" + @echo "'help' - outputs this message" ##################################################################### -obj_txt: - -mkdir obj_txt +needs_mysql: + @echo "MySQL not found or disabled by the configure script" + @exit 1 -obj_txt/%.o: %.c $(CHAR_H) $(COMMON_H) $(MT19937AR_H) - @CC@ @CFLAGS@ $(MT19937AR_INCLUDE) -DTXT_ONLY @CPPFLAGS@ -c $(OUTPUT_OPTION) $< +obj_sql: + -mkdir obj_sql + +obj_sql/%.o: %.c $(CHAR_H) $(COMMON_H) $(COMMON_SQL_H) $(MT19937AR_H) + @CC@ @CFLAGS@ $(MT19937AR_INCLUDE) @MYSQL_CFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $< # missing object files ../common/obj_all/%.o: - @$(MAKE) -C ../common txt + @$(MAKE) -C ../common sql + +../common/obj_sql/%.o: + @$(MAKE) -C ../common sql MT19937AR_OBJ: @$(MAKE) -C ../../3rdparty/mt19937ar diff --git a/src/char/char.c b/src/char/char.c index aac469c5b..cb3007ff9 100644 --- a/src/char/char.c +++ b/src/char/char.c @@ -4,7 +4,6 @@ #include "../common/cbasetypes.h" #include "../common/core.h" #include "../common/db.h" -#include "../common/lock.h" #include "../common/malloc.h" #include "../common/mapindex.h" #include "../common/mmo.h" @@ -17,10 +16,9 @@ #include "inter.h" #include "int_guild.h" #include "int_homun.h" -#include "int_pet.h" +#include "int_mercenary.h" #include "int_party.h" #include "int_storage.h" -#include "int_status.h" #include "char.h" #include @@ -34,22 +32,43 @@ // private declarations #define CHAR_CONF_NAME "conf/char_athena.conf" #define LAN_CONF_NAME "conf/subnet_athena.conf" - -char char_txt[1024] = "save/athena.txt"; -char friends_txt[1024] = "save/friends.txt"; -char hotkeys_txt[1024] = "save/hotkeys.txt"; -char char_log_filename[1024] = "log/char.log"; +#define SQL_CONF_NAME "conf/inter_athena.conf" + +char char_db[256] = "char"; +char scdata_db[256] = "sc_data"; +char cart_db[256] = "cart_inventory"; +char inventory_db[256] = "inventory"; +char charlog_db[256] = "charlog"; +char storage_db[256] = "storage"; +char interlog_db[256] = "interlog"; +char reg_db[256] = "global_reg_value"; +char skill_db[256] = "skill"; +char memo_db[256] = "memo"; +char guild_db[256] = "guild"; +char guild_alliance_db[256] = "guild_alliance"; +char guild_castle_db[256] = "guild_castle"; +char guild_expulsion_db[256] = "guild_expulsion"; +char guild_member_db[256] = "guild_member"; +char guild_position_db[256] = "guild_position"; +char guild_skill_db[256] = "guild_skill"; +char guild_storage_db[256] = "guild_storage"; +char party_db[256] = "party"; +char pet_db[256] = "pet"; +char mail_db[256] = "mail"; // MAIL SYSTEM +char auction_db[256] = "auction"; // Auctions System +char friend_db[256] = "friends"; +char hotkey_db[256] = "hotkey"; +char quest_db[256] = "quest"; // show loading/saving messages -#ifndef TXT_SQL_CONVERT int save_log = 1; -#endif -//If your code editor is having problems syntax highlighting this file, uncomment this and RECOMMENT IT BEFORE COMPILING -//#undef TXT_SQL_CONVERT -#ifndef TXT_SQL_CONVERT +static DBMap* char_db_; // int char_id -> struct mmo_charstatus* + char db_path[1024] = "db"; +int db_use_sqldbs; + struct mmo_map_server { int fd; uint32 ip; @@ -75,12 +94,10 @@ int char_maintenance = 0; bool char_new = true; int char_new_display = 0; -int email_creation = 0; // disabled by default - bool name_ignoring_case = false; // Allow or not identical name for characters but with a different case by [Yor] int char_name_option = 0; // Option to know which letters/symbols are authorised in the name of a character (0: all, 1: only those in char_name_letters, 2: all EXCEPT those in char_name_letters) by [Yor] char unknown_char_name[NAME_LENGTH] = "Unknown"; // Name to use when the requested name cannot be determined -#define TRIM_CHARS "\032\t\x0A\x0D " //The following characters are trimmed regardless because they cause confusion and problems on the servers. [Skotlex] +#define TRIM_CHARS "\255\xA0\032\t\x0A\x0D " //The following characters are trimmed regardless because they cause confusion and problems on the servers. [Skotlex] char char_name_letters[1024] = ""; // list of letters/symbols allowed (or not) in a character name. by [Yor] int char_per_account = 0; //Maximum charas per account (default unlimited) [Sirius] @@ -107,13 +124,10 @@ struct char_session_data { int gmlevel; uint32 version; uint8 clienttype; + char new_name[NAME_LENGTH]; char birthdate[10+1]; // YYYY-MM-DD }; -int char_id_count = START_CHAR_NUM; -struct character_data *char_dat; - -int char_num, char_max; int max_connect_user = 0; int gm_allow_level = 99; int autosave_interval = DEFAULT_AUTOSAVE_INTERVAL; @@ -132,17 +146,14 @@ 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]; +// check for exit signal +// 0 is saving complete +// other is char_id +unsigned int save_flag = 0; + // Initial position (it's possible to set it in conf file) struct point start_point = { 0, 53, 111 }; -// online players by [Yor] -char online_txt_filename[1024] = "online.txt"; -char online_html_filename[1024] = "online.html"; -int online_sorting_option = 0; // sorting option to display online players in online files -int online_display_option = 1; // display options: to know which columns must be displayed -int online_refresh_html = 20; // refresh time (in sec) of the html file in the explorer -int online_gm_display_min_level = 20; // minimum GM level to display 'GM' when we want to display it - int console = 0; //----------------------------------------------------- @@ -159,6 +170,7 @@ struct auth_node { int sex; time_t expiration_time; // # of seconds 1/1/1970 (timestamp): Validity limit of the account (0 = unlimited) int gmlevel; + unsigned changing_mapservers : 1; }; static DBMap* auth_db; // int account_id -> struct auth_node* @@ -177,6 +189,7 @@ struct online_char_data { static DBMap* online_char_db; // int account_id -> struct online_char_data* static int chardb_waiting_disconnect(int tid, unsigned int tick, int id, intptr_t data); +int delete_char_sql(int char_id); static void* create_online_char_data(DBKey key, va_list args) { @@ -221,7 +234,12 @@ void set_char_charselect(int account_id) void set_char_online(int map_id, int char_id, int account_id) { struct online_char_data* character; + struct mmo_charstatus *cp; + //Update DB + if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `online`='1' WHERE `char_id`='%d' LIMIT 1", char_db, char_id) ) + Sql_ShowDebug(sql_handle); + //Check to see for online conflicts character = (struct online_char_data*)idb_ensure(online_char_db, account_id, create_online_char_data); if( character->char_id != -1 && character->server > -1 && character->server != map_id ) @@ -244,6 +262,10 @@ void set_char_online(int map_id, int char_id, int account_id) character->waiting_disconnect = INVALID_TIMER; } + //Set char online in guild cache. If char is in memory, use the guild id on it, otherwise seek it. + cp = (struct mmo_charstatus*)idb_get(char_db_,char_id); + inter_guild_CharOnline(char_id, cp?cp->guild_id:-1); + //Notify login server if (login_fd > 0 && !session[login_fd]->flag.eof) { @@ -258,6 +280,22 @@ void set_char_offline(int char_id, int account_id) { struct online_char_data* character; + if ( char_id == -1 ) + { + if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `online`='0' WHERE `account_id`='%d'", char_db, account_id) ) + Sql_ShowDebug(sql_handle); + } + else + { + struct mmo_charstatus* cp = (struct mmo_charstatus*)idb_get(char_db_,char_id); + inter_guild_CharOffline(char_id, cp?cp->guild_id:-1); + if (cp) + idb_remove(char_db_,char_id); + + if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `online`='0' WHERE `char_id`='%d' LIMIT 1", char_db, char_id) ) + Sql_ShowDebug(sql_handle); + } + if ((character = (struct online_char_data*)idb_get(online_char_db, account_id)) != NULL) { //We don't free yet to avoid aCalloc/aFree spamming during char change. [Skotlex] if( character->server > -1 ) @@ -339,913 +377,904 @@ void set_all_offline(int id) WFIFOSET(login_fd,2); } -//------------------------------ -// Writing function of logs file -//------------------------------ -int char_log(char *fmt, ...) +void set_all_offline_sql(void) { - if(log_char) - { - FILE *logfp; - va_list ap; - time_t raw_time; - char tmpstr[2048]; - - va_start(ap, fmt); - - logfp = fopen(char_log_filename, "a"); - if (logfp) { - if (fmt[0] == '\0') // jump a line if no message - fprintf(logfp, "\n"); - else { - time(&raw_time); - strftime(tmpstr, 24, "%d-%m-%Y %H:%M:%S", localtime(&raw_time)); - sprintf(tmpstr + 19, ": %s", fmt); - vfprintf(logfp, tmpstr, ap); - } - fclose(logfp); - } - va_end(ap); - } - return 0; + //Set all players to 'OFFLINE' + if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `online` = '0'", char_db) ) + Sql_ShowDebug(sql_handle); + if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `online` = '0'", guild_member_db) ) + Sql_ShowDebug(sql_handle); + if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `connect_member` = '0'", guild_db) ) + Sql_ShowDebug(sql_handle); } - -/// Find all characters for given session and update the session character cache. -int char_find_characters(struct char_session_data* sd) +static void* create_charstatus(DBKey key, va_list args) { - int i, found_num = 0; + struct mmo_charstatus *cp; + cp = (struct mmo_charstatus *) aCalloc(1,sizeof(struct mmo_charstatus)); + cp->char_id = key.i; + return cp; +} - for( i = 0; i < char_num; i++ ) - {// find character entries and save them - if( char_dat[i].status.account_id == sd->account_id ) - { - sd->found_char[found_num++] = i; - if( found_num >= MAX_CHARS ) - { - break; - } - } - } +int mmo_char_tosql(int char_id, struct mmo_charstatus* p) +{ + int i = 0; + int count = 0; + int diff = 0; + char save_status[128]; //For displaying save information. [Skotlex] + struct mmo_charstatus *cp; + int errors = 0; //If there are any errors while saving, "cp" will not be updated at the end. + StringBuf buf; - for( i = found_num; i < MAX_CHARS; i++ ) - {// fill remaining blanks - sd->found_char[i] = -1; - } + if (char_id!=p->char_id) return 0; - return found_num; -} + cp = (struct mmo_charstatus*)idb_ensure(char_db_, char_id, create_charstatus); + StringBuf_Init(&buf); + memset(save_status, 0, sizeof(save_status)); -/// Search character data from given session. -struct mmo_charstatus* search_session_character(struct char_session_data* sd, int char_id) -{ - int i; + //map inventory data + if( memcmp(p->inventory, cp->inventory, sizeof(p->inventory)) ) + { + if (!memitemdata_to_sql(p->inventory, MAX_INVENTORY, p->char_id, TABLE_INVENTORY)) + strcat(save_status, " inventory"); + else + errors++; + } - ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] != -1 && char_dat[sd->found_char[i]].status.char_id == char_id ); - if( i == MAX_CHARS ) + //map cart data + if( memcmp(p->cart, cp->cart, sizeof(p->cart)) ) { - return NULL; + if (!memitemdata_to_sql(p->cart, MAX_CART, p->char_id, TABLE_CART)) + strcat(save_status, " cart"); + else + errors++; } - return &char_dat[sd->found_char[i]].status; -} + //map storage data + if( memcmp(p->storage.items, cp->storage.items, sizeof(p->storage.items)) ) + { + if (!memitemdata_to_sql(p->storage.items, MAX_STORAGE, p->account_id, TABLE_STORAGE)) + strcat(save_status, " storage"); + else + errors++; + } -//Search character data from the aid/cid givem -struct mmo_charstatus* search_character(int aid, int cid) -{ - int i; - for (i = 0; i < char_num; i++) { - if (char_dat[i].status.char_id == cid && char_dat[i].status.account_id == aid) - return &char_dat[i].status; + if ( + (p->base_exp != cp->base_exp) || (p->base_level != cp->base_level) || + (p->job_level != cp->job_level) || (p->job_exp != cp->job_exp) || + (p->zeny != cp->zeny) || + (p->last_point.map != cp->last_point.map) || + (p->last_point.x != cp->last_point.x) || (p->last_point.y != cp->last_point.y) || + (p->max_hp != cp->max_hp) || (p->hp != cp->hp) || + (p->max_sp != cp->max_sp) || (p->sp != cp->sp) || + (p->status_point != cp->status_point) || (p->skill_point != cp->skill_point) || + (p->str != cp->str) || (p->agi != cp->agi) || (p->vit != cp->vit) || + (p->int_ != cp->int_) || (p->dex != cp->dex) || (p->luk != cp->luk) || + (p->option != cp->option) || + (p->party_id != cp->party_id) || (p->guild_id != cp->guild_id) || + (p->pet_id != cp->pet_id) || (p->weapon != cp->weapon) || (p->hom_id != cp->hom_id) || + (p->shield != cp->shield) || (p->head_top != cp->head_top) || + (p->head_mid != cp->head_mid) || (p->head_bottom != cp->head_bottom) || (p->delete_date != cp->delete_date) || + (p->rename != cp->rename) || (p->robe != cp->robe) + ) + { //Save status + if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `base_level`='%d', `job_level`='%d'," + "`base_exp`='%u', `job_exp`='%u', `zeny`='%d'," + "`max_hp`='%d',`hp`='%d',`max_sp`='%d',`sp`='%d',`status_point`='%d',`skill_point`='%d'," + "`str`='%d',`agi`='%d',`vit`='%d',`int`='%d',`dex`='%d',`luk`='%d'," + "`option`='%d',`party_id`='%d',`guild_id`='%d',`pet_id`='%d',`homun_id`='%d'," + "`weapon`='%d',`shield`='%d',`head_top`='%d',`head_mid`='%d',`head_bottom`='%d'," + "`last_map`='%s',`last_x`='%d',`last_y`='%d',`save_map`='%s',`save_x`='%d',`save_y`='%d', `rename`='%d'," + "`delete_date`='%lu',`robe`='%d'" + " WHERE `account_id`='%d' AND `char_id` = '%d'", + char_db, p->base_level, p->job_level, + p->base_exp, p->job_exp, p->zeny, + p->max_hp, p->hp, p->max_sp, p->sp, p->status_point, p->skill_point, + p->str, p->agi, p->vit, p->int_, p->dex, p->luk, + p->option, p->party_id, p->guild_id, p->pet_id, p->hom_id, + p->weapon, p->shield, p->head_top, p->head_mid, p->head_bottom, + mapindex_id2name(p->last_point.map), p->last_point.x, p->last_point.y, + mapindex_id2name(p->save_point.map), p->save_point.x, p->save_point.y, p->rename, + (unsigned long)p->delete_date, // FIXME: platform-dependent size + p->robe, + p->account_id, p->char_id) ) + { + Sql_ShowDebug(sql_handle); + errors++; + } else + strcat(save_status, " status"); } - return NULL; -} - -struct mmo_charstatus* search_character_byname(char* character_name) -{ - int i = search_character_index(character_name); - if (i == -1) return NULL; - return &char_dat[i].status; -} -// Searches if the given character is online, and returns the fd of the -// map-server it is connected to. -int search_character_online(int aid, int cid) -{ - //Look for online character. - struct online_char_data* character; - character = (struct online_char_data*)idb_get(online_char_db, aid); - if(character && - character->char_id == cid && - character->server > -1) - return server[character->server].fd; - return -1; -} + //Values that will seldom change (to speed up saving) + if ( + (p->hair != cp->hair) || (p->hair_color != cp->hair_color) || (p->clothes_color != cp->clothes_color) || + (p->class_ != cp->class_) || + (p->partner_id != cp->partner_id) || (p->father != cp->father) || + (p->mother != cp->mother) || (p->child != cp->child) || + (p->karma != cp->karma) || (p->manner != cp->manner) || + (p->fame != cp->fame) + ) + { + if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `class`='%d'," + "`hair`='%d',`hair_color`='%d',`clothes_color`='%d'," + "`partner_id`='%d', `father`='%d', `mother`='%d', `child`='%d'," + "`karma`='%d',`manner`='%d', `fame`='%d'" + " WHERE `account_id`='%d' AND `char_id` = '%d'", + char_db, p->class_, + p->hair, p->hair_color, p->clothes_color, + p->partner_id, p->father, p->mother, p->child, + p->karma, p->manner, p->fame, + p->account_id, p->char_id) ) + { + Sql_ShowDebug(sql_handle); + errors++; + } else + strcat(save_status, " status2"); + } -//---------------------------------------------- -// Search an character id -// (return character index or -1 (if not found)) -// If exact character name is not found, -// the function checks without case sensitive -// and returns index if only 1 character is found -// and similar to the searched name. -//---------------------------------------------- -int search_character_index(char* character_name) -{ - int i, quantity, index; - - quantity = 0; - index = -1; - for(i = 0; i < char_num; i++) { - // Without case sensitive check (increase the number of similar character names found) - if (stricmp(char_dat[i].status.name, character_name) == 0) { - // Strict comparison (if found, we finish the function immediatly with correct value) - if (strcmp(char_dat[i].status.name, character_name) == 0) - return i; - quantity++; - index = i; - } + /* Mercenary Owner */ + if( (p->mer_id != cp->mer_id) || + (p->arch_calls != cp->arch_calls) || (p->arch_faith != cp->arch_faith) || + (p->spear_calls != cp->spear_calls) || (p->spear_faith != cp->spear_faith) || + (p->sword_calls != cp->sword_calls) || (p->sword_faith != cp->sword_faith) ) + { + if (mercenary_owner_tosql(char_id, p)) + strcat(save_status, " mercenary"); + else + errors++; } - // Here, the exact character name is not found - // We return the found index of a similar account ONLY if there is 1 similar character - if (quantity == 1) - return index; - // Exact character name is not found and 0 or more than 1 similar characters have been found ==> we say not found - return -1; -} + //memo points + if( memcmp(p->memo_point, cp->memo_point, sizeof(p->memo_point)) ) + { + char esc_mapname[NAME_LENGTH*2+1]; -/*--------------------------------------------------- - Make a data line for friends list - --------------------------------------------------*/ -int mmo_friends_list_data_str(char *str, struct mmo_charstatus *p) -{ - int i; - char *str_p = str; - str_p += sprintf(str_p, "%d", p->char_id); + //`memo` (`memo_id`,`char_id`,`map`,`x`,`y`) + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", memo_db, p->char_id) ) + { + Sql_ShowDebug(sql_handle); + errors++; + } - for (i=0;ifriends[i].account_id > 0 && p->friends[i].char_id > 0 && p->friends[i].name[0]) - str_p += sprintf(str_p, ",%d,%d,%s", p->friends[i].account_id, p->friends[i].char_id, p->friends[i].name); + //insert here. + StringBuf_Clear(&buf); + StringBuf_Printf(&buf, "INSERT INTO `%s`(`char_id`,`map`,`x`,`y`) VALUES ", memo_db); + for( i = 0, count = 0; i < MAX_MEMOPOINTS; ++i ) + { + if( p->memo_point[i].map ) + { + if( count ) + StringBuf_AppendStr(&buf, ","); + Sql_EscapeString(sql_handle, esc_mapname, mapindex_id2name(p->memo_point[i].map)); + StringBuf_Printf(&buf, "('%d', '%s', '%d', '%d')", char_id, esc_mapname, p->memo_point[i].x, p->memo_point[i].y); + ++count; + } + } + if( count ) + { + if( SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf)) ) + { + Sql_ShowDebug(sql_handle); + errors++; + } + } + strcat(save_status, " memo"); } - str_p += '\0'; + //FIXME: is this neccessary? [ultramage] + for(i=0;iskill[i].lv != 0) && (p->skill[i].id == 0)) + p->skill[i].id = i; // Fix skill tree - return 0; -} -/*--------------------------------------------------- - Make a data line for hotkeys list - --------------------------------------------------*/ -int mmo_hotkeys_tostr(char *str, struct mmo_charstatus *p) -{ -#ifdef HOTKEY_SAVING - int i; - char *str_p = str; - str_p += sprintf(str_p, "%d", p->char_id); - for (i=0;ihotkeys[i].type, p->hotkeys[i].id, p->hotkeys[i].lv); - str_p += '\0'; -#endif - - return 0; -} - -//------------------------------------------------- -// Function to create the character line (for save) -//------------------------------------------------- -int mmo_char_tostr(char *str, struct mmo_charstatus *p, struct global_reg *reg, int reg_num) -{ - int i,j; - char *str_p = str; - - str_p += sprintf(str_p, - "%d\t%d,%d\t%s\t%d,%d,%d\t%u,%u,%d" //Up to Zeny field - "\t%d,%d,%d,%d\t%d,%d,%d,%d,%d,%d\t%d,%d" //Up to Skill Point - "\t%d,%d,%d\t%d,%d,%d,%d" //Up to hom id - "\t%d,%d,%d\t%d,%d,%d,%d,%d,%d" //Up to robe - "\t%d,%d,%d\t%d,%d,%d" //last point + save point - ",%d,%d,%d,%d,%d,%lu\t", //Family info + delete date - p->char_id, p->account_id, p->slot, p->name, // - p->class_, p->base_level, p->job_level, - p->base_exp, p->job_exp, p->zeny, - p->hp, p->max_hp, p->sp, p->max_sp, - p->str, p->agi, p->vit, p->int_, p->dex, p->luk, - p->status_point, p->skill_point, - p->option, p->karma, p->manner, // - p->party_id, p->guild_id, p->pet_id, p->hom_id, - p->hair, p->hair_color, p->clothes_color, - p->weapon, p->shield, p->head_top, p->head_mid, p->head_bottom, p->robe, - p->last_point.map, p->last_point.x, p->last_point.y, // - p->save_point.map, p->save_point.x, p->save_point.y, - p->partner_id,p->father,p->mother,p->child,p->fame, // - (unsigned long)p->delete_date); // FIXME: platform-dependent size - for(i = 0; i < MAX_MEMOPOINTS; i++) - if (p->memo_point[i].map) { - str_p += sprintf(str_p, "%d,%d,%d ", p->memo_point[i].map, p->memo_point[i].x, p->memo_point[i].y); - } - *(str_p++) = '\t'; - - for(i = 0; i < MAX_INVENTORY; i++) - if (p->inventory[i].nameid) { - str_p += sprintf(str_p,"%d,%d,%d,%d,%d,%d,%d", - p->inventory[i].id,p->inventory[i].nameid,p->inventory[i].amount,p->inventory[i].equip, - p->inventory[i].identify,p->inventory[i].refine,p->inventory[i].attribute); - for(j=0; jinventory[i].card[j]); - str_p += sprintf(str_p," "); - } - *(str_p++) = '\t'; - - for(i = 0; i < MAX_CART; i++) - if (p->cart[i].nameid) { - str_p += sprintf(str_p,"%d,%d,%d,%d,%d,%d,%d", - p->cart[i].id,p->cart[i].nameid,p->cart[i].amount,p->cart[i].equip, - p->cart[i].identify,p->cart[i].refine,p->cart[i].attribute); - for(j=0; jcart[i].card[j]); - str_p += sprintf(str_p," "); + //skills + if( memcmp(p->skill, cp->skill, sizeof(p->skill)) ) + { + //`skill` (`char_id`, `id`, `lv`) + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", skill_db, p->char_id) ) + { + Sql_ShowDebug(sql_handle); + errors++; } - *(str_p++) = '\t'; - for(i = 0; i < MAX_SKILL; i++) - if (p->skill[i].id != 0 && p->skill[i].flag != SKILL_FLAG_TEMPORARY) { - str_p += sprintf(str_p, "%d,%d ", p->skill[i].id, (p->skill[i].flag == SKILL_FLAG_PERMANENT) ? p->skill[i].lv : p->skill[i].flag - SKILL_FLAG_REPLACED_LV_0); + StringBuf_Clear(&buf); + StringBuf_Printf(&buf, "INSERT INTO `%s`(`char_id`,`id`,`lv`) VALUES ", skill_db); + //insert here. + for( i = 0, count = 0; i < MAX_SKILL; ++i ) + { + if( p->skill[i].id != 0 && p->skill[i].flag != SKILL_FLAG_TEMPORARY ) + { + if( p->skill[i].flag == SKILL_FLAG_PERMANENT && p->skill[i].lv == 0 ) + continue; + if( p->skill[i].flag != SKILL_FLAG_PERMANENT && (p->skill[i].flag - SKILL_FLAG_REPLACED_LV_0) == 0 ) + continue; + if( count ) + StringBuf_AppendStr(&buf, ","); + StringBuf_Printf(&buf, "('%d','%d','%d')", char_id, p->skill[i].id, (p->skill[i].flag == SKILL_FLAG_PERMANENT ? p->skill[i].lv : p->skill[i].flag - SKILL_FLAG_REPLACED_LV_0)); + ++count; + } + } + if( count ) + { + if( SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf)) ) + { + Sql_ShowDebug(sql_handle); + errors++; + } } - *(str_p++) = '\t'; - - for(i = 0; i < reg_num; i++) - if (reg[i].str[0]) - str_p += sprintf(str_p, "%s,%s ", reg[i].str, reg[i].value); - *(str_p++) = '\t'; - *str_p = '\0'; - return 0; -} -#endif //TXT_SQL_CONVERT -//------------------------------------------------------------------------- -// Function to set the character from the line (at read of characters file) -//------------------------------------------------------------------------- -int mmo_char_fromstr(char *str, struct mmo_charstatus *p, struct global_reg *reg, int *reg_num) -{ - char tmp_str[3][128]; //To avoid deleting chars with too long names. - int tmp_int[256]; - unsigned int tmp_uint[2]; //To read exp.... - int next, len, i, j; - unsigned long tmp_ulong[1]; - - // initilialise character - memset(p, '\0', sizeof(struct mmo_charstatus)); - -// Char structure of version 14797 (robe) - if (sscanf(str, "%d\t%d,%d\t%127[^\t]\t%d,%d,%d\t%u,%u,%d\t%d,%d,%d,%d\t%d,%d,%d,%d,%d,%d\t%d,%d" - "\t%d,%d,%d\t%d,%d,%d,%d\t%d,%d,%d\t%d,%d,%d,%d,%d,%d" - "\t%d,%d,%d\t%d,%d,%d,%d,%d,%d,%d,%d,%lu%n", - &tmp_int[0], &tmp_int[1], &tmp_int[2], tmp_str[0], - &tmp_int[3], &tmp_int[4], &tmp_int[5], - &tmp_uint[0], &tmp_uint[1], &tmp_int[8], - &tmp_int[9], &tmp_int[10], &tmp_int[11], &tmp_int[12], - &tmp_int[13], &tmp_int[14], &tmp_int[15], &tmp_int[16], &tmp_int[17], &tmp_int[18], - &tmp_int[19], &tmp_int[20], - &tmp_int[21], &tmp_int[22], &tmp_int[23], // - &tmp_int[24], &tmp_int[25], &tmp_int[26], &tmp_int[44], - &tmp_int[27], &tmp_int[28], &tmp_int[29], - &tmp_int[30], &tmp_int[31], &tmp_int[32], &tmp_int[33], &tmp_int[34], &tmp_int[47], - &tmp_int[45], &tmp_int[35], &tmp_int[36], - &tmp_int[46], &tmp_int[37], &tmp_int[38], &tmp_int[39], - &tmp_int[40], &tmp_int[41], &tmp_int[42], &tmp_int[43], &tmp_ulong[0], &next) != 50) - { - tmp_int[47] = 0; // robe -// Char structure of version 14700 (delete date) - if (sscanf(str, "%d\t%d,%d\t%127[^\t]\t%d,%d,%d\t%u,%u,%d\t%d,%d,%d,%d\t%d,%d,%d,%d,%d,%d\t%d,%d" - "\t%d,%d,%d\t%d,%d,%d,%d\t%d,%d,%d\t%d,%d,%d,%d,%d" - "\t%d,%d,%d\t%d,%d,%d,%d,%d,%d,%d,%d,%lu%n", - &tmp_int[0], &tmp_int[1], &tmp_int[2], tmp_str[0], - &tmp_int[3], &tmp_int[4], &tmp_int[5], - &tmp_uint[0], &tmp_uint[1], &tmp_int[8], - &tmp_int[9], &tmp_int[10], &tmp_int[11], &tmp_int[12], - &tmp_int[13], &tmp_int[14], &tmp_int[15], &tmp_int[16], &tmp_int[17], &tmp_int[18], - &tmp_int[19], &tmp_int[20], - &tmp_int[21], &tmp_int[22], &tmp_int[23], // - &tmp_int[24], &tmp_int[25], &tmp_int[26], &tmp_int[44], - &tmp_int[27], &tmp_int[28], &tmp_int[29], - &tmp_int[30], &tmp_int[31], &tmp_int[32], &tmp_int[33], &tmp_int[34], - &tmp_int[45], &tmp_int[35], &tmp_int[36], - &tmp_int[46], &tmp_int[37], &tmp_int[38], &tmp_int[39], - &tmp_int[40], &tmp_int[41], &tmp_int[42], &tmp_int[43], &tmp_ulong[0], &next) != 49) - { - tmp_ulong[0] = 0; // delete date -// Char structure of version 1500 (homun + mapindex maps) - if (sscanf(str, "%d\t%d,%d\t%127[^\t]\t%d,%d,%d\t%u,%u,%d\t%d,%d,%d,%d\t%d,%d,%d,%d,%d,%d\t%d,%d" - "\t%d,%d,%d\t%d,%d,%d,%d\t%d,%d,%d\t%d,%d,%d,%d,%d" - "\t%d,%d,%d\t%d,%d,%d,%d,%d,%d,%d,%d%n", - &tmp_int[0], &tmp_int[1], &tmp_int[2], tmp_str[0], - &tmp_int[3], &tmp_int[4], &tmp_int[5], - &tmp_uint[0], &tmp_uint[1], &tmp_int[8], - &tmp_int[9], &tmp_int[10], &tmp_int[11], &tmp_int[12], - &tmp_int[13], &tmp_int[14], &tmp_int[15], &tmp_int[16], &tmp_int[17], &tmp_int[18], - &tmp_int[19], &tmp_int[20], - &tmp_int[21], &tmp_int[22], &tmp_int[23], // - &tmp_int[24], &tmp_int[25], &tmp_int[26], &tmp_int[44], - &tmp_int[27], &tmp_int[28], &tmp_int[29], - &tmp_int[30], &tmp_int[31], &tmp_int[32], &tmp_int[33], &tmp_int[34], - &tmp_int[45], &tmp_int[35], &tmp_int[36], - &tmp_int[46], &tmp_int[37], &tmp_int[38], &tmp_int[39], - &tmp_int[40], &tmp_int[41], &tmp_int[42], &tmp_int[43], &next) != 48) - { - tmp_int[44] = 0; //Hom ID. -// Char structure of version 1488 (fame field addition) - if (sscanf(str, "%d\t%d,%d\t%127[^\t]\t%d,%d,%d\t%u,%u,%d\t%d,%d,%d,%d\t%d,%d,%d,%d,%d,%d\t%d,%d" - "\t%d,%d,%d\t%d,%d,%d\t%d,%d,%d\t%d,%d,%d,%d,%d" - "\t%127[^,],%d,%d\t%127[^,],%d,%d,%d,%d,%d,%d,%d%n", - &tmp_int[0], &tmp_int[1], &tmp_int[2], tmp_str[0], - &tmp_int[3], &tmp_int[4], &tmp_int[5], - &tmp_uint[0], &tmp_uint[1], &tmp_int[8], - &tmp_int[9], &tmp_int[10], &tmp_int[11], &tmp_int[12], - &tmp_int[13], &tmp_int[14], &tmp_int[15], &tmp_int[16], &tmp_int[17], &tmp_int[18], - &tmp_int[19], &tmp_int[20], - &tmp_int[21], &tmp_int[22], &tmp_int[23], // - &tmp_int[24], &tmp_int[25], &tmp_int[26], - &tmp_int[27], &tmp_int[28], &tmp_int[29], - &tmp_int[30], &tmp_int[31], &tmp_int[32], &tmp_int[33], &tmp_int[34], - tmp_str[1], &tmp_int[35], &tmp_int[36], - tmp_str[2], &tmp_int[37], &tmp_int[38], &tmp_int[39], - &tmp_int[40], &tmp_int[41], &tmp_int[42], &tmp_int[43], &next) != 47) - { - tmp_int[43] = 0; //Fame -// Char structure of version 1363 (family data addition) - if (sscanf(str, "%d\t%d,%d\t%127[^\t]\t%d,%d,%d\t%u,%u,%d\t%d,%d,%d,%d\t%d,%d,%d,%d,%d,%d\t%d,%d" - "\t%d,%d,%d\t%d,%d,%d\t%d,%d,%d\t%d,%d,%d,%d,%d" - "\t%127[^,],%d,%d\t%127[^,],%d,%d,%d,%d,%d,%d%n", - &tmp_int[0], &tmp_int[1], &tmp_int[2], tmp_str[0], // - &tmp_int[3], &tmp_int[4], &tmp_int[5], - &tmp_uint[0], &tmp_uint[1], &tmp_int[8], - &tmp_int[9], &tmp_int[10], &tmp_int[11], &tmp_int[12], - &tmp_int[13], &tmp_int[14], &tmp_int[15], &tmp_int[16], &tmp_int[17], &tmp_int[18], - &tmp_int[19], &tmp_int[20], - &tmp_int[21], &tmp_int[22], &tmp_int[23], // - &tmp_int[24], &tmp_int[25], &tmp_int[26], - &tmp_int[27], &tmp_int[28], &tmp_int[29], - &tmp_int[30], &tmp_int[31], &tmp_int[32], &tmp_int[33], &tmp_int[34], - tmp_str[1], &tmp_int[35], &tmp_int[36], // - tmp_str[2], &tmp_int[37], &tmp_int[38], &tmp_int[39], - &tmp_int[40], &tmp_int[41], &tmp_int[42], &next) != 46) - { - tmp_int[40] = 0; // father - tmp_int[41] = 0; // mother - tmp_int[42] = 0; // child -// Char structure version 1008 (marriage partner addition) - if (sscanf(str, "%d\t%d,%d\t%127[^\t]\t%d,%d,%d\t%u,%u,%d\t%d,%d,%d,%d\t%d,%d,%d,%d,%d,%d\t%d,%d" - "\t%d,%d,%d\t%d,%d,%d\t%d,%d,%d\t%d,%d,%d,%d,%d" - "\t%127[^,],%d,%d\t%127[^,],%d,%d,%d%n", - &tmp_int[0], &tmp_int[1], &tmp_int[2], tmp_str[0], // - &tmp_int[3], &tmp_int[4], &tmp_int[5], - &tmp_uint[0], &tmp_uint[1], &tmp_int[8], - &tmp_int[9], &tmp_int[10], &tmp_int[11], &tmp_int[12], - &tmp_int[13], &tmp_int[14], &tmp_int[15], &tmp_int[16], &tmp_int[17], &tmp_int[18], - &tmp_int[19], &tmp_int[20], - &tmp_int[21], &tmp_int[22], &tmp_int[23], // - &tmp_int[24], &tmp_int[25], &tmp_int[26], - &tmp_int[27], &tmp_int[28], &tmp_int[29], - &tmp_int[30], &tmp_int[31], &tmp_int[32], &tmp_int[33], &tmp_int[34], - tmp_str[1], &tmp_int[35], &tmp_int[36], // - tmp_str[2], &tmp_int[37], &tmp_int[38], &tmp_int[39], &next) != 43) - { - tmp_int[39] = 0; // partner id -// Char structure version 384 (pet addition) - if (sscanf(str, "%d\t%d,%d\t%127[^\t]\t%d,%d,%d\t%u,%u,%d\t%d,%d,%d,%d\t%d,%d,%d,%d,%d,%d\t%d,%d" - "\t%d,%d,%d\t%d,%d,%d\t%d,%d,%d\t%d,%d,%d,%d,%d" - "\t%127[^,],%d,%d\t%127[^,],%d,%d%n", - &tmp_int[0], &tmp_int[1], &tmp_int[2], tmp_str[0], // - &tmp_int[3], &tmp_int[4], &tmp_int[5], - &tmp_uint[0], &tmp_uint[1], &tmp_int[8], - &tmp_int[9], &tmp_int[10], &tmp_int[11], &tmp_int[12], - &tmp_int[13], &tmp_int[14], &tmp_int[15], &tmp_int[16], &tmp_int[17], &tmp_int[18], - &tmp_int[19], &tmp_int[20], - &tmp_int[21], &tmp_int[22], &tmp_int[23], // - &tmp_int[24], &tmp_int[25], &tmp_int[26], - &tmp_int[27], &tmp_int[28], &tmp_int[29], - &tmp_int[30], &tmp_int[31], &tmp_int[32], &tmp_int[33], &tmp_int[34], - tmp_str[1], &tmp_int[35], &tmp_int[36], // - tmp_str[2], &tmp_int[37], &tmp_int[38], &next) != 42) - { - tmp_int[26] = 0; // pet id -// Char structure of a version 1 (original data structure) - if (sscanf(str, "%d\t%d,%d\t%127[^\t]\t%d,%d,%d\t%u,%u,%d\t%d,%d,%d,%d\t%d,%d,%d,%d,%d,%d\t%d,%d" - "\t%d,%d,%d\t%d,%d\t%d,%d,%d\t%d,%d,%d,%d,%d" - "\t%127[^,],%d,%d\t%127[^,],%d,%d%n", - &tmp_int[0], &tmp_int[1], &tmp_int[2], tmp_str[0], // - &tmp_int[3], &tmp_int[4], &tmp_int[5], - &tmp_uint[0], &tmp_uint[1], &tmp_int[8], - &tmp_int[9], &tmp_int[10], &tmp_int[11], &tmp_int[12], - &tmp_int[13], &tmp_int[14], &tmp_int[15], &tmp_int[16], &tmp_int[17], &tmp_int[18], - &tmp_int[19], &tmp_int[20], - &tmp_int[21], &tmp_int[22], &tmp_int[23], // - &tmp_int[24], &tmp_int[25], // - &tmp_int[27], &tmp_int[28], &tmp_int[29], - &tmp_int[30], &tmp_int[31], &tmp_int[32], &tmp_int[33], &tmp_int[34], - tmp_str[1], &tmp_int[35], &tmp_int[36], // - tmp_str[2], &tmp_int[37], &tmp_int[38], &next) != 41) - { - ShowError("Char-loading: Unrecognized character data version, info lost!\n"); - ShowDebug("Character info: %s\n", str); - return 0; + strcat(save_status, " skills"); } - } // Char structure version 384 (pet addition) - } // Char structure version 1008 (marriage partner addition) - } // Char structure of version 1363 (family data addition) - } // Char structure of version 1488 (fame field addition) - //Convert save data from string to integer for older formats - tmp_int[45] = mapindex_name2id(tmp_str[1]); - tmp_int[46] = mapindex_name2id(tmp_str[2]); - } // Char structure of version 1500 (homun + mapindex maps) - } // Char structure of version 14700 (delete date) - } // Char structure of version 14797 (robe) - - safestrncpy(p->name, tmp_str[0], NAME_LENGTH); //Overflow protection [Skotlex] - p->char_id = tmp_int[0]; - p->account_id = tmp_int[1]; - p->slot = tmp_int[2]; - p->class_ = tmp_int[3]; - p->base_level = tmp_int[4]; - p->job_level = tmp_int[5]; - p->base_exp = tmp_uint[0]; - p->job_exp = tmp_uint[1]; - p->zeny = tmp_int[8]; - p->hp = tmp_int[9]; - p->max_hp = tmp_int[10]; - p->sp = tmp_int[11]; - p->max_sp = tmp_int[12]; - p->str = tmp_int[13]; - p->agi = tmp_int[14]; - p->vit = tmp_int[15]; - p->int_ = tmp_int[16]; - p->dex = tmp_int[17]; - p->luk = tmp_int[18]; - p->status_point = tmp_int[19]; - p->skill_point = tmp_int[20]; - p->option = tmp_int[21]; - p->karma = tmp_int[22]; - p->manner = tmp_int[23]; - p->party_id = tmp_int[24]; - p->guild_id = tmp_int[25]; - p->pet_id = tmp_int[26]; - p->hair = tmp_int[27]; - p->hair_color = tmp_int[28]; - p->clothes_color = tmp_int[29]; - p->weapon = tmp_int[30]; - p->shield = tmp_int[31]; - p->head_top = tmp_int[32]; - p->head_mid = tmp_int[33]; - p->head_bottom = tmp_int[34]; - p->last_point.x = tmp_int[35]; - p->last_point.y = tmp_int[36]; - p->save_point.x = tmp_int[37]; - p->save_point.y = tmp_int[38]; - p->partner_id = tmp_int[39]; - p->father = tmp_int[40]; - p->mother = tmp_int[41]; - p->child = tmp_int[42]; - p->fame = tmp_int[43]; - p->hom_id = tmp_int[44]; - p->last_point.map = tmp_int[45]; - p->save_point.map = tmp_int[46]; - p->delete_date = tmp_ulong[0]; - p->robe = tmp_int[47]; - -#ifndef TXT_SQL_CONVERT - // Some checks - for(i = 0; i < char_num; i++) { - if (char_dat[i].status.char_id == p->char_id) { - ShowError(CL_RED"mmmo_auth_init: a character has an identical id to another.\n"); - ShowError(" character id #%d -> new character not readed.\n", p->char_id); - ShowError(" Character saved in log file."CL_RESET"\n"); - return -1; - } else if (strcmp(char_dat[i].status.name, p->name) == 0) { - ShowError(CL_RED"mmmo_auth_init: a character name already exists.\n"); - ShowError(" character name '%s' -> new character not read.\n", p->name); - ShowError(" Character saved in log file."CL_RESET"\n"); - return -2; + + diff = 0; + for(i = 0; i < MAX_FRIENDS; i++){ + if(p->friends[i].char_id != cp->friends[i].char_id || + p->friends[i].account_id != cp->friends[i].account_id){ + diff = 1; + break; } } - if (strcmpi(wisp_server_name, p->name) == 0) { - ShowWarning("mmo_auth_init: ******WARNING: character name has wisp server name.\n"); - ShowWarning(" Character name '%s' = wisp server name '%s'.\n", p->name, wisp_server_name); - ShowWarning(" Character readed. Suggestion: change the wisp server name.\n"); - char_log("mmo_auth_init: ******WARNING: character name has wisp server name: Character name '%s' = wisp server name '%s'.\n", - p->name, wisp_server_name); - } -#endif //TXT_SQL_CONVERT - if (str[next] == '\n' || str[next] == '\r') - return 1; // 新規データ - - next++; - - for(i = 0; str[next] && str[next] != '\t'; i++) { - //mapindex memo format - if (sscanf(str+next, "%d,%d,%d%n", &tmp_int[2], &tmp_int[0], &tmp_int[1], &len) != 3) - { //Old string-based memo format. - if (sscanf(str+next, "%[^,],%d,%d%n", tmp_str[0], &tmp_int[0], &tmp_int[1], &len) != 3) - return -3; - tmp_int[2] = mapindex_name2id(tmp_str[0]); + if(diff == 1) + { //Save friends + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", friend_db, char_id) ) + { + Sql_ShowDebug(sql_handle); + errors++; } - if (i < MAX_MEMOPOINTS) - { //Avoid overflowing (but we must also read through all saved memos) - p->memo_point[i].x = tmp_int[0]; - p->memo_point[i].y = tmp_int[1]; - p->memo_point[i].map = tmp_int[2]; + + StringBuf_Clear(&buf); + StringBuf_Printf(&buf, "INSERT INTO `%s` (`char_id`, `friend_account`, `friend_id`) VALUES ", friend_db); + for( i = 0, count = 0; i < MAX_FRIENDS; ++i ) + { + if( p->friends[i].char_id > 0 ) + { + if( count ) + StringBuf_AppendStr(&buf, ","); + StringBuf_Printf(&buf, "('%d','%d','%d')", char_id, p->friends[i].account_id, p->friends[i].char_id); + count++; + } } - next += len; - if (str[next] == ' ') - next++; + if( count ) + { + if( SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf)) ) + { + Sql_ShowDebug(sql_handle); + errors++; + } + } + strcat(save_status, " friends"); } - next++; - - for(i = 0; str[next] && str[next] != '\t'; i++) { - if(sscanf(str + next, "%d,%d,%d,%d,%d,%d,%d%[0-9,-]%n", - &tmp_int[0], &tmp_int[1], &tmp_int[2], &tmp_int[3], - &tmp_int[4], &tmp_int[5], &tmp_int[6], tmp_str[0], &len) == 8) +#ifdef HOTKEY_SAVING + // hotkeys + StringBuf_Clear(&buf); + StringBuf_Printf(&buf, "REPLACE INTO `%s` (`char_id`, `hotkey`, `type`, `itemskill_id`, `skill_lvl`) VALUES ", hotkey_db); + diff = 0; + for(i = 0; i < ARRAYLENGTH(p->hotkeys); i++){ + if(memcmp(&p->hotkeys[i], &cp->hotkeys[i], sizeof(struct hotkey))) { - p->inventory[i].id = tmp_int[0]; - p->inventory[i].nameid = tmp_int[1]; - p->inventory[i].amount = tmp_int[2]; - p->inventory[i].equip = tmp_int[3]; - p->inventory[i].identify = tmp_int[4]; - p->inventory[i].refine = tmp_int[5]; - p->inventory[i].attribute = tmp_int[6]; - - for(j = 0; j < MAX_SLOTS && tmp_str[0][0] && sscanf(tmp_str[0], ",%d%[0-9,-]",&tmp_int[0], tmp_str[0]) > 0; j++) - p->inventory[i].card[j] = tmp_int[0]; - - next += len; - if (str[next] == ' ') - next++; - } else // invalid structure - return -4; + if( diff ) + StringBuf_AppendStr(&buf, ",");// not the first hotkey + StringBuf_Printf(&buf, "('%d','%u','%u','%u','%u')", char_id, (unsigned int)i, (unsigned int)p->hotkeys[i].type, p->hotkeys[i].id , (unsigned int)p->hotkeys[i].lv); + diff = 1; + } } - next++; - - for(i = 0; str[next] && str[next] != '\t'; i++) { - if(sscanf(str + next, "%d,%d,%d,%d,%d,%d,%d%[0-9,-]%n", - &tmp_int[0], &tmp_int[1], &tmp_int[2], &tmp_int[3], - &tmp_int[4], &tmp_int[5], &tmp_int[6], tmp_str[0], &len) == 8) + if(diff) { + if( SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf)) ) { - p->cart[i].id = tmp_int[0]; - p->cart[i].nameid = tmp_int[1]; - p->cart[i].amount = tmp_int[2]; - p->cart[i].equip = tmp_int[3]; - p->cart[i].identify = tmp_int[4]; - p->cart[i].refine = tmp_int[5]; - p->cart[i].attribute = tmp_int[6]; - - for(j = 0; j < MAX_SLOTS && tmp_str[0][0] && sscanf(tmp_str[0], ",%d%[0-9,-]",&tmp_int[0], tmp_str[0]) > 0; j++) - p->cart[i].card[j] = tmp_int[0]; - - next += len; - if (str[next] == ' ') - next++; - } else // invalid structure - return -5; + Sql_ShowDebug(sql_handle); + errors++; + } else + strcat(save_status, " hotkeys"); } +#endif + StringBuf_Destroy(&buf); + if (save_status[0]!='\0' && save_log) + ShowInfo("Saved char %d - %s:%s.\n", char_id, p->name, save_status); + if (!errors) + memcpy(cp, p, sizeof(struct mmo_charstatus)); + return 0; +} - next++; +/// Saves an array of 'item' entries into the specified table. +int memitemdata_to_sql(const struct item items[], int max, int id, int tableswitch) +{ + StringBuf buf; + SqlStmt* stmt; + int i; + int j; + const char* tablename; + const char* selectoption; + struct item item; // temp storage variable + bool* flag; // bit array for inventory matching + bool found; + int errors = 0; + + switch (tableswitch) { + case TABLE_INVENTORY: tablename = inventory_db; selectoption = "char_id"; break; + case TABLE_CART: tablename = cart_db; selectoption = "char_id"; break; + case TABLE_STORAGE: tablename = storage_db; selectoption = "account_id"; break; + case TABLE_GUILD_STORAGE: tablename = guild_storage_db; selectoption = "guild_id"; break; + default: + ShowError("Invalid table name!\n"); + return 1; + } + + + // The following code compares inventory with current database values + // and performs modification/deletion/insertion only on relevant rows. + // This approach is more complicated than a trivial delete&insert, but + // it significantly reduces cpu load on the database server. + + StringBuf_Init(&buf); + StringBuf_AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`"); + for( j = 0; j < MAX_SLOTS; ++j ) + StringBuf_Printf(&buf, ", `card%d`", j); + StringBuf_Printf(&buf, " FROM `%s` WHERE `%s`='%d'", tablename, selectoption, id); - for(i = 0; str[next] && str[next] != '\t'; i++) { - if (sscanf(str + next, "%d,%d%n", &tmp_int[0], &tmp_int[1], &len) != 2) - return -6; - p->skill[tmp_int[0]].id = tmp_int[0]; - p->skill[tmp_int[0]].lv = tmp_int[1]; - next += len; - if (str[next] == ' ') - next++; + stmt = SqlStmt_Malloc(sql_handle); + if( SQL_ERROR == SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf)) + || SQL_ERROR == SqlStmt_Execute(stmt) ) + { + SqlStmt_ShowDebug(stmt); + SqlStmt_Free(stmt); + StringBuf_Destroy(&buf); + return 1; } - next++; + SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &item.id, 0, NULL, NULL); + SqlStmt_BindColumn(stmt, 1, SQLDT_SHORT, &item.nameid, 0, NULL, NULL); + SqlStmt_BindColumn(stmt, 2, SQLDT_SHORT, &item.amount, 0, NULL, NULL); + SqlStmt_BindColumn(stmt, 3, SQLDT_USHORT, &item.equip, 0, NULL, NULL); + SqlStmt_BindColumn(stmt, 4, SQLDT_CHAR, &item.identify, 0, NULL, NULL); + SqlStmt_BindColumn(stmt, 5, SQLDT_CHAR, &item.refine, 0, NULL, NULL); + SqlStmt_BindColumn(stmt, 6, SQLDT_CHAR, &item.attribute, 0, NULL, NULL); + SqlStmt_BindColumn(stmt, 7, SQLDT_UINT, &item.expire_time, 0, NULL, NULL); + for( j = 0; j < MAX_SLOTS; ++j ) + SqlStmt_BindColumn(stmt, 8+j, SQLDT_SHORT, &item.card[j], 0, NULL, NULL); + + // bit array indicating which inventory items have already been matched + flag = (bool*) aCallocA(max, sizeof(bool)); + + while( SQL_SUCCESS == SqlStmt_NextRow(stmt) ) + { + found = false; + // search for the presence of the item in the char's inventory + for( i = 0; i < max; ++i ) + { + // skip empty and already matched entries + if( items[i].nameid == 0 || flag[i] ) + continue; - for(i = 0; str[next] && str[next] != '\t' && str[next] != '\n' && str[next] != '\r'; i++) { // global_reg実装以前のathena.txt互換のため一応'\n'チェック - if (sscanf(str + next, "%[^,],%[^ ] %n", reg[i].str, reg[i].value, &len) != 2) { - // because some scripts are not correct, the str can be "". So, we must check that. - // If it's, we must not refuse the character, but just this REG value. - // Character line will have something like: nov_2nd_cos,9 ,9 nov_1_2_cos_c,1 (here, ,9 is not good) - if (str[next] == ',' && sscanf(str + next, ",%[^ ] %n", reg[i].value, &len) == 1) - i--; - else - return -7; + if( items[i].nameid == item.nameid + && items[i].card[0] == item.card[0] + && items[i].card[2] == item.card[2] + && items[i].card[3] == item.card[3] + ) { //They are the same item. + ARR_FIND( 0, MAX_SLOTS, j, items[i].card[j] != item.card[j] ); + if( j == MAX_SLOTS && + items[i].amount == item.amount && + items[i].equip == item.equip && + items[i].identify == item.identify && + items[i].refine == item.refine && + items[i].attribute == item.attribute && + items[i].expire_time == item.expire_time ) + ; //Do nothing. + else + { + // update all fields. + StringBuf_Clear(&buf); + StringBuf_Printf(&buf, "UPDATE `%s` SET `amount`='%d', `equip`='%d', `identify`='%d', `refine`='%d',`attribute`='%d', `expire_time`='%u'", + tablename, items[i].amount, items[i].equip, items[i].identify, items[i].refine, items[i].attribute, items[i].expire_time); + for( j = 0; j < MAX_SLOTS; ++j ) + StringBuf_Printf(&buf, ", `card%d`=%d", j, items[i].card[j]); + StringBuf_Printf(&buf, " WHERE `id`='%d' LIMIT 1", item.id); + + if( SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf)) ) + { + Sql_ShowDebug(sql_handle); + errors++; + } + } + + found = flag[i] = true; //Item dealt with, + break; //skip to next item in the db. + } + } + if( !found ) + {// Item not present in inventory, remove it. + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE from `%s` where `id`='%d' LIMIT 1", tablename, item.id) ) + { + Sql_ShowDebug(sql_handle); + errors++; + } } - next += len; - if (str[next] == ' ') - next++; } - *reg_num = i; + SqlStmt_Free(stmt); - return 1; -} + StringBuf_Clear(&buf); + StringBuf_Printf(&buf, "INSERT INTO `%s`(`%s`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`", tablename, selectoption); + for( j = 0; j < MAX_SLOTS; ++j ) + StringBuf_Printf(&buf, ", `card%d`", j); + StringBuf_AppendStr(&buf, ") VALUES "); -//--------------------------------- -// Function to read friend list -//--------------------------------- -int parse_friend_txt(struct mmo_charstatus *p) -{ - char line[1024], temp[1024]; - int pos = 0, count = 0, next; - int i,len; - FILE *fp; + found = false; + // insert non-matched items into the db as new items + for( i = 0; i < max; ++i ) + { + // skip empty and already matched entries + if( items[i].nameid == 0 || flag[i] ) + continue; - // Open the file and look for the ID - fp = fopen(friends_txt, "r"); + if( found ) + StringBuf_AppendStr(&buf, ","); + else + found = true; - if(fp == NULL) - return -1; - - while(fgets(line, sizeof(line), fp)) + StringBuf_Printf(&buf, "('%d', '%d', '%d', '%d', '%d', '%d', '%d', '%u'", + id, items[i].nameid, items[i].amount, items[i].equip, items[i].identify, items[i].refine, items[i].attribute, items[i].expire_time); + for( j = 0; j < MAX_SLOTS; ++j ) + StringBuf_Printf(&buf, ", '%d'", items[i].card[j]); + StringBuf_AppendStr(&buf, ")"); + } + + if( found && SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf)) ) { - if(line[0] == '/' && line[1] == '/') - continue; - if (sscanf(line, "%d%n",&i, &pos) < 1 || i != p->char_id) - continue; //Not this line... - //Read friends - len = strlen(line); - next = pos; - for (count = 0; next < len && count < MAX_FRIENDS; count++) - { //Read friends. - if (sscanf(line+next, ",%d,%d,%23[^,^\n]%n",&p->friends[count].account_id,&p->friends[count].char_id, p->friends[count].name, &pos) < 3) - { //Invalid friend? - memset(&p->friends[count], 0, sizeof(p->friends[count])); - break; - } - next+=pos; - //What IF the name contains a comma? while the next field is not a - //number, we assume it belongs to the current name. [Skotlex] - //NOTE: Of course, this will fail if someone sets their name to something like - //Bob,2005 but... meh, it's the problem of parsing a text file (encasing it in " - //won't do as quotes are also valid name chars!) - while(next < len && sscanf(line+next, ",%23[^,^\n]%n", temp, &pos) > 0) - { - if (atoi(temp)) //We read the next friend, just continue. - break; - //Append the name. - next+=pos; - i = strlen(p->friends[count].name); - if (i + strlen(temp) +1 < NAME_LENGTH) - { - p->friends[count].name[i] = ','; - strcpy(p->friends[count].name+i+1, temp); - } - } //End Guess Block - } //Friend's for. - break; //Found friends. + Sql_ShowDebug(sql_handle); + errors++; } - fclose(fp); - return count; + + StringBuf_Destroy(&buf); + aFree(flag); + + return errors; } -//--------------------------------- -// Function to read hotkey list -//--------------------------------- -int parse_hotkey_txt(struct mmo_charstatus *p) +int mmo_char_tobuf(uint8* buf, struct mmo_charstatus* p); + +//===================================================================================================== +// Loads the basic character rooster for the given account. Returns total buffer used. +int mmo_chars_fromsql(struct char_session_data* sd, uint8* buf) { -#ifdef HOTKEY_SAVING - char line[1024]; - int pos = 0, count = 0, next; - int i,len; - int type, id, lv; - FILE *fp; + SqlStmt* stmt; + struct mmo_charstatus p; + int j = 0, i; + char last_map[MAP_NAME_LENGTH_EXT]; - // Open the file and look for the ID - fp = fopen(hotkeys_txt, "r"); - if(fp == NULL) - return -1; - - while(fgets(line, sizeof(line), fp)) + stmt = SqlStmt_Malloc(sql_handle); + if( stmt == NULL ) { - if(line[0] == '/' && line[1] == '/') + SqlStmt_ShowDebug(stmt); + return 0; + } + memset(&p, 0, sizeof(p)); + + // read char data + if( SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT " + "`char_id`,`char_num`,`name`,`class`,`base_level`,`job_level`,`base_exp`,`job_exp`,`zeny`," + "`str`,`agi`,`vit`,`int`,`dex`,`luk`,`max_hp`,`hp`,`max_sp`,`sp`," + "`status_point`,`skill_point`,`option`,`karma`,`manner`,`hair`,`hair_color`," + "`clothes_color`,`weapon`,`shield`,`head_top`,`head_mid`,`head_bottom`,`last_map`,`rename`,`delete_date`," + "`robe`" + " FROM `%s` WHERE `account_id`='%d' AND `char_num` < '%d'", char_db, sd->account_id, MAX_CHARS) + || SQL_ERROR == SqlStmt_Execute(stmt) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &p.char_id, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_UCHAR, &p.slot, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_STRING, &p.name, sizeof(p.name), NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 3, SQLDT_SHORT, &p.class_, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 4, SQLDT_UINT, &p.base_level, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 5, SQLDT_UINT, &p.job_level, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 6, SQLDT_UINT, &p.base_exp, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 7, SQLDT_UINT, &p.job_exp, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 8, SQLDT_INT, &p.zeny, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 9, SQLDT_SHORT, &p.str, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 10, SQLDT_SHORT, &p.agi, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 11, SQLDT_SHORT, &p.vit, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 12, SQLDT_SHORT, &p.int_, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 13, SQLDT_SHORT, &p.dex, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 14, SQLDT_SHORT, &p.luk, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 15, SQLDT_INT, &p.max_hp, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 16, SQLDT_INT, &p.hp, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 17, SQLDT_INT, &p.max_sp, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 18, SQLDT_INT, &p.sp, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 19, SQLDT_UINT, &p.status_point, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 20, SQLDT_UINT, &p.skill_point, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 21, SQLDT_UINT, &p.option, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 22, SQLDT_UCHAR, &p.karma, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 23, SQLDT_SHORT, &p.manner, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 24, SQLDT_SHORT, &p.hair, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 25, SQLDT_SHORT, &p.hair_color, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 26, SQLDT_SHORT, &p.clothes_color, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 27, SQLDT_SHORT, &p.weapon, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 28, SQLDT_SHORT, &p.shield, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 29, SQLDT_SHORT, &p.head_top, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 30, SQLDT_SHORT, &p.head_mid, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 31, SQLDT_SHORT, &p.head_bottom, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 32, SQLDT_STRING, &last_map, sizeof(last_map), NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 33, SQLDT_SHORT, &p.rename, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 34, SQLDT_UINT32, &p.delete_date, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 35, SQLDT_SHORT, &p.robe, 0, NULL, NULL) + ) + { + SqlStmt_ShowDebug(stmt); + SqlStmt_Free(stmt); + return 0; + } + for( i = 0; i < MAX_CHARS && SQL_SUCCESS == SqlStmt_NextRow(stmt); i++ ) + { + if( p.delete_date && p.delete_date < time(NULL) ) { + delete_char_sql(p.char_id); + i--; continue; - if (sscanf(line, "%d%n",&i, &pos) < 1 || i != p->char_id) - continue; //Not this line... - //Read hotkeys - len = strlen(line); - next = pos; - for (count = 0; next < len && count < MAX_HOTKEYS; count++) - { - if (sscanf(line+next, ",%d,%d,%d%n",&type,&id,&lv, &pos) < 3) - //Invalid entry? - break; - p->hotkeys[count].type = type; - p->hotkeys[count].id = id; - p->hotkeys[count].lv = lv; - next+=pos; } - break; //Found hotkeys. + p.last_point.map = mapindex_name2id(last_map); + sd->found_char[i] = p.char_id; + j += mmo_char_tobuf(WBUFP(buf, j), &p); } - fclose(fp); - return count; -#else - return 0; -#endif -} + for( ; i < MAX_CHARS; i++ ) + sd->found_char[i] = -1; + memset(sd->new_name,0,sizeof(sd->new_name)); + SqlStmt_Free(stmt); + return j; +} -#ifndef TXT_SQL_CONVERT -//--------------------------------- -// Function to read characters file -//--------------------------------- -int mmo_char_init(void) +//===================================================================================================== +int mmo_char_fromsql(int char_id, struct mmo_charstatus* p, bool load_everything) { - char line[65536]; - int ret, line_count; - FILE* fp; + int i,j; + char t_msg[128] = ""; + struct mmo_charstatus* cp; + StringBuf buf; + SqlStmt* stmt; + char last_map[MAP_NAME_LENGTH_EXT]; + char save_map[MAP_NAME_LENGTH_EXT]; + char point_map[MAP_NAME_LENGTH_EXT]; + struct point tmp_point; + struct item tmp_item; + struct s_skill tmp_skill; + struct s_friend tmp_friend; +#ifdef HOTKEY_SAVING + struct hotkey tmp_hotkey; + int hotkey_num; +#endif - char_num = 0; - char_max = 0; - char_dat = NULL; + memset(p, 0, sizeof(struct mmo_charstatus)); + + if (save_log) ShowInfo("Char load request (%d)\n", char_id); - fp = fopen(char_txt, "r"); + stmt = SqlStmt_Malloc(sql_handle); + if( stmt == NULL ) + { + SqlStmt_ShowDebug(stmt); + return 0; + } - if (fp == NULL) { - ShowError("Characters file not found: %s.\n", char_txt); - char_log("Characters file not found: %s.\n", char_txt); - char_log("Id for the next created character: %d.\n", char_id_count); + // read char data + if( SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT " + "`char_id`,`account_id`,`char_num`,`name`,`class`,`base_level`,`job_level`,`base_exp`,`job_exp`,`zeny`," + "`str`,`agi`,`vit`,`int`,`dex`,`luk`,`max_hp`,`hp`,`max_sp`,`sp`," + "`status_point`,`skill_point`,`option`,`karma`,`manner`,`party_id`,`guild_id`,`pet_id`,`homun_id`,`hair`," + "`hair_color`,`clothes_color`,`weapon`,`shield`,`head_top`,`head_mid`,`head_bottom`,`last_map`,`last_x`,`last_y`," + "`save_map`,`save_x`,`save_y`,`partner_id`,`father`,`mother`,`child`,`fame`,`rename`,`delete_date`,`robe`" + " FROM `%s` WHERE `char_id`=? LIMIT 1", char_db) + || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0) + || SQL_ERROR == SqlStmt_Execute(stmt) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &p->char_id, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_INT, &p->account_id, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_UCHAR, &p->slot, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 3, SQLDT_STRING, &p->name, sizeof(p->name), NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 4, SQLDT_SHORT, &p->class_, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 5, SQLDT_UINT, &p->base_level, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 6, SQLDT_UINT, &p->job_level, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 7, SQLDT_UINT, &p->base_exp, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 8, SQLDT_UINT, &p->job_exp, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 9, SQLDT_INT, &p->zeny, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 10, SQLDT_SHORT, &p->str, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 11, SQLDT_SHORT, &p->agi, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 12, SQLDT_SHORT, &p->vit, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 13, SQLDT_SHORT, &p->int_, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 14, SQLDT_SHORT, &p->dex, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 15, SQLDT_SHORT, &p->luk, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 16, SQLDT_INT, &p->max_hp, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 17, SQLDT_INT, &p->hp, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 18, SQLDT_INT, &p->max_sp, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 19, SQLDT_INT, &p->sp, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 20, SQLDT_UINT, &p->status_point, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 21, SQLDT_UINT, &p->skill_point, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 22, SQLDT_UINT, &p->option, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 23, SQLDT_UCHAR, &p->karma, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 24, SQLDT_SHORT, &p->manner, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 25, SQLDT_INT, &p->party_id, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 26, SQLDT_INT, &p->guild_id, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 27, SQLDT_INT, &p->pet_id, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 28, SQLDT_INT, &p->hom_id, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 29, SQLDT_SHORT, &p->hair, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 30, SQLDT_SHORT, &p->hair_color, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 31, SQLDT_SHORT, &p->clothes_color, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 32, SQLDT_SHORT, &p->weapon, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 33, SQLDT_SHORT, &p->shield, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 34, SQLDT_SHORT, &p->head_top, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 35, SQLDT_SHORT, &p->head_mid, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 36, SQLDT_SHORT, &p->head_bottom, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 37, SQLDT_STRING, &last_map, sizeof(last_map), NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 38, SQLDT_SHORT, &p->last_point.x, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 39, SQLDT_SHORT, &p->last_point.y, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 40, SQLDT_STRING, &save_map, sizeof(save_map), NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 41, SQLDT_SHORT, &p->save_point.x, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 42, SQLDT_SHORT, &p->save_point.y, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 43, SQLDT_INT, &p->partner_id, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 44, SQLDT_INT, &p->father, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 45, SQLDT_INT, &p->mother, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 46, SQLDT_INT, &p->child, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 47, SQLDT_INT, &p->fame, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 48, SQLDT_SHORT, &p->rename, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 49, SQLDT_UINT32, &p->delete_date, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 50, SQLDT_SHORT, &p->robe, 0, NULL, NULL) + ) + { + SqlStmt_ShowDebug(stmt); + SqlStmt_Free(stmt); return 0; } + if( SQL_ERROR == SqlStmt_NextRow(stmt) ) + { + ShowError("Requested non-existant character id: %d!\n", char_id); + SqlStmt_Free(stmt); + return 0; + } + p->last_point.map = mapindex_name2id(last_map); + p->save_point.map = mapindex_name2id(save_map); - line_count = 0; - while(fgets(line, sizeof(line), fp)) + strcat(t_msg, " status"); + + if (!load_everything) // For quick selection of data when displaying the char menu { - int i, j; - line_count++; + SqlStmt_Free(stmt); + return 1; + } - if (line[0] == '/' && line[1] == '/') - continue; + //read memo data + //`memo` (`memo_id`,`char_id`,`map`,`x`,`y`) + if( SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT `map`,`x`,`y` FROM `%s` WHERE `char_id`=? ORDER by `memo_id` LIMIT %d", memo_db, MAX_MEMOPOINTS) + || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0) + || SQL_ERROR == SqlStmt_Execute(stmt) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_STRING, &point_map, sizeof(point_map), NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_SHORT, &tmp_point.x, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_SHORT, &tmp_point.y, 0, NULL, NULL) ) + SqlStmt_ShowDebug(stmt); + + for( i = 0; i < MAX_MEMOPOINTS && SQL_SUCCESS == SqlStmt_NextRow(stmt); ++i ) + { + tmp_point.map = mapindex_name2id(point_map); + memcpy(&p->memo_point[i], &tmp_point, sizeof(tmp_point)); + } + strcat(t_msg, " memo"); + + //read inventory + //`inventory` (`id`,`char_id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `card0`, `card1`, `card2`, `card3`) + StringBuf_Init(&buf); + StringBuf_AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`"); + for( i = 0; i < MAX_SLOTS; ++i ) + StringBuf_Printf(&buf, ", `card%d`", i); + StringBuf_Printf(&buf, " FROM `%s` WHERE `char_id`=? LIMIT %d", inventory_db, MAX_INVENTORY); + + if( SQL_ERROR == SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf)) + || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0) + || SQL_ERROR == SqlStmt_Execute(stmt) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &tmp_item.id, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_SHORT, &tmp_item.nameid, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_SHORT, &tmp_item.amount, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 3, SQLDT_USHORT, &tmp_item.equip, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 4, SQLDT_CHAR, &tmp_item.identify, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 5, SQLDT_CHAR, &tmp_item.refine, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 6, SQLDT_CHAR, &tmp_item.attribute, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 7, SQLDT_UINT, &tmp_item.expire_time, 0, NULL, NULL) ) + SqlStmt_ShowDebug(stmt); + for( i = 0; i < MAX_SLOTS; ++i ) + if( SQL_ERROR == SqlStmt_BindColumn(stmt, 8+i, SQLDT_SHORT, &tmp_item.card[i], 0, NULL, NULL) ) + SqlStmt_ShowDebug(stmt); + + for( i = 0; i < MAX_INVENTORY && SQL_SUCCESS == SqlStmt_NextRow(stmt); ++i ) + memcpy(&p->inventory[i], &tmp_item, sizeof(tmp_item)); + + strcat(t_msg, " inventory"); + + //read cart + //`cart_inventory` (`id`,`char_id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `card0`, `card1`, `card2`, `card3`) + StringBuf_Clear(&buf); + StringBuf_AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`"); + for( j = 0; j < MAX_SLOTS; ++j ) + StringBuf_Printf(&buf, ", `card%d`", j); + StringBuf_Printf(&buf, " FROM `%s` WHERE `char_id`=? LIMIT %d", cart_db, MAX_CART); + + if( SQL_ERROR == SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf)) + || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0) + || SQL_ERROR == SqlStmt_Execute(stmt) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &tmp_item.id, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_SHORT, &tmp_item.nameid, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_SHORT, &tmp_item.amount, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 3, SQLDT_USHORT, &tmp_item.equip, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 4, SQLDT_CHAR, &tmp_item.identify, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 5, SQLDT_CHAR, &tmp_item.refine, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 6, SQLDT_CHAR, &tmp_item.attribute, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 7, SQLDT_UINT, &tmp_item.expire_time, 0, NULL, NULL) ) + SqlStmt_ShowDebug(stmt); + for( i = 0; i < MAX_SLOTS; ++i ) + if( SQL_ERROR == SqlStmt_BindColumn(stmt, 8+i, SQLDT_SHORT, &tmp_item.card[i], 0, NULL, NULL) ) + SqlStmt_ShowDebug(stmt); + + for( i = 0; i < MAX_CART && SQL_SUCCESS == SqlStmt_NextRow(stmt); ++i ) + memcpy(&p->cart[i], &tmp_item, sizeof(tmp_item)); + strcat(t_msg, " cart"); + + //read storage + storage_fromsql(p->account_id, &p->storage); + strcat(t_msg, " storage"); + + //read skill + //`skill` (`char_id`, `id`, `lv`) + if( SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT `id`, `lv` FROM `%s` WHERE `char_id`=? LIMIT %d", skill_db, MAX_SKILL) + || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0) + || SQL_ERROR == SqlStmt_Execute(stmt) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_USHORT, &tmp_skill.id, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_USHORT, &tmp_skill.lv, 0, NULL, NULL) ) + SqlStmt_ShowDebug(stmt); + tmp_skill.flag = SKILL_FLAG_PERMANENT; + + for( i = 0; i < MAX_SKILL && SQL_SUCCESS == SqlStmt_NextRow(stmt); ++i ) + { + if( tmp_skill.id < ARRAYLENGTH(p->skill) ) + memcpy(&p->skill[tmp_skill.id], &tmp_skill, sizeof(tmp_skill)); + else + ShowWarning("mmo_char_fromsql: ignoring invalid skill (id=%u,lv=%u) of character %s (AID=%d,CID=%d)\n", tmp_skill.id, tmp_skill.lv, p->name, p->account_id, p->char_id); + } + strcat(t_msg, " skills"); + + //read friends + //`friends` (`char_id`, `friend_account`, `friend_id`) + if( SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT c.`account_id`, c.`char_id`, c.`name` FROM `%s` c LEFT JOIN `%s` f ON f.`friend_account` = c.`account_id` AND f.`friend_id` = c.`char_id` WHERE f.`char_id`=? LIMIT %d", char_db, friend_db, MAX_FRIENDS) + || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0) + || SQL_ERROR == SqlStmt_Execute(stmt) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &tmp_friend.account_id, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_INT, &tmp_friend.char_id, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_STRING, &tmp_friend.name, sizeof(tmp_friend.name), NULL, NULL) ) + SqlStmt_ShowDebug(stmt); + + for( i = 0; i < MAX_FRIENDS && SQL_SUCCESS == SqlStmt_NextRow(stmt); ++i ) + memcpy(&p->friends[i], &tmp_friend, sizeof(tmp_friend)); + strcat(t_msg, " friends"); - j = 0; - if (sscanf(line, "%d\t%%newid%%%n", &i, &j) == 1 && j > 0) { - if (char_id_count < i) - char_id_count = i; - continue; - } +#ifdef HOTKEY_SAVING + //read hotkeys + //`hotkey` (`char_id`, `hotkey`, `type`, `itemskill_id`, `skill_lvl` + if( SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT `hotkey`, `type`, `itemskill_id`, `skill_lvl` FROM `%s` WHERE `char_id`=?", hotkey_db) + || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0) + || SQL_ERROR == SqlStmt_Execute(stmt) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &hotkey_num, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_UCHAR, &tmp_hotkey.type, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_UINT, &tmp_hotkey.id, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 3, SQLDT_USHORT, &tmp_hotkey.lv, 0, NULL, NULL) ) + SqlStmt_ShowDebug(stmt); + + while( SQL_SUCCESS == SqlStmt_NextRow(stmt) ) + { + if( hotkey_num >= 0 && hotkey_num < MAX_HOTKEYS ) + memcpy(&p->hotkeys[hotkey_num], &tmp_hotkey, sizeof(tmp_hotkey)); + else + ShowWarning("mmo_char_fromsql: ignoring invalid hotkey (hotkey=%d,type=%u,id=%u,lv=%u) of character %s (AID=%d,CID=%d)\n", hotkey_num, tmp_hotkey.type, tmp_hotkey.id, tmp_hotkey.lv, p->name, p->account_id, p->char_id); + } + strcat(t_msg, " hotkeys"); +#endif - if (char_num >= char_max) { - char_max += 256; - char_dat = (struct character_data*)aRealloc(char_dat, sizeof(struct character_data) * char_max); - if (!char_dat) { - ShowFatalError("Out of memory: mmo_char_init (realloc of char_dat).\n"); - char_log("Out of memory: mmo_char_init (realloc of char_dat).\n"); - exit(EXIT_FAILURE); - } - } + /* Mercenary Owner DataBase */ + mercenary_owner_fromsql(char_id, p); + strcat(t_msg, " mercenary"); - ret = mmo_char_fromstr(line, &char_dat[char_num].status, char_dat[char_num].global, &char_dat[char_num].global_num); - // Initialize friends list - parse_friend_txt(&char_dat[char_num].status); // Grab friends for the character - // Initialize hotkey list - parse_hotkey_txt(&char_dat[char_num].status); // Grab hotkeys for the character - - if (ret > 0) { // negative value or zero for errors - if (char_dat[char_num].status.char_id >= char_id_count) - char_id_count = char_dat[char_num].status.char_id + 1; - char_num++; - } else { - ShowError("mmo_char_init: in characters file, unable to read the line #%d.\n", line_count); - ShowError(" -> Character saved in log file.\n"); - switch (ret) { - case -1: - char_log("Duplicate character id in the next character line (character not readed):\n"); - break; - case -2: - char_log("Duplicate character name in the next character line (character not readed):\n"); - break; - case -3: - char_log("Invalid memo point structure in the next character line (character not readed):\n"); - break; - case -4: - char_log("Invalid inventory item structure in the next character line (character not readed):\n"); - break; - case -5: - char_log("Invalid cart item structure in the next character line (character not readed):\n"); - break; - case -6: - char_log("Invalid skill structure in the next character line (character not readed):\n"); - break; - case -7: - char_log("Invalid register structure in the next character line (character not readed):\n"); - break; - default: // 0 - char_log("Unabled to get a character in the next line - Basic structure of line (before inventory) is incorrect (character not readed):\n"); - break; - } - char_log("%s", line); - } - } - fclose(fp); + if (save_log) ShowInfo("Loaded char (%d - %s): %s\n", char_id, p->name, t_msg); //ok. all data load successfuly! + SqlStmt_Free(stmt); + StringBuf_Destroy(&buf); - if (char_num == 0) { - ShowNotice("mmo_char_init: No character found in %s.\n", char_txt); - char_log("mmo_char_init: No character found in %s.\n", char_txt); - } else if (char_num == 1) { - ShowStatus("mmo_char_init: 1 character read in %s.\n", char_txt); - char_log("mmo_char_init: 1 character read in %s.\n", char_txt); - } else { - ShowStatus("mmo_char_init: %d characters read in %s.\n", char_num, char_txt); - char_log("mmo_char_init: %d characters read in %s.\n", char_num, char_txt); + cp = (struct mmo_charstatus*)idb_ensure(char_db_, char_id, create_charstatus); + memcpy(cp, p, sizeof(struct mmo_charstatus)); + return 1; +} + +//========================================================================================================== +int mmo_char_sql_init(void) +{ + ShowInfo("Begin Initializing.......\n"); + char_db_= idb_alloc(DB_OPT_RELEASE_DATA); + + if(char_per_account == 0){ + ShowStatus("Chars per Account: 'Unlimited'.......\n"); + }else{ + ShowStatus("Chars per Account: '%d'.......\n", char_per_account); } - char_log("Id for the next created character: %d.\n", char_id_count); + //the 'set offline' part is now in check_login_conn ... + //if the server connects to loginserver + //it will dc all off players + //and send the loginserver the new state.... + + // Force all users offline in sql when starting char-server + // (useful when servers crashs and don't clean the database) + set_all_offline_sql(); + + ShowInfo("Finished initilizing.......\n"); return 0; } -//--------------------------------------------------------- -// Function to save characters in files (speed up by [Yor]) -//--------------------------------------------------------- -void mmo_char_sync(void) +//----------------------------------- +// Function to change chararcter's names +//----------------------------------- +int rename_char_sql(struct char_session_data *sd, int char_id) { - char line[65536],f_line[1024]; - int i, j, k; - int lock; - FILE *fp,*f_fp; - CREATE_BUFFER(id, int, char_num); - - // Sorting before save (by [Yor]) - for(i = 0; i < char_num; i++) { - id[i] = i; - for(j = 0; j < i; j++) { - if ((char_dat[i].status.account_id < char_dat[id[j]].status.account_id) || - // if same account id, we sort by slot. - (char_dat[i].status.account_id == char_dat[id[j]].status.account_id && - char_dat[i].status.slot < char_dat[id[j]].status.slot)) { - for(k = i; k > j; k--) - id[k] = id[k-1]; - id[j] = i; // id[i] - break; - } - } - } + struct mmo_charstatus char_dat; + char esc_name[NAME_LENGTH*2+1]; - // Data save - fp = lock_fopen(char_txt, &lock); - if (fp == NULL) { - ShowWarning("Server cannot save characters.\n"); - char_log("WARNING: Server cannot save characters.\n"); - } else { - for(i = 0; i < char_num; i++) { - mmo_char_tostr(line, &char_dat[id[i]].status, char_dat[id[i]].global, char_dat[id[i]].global_num); // use of sorted index - fprintf(fp, "%s\n", line); - } - fprintf(fp, "%d\t%%newid%%\n", char_id_count); - lock_fclose(fp, char_txt, &lock); - } + if( sd->new_name[0] == 0 ) // Not ready for rename + return 2; + + if( !mmo_char_fromsql(char_id, &char_dat, false) ) // Only the short data is needed. + return 2; - // Friends List data save (davidsiaw) - f_fp = lock_fopen(friends_txt, &lock); - for(i = 0; i < char_num; i++) { - mmo_friends_list_data_str(f_line, &char_dat[id[i]].status); - fprintf(f_fp, "%s\n", f_line); - } + if( char_dat.rename == 0 ) + return 1; - lock_fclose(f_fp, friends_txt, &lock); + Sql_EscapeStringLen(sql_handle, esc_name, sd->new_name, strnlen(sd->new_name, NAME_LENGTH)); -#ifdef HOTKEY_SAVING - // Hotkey List data save (Skotlex) - f_fp = lock_fopen(hotkeys_txt, &lock); - for(i = 0; i < char_num; i++) { - mmo_hotkeys_tostr(f_line, &char_dat[id[i]].status); - fprintf(f_fp, "%s\n", f_line); + // check if the char exist + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT 1 FROM `%s` WHERE `name` LIKE '%s' LIMIT 1", char_db, esc_name) ) + { + Sql_ShowDebug(sql_handle); + return 4; } - lock_fclose(f_fp, hotkeys_txt, &lock); -#endif + if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `name` = '%s', `rename` = '%d' WHERE `char_id` = '%d'", char_db, esc_name, --char_dat.rename, char_id) ) + { + Sql_ShowDebug(sql_handle); + return 3; + } - DELETE_BUFFER(id); + // Change character's name into guild_db. + if( char_dat.guild_id ) + inter_guild_charname_changed(char_dat.guild_id, sd->account_id, char_id, sd->new_name); - return; -} + safestrncpy(char_dat.name, sd->new_name, NAME_LENGTH); + memset(sd->new_name,0,sizeof(sd->new_name)); + + // log change + if( log_char ) + { + if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`time`, `char_msg`,`account_id`,`char_num`,`name`,`str`,`agi`,`vit`,`int`,`dex`,`luk`,`hair`,`hair_color`)" + "VALUES (NOW(), '%s', '%d', '%d', '%s', '0', '0', '0', '0', '0', '0', '0', '0')", + charlog_db, "change char name", sd->account_id, char_dat.slot, esc_name) ) + Sql_ShowDebug(sql_handle); + } -//---------------------------------------------------- -// Function to save (in a periodic way) datas in files -//---------------------------------------------------- -int mmo_char_sync_timer(int tid, unsigned int tick, int id, intptr_t data) -{ - if (save_log) - ShowInfo("Saving all files...\n"); - mmo_char_sync(); - inter_save(); return 0; } -int check_char_name(char * name) +int check_char_name(char * name, char * esc_name) { int i; // check length of character name if( name[0] == '\0' ) return -2; // empty character name - + /** + * The client does not allow you to create names with less than 4 characters, however, + * the use of WPE can bypass this, and this fixes the exploit. + **/ + if( strlen( name ) < 4 ) + return -2; // check content of character name if( remove_control_chars(name) ) return -2; // control chars in name @@ -1267,17 +1296,18 @@ int check_char_name(char * name) if( strchr(char_name_letters, name[i]) != NULL ) return -2; } - - // check name (already in use?) - if( name_ignoring_case ) - { - ARR_FIND( 0, char_num, i, strncmp(char_dat[i].status.name, name, NAME_LENGTH) == 0 ); - } - else - { - ARR_FIND( 0, char_num, i, strncmpi(char_dat[i].status.name, name, NAME_LENGTH) == 0 ); + if( name_ignoring_case ) { + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT 1 FROM `%s` WHERE BINARY `name` = '%s' LIMIT 1", char_db, esc_name) ) { + Sql_ShowDebug(sql_handle); + return -2; + } + } else { + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT 1 FROM `%s` WHERE `name` = '%s' LIMIT 1", char_db, esc_name) ) { + Sql_ShowDebug(sql_handle); + return -2; + } } - if( i < char_num ) + if( Sql_NumRows(sql_handle) > 0 ) return -1; // name already exists return 0; @@ -1286,15 +1316,17 @@ int check_char_name(char * name) //----------------------------------- // Function to create a new character //----------------------------------- -int make_new_char(struct char_session_data* sd, char* name_, int str, int agi, int vit, int int_, int dex, int luk, int slot, int hair_color, int hair_style) +int make_new_char_sql(struct char_session_data* sd, char* name_, int str, int agi, int vit, int int_, int dex, int luk, int slot, int hair_color, int hair_style) { char name[NAME_LENGTH]; - int i, flag; - + char esc_name[NAME_LENGTH*2+1]; + int char_id, flag; + safestrncpy(name, name_, NAME_LENGTH); normalize_name(name,TRIM_CHARS); + Sql_EscapeStringLen(sql_handle, esc_name, name, strnlen(name, NAME_LENGTH)); - flag = check_char_name(name); + flag = check_char_name(name,esc_name); if( flag < 0 ) return flag; @@ -1307,471 +1339,226 @@ int make_new_char(struct char_session_data* sd, char* name_, int str, int agi, i // check the number of already existing chars in this account if( char_per_account != 0 ) { - ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == -1 ); - - if( i >= char_per_account ) + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT 1 FROM `%s` WHERE `account_id` = '%d'", char_db, sd->account_id) ) + Sql_ShowDebug(sql_handle); + if( Sql_NumRows(sql_handle) >= char_per_account ) return -2; // character account limit exceeded } // check char slot - ARR_FIND( 0, char_num, i, char_dat[i].status.account_id == sd->account_id && char_dat[i].status.slot == slot ); - if( i < char_num ) + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT 1 FROM `%s` WHERE `account_id` = '%d' AND `char_num` = '%d' LIMIT 1", char_db, sd->account_id, slot) ) + Sql_ShowDebug(sql_handle); + if( Sql_NumRows(sql_handle) > 0 ) return -2; // slot already in use - if (char_num >= char_max) { - char_max += 256; - RECREATE(char_dat, struct character_data, char_max); - if (!char_dat) { - ShowFatalError("Out of memory: make_new_char (realloc of char_dat).\n"); - char_log("Out of memory: make_new_char (realloc of char_dat).\n"); - exit(EXIT_FAILURE); - } + // validation success, log result + if (log_char) { + if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`time`, `char_msg`,`account_id`,`char_num`,`name`,`str`,`agi`,`vit`,`int`,`dex`,`luk`,`hair`,`hair_color`)" + "VALUES (NOW(), '%s', '%d', '%d', '%s', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d')", + charlog_db, "make new char", sd->account_id, slot, esc_name, str, agi, vit, int_, dex, luk, hair_style, hair_color) ) + Sql_ShowDebug(sql_handle); } - // validation success, log result - char_log("make new char: account: %d, slot %d, name: %s, stats: %d/%d/%d/%d/%d/%d, hair: %d, hair color: %d.\n", - sd->account_id, slot, name, str, agi, vit, int_, dex, luk, hair_style, hair_color); - - i = char_num; - memset(&char_dat[i], 0, sizeof(struct character_data)); - - char_dat[i].status.char_id = char_id_count++; - char_dat[i].status.account_id = sd->account_id; - char_dat[i].status.slot = slot; - safestrncpy(char_dat[i].status.name,name,NAME_LENGTH); - char_dat[i].status.class_ = 0; - char_dat[i].status.base_level = 1; - char_dat[i].status.job_level = 1; - char_dat[i].status.base_exp = 0; - char_dat[i].status.job_exp = 0; - char_dat[i].status.zeny = start_zeny; - char_dat[i].status.str = str; - char_dat[i].status.agi = agi; - char_dat[i].status.vit = vit; - char_dat[i].status.int_ = int_; - char_dat[i].status.dex = dex; - char_dat[i].status.luk = luk; - char_dat[i].status.max_hp = 40 * (100 + char_dat[i].status.vit) / 100; - char_dat[i].status.max_sp = 11 * (100 + char_dat[i].status.int_) / 100; - char_dat[i].status.hp = char_dat[i].status.max_hp; - char_dat[i].status.sp = char_dat[i].status.max_sp; - char_dat[i].status.status_point = 0; - char_dat[i].status.skill_point = 0; - char_dat[i].status.option = 0; - char_dat[i].status.karma = 0; - char_dat[i].status.manner = 0; - char_dat[i].status.party_id = 0; - char_dat[i].status.guild_id = 0; - char_dat[i].status.hair = hair_style; - char_dat[i].status.hair_color = hair_color; - char_dat[i].status.clothes_color = 0; - char_dat[i].status.inventory[0].nameid = start_weapon; // Knife - char_dat[i].status.inventory[0].amount = 1; - char_dat[i].status.inventory[0].identify = 1; - char_dat[i].status.inventory[1].nameid = start_armor; // Cotton Shirt - char_dat[i].status.inventory[1].amount = 1; - char_dat[i].status.inventory[1].identify = 1; - char_dat[i].status.weapon = 0; // W_FIST - char_dat[i].status.shield = 0; - char_dat[i].status.head_top = 0; - char_dat[i].status.head_mid = 0; - char_dat[i].status.head_bottom = 0; - memcpy(&char_dat[i].status.last_point, &start_point, sizeof(start_point)); - memcpy(&char_dat[i].status.save_point, &start_point, sizeof(start_point)); - char_num++; - - ShowInfo("Created char: account: %d, char: %d, slot: %d, name: %s\n", sd->account_id, i, slot, name); - mmo_char_sync(); - return i; + //Insert the new char entry to the database + if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`account_id`, `char_num`, `name`, `zeny`, `str`, `agi`, `vit`, `int`, `dex`, `luk`, `max_hp`, `hp`," + "`max_sp`, `sp`, `hair`, `hair_color`, `last_map`, `last_x`, `last_y`, `save_map`, `save_x`, `save_y`) VALUES (" + "'%d', '%d', '%s', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d','%d', '%d','%d', '%d', '%s', '%d', '%d', '%s', '%d', '%d')", + char_db, sd->account_id , slot, esc_name, start_zeny, str, agi, vit, int_, dex, luk, + (40 * (100 + vit)/100) , (40 * (100 + vit)/100 ), (11 * (100 + int_)/100), (11 * (100 + int_)/100), hair_style, hair_color, + mapindex_id2name(start_point.map), start_point.x, start_point.y, mapindex_id2name(start_point.map), start_point.x, start_point.y) ) + { + Sql_ShowDebug(sql_handle); + return -2; //No, stop the procedure! + } + //Retrieve the newly auto-generated char id + char_id = (int)Sql_LastInsertId(sql_handle); + //Give the char the default items + if (start_weapon > 0) { //add Start Weapon (Knife?) + if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`char_id`,`nameid`, `amount`, `identify`) VALUES ('%d', '%d', '%d', '%d')", inventory_db, char_id, start_weapon, 1, 1) ) + Sql_ShowDebug(sql_handle); + } + if (start_armor > 0) { //Add default armor (cotton shirt?) + if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`char_id`,`nameid`, `amount`, `identify`) VALUES ('%d', '%d', '%d', '%d')", inventory_db, char_id, start_armor, 1, 1) ) + Sql_ShowDebug(sql_handle); + } + + ShowInfo("Created char: account: %d, char: %d, slot: %d, name: %s\n", sd->account_id, char_id, slot, name); + return char_id; } -//---------------------------------------------------- -// This function return the name of the job (by [Yor]) -//---------------------------------------------------- -char * job_name(int class_) +/*----------------------------------------------------------------------------------------------------------*/ +/* Divorce Players */ +/*----------------------------------------------------------------------------------------------------------*/ +int divorce_char_sql(int partner_id1, int partner_id2) { - switch (class_) { - case JOB_NOVICE: return "Novice"; - case JOB_SWORDMAN: return "Swordsman"; - case JOB_MAGE: return "Mage"; - case JOB_ARCHER: return "Archer"; - case JOB_ACOLYTE: return "Acolyte"; - case JOB_MERCHANT: return "Merchant"; - case JOB_THIEF: return "Thief"; - case JOB_KNIGHT: return "Knight"; - case JOB_PRIEST: return "Priest"; - case JOB_WIZARD: return "Wizard"; - case JOB_BLACKSMITH: return "Blacksmith"; - case JOB_HUNTER: return "Hunter"; - case JOB_ASSASSIN: return "Assassin"; - case JOB_KNIGHT2: return "Peco-Knight"; - case JOB_CRUSADER: return "Crusader"; - case JOB_MONK: return "Monk"; - case JOB_SAGE: return "Sage"; - case JOB_ROGUE: return "Rogue"; - case JOB_ALCHEMIST: return "Alchemist"; - case JOB_BARD: return "Bard"; - case JOB_DANCER: return "Dancer"; - case JOB_CRUSADER2: return "Peco-Crusader"; - case JOB_WEDDING: return "Wedding"; - case JOB_SUPER_NOVICE: return "Super Novice"; - case JOB_GUNSLINGER: return "Gunslinger"; - case JOB_NINJA: return "Ninja"; - case JOB_XMAS: return "Christmas"; - case JOB_NOVICE_HIGH: return "Novice High"; - case JOB_SWORDMAN_HIGH: return "Swordsman High"; - case JOB_MAGE_HIGH: return "Mage High"; - case JOB_ARCHER_HIGH: return "Archer High"; - case JOB_ACOLYTE_HIGH: return "Acolyte High"; - case JOB_MERCHANT_HIGH: return "Merchant High"; - case JOB_THIEF_HIGH: return "Thief High"; - case JOB_LORD_KNIGHT: return "Lord Knight"; - case JOB_HIGH_PRIEST: return "High Priest"; - case JOB_HIGH_WIZARD: return "High Wizard"; - case JOB_WHITESMITH: return "Whitesmith"; - case JOB_SNIPER: return "Sniper"; - case JOB_ASSASSIN_CROSS: return "Assassin Cross"; - case JOB_LORD_KNIGHT2: return "Peko Knight"; - case JOB_PALADIN: return "Paladin"; - case JOB_CHAMPION: return "Champion"; - case JOB_PROFESSOR: return "Professor"; - case JOB_STALKER: return "Stalker"; - case JOB_CREATOR: return "Creator"; - case JOB_CLOWN: return "Clown"; - case JOB_GYPSY: return "Gypsy"; - case JOB_PALADIN2: return "Peko Paladin"; - case JOB_BABY: return "Baby Novice"; - case JOB_BABY_SWORDMAN: return "Baby Swordsman"; - case JOB_BABY_MAGE: return "Baby Mage"; - case JOB_BABY_ARCHER: return "Baby Archer"; - case JOB_BABY_ACOLYTE: return "Baby Acolyte"; - case JOB_BABY_MERCHANT: return "Baby Merchant"; - case JOB_BABY_THIEF: return "Baby Thief"; - case JOB_BABY_KNIGHT: return "Baby Knight"; - case JOB_BABY_PRIEST: return "Baby Priest"; - case JOB_BABY_WIZARD: return "Baby Wizard"; - case JOB_BABY_BLACKSMITH: return "Baby Blacksmith"; - case JOB_BABY_HUNTER: return "Baby Hunter"; - case JOB_BABY_ASSASSIN: return "Baby Assassin"; - case JOB_BABY_KNIGHT2: return "Baby Peco Knight"; - case JOB_BABY_CRUSADER: return "Baby Crusader"; - case JOB_BABY_MONK: return "Baby Monk"; - case JOB_BABY_SAGE: return "Baby Sage"; - case JOB_BABY_ROGUE: return "Baby Rogue"; - case JOB_BABY_ALCHEMIST: return "Baby Alchemist"; - case JOB_BABY_BARD: return "Baby Bard"; - case JOB_BABY_DANCER: return "Baby Dancer"; - case JOB_BABY_CRUSADER2: return "Baby Peco Crusader"; - case JOB_SUPER_BABY: return "Super Baby"; - case JOB_TAEKWON: return "Taekwon"; - case JOB_STAR_GLADIATOR: return "Star Gladiator"; - case JOB_STAR_GLADIATOR2: return "Flying Star Gladiator"; - case JOB_SOUL_LINKER: return "Soul Linker"; - } - return "Unknown Job"; + unsigned char buf[64]; + + if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `partner_id`='0' WHERE `char_id`='%d' OR `char_id`='%d' LIMIT 2", char_db, partner_id1, partner_id2) ) + Sql_ShowDebug(sql_handle); + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE (`nameid`='%d' OR `nameid`='%d') AND (`char_id`='%d' OR `char_id`='%d') LIMIT 2", inventory_db, WEDDING_RING_M, WEDDING_RING_F, partner_id1, partner_id2) ) + Sql_ShowDebug(sql_handle); + + WBUFW(buf,0) = 0x2b12; + WBUFL(buf,2) = partner_id1; + WBUFL(buf,6) = partner_id2; + mapif_sendall(buf,10); + + return 0; } -static int create_online_files_sub(DBKey key, void* data, va_list va) +/*----------------------------------------------------------------------------------------------------------*/ +/* Delete char - davidsiaw */ +/*----------------------------------------------------------------------------------------------------------*/ +/* Returns 0 if successful + * Returns < 0 for error + */ +int delete_char_sql(int char_id) { - struct online_char_data *character; - int* players; - int *id; - int j,k,l; - character = (struct online_char_data*) data; - players = va_arg(va, int*); - id = va_arg(va, int*); - - // check if map-server is online - if (character->server == -1 || character->char_id == -1) { //Character not currently online. + char name[NAME_LENGTH]; + char esc_name[NAME_LENGTH*2+1]; //Name needs be escaped. + int account_id, party_id, guild_id, hom_id, base_level, partner_id, father_id, mother_id; + char* data; + size_t len; + + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `name`,`account_id`,`party_id`,`guild_id`,`base_level`,`homun_id`,`partner_id`,`father`,`mother` FROM `%s` WHERE `char_id`='%d'", char_db, char_id) ) + Sql_ShowDebug(sql_handle); + + if( SQL_SUCCESS != Sql_NextRow(sql_handle) ) + { + ShowError("delete_char_sql: Unable to fetch character data, deletion aborted.\n"); + Sql_FreeResult(sql_handle); return -1; } - - j = character->server; - if (server[j].fd < 0) { - server[j].users = 0; - return -1; + + Sql_GetData(sql_handle, 0, &data, &len); safestrncpy(name, data, NAME_LENGTH); + Sql_GetData(sql_handle, 1, &data, NULL); account_id = atoi(data); + Sql_GetData(sql_handle, 2, &data, NULL); party_id = atoi(data); + Sql_GetData(sql_handle, 3, &data, NULL); guild_id = atoi(data); + Sql_GetData(sql_handle, 4, &data, NULL); base_level = atoi(data); + Sql_GetData(sql_handle, 5, &data, NULL); hom_id = atoi(data); + Sql_GetData(sql_handle, 6, &data, NULL); partner_id = atoi(data); + Sql_GetData(sql_handle, 7, &data, NULL); father_id = atoi(data); + Sql_GetData(sql_handle, 8, &data, NULL); mother_id = atoi(data); + + Sql_EscapeStringLen(sql_handle, esc_name, name, min(len, NAME_LENGTH)); + Sql_FreeResult(sql_handle); + + //check for config char del condition [Lupus] + // TODO: Move this out to packet processing (0x68/0x1fb). + if( ( char_del_level > 0 && base_level >= char_del_level ) + || ( char_del_level < 0 && base_level <= -char_del_level ) + ) { + ShowInfo("Char deletion aborted: %s, BaseLevel: %i\n", name, base_level); + return -1; } - // search position of character in char_dat and sort online characters. - for(j = 0; j < char_num; j++) { - if (char_dat[j].status.char_id != character->char_id) - continue; - id[*players] = j; - // use sorting option - switch (online_sorting_option) { - case 1: // by name (without case sensitive) - for(k = 0; k < *players; k++) - if (stricmp(char_dat[j].status.name, char_dat[id[k]].status.name) < 0 || - // if same name, we sort with case sensitive. - (stricmp(char_dat[j].status.name, char_dat[id[k]].status.name) == 0 && - strcmp(char_dat[j].status.name, char_dat[id[k]].status.name) < 0)) { - for(l = *players; l > k; l--) - id[l] = id[l-1]; - id[k] = j; // id[*players] - break; - } - break; - case 2: // by zeny - for(k = 0; k < *players; k++) - if (char_dat[j].status.zeny < char_dat[id[k]].status.zeny || - // if same number of zenys, we sort by name. - (char_dat[j].status.zeny == char_dat[id[k]].status.zeny && - stricmp(char_dat[j].status.name, char_dat[id[k]].status.name) < 0)) { - for(l = *players; l > k; l--) - id[l] = id[l-1]; - id[k] = j; // id[*players] - break; - } - break; - case 3: // by base level - for(k = 0; k < *players; k++) - if (char_dat[j].status.base_level < char_dat[id[k]].status.base_level || - // if same base level, we sort by base exp. - (char_dat[j].status.base_level == char_dat[id[k]].status.base_level && - char_dat[j].status.base_exp < char_dat[id[k]].status.base_exp)) { - for(l = *players; l > k; l--) - id[l] = id[l-1]; - id[k] = j; // id[*players] - break; - } - break; - case 4: // by job (and job level) - for(k = 0; k < *players; k++) - if (char_dat[j].status.class_ < char_dat[id[k]].status.class_ || - // if same job, we sort by job level. - (char_dat[j].status.class_ == char_dat[id[k]].status.class_ && - char_dat[j].status.job_level < char_dat[id[k]].status.job_level) || - // if same job and job level, we sort by job exp. - (char_dat[j].status.class_ == char_dat[id[k]].status.class_ && - char_dat[j].status.job_level == char_dat[id[k]].status.job_level && - char_dat[j].status.job_exp < char_dat[id[k]].status.job_exp)) { - for(l = *players; l > k; l--) - id[l] = id[l-1]; - id[k] = j; // id[*players] - break; - } - break; - case 5: // by location map name - { - const char *map1, *map2; - map1 = mapindex_id2name(char_dat[j].status.last_point.map); - - for(k = 0; k < *players; k++) { - map2 = mapindex_id2name(char_dat[id[k]].status.last_point.map); - if (!map1 || !map2 || //Avoid sorting if either one failed to resolve. - stricmp(map1, map2) < 0 || - // if same map name, we sort by name. - (stricmp(map1, map2) == 0 && - stricmp(char_dat[j].status.name, char_dat[id[k]].status.name) < 0)) { - for(l = *players; l > k; l--) - id[l] = id[l-1]; - id[k] = j; // id[*players] - break; - } - } - } - break; - default: // 0 or invalid value: no sorting - break; - } - (*players)++; - break; + + /* Divorce [Wizputer] */ + if( partner_id ) + divorce_char_sql(char_id, partner_id); + + /* De-addopt [Zephyrus] */ + if( father_id || mother_id ) + { // Char is Baby + unsigned char buf[64]; + + if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `child`='0' WHERE `char_id`='%d' OR `char_id`='%d'", char_db, father_id, mother_id) ) + Sql_ShowDebug(sql_handle); + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `id` = '410'AND (`char_id`='%d' OR `char_id`='%d')", skill_db, father_id, mother_id) ) + Sql_ShowDebug(sql_handle); + + WBUFW(buf,0) = 0x2b25; + WBUFL(buf,2) = father_id; + WBUFL(buf,6) = mother_id; + WBUFL(buf,10) = char_id; // Baby + mapif_sendall(buf,14); } - return 0; -} -//------------------------------------------------------------- -// Function to create the online files (txt and html). by [Yor] -//------------------------------------------------------------- -void create_online_files(void) -{ - unsigned int k, j; // for loop with strlen comparing - int i, l; // for loops - int players; // count the number of players - FILE *fp; // for the txt file - FILE *fp2; // for the html file - char temp[256]; // to prepare what we must display - time_t time_server; // for number of seconds - struct tm *datetime; // variable for time in structure ->tm_mday, ->tm_sec, ... - int id[4096]; - - if (online_display_option == 0) // we display nothing, so return - return; - // Get number of online players, id of each online players, and verify if a server is offline - players = 0; - online_char_db->foreach(online_char_db, create_online_files_sub, &players, &id); - - // write files - fp = fopen(online_txt_filename, "w"); - if (fp != NULL) { - fp2 = fopen(online_html_filename, "w"); - if (fp2 != NULL) { - // get time - time(&time_server); // get time in seconds since 1/1/1970 - datetime = localtime(&time_server); // convert seconds in structure - strftime(temp, sizeof(temp), "%d %b %Y %X", datetime); // like sprintf, but only for date/time (05 dec 2003 15:12:52) - // write heading - fprintf(fp2, "\n"); - fprintf(fp2, " \n", online_refresh_html); // update on client explorer every x seconds - fprintf(fp2, " \n"); - fprintf(fp2, " Online Players on %s\n", server_name); - fprintf(fp2, " \n"); - fprintf(fp2, " \n"); - fprintf(fp2, "

Online Players on %s (%s):

\n", server_name, temp); - fprintf(fp, "Online Players on %s (%s):\n", server_name, temp); - fprintf(fp, "\n"); - - for (i = 0; i < players; i++) { - // if it's the first player - if (i == 0) { - j = 0; // count the number of characters for the txt version and to set the separate line - fprintf(fp2, " \n"); - fprintf(fp2, " \n"); - if ((online_display_option & 1) || (online_display_option & 64)) { - fprintf(fp2, " \n"); - if (online_display_option & 64) { - fprintf(fp, "Name "); // 30 - j += 30; - } else { - fprintf(fp, "Name "); // 25 - j += 25; - } - } - if ((online_display_option & 6) == 6) { - fprintf(fp2, " \n"); - fprintf(fp, "Job Levels "); // 27 - j += 27; - } else if (online_display_option & 2) { - fprintf(fp2, " \n"); - fprintf(fp, "Job "); // 19 - j += 19; - } else if (online_display_option & 4) { - fprintf(fp2, " \n"); - fprintf(fp, " Levels "); // 8 - j += 8; - } - if (online_display_option & 24) { // 8 or 16 - fprintf(fp2, " \n"); - if (online_display_option & 16) { - fprintf(fp, "Location ( x , y ) "); // 23 - j += 23; - } else { - fprintf(fp, "Location "); // 13 - j += 13; - } - } - if (online_display_option & 32) { - fprintf(fp2, " \n"); - fprintf(fp, " Zenys "); // 16 - j += 16; - } - fprintf(fp2, " \n"); - fprintf(fp, "\n"); - for (k = 0; k < j; k++) - fprintf(fp, "-"); - fprintf(fp, "\n"); - } - fprintf(fp2, " \n"); - // get id of the character (more speed) - j = id[i]; - // displaying the character name - if ((online_display_option & 1) || (online_display_option & 64)) { // without/with 'GM' display - safestrncpy(temp, char_dat[j].status.name, sizeof(temp)); - //l = isGM(char_dat[j].status.account_id); - l = 0; //FIXME: how to get the gm level? - if (online_display_option & 64) { - if (l >= online_gm_display_min_level) - fprintf(fp, "%-24s (GM) ", temp); - else - fprintf(fp, "%-24s ", temp); - } else - fprintf(fp, "%-24s ", temp); - // name of the character in the html (no < >, because that create problem in html code) - fprintf(fp2, " \n"); - } - // displaying of the job - if (online_display_option & 6) { - char * jobname = job_name(char_dat[j].status.class_); - if ((online_display_option & 6) == 6) { - fprintf(fp2, " \n", jobname, char_dat[j].status.base_level, char_dat[j].status.job_level); - fprintf(fp, "%-18s %3d/%3d ", jobname, char_dat[j].status.base_level, char_dat[j].status.job_level); - } else if (online_display_option & 2) { - fprintf(fp2, " \n", jobname); - fprintf(fp, "%-18s ", jobname); - } else if (online_display_option & 4) { - fprintf(fp2, " \n", char_dat[j].status.base_level, char_dat[j].status.job_level); - fprintf(fp, "%3d/%3d ", char_dat[j].status.base_level, char_dat[j].status.job_level); - } - } - // displaying of the map - if (online_display_option & 24) { // 8 or 16 - // prepare map name - safestrncpy(temp, mapindex_id2name(char_dat[j].status.last_point.map), sizeof(temp)); - // write map name - if (online_display_option & 16) { // map-name AND coordinates - fprintf(fp2, " \n", temp, char_dat[j].status.last_point.x, char_dat[j].status.last_point.y); - fprintf(fp, "%-12s (%3d,%3d) ", temp, char_dat[j].status.last_point.x, char_dat[j].status.last_point.y); - } else { - fprintf(fp2, " \n", temp); - fprintf(fp, "%-12s ", temp); - } - } - // displaying nimber of zenys - if (online_display_option & 32) { - // write number of zenys - if (char_dat[j].status.zeny == 0) { // if no zeny - fprintf(fp2, " \n"); - fprintf(fp, " no zeny "); - } else { - fprintf(fp2, " \n", char_dat[j].status.zeny); - fprintf(fp, "%13d z ", char_dat[j].status.zeny); - } - } - fprintf(fp, "\n"); - fprintf(fp2, " \n"); - } - // If we display at least 1 player - if (players > 0) { - fprintf(fp2, "
NameJob (levels)JobLevelsLocationzenys
"); - if ((online_display_option & 64) && l >= online_gm_display_min_level) - fprintf(fp2, ""); - for (k = 0; k < strlen(temp); k++) { - switch(temp[k]) { - case '<': // < - fprintf(fp2, "<"); - break; - case '>': // > - fprintf(fp2, ">"); - break; - default: - fprintf(fp2, "%c", temp[k]); - break; - }; - } - if ((online_display_option & 64) && l >= online_gm_display_min_level) - fprintf(fp2, " (GM)"); - fprintf(fp2, "%s %d/%d%s%d/%d%s (%d, %d)%sno zeny%d z
\n"); - fprintf(fp, "\n"); - } + //Make the character leave the party [Skotlex] + if (party_id) + inter_party_leave(party_id, account_id, char_id); - // Displaying number of online players - if (players == 0) { - fprintf(fp2, "

No user is online.

\n"); - fprintf(fp, "No user is online.\n"); - } else if (players == 1) { - fprintf(fp2, "

%d user is online.

\n", players); - fprintf(fp, "%d user is online.\n", players); - } else { - fprintf(fp2, "

%d users are online.

\n", players); - fprintf(fp, "%d users are online.\n", players); - } - fprintf(fp2, " \n"); - fprintf(fp2, "\n"); - fclose(fp2); - } - fclose(fp); + /* delete char's pet */ + //Delete the hatched pet if you have one... + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d' AND `incuvate` = '0'", pet_db, char_id) ) + Sql_ShowDebug(sql_handle); + + //Delete all pets that are stored in eggs (inventory + cart) + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` USING `%s` JOIN `%s` ON `pet_id` = `card1`|`card2`<<16 WHERE `%s`.char_id = '%d' AND card0 = -256", pet_db, pet_db, inventory_db, inventory_db, char_id) ) + Sql_ShowDebug(sql_handle); + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` USING `%s` JOIN `%s` ON `pet_id` = `card1`|`card2`<<16 WHERE `%s`.char_id = '%d' AND card0 = -256", pet_db, pet_db, cart_db, cart_db, char_id) ) + Sql_ShowDebug(sql_handle); + + /* remove homunculus */ + if( hom_id ) + mapif_homunculus_delete(hom_id); + + /* remove mercenary data */ + mercenary_owner_delete(char_id); + + /* delete char's friends list */ + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id` = '%d'", friend_db, char_id) ) + Sql_ShowDebug(sql_handle); + + /* delete char from other's friend list */ + //NOTE: Won't this cause problems for people who are already online? [Skotlex] + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `friend_id` = '%d'", friend_db, char_id) ) + Sql_ShowDebug(sql_handle); + +#ifdef HOTKEY_SAVING + /* delete hotkeys */ + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", hotkey_db, char_id) ) + Sql_ShowDebug(sql_handle); +#endif + + /* delete inventory */ + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", inventory_db, char_id) ) + Sql_ShowDebug(sql_handle); + + /* delete cart inventory */ + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", cart_db, char_id) ) + Sql_ShowDebug(sql_handle); + + /* delete memo areas */ + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", memo_db, char_id) ) + Sql_ShowDebug(sql_handle); + + /* delete character registry */ + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `type`=3 AND `char_id`='%d'", reg_db, char_id) ) + Sql_ShowDebug(sql_handle); + + /* delete skills */ + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", skill_db, char_id) ) + Sql_ShowDebug(sql_handle); + +#ifdef ENABLE_SC_SAVING + /* status changes */ + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `account_id` = '%d' AND `char_id`='%d'", scdata_db, account_id, char_id) ) + Sql_ShowDebug(sql_handle); +#endif + + if (log_char) { + if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s`(`time`, `account_id`,`char_num`,`char_msg`,`name`) VALUES (NOW(), '%d', '%d', 'Deleted char (CID %d)', '%s')", + charlog_db, account_id, 0, char_id, esc_name) ) + Sql_ShowDebug(sql_handle); } - return; + /* delete character */ + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", char_db, char_id) ) + Sql_ShowDebug(sql_handle); + + /* No need as we used inter_guild_leave [Skotlex] + // Also delete info from guildtables. + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", guild_member_db, char_id) ) + Sql_ShowDebug(sql_handle); + */ + + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `guild_id` FROM `%s` WHERE `char_id` = '%d'", guild_db, char_id) ) + Sql_ShowDebug(sql_handle); + else if( Sql_NumRows(sql_handle) > 0 ) + mapif_parse_BreakGuild(0,guild_id); + else if( guild_id ) + inter_guild_leave(guild_id, account_id, char_id);// Leave your guild. + return 0; } //--------------------------------------------------------------------- @@ -1828,7 +1615,10 @@ int mmo_char_tobuf(uint8* buffer, struct mmo_charstatus* p) WBUFW(buf,50) = DEFAULT_WALK_SPEED; // p->speed; WBUFW(buf,52) = p->class_; WBUFW(buf,54) = p->hair; - WBUFW(buf,56) = p->option&0x20 ? 0 : p->weapon; //When the weapon is sent and your option is riding, the client crashes on login!? + + //When the weapon is sent and your option is riding, the client crashes on login!? + WBUFW(buf,56) = p->option&(0x20|0x80000|0x100000|0x200000|0x400000|0x800000|0x1000000|0x2000000|0x4000000|0x8000000) ? 0 : p->weapon; + WBUFW(buf,58) = p->base_level; WBUFW(buf,60) = min(p->skill_point, INT16_MAX); WBUFW(buf,62) = p->head_bottom; @@ -1861,14 +1651,17 @@ int mmo_char_tobuf(uint8* buffer, struct mmo_charstatus* p) WBUFL(buf,128) = p->robe; offset += 4; #endif -#if PACKETVER >= 20110928 - WBUFL(buf,132) = 0; // change slot feature (0 = disabled, otherwise enabled) - offset += 4; -#endif -#if PACKETVER >= 20111025 - WBUFL(buf,136) = 0; // unknown purpose (0 = disabled, otherwise displays "Add-Ons" sidebar) - offset += 4; +#if PACKETVER != 20111116 //2011-11-16 wants 136, ask gravity. + #if PACKETVER >= 20110928 + WBUFL(buf,132) = 0; // change slot feature (0 = disabled, otherwise enabled) + offset += 4; + #endif + #if PACKETVER >= 20111025 + WBUFL(buf,136) = 0; // unknown purpose (0 = disabled, otherwise displays "Add-Ons" sidebar) + offset += 4; + #endif #endif + return 106+offset; } @@ -1877,15 +1670,16 @@ int mmo_char_tobuf(uint8* buffer, struct mmo_charstatus* p) //---------------------------------------- int mmo_char_send006b(int fd, struct char_session_data* sd) { - int i, j, found_num, offset = 0; + int j, offset = 0; #if PACKETVER >= 20100413 offset += 3; #endif - found_num = char_find_characters(sd); + if (save_log) + ShowInfo("Loading Char Data ("CL_BOLD"%d"CL_RESET")\n",sd->account_id); j = 24 + offset; // offset - WFIFOHEAD(fd,j + found_num*MAX_CHAR_BUF); + WFIFOHEAD(fd,j + MAX_CHARS*MAX_CHAR_BUF); WFIFOW(fd,0) = 0x6b; #if PACKETVER >= 20100413 WFIFOB(fd,4) = MAX_CHARS; // Max slots. @@ -1893,80 +1687,75 @@ int mmo_char_send006b(int fd, struct char_session_data* sd) WFIFOB(fd,6) = MAX_CHARS; // Premium slots. #endif memset(WFIFOP(fd,4 + offset), 0, 20); // unknown bytes - for(i = 0; i < found_num; i++) - j += mmo_char_tobuf(WFIFOP(fd,j), &char_dat[sd->found_char[i]].status); + j+=mmo_chars_fromsql(sd, WFIFOP(fd,j)); WFIFOW(fd,2) = j; // packet len WFIFOSET(fd,j); return 0; } -// 離婚(char削除時に使用) -int char_divorce(struct mmo_charstatus *cs) +int char_married(int pl1, int pl2) { - if (cs == NULL) - return 0; + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `partner_id` FROM `%s` WHERE `char_id` = '%d'", char_db, pl1) ) + Sql_ShowDebug(sql_handle); + else if( SQL_SUCCESS == Sql_NextRow(sql_handle) ) + { + char* data; - if (cs->partner_id > 0){ - int i, j; - for(i = 0; i < char_num; i++) { - if (char_dat[i].status.char_id == cs->partner_id && char_dat[i].status.partner_id == cs->char_id) { - cs->partner_id = 0; - char_dat[i].status.partner_id = 0; - for(j = 0; j < MAX_INVENTORY; j++) - { - if (char_dat[i].status.inventory[j].nameid == WEDDING_RING_M || char_dat[i].status.inventory[j].nameid == WEDDING_RING_F) - memset(&char_dat[i].status.inventory[j], 0, sizeof(char_dat[i].status.inventory[0])); - if (cs->inventory[j].nameid == WEDDING_RING_M || cs->inventory[j].nameid == WEDDING_RING_F) - memset(&cs->inventory[j], 0, sizeof(cs->inventory[0])); - } - return 0; - } + Sql_GetData(sql_handle, 0, &data, NULL); + if( pl2 == atoi(data) ) + { + Sql_FreeResult(sql_handle); + return 1; } } + Sql_FreeResult(sql_handle); return 0; } -int char_married(int pl1, int pl2) -{ - return (char_dat[pl1].status.char_id == char_dat[pl2].status.partner_id && char_dat[pl2].status.char_id == char_dat[pl1].status.partner_id); -} - int char_child(int parent_id, int child_id) { - return (char_dat[parent_id].status.child == char_dat[child_id].status.char_id && - ((char_dat[parent_id].status.char_id == char_dat[child_id].status.father) || - (char_dat[parent_id].status.char_id == char_dat[child_id].status.mother))); + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `child` FROM `%s` WHERE `char_id` = '%d'", char_db, parent_id) ) + Sql_ShowDebug(sql_handle); + else if( SQL_SUCCESS == Sql_NextRow(sql_handle) ) + { + char* data; + + Sql_GetData(sql_handle, 0, &data, NULL); + if( child_id == atoi(data) ) + { + Sql_FreeResult(sql_handle); + return 1; + } + } + Sql_FreeResult(sql_handle); + return 0; } int char_family(int cid1, int cid2, int cid3) { - int i, idx1 = -1, idx2 =-1;//, idx3 =-1; - for(i = 0; i < char_num && (idx1 == -1 || idx2 == -1/* || idx3 == 1*/); i++) - { - if (char_dat[i].status.char_id == cid1) - idx1 = i; - if (char_dat[i].status.char_id == cid2) - idx2 = i; -// if (char_dat[i].status.char_id == cid2) -// idx3 = i; + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`,`partner_id`,`child` FROM `%s` WHERE `char_id` IN ('%d','%d','%d')", char_db, cid1, cid2, cid3) ) + Sql_ShowDebug(sql_handle); + else while( SQL_SUCCESS == Sql_NextRow(sql_handle) ) + { + int charid; + int partnerid; + int childid; + char* data; + + Sql_GetData(sql_handle, 0, &data, NULL); charid = atoi(data); + Sql_GetData(sql_handle, 1, &data, NULL); partnerid = atoi(data); + Sql_GetData(sql_handle, 2, &data, NULL); childid = atoi(data); + + if( (cid1 == charid && ((cid2 == partnerid && cid3 == childid ) || (cid2 == childid && cid3 == partnerid))) || + (cid1 == partnerid && ((cid2 == charid && cid3 == childid ) || (cid2 == childid && cid3 == charid ))) || + (cid1 == childid && ((cid2 == charid && cid3 == partnerid) || (cid2 == partnerid && cid3 == charid ))) ) + { + Sql_FreeResult(sql_handle); + return childid; + } } - if (idx1 == -1 || idx2 == -1/* || idx3 == -1*/) - return 0; //Some character not found?? - - //Unless the dbs are corrupted, these 3 checks should suffice, even though - //we could do a lot more checks and force cross-reference integrity. - if(char_dat[idx1].status.partner_id == cid2 && - char_dat[idx1].status.child == cid3) - return cid3; //cid1/cid2 parents. cid3 child. - - if(char_dat[idx1].status.partner_id == cid3 && - char_dat[idx1].status.child == cid2) - return cid2; //cid1/cid3 parents. cid2 child. - - if(char_dat[idx2].status.partner_id == cid3 && - char_dat[idx2].status.child == cid1) - return cid1; //cid2/cid3 parents. cid1 child. + Sql_FreeResult(sql_handle); return 0; } @@ -1984,45 +1773,6 @@ void disconnect_player(int account_id) set_eof(i); } -// キャラ削除に伴うデータ削除 -static int char_delete(struct mmo_charstatus *cs) -{ - int j; - - // ペット削除 - if (cs->pet_id) - inter_pet_delete(cs->pet_id); - if (cs->hom_id) - inter_homun_delete(cs->hom_id); - for (j = 0; j < MAX_INVENTORY; j++) - if (cs->inventory[j].card[0] == (short)0xff00) - inter_pet_delete(MakeDWord(cs->inventory[j].card[1],cs->inventory[j].card[2])); - for (j = 0; j < MAX_CART; j++) - if (cs->cart[j].card[0] == (short)0xff00) - inter_pet_delete( MakeDWord(cs->cart[j].card[1],cs->cart[j].card[2]) ); - // ギルド脱退 - if (cs->guild_id) - inter_guild_leave(cs->guild_id, cs->account_id, cs->char_id); - // パーティー脱退 - if (cs->party_id) - inter_party_leave(cs->party_id, cs->account_id, cs->char_id); - // 離婚 - if (cs->partner_id){ - // 離婚情報をmapに通知 - unsigned char buf[10]; - WBUFW(buf,0) = 0x2b12; - WBUFL(buf,2) = cs->char_id; - WBUFL(buf,6) = cs->partner_id; - mapif_sendall(buf,10); - // 離婚 - char_divorce(cs); - } -#ifdef ENABLE_SC_SAVING - status_delete_scdata(cs->account_id, cs->char_id); -#endif - return 0; -} - static void char_auth_ok(int fd, struct char_session_data *sd) { struct online_char_data* character; @@ -2085,6 +1835,7 @@ void loginif_reset(void) /// 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 loginif_check_shutdown(void) { @@ -2107,7 +1858,7 @@ void loginif_on_ready(void) int i; loginif_check_shutdown(); - + //Send online accounts to login server. send_accounts_tologin(INVALID_TIMER, gettick(), 0, 0); @@ -2122,7 +1873,7 @@ int parse_fromlogin(int fd) { struct char_session_data* sd = NULL; int i; - + // only process data from the login-server if( fd != login_fd ) { @@ -2157,7 +1908,7 @@ int parse_fromlogin(int fd) //printf("connect login server error : %d\n", RFIFOB(fd,2)); ShowError("Can not connect to login-server.\n"); ShowError("The server communication passwords (default s1/p1) are probably invalid.\n"); - ShowError("Also, please make sure your accounts file (default: accounts.txt) has the correct communication username/passwords and the gender of the account is S.\n"); + ShowError("Also, please make sure your login db has the correct communication username/passwords and the gender of the account is S.\n"); ShowError("The communication passwords are set in map_athena.conf and char_athena.conf\n"); set_eof(fd); return 0; @@ -2213,22 +1964,21 @@ int parse_fromlogin(int fd) ARR_FIND( 0, fd_max, i, session[i] && (sd = (struct char_session_data*)session[i]->session_data) && sd->auth && sd->account_id == RFIFOL(fd,2) ); if( i < fd_max ) { + int server_id; memcpy(sd->email, RFIFOP(fd,6), 40); sd->expiration_time = (time_t)RFIFOL(fd,46); sd->gmlevel = RFIFOB(fd,50); safestrncpy(sd->birthdate, (const char*)RFIFOP(fd,51), sizeof(sd->birthdate)); - + ARR_FIND( 0, ARRAYLENGTH(server), server_id, server[server_id].fd > 0 && server[server_id].map[0] ); // continued from char_auth_ok... - if( max_connect_user && count_users() >= max_connect_user && sd->gmlevel < gm_allow_level ) - { + if( server_id == ARRAYLENGTH(server) || //server not online, bugreport:2359 + ( max_connect_user && count_users() >= max_connect_user && sd->gmlevel < gm_allow_level ) ) { // refuse connection (over populated) WFIFOHEAD(i,3); WFIFOW(i,0) = 0x6c; WFIFOW(i,2) = 0; WFIFOSET(i,3); - } - else - { + } else { // send characters to player mmo_char_send006b(i, sd); #if PACKETVER >= 20110309 @@ -2258,7 +2008,6 @@ int parse_fromlogin(int fd) if (RFIFOREST(fd) < 7) return 0; { - int j; unsigned char buf[7]; int acc = RFIFOL(fd,2); @@ -2267,57 +2016,65 @@ int parse_fromlogin(int fd) if( acc > 0 ) {// TODO: Is this even possible? + int char_id[MAX_CHARS]; + int class_[MAX_CHARS]; + int guild_id[MAX_CHARS]; + int num; + char* data; + struct auth_node* node = (struct auth_node*)idb_get(auth_db, acc); if( node != NULL ) node->sex = sex; - ARR_FIND( 0, char_num, i, char_dat[i].status.account_id == acc ); - if( i < char_num ) + // get characters + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`,`class`,`guild_id` FROM `%s` WHERE `account_id` = '%d'", char_db, acc) ) + Sql_ShowDebug(sql_handle); + for( i = 0; i < MAX_CHARS && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i ) + { + Sql_GetData(sql_handle, 0, &data, NULL); char_id[i] = atoi(data); + Sql_GetData(sql_handle, 1, &data, NULL); class_[i] = atoi(data); + Sql_GetData(sql_handle, 2, &data, NULL); guild_id[i] = atoi(data); + } + num = i; + for( i = 0; i < num; ++i ) { - int jobclass = char_dat[i].status.class_; - char_dat[i].status.sex = sex; - if (jobclass == JOB_BARD || jobclass == JOB_DANCER || - jobclass == JOB_CLOWN || jobclass == JOB_GYPSY || - jobclass == JOB_BABY_BARD || jobclass == JOB_BABY_DANCER) { + if( class_[i] == JOB_BARD || class_[i] == JOB_DANCER || + class_[i] == JOB_CLOWN || class_[i] == JOB_GYPSY || + class_[i] == JOB_BABY_BARD || class_[i] == JOB_BABY_DANCER || + class_[i] == JOB_WANDERER || class_[i] == JOB_WANDERER_T || + class_[i] == JOB_MINSTREL || class_[i] == JOB_MINSTREL_T ) + { // job modification - if (jobclass == JOB_BARD || jobclass == JOB_DANCER) { - char_dat[i].status.class_ = (sex) ? JOB_BARD : JOB_DANCER; - } else if (jobclass == JOB_CLOWN || jobclass == JOB_GYPSY) { - char_dat[i].status.class_ = (sex) ? JOB_CLOWN : JOB_GYPSY; - } else if (jobclass == JOB_BABY_BARD || jobclass == JOB_BABY_DANCER) { - char_dat[i].status.class_ = (sex) ? JOB_BABY_BARD : JOB_BABY_DANCER; - } - // remove specifical skills of classes 19, 4020 and 4042 - for(j = 315; j <= 322; j++) { - if (char_dat[i].status.skill[j].id > 0 && char_dat[i].status.skill[j].flag == SKILL_FLAG_PERMANENT) { - char_dat[i].status.skill_point += char_dat[i].status.skill[j].lv; - char_dat[i].status.skill[j].id = 0; - char_dat[i].status.skill[j].lv = 0; - } - } - // remove specifical skills of classes 20, 4021 and 4043 - for(j = 323; j <= 330; j++) { - if (char_dat[i].status.skill[j].id > 0 && char_dat[i].status.skill[j].flag == SKILL_FLAG_PERMANENT) { - char_dat[i].status.skill_point += char_dat[i].status.skill[j].lv; - char_dat[i].status.skill[j].id = 0; - char_dat[i].status.skill[j].lv = 0; - } - } + if( class_[i] == JOB_BARD || class_[i] == JOB_DANCER ) + class_[i] = (sex ? JOB_BARD : JOB_DANCER); + else if( class_[i] == JOB_CLOWN || class_[i] == JOB_GYPSY ) + class_[i] = (sex ? JOB_CLOWN : JOB_GYPSY); + else if( class_[i] == JOB_BABY_BARD || class_[i] == JOB_BABY_DANCER ) + class_[i] = (sex ? JOB_BABY_BARD : JOB_BABY_DANCER); + else if( class_[i] == JOB_MINSTREL || class_[i] == JOB_WANDERER ) + class_[i] = (sex ? JOB_MINSTREL : JOB_WANDERER); + else if( class_[i] == JOB_MINSTREL_T || class_[i] == JOB_WANDERER_T ) + class_[i] = (sex ? JOB_MINSTREL_T : JOB_WANDERER_T); + // remove specifical skills of classes 19,20 4020,4021 and 4042,4043 + if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `skill_point` = `skill_point` +" + " (SELECT SUM(lv) FROM `%s` WHERE `char_id` = '%d' AND `id` >= '315' AND `id` <= '330' AND `lv` > '0')" + " WHERE `char_id` = '%d'", + char_db, skill_db, char_id[i], char_id[i]) ) + Sql_ShowDebug(sql_handle); + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id` = '%d' AND `id` >= '315' AND `id` <= '330'", skill_db, char_id[i]) ) + Sql_ShowDebug(sql_handle); } // to avoid any problem with equipment and invalid sex, equipment is unequiped. - for (j = 0; j < MAX_INVENTORY; j++) { - if (char_dat[i].status.inventory[j].nameid && char_dat[i].status.inventory[j].equip) - char_dat[i].status.inventory[j].equip = 0; - } - char_dat[i].status.weapon = 0; - char_dat[i].status.shield = 0; - char_dat[i].status.head_top = 0; - char_dat[i].status.head_mid = 0; - char_dat[i].status.head_bottom = 0; - - if (char_dat[i].status.guild_id) //If there is a guild, update the guild_member data [Skotlex] - inter_guild_sex_changed(char_dat[i].status.guild_id, acc, char_dat[i].status.char_id, sex); + if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `equip` = '0' WHERE `char_id` = '%d'", inventory_db, char_id[i]) ) + Sql_ShowDebug(sql_handle); + if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `class`='%d', `weapon`='0', `shield`='0', `head_top`='0', `head_mid`='0', `head_bottom`='0' WHERE `char_id`='%d'", char_db, class_[i], char_id[i]) ) + Sql_ShowDebug(sql_handle); + + if( guild_id[i] )// If there is a guild, update the guild_member data [Skotlex] + inter_guild_sex_changed(guild_id[i], acc, char_id[i], sex); } + Sql_FreeResult(sql_handle); + // disconnect player if online on char-server disconnect_player(acc); } @@ -2495,124 +2252,62 @@ int save_accreg2(unsigned char* buf, int len) return 0; } -//Receive Registry information for a character. -int char_parse_Registry(int account_id, int char_id, unsigned char *buf, int buf_len) -{ - int i,j,p,len; - for (i = 0; i < char_num; i++) { - if (char_dat[i].status.account_id == account_id && char_dat[i].status.char_id == char_id) - break; - } - if(i >= char_num) //Character not found? - return 1; - for(j=0,p=0;j= char_num){ //Character not found? Sent empty packet. - WFIFOW(fd,2)=13; - }else{ - for (p=13,j = 0; j < char_dat[i].global_num; j++) { - if (char_dat[i].global[j].str[0]) { - p+= sprintf((char*)WFIFOP(fd,p), "%s", char_dat[i].global[j].str)+1; //We add 1 to consider the '\0' in place. - p+= sprintf((char*)WFIFOP(fd,p), "%s", char_dat[i].global[j].value)+1; - } - } - WFIFOW(fd,2)=p; - } - WFIFOSET(fd,WFIFOW(fd,2)); - return 0; -} - void char_read_fame_list(void) { - int i, j, k; - struct fame_list fame_item; - CREATE_BUFFER(id, int, char_num); - - for(i = 0; i < char_num; i++) { - id[i] = i; - for(j = 0; j < i; j++) { - if (char_dat[i].status.fame > char_dat[id[j]].status.fame) { - for(k = i; k > j; k--) - id[k] = id[k-1]; - id[j] = i; // id[i] - break; - } - } - } + int i; + char* data; + size_t len; // Empty ranking lists 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)); // Build Blacksmith ranking list - for (i = 0, j = 0; i < char_num && j < fame_list_size_smith; i++) { - if (char_dat[id[i]].status.fame && ( - char_dat[id[i]].status.class_ == JOB_BLACKSMITH || - char_dat[id[i]].status.class_ == JOB_WHITESMITH || - char_dat[id[i]].status.class_ == JOB_BABY_BLACKSMITH)) - { - fame_item.id = char_dat[id[i]].status.char_id; - fame_item.fame = char_dat[id[i]].status.fame; - safestrncpy(fame_item.name, char_dat[id[i]].status.name, NAME_LENGTH); - - memcpy(&smith_fame_list[j],&fame_item,sizeof(struct fame_list)); - j++; - } + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`,`fame`,`name` FROM `%s` WHERE `fame`>0 AND (`class`='%d' OR `class`='%d' OR `class`='%d') ORDER BY `fame` DESC LIMIT 0,%d", char_db, JOB_BLACKSMITH, JOB_WHITESMITH, JOB_BABY_BLACKSMITH, fame_list_size_smith) ) + Sql_ShowDebug(sql_handle); + for( i = 0; i < fame_list_size_smith && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i ) + { + // char_id + Sql_GetData(sql_handle, 0, &data, NULL); + smith_fame_list[i].id = atoi(data); + // fame + Sql_GetData(sql_handle, 1, &data, &len); + smith_fame_list[i].fame = atoi(data); + // name + Sql_GetData(sql_handle, 2, &data, &len); + memcpy(smith_fame_list[i].name, data, min(len, NAME_LENGTH)); } // Build Alchemist ranking list - for (i = 0, j = 0; i < char_num && j < fame_list_size_chemist; i++) { - if (char_dat[id[i]].status.fame && ( - char_dat[id[i]].status.class_ == JOB_ALCHEMIST || - char_dat[id[i]].status.class_ == JOB_CREATOR || - char_dat[id[i]].status.class_ == JOB_BABY_ALCHEMIST)) - { - fame_item.id = char_dat[id[i]].status.char_id; - fame_item.fame = char_dat[id[i]].status.fame; - safestrncpy(fame_item.name, char_dat[id[i]].status.name, NAME_LENGTH); - - memcpy(&chemist_fame_list[j],&fame_item,sizeof(struct fame_list)); - - j++; - } + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`,`fame`,`name` FROM `%s` WHERE `fame`>0 AND (`class`='%d' OR `class`='%d' OR `class`='%d') ORDER BY `fame` DESC LIMIT 0,%d", char_db, JOB_ALCHEMIST, JOB_CREATOR, JOB_BABY_ALCHEMIST, fame_list_size_chemist) ) + Sql_ShowDebug(sql_handle); + for( i = 0; i < fame_list_size_chemist && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i ) + { + // char_id + Sql_GetData(sql_handle, 0, &data, NULL); + chemist_fame_list[i].id = atoi(data); + // fame + Sql_GetData(sql_handle, 1, &data, &len); + chemist_fame_list[i].fame = atoi(data); + // name + Sql_GetData(sql_handle, 2, &data, &len); + memcpy(chemist_fame_list[i].name, data, min(len, NAME_LENGTH)); } // Build Taekwon ranking list - for (i = 0, j = 0; i < char_num && j < fame_list_size_taekwon; i++) { - if (char_dat[id[i]].status.fame && - char_dat[id[i]].status.class_ == JOB_TAEKWON) - { - fame_item.id = char_dat[id[i]].status.char_id; - fame_item.fame = char_dat[id[i]].status.fame; - safestrncpy(fame_item.name, char_dat[id[i]].status.name, NAME_LENGTH); - - memcpy(&taekwon_fame_list[j],&fame_item,sizeof(struct fame_list)); - - j++; - } + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`,`fame`,`name` FROM `%s` WHERE `fame`>0 AND (`class`='%d') ORDER BY `fame` DESC LIMIT 0,%d", char_db, JOB_TAEKWON, fame_list_size_taekwon) ) + Sql_ShowDebug(sql_handle); + for( i = 0; i < fame_list_size_taekwon && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i ) + { + // char_id + Sql_GetData(sql_handle, 0, &data, NULL); + taekwon_fame_list[i].id = atoi(data); + // fame + Sql_GetData(sql_handle, 1, &data, &len); + taekwon_fame_list[i].fame = atoi(data); + // name + Sql_GetData(sql_handle, 2, &data, &len); + memcpy(taekwon_fame_list[i].name, data, min(len, NAME_LENGTH)); } - DELETE_BUFFER(id); + Sql_FreeResult(sql_handle); } // Send map-servers the fame ranking lists @@ -2666,12 +2361,15 @@ void char_update_fame_list(int type, int index, int fame) //Returns 1 on found, 0 on not found (buffer is filled with Unknown char name) int char_loadName(int char_id, char* name) { - int j; + char* data; + size_t len; - ARR_FIND( 0, char_num, j, char_dat[j].status.char_id == char_id ); - if( j < char_num ) + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `name` FROM `%s` WHERE `char_id`='%d'", char_db, char_id) ) + Sql_ShowDebug(sql_handle); + else if( SQL_SUCCESS == Sql_NextRow(sql_handle) ) { - safestrncpy(name, char_dat[j].status.name, NAME_LENGTH); + Sql_GetData(sql_handle, 0, &data, &len); + safestrncpy(name, data, NAME_LENGTH); return 1; } else @@ -2721,8 +2419,9 @@ void mapif_server_reset(int id) WBUFW(buf,2) = j * 4 + 10; mapif_sendallwos(fd, buf, WBUFW(buf,2)); } + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `ragsrvinfo` WHERE `index`='%d'", server[id].fd) ) + Sql_ShowDebug(sql_handle); online_char_db->foreach(online_char_db,char_db_setoffline,id); //Tag relevant chars as 'in disconnected' server. - create_online_files(); mapif_server_destroy(id); mapif_server_init(id); } @@ -2775,9 +2474,7 @@ int parse_frommap(int fd) ShowStatus("Map-Server %d connected: %d maps, from IP %d.%d.%d.%d port %d.\n", id, j, CONVIP(server[id].ip), server[id].port); ShowStatus("Map-server %d loading complete.\n", id); - char_log("Map-Server %d connected: %d maps, from IP %d.%d.%d.%d port %d. Map-server %d loading complete.\n", - id, j, CONVIP(server[id].ip), server[id].port, id); - + // send name for wisp to player WFIFOHEAD(fd, 3 + NAME_LENGTH); WFIFOW(fd,0) = 0x2afb; @@ -2792,7 +2489,6 @@ int parse_frommap(int fd) int x; if (j == 0) { ShowWarning("Map-server %d has NO maps.\n", id); - char_log("WARNING: Map-server %d has NO maps.\n", id); } else { // Transmitting maps information to the other map-servers WBUFW(buf,0) = 0x2b04; @@ -2829,23 +2525,48 @@ int parse_frommap(int fd) { #ifdef ENABLE_SC_SAVING int aid, cid; - struct scdata *data; aid = RFIFOL(fd,2); cid = RFIFOL(fd,6); - data = status_search_scdata(aid, cid); - if (data->count > 0) - { //Deliver status change data. - WFIFOHEAD(fd,14 + data->count*sizeof(struct status_change_data)); + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT type, tick, val1, val2, val3, val4 from `%s` WHERE `account_id` = '%d' AND `char_id`='%d'", + scdata_db, aid, cid) ) + { + Sql_ShowDebug(sql_handle); + break; + } + if( Sql_NumRows(sql_handle) > 0 ) + { + struct status_change_data scdata; + int count; + char* data; + + WFIFOHEAD(fd,14+50*sizeof(struct status_change_data)); WFIFOW(fd,0) = 0x2b1d; - WFIFOW(fd,2) = 14 + data->count*sizeof(struct status_change_data); WFIFOL(fd,4) = aid; WFIFOL(fd,8) = cid; - WFIFOW(fd,12) = data->count; - for (i = 0; i < data->count; i++) - memcpy(WFIFOP(fd,14+i*sizeof(struct status_change_data)), &data->data[i], sizeof(struct status_change_data)); - WFIFOSET(fd, WFIFOW(fd,2)); - status_delete_scdata(aid, cid); //Data sent, so it needs be discarded now. + for( count = 0; count < 50 && SQL_SUCCESS == Sql_NextRow(sql_handle); ++count ) + { + Sql_GetData(sql_handle, 0, &data, NULL); scdata.type = atoi(data); + Sql_GetData(sql_handle, 1, &data, NULL); scdata.tick = atoi(data); + Sql_GetData(sql_handle, 2, &data, NULL); scdata.val1 = atoi(data); + Sql_GetData(sql_handle, 3, &data, NULL); scdata.val2 = atoi(data); + Sql_GetData(sql_handle, 4, &data, NULL); scdata.val3 = atoi(data); + Sql_GetData(sql_handle, 5, &data, NULL); scdata.val4 = atoi(data); + memcpy(WFIFOP(fd, 14+count*sizeof(struct status_change_data)), &scdata, sizeof(struct status_change_data)); + } + if (count >= 50) + ShowWarning("Too many status changes for %d:%d, some of them were not loaded.\n", aid, cid); + if (count > 0) + { + WFIFOW(fd,2) = 14 + count*sizeof(struct status_change_data); + WFIFOW(fd,12) = count; + WFIFOSET(fd,WFIFOW(fd,2)); + + //Clear the data once loaded. + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `account_id` = '%d' AND `char_id`='%d'", scdata_db, aid, cid) ) + Sql_ShowDebug(sql_handle); + } } + Sql_FreeResult(sql_handle); #endif RFIFOSKIP(fd, 10); } @@ -2894,7 +2615,7 @@ int parse_frommap(int fd) return 0; { int aid = RFIFOL(fd,4), cid = RFIFOL(fd,8), size = RFIFOW(fd,2); - struct mmo_charstatus* cs; + struct online_char_data* character; if (size - 13 != sizeof(struct mmo_charstatus)) { @@ -2902,10 +2623,17 @@ int parse_frommap(int fd) RFIFOSKIP(fd,size); break; } - if( ( cs = search_character(aid, cid) ) != NULL ) + //Check account only if this ain't final save. Final-save goes through because of the char-map reconnect + if (RFIFOB(fd,12) || ( + (character = (struct online_char_data*)idb_get(online_char_db, aid)) != NULL && + character->char_id == cid)) { - memcpy(cs, RFIFOP(fd,13), sizeof(struct mmo_charstatus)); - storage_save(cs->account_id, &cs->storage); + struct mmo_charstatus char_dat; + memcpy(&char_dat, RFIFOP(fd,13), sizeof(struct mmo_charstatus)); + mmo_char_tosql(cid, &char_dat); + } else { //This may be valid on char-server reconnection, when re-sending characters that already logged off. + ShowError("parse_from_map (save-char): Received data for non-existant/offline character (%d:%d).\n", aid, cid); + set_char_online(id, cid, aid); } if (RFIFOB(fd,12)) @@ -2932,7 +2660,7 @@ int parse_frommap(int fd) uint32 login_id2 = RFIFOL(fd,10); uint32 ip = RFIFOL(fd,14); RFIFOSKIP(fd,18); - + if( runflag != CHARSERVER_ST_RUNNING ) { WFIFOHEAD(fd,7); @@ -2968,19 +2696,25 @@ int parse_frommap(int fd) break; case 0x2b05: // request "change map server" - if (RFIFOREST(fd) < 35) + if (RFIFOREST(fd) < 39) return 0; { int map_id, map_fd = -1; struct online_char_data* data; struct mmo_charstatus* char_data; + struct mmo_charstatus char_dat; map_id = search_mapserver(RFIFOW(fd,18), ntohl(RFIFOL(fd,24)), ntohs(RFIFOW(fd,28))); //Locate mapserver by ip and port. if (map_id >= 0) map_fd = server[map_id].fd; - - char_data = search_character(RFIFOL(fd,2), RFIFOL(fd,14)); - + //Char should just had been saved before this packet, so this should be safe. [Skotlex] + char_data = (struct mmo_charstatus*)uidb_get(char_db_,RFIFOL(fd,14)); + if (char_data == NULL) + { //Really shouldn't happen. + mmo_char_fromsql(RFIFOL(fd,14), &char_dat, true); + char_data = (struct mmo_charstatus*)uidb_get(char_db_,RFIFOL(fd,14)); + } + if( runflag == CHARSERVER_ST_RUNNING && session_isActive(map_fd) && char_data ) @@ -3000,8 +2734,10 @@ int parse_frommap(int fd) node->login_id1 = RFIFOL(fd,6); node->login_id2 = RFIFOL(fd,10); node->sex = RFIFOB(fd,30); - node->expiration_time = 0; // FIXME + node->expiration_time = 0; // FIXME (this thing isn't really supported we could as well purge it instead of fixing) node->ip = ntohl(RFIFOL(fd,31)); + node->gmlevel = RFIFOL(fd,35); + node->changing_mapservers = 1; idb_put(auth_db, RFIFOL(fd,2), node); data = (struct online_char_data*)idb_ensure(online_char_db, RFIFOL(fd,2), create_online_char_data); @@ -3024,6 +2760,22 @@ int parse_frommap(int fd) } break; + case 0x2b07: // Remove RFIFOL(fd,6) (friend_id) from RFIFOL(fd,2) (char_id) friend list [Ind] + if (RFIFOREST(fd) < 10) + return 0; + { + int char_id, friend_id; + char_id = RFIFOL(fd,2); + friend_id = RFIFOL(fd,6); + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d' AND `friend_id`='%d' LIMIT 1", + friend_db, char_id, friend_id) ) { + Sql_ShowDebug(sql_handle); + break; + } + RFIFOSKIP(fd,10); + } + break; + case 0x2b08: // char name request if (RFIFOREST(fd) < 6) return 0; @@ -3054,7 +2806,7 @@ int parse_frommap(int fd) return 0; { int result = 0; // 0-login-server request done, 1-player not found, 2-gm level too low, 3-login-server offline - char character_name[NAME_LENGTH]; + char esc_name[NAME_LENGTH*2+1]; int acc = RFIFOL(fd,2); // account_id of who ask (-1 if server itself made this request) const char* name = (char*)RFIFOP(fd,6); // name of the target character @@ -3067,19 +2819,26 @@ int parse_frommap(int fd) short second = RFIFOW(fd,42); RFIFOSKIP(fd,44); - safestrncpy(character_name, name, NAME_LENGTH); - i = search_character_index(character_name); - if( i < 0 ) + Sql_EscapeStringLen(sql_handle, esc_name, name, strnlen(name, NAME_LENGTH)); + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id`,`name` FROM `%s` WHERE `name` = '%s'", char_db, esc_name) ) + Sql_ShowDebug(sql_handle); + else + if( Sql_NumRows(sql_handle) == 0 ) { result = 1; // 1-player not found } else + if( SQL_SUCCESS != Sql_NextRow(sql_handle) ) + Sql_ShowDebug(sql_handle); + //FIXME: set proper result value? + else { char name[NAME_LENGTH]; int account_id; + char* data; - account_id = char_dat[i].status.account_id; - safestrncpy(name, char_dat[i].status.name, NAME_LENGTH); + Sql_GetData(sql_handle, 0, &data, NULL); account_id = atoi(data); + Sql_GetData(sql_handle, 1, &data, NULL); safestrncpy(name, data, sizeof(name)); if( login_fd <= 0 ) result = 3; // 3-login-server offline @@ -3130,6 +2889,8 @@ int parse_frommap(int fd) } } + Sql_FreeResult(sql_handle); + // send answer if a player ask, not if the server ask if( acc != -1 && type != 5) { // Don't send answer for changesex WFIFOHEAD(fd,34); @@ -3196,11 +2957,28 @@ int parse_frommap(int fd) } break; + // Divorce chars + case 0x2b11: + if( RFIFOREST(fd) < 10 ) + return 0; + + divorce_char_sql(RFIFOL(fd,2), RFIFOL(fd,6)); + RFIFOSKIP(fd,10); + break; + case 0x2b16: // Receive rates [Wizputer] if( RFIFOREST(fd) < 14 ) return 0; - // Txt doesn't need this packet, so just skip it + { + char esc_server_name[sizeof(server_name)*2+1]; + + Sql_EscapeString(sql_handle, esc_server_name, server_name); + + if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `ragsrvinfo` SET `index`='%d',`name`='%s',`exp`='%d',`jexp`='%d',`drop`='%d'", + fd, esc_server_name, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10)) ) + Sql_ShowDebug(sql_handle); RFIFOSKIP(fd,14); + } break; case 0x2b17: // Character disconnected set online 0 [Wizputer] @@ -3236,20 +3014,31 @@ int parse_frommap(int fd) { #ifdef ENABLE_SC_SAVING int count, aid, cid; - struct scdata *data; aid = RFIFOL(fd, 4); cid = RFIFOL(fd, 8); count = RFIFOW(fd, 12); - data = status_search_scdata(aid, cid); - if (data->count != count) + if( count > 0 ) { - data->count = count; - data->data = (struct status_change_data*)aRealloc(data->data, count*sizeof(struct status_change_data)); + struct status_change_data data; + StringBuf buf; + int i; + + StringBuf_Init(&buf); + StringBuf_Printf(&buf, "INSERT INTO `%s` (`account_id`, `char_id`, `type`, `tick`, `val1`, `val2`, `val3`, `val4`) VALUES ", scdata_db); + for( i = 0; i < count; ++i ) + { + memcpy (&data, RFIFOP(fd, 14+i*sizeof(struct status_change_data)), sizeof(struct status_change_data)); + if( i > 0 ) + StringBuf_AppendStr(&buf, ", "); + StringBuf_Printf(&buf, "('%d','%d','%hu','%d','%d','%d','%d','%d')", aid, cid, + data.type, data.tick, data.val1, data.val2, data.val3, data.val4); + } + if( SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf)) ) + Sql_ShowDebug(sql_handle); + StringBuf_Destroy(&buf); } - for (i = 0; i < count; i++) - memcpy (&data->data[i], RFIFOP(fd, 14+i*sizeof(struct status_change_data)), sizeof(struct status_change_data)); #endif RFIFOSKIP(fd, RFIFOW(fd, 2)); } @@ -3274,6 +3063,7 @@ int parse_frommap(int fd) uint32 ip; struct auth_node* node; struct mmo_charstatus* cd; + struct mmo_charstatus char_dat; account_id = RFIFOL(fd,2); char_id = RFIFOL(fd,6); @@ -3283,10 +3073,15 @@ int parse_frommap(int fd) RFIFOSKIP(fd,19); node = (struct auth_node*)idb_get(auth_db, account_id); - cd = search_character(account_id, char_id); + cd = (struct mmo_charstatus*)uidb_get(char_db_,char_id); + if( cd == NULL ) + { //Really shouldn't happen. + mmo_char_fromsql(char_id, &char_dat, true); + cd = (struct mmo_charstatus*)uidb_get(char_db_,char_id); + } if( runflag == CHARSERVER_ST_RUNNING && cd != NULL && - node != NULL && + node != NULL && node->account_id == account_id && node->char_id == char_id && node->login_id1 == login_id1 && @@ -3295,16 +3090,16 @@ int parse_frommap(int fd) {// auth ok cd->sex = sex; - WFIFOHEAD(fd,24 + sizeof(struct mmo_charstatus)); + WFIFOHEAD(fd,25 + sizeof(struct mmo_charstatus)); WFIFOW(fd,0) = 0x2afd; - WFIFOW(fd,2) = 24 + sizeof(struct mmo_charstatus); + WFIFOW(fd,2) = 25 + sizeof(struct mmo_charstatus); WFIFOL(fd,4) = account_id; WFIFOL(fd,8) = node->login_id1; WFIFOL(fd,12) = node->login_id2; WFIFOL(fd,16) = (uint32)node->expiration_time; // FIXME: will wrap to negative after "19-Jan-2038, 03:14:07 AM GMT" WFIFOL(fd,20) = node->gmlevel; - storage_load(cd->account_id, &cd->storage); //FIXME: storage is used as a temp buffer here - memcpy(WFIFOP(fd,24), cd, sizeof(struct mmo_charstatus)); + WFIFOB(fd,24) = node->changing_mapservers; + memcpy(WFIFOP(fd,25), cd, sizeof(struct mmo_charstatus)); WFIFOSET(fd, WFIFOW(fd,2)); // only use the auth once and mark user online @@ -3460,18 +3255,31 @@ void char_delete2_cancel_ack(int fd, int char_id, uint32 result) static void char_delete2_req(int fd, struct char_session_data* sd) {// CH: <0827>.W .L - int char_id; - struct mmo_charstatus* cs; + int char_id, i, guild_id, party_id; + char* data; + time_t delete_date; char_id = RFIFOL(fd,2); - if( ( cs = search_session_character(sd, char_id) ) == NULL ) + ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == char_id ); + if( i == MAX_CHARS ) {// character not found char_delete2_ack(fd, char_id, 3, 0); return; } - if( cs->delete_date ) + if( SQL_SUCCESS != Sql_Query(sql_handle, "SELECT `guild_id`,`party_id`,`delete_date` FROM `%s` WHERE `char_id`='%d'", char_db, char_id) || SQL_SUCCESS != Sql_NextRow(sql_handle) ) + { + Sql_ShowDebug(sql_handle); + char_delete2_ack(fd, char_id, 3, 0); + return; + } + + Sql_GetData(sql_handle, 0, &data, NULL); guild_id = atoi(data); + Sql_GetData(sql_handle, 1, &data, NULL); party_id = atoi(data); + Sql_GetData(sql_handle, 2, &data, NULL); delete_date = strtoul(data, NULL, 10); + + if( delete_date ) {// character already queued for deletion char_delete2_ack(fd, char_id, 0, 0); return; @@ -3481,13 +3289,13 @@ static void char_delete2_req(int fd, struct char_session_data* sd) // Aegis imposes these checks probably to avoid dead member // entries in guilds/parties, otherwise they are not required. // TODO: Figure out how these are enforced during waiting. - if( cs->guild_id ) + if( guild_id ) {// character in guild char_delete2_ack(fd, char_id, 4, 0); return; } - if( cs->party_id ) + if( party_id ) {// character in party char_delete2_ack(fd, char_id, 5, 0); return; @@ -3495,17 +3303,26 @@ static void char_delete2_req(int fd, struct char_session_data* sd) */ // success - cs->delete_date = time(NULL)+char_del_delay; + delete_date = time(NULL)+char_del_delay; + + if( SQL_SUCCESS != Sql_Query(sql_handle, "UPDATE `%s` SET `delete_date`='%lu' WHERE `char_id`='%d'", char_db, (unsigned long)delete_date, char_id) ) + { + Sql_ShowDebug(sql_handle); + char_delete2_ack(fd, char_id, 3, 0); + return; + } - char_delete2_ack(fd, char_id, 1, cs->delete_date); + char_delete2_ack(fd, char_id, 1, delete_date); } static void char_delete2_accept(int fd, struct char_session_data* sd) {// CH: <0829>.W .L .6B char birthdate[8+1]; - int char_id, i; - struct mmo_charstatus* cs; + int char_id, i, k; + unsigned int base_level; + char* data; + time_t delete_date; char_id = RFIFOL(fd,2); @@ -3522,15 +3339,24 @@ static void char_delete2_accept(int fd, struct char_session_data* sd) birthdate[7] = RFIFOB(fd,11); birthdate[8] = 0; - ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] != -1 && char_dat[sd->found_char[i]].status.char_id == char_id ); + ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == char_id ); if( i == MAX_CHARS ) {// character not found char_delete2_accept_ack(fd, char_id, 3); return; } - cs = &char_dat[sd->found_char[i]].status; - if( !cs->delete_date || cs->delete_date>time(NULL) ) + if( SQL_SUCCESS != Sql_Query(sql_handle, "SELECT `base_level`,`delete_date` FROM `%s` WHERE `char_id`='%d'", char_db, char_id) || SQL_SUCCESS != Sql_NextRow(sql_handle) ) + {// data error + Sql_ShowDebug(sql_handle); + char_delete2_accept_ack(fd, char_id, 3); + return; + } + + Sql_GetData(sql_handle, 0, &data, NULL); base_level = (unsigned int)strtoul(data, NULL, 10); + Sql_GetData(sql_handle, 1, &data, NULL); delete_date = strtoul(data, NULL, 10); + + if( !delete_date || delete_date>time(NULL) ) {// not queued or delay not yet passed char_delete2_accept_ack(fd, char_id, 4); return; @@ -3542,49 +3368,25 @@ static void char_delete2_accept(int fd, struct char_session_data* sd) return; } - if( ( char_del_level > 0 && cs->base_level >= (unsigned int)char_del_level ) || ( char_del_level < 0 && cs->base_level <= (unsigned int)(-char_del_level) ) ) + if( ( char_del_level > 0 && base_level >= (unsigned int)char_del_level ) || ( char_del_level < 0 && base_level <= (unsigned int)(-char_del_level) ) ) {// character level config restriction char_delete2_accept_ack(fd, char_id, 2); return; } // success - char_delete(cs); - - // drop character entry - if( --char_num > 0 && sd->found_char[i] != char_num ) + if( delete_char_sql(char_id) < 0 ) { - int s, c; - - // move the last entry to the place of the deleted character - memcpy(&char_dat[sd->found_char[i]], &char_dat[char_num], sizeof(struct mmo_charstatus)); - - // scan currently online accounts, if the moved character - // entry requires an update of the cached character list - for( s = 0; s < fd_max; s++ ) - { - struct char_session_data* osd; - - if( session[s] && ( osd = (struct char_session_data*)session[s]->session_data ) != NULL && osd->account_id == char_dat[char_num].status.account_id ) - { - for( c = 0; c < MAX_CHARS; c++ ) - { - if( osd->found_char[c] == char_num ) - { - osd->found_char[c] = sd->found_char[i]; - break; - } - } - break; - } - } - - // wipe the last entry - memset(&char_dat[char_num], 0, sizeof(struct mmo_charstatus)); + char_delete2_accept_ack(fd, char_id, 3); + return; } // refresh character list cache - char_find_characters(sd); + for(k = i; k < MAX_CHARS-1; k++) + { + sd->found_char[k] = sd->found_char[k+1]; + } + sd->found_char[MAX_CHARS-1] = -1; char_delete2_accept_ack(fd, char_id, 1); } @@ -3592,12 +3394,12 @@ static void char_delete2_accept(int fd, struct char_session_data* sd) static void char_delete2_cancel(int fd, struct char_session_data* sd) {// CH: <082b>.W .L - int char_id; - struct mmo_charstatus* cs; + int char_id, i; char_id = RFIFOL(fd,2); - if( ( cs = search_session_character(sd, char_id) ) == NULL ) + ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == char_id ); + if( i == MAX_CHARS ) {// character not found char_delete2_cancel_ack(fd, char_id, 2); return; @@ -3606,7 +3408,12 @@ static void char_delete2_cancel(int fd, struct char_session_data* sd) // there is no need to check, whether or not the character was // queued for deletion, as the client prints an error message by // itself, if it was not the case (@see char_delete2_cancel_ack) - cs->delete_date = 0; + if( SQL_SUCCESS != Sql_Query(sql_handle, "UPDATE `%s` SET `delete_date`='0' WHERE `char_id`='%d'", char_db, char_id) ) + { + Sql_ShowDebug(sql_handle); + char_delete2_cancel_ack(fd, char_id, 2); + return; + } char_delete2_cancel_ack(fd, char_id, 1); } @@ -3732,37 +3539,46 @@ int parse_char(int fd) case 0x66: FIFOSD_CHECK(3); { + struct mmo_charstatus char_dat; struct mmo_charstatus *cd; + char* data; + int char_id; uint32 subnet_map_ip; struct auth_node* node; int slot = RFIFOB(fd,2); RFIFOSKIP(fd,3); - // if we activated email creation and email is default email - if (email_creation != 0 && strcmp(sd->email, "a@a.com") == 0 && login_fd > 0) { // to modify an e-mail, login-server must be online - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x70; - WFIFOB(fd,2) = 0; // 00 = Incorrect Email address - WFIFOSET(fd,3); - break; - } - // otherwise, load the character - ARR_FIND( 0, MAX_CHARS, ch, sd->found_char[ch] >= 0 && char_dat[sd->found_char[ch]].status.slot == slot ); - if (ch == MAX_CHARS) + if ( SQL_SUCCESS != Sql_Query(sql_handle, "SELECT `char_id` FROM `%s` WHERE `account_id`='%d' AND `char_num`='%d'", char_db, sd->account_id, slot) + || SQL_SUCCESS != Sql_NextRow(sql_handle) + || SQL_SUCCESS != Sql_GetData(sql_handle, 0, &data, NULL) ) { //Not found?? May be forged packet. + Sql_ShowDebug(sql_handle); + Sql_FreeResult(sql_handle); WFIFOHEAD(fd,3); WFIFOW(fd,0) = 0x6c; WFIFOB(fd,2) = 0; // rejected from server WFIFOSET(fd,3); break; } - cd = &char_dat[sd->found_char[ch]].status; - char_log("Character Selected, Account ID: %d, Character Slot: %d, Character Name: %s.\n", sd->account_id, slot, cd->name); + char_id = atoi(data); + Sql_FreeResult(sql_handle); + mmo_char_fromsql(char_id, &char_dat, true); + + //Have to switch over to the DB instance otherwise data won't propagate [Kevin] + cd = (struct mmo_charstatus *)idb_get(char_db_, char_id); cd->sex = sd->sex; - ShowInfo("Selected char: (Account %d: %d - %s)\n", sd->account_id, slot, cd->name); + if (log_char) { + char esc_name[NAME_LENGTH*2+1]; + + Sql_EscapeStringLen(sql_handle, esc_name, char_dat.name, strnlen(char_dat.name, NAME_LENGTH)); + if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s`(`time`, `account_id`,`char_num`,`name`) VALUES (NOW(), '%d', '%d', '%s')", + charlog_db, sd->account_id, slot, esc_name) ) + Sql_ShowDebug(sql_handle); + } + ShowInfo("Selected char: (Account %d: %d - %s)\n", sd->account_id, slot, char_dat.name); // searching map server i = search_mapserver(cd->last_point.map, -1, -1); @@ -3846,6 +3662,9 @@ int parse_char(int fd) node->gmlevel = sd->gmlevel; node->ip = ipl; idb_put(auth_db, sd->account_id, node); + + set_char_online(-2,node->char_id,sd->account_id); + } break; @@ -3857,7 +3676,7 @@ int parse_char(int fd) if( !char_new ) //turn character creation on/off [Kevin] i = -2; else - i = make_new_char(sd, (char*)RFIFOP(fd,2),RFIFOB(fd,26),RFIFOB(fd,27),RFIFOB(fd,28),RFIFOB(fd,29),RFIFOB(fd,30),RFIFOB(fd,31),RFIFOB(fd,32),RFIFOW(fd,33),RFIFOW(fd,35)); + i = make_new_char_sql(sd, (char*)RFIFOP(fd,2),RFIFOB(fd,26),RFIFOB(fd,27),RFIFOB(fd,28),RFIFOB(fd,29),RFIFOB(fd,30),RFIFOB(fd,31),RFIFOB(fd,32),RFIFOW(fd,33),RFIFOW(fd,35)); //'Charname already exists' (-1), 'Char creation denied' (-2) and 'You are underaged' (-3) if (i < 0) @@ -3874,17 +3693,20 @@ int parse_char(int fd) else { int len; + // retrieve data + struct mmo_charstatus char_dat; + mmo_char_fromsql(i, &char_dat, false); //Only the short data is needed. // send to player WFIFOHEAD(fd,2+MAX_CHAR_BUF); WFIFOW(fd,0) = 0x6d; - len = 2 + mmo_char_tobuf(WFIFOP(fd,2), &char_dat[i].status); + len = 2 + mmo_char_tobuf(WFIFOP(fd,2), &char_dat); WFIFOSET(fd,len); // add new entry to the chars list ARR_FIND( 0, MAX_CHARS, ch, sd->found_char[ch] == -1 ); if( ch < MAX_CHARS ) - sd->found_char[ch] = i; // position of the new char in the char_dat[] array + sd->found_char[ch] = i; // the char_id of the new char } RFIFOSKIP(fd,37); @@ -3898,56 +3720,17 @@ int parse_char(int fd) if (cmd == 0x1fb) FIFOSD_CHECK(56); { int cid = RFIFOL(fd,2); - struct mmo_charstatus* cs = NULL; ShowInfo(CL_RED"Request Char Deletion: "CL_GREEN"%d (%d)"CL_RESET"\n", sd->account_id, cid); memcpy(email, RFIFOP(fd,6), 40); - RFIFOSKIP(fd,( cmd == 0x68 ) ? 46 : 56); - - if (e_mail_check(email) == 0) - safestrncpy(email, "a@a.com", sizeof(email)); // default e-mail - - // BEGIN HACK: "change email using the char deletion 'confirm email' menu" - // if we activated email creation and email is default email - if (email_creation != 0 && strcmp(sd->email, "a@a.com") == 0 && login_fd > 0) { // to modify an e-mail, login-server must be online - // if sended email is incorrect e-mail - if (strcmp(email, "a@a.com") == 0) { - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x70; - WFIFOB(fd,2) = 0; // 00 = Incorrect Email address - WFIFOSET(fd,3); - break; - } - // we change the packet to set it like selection. - ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] != -1 && char_dat[sd->found_char[i]].status.char_id == cid ); - if( i < MAX_CHARS ) - { - // we save new e-mail - memcpy(sd->email, email, 40); - // we send new e-mail to login-server ('online' login-server is checked before) - WFIFOHEAD(login_fd,46); - WFIFOW(login_fd,0) = 0x2715; - WFIFOL(login_fd,2) = sd->account_id; - memcpy(WFIFOP(login_fd, 6), email, 40); - WFIFOSET(login_fd,46); - - // change value to put new packet (char selection) - RFIFOSKIP(fd,-3); //FIXME: Will this work? Messing with the received buffer is ugly anyway... - RFIFOW(fd,0) = 0x66; - RFIFOB(fd,2) = char_dat[sd->found_char[i]].status.slot; - // not send packet, it's modify of actual packet - } else { - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x70; - WFIFOB(fd,2) = 0; // 00 = Incorrect Email address - WFIFOSET(fd,3); - } - break; - } - // END HACK - - // otherwise, we delete the character - if (strcmpi(email, sd->email) != 0) { // if it's an invalid email + RFIFOSKIP(fd,( cmd == 0x68) ? 46 : 56); + + // Check if e-mail is correct + if(strcmpi(email, sd->email) && //email does not matches and + ( + strcmp("a@a.com", sd->email) || //it is not default email, or + (strcmp("a@a.com", email) && strcmp("", email)) //email sent does not matches default + )) { //Fail WFIFOHEAD(fd,3); WFIFOW(fd,0) = 0x70; WFIFOB(fd,2) = 0; // 00 = Incorrect Email address @@ -3956,7 +3739,7 @@ int parse_char(int fd) } // check if this char exists - ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] != -1 && char_dat[sd->found_char[i]].status.char_id == cid ); + ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == cid ); if( i == MAX_CHARS ) { // Such a character does not exist in the account WFIFOHEAD(fd,3); @@ -3966,45 +3749,22 @@ int parse_char(int fd) break; } - // deletion process - cs = &char_dat[sd->found_char[i]].status; - - //check for config char del condition [Lupus] - if( ( char_del_level > 0 && cs->base_level >= (unsigned int)char_del_level ) || ( char_del_level < 0 && cs->base_level <= (unsigned int)(-char_del_level) ) ) - { - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x70; - WFIFOB(fd,2) = 1; // This character cannot be deleted. - WFIFOSET(fd,3); - break; - } - - char_delete(cs); - if (sd->found_char[i] != char_num - 1) { - int j, k; - struct char_session_data *sd2; - memcpy(&char_dat[sd->found_char[i]], &char_dat[char_num-1], sizeof(struct mmo_charstatus)); - // Correct moved character reference in the character's owner - for (j = 0; j < fd_max; j++) { - if (session[j] && (sd2 = (struct char_session_data*)session[j]->session_data) && - sd2->account_id == char_dat[char_num-1].status.account_id) { - for (k = 0; k < MAX_CHARS; k++) { - if (sd2->found_char[k] == char_num-1) { - sd2->found_char[k] = sd->found_char[i]; - break; - } - } - break; - } - } - } - char_num--; - // remove char from list and compact it for(ch = i; ch < MAX_CHARS-1; ch++) sd->found_char[ch] = sd->found_char[ch+1]; sd->found_char[MAX_CHARS-1] = -1; - + + /* Delete character */ + if(delete_char_sql(cid)<0){ + //can't delete the char + //either SQL error or can't delete by some CONFIG conditions + //del fail + WFIFOHEAD(fd,3); + WFIFOW(fd, 0) = 0x70; + WFIFOB(fd, 2) = 0; + WFIFOSET(fd, 3); + break; + } /* Char successfully deleted.*/ WFIFOHEAD(fd,2); WFIFOW(fd,0) = 0x6f; @@ -4025,8 +3785,32 @@ int parse_char(int fd) case 0x28d: FIFOSD_CHECK(34); { - //not implemented + int i, aid = RFIFOL(fd,2), cid =RFIFOL(fd,6); + char name[NAME_LENGTH]; + char esc_name[NAME_LENGTH*2+1]; + safestrncpy(name, (char *)RFIFOP(fd,10), NAME_LENGTH); RFIFOSKIP(fd,34); + + if( aid != sd->account_id ) + break; + ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == cid ); + if( i == MAX_CHARS ) + break; + + normalize_name(name,TRIM_CHARS); + Sql_EscapeStringLen(sql_handle, esc_name, name, strnlen(name, NAME_LENGTH)); + if( !check_char_name(name,esc_name) ) + { + i = 1; + safestrncpy(sd->new_name, name, NAME_LENGTH); + } + else + i = 0; + + WFIFOHEAD(fd, 4); + WFIFOW(fd,0) = 0x28e; + WFIFOW(fd,2) = i; + WFIFOSET(fd,4); } break; //Confirm change name. @@ -4039,8 +3823,19 @@ int parse_char(int fd) // 4: Another user is using this character name, so please select another one. FIFOSD_CHECK(6); { - //not implemented + int i; + int cid = RFIFOL(fd,2); RFIFOSKIP(fd,6); + + ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == cid ); + if( i == MAX_CHARS ) + break; + i = rename_char_sql(sd, cid); + + WFIFOHEAD(fd, 4); + WFIFOW(fd,0) = 0x290; + WFIFOW(fd,2) = i; + WFIFOSET(fd,4); } break; @@ -4237,9 +4032,6 @@ int broadcast_user_count(int tid, unsigned int tick, int id, intptr_t data) WBUFL(buf,2) = users; mapif_sendall(buf,6); - // refresh online files (txt and html) - create_online_files(); - return 0; } @@ -4409,9 +4201,86 @@ int char_lan_config_read(const char *lancfgName) fclose(fp); return 0; } -#endif //TXT_SQL_CONVERT -int char_config_read(const char *cfgName) +void sql_config_read(const char* cfgName) +{ + char line[1024], w1[1024], w2[1024]; + FILE* fp; + + ShowInfo("Reading file %s...\n", cfgName); + + if ((fp = fopen(cfgName, "r")) == NULL) { + ShowError("file not found: %s\n", cfgName); + return; + } + + while(fgets(line, sizeof(line), fp)) + { + if(line[0] == '/' && line[1] == '/') + continue; + + if (sscanf(line, "%[^:]: %[^\r\n]", w1, w2) != 2) + continue; + + if(!strcmpi(w1,"char_db")) + safestrncpy(char_db, w2, sizeof(char_db)); + else if(!strcmpi(w1,"scdata_db")) + safestrncpy(scdata_db, w2, sizeof(scdata_db)); + else if(!strcmpi(w1,"cart_db")) + safestrncpy(cart_db, w2, sizeof(cart_db)); + else if(!strcmpi(w1,"inventory_db")) + safestrncpy(inventory_db, w2, sizeof(inventory_db)); + else if(!strcmpi(w1,"charlog_db")) + safestrncpy(charlog_db, w2, sizeof(charlog_db)); + else if(!strcmpi(w1,"storage_db")) + safestrncpy(storage_db, w2, sizeof(storage_db)); + else if(!strcmpi(w1,"reg_db")) + safestrncpy(reg_db, w2, sizeof(reg_db)); + else if(!strcmpi(w1,"skill_db")) + safestrncpy(skill_db, w2, sizeof(skill_db)); + else if(!strcmpi(w1,"interlog_db")) + safestrncpy(interlog_db, w2, sizeof(interlog_db)); + else if(!strcmpi(w1,"memo_db")) + safestrncpy(memo_db, w2, sizeof(memo_db)); + else if(!strcmpi(w1,"guild_db")) + safestrncpy(guild_db, w2, sizeof(guild_db)); + else if(!strcmpi(w1,"guild_alliance_db")) + safestrncpy(guild_alliance_db, w2, sizeof(guild_alliance_db)); + else if(!strcmpi(w1,"guild_castle_db")) + safestrncpy(guild_castle_db, w2, sizeof(guild_castle_db)); + else if(!strcmpi(w1,"guild_expulsion_db")) + safestrncpy(guild_expulsion_db, w2, sizeof(guild_expulsion_db)); + else if(!strcmpi(w1,"guild_member_db")) + safestrncpy(guild_member_db, w2, sizeof(guild_member_db)); + else if(!strcmpi(w1,"guild_skill_db")) + safestrncpy(guild_skill_db, w2, sizeof(guild_skill_db)); + else if(!strcmpi(w1,"guild_position_db")) + safestrncpy(guild_position_db, w2, sizeof(guild_position_db)); + else if(!strcmpi(w1,"guild_storage_db")) + safestrncpy(guild_storage_db, w2, sizeof(guild_storage_db)); + else if(!strcmpi(w1,"party_db")) + safestrncpy(party_db, w2, sizeof(party_db)); + else if(!strcmpi(w1,"pet_db")) + safestrncpy(pet_db, w2, sizeof(pet_db)); + else if(!strcmpi(w1,"mail_db")) + safestrncpy(mail_db, w2, sizeof(mail_db)); + else if(!strcmpi(w1,"auction_db")) + safestrncpy(auction_db, w2, sizeof(auction_db)); + else if(!strcmpi(w1,"friend_db")) + safestrncpy(friend_db, w2, sizeof(friend_db)); + else if(!strcmpi(w1,"hotkey_db")) + safestrncpy(hotkey_db, w2, sizeof(hotkey_db)); + else if(!strcmpi(w1,"quest_db")) + safestrncpy(quest_db,w2,sizeof(quest_db)); + //support the import command, just like any other config + else if(!strcmpi(w1,"import")) + sql_config_read(w2); + } + fclose(fp); + ShowInfo("Done reading %s.\n", cfgName); +} + +int char_config_read(const char* cfgName) { char line[1024], w1[1024], w2[1024]; FILE* fp = fopen(cfgName, "r"); @@ -4437,7 +4306,6 @@ int char_config_read(const char *cfgName) } else if(strcmpi(w1,"console_silent")==0){ ShowInfo("Console Silent Setting: %d\n", atoi(w2)); msg_silent = atoi(w2); -#ifndef TXT_SQL_CONVERT } else if(strcmpi(w1,"stdout_with_ansisequence")==0){ stdout_with_ansisequence = config_switch(w2); } else if (strcmpi(w1, "userid") == 0) { @@ -4482,18 +4350,6 @@ int char_config_read(const char *cfgName) char_new = (bool)atoi(w2); } else if (strcmpi(w1, "char_new_display") == 0) { char_new_display = atoi(w2); - } else if (strcmpi(w1, "email_creation") == 0) { - email_creation = config_switch(w2); - } else if (strcmpi(w1, "scdata_txt") == 0) { //By Skotlex - safestrncpy(scdata_txt, w2, sizeof(scdata_txt)); -#endif - } else if (strcmpi(w1, "char_txt") == 0) { - safestrncpy(char_txt, w2, sizeof(char_txt)); - } else if (strcmpi(w1, "friends_txt") == 0) { //By davidsiaw - safestrncpy(friends_txt, w2, sizeof(friends_txt)); - } else if (strcmpi(w1, "hotkeys_txt") == 0) { //By davidsiaw - safestrncpy(hotkeys_txt, w2, sizeof(hotkeys_txt)); -#ifndef TXT_SQL_CONVERT } else if (strcmpi(w1, "max_connect_user") == 0) { max_connect_user = atoi(w2); if (max_connect_user < 0) @@ -4535,8 +4391,6 @@ int char_config_read(const char *cfgName) } else if (strcmpi(w1, "unknown_char_name") == 0) { safestrncpy(unknown_char_name, w2, sizeof(unknown_char_name)); unknown_char_name[NAME_LENGTH-1] = '\0'; - } else if (strcmpi(w1, "char_log_filename") == 0) { - safestrncpy(char_log_filename, w2, sizeof(char_log_filename)); } else if (strcmpi(w1, "name_ignoring_case") == 0) { name_ignoring_case = (bool)config_switch(w2); } else if (strcmpi(w1, "char_name_option") == 0) { @@ -4549,23 +4403,6 @@ int char_config_read(const char *cfgName) char_del_level = atoi(w2); } else if (strcmpi(w1, "char_del_delay") == 0) { char_del_delay = atoi(w2); -// online files options - } else if (strcmpi(w1, "online_txt_filename") == 0) { - safestrncpy(online_txt_filename, w2, sizeof(online_txt_filename)); - } else if (strcmpi(w1, "online_html_filename") == 0) { - safestrncpy(online_html_filename, w2, sizeof(online_html_filename)); - } else if (strcmpi(w1, "online_sorting_option") == 0) { - online_sorting_option = atoi(w2); - } else if (strcmpi(w1, "online_display_option") == 0) { - online_display_option = atoi(w2); - } else if (strcmpi(w1, "online_gm_display_min_level") == 0) { // minimum GM level to display 'GM' when we want to display it - online_gm_display_min_level = atoi(w2); - if (online_gm_display_min_level < 5) // send online file every 5 seconds to player is enough - online_gm_display_min_level = 5; - } else if (strcmpi(w1, "online_refresh_html") == 0) { - online_refresh_html = atoi(w2); - if (online_refresh_html < 1) - online_refresh_html = 1; } else if(strcmpi(w1,"db_path")==0) { safestrncpy(db_path, w2, sizeof(db_path)); } else if (strcmpi(w1, "console") == 0) { @@ -4590,7 +4427,6 @@ int char_config_read(const char *cfgName) } } else if (strcmpi(w1, "guild_exp_rate") == 0) { guild_exp_rate = atoi(w2); -#endif //TXT_SQL_CONVERT } else if (strcmpi(w1, "import") == 0) { char_config_read(w2); } @@ -4601,41 +4437,36 @@ int char_config_read(const char *cfgName) return 0; } -#ifndef TXT_SQL_CONVERT void do_final(void) { ShowStatus("Terminating...\n"); - mmo_char_sync(); - inter_save(); set_all_offline(-1); + set_all_offline_sql(); + + inter_final(); + flush_fifos(); do_final_mapif(); do_final_loginif(); - // write online players files with no player - online_char_db->clear(online_char_db, NULL); - create_online_files(); + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `ragsrvinfo`") ) + Sql_ShowDebug(sql_handle); + char_db_->destroy(char_db_, NULL); online_char_db->destroy(online_char_db, NULL); auth_db->destroy(auth_db, NULL); - - if(char_dat) aFree(char_dat); - + if( char_fd != -1 ) { do_close(char_fd); char_fd = -1; } -#ifdef ENABLE_SC_SAVING - status_final(); -#endif - inter_final(); + Sql_Free(sql_handle); mapindex_final(); - char_log("----End of char-server (normal end with closing of all files).\n"); ShowStatus("Finished.\n"); } @@ -4679,28 +4510,24 @@ int do_init(int argc, char **argv) char_config_read((argc < 2) ? CHAR_CONF_NAME : argv[1]); char_lan_config_read((argc > 3) ? argv[3] : LAN_CONF_NAME); + sql_config_read(SQL_CONF_NAME); if (strcmp(userid, "s1")==0 && strcmp(passwd, "p1")==0) { ShowError("Using the default user/password s1/p1 is NOT RECOMMENDED.\n"); - ShowNotice("Please edit your save/account.txt file to create a proper inter-server user/password (gender 'S')\n"); + ShowNotice("Please edit your 'login' table to create a proper inter-server user/password (gender 'S')\n"); ShowNotice("And then change the user/password to use in conf/char_athena.conf (or conf/import/char_conf.txt)\n"); } ShowInfo("Finished reading the char-server configuration.\n"); - // a newline in the log... - char_log(""); - char_log("The char-server starting...\n"); - + inter_init_sql((argc > 2) ? argv[2] : inter_cfgName); // inter server テハア篳ュ + ShowInfo("Finished reading the inter-server configuration.\n"); + ShowInfo("Initializing char server.\n"); auth_db = idb_alloc(DB_OPT_RELEASE_DATA); online_char_db = idb_alloc(DB_OPT_RELEASE_DATA); - mmo_char_init(); + mmo_char_sql_init(); char_read_fame_list(); //Read fame lists. -#ifdef ENABLE_SC_SAVING - status_init(); -#endif - inter_init_txt((argc > 2) ? argv[2] : inter_cfgName); // inter server 初期化 ShowInfo("char server initialized.\n"); if ((naddr_ != 0) && (!login_ip || !char_ip)) @@ -4736,18 +4563,32 @@ int do_init(int argc, char **argv) add_timer_func_list(online_data_cleanup, "online_data_cleanup"); add_timer_interval(gettick() + 1000, online_data_cleanup, 0, 0, 600 * 1000); - // periodic flush of all saved data to disk - add_timer_func_list(mmo_char_sync_timer, "mmo_char_sync_timer"); - add_timer_interval(gettick() + 1000, mmo_char_sync_timer, 0, 0, autosave_interval); - if( console ) { //##TODO invoke a CONSOLE_START plugin event } + //Cleaning the tables for NULL entrys @ startup [Sirius] + //Chardb clean + ShowInfo("Cleaning the '%s' table...\n", char_db); + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `account_id` = '0'", char_db) ) + Sql_ShowDebug(sql_handle); + + //guilddb clean + ShowInfo("Cleaning the '%s' table...\n", guild_db); + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_lv` = '0' AND `max_member` = '0' AND `exp` = '0' AND `next_exp` = '0' AND `average_lv` = '0'", guild_db) ) + Sql_ShowDebug(sql_handle); + + //guildmemberdb clean + ShowInfo("Cleaning the '%s' table...\n", guild_member_db); + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '0' AND `account_id` = '0' AND `char_id` = '0'", guild_member_db) ) + Sql_ShowDebug(sql_handle); + + ShowInfo("End of char server initilization function.\n"); + set_defaultparse(parse_char); + ShowInfo("open port %d.....\n",char_port); char_fd = make_listen_bind(bind_ip, char_port); - char_log("The char-server is ready (Server is listening on the port %d).\n", char_port); ShowStatus("The char-server is "CL_GREEN"ready"CL_RESET" (Server is listening on the port %d).\n\n", char_port); if( runflag != CORE_ST_STOP ) @@ -4758,5 +4599,3 @@ int do_init(int argc, char **argv) return 0; } - -#endif //TXT_SQL_CONVERT diff --git a/src/char/char.h b/src/char/char.h index bb1a530f0..73c2f9f72 100644 --- a/src/char/char.h +++ b/src/char/char.h @@ -1,62 +1,81 @@ // Copyright (c) Athena Dev Teams - Licensed under GNU GPL // For more information, see LICENCE in the main folder -#ifndef _CHAR_H_ -#define _CHAR_H_ +#ifndef _CHAR_SQL_H_ +#define _CHAR_SQL_H_ #include "../common/core.h" // CORE_ST_LAST -#include "../common/mmo.h" -#ifndef TXT_SQL_CONVERT enum E_CHARSERVER_ST { CHARSERVER_ST_RUNNING = CORE_ST_LAST, CHARSERVER_ST_SHUTDOWN, CHARSERVER_ST_LAST }; -#endif + +struct mmo_charstatus; #define MAX_MAP_SERVERS 30 #define DEFAULT_AUTOSAVE_INTERVAL 300*1000 -struct character_data { - struct mmo_charstatus status; - int global_num; - struct global_reg global[GLOBAL_REG_NUM]; +enum { + TABLE_INVENTORY, + TABLE_CART, + TABLE_STORAGE, + TABLE_GUILD_STORAGE, }; -struct mmo_charstatus* search_character(int aid, int cid); -struct mmo_charstatus* search_character_byname(char* character_name); -int search_character_index(char* character_name); -char* search_character_name(int index); -int search_character_online(int aid, int cid); +int memitemdata_to_sql(const struct item items[], int max, int id, int tableswitch); -int mapif_sendall(unsigned char *buf, unsigned int len); -int mapif_sendallwos(int fd,unsigned char *buf, unsigned int len); -int mapif_send(int fd,unsigned char *buf, unsigned int len); +int mapif_sendall(unsigned char *buf,unsigned int len); +int mapif_sendallwos(int fd,unsigned char *buf,unsigned int len); +int mapif_send(int fd,unsigned char *buf,unsigned int len); int char_married(int pl1,int pl2); int char_child(int parent_id, int child_id); -int char_family(int cid1, int cid2, int cid3); - -int char_log(char *fmt, ...); +int char_family(int pl1,int pl2,int pl3); int request_accreg2(int account_id, int char_id); -int char_parse_Registry(int account_id, int char_id, unsigned char *buf, int len); -int save_accreg2(unsigned char *buf, int len); -int char_account_reg_reply(int fd,int account_id,int char_id); +int save_accreg2(unsigned char* buf, int len); extern int char_name_option; extern char char_name_letters[]; +extern bool char_gm_read; extern int autosave_interval; +extern int save_log; extern char db_path[]; +extern char char_db[256]; +extern char scdata_db[256]; +extern char cart_db[256]; +extern char inventory_db[256]; +extern char charlog_db[256]; +extern char storage_db[256]; +extern char interlog_db[256]; +extern char reg_db[256]; +extern char skill_db[256]; +extern char memo_db[256]; +extern char guild_db[256]; +extern char guild_alliance_db[256]; +extern char guild_castle_db[256]; +extern char guild_expulsion_db[256]; +extern char guild_member_db[256]; +extern char guild_position_db[256]; +extern char guild_skill_db[256]; +extern char guild_storage_db[256]; +extern char party_db[256]; +extern char pet_db[256]; +extern char mail_db[256]; +extern char auction_db[256]; +extern char quest_db[256]; + +extern int db_use_sqldbs; // added for sql item_db read for char server [Valaris] + extern int guild_exp_rate; extern int log_inter; + //Exported for use in the TXT-SQL converter. -extern char char_txt[]; -int char_config_read(const char *cfgName); -int mmo_char_fromstr(char *str, struct mmo_charstatus *p, struct global_reg *reg, int *reg_num); -int parse_friend_txt(struct mmo_charstatus *p); +int mmo_char_tosql(int char_id, struct mmo_charstatus *p); +void sql_config_read(const char *cfgName); -#endif /* _CHAR_H_ */ +#endif /* _CHAR_SQL_H_ */ diff --git a/src/char/int_auction.c b/src/char/int_auction.c new file mode 100644 index 000000000..04e321062 --- /dev/null +++ b/src/char/int_auction.c @@ -0,0 +1,494 @@ +// Copyright (c) Athena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + +#include "../common/mmo.h" +#include "../common/malloc.h" +#include "../common/db.h" +#include "../common/showmsg.h" +#include "../common/socket.h" +#include "../common/strlib.h" +#include "../common/sql.h" +#include "../common/timer.h" +#include "char.h" +#include "inter.h" +#include "int_mail.h" +#include "int_auction.h" + +#include +#include +#include + +static DBMap* auction_db_ = NULL; // int auction_id -> struct auction_data* + +void auction_delete(struct auction_data *auction); +static int auction_end_timer(int tid, unsigned int tick, int id, intptr_t data); + +static int auction_count(int char_id, bool buy) +{ + int i = 0; + struct auction_data *auction; + DBIterator* iter; + DBKey key; + + iter = auction_db_->iterator(auction_db_); + for( auction = (struct auction_data*)iter->first(iter,&key); iter->exists(iter); auction = (struct auction_data*)iter->next(iter,&key) ) + { + if( (buy && auction->buyer_id == char_id) || (!buy && auction->seller_id == char_id) ) + i++; + } + iter->destroy(iter); + + return i; +} + +void auction_save(struct auction_data *auction) +{ + int j; + StringBuf buf; + SqlStmt* stmt; + + if( !auction ) + return; + + StringBuf_Init(&buf); + StringBuf_Printf(&buf, "UPDATE `%s` SET `seller_id` = '%d', `seller_name` = ?, `buyer_id` = '%d', `buyer_name` = ?, `price` = '%d', `buynow` = '%d', `hours` = '%d', `timestamp` = '%lu', `nameid` = '%d', `item_name` = ?, `type` = '%d', `refine` = '%d', `attribute` = '%d'", + auction_db, auction->seller_id, auction->buyer_id, auction->price, auction->buynow, auction->hours, (unsigned long)auction->timestamp, auction->item.nameid, auction->type, auction->item.refine, auction->item.attribute); + for( j = 0; j < MAX_SLOTS; j++ ) + StringBuf_Printf(&buf, ", `card%d` = '%d'", j, auction->item.card[j]); + StringBuf_Printf(&buf, " WHERE `auction_id` = '%d'", auction->auction_id); + + stmt = SqlStmt_Malloc(sql_handle); + if( SQL_SUCCESS != SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_STRING, auction->seller_name, strnlen(auction->seller_name, NAME_LENGTH)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_STRING, auction->buyer_name, strnlen(auction->buyer_name, NAME_LENGTH)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 2, SQLDT_STRING, auction->item_name, strnlen(auction->item_name, ITEM_NAME_LENGTH)) + || SQL_SUCCESS != SqlStmt_Execute(stmt) ) + { + SqlStmt_ShowDebug(stmt); + } + + SqlStmt_Free(stmt); + StringBuf_Destroy(&buf); +} + +unsigned int auction_create(struct auction_data *auction) +{ + int j; + StringBuf buf; + SqlStmt* stmt; + + if( !auction ) + return false; + + auction->timestamp = time(NULL) + (auction->hours * 3600); + + StringBuf_Init(&buf); + StringBuf_Printf(&buf, "INSERT INTO `%s` (`seller_id`,`seller_name`,`buyer_id`,`buyer_name`,`price`,`buynow`,`hours`,`timestamp`,`nameid`,`item_name`,`type`,`refine`,`attribute`", auction_db); + for( j = 0; j < MAX_SLOTS; j++ ) + StringBuf_Printf(&buf, ",`card%d`", j); + StringBuf_Printf(&buf, ") VALUES ('%d',?,'%d',?,'%d','%d','%d','%lu','%d',?,'%d','%d','%d'", + auction->seller_id, auction->buyer_id, auction->price, auction->buynow, auction->hours, (unsigned long)auction->timestamp, auction->item.nameid, auction->type, auction->item.refine, auction->item.attribute); + for( j = 0; j < MAX_SLOTS; j++ ) + StringBuf_Printf(&buf, ",'%d'", auction->item.card[j]); + StringBuf_AppendStr(&buf, ")"); + + stmt = SqlStmt_Malloc(sql_handle); + if( SQL_SUCCESS != SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_STRING, auction->seller_name, strnlen(auction->seller_name, NAME_LENGTH)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_STRING, auction->buyer_name, strnlen(auction->buyer_name, NAME_LENGTH)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 2, SQLDT_STRING, auction->item_name, strnlen(auction->item_name, ITEM_NAME_LENGTH)) + || SQL_SUCCESS != SqlStmt_Execute(stmt) ) + { + SqlStmt_ShowDebug(stmt); + auction->auction_id = 0; + } + else + { + struct auction_data *auction_; + unsigned int tick = auction->hours * 3600000; + + auction->item.amount = 1; + auction->item.identify = 1; + auction->item.expire_time = 0; + + auction->auction_id = (unsigned int)SqlStmt_LastInsertId(stmt); + auction->auction_end_timer = add_timer( gettick() + tick , auction_end_timer, auction->auction_id, 0); + ShowInfo("New Auction %u | time left %u ms | By %s.\n", auction->auction_id, tick, auction->seller_name); + + CREATE(auction_, struct auction_data, 1); + memcpy(auction_, auction, sizeof(struct auction_data)); + idb_put(auction_db_, auction_->auction_id, auction_); + } + + SqlStmt_Free(stmt); + StringBuf_Destroy(&buf); + + return auction->auction_id; +} + +static void mapif_Auction_message(int char_id, unsigned char result) +{ + unsigned char buf[74]; + + WBUFW(buf,0) = 0x3854; + WBUFL(buf,2) = char_id; + WBUFL(buf,6) = result; + mapif_sendall(buf,7); +} + +static int auction_end_timer(int tid, unsigned int tick, int id, intptr_t data) +{ + struct auction_data *auction; + if( (auction = (struct auction_data *)idb_get(auction_db_, id)) != NULL ) + { + if( auction->buyer_id ) + { + mail_sendmail(0, "Auction Manager", auction->buyer_id, auction->buyer_name, "Auction", "Thanks, you won the auction!.", 0, &auction->item); + mapif_Auction_message(auction->buyer_id, 6); // You have won the auction + mail_sendmail(0, "Auction Manager", auction->seller_id, auction->seller_name, "Auction", "Payment for your auction!.", auction->price, NULL); + } + else + mail_sendmail(0, "Auction Manager", auction->seller_id, auction->seller_name, "Auction", "No buyers have been found for your auction.", 0, &auction->item); + + ShowInfo("Auction End: id %u.\n", auction->auction_id); + + auction->auction_end_timer = INVALID_TIMER; + auction_delete(auction); + } + + return 0; +} + +void auction_delete(struct auction_data *auction) +{ + unsigned int auction_id = auction->auction_id; + + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `auction_id` = '%d'", auction_db, auction_id) ) + Sql_ShowDebug(sql_handle); + + if( auction->auction_end_timer != INVALID_TIMER ) + delete_timer(auction->auction_end_timer, auction_end_timer); + + idb_remove(auction_db_, auction_id); +} + +void inter_auctions_fromsql(void) +{ + int i; + struct auction_data *auction; + struct item *item; + char *data; + StringBuf buf; + unsigned int tick = gettick(), endtick; + time_t now = time(NULL); + + StringBuf_Init(&buf); + StringBuf_AppendStr(&buf, "SELECT `auction_id`,`seller_id`,`seller_name`,`buyer_id`,`buyer_name`," + "`price`,`buynow`,`hours`,`timestamp`,`nameid`,`item_name`,`type`,`refine`,`attribute`"); + for( i = 0; i < MAX_SLOTS; i++ ) + StringBuf_Printf(&buf, ",`card%d`", i); + StringBuf_Printf(&buf, " FROM `%s` ORDER BY `auction_id` DESC", auction_db); + + if( SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf)) ) + Sql_ShowDebug(sql_handle); + + StringBuf_Destroy(&buf); + + while( SQL_SUCCESS == Sql_NextRow(sql_handle) ) + { + CREATE(auction, struct auction_data, 1); + Sql_GetData(sql_handle, 0, &data, NULL); auction->auction_id = atoi(data); + Sql_GetData(sql_handle, 1, &data, NULL); auction->seller_id = atoi(data); + Sql_GetData(sql_handle, 2, &data, NULL); safestrncpy(auction->seller_name, data, NAME_LENGTH); + Sql_GetData(sql_handle, 3, &data, NULL); auction->buyer_id = atoi(data); + Sql_GetData(sql_handle, 4, &data, NULL); safestrncpy(auction->buyer_name, data, NAME_LENGTH); + Sql_GetData(sql_handle, 5, &data, NULL); auction->price = atoi(data); + Sql_GetData(sql_handle, 6, &data, NULL); auction->buynow = atoi(data); + Sql_GetData(sql_handle, 7, &data, NULL); auction->hours = atoi(data); + Sql_GetData(sql_handle, 8, &data, NULL); auction->timestamp = atoi(data); + + item = &auction->item; + Sql_GetData(sql_handle, 9, &data, NULL); item->nameid = atoi(data); + Sql_GetData(sql_handle,10, &data, NULL); safestrncpy(auction->item_name, data, ITEM_NAME_LENGTH); + Sql_GetData(sql_handle,11, &data, NULL); auction->type = atoi(data); + + Sql_GetData(sql_handle,12, &data, NULL); item->refine = atoi(data); + Sql_GetData(sql_handle,13, &data, NULL); item->attribute = atoi(data); + + item->identify = 1; + item->amount = 1; + item->expire_time = 0; + + for( i = 0; i < MAX_SLOTS; i++ ) + { + Sql_GetData(sql_handle, 14 + i, &data, NULL); + item->card[i] = atoi(data); + } + + if( auction->timestamp > now ) + endtick = ((unsigned int)(auction->timestamp - now) * 1000) + tick; + else + endtick = tick + 10000; // 10 Second's to process ended auctions + + auction->auction_end_timer = add_timer(endtick, auction_end_timer, auction->auction_id, 0); + idb_put(auction_db_, auction->auction_id, auction); + } + + Sql_FreeResult(sql_handle); +} + +static void mapif_Auction_sendlist(int fd, int char_id, short count, short pages, unsigned char *buf) +{ + int len = (sizeof(struct auction_data) * count) + 12; + + WFIFOHEAD(fd, len); + WFIFOW(fd,0) = 0x3850; + WFIFOW(fd,2) = len; + WFIFOL(fd,4) = char_id; + WFIFOW(fd,8) = count; + WFIFOW(fd,10) = pages; + memcpy(WFIFOP(fd,12), buf, len - 12); + WFIFOSET(fd,len); +} + +static void mapif_parse_Auction_requestlist(int fd) +{ + char searchtext[NAME_LENGTH]; + int char_id = RFIFOL(fd,4), len = sizeof(struct auction_data); + int price = RFIFOL(fd,10); + short type = RFIFOW(fd,8), page = max(1,RFIFOW(fd,14)); + unsigned char buf[5 * sizeof(struct auction_data)]; + DBIterator* iter; + DBKey key; + struct auction_data *auction; + short i = 0, j = 0, pages = 1; + + memcpy(searchtext, RFIFOP(fd,16), NAME_LENGTH); + + iter = auction_db_->iterator(auction_db_); + for( auction = (struct auction_data*)iter->first(iter,&key); iter->exists(iter); auction = (struct auction_data*)iter->next(iter,&key) ) + { + if( (type == 0 && auction->type != IT_ARMOR && auction->type != IT_PETARMOR) || + (type == 1 && auction->type != IT_WEAPON) || + (type == 2 && auction->type != IT_CARD) || + (type == 3 && auction->type != IT_ETC) || + (type == 4 && !strstr(auction->item_name, searchtext)) || + (type == 5 && auction->price > price) || + (type == 6 && auction->seller_id != char_id) || + (type == 7 && auction->buyer_id != char_id) ) + continue; + + i++; + if( i > 5 ) + { // Counting Pages of Total Results (5 Results per Page) + pages++; + i = 1; // First Result of This Page + } + + if( page != pages ) + continue; // This is not the requested Page + + memcpy(WBUFP(buf, j * len), auction, len); + j++; // Found Results + } + iter->destroy(iter); + + mapif_Auction_sendlist(fd, char_id, j, pages, buf); +} + +static void mapif_Auction_register(int fd, struct auction_data *auction) +{ + int len = sizeof(struct auction_data) + 4; + + WFIFOHEAD(fd,len); + WFIFOW(fd,0) = 0x3851; + WFIFOW(fd,2) = len; + memcpy(WFIFOP(fd,4), auction, sizeof(struct auction_data)); + WFIFOSET(fd,len); +} + +static void mapif_parse_Auction_register(int fd) +{ + struct auction_data auction; + if( RFIFOW(fd,2) != sizeof(struct auction_data) + 4 ) + return; + + memcpy(&auction, RFIFOP(fd,4), sizeof(struct auction_data)); + if( auction_count(auction.seller_id, false) < 5 ) + auction.auction_id = auction_create(&auction); + + mapif_Auction_register(fd, &auction); +} + +static void mapif_Auction_cancel(int fd, int char_id, unsigned char result) +{ + WFIFOHEAD(fd,7); + WFIFOW(fd,0) = 0x3852; + WFIFOL(fd,2) = char_id; + WFIFOB(fd,6) = result; + WFIFOSET(fd,7); +} + +static void mapif_parse_Auction_cancel(int fd) +{ + int char_id = RFIFOL(fd,2), auction_id = RFIFOL(fd,6); + struct auction_data *auction; + + if( (auction = (struct auction_data *)idb_get(auction_db_, auction_id)) == NULL ) + { + mapif_Auction_cancel(fd, char_id, 1); // Bid Number is Incorrect + return; + } + + if( auction->seller_id != char_id ) + { + mapif_Auction_cancel(fd, char_id, 2); // You cannot end the auction + return; + } + + if( auction->buyer_id > 0 ) + { + mapif_Auction_cancel(fd, char_id, 3); // An auction with at least one bidder cannot be canceled + return; + } + + mail_sendmail(0, "Auction Manager", auction->seller_id, auction->seller_name, "Auction", "Auction canceled.", 0, &auction->item); + auction_delete(auction); + + mapif_Auction_cancel(fd, char_id, 0); // The auction has been canceled +} + +static void mapif_Auction_close(int fd, int char_id, unsigned char result) +{ + WFIFOHEAD(fd,7); + WFIFOW(fd,0) = 0x3853; + WFIFOL(fd,2) = char_id; + WFIFOB(fd,6) = result; + WFIFOSET(fd,7); +} + +static void mapif_parse_Auction_close(int fd) +{ + int char_id = RFIFOL(fd,2), auction_id = RFIFOL(fd,6); + struct auction_data *auction; + + if( (auction = (struct auction_data *)idb_get(auction_db_, auction_id)) == NULL ) + { + mapif_Auction_close(fd, char_id, 2); // Bid Number is Incorrect + return; + } + + if( auction->seller_id != char_id ) + { + mapif_Auction_close(fd, char_id, 1); // You cannot end the auction + return; + } + + if( auction->buyer_id == 0 ) + { + mapif_Auction_close(fd, char_id, 1); // You cannot end the auction + return; + } + + // Send Money to Seller + mail_sendmail(0, "Auction Manager", auction->seller_id, auction->seller_name, "Auction", "Auction closed.", auction->price, NULL); + // Send Item to Buyer + mail_sendmail(0, "Auction Manager", auction->buyer_id, auction->buyer_name, "Auction", "Auction winner.", 0, &auction->item); + mapif_Auction_message(auction->buyer_id, 6); // You have won the auction + auction_delete(auction); + + mapif_Auction_close(fd, char_id, 0); // You have ended the auction +} + +static void mapif_Auction_bid(int fd, int char_id, int bid, unsigned char result) +{ + WFIFOHEAD(fd,11); + WFIFOW(fd,0) = 0x3855; + WFIFOL(fd,2) = char_id; + WFIFOL(fd,6) = bid; // To Return Zeny + WFIFOB(fd,10) = result; + WFIFOSET(fd,11); +} + +static void mapif_parse_Auction_bid(int fd) +{ + int char_id = RFIFOL(fd,4), bid = RFIFOL(fd,12); + unsigned int auction_id = RFIFOL(fd,8); + struct auction_data *auction; + + if( (auction = (struct auction_data *)idb_get(auction_db_, auction_id)) == NULL || auction->price >= bid || auction->seller_id == char_id ) + { + mapif_Auction_bid(fd, char_id, bid, 0); // You have failed to bid in the auction + return; + } + + if( auction_count(char_id, true) > 4 && bid < auction->buynow && auction->buyer_id != char_id ) + { + mapif_Auction_bid(fd, char_id, bid, 9); // You cannot place more than 5 bids at a time + return; + } + + if( auction->buyer_id > 0 ) + { // Send Money back to the previous Buyer + if( auction->buyer_id != char_id ) + { + mail_sendmail(0, "Auction Manager", auction->buyer_id, auction->buyer_name, "Auction", "Someone has placed a higher bid.", auction->price, NULL); + mapif_Auction_message(auction->buyer_id, 7); // You have failed to win the auction + } + else + mail_sendmail(0, "Auction Manager", auction->buyer_id, auction->buyer_name, "Auction", "You have placed a higher bid.", auction->price, NULL); + } + + auction->buyer_id = char_id; + safestrncpy(auction->buyer_name, (char*)RFIFOP(fd,16), NAME_LENGTH); + auction->price = bid; + + if( bid >= auction->buynow ) + { // Automatic won the auction + mapif_Auction_bid(fd, char_id, bid - auction->buynow, 1); // You have successfully bid in the auction + + mail_sendmail(0, "Auction Manager", auction->buyer_id, auction->buyer_name, "Auction", "You have won the auction.", 0, &auction->item); + mapif_Auction_message(char_id, 6); // You have won the auction + mail_sendmail(0, "Auction Manager", auction->seller_id, auction->seller_name, "Auction", "Payment for your auction!.", auction->buynow, NULL); + + auction_delete(auction); + return; + } + + auction_save(auction); + + mapif_Auction_bid(fd, char_id, 0, 1); // You have successfully bid in the auction +} + +/*========================================== + * Packets From Map Server + *------------------------------------------*/ +int inter_auction_parse_frommap(int fd) +{ + switch(RFIFOW(fd,0)) + { + case 0x3050: mapif_parse_Auction_requestlist(fd); break; + case 0x3051: mapif_parse_Auction_register(fd); break; + case 0x3052: mapif_parse_Auction_cancel(fd); break; + case 0x3053: mapif_parse_Auction_close(fd); break; + case 0x3055: mapif_parse_Auction_bid(fd); break; + default: + return 0; + } + return 1; +} + +int inter_auction_sql_init(void) +{ + auction_db_ = idb_alloc(DB_OPT_RELEASE_DATA); + inter_auctions_fromsql(); + + return 0; +} + +void inter_auction_sql_final(void) +{ + auction_db_->destroy(auction_db_,NULL); + + return; +} diff --git a/src/char/int_auction.h b/src/char/int_auction.h new file mode 100644 index 000000000..bf26b152c --- /dev/null +++ b/src/char/int_auction.h @@ -0,0 +1,12 @@ +// Copyright (c) Athena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + +#ifndef _INT_AUCTION_SQL_H_ +#define _INT_AUCTION_SQL_H_ + +int inter_auction_parse_frommap(int fd); + +int inter_auction_sql_init(void); +void inter_auction_sql_final(void); + +#endif /* _INT_AUCTION_SQL_H_ */ diff --git a/src/char/int_guild.c b/src/char/int_guild.c index 31cceeff0..2ce6d6141 100644 --- a/src/char/int_guild.c +++ b/src/char/int_guild.c @@ -6,381 +6,634 @@ #include "../common/malloc.h" #include "../common/socket.h" #include "../common/db.h" -#include "../common/lock.h" #include "../common/showmsg.h" #include "../common/strlib.h" +#include "../common/timer.h" #include "char.h" #include "inter.h" -#include "int_storage.h" #include "int_guild.h" #include #include #include -char guild_txt[1024] = "save/guild.txt"; -char castle_txt[1024] = "save/castle.txt"; +#define GS_MEMBER_UNMODIFIED 0x00 +#define GS_MEMBER_MODIFIED 0x01 +#define GS_MEMBER_NEW 0x02 -#ifndef TXT_SQL_CONVERT -static DBMap* guild_db; // int guild_id -> struct guild* -static DBMap* castle_db; // int castle_id -> struct guild_castle* +#define GS_POSITION_UNMODIFIED 0x00 +#define GS_POSITION_MODIFIED 0x01 -static int guild_newid = 10000; +// LSB = 0 => Alliance, LSB = 1 => Opposition +#define GUILD_ALLIANCE_TYPE_MASK 0x01 +#define GUILD_ALLIANCE_REMOVE 0x08 + +static const char dataToHex[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; + +//Guild cache +static DBMap* guild_db_; // int guild_id -> struct guild* + +struct guild_castle castles[MAX_GUILDCASTLE]; static unsigned int guild_exp[100]; -int mapif_guild_broken(int guild_id, int flag); +int mapif_parse_GuildLeave(int fd,int guild_id,int account_id,int char_id,int flag,const char *mes); +int mapif_guild_broken(int guild_id,int flag); static bool guild_check_empty(struct guild *g); int guild_calcinfo(struct guild *g); -int mapif_guild_basicinfochanged(int guild_id, int type, const void *data, int len); -int mapif_guild_info(int fd, struct guild *g); -int guild_break_sub(DBKey key, void *data, va_list ap); +int mapif_guild_basicinfochanged(int guild_id,int type,const void *data,int len); +int mapif_guild_info(int fd,struct guild *g); +int guild_break_sub(int key,void *data,va_list ap); +int inter_guild_tosql(struct guild *g,int flag); -/// serializes the guild data structure into the provided string -int inter_guild_tostr(char* str, struct guild* g) +static int guild_save_timer(int tid, unsigned int tick, int id, intptr_t data) { - int i, c, len; + static int last_id = 0; //To know in which guild we were. + int state = 0; //0: Have not reached last guild. 1: Reached last guild, ready for save. 2: Some guild saved, don't do further saving. + DBIterator* iter; + DBKey key; + struct guild* g; - // save guild base info - len = sprintf(str, "%d\t%s\t%s\t%d,%d,%"PRIu64",%d,%d\t%s#\t%s#\t", - g->guild_id, g->name, g->master, g->guild_lv, g->max_member, g->exp, g->skill_point, 0, g->mes1, g->mes2); + if( last_id == 0 ) //Save the first guild in the list. + state = 1; - // save guild member info - for(i = 0; i < g->max_member; i++) + iter = guild_db_->iterator(guild_db_); + for( g = (struct guild*)iter->first(iter,&key); iter->exists(iter); g = (struct guild*)iter->next(iter,&key) ) { - struct guild_member *m = &g->member[i]; - len += sprintf(str + len, "%d,%d,%d,%d,%d,%d,%d,%"PRIu64",%d,%d\t%s\t", - m->account_id, m->char_id, - m->hair, m->hair_color, m->gender, - m->class_, m->lv, m->exp, m->exp_payper, m->position, - ((m->account_id > 0) ? m->name : "-")); - } - - // save guild position info - for(i = 0; i < MAX_GUILDPOSITION; i++) { - struct guild_position *p = &g->position[i]; - len += sprintf(str + len, "%d,%d\t%s#\t", p->mode, p->exp_mode, p->name); - } + if( state == 0 && g->guild_id == last_id ) + state++; //Save next guild in the list. + else + if( state == 1 && g->save_flag&GS_MASK ) + { + inter_guild_tosql(g, g->save_flag&GS_MASK); + g->save_flag &= ~GS_MASK; - // save guild emblem - len += sprintf(str + len, "%d,%d,", g->emblem_len, g->emblem_id); - for(i = 0; i < g->emblem_len; i++) { - len += sprintf(str + len, "%02x", (unsigned char)(g->emblem_data[i])); - } - len += sprintf(str + len, "$\t"); + //Some guild saved. + last_id = g->guild_id; + state++; + } - // save guild alliance info - c = 0; - for(i = 0; i < MAX_GUILDALLIANCE; i++) - if (g->alliance[i].guild_id > 0) - c++; - len += sprintf(str + len, "%d\t", c); - for(i = 0; i < MAX_GUILDALLIANCE; i++) { - struct guild_alliance *a = &g->alliance[i]; - if (a->guild_id > 0) - len += sprintf(str + len, "%d,%d\t%s\t", a->guild_id, a->opposition, a->name); + if( g->save_flag == GS_REMOVE ) + {// Nothing to save, guild is ready for removal. + if (save_log) + ShowInfo("Guild Unloaded (%d - %s)\n", g->guild_id, g->name); + db_remove(guild_db_, key); + } } + iter->destroy(iter); - // save guild expulsion info - c = 0; - for(i = 0; i < MAX_GUILDEXPULSION; i++) - if (g->expulsion[i].account_id > 0) - c++; - len += sprintf(str + len, "%d\t", c); - for(i = 0; i < MAX_GUILDEXPULSION; i++) { - struct guild_expulsion *e = &g->expulsion[i]; - if (e->account_id > 0) - len += sprintf(str + len, "%d,%d,%d,%d\t%s\t%s\t%s#\t", - e->account_id, 0, 0, 0, e->name, "#", e->mes ); - } + if( state != 2 ) //Reached the end of the guild db without saving. + last_id = 0; //Reset guild saved, return to beginning. - // save guild skill info - for(i = 0; i < MAX_GUILDSKILL; i++) { - len += sprintf(str + len, "%d,%d ", g->skill[i].id, g->skill[i].lv); - } - len += sprintf(str + len, "\t"); + state = guild_db_->size(guild_db_); + if( state < 1 ) state = 1; //Calculate the time slot for the next save. + add_timer(tick + autosave_interval/state, guild_save_timer, 0, 0); + return 0; +} +int inter_guild_removemember_tosql(int account_id, int char_id) +{ + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE from `%s` where `account_id` = '%d' and `char_id` = '%d'", guild_member_db, account_id, char_id) ) + Sql_ShowDebug(sql_handle); + if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `guild_id` = '0' WHERE `char_id` = '%d'", char_db, char_id) ) + Sql_ShowDebug(sql_handle); return 0; } -#endif //TXT_SQL_CONVERT -/// parses the guild data string into a guild data structure -int inter_guild_fromstr(char* str, struct guild* g) +// Save guild into sql +int inter_guild_tosql(struct guild *g,int flag) { - int i, c; - char *pstr; - - memset(g, 0, sizeof(struct guild)); - - {// load guild base info - int guildid; - char name[256]; // only 24 used - char master[256]; // only 24 used - int guildlv; - int max_member; - uint64 exp; - int skpoint; - char mes1[256]; // only 60 used - char mes2[256]; // only 120 used - int len; - - if( sscanf(str, "%d\t%[^\t]\t%[^\t]\t%d,%d,%"SCNu64",%d,%*d\t%[^\t]\t%[^\t]\t%n", - &guildid, name, master, &guildlv, &max_member, &exp, &skpoint, mes1, mes2, &len) < 9 ) - return 1; - - // remove '#' - mes1[strlen(mes1)-1] = '\0'; - mes2[strlen(mes2)-1] = '\0'; - - g->guild_id = guildid; - g->guild_lv = guildlv; - g->max_member = max_member; - g->exp = exp; - g->skill_point = skpoint; - safestrncpy(g->name, name, sizeof(g->name)); - safestrncpy(g->master, master, sizeof(g->master)); - safestrncpy(g->mes1, mes1, sizeof(g->mes1)); - safestrncpy(g->mes2, mes2, sizeof(g->mes2)); - - str+= len; - } - - {// load guild member info - int accountid; - int charid; - int hair, hair_color, gender; - int class_, lv; - uint64 exp; - int exp_payper; - int position; - char name[256]; // only 24 used - int len; - int i; + // Table guild (GS_BASIC_MASK) + // GS_EMBLEM `emblem_len`,`emblem_id`,`emblem_data` + // GS_CONNECT `connect_member`,`average_lv` + // GS_MES `mes1`,`mes2` + // GS_LEVEL `guild_lv`,`max_member`,`exp`,`next_exp`,`skill_point` + // GS_BASIC `name`,`master`,`char_id` + + // GS_MEMBER `guild_member` (`guild_id`,`account_id`,`char_id`,`hair`,`hair_color`,`gender`,`class`,`lv`,`exp`,`exp_payper`,`online`,`position`,`name`) + // GS_POSITION `guild_position` (`guild_id`,`position`,`name`,`mode`,`exp_mode`) + // GS_ALLIANCE `guild_alliance` (`guild_id`,`opposition`,`alliance_id`,`name`) + // GS_EXPULSION `guild_expulsion` (`guild_id`,`account_id`,`name`,`mes`) + // GS_SKILL `guild_skill` (`guild_id`,`id`,`lv`) + + // temporary storage for str convertion. They must be twice the size of the + // original string to ensure no overflows will occur. [Skotlex] + char t_info[256]; + char esc_name[NAME_LENGTH*2+1]; + char esc_master[NAME_LENGTH*2+1]; + char new_guild = 0; + int i=0; + + if (g->guild_id<=0 && g->guild_id != -1) return 0; + +#ifdef NOISY + ShowInfo("Save guild request ("CL_BOLD"%d"CL_RESET" - flag 0x%x).",g->guild_id, flag); +#endif + + Sql_EscapeStringLen(sql_handle, esc_name, g->name, strnlen(g->name, NAME_LENGTH)); + Sql_EscapeStringLen(sql_handle, esc_master, g->master, strnlen(g->master, NAME_LENGTH)); + *t_info = '\0'; + + // Insert a new guild the guild + if (flag&GS_BASIC && g->guild_id == -1) + { + strcat(t_info, " guild_create"); - for( i = 0; i < g->max_member; i++ ) + // Create a new guild + if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` " + "(`name`,`master`,`guild_lv`,`max_member`,`average_lv`,`char_id`) " + "VALUES ('%s', '%s', '%d', '%d', '%d', '%d')", + guild_db, esc_name, esc_master, g->guild_lv, g->max_member, g->average_lv, g->member[0].char_id) ) + { + Sql_ShowDebug(sql_handle); + if (g->guild_id == -1) + return 0; //Failed to create guild! + } + else { - struct guild_member* m = &g->member[i]; - if (sscanf(str, "%d,%d,%d,%d,%d,%d,%d,%"SCNu64",%d,%d\t%[^\t]\t%n", - &accountid, &charid, &hair, &hair_color, &gender, - &class_, &lv, &exp, &exp_payper, &position, - name, &len) < 11) - return 1; - - m->account_id = accountid; - m->char_id = charid; - m->hair = hair; - m->hair_color = hair_color; - m->gender = gender; - m->class_ = class_; - m->lv = lv; - m->exp = exp; - m->exp_payper = exp_payper; - m->position = position; - safestrncpy(m->name, name, NAME_LENGTH); - - str+= len; + g->guild_id = (int)Sql_LastInsertId(sql_handle); + new_guild = 1; } } - {// load guild position info - int mode, exp_mode; - char name[256]; // only 24 used - int len; - int i = 0; - int j; + // If we need an update on an existing guild or more update on the new guild + if (((flag & GS_BASIC_MASK) && !new_guild) || ((flag & (GS_BASIC_MASK & ~GS_BASIC)) && new_guild)) + { + StringBuf buf; + bool add_comma = false; - while (sscanf(str, "%d,%d%n", &mode, &exp_mode, &j) == 2 && str[j] == '\t') + StringBuf_Init(&buf); + StringBuf_Printf(&buf, "UPDATE `%s` SET ", guild_db); + + if (flag & GS_EMBLEM) { - struct guild_position *p = &g->position[i]; - if (sscanf(str, "%d,%d\t%[^\t]\t%n", &mode, &exp_mode, name, &len) < 3) - return 1; + char emblem_data[sizeof(g->emblem_data)*2+1]; + char* pData = emblem_data; + + strcat(t_info, " emblem"); + // Convert emblem_data to hex + //TODO: why not use binary directly? [ultramage] + for(i=0; iemblem_len; i++){ + *pData++ = dataToHex[(g->emblem_data[i] >> 4) & 0x0F]; + *pData++ = dataToHex[g->emblem_data[i] & 0x0F]; + } + *pData = 0; + StringBuf_Printf(&buf, "`emblem_len`=%d, `emblem_id`=%d, `emblem_data`='%s'", g->emblem_len, g->emblem_id, emblem_data); + add_comma = true; + } + if (flag & GS_BASIC) + { + strcat(t_info, " basic"); + if( add_comma ) + StringBuf_AppendStr(&buf, ", "); + else + add_comma = true; + StringBuf_Printf(&buf, "`name`='%s', `master`='%s', `char_id`=%d", esc_name, esc_master, g->member[0].char_id); + } + if (flag & GS_CONNECT) + { + strcat(t_info, " connect"); + if( add_comma ) + StringBuf_AppendStr(&buf, ", "); + else + add_comma = true; + StringBuf_Printf(&buf, "`connect_member`=%d, `average_lv`=%d", g->connect_member, g->average_lv); + } + if (flag & GS_MES) + { + char esc_mes1[sizeof(g->mes1)*2+1]; + char esc_mes2[sizeof(g->mes2)*2+1]; - p->mode = mode; - p->exp_mode = exp_mode; - name[strlen(name)-1] = 0; - safestrncpy(p->name, name, NAME_LENGTH); + strcat(t_info, " mes"); + if( add_comma ) + StringBuf_AppendStr(&buf, ", "); + else + add_comma = true; + Sql_EscapeStringLen(sql_handle, esc_mes1, g->mes1, strnlen(g->mes1, sizeof(g->mes1))); + Sql_EscapeStringLen(sql_handle, esc_mes2, g->mes2, strnlen(g->mes2, sizeof(g->mes2))); + StringBuf_Printf(&buf, "`mes1`='%s', `mes2`='%s'", esc_mes1, esc_mes2); + } + if (flag & GS_LEVEL) + { + strcat(t_info, " level"); + if( add_comma ) + StringBuf_AppendStr(&buf, ", "); + else + add_comma = true; + StringBuf_Printf(&buf, "`guild_lv`=%d, `skill_point`=%d, `exp`=%"PRIu64", `next_exp`=%u, `max_member`=%d", g->guild_lv, g->skill_point, g->exp, g->next_exp, g->max_member); + } + StringBuf_Printf(&buf, " WHERE `guild_id`=%d", g->guild_id); + if( SQL_ERROR == Sql_Query(sql_handle, "%s", StringBuf_Value(&buf)) ) + Sql_ShowDebug(sql_handle); + StringBuf_Destroy(&buf); + } - i++; - str+= len; + if (flag&GS_MEMBER) + { + struct guild_member *m; + + strcat(t_info, " members"); + // Update only needed players + for(i=0;imax_member;i++){ + m = &g->member[i]; + if (!m->modified) + continue; + if(m->account_id) { + //Since nothing references guild member table as foreign keys, it's safe to use REPLACE INTO + Sql_EscapeStringLen(sql_handle, esc_name, m->name, strnlen(m->name, NAME_LENGTH)); + if( SQL_ERROR == Sql_Query(sql_handle, "REPLACE INTO `%s` (`guild_id`,`account_id`,`char_id`,`hair`,`hair_color`,`gender`,`class`,`lv`,`exp`,`exp_payper`,`online`,`position`,`name`) " + "VALUES ('%d','%d','%d','%d','%d','%d','%d','%d','%"PRIu64"','%d','%d','%d','%s')", + guild_member_db, g->guild_id, m->account_id, m->char_id, + m->hair, m->hair_color, m->gender, + m->class_, m->lv, m->exp, m->exp_payper, m->online, m->position, esc_name) ) + Sql_ShowDebug(sql_handle); + if (m->modified & GS_MEMBER_NEW) + { + if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `guild_id` = '%d' WHERE `char_id` = '%d'", + char_db, g->guild_id, m->char_id) ) + Sql_ShowDebug(sql_handle); + } + m->modified = GS_MEMBER_UNMODIFIED; + } } } - {// load guild emblem - int emblemlen; - int emblemid; - char emblem[4096]; - int len; - - emblemid = 0; - if( sscanf(str, "%d,%d,%[^\t]\t%n", &emblemlen, &emblemid, emblem, &len) < 3 ) - if( sscanf(str, "%d,%[^\t]\t%n", &emblemlen, emblem, &len) < 2 ) //! pre-svn format - return 1; - - g->emblem_len = emblemlen; - g->emblem_id = emblemid; - for(i = 0, pstr = emblem; i < g->emblem_len; i++, pstr += 2) { - int c1 = pstr[0], c2 = pstr[1], x1 = 0, x2 = 0; - if (c1 >= '0' && c1 <= '9') x1 = c1 - '0'; - if (c1 >= 'a' && c1 <= 'f') x1 = c1 - 'a' + 10; - if (c1 >= 'A' && c1 <= 'F') x1 = c1 - 'A' + 10; - if (c2 >= '0' && c2 <= '9') x2 = c2 - '0'; - if (c2 >= 'a' && c2 <= 'f') x2 = c2 - 'a' + 10; - if (c2 >= 'A' && c2 <= 'F') x2 = c2 - 'A' + 10; - g->emblem_data[i] = (x1<<4) | x2; + if (flag&GS_POSITION){ + strcat(t_info, " positions"); + //printf("- Insert guild %d to guild_position\n",g->guild_id); + for(i=0;iposition[i]; + if (!p->modified) + continue; + Sql_EscapeStringLen(sql_handle, esc_name, p->name, strnlen(p->name, NAME_LENGTH)); + if( SQL_ERROR == Sql_Query(sql_handle, "REPLACE INTO `%s` (`guild_id`,`position`,`name`,`mode`,`exp_mode`) VALUES ('%d','%d','%s','%d','%d')", + guild_position_db, g->guild_id, i, esc_name, p->mode, p->exp_mode) ) + Sql_ShowDebug(sql_handle); + p->modified = GS_POSITION_UNMODIFIED; } + } - str+= len; + if (flag&GS_ALLIANCE) + { + // Delete current alliances + // NOTE: no need to do it on both sides since both guilds in memory had + // their info changed, not to mention this would also mess up oppositions! + // [Skotlex] + //if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id`='%d' OR `alliance_id`='%d'", guild_alliance_db, g->guild_id, g->guild_id) ) + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id`='%d'", guild_alliance_db, g->guild_id) ) + { + Sql_ShowDebug(sql_handle); + } + else + { + //printf("- Insert guild %d to guild_alliance\n",g->guild_id); + for(i=0;ialliance[i]; + if(a->guild_id>0) + { + Sql_EscapeStringLen(sql_handle, esc_name, a->name, strnlen(a->name, NAME_LENGTH)); + if( SQL_ERROR == Sql_Query(sql_handle, "REPLACE INTO `%s` (`guild_id`,`opposition`,`alliance_id`,`name`) " + "VALUES ('%d','%d','%d','%s')", + guild_alliance_db, g->guild_id, a->opposition, a->guild_id, esc_name) ) + Sql_ShowDebug(sql_handle); + } + } + } } - {// load guild alliance info - int guildid; - int opposition; - char name[256]; // only 24 used - int len; + if (flag&GS_EXPULSION){ + strcat(t_info, " expulsions"); + //printf("- Insert guild %d to guild_expulsion\n",g->guild_id); + for(i=0;iexpulsion[i]; + if(e->account_id>0){ + char esc_mes[sizeof(e->mes)*2+1]; + + Sql_EscapeStringLen(sql_handle, esc_name, e->name, strnlen(e->name, NAME_LENGTH)); + Sql_EscapeStringLen(sql_handle, esc_mes, e->mes, strnlen(e->mes, sizeof(e->mes))); + if( SQL_ERROR == Sql_Query(sql_handle, "REPLACE INTO `%s` (`guild_id`,`account_id`,`name`,`mes`) " + "VALUES ('%d','%d','%s','%s')", guild_expulsion_db, g->guild_id, e->account_id, esc_name, esc_mes) ) + Sql_ShowDebug(sql_handle); + } + } + } - if (sscanf(str, "%d\t%n", &c, &len) < 1) - return 1; - str+= len; + if (flag&GS_SKILL){ + strcat(t_info, " skills"); + //printf("- Insert guild %d to guild_skill\n",g->guild_id); + for(i=0;iskill[i].id>0 && g->skill[i].lv>0){ + if( SQL_ERROR == Sql_Query(sql_handle, "REPLACE INTO `%s` (`guild_id`,`id`,`lv`) VALUES ('%d','%d','%d')", + guild_skill_db, g->guild_id, g->skill[i].id, g->skill[i].lv) ) + Sql_ShowDebug(sql_handle); + } + } + } - for(i = 0; i < c; i++) - { - struct guild_alliance* a = &g->alliance[i]; - if (sscanf(str, "%d,%d\t%[^\t]\t%n", &guildid, &opposition, name, &len) < 3) - return 1; + if (save_log) + ShowInfo("Saved guild (%d - %s):%s\n",g->guild_id,g->name,t_info); + return 1; +} - a->guild_id = guildid; - a->opposition = opposition; - safestrncpy(a->name, name, NAME_LENGTH); +// Read guild from sql +struct guild * inter_guild_fromsql(int guild_id) +{ + struct guild *g; + char* data; + size_t len; + char* p; + int i; - str+= len; - } + if( guild_id <= 0 ) + return NULL; + + g = (struct guild*)idb_get(guild_db_, guild_id); + if( g ) + return g; + +#ifdef NOISY + ShowInfo("Guild load request (%d)...\n", guild_id); +#endif + + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT g.`name`,c.`name`,g.`guild_lv`,g.`connect_member`,g.`max_member`,g.`average_lv`,g.`exp`,g.`next_exp`,g.`skill_point`,g.`mes1`,g.`mes2`,g.`emblem_len`,g.`emblem_id`,g.`emblem_data` " + "FROM `%s` g LEFT JOIN `%s` c ON c.`char_id` = g.`char_id` WHERE g.`guild_id`='%d'", guild_db, char_db, guild_id) ) + { + Sql_ShowDebug(sql_handle); + return NULL; } - {// load guild expulsion info - int accountid; - char name[256]; // only 24 used - char message[256]; // only 40 used - int len; - int i; + if( SQL_SUCCESS != Sql_NextRow(sql_handle) ) + return NULL;// Guild does not exists. - if (sscanf(str, "%d\t%n", &c, &len) < 1) - return 1; - str+= len; + CREATE(g, struct guild, 1); - for(i = 0; i < c; i++) - { - struct guild_expulsion *e = &g->expulsion[i]; - if (sscanf(str, "%d,%*d,%*d,%*d\t%[^\t]\t%*[^\t]\t%[^\t]\t%n", &accountid, name, message, &len) < 3) - return 1; + g->guild_id = guild_id; + Sql_GetData(sql_handle, 0, &data, &len); memcpy(g->name, data, min(len, NAME_LENGTH)); + Sql_GetData(sql_handle, 1, &data, &len); memcpy(g->master, data, min(len, NAME_LENGTH)); + Sql_GetData(sql_handle, 2, &data, NULL); g->guild_lv = atoi(data); + Sql_GetData(sql_handle, 3, &data, NULL); g->connect_member = atoi(data); + Sql_GetData(sql_handle, 4, &data, NULL); g->max_member = atoi(data); + if( g->max_member > MAX_GUILD ) + { // Fix reduction of MAX_GUILD [PoW] + ShowWarning("Guild %d:%s specifies higher capacity (%d) than MAX_GUILD (%d)\n", guild_id, g->name, g->max_member, MAX_GUILD); + g->max_member = MAX_GUILD; + } + Sql_GetData(sql_handle, 5, &data, NULL); g->average_lv = atoi(data); + Sql_GetData(sql_handle, 6, &data, NULL); g->exp = strtoull(data, NULL, 10); + Sql_GetData(sql_handle, 7, &data, NULL); g->next_exp = (unsigned int)strtoul(data, NULL, 10); + Sql_GetData(sql_handle, 8, &data, NULL); g->skill_point = atoi(data); + Sql_GetData(sql_handle, 9, &data, &len); memcpy(g->mes1, data, min(len, sizeof(g->mes1))); + Sql_GetData(sql_handle, 10, &data, &len); memcpy(g->mes2, data, min(len, sizeof(g->mes2))); + Sql_GetData(sql_handle, 11, &data, &len); g->emblem_len = atoi(data); + Sql_GetData(sql_handle, 12, &data, &len); g->emblem_id = atoi(data); + Sql_GetData(sql_handle, 13, &data, &len); + // convert emblem data from hexadecimal to binary + //TODO: why not store it in the db as binary directly? [ultramage] + for( i = 0, p = g->emblem_data; i < g->emblem_len; ++i, ++p ) + { + if( *data >= '0' && *data <= '9' ) + *p = *data - '0'; + else if( *data >= 'a' && *data <= 'f' ) + *p = *data - 'a' + 10; + else if( *data >= 'A' && *data <= 'F' ) + *p = *data - 'A' + 10; + *p <<= 4; + ++data; + + if( *data >= '0' && *data <= '9' ) + *p |= *data - '0'; + else if( *data >= 'a' && *data <= 'f' ) + *p |= *data - 'a' + 10; + else if( *data >= 'A' && *data <= 'F' ) + *p |= *data - 'A' + 10; + ++data; + } - e->account_id = accountid; - safestrncpy(e->name, name, sizeof(e->name)); - message[strlen(message)-1] = 0; // remove '#' - safestrncpy(e->mes, message, sizeof(e->mes)); + // load guild member info + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id`,`char_id`,`hair`,`hair_color`,`gender`,`class`,`lv`,`exp`,`exp_payper`,`online`,`position`,`name` " + "FROM `%s` WHERE `guild_id`='%d' ORDER BY `position`", guild_member_db, guild_id) ) + { + Sql_ShowDebug(sql_handle); + aFree(g); + return NULL; + } + for( i = 0; i < g->max_member && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i ) + { + struct guild_member* m = &g->member[i]; + + Sql_GetData(sql_handle, 0, &data, NULL); m->account_id = atoi(data); + Sql_GetData(sql_handle, 1, &data, NULL); m->char_id = atoi(data); + Sql_GetData(sql_handle, 2, &data, NULL); m->hair = atoi(data); + Sql_GetData(sql_handle, 3, &data, NULL); m->hair_color = atoi(data); + Sql_GetData(sql_handle, 4, &data, NULL); m->gender = atoi(data); + Sql_GetData(sql_handle, 5, &data, NULL); m->class_ = atoi(data); + Sql_GetData(sql_handle, 6, &data, NULL); m->lv = atoi(data); + Sql_GetData(sql_handle, 7, &data, NULL); m->exp = strtoull(data, NULL, 10); + Sql_GetData(sql_handle, 8, &data, NULL); m->exp_payper = (unsigned int)atoi(data); + Sql_GetData(sql_handle, 9, &data, NULL); m->online = atoi(data); + Sql_GetData(sql_handle, 10, &data, NULL); m->position = atoi(data); + if( m->position >= MAX_GUILDPOSITION ) // Fix reduction of MAX_GUILDPOSITION [PoW] + m->position = MAX_GUILDPOSITION - 1; + Sql_GetData(sql_handle, 11, &data, &len); memcpy(m->name, data, min(len, NAME_LENGTH)); + m->modified = GS_MEMBER_UNMODIFIED; + } - str+= len; - } + //printf("- Read guild_position %d from sql \n",guild_id); + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `position`,`name`,`mode`,`exp_mode` FROM `%s` WHERE `guild_id`='%d'", guild_position_db, guild_id) ) + { + Sql_ShowDebug(sql_handle); + aFree(g); + return NULL; + } + while( SQL_SUCCESS == Sql_NextRow(sql_handle) ) + { + int position; + struct guild_position* p; + + Sql_GetData(sql_handle, 0, &data, NULL); position = atoi(data); + if( position < 0 || position >= MAX_GUILDPOSITION ) + continue;// invalid position + p = &g->position[position]; + Sql_GetData(sql_handle, 1, &data, &len); memcpy(p->name, data, min(len, NAME_LENGTH)); + Sql_GetData(sql_handle, 2, &data, NULL); p->mode = atoi(data); + Sql_GetData(sql_handle, 3, &data, NULL); p->exp_mode = atoi(data); + p->modified = GS_POSITION_UNMODIFIED; } - {// load guild skill info - int skillid; - int skilllv; - int len; - int i; + //printf("- Read guild_alliance %d from sql \n",guild_id); + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `opposition`,`alliance_id`,`name` FROM `%s` WHERE `guild_id`='%d'", guild_alliance_db, guild_id) ) + { + Sql_ShowDebug(sql_handle); + aFree(g); + return NULL; + } + for( i = 0; i < MAX_GUILDALLIANCE && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i ) + { + struct guild_alliance* a = &g->alliance[i]; - for(i = 0; i < MAX_GUILDSKILL; i++) - { - if (sscanf(str, "%d,%d %n", &skillid, &skilllv, &len) < 2) - break; - g->skill[i].id = skillid; - g->skill[i].lv = skilllv; + Sql_GetData(sql_handle, 0, &data, NULL); a->opposition = atoi(data); + Sql_GetData(sql_handle, 1, &data, NULL); a->guild_id = atoi(data); + Sql_GetData(sql_handle, 2, &data, &len); memcpy(a->name, data, min(len, NAME_LENGTH)); + } - str+= len; - } - str = strchr(str, '\t'); + //printf("- Read guild_expulsion %d from sql \n",guild_id); + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id`,`name`,`mes` FROM `%s` WHERE `guild_id`='%d'", guild_expulsion_db, guild_id) ) + { + Sql_ShowDebug(sql_handle); + aFree(g); + return NULL; } + for( i = 0; i < MAX_GUILDEXPULSION && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i ) + { + struct guild_expulsion *e = &g->expulsion[i]; - return 0; -} + Sql_GetData(sql_handle, 0, &data, NULL); e->account_id = atoi(data); + Sql_GetData(sql_handle, 1, &data, &len); memcpy(e->name, data, min(len, NAME_LENGTH)); + Sql_GetData(sql_handle, 2, &data, &len); memcpy(e->mes, data, min(len, sizeof(e->mes))); + } -#ifndef TXT_SQL_CONVERT -// ギルド城データの文字列への変換 -int inter_guildcastle_tostr(char *str, struct guild_castle *gc) -{ - int len; + //printf("- Read guild_skill %d from sql \n",guild_id); + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `id`,`lv` FROM `%s` WHERE `guild_id`='%d' ORDER BY `id`", guild_skill_db, guild_id) ) + { + Sql_ShowDebug(sql_handle); + aFree(g); + return NULL; + } - len = sprintf(str, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d", - gc->castle_id, gc->guild_id, gc->economy, gc->defense, gc->triggerE, - gc->triggerD, gc->nextTime, gc->payTime, gc->createTime, gc->visibleC, - gc->guardian[0].visible, gc->guardian[1].visible, gc->guardian[2].visible, gc->guardian[3].visible, - gc->guardian[4].visible, gc->guardian[5].visible, gc->guardian[6].visible, gc->guardian[7].visible); + for(i = 0; i < MAX_GUILDSKILL; i++) + { //Skill IDs must always be initialized. [Skotlex] + g->skill[i].id = i + GD_SKILLBASE; + } + + while( SQL_SUCCESS == Sql_NextRow(sql_handle) ) + { + int id; + Sql_GetData(sql_handle, 0, &data, NULL); id = atoi(data) - GD_SKILLBASE; + if( id < 0 && id >= MAX_GUILDSKILL ) + continue;// invalid guild skill + Sql_GetData(sql_handle, 1, &data, NULL); g->skill[id].lv = atoi(data); + } + Sql_FreeResult(sql_handle); + + idb_put(guild_db_, guild_id, g); //Add to cache + g->save_flag |= GS_REMOVE; //But set it to be removed, in case it is not needed for long. + + if (save_log) + ShowInfo("Guild loaded (%d - %s)\n", guild_id, g->name); + return g; +} + +int inter_guildcastle_tosql(struct guild_castle *gc) +{ + // `guild_castle` (`castle_id`, `guild_id`, `economy`, `defense`, `triggerE`, `triggerD`, `nextTime`, `payTime`, `createTime`, `visibleC`, `visibleG0`, `visibleG1`, `visibleG2`, `visibleG3`, `visibleG4`, `visibleG5`, `visibleG6`, `visibleG7`) + + if (gc==NULL) return 0; + #ifdef GUILD_DEBUG +ShowDebug("Save guild_castle (%d)\n", gc->castle_id); + #endif + +// sql_query("DELETE FROM `%s` WHERE `castle_id`='%d'",guild_castle_db, gc->castle_id); + if( SQL_ERROR == Sql_Query(sql_handle, "REPLACE INTO `%s` " + "(`castle_id`, `guild_id`, `economy`, `defense`, `triggerE`, `triggerD`, `nextTime`, `payTime`, `createTime`," + "`visibleC`, `visibleG0`, `visibleG1`, `visibleG2`, `visibleG3`, `visibleG4`, `visibleG5`, `visibleG6`, `visibleG7`)" + "VALUES ('%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d')", + guild_castle_db, gc->castle_id, gc->guild_id, gc->economy, gc->defense, gc->triggerE, gc->triggerD, gc->nextTime, gc->payTime, gc->createTime, gc->visibleC, + gc->guardian[0].visible, gc->guardian[1].visible, gc->guardian[2].visible, gc->guardian[3].visible, gc->guardian[4].visible, gc->guardian[5].visible, gc->guardian[6].visible, gc->guardian[7].visible) ) + Sql_ShowDebug(sql_handle); + + memcpy(&castles[gc->castle_id],gc,sizeof(struct guild_castle)); return 0; } -#endif ///TXT_SQL_CONVERT -// ギルド城データの文字列からの変換 -int inter_guildcastle_fromstr(char *str, struct guild_castle *gc) +// Read guild_castle from sql +int inter_guildcastle_fromsql(int castle_id,struct guild_castle *gc) { - int castleid, guildid, economy, defense, triggerE, triggerD, nextTime, payTime, createTime, visibleC; - int guardian[8]; - int dummy; - - memset(gc, 0, sizeof(struct guild_castle)); - // structure of guild castle with the guardian hp included - if( sscanf(str, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d", - &castleid, &guildid, &economy, &defense, &triggerE, &triggerD, &nextTime, &payTime, &createTime, &visibleC, - &guardian[0], &guardian[1], &guardian[2], &guardian[3], &guardian[4], &guardian[5], &guardian[6], &guardian[7], - &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy) != 26 ) - // structure of guild castle without the hps (current one) - if( sscanf(str, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d", - &castleid, &guildid, &economy, &defense, &triggerE, &triggerD, &nextTime, &payTime, &createTime, &visibleC, - &guardian[0], &guardian[1], &guardian[2], &guardian[3], &guardian[4], &guardian[5], &guardian[6], &guardian[7]) != 18 ) + static int castles_init=0; + char* data; + + if (gc==NULL) return 0; + if (castle_id==-1) return 0; + + if(!castles_init) + { + int i; + for(i=0;icastle_id=castle_id; + if( SQL_SUCCESS != Sql_NextRow(sql_handle) ) + { + Sql_FreeResult(sql_handle); + return 1; //Assume empty castle. + } - gc->castle_id = castleid; - gc->guild_id = guildid; - gc->economy = economy; - gc->defense = defense; - gc->triggerE = triggerE; - gc->triggerD = triggerD; - gc->nextTime = nextTime; - gc->payTime = payTime; - gc->createTime = createTime; - gc->visibleC = visibleC; - gc->guardian[0].visible = guardian[0]; - gc->guardian[1].visible = guardian[1]; - gc->guardian[2].visible = guardian[2]; - gc->guardian[3].visible = guardian[3]; - gc->guardian[4].visible = guardian[4]; - gc->guardian[5].visible = guardian[5]; - gc->guardian[6].visible = guardian[6]; - gc->guardian[7].visible = guardian[7]; + Sql_GetData(sql_handle, 1, &data, NULL); gc->guild_id = atoi(data); + Sql_GetData(sql_handle, 2, &data, NULL); gc->economy = atoi(data); + Sql_GetData(sql_handle, 3, &data, NULL); gc->defense = atoi(data); + Sql_GetData(sql_handle, 4, &data, NULL); gc->triggerE = atoi(data); + Sql_GetData(sql_handle, 5, &data, NULL); gc->triggerD = atoi(data); + Sql_GetData(sql_handle, 6, &data, NULL); gc->nextTime = atoi(data); + Sql_GetData(sql_handle, 7, &data, NULL); gc->payTime = atoi(data); + Sql_GetData(sql_handle, 8, &data, NULL); gc->createTime = atoi(data); + Sql_GetData(sql_handle, 9, &data, NULL); gc->visibleC = atoi(data); + Sql_GetData(sql_handle, 10, &data, NULL); gc->guardian[0].visible = atoi(data); + Sql_GetData(sql_handle, 11, &data, NULL); gc->guardian[1].visible = atoi(data); + Sql_GetData(sql_handle, 12, &data, NULL); gc->guardian[2].visible = atoi(data); + Sql_GetData(sql_handle, 13, &data, NULL); gc->guardian[3].visible = atoi(data); + Sql_GetData(sql_handle, 14, &data, NULL); gc->guardian[4].visible = atoi(data); + Sql_GetData(sql_handle, 15, &data, NULL); gc->guardian[5].visible = atoi(data); + Sql_GetData(sql_handle, 16, &data, NULL); gc->guardian[6].visible = atoi(data); + Sql_GetData(sql_handle, 17, &data, NULL); gc->guardian[7].visible = atoi(data); + + Sql_FreeResult(sql_handle); + memcpy(&castles[castle_id],gc,sizeof(struct guild_castle)); + + if( save_log ) + ShowInfo("Loaded Castle %d (guild %d)\n", castle_id, gc->guild_id); - return 0; + return 1; } -#ifndef TXT_SQL_CONVERT -// ギルド関連データベース読み込み -int inter_guild_readdb(void) + +// Read exp_guild.txt +int inter_guild_ReadEXP(void) { int i; FILE *fp; char line[1024]; - char path[1024]; - - sprintf(path, "%s%s", db_path, "/exp_guild.txt"); - fp = fopen(path, "r"); - if (fp == NULL) { - ShowError("can't read db/exp_guild.txt\n"); + for (i=0;i<100;i++) guild_exp[i]=0; + //this is going to be discussed, temp fix + sprintf(line, "%s/pre-re/exp_guild.txt", db_path); + fp=fopen(line,"r"); + if(fp==NULL){ + ShowError("can't read %s\n", line); return 1; } - i = 0; + i=0; while(fgets(line, sizeof(line), fp) && i < 100) { - if (line[0] == '/' && line[1] == '/') + if(line[0]=='/' && line[1]=='/') continue; - guild_exp[i] = (unsigned int)atof(line); + guild_exp[i]=(unsigned int)atof(line); i++; } fclose(fp); @@ -388,171 +641,172 @@ int inter_guild_readdb(void) return 0; } -// ギルドデータの読み込み -int inter_guild_init() -{ - char line[16384]; - struct guild *g; - struct guild_castle *gc; - FILE *fp; - int i, j, c = 0; - inter_guild_readdb(); - - guild_db = idb_alloc(DB_OPT_RELEASE_DATA); - castle_db = idb_alloc(DB_OPT_RELEASE_DATA); - - if ((fp = fopen(guild_txt,"r")) == NULL) - return 1; - while(fgets(line, sizeof(line), fp)) - { - j = 0; - if (sscanf(line, "%d\t%%newid%%\n%n", &i, &j) == 1 && j > 0 && guild_newid <= i) { - guild_newid = i; - continue; +int inter_guild_CharOnline(int char_id, int guild_id) +{ + struct guild *g; + int i; + + if (guild_id == -1) { + //Get guild_id from the database + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT guild_id FROM `%s` WHERE char_id='%d'", char_db, char_id) ) + { + Sql_ShowDebug(sql_handle); + return 0; } - g = (struct guild *) aCalloc(sizeof(struct guild), 1); - if(g == NULL){ - ShowFatalError("int_guild: out of memory!\n"); - exit(EXIT_FAILURE); + if( SQL_SUCCESS == Sql_NextRow(sql_handle) ) + { + char* data; + + Sql_GetData(sql_handle, 0, &data, NULL); + guild_id = atoi(data); } -// memset(g, 0, sizeof(struct guild)); not needed... - if (inter_guild_fromstr(line, g) == 0 && g->guild_id > 0) { - if (g->guild_id >= guild_newid) - guild_newid = g->guild_id + 1; - idb_put(guild_db, g->guild_id, g); - guild_check_empty(g); - guild_calcinfo(g); - } else { - ShowError("int_guild: broken data [%s] line %d\n", guild_txt, c); - aFree(g); + else + { + guild_id = 0; } - c++; + Sql_FreeResult(sql_handle); + } + if (guild_id == 0) + return 0; //No guild... + + g = inter_guild_fromsql(guild_id); + if(!g) { + ShowError("Character %d's guild %d not found!\n", char_id, guild_id); + return 0; } - fclose(fp); - c = 0;//カウンタ初期化 + //Member has logged in before saving, tell saver not to delete + if(g->save_flag & GS_REMOVE) + g->save_flag &= ~GS_REMOVE; - if ((fp = fopen(castle_txt, "r")) == NULL) { - return 1; + //Set member online + ARR_FIND( 0, g->max_member, i, g->member[i].char_id == char_id ); + if( i < g->max_member ) + { + g->member[i].online = 1; + g->member[i].modified = GS_MEMBER_MODIFIED; } - while(fgets(line, sizeof(line), fp)) + return 1; +} + +int inter_guild_CharOffline(int char_id, int guild_id) +{ + struct guild *g=NULL; + int online_count, i; + + if (guild_id == -1) { - gc = (struct guild_castle *) aCalloc(sizeof(struct guild_castle), 1); - if(gc == NULL){ - ShowFatalError("int_guild: out of memory!\n"); - exit(EXIT_FAILURE); - } -// memset(gc, 0, sizeof(struct guild_castle)); No need... - if (inter_guildcastle_fromstr(line, gc) == 0) { - idb_put(castle_db, gc->castle_id, gc); - } else { - ShowError("int_guild: broken data [%s] line %d\n", castle_txt, c); - aFree(gc); + //Get guild_id from the database + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT guild_id FROM `%s` WHERE char_id='%d'", char_db, char_id) ) + { + Sql_ShowDebug(sql_handle); + return 0; } - c++; - } - fclose(fp); + if( SQL_SUCCESS == Sql_NextRow(sql_handle) ) + { + char* data; - if (!c) { - ShowStatus(" %s - making Default Data...\n", castle_txt); - //デフォルトデータを作成 - for(i = 0; i < MAX_GUILDCASTLE; i++) { - gc = (struct guild_castle *) aCalloc(sizeof(struct guild_castle), 1); - if (gc == NULL) { - ShowFatalError("int_guild: out of memory!\n"); - exit(EXIT_FAILURE); - } - gc->castle_id = i; - idb_put(castle_db, gc->castle_id, gc); + Sql_GetData(sql_handle, 0, &data, NULL); + guild_id = atoi(data); + } + else + { + guild_id = 0; } - ShowStatus(" %s - making done\n",castle_txt); + Sql_FreeResult(sql_handle); + } + if (guild_id == 0) + return 0; //No guild... + + //Character has a guild, set character offline and check if they were the only member online + g = inter_guild_fromsql(guild_id); + if (g == NULL) //Guild not found? return 0; + + //Set member offline + ARR_FIND( 0, g->max_member, i, g->member[i].char_id == char_id ); + if( i < g->max_member ) + { + g->member[i].online = 0; + g->member[i].modified = GS_MEMBER_MODIFIED; } - return 0; -} + online_count = 0; + for( i = 0; i < g->max_member; i++ ) + if( g->member[i].online ) + online_count++; -void inter_guild_final() -{ - castle_db->destroy(castle_db, NULL); - guild_db->destroy(guild_db, NULL); - return; + // Remove guild from memory if no players online + if( online_count == 0 ) + g->save_flag |= GS_REMOVE; + + return 1; } -struct guild *inter_guild_search(int guild_id) +// Initialize guild sql +int inter_guild_sql_init(void) { - return (struct guild*)idb_get(guild_db, guild_id); + //Initialize the guild cache + guild_db_= idb_alloc(DB_OPT_RELEASE_DATA); + + //Read exp file + inter_guild_ReadEXP(); + + add_timer_func_list(guild_save_timer, "guild_save_timer"); + add_timer(gettick() + 10000, guild_save_timer, 0, 0); + return 0; } -// ギルドデータのセーブ -int inter_guild_save() +static int guild_db_final(DBKey key, void *data, va_list ap) { - FILE *fp; - int lock; - DBIterator* iter; - struct guild* g; - struct guild_castle* gc; - - // save guild data - if ((fp = lock_fopen(guild_txt, &lock)) == NULL) { - ShowError("int_guild: can't write [%s] !!! data is lost !!!\n", guild_txt); + struct guild *g = (struct guild*)data; + if (g->save_flag&GS_MASK) { + inter_guild_tosql(g, g->save_flag&GS_MASK); return 1; } - - iter = guild_db->iterator(guild_db); - for( g = (struct guild*)iter->first(iter,NULL); iter->exists(iter); g = (struct guild*)iter->next(iter,NULL) ) - { - char line[16384]; - inter_guild_tostr(line, g); - fprintf(fp, "%s\n", line); - } - iter->destroy(iter); - -// fprintf(fp, "%d\t%%newid%%\n", guild_newid); - lock_fclose(fp, guild_txt, &lock); - - // save castle data - if ((fp = lock_fopen(castle_txt,&lock)) == NULL) { - ShowError("int_guild: can't write [%s] !!! data is lost !!!\n", castle_txt); - return 1; - } - - iter = castle_db->iterator(castle_db); - for( gc = (struct guild_castle*)iter->first(iter,NULL); iter->exists(iter); gc = (struct guild_castle*)iter->next(iter,NULL) ) - { - char line[16384]; - inter_guildcastle_tostr(line, gc); - fprintf(fp, "%s\n", line); - } - iter->destroy(iter); - - lock_fclose(fp, castle_txt, &lock); - return 0; } -// ギルド名検索 -struct guild* search_guildname(char *str) +void inter_guild_sql_final(void) { - DBIterator* iter; - struct guild* g; + guild_db_->destroy(guild_db_, guild_db_final); + return; +} - iter = guild_db->iterator(guild_db); - for( g = (struct guild*)iter->first(iter,NULL); iter->exists(iter); g = (struct guild*)iter->next(iter,NULL) ) +// Get guild_id by its name. Returns 0 if not found, -1 on error. +int search_guildname(char *str) +{ + int guild_id; + char esc_name[NAME_LENGTH*2+1]; + + Sql_EscapeStringLen(sql_handle, esc_name, str, safestrnlen(str, NAME_LENGTH)); + //Lookup guilds with the same name + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT guild_id FROM `%s` WHERE name='%s'", guild_db, esc_name) ) { - if (strcmpi(g->name, str) == 0) - break; + Sql_ShowDebug(sql_handle); + return -1; } - iter->destroy(iter); - return g; + if( SQL_SUCCESS == Sql_NextRow(sql_handle) ) + { + char* data; + + Sql_GetData(sql_handle, 0, &data, NULL); + guild_id = atoi(data); + } + else + { + guild_id = 0; + } + Sql_FreeResult(sql_handle); + return guild_id; } -// ギルドが空かどうかチェック +// Check if guild is empty static bool guild_check_empty(struct guild *g) { int i; @@ -560,11 +814,8 @@ static bool guild_check_empty(struct guild *g) if( i < g->max_member) return false; // not empty - // 誰もいないので解散 - guild_db->foreach(guild_db, guild_break_sub, g->guild_id); - inter_guild_storage_delete(g->guild_id); - mapif_guild_broken(g->guild_id, 0); - idb_remove(guild_db, g->guild_id); + //Let the calling function handle the guild removal in case they need + //to do something else with it before freeing the data. [Skotlex] return true; } @@ -572,79 +823,80 @@ unsigned int guild_nextexp(int level) { if (level == 0) return 1; - if (level > 0 && level < 100) + if (level < 100 && level > 0) // Change by hack return guild_exp[level-1]; return 0; } -// ギルドスキルがあるか確認 -int guild_checkskill(struct guild *g, int id) +int guild_checkskill(struct guild *g,int id) { int idx = id - GD_SKILLBASE; - if(idx < 0 || idx >= MAX_GUILDSKILL) - return 0; return g->skill[idx].lv; } -// ギルドの情報の再計算 int guild_calcinfo(struct guild *g) { - int i, c; + int i,c; unsigned int nextexp; - struct guild before = *g; - - // スキルIDの設定 - for(i = 0; i < MAX_GUILDSKILL; i++) - g->skill[i].id=i+GD_SKILLBASE; + struct guild before = *g; // Save guild current values - // ギルドレベル - if (g->guild_lv <= 0) + if(g->guild_lv<=0) g->guild_lv = 1; nextexp = guild_nextexp(g->guild_lv); - if (nextexp > 0) { - while(g->exp >= nextexp && nextexp > 0) { //fixed guild exp overflow [Kevin] - g->exp -= nextexp; - g->guild_lv++; - g->skill_point++; - nextexp = guild_nextexp(g->guild_lv); - } + + // Consume guild exp and increase guild level + while(g->exp >= nextexp && nextexp > 0){ //fixed guild exp overflow [Kevin] + g->exp-=nextexp; + g->guild_lv++; + g->skill_point++; + nextexp = guild_nextexp(g->guild_lv); } - // ギルドの次の経験値 - g->next_exp = guild_nextexp(g->guild_lv); + // Save next exp step + g->next_exp = nextexp; - // メンバ上限(ギルド拡張適用) - g->max_member = 16 + guild_checkskill(g, GD_EXTENSION) * 6; //Guild Extention skill - currently adds 6 to max per skill lv. + // Set the max number of members, Guild Extention skill - currently adds 6 to max per skill lv. + g->max_member = 16 + guild_checkskill(g, GD_EXTENSION) * 6; if(g->max_member > MAX_GUILD) { ShowError("Guild %d:%s has capacity for too many guild members (%d), max supported is %d\n", g->guild_id, g->name, g->max_member, MAX_GUILD); g->max_member = MAX_GUILD; } + + // Compute the guild average level level + g->average_lv=0; + g->connect_member=0; + for(i=c=0;imax_member;i++) + { + if(g->member[i].account_id>0) + { + if (g->member[i].lv >= 0) + { + g->average_lv+=g->member[i].lv; + c++; + } + else + { + ShowWarning("Guild %d:%s, member %d:%s has an invalid level %d\n", g->guild_id, g->name, g->member[i].char_id, g->member[i].name, g->member[i].lv); + } - // 平均レベルとオンライン人数 - g->average_lv = 0; - g->connect_member = 0; - c = 0; - for(i = 0; i < g->max_member; i++) { - if (g->member[i].account_id > 0) { - g->average_lv += g->member[i].lv; - c++; - if (g->member[i].online > 0) + if(g->member[i].online) g->connect_member++; } } - if(c) g->average_lv /= c; + if(c) + g->average_lv /= c; - // 全データを送る必要がありそう - if (g->max_member != before.max_member || - g->guild_lv != before.guild_lv || - g->skill_point != before.skill_point) { - mapif_guild_info(-1, g); + // Check if guild stats has change + if(g->max_member != before.max_member || g->guild_lv != before.guild_lv || g->skill_point != before.skill_point ) + { + g->save_flag |= GS_LEVEL; + mapif_guild_info(-1,g); return 1; } @@ -652,238 +904,219 @@ int guild_calcinfo(struct guild *g) } //------------------------------------------------------------------- -// map serverへの通信 +// Packet sent to map server -// ギルド作成可否 -int mapif_guild_created(int fd, int account_id, struct guild *g) +int mapif_guild_created(int fd,int account_id,struct guild *g) { WFIFOHEAD(fd, 10); - WFIFOW(fd,0) = 0x3830; - WFIFOL(fd,2) = account_id; - if (g != NULL) { - WFIFOL(fd,6) = g->guild_id; - ShowInfo("Created Guild (%d %s)\n", g->guild_id, g->name); - }else{ - WFIFOL(fd,6) = 0; - } + WFIFOW(fd,0)=0x3830; + WFIFOL(fd,2)=account_id; + if(g != NULL) + { + WFIFOL(fd,6)=g->guild_id; + ShowInfo("int_guild: Guild created (%d - %s)\n",g->guild_id,g->name); + } else + WFIFOL(fd,6)=0; + WFIFOSET(fd,10); return 0; } -// ギルド情報見つからず -int mapif_guild_noinfo(int fd, int guild_id) +// Guild not found +int mapif_guild_noinfo(int fd,int guild_id) { - WFIFOHEAD(fd, 8); - WFIFOW(fd,0) = 0x3831; - WFIFOW(fd,2) = 8; - WFIFOL(fd,4) = guild_id; - WFIFOSET(fd,8); - ShowNotice("int_guild: info not found %d\n", guild_id); - + unsigned char buf[12]; + WBUFW(buf,0)=0x3831; + WBUFW(buf,2)=8; + WBUFL(buf,4)=guild_id; + ShowWarning("int_guild: info not found %d\n",guild_id); + if(fd<0) + mapif_sendall(buf,8); + else + mapif_send(fd,buf,8); return 0; } -// ギルド情報まとめ送り -int mapif_guild_info(int fd, struct guild *g) +// Send guild info +int mapif_guild_info(int fd,struct guild *g) { unsigned char buf[8+sizeof(struct guild)]; - - WBUFW(buf,0) = 0x3831; - memcpy(buf + 4, g, sizeof(struct guild)); - WBUFW(buf,2) = 4 + sizeof(struct guild); - if (fd < 0) - mapif_sendall(buf, WBUFW(buf,2)); + WBUFW(buf,0)=0x3831; + WBUFW(buf,2)=4+sizeof(struct guild); + memcpy(buf+4,g,sizeof(struct guild)); + if(fd<0) + mapif_sendall(buf,WBUFW(buf,2)); else - mapif_send(fd, buf, WBUFW(buf,2)); - + mapif_send(fd,buf,WBUFW(buf,2)); return 0; } -// メンバ追加可否 -int mapif_guild_memberadded(int fd, int guild_id, int account_id, int char_id, int flag) +// ACK member add +int mapif_guild_memberadded(int fd,int guild_id,int account_id,int char_id,int flag) { WFIFOHEAD(fd, 15); - WFIFOW(fd,0) = 0x3832; - WFIFOL(fd,2) = guild_id; - WFIFOL(fd,6) = account_id; - WFIFOL(fd,10) = char_id; - WFIFOB(fd,14) = flag; - WFIFOSET(fd, 15); - + WFIFOW(fd,0)=0x3832; + WFIFOL(fd,2)=guild_id; + WFIFOL(fd,6)=account_id; + WFIFOL(fd,10)=char_id; + WFIFOB(fd,14)=flag; + WFIFOSET(fd,15); return 0; } -// 脱退/追放通知 -int mapif_guild_withdraw(int guild_id, int account_id, int char_id, int flag, const char *name, const char *mes) +// ACK member leave +int mapif_guild_withdraw(int guild_id,int account_id,int char_id,int flag, const char *name, const char *mes) { - unsigned char buf[79]; - - WBUFW(buf, 0) = 0x3834; - WBUFL(buf, 2) = guild_id; - WBUFL(buf, 6) = account_id; - WBUFL(buf,10) = char_id; - WBUFB(buf,14) = flag; - memcpy(WBUFP(buf,15), mes, 40); - memcpy(WBUFP(buf,55), name, NAME_LENGTH); - mapif_sendall(buf, 55+NAME_LENGTH); -// mapif_sendall(buf, 79); - ShowInfo("Character left guild (Guild %d, %d - %s: %s)\n", guild_id, account_id, name, mes); - + unsigned char buf[55+NAME_LENGTH]; + WBUFW(buf, 0)=0x3834; + WBUFL(buf, 2)=guild_id; + WBUFL(buf, 6)=account_id; + WBUFL(buf,10)=char_id; + WBUFB(buf,14)=flag; + memcpy(WBUFP(buf,15),mes,40); + memcpy(WBUFP(buf,55),name,NAME_LENGTH); + mapif_sendall(buf,55+NAME_LENGTH); + ShowInfo("int_guild: guild withdraw (%d - %d: %s - %s)\n",guild_id,account_id,name,mes); return 0; } -// オンライン状態とLv更新通知 -int mapif_guild_memberinfoshort(struct guild *g, int idx) +// Send short member's info +int mapif_guild_memberinfoshort(struct guild *g,int idx) { unsigned char buf[19]; - - WBUFW(buf, 0) = 0x3835; - WBUFL(buf, 2) = g->guild_id; - WBUFL(buf, 6) = g->member[idx].account_id; - WBUFL(buf,10) = g->member[idx].char_id; - WBUFB(buf,14) = (unsigned char)g->member[idx].online; - WBUFW(buf,15) = g->member[idx].lv; - WBUFW(buf,17) = g->member[idx].class_; - mapif_sendall(buf, 19); + WBUFW(buf, 0)=0x3835; + WBUFL(buf, 2)=g->guild_id; + WBUFL(buf, 6)=g->member[idx].account_id; + WBUFL(buf,10)=g->member[idx].char_id; + WBUFB(buf,14)=(unsigned char)g->member[idx].online; + WBUFW(buf,15)=g->member[idx].lv; + WBUFW(buf,17)=g->member[idx].class_; + mapif_sendall(buf,19); return 0; } -// 解散通知 -int mapif_guild_broken(int guild_id, int flag) +// Send guild broken +int mapif_guild_broken(int guild_id,int flag) { unsigned char buf[7]; - - WBUFW(buf,0) = 0x3836; - WBUFL(buf,2) = guild_id; - WBUFB(buf,6) = flag; - mapif_sendall(buf, 7); - ShowInfo("Guild Break (%d)\n", guild_id); - + WBUFW(buf,0)=0x3836; + WBUFL(buf,2)=guild_id; + WBUFB(buf,6)=flag; + mapif_sendall(buf,7); + ShowInfo("int_guild: Guild broken (%d)\n",guild_id); return 0; } -// ギルド内発言 -int mapif_guild_message(int guild_id, int account_id, char *mes, int len, int sfd) +// Send guild message +int mapif_guild_message(int guild_id,int account_id,char *mes,int len, int sfd) { - unsigned char buf[2048]; - - WBUFW(buf,0) = 0x3837; - WBUFW(buf,2) = len + 12; - WBUFL(buf,4) = guild_id; - WBUFL(buf,8) = account_id; - memcpy(WBUFP(buf,12), mes, len); - mapif_sendallwos(sfd, buf, len + 12); - + unsigned char buf[512]; + if (len > 500) + len = 500; + WBUFW(buf,0)=0x3837; + WBUFW(buf,2)=len+12; + WBUFL(buf,4)=guild_id; + WBUFL(buf,8)=account_id; + memcpy(WBUFP(buf,12),mes,len); + mapif_sendallwos(sfd, buf,len+12); return 0; } -// ギルド基本情報変更通知 -int mapif_guild_basicinfochanged(int guild_id, int type, const void *data, int len) +// Send basic info +int mapif_guild_basicinfochanged(int guild_id,int type,const void *data,int len) { unsigned char buf[2048]; - - WBUFW(buf,0) = 0x3839; - WBUFW(buf,2) = len+10; - WBUFL(buf,4) = guild_id; - WBUFW(buf,8) = type; + if (len > 2038) + len = 2038; + WBUFW(buf, 0)=0x3839; + WBUFW(buf, 2)=len+10; + WBUFL(buf, 4)=guild_id; + WBUFW(buf, 8)=type; memcpy(WBUFP(buf,10),data,len); mapif_sendall(buf,len+10); return 0; } -// ギルドメンバ情報変更通知 -int mapif_guild_memberinfochanged(int guild_id, int account_id, int char_id, int type, const void *data, int len) +// Send member info +int mapif_guild_memberinfochanged(int guild_id,int account_id,int char_id, int type,const void *data,int len) { - unsigned char buf[4096]; - - WBUFW(buf, 0) = 0x383a; - WBUFW(buf, 2) = len + 18; - WBUFL(buf, 4) = guild_id; - WBUFL(buf, 8) = account_id; - WBUFL(buf,12) = char_id; - WBUFW(buf,16) = type; - memcpy(WBUFP(buf,18), data, len); + unsigned char buf[2048]; + if (len > 2030) + len = 2030; + WBUFW(buf, 0)=0x383a; + WBUFW(buf, 2)=len+18; + WBUFL(buf, 4)=guild_id; + WBUFL(buf, 8)=account_id; + WBUFL(buf,12)=char_id; + WBUFW(buf,16)=type; + memcpy(WBUFP(buf,18),data,len); mapif_sendall(buf,len+18); - return 0; } -// ギルドスキルアップ通知 -int mapif_guild_skillupack(int guild_id, int skill_num, int account_id) +// ACK guild skill up +int mapif_guild_skillupack(int guild_id,int skill_num,int account_id) { unsigned char buf[14]; - - WBUFW(buf, 0) = 0x383c; - WBUFL(buf, 2) = guild_id; - WBUFL(buf, 6) = skill_num; - WBUFL(buf,10) = account_id; - mapif_sendall(buf, 14); - + WBUFW(buf, 0)=0x383c; + WBUFL(buf, 2)=guild_id; + WBUFL(buf, 6)=skill_num; + WBUFL(buf,10)=account_id; + mapif_sendall(buf,14); return 0; } -// ギルド同盟/敵対通知 -int mapif_guild_alliance(int guild_id1, int guild_id2, int account_id1, int account_id2, int flag, const char *name1, const char *name2) +// ACK guild alliance +int mapif_guild_alliance(int guild_id1,int guild_id2,int account_id1,int account_id2,int flag,const char *name1,const char *name2) { - unsigned char buf[67]; - - WBUFW(buf, 0) = 0x383d; - WBUFL(buf, 2) = guild_id1; - WBUFL(buf, 6) = guild_id2; - WBUFL(buf,10) = account_id1; - WBUFL(buf,14) = account_id2; - WBUFB(buf,18) = flag; - memcpy(WBUFP(buf,19), name1, NAME_LENGTH); - memcpy(WBUFP(buf,19+NAME_LENGTH), name2, NAME_LENGTH); + unsigned char buf[19+2*NAME_LENGTH]; + WBUFW(buf, 0)=0x383d; + WBUFL(buf, 2)=guild_id1; + WBUFL(buf, 6)=guild_id2; + WBUFL(buf,10)=account_id1; + WBUFL(buf,14)=account_id2; + WBUFB(buf,18)=flag; + memcpy(WBUFP(buf,19),name1,NAME_LENGTH); + memcpy(WBUFP(buf,19+NAME_LENGTH),name2,NAME_LENGTH); mapif_sendall(buf,19+2*NAME_LENGTH); -/* - memcpy(WBUFP(buf,43), name2, NAME_LENGTH); - mapif_sendall(buf, 67); -*/ return 0; } -// ギルド役職変更通知 -int mapif_guild_position(struct guild *g, int idx) +// Send a guild position desc +int mapif_guild_position(struct guild *g,int idx) { - unsigned char buf[2048]; - - WBUFW(buf,0) = 0x383b; - WBUFW(buf,2) = sizeof(struct guild_position) + 12; - WBUFL(buf,4) = g->guild_id; - WBUFL(buf,8) = idx; - memcpy(WBUFP(buf,12), &g->position[idx], sizeof(struct guild_position)); - mapif_sendall(buf, WBUFW(buf,2)); - + unsigned char buf[12 + sizeof(struct guild_position)]; + WBUFW(buf,0)=0x383b; + WBUFW(buf,2)=sizeof(struct guild_position)+12; + WBUFL(buf,4)=g->guild_id; + WBUFL(buf,8)=idx; + memcpy(WBUFP(buf,12),&g->position[idx],sizeof(struct guild_position)); + mapif_sendall(buf,WBUFW(buf,2)); return 0; } -// ギルド告知変更通知 +// Send the guild notice int mapif_guild_notice(struct guild *g) { - unsigned char buf[186]; - - WBUFW(buf,0) = 0x383e; - WBUFL(buf,2) = g->guild_id; - memcpy(WBUFP(buf,6), g->mes1, MAX_GUILDMES1); - memcpy(WBUFP(buf,66), g->mes2, MAX_GUILDMES2); - mapif_sendall(buf, 186); - + unsigned char buf[256]; + WBUFW(buf,0)=0x383e; + WBUFL(buf,2)=g->guild_id; + memcpy(WBUFP(buf,6),g->mes1,MAX_GUILDMES1); + memcpy(WBUFP(buf,66),g->mes2,MAX_GUILDMES2); + mapif_sendall(buf,186); return 0; } -// ギルドエンブレム変更通知 +// Send emblem data int mapif_guild_emblem(struct guild *g) { - unsigned char buf[2048]; - - WBUFW(buf,0) = 0x383f; - WBUFW(buf,2) = g->emblem_len + 12; - WBUFL(buf,4) = g->guild_id; - WBUFL(buf,8) = g->emblem_id; - memcpy(WBUFP(buf,12), g->emblem_data, g->emblem_len); - mapif_sendall(buf, WBUFW(buf,2)); - + unsigned char buf[12 + sizeof(g->emblem_data)]; + WBUFW(buf,0)=0x383f; + WBUFW(buf,2)=g->emblem_len+12; + WBUFL(buf,4)=g->guild_id; + WBUFL(buf,8)=g->emblem_id; + memcpy(WBUFP(buf,12),g->emblem_data,g->emblem_len); + mapif_sendall(buf,WBUFW(buf,2)); return 0; } @@ -898,76 +1131,94 @@ int mapif_guild_master_changed(struct guild *g, int aid, int cid) return 0; } -int mapif_guild_castle_dataload(int castle_id, int index, int value) +int mapif_guild_castle_dataload(int castle_id,int index,int value) { unsigned char buf[9]; - - WBUFW(buf,0) = 0x3840; - WBUFW(buf,2) = castle_id; - WBUFB(buf,4) = index; - WBUFL(buf,5) = value; + WBUFW(buf, 0)=0x3840; + WBUFW(buf, 2)=castle_id; + WBUFB(buf, 4)=index; + WBUFL(buf, 5)=value; mapif_sendall(buf,9); - return 0; } -int mapif_guild_castle_datasave(int castle_id, int index, int value) +int mapif_guild_castle_datasave(int castle_id,int index,int value) { unsigned char buf[9]; - - WBUFW(buf,0) = 0x3841; - WBUFW(buf,2) = castle_id; - WBUFB(buf,4) = index; - WBUFL(buf,5) = value; + WBUFW(buf, 0)=0x3841; + WBUFW(buf, 2)=castle_id; + WBUFB(buf, 4)=index; + WBUFL(buf, 5)=value; mapif_sendall(buf,9); - return 0; } int mapif_guild_castle_alldataload(int fd) { - DBIterator* iter; - struct guild_castle* gc; - int len = 4; + struct guild_castle s_gc; + struct guild_castle* gc = &s_gc; + int i; + int len; + char* data; WFIFOHEAD(fd, 4 + MAX_GUILDCASTLE*sizeof(struct guild_castle)); - WFIFOW(fd,0) = 0x3842; - iter = castle_db->iterator(castle_db); - for( gc = (struct guild_castle*)iter->first(iter,NULL); iter->exists(iter); gc = (struct guild_castle*)iter->next(iter,NULL) ) + WFIFOW(fd, 0) = 0x3842; + if( SQL_ERROR == Sql_Query(sql_handle, + "SELECT `castle_id`, `guild_id`, `economy`, `defense`, `triggerE`, `triggerD`, `nextTime`, `payTime`, `createTime`," + " `visibleC`, `visibleG0`, `visibleG1`, `visibleG2`, `visibleG3`, `visibleG4`, `visibleG5`, `visibleG6`, `visibleG7`" + " FROM `%s` ORDER BY `castle_id`", guild_castle_db) ) + Sql_ShowDebug(sql_handle); + for( i = 0, len = 4; i < MAX_GUILDCASTLE && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i ) { - memcpy(WFIFOP(fd,len), gc, sizeof(struct guild_castle)); + memset(gc, 0, sizeof(struct guild_castle)); + + Sql_GetData(sql_handle, 0, &data, NULL); gc->castle_id = atoi(data); + Sql_GetData(sql_handle, 1, &data, NULL); gc->guild_id = atoi(data); + Sql_GetData(sql_handle, 2, &data, NULL); gc->economy = atoi(data); + Sql_GetData(sql_handle, 3, &data, NULL); gc->defense = atoi(data); + Sql_GetData(sql_handle, 4, &data, NULL); gc->triggerE = atoi(data); + Sql_GetData(sql_handle, 5, &data, NULL); gc->triggerD = atoi(data); + Sql_GetData(sql_handle, 6, &data, NULL); gc->nextTime = atoi(data); + Sql_GetData(sql_handle, 7, &data, NULL); gc->payTime = atoi(data); + Sql_GetData(sql_handle, 8, &data, NULL); gc->createTime = atoi(data); + Sql_GetData(sql_handle, 9, &data, NULL); gc->visibleC = atoi(data); + Sql_GetData(sql_handle, 10, &data, NULL); gc->guardian[0].visible = atoi(data); + Sql_GetData(sql_handle, 11, &data, NULL); gc->guardian[1].visible = atoi(data); + Sql_GetData(sql_handle, 12, &data, NULL); gc->guardian[2].visible = atoi(data); + Sql_GetData(sql_handle, 13, &data, NULL); gc->guardian[3].visible = atoi(data); + Sql_GetData(sql_handle, 14, &data, NULL); gc->guardian[4].visible = atoi(data); + Sql_GetData(sql_handle, 15, &data, NULL); gc->guardian[5].visible = atoi(data); + Sql_GetData(sql_handle, 16, &data, NULL); gc->guardian[6].visible = atoi(data); + Sql_GetData(sql_handle, 17, &data, NULL); gc->guardian[7].visible = atoi(data); + + memcpy(WFIFOP(fd, len), gc, sizeof(struct guild_castle)); len += sizeof(struct guild_castle); } - iter->destroy(iter); - WFIFOW(fd,2) = len; + Sql_FreeResult(sql_handle); + WFIFOW(fd, 2) = len; WFIFOSET(fd, len); - + return 0; } + //------------------------------------------------------------------- -// map serverからの通信 +// Packet received from map server + // ギルド作成要求 -int mapif_parse_CreateGuild(int fd, int account_id, char *name, struct guild_member *master) +int mapif_parse_CreateGuild(int fd,int account_id,char *name,struct guild_member *master) { struct guild *g; - int i; - - for(i = 0; i < NAME_LENGTH && name[i]; i++) { - if (!(name[i] & 0xe0) || name[i] == 0x7f) { - ShowInfo("Create Guild: illegal guild name [%s]\n", name); - mapif_guild_created(fd, account_id, NULL); - return 0; - } - } - - if ((g = search_guildname(name)) != NULL) { - ShowInfo("Create Guild: same name guild exists [%s]\n", name); - mapif_guild_created(fd, account_id, NULL); + int i=0; +#ifdef NOISY + ShowInfo("Creating Guild (%s)\n", name); +#endif + if(search_guildname(name) != 0){ + ShowInfo("int_guild: guild with same name exists [%s]\n",name); + mapif_guild_created(fd,account_id,NULL); return 0; } - // Check Authorised letters/symbols in the name of the character if (char_name_option == 1) { // only letters/symbols in char_name_letters are authorised for (i = 0; i < NAME_LENGTH && name[i]; i++) @@ -983,81 +1234,104 @@ int mapif_parse_CreateGuild(int fd, int account_id, char *name, struct guild_mem } } - g = (struct guild *) aCalloc(sizeof(struct guild), 1); - if (g == NULL) { - ShowFatalError("int_guild: CreateGuild: out of memory !\n"); - mapif_guild_created(fd, account_id, NULL); - exit(EXIT_FAILURE); - } -// memset(g, 0, sizeof(struct guild)); Meh... - g->guild_id = guild_newid++; - memcpy(g->name, name, NAME_LENGTH); - memcpy(g->master, master->name, NAME_LENGTH); - memcpy(&g->member[0], master, sizeof(struct guild_member)); - - g->position[0].mode = 0x11; - strcpy(g->position[ 0].name, "GuildMaster"); - strcpy(g->position[MAX_GUILDPOSITION-1].name, "Newbie"); - for(i = 1; i < MAX_GUILDPOSITION-1; i++) - sprintf(g->position[i].name, "Position %d", i + 1); - - // ここでギルド情報計算が必要と思われる - g->max_member = 16; - g->average_lv = master->lv; - g->connect_member = 1; - for(i = 0; i < MAX_GUILDSKILL; i++) - g->skill[i].id=i + GD_SKILLBASE; + g = (struct guild *)aMalloc(sizeof(struct guild)); + memset(g,0,sizeof(struct guild)); + + memcpy(g->name,name,NAME_LENGTH); + memcpy(g->master,master->name,NAME_LENGTH); + memcpy(&g->member[0],master,sizeof(struct guild_member)); + g->member[0].modified = GS_MEMBER_MODIFIED; + + // Set default positions + g->position[0].mode=0x11; + strcpy(g->position[0].name,"GuildMaster"); + strcpy(g->position[MAX_GUILDPOSITION-1].name,"Newbie"); + g->position[0].modified = g->position[MAX_GUILDPOSITION-1].modified = GS_POSITION_MODIFIED; + for(i=1;iposition[i].name,"Position %d",i+1); + g->position[i].modified = GS_POSITION_MODIFIED; + } - idb_put(guild_db, g->guild_id, g); + // Initialize guild property + g->max_member=16; + g->average_lv=master->lv; + g->connect_member=1; - mapif_guild_created(fd, account_id, g); - mapif_guild_info(fd, g); + for(i=0;iskill[i].id=i + GD_SKILLBASE; + g->guild_id= -1; //Request to create guild. + + // Create the guild + if (!inter_guild_tosql(g,GS_BASIC|GS_POSITION|GS_SKILL)) { + //Failed to Create guild.... + ShowError("Failed to create Guild %s (Guild Master: %s)\n", g->name, g->master); + mapif_guild_created(fd,account_id,NULL); + aFree(g); + return 0; + } + ShowInfo("Created Guild %d - %s (Guild Master: %s)\n", g->guild_id, g->name, g->master); + + //Add to cache + idb_put(guild_db_, g->guild_id, g); + + // Report to client + mapif_guild_created(fd,account_id,g); + mapif_guild_info(fd,g); if(log_inter) inter_log("guild %s (id=%d) created by master %s (id=%d)\n", - name, g->guild_id, master->name, master->account_id); + name, g->guild_id, master->name, master->account_id ); return 0; } -// ギルド情報要求 -int mapif_parse_GuildInfo(int fd, int guild_id) +// Return guild info to client +int mapif_parse_GuildInfo(int fd,int guild_id) { - struct guild *g; - - g = (struct guild*)idb_get(guild_db, guild_id); - if (g != NULL){ - guild_calcinfo(g); - mapif_guild_info(fd, g); - } else - mapif_guild_noinfo(fd, guild_id); - + struct guild * g = inter_guild_fromsql(guild_id); //We use this because on start-up the info of castle-owned guilds is requied. [Skotlex] + if(g) + { + if (!guild_calcinfo(g)) + mapif_guild_info(fd,g); + } + else + mapif_guild_noinfo(fd,guild_id); // Failed to load info return 0; } -// ギルドメンバ追加要求 -int mapif_parse_GuildAddMember(int fd, int guild_id, struct guild_member *m) +// Add member to guild +int mapif_parse_GuildAddMember(int fd,int guild_id,struct guild_member *m) { - struct guild *g; + struct guild * g; int i; - g = (struct guild*)idb_get(guild_db, guild_id); - if (g == NULL) { - mapif_guild_memberadded(fd, guild_id, m->account_id, m->char_id, 1); + g = inter_guild_fromsql(guild_id); + if(g==NULL){ + // Failed to add + mapif_guild_memberadded(fd,guild_id,m->account_id,m->char_id,1); return 0; } - ARR_FIND( 0, g->max_member, i, g->member[i].account_id == 0 ); - if( i < g->max_member ) + // Find an empty slot + for(i=0;imax_member;i++) { - memcpy(&g->member[i], m, sizeof(struct guild_member)); - mapif_guild_memberadded(fd, guild_id, m->account_id, m->char_id, 0); - guild_calcinfo(g); - mapif_guild_info(-1, g); + if(g->member[i].account_id==0) + { + memcpy(&g->member[i],m,sizeof(struct guild_member)); + g->member[i].modified = (GS_MEMBER_NEW | GS_MEMBER_MODIFIED); + mapif_guild_memberadded(fd,guild_id,m->account_id,m->char_id,0); + if (!guild_calcinfo(g)) //Send members if it was not invoked. + mapif_guild_info(-1,g); + + g->save_flag |= GS_MEMBER; + if (g->save_flag&GS_REMOVE) + g->save_flag&=~GS_REMOVE; + return 0; + } } - else - mapif_guild_memberadded(fd, guild_id, m->account_id, m->char_id, 1); + // Failed to add + mapif_guild_memberadded(fd,guild_id,m->account_id,m->char_id,1); return 0; } @@ -1066,10 +1340,13 @@ int mapif_parse_GuildLeave(int fd, int guild_id, int account_id, int char_id, in { int i, j; - struct guild* g = (struct guild*)idb_get(guild_db, guild_id); + struct guild* g = inter_guild_fromsql(guild_id); if( g == NULL ) { - //TODO + // Unknown guild, just update the player + if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `guild_id`='0' WHERE `account_id`='%d' AND `char_id`='%d'", char_db, account_id, char_id) ) + Sql_ShowDebug(sql_handle); + // mapif_guild_withdraw(guild_id,account_id,char_id,flag,g->member[i].name,mes); return 0; } @@ -1082,13 +1359,15 @@ int mapif_parse_GuildLeave(int fd, int guild_id, int account_id, int char_id, in } if( flag ) - { // 追放の場合追放リストに入れる + { // Write expulsion reason + // Find an empty slot ARR_FIND( 0, MAX_GUILDEXPULSION, j, g->expulsion[j].account_id == 0 ); - if (j == MAX_GUILDEXPULSION) - { // 一杯なので古いのを消す - for(j = 0; j < MAX_GUILDEXPULSION - 1; j++) + if( j == MAX_GUILDEXPULSION ) + { + // Expulsion list is full, flush the oldest one + for( j = 0; j < MAX_GUILDEXPULSION - 1; j++ ) g->expulsion[j] = g->expulsion[j+1]; - j = MAX_GUILDEXPULSION - 1; + j = MAX_GUILDEXPULSION-1; } // Save the expulsion entry g->expulsion[j].account_id = account_id; @@ -1096,41 +1375,54 @@ int mapif_parse_GuildLeave(int fd, int guild_id, int account_id, int char_id, in safestrncpy(g->expulsion[j].mes, mes, 40); } - mapif_guild_withdraw(guild_id, account_id, char_id, flag, g->member[i].name, mes); + mapif_guild_withdraw(guild_id,account_id,char_id,flag,g->member[i].name,mes); + inter_guild_removemember_tosql(g->member[i].account_id,g->member[i].char_id); - memset(&g->member[i], 0, sizeof(struct guild_member)); + memset(&g->member[i],0,sizeof(struct guild_member)); - if (guild_check_empty(g) == 0) - mapif_guild_info(-1,g);// まだ人がいるのでデータ送信 + if( guild_check_empty(g) ) + mapif_parse_BreakGuild(-1,guild_id); //Break the guild. + else { + //Update member info. + if (!guild_calcinfo(g)) + mapif_guild_info(fd,g); + g->save_flag |= GS_EXPULSION; + } return 0; } -// オンライン/Lv更新 -int mapif_parse_GuildChangeMemberInfoShort(int fd, int guild_id, int account_id, int char_id, int online, int lv, int class_) +// Change member info +int mapif_parse_GuildChangeMemberInfoShort(int fd,int guild_id,int account_id,int char_id,int online,int lv,int class_) { - struct guild *g; - int i, sum, c; + // Could speed up by manipulating only guild_member + struct guild * g; + int i,sum,c; + int prev_count, prev_alv; - g = (struct guild*)idb_get(guild_db, guild_id); - if (g == NULL) + g = inter_guild_fromsql(guild_id); + if(g==NULL) return 0; - + ARR_FIND( 0, g->max_member, i, g->member[i].account_id == account_id && g->member[i].char_id == char_id ); if( i < g->max_member ) { - g->member[i].online = online; - g->member[i].lv = lv; - g->member[i].class_ = class_; - mapif_guild_memberinfoshort(g, i); + g->member[i].online = online; + g->member[i].lv = lv; + g->member[i].class_ = class_; + g->member[i].modified = GS_MEMBER_MODIFIED; + mapif_guild_memberinfoshort(g,i); } + prev_count = g->connect_member; + prev_alv = g->average_lv; + g->average_lv = 0; g->connect_member = 0; - c = 0; // member count - sum = 0; // total sum of base levels + c = 0; + sum = 0; - for(i = 0; i < g->max_member; i++) + for( i = 0; i < g->max_member; i++ ) { if( g->member[i].account_id > 0 ) { @@ -1142,198 +1434,287 @@ int mapif_parse_GuildChangeMemberInfoShort(int fd, int guild_id, int account_id, } if( c ) // this check should always succeed... + { g->average_lv = sum / c; - - //FIXME: how about sending a mapif_guild_info() update to the mapserver? [ultramage] - + if( g->connect_member != prev_count || g->average_lv != prev_alv ) + g->save_flag |= GS_CONNECT; + if( g->save_flag & GS_REMOVE ) + g->save_flag &= ~GS_REMOVE; + } + g->save_flag |= GS_MEMBER; //Update guild member data return 0; } -// ギルド解散処理用(同盟/敵対を解除) -int guild_break_sub(DBKey key, void *data, va_list ap) +// BreakGuild +int mapif_parse_BreakGuild(int fd,int guild_id) { - struct guild *g = (struct guild *)data; - int guild_id = va_arg(ap, int); - int i; + struct guild * g; + + g = inter_guild_fromsql(guild_id); + if(g==NULL) + return 0; - for(i = 0; i < MAX_GUILDALLIANCE; i++) { - if (g->alliance[i].guild_id == guild_id) - g->alliance[i].guild_id = 0; - } - return 0; -} + // Delete guild from sql + //printf("- Delete guild %d from guild\n",guild_id); + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d'", guild_db, guild_id) ) + Sql_ShowDebug(sql_handle); -// ギルド解散要求 -int mapif_parse_BreakGuild(int fd, int guild_id) -{ - struct guild *g; + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d'", guild_member_db, guild_id) ) + Sql_ShowDebug(sql_handle); - g = (struct guild*)idb_get(guild_db, guild_id); - if(g == NULL) - return 0; + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d'", guild_castle_db, guild_id) ) + Sql_ShowDebug(sql_handle); + + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d'", guild_storage_db, guild_id) ) + Sql_ShowDebug(sql_handle); + + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d' OR `alliance_id` = '%d'", guild_alliance_db, guild_id, guild_id) ) + Sql_ShowDebug(sql_handle); - guild_db->foreach(guild_db, guild_break_sub, guild_id); - inter_guild_storage_delete(guild_id); - mapif_guild_broken(guild_id, 0); + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d'", guild_position_db, guild_id) ) + Sql_ShowDebug(sql_handle); + + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d'", guild_skill_db, guild_id) ) + Sql_ShowDebug(sql_handle); + + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d'", guild_expulsion_db, guild_id) ) + Sql_ShowDebug(sql_handle); + + //printf("- Update guild %d of char\n",guild_id); + if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `guild_id`='0' WHERE `guild_id`='%d'", char_db, guild_id) ) + Sql_ShowDebug(sql_handle); + + mapif_guild_broken(guild_id,0); if(log_inter) - inter_log("guild %s (id=%d) broken\n", g->name, guild_id); + inter_log("guild %s (id=%d) broken\n",g->name,guild_id); - idb_remove(guild_db, guild_id); + //Remove the guild from memory. [Skotlex] + idb_remove(guild_db_, guild_id); return 0; } -// ギルドメッセージ送信 -int mapif_parse_GuildMessage(int fd, int guild_id, int account_id, char *mes, int len) +// Forward Guild message to others map servers +int mapif_parse_GuildMessage(int fd,int guild_id,int account_id,char *mes,int len) { - return mapif_guild_message(guild_id, account_id, mes, len, fd); + return mapif_guild_message(guild_id,account_id,mes,len, fd); } -// ギルド基本データ変更要求 -int mapif_parse_GuildBasicInfoChange(int fd, int guild_id, int type, const char *data, int len) +// Modification of the guild +int mapif_parse_GuildBasicInfoChange(int fd,int guild_id,int type,const char *data,int len) { - struct guild *g; - short dw = *((short *)data); - - g = (struct guild*)idb_get(guild_db, guild_id); - if (g == NULL) + struct guild * g; + short dw=*((short *)data); + g = inter_guild_fromsql(guild_id); + if(g==NULL) return 0; - switch(type) { - case GBI_GUILDLV: - if (dw > 0 && g->guild_lv + dw <= 50) { - g->guild_lv+=dw; - g->skill_point+=dw; - } else if (dw < 0 && g->guild_lv + dw >= 1) - g->guild_lv += dw; - mapif_guild_info(-1, g); - return 0; - default: - ShowError("int_guild: GuildBasicInfoChange: Unknown type %d\n", type); - break; + switch(type) + { + case GBI_GUILDLV: + if(dw>0 && g->guild_lv+dw<=50) + { + g->guild_lv+=dw; + g->skill_point+=dw; + } + else if(dw<0 && g->guild_lv+dw>=1) + g->guild_lv+=dw; + mapif_guild_info(-1,g); + g->save_flag |= GS_LEVEL; + return 0; + default: + ShowError("int_guild: GuildBasicInfoChange: Unknown type %d\n",type); + break; } - mapif_guild_basicinfochanged(guild_id, type, data, len); - + mapif_guild_basicinfochanged(guild_id,type,data,len); return 0; } -// ギルドメンバデータ変更要求 -int mapif_parse_GuildMemberInfoChange(int fd, int guild_id, int account_id, int char_id, int type, const char *data, int len) +// Modification of the guild +int mapif_parse_GuildMemberInfoChange(int fd,int guild_id,int account_id,int char_id,int type,const char *data,int len) { + // Could make some improvement in speed, because only change guild_member int i; - struct guild *g; + struct guild * g; - g = (struct guild*)idb_get(guild_db, guild_id); - if(g == NULL) + g = inter_guild_fromsql(guild_id); + if(g==NULL) return 0; - for(i = 0; i < g->max_member; i++) - if (g->member[i].account_id == account_id && g->member[i].char_id == char_id) - break; - if (i == g->max_member) { - ShowWarning("int_guild: GuildMemberChange: Not found %d,%d in %d[%s]\n", account_id, char_id, guild_id, g->name); + // Search the member + for(i=0;imax_member;i++) + if( g->member[i].account_id==account_id && + g->member[i].char_id==char_id ) + break; + + // Not Found + if(i==g->max_member){ + ShowWarning("int_guild: GuildMemberChange: Not found %d,%d in guild (%d - %s)\n", + account_id,char_id,guild_id,g->name); return 0; } - switch(type) { - case GMI_POSITION: // 役職 - g->member[i].position = *((short *)data); - mapif_guild_memberinfochanged(guild_id, account_id, char_id, type, data, len); - break; - case GMI_EXP: // EXP + + switch(type) { - uint64 exp, old_exp=g->member[i].exp; - g->member[i].exp=*((uint64 *)data); - if (g->member[i].exp > old_exp) + case GMI_POSITION: + { + g->member[i].position=*((short *)data); + g->member[i].modified = GS_MEMBER_MODIFIED; + mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len); + g->save_flag |= GS_MEMBER; + break; + } + case GMI_EXP: + { // EXP + uint64 exp, old_exp=g->member[i].exp; + g->member[i].exp=*((uint64 *)data); + g->member[i].modified = GS_MEMBER_MODIFIED; + if (g->member[i].exp > old_exp) + { + exp = g->member[i].exp - old_exp; + + // Compute gained exp + if (guild_exp_rate != 100) + exp = exp*guild_exp_rate/100; + + // Update guild exp + if (exp > UINT64_MAX - g->exp) + g->exp = UINT64_MAX; + else + g->exp+=exp; + + guild_calcinfo(g); + mapif_guild_basicinfochanged(guild_id,GBI_EXP,&g->exp,sizeof(g->exp)); + g->save_flag |= GS_LEVEL; + } + mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len); + g->save_flag |= GS_MEMBER; + break; + } + case GMI_HAIR: { - exp = g->member[i].exp - old_exp; - if (guild_exp_rate != 100) - exp = exp*guild_exp_rate/100; - if (exp > UINT64_MAX - g->exp) - g->exp = UINT64_MAX; - else - g->exp+=exp; - guild_calcinfo(g); - mapif_guild_basicinfochanged(guild_id,GBI_EXP,&g->exp,sizeof(g->exp)); + g->member[i].hair=*((short *)data); + g->member[i].modified = GS_MEMBER_MODIFIED; + mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len); + g->save_flag |= GS_MEMBER; //Save new data. + break; } - mapif_guild_memberinfochanged(guild_id, account_id, char_id, type, data, len); - break; - } - case GMI_HAIR: - { - g->member[i].hair=*((short *)data); - mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len); - break; - } - case GMI_HAIR_COLOR: - { - g->member[i].hair_color=*((short *)data); - mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len); - break; + case GMI_HAIR_COLOR: + { + g->member[i].hair_color=*((short *)data); + g->member[i].modified = GS_MEMBER_MODIFIED; + mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len); + g->save_flag |= GS_MEMBER; //Save new data. + break; + } + case GMI_GENDER: + { + g->member[i].gender=*((short *)data); + g->member[i].modified = GS_MEMBER_MODIFIED; + mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len); + g->save_flag |= GS_MEMBER; //Save new data. + break; + } + case GMI_CLASS: + { + g->member[i].class_=*((short *)data); + g->member[i].modified = GS_MEMBER_MODIFIED; + mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len); + g->save_flag |= GS_MEMBER; //Save new data. + break; + } + case GMI_LEVEL: + { + g->member[i].lv=*((short *)data); + g->member[i].modified = GS_MEMBER_MODIFIED; + mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len); + g->save_flag |= GS_MEMBER; //Save new data. + break; + } + default: + ShowError("int_guild: GuildMemberInfoChange: Unknown type %d\n",type); + break; } - case GMI_GENDER: + return 0; +} + +int inter_guild_sex_changed(int guild_id,int account_id,int char_id, short gender) +{ + return mapif_parse_GuildMemberInfoChange(0, guild_id, account_id, char_id, GMI_GENDER, (const char*)&gender, sizeof(gender)); +} + +int inter_guild_charname_changed(int guild_id,int account_id, int char_id, char *name) +{ + struct guild *g; + int i, flag = 0; + + g = inter_guild_fromsql(guild_id); + if( g == NULL ) { - g->member[i].gender=*((short *)data); - mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len); - break; + ShowError("inter_guild_charrenamed: Can't find guild %d.\n", guild_id); + return 0; } - case GMI_CLASS: + + ARR_FIND(0, g->max_member, i, g->member[i].char_id == char_id); + if( i == g->max_member ) { - g->member[i].class_=*((short *)data); - mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len); - break; + ShowError("inter_guild_charrenamed: Can't find character %d in the guild\n", char_id); + return 0; } - case GMI_LEVEL: + + if( !strcmp(g->member[i].name, g->master) ) { - g->member[i].lv=*((short *)data); - mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len); - break; + safestrncpy(g->master, name, NAME_LENGTH); + flag |= GS_BASIC; } + safestrncpy(g->member[i].name, name, NAME_LENGTH); + g->member[i].modified = GS_MEMBER_MODIFIED; + flag |= GS_MEMBER; - default: - ShowError("int_guild: GuildMemberInfoChange: Unknown type %d\n", type); - break; - } + if( !inter_guild_tosql(g, flag) ) + return 0; + mapif_guild_info(-1,g); + return 0; } -int inter_guild_sex_changed(int guild_id,int account_id,int char_id, short gender) +// Change a position desc +int mapif_parse_GuildPosition(int fd,int guild_id,int idx,struct guild_position *p) { - return mapif_parse_GuildMemberInfoChange(0, guild_id, account_id, char_id, GMI_GENDER, (const char*)&gender, sizeof(gender)); -} + // Could make some improvement in speed, because only change guild_position + struct guild * g; -// ギルド役職名変更要求 -int mapif_parse_GuildPosition(int fd, int guild_id, int idx, struct guild_position *p) -{ - struct guild *g = (struct guild*)idb_get(guild_db, guild_id); - - if (g == NULL || idx < 0 || idx >= MAX_GUILDPOSITION) { + g = inter_guild_fromsql(guild_id); + if(g==NULL || idx<0 || idx>=MAX_GUILDPOSITION) return 0; - } - memcpy(&g->position[idx], p, sizeof(struct guild_position)); - mapif_guild_position(g, idx); - ShowInfo("int_guild: position [%d] changed\n", idx); + memcpy(&g->position[idx],p,sizeof(struct guild_position)); + mapif_guild_position(g,idx); + g->position[idx].modified = GS_POSITION_MODIFIED; + g->save_flag |= GS_POSITION; // Change guild_position return 0; } -// ギルドスキルアップ要求 -int mapif_parse_GuildSkillUp(int fd, int guild_id, int skill_num, int account_id, int max) +// Guild Skill UP +int mapif_parse_GuildSkillUp(int fd,int guild_id,int skill_num,int account_id,int max) { - struct guild *g = (struct guild*)idb_get(guild_db, guild_id); + struct guild * g; int idx = skill_num - GD_SKILLBASE; - if (g == NULL || idx < 0 || idx >= MAX_GUILDSKILL) + g = inter_guild_fromsql(guild_id); + if(g == NULL || idx < 0 || idx >= MAX_GUILDSKILL) return 0; - if (g->skill_point > 0 && g->skill[idx].id > 0 && g->skill[idx].lv < max) { + if(g->skill_point>0 && g->skill[idx].id>0 && g->skill[idx].lvskill[idx].lv++; g->skill_point--; - if (guild_calcinfo(g) == 0) - mapif_guild_info(-1, g); - mapif_guild_skillupack(guild_id, skill_num, account_id); + if (!guild_calcinfo(g)) + mapif_guild_info(-1,g); + mapif_guild_skillupack(guild_id,skill_num,account_id); + g->save_flag |= (GS_LEVEL|GS_SKILL); // Change guild & guild_skill } - return 0; } @@ -1342,106 +1723,119 @@ static int mapif_parse_GuildDeleteAlliance(struct guild *g, int guild_id, int ac { int i; char name[NAME_LENGTH]; - for(i=0;ialliance[i].guild_id == guild_id) - { - strcpy(name, g->alliance[i].name); - g->alliance[i].guild_id=0; - break; - } - if (i == MAX_GUILDALLIANCE) + + ARR_FIND( 0, MAX_GUILDALLIANCE, i, g->alliance[i].guild_id == guild_id ); + if( i == MAX_GUILDALLIANCE ) return -1; + + strcpy(name, g->alliance[i].name); + g->alliance[i].guild_id=0; mapif_guild_alliance(g->guild_id,guild_id,account_id1,account_id2,flag,g->name,name); + g->save_flag |= GS_ALLIANCE; return 0; } -// ギルド同盟要求 -int mapif_parse_GuildAlliance(int fd, int guild_id1, int guild_id2, int account_id1, int account_id2, int flag) +// Alliance modification +int mapif_parse_GuildAlliance(int fd,int guild_id1,int guild_id2,int account_id1,int account_id2,int flag) { + // Could speed up struct guild *g[2]; - int j, i; - - g[0] = (struct guild*)idb_get(guild_db, guild_id1); - g[1] = (struct guild*)idb_get(guild_db, guild_id2); - - if(g[0] && g[1]==NULL && (flag&0x8)) //Requested to remove an alliance with a not found guild. - return mapif_parse_GuildDeleteAlliance(g[0], guild_id2, - account_id1, account_id2, flag); //Try to do a manual removal of said guild. - - if (g[0] == NULL || g[1] == NULL) + int j,i; + g[0] = inter_guild_fromsql(guild_id1); + g[1] = inter_guild_fromsql(guild_id2); + + if(g[0] && g[1]==NULL && (flag & GUILD_ALLIANCE_REMOVE)) //Requested to remove an alliance with a not found guild. + return mapif_parse_GuildDeleteAlliance(g[0], guild_id2, account_id1, account_id2, flag); //Try to do a manual removal of said guild. + + if(g[0]==NULL || g[1]==NULL) return 0; - if (!(flag & 0x8)) { - for(i = 0; i < 2 - (flag & 1); i++) { - for(j = 0; j < MAX_GUILDALLIANCE; j++) - if (g[i]->alliance[j].guild_id == 0) { - g[i]->alliance[j].guild_id = g[1-i]->guild_id; - memcpy(g[i]->alliance[j].name, g[1-i]->name, NAME_LENGTH); - g[i]->alliance[j].opposition = flag & 1; - break; - } + if(flag&GUILD_ALLIANCE_REMOVE) + { + // Remove alliance/opposition, in case of alliance, remove on both side + for(i=0;i<2-(flag&GUILD_ALLIANCE_TYPE_MASK);i++) + { + ARR_FIND( 0, MAX_GUILDALLIANCE, j, g[i]->alliance[j].guild_id == g[1-i]->guild_id && g[i]->alliance[j].opposition == (flag&GUILD_ALLIANCE_TYPE_MASK) ); + if( j < MAX_GUILDALLIANCE ) + g[i]->alliance[j].guild_id = 0; } - } else { // 関係解消 - for(i = 0; i < 2 - (flag & 1); i++) { - for(j = 0; j < MAX_GUILDALLIANCE; j++) - if (g[i]->alliance[j].guild_id == g[1-i]->guild_id && g[i]->alliance[j].opposition == (flag & 1)) { - g[i]->alliance[j].guild_id = 0; - break; - } + } + else + { + // Add alliance, in case of alliance, add on both side + for(i=0;i<2-(flag&GUILD_ALLIANCE_TYPE_MASK);i++) + { + // Search an empty slot + ARR_FIND( 0, MAX_GUILDALLIANCE, j, g[i]->alliance[j].guild_id == 0 ); + if( j < MAX_GUILDALLIANCE ) + { + g[i]->alliance[j].guild_id=g[1-i]->guild_id; + memcpy(g[i]->alliance[j].name,g[1-i]->name,NAME_LENGTH); + // Set alliance type + g[i]->alliance[j].opposition = flag&GUILD_ALLIANCE_TYPE_MASK; + } } } - mapif_guild_alliance(guild_id1, guild_id2, account_id1, account_id2, flag, g[0]->name, g[1]->name); + // Send on all map the new alliance/opposition + mapif_guild_alliance(guild_id1,guild_id2,account_id1,account_id2,flag,g[0]->name,g[1]->name); + + // Mark the two guild to be saved + g[0]->save_flag |= GS_ALLIANCE; + g[1]->save_flag |= GS_ALLIANCE; return 0; } -// ギルド告知変更要求 -int mapif_parse_GuildNotice(int fd, int guild_id, const char *mes1, const char *mes2) +// Change guild message +int mapif_parse_GuildNotice(int fd,int guild_id,const char *mes1,const char *mes2) { struct guild *g; - g = (struct guild*)idb_get(guild_db, guild_id); - if (g == NULL) + g = inter_guild_fromsql(guild_id); + if(g==NULL) return 0; - memcpy(g->mes1, mes1, MAX_GUILDMES1); - memcpy(g->mes2, mes2, MAX_GUILDMES2); + memcpy(g->mes1,mes1,MAX_GUILDMES1); + memcpy(g->mes2,mes2,MAX_GUILDMES2); + g->save_flag |= GS_MES; //Change mes of guild return mapif_guild_notice(g); } -// ギルドエンブレム変更要求 -int mapif_parse_GuildEmblem(int fd, int len, int guild_id, int dummy, const char *data) +int mapif_parse_GuildEmblem(int fd,int len,int guild_id,int dummy,const char *data) { - struct guild *g; + struct guild * g; - g = (struct guild*)idb_get(guild_db, guild_id); - if (g == NULL) + g = inter_guild_fromsql(guild_id); + if(g==NULL) return 0; - memcpy(g->emblem_data, data, len); - g->emblem_len = len; - g->emblem_id++; + if (len > sizeof(g->emblem_data)) + len = sizeof(g->emblem_data); + + memcpy(g->emblem_data,data,len); + g->emblem_len=len; + g->emblem_id++; + g->save_flag |= GS_EMBLEM; //Change guild return mapif_guild_emblem(g); } -int mapif_parse_GuildCastleDataLoad(int fd, int castle_id, int index) +int mapif_parse_GuildCastleDataLoad(int fd,int castle_id,int index) { - struct guild_castle *gc = (struct guild_castle*)idb_get(castle_db, castle_id); - - if (gc == NULL) { - return mapif_guild_castle_dataload(castle_id, 0, 0); - } - switch(index) { - case 1: return mapif_guild_castle_dataload(gc->castle_id, index, gc->guild_id); - case 2: return mapif_guild_castle_dataload(gc->castle_id, index, gc->economy); - case 3: return mapif_guild_castle_dataload(gc->castle_id, index, gc->defense); - case 4: return mapif_guild_castle_dataload(gc->castle_id, index, gc->triggerE); - case 5: return mapif_guild_castle_dataload(gc->castle_id, index, gc->triggerD); - case 6: return mapif_guild_castle_dataload(gc->castle_id, index, gc->nextTime); - case 7: return mapif_guild_castle_dataload(gc->castle_id, index, gc->payTime); - case 8: return mapif_guild_castle_dataload(gc->castle_id, index, gc->createTime); - case 9: return mapif_guild_castle_dataload(gc->castle_id, index, gc->visibleC); + struct guild_castle gc; + if (!inter_guildcastle_fromsql(castle_id, &gc)) { + return mapif_guild_castle_dataload(castle_id,0,0); + } + switch(index){ + case 1: return mapif_guild_castle_dataload(gc.castle_id,index,gc.guild_id); break; + case 2: return mapif_guild_castle_dataload(gc.castle_id,index,gc.economy); break; + case 3: return mapif_guild_castle_dataload(gc.castle_id,index,gc.defense); break; + case 4: return mapif_guild_castle_dataload(gc.castle_id,index,gc.triggerE); break; + case 5: return mapif_guild_castle_dataload(gc.castle_id,index,gc.triggerD); break; + case 6: return mapif_guild_castle_dataload(gc.castle_id,index,gc.nextTime); break; + case 7: return mapif_guild_castle_dataload(gc.castle_id,index,gc.payTime); break; + case 8: return mapif_guild_castle_dataload(gc.castle_id,index,gc.createTime); break; + case 9: return mapif_guild_castle_dataload(gc.castle_id,index,gc.visibleC); break; case 10: case 11: case 12: @@ -1450,45 +1844,42 @@ int mapif_parse_GuildCastleDataLoad(int fd, int castle_id, int index) case 15: case 16: case 17: - return mapif_guild_castle_dataload(gc->castle_id, index, gc->guardian[index-10].visible); + return mapif_guild_castle_dataload(gc.castle_id,index,gc.guardian[index-10].visible); break; default: ShowError("mapif_parse_GuildCastleDataLoad ERROR!! (Not found index=%d)\n", index); return 0; } - - return 0; } -int mapif_parse_GuildCastleDataSave(int fd, int castle_id, int index, int value) +int mapif_parse_GuildCastleDataSave(int fd,int castle_id,int index,int value) { - struct guild_castle *gc = (struct guild_castle*)idb_get(castle_db, castle_id); - - if (gc == NULL) - return mapif_guild_castle_datasave(castle_id, index, value); + struct guild_castle gc; + if(!inter_guildcastle_fromsql(castle_id, &gc)) + return mapif_guild_castle_datasave(castle_id,index,value); - switch(index) { + switch(index){ case 1: - if (gc->guild_id != value) { - int gid = (value) ? value : gc->guild_id; - struct guild *g = (struct guild*)idb_get(guild_db, gid); + if( gc.guild_id!=value ){ + int gid=(value)?value:gc.guild_id; + struct guild *g = (struct guild*)idb_get(guild_db_, gid); if(log_inter) inter_log("guild %s (id=%d) %s castle id=%d\n", - (g) ? g->name : "??", gid, (value) ? "occupy" : "abandon", castle_id); + (g)?g->name:"??" ,gid, (value)?"occupy":"abandon", castle_id); } - gc->guild_id = value; - if(gc->guild_id == 0) { + gc.guild_id = value; + if(gc.guild_id == 0) { //Delete guardians. - memset(&gc->guardian, 0, sizeof(gc->guardian)); + memset(&gc.guardian, 0, sizeof(gc.guardian)); } break; - case 2: gc->economy = value; break; - case 3: gc->defense = value; break; - case 4: gc->triggerE = value; break; - case 5: gc->triggerD = value; break; - case 6: gc->nextTime = value; break; - case 7: gc->payTime = value; break; - case 8: gc->createTime = value; break; - case 9: gc->visibleC = value; break; + case 2: gc.economy = value; break; + case 3: gc.defense = value; break; + case 4: gc.triggerE = value; break; + case 5: gc.triggerD = value; break; + case 6: gc.nextTime = value; break; + case 7: gc.payTime = value; break; + case 8: gc.createTime = value; break; + case 9: gc.visibleC = value; break; case 10: case 11: case 12: @@ -1497,38 +1888,50 @@ int mapif_parse_GuildCastleDataSave(int fd, int castle_id, int index, int value) case 15: case 16: case 17: - gc->guardian[index-10].visible = value; break; + gc.guardian[index-10].visible = value; break; default: ShowError("mapif_parse_GuildCastleDataSave ERROR!! (Not found index=%d)\n", index); return 0; } - - return mapif_guild_castle_datasave(gc->castle_id, index, value); + inter_guildcastle_tosql(&gc); + mapif_guild_castle_datasave(gc.castle_id,index,value); + return 0; } int mapif_parse_GuildMasterChange(int fd, int guild_id, const char* name, int len) { - struct guild *g = (struct guild*)idb_get(guild_db, guild_id); + struct guild * g; struct guild_member gm; int pos; - if(g==NULL || g->guild_id<=0 || len > NAME_LENGTH) + g = inter_guild_fromsql(guild_id); + + if(g==NULL || len > NAME_LENGTH) return 0; + // Find member (name) for (pos = 0; pos < g->max_member && strncmp(g->member[pos].name, name, len); pos++); if (pos == g->max_member) return 0; //Character not found?? + // Switch current and old GM memcpy(&gm, &g->member[pos], sizeof (struct guild_member)); memcpy(&g->member[pos], &g->member[0], sizeof(struct guild_member)); memcpy(&g->member[0], &gm, sizeof(struct guild_member)); + // Switch positions g->member[pos].position = g->member[0].position; + g->member[pos].modified = GS_MEMBER_MODIFIED; g->member[0].position = 0; //Position 0: guild Master. - safestrncpy(g->master, name, NAME_LENGTH); + g->member[0].modified = GS_MEMBER_MODIFIED; + + strncpy(g->master, name, len); + if (len < NAME_LENGTH) + g->master[len] = '\0'; - ShowInfo("int_guild: Guildmaster Changed to %s (Guild %d - %s)\n",name, guild_id, g->name); + ShowInfo("int_guild: Guildmaster Changed to %s (Guild %d - %s)\n",g->master, guild_id, g->name); + g->save_flag |= (GS_BASIC|GS_MEMBER); //Save main data and member data. return mapif_guild_master_changed(g, g->member[0].account_id, g->member[0].char_id); } @@ -1541,23 +1944,23 @@ int inter_guild_parse_frommap(int fd) { RFIFOHEAD(fd); switch(RFIFOW(fd,0)) { - case 0x3030: mapif_parse_CreateGuild(fd, RFIFOL(fd,4), (char*)RFIFOP(fd,8), (struct guild_member *)RFIFOP(fd,32)); break; - case 0x3031: mapif_parse_GuildInfo(fd, RFIFOL(fd,2)); break; - case 0x3032: mapif_parse_GuildAddMember(fd, RFIFOL(fd,4), (struct guild_member *)RFIFOP(fd,8)); break; + case 0x3030: mapif_parse_CreateGuild(fd,RFIFOL(fd,4),(char*)RFIFOP(fd,8),(struct guild_member *)RFIFOP(fd,32)); break; + case 0x3031: mapif_parse_GuildInfo(fd,RFIFOL(fd,2)); break; + case 0x3032: mapif_parse_GuildAddMember(fd,RFIFOL(fd,4),(struct guild_member *)RFIFOP(fd,8)); break; case 0x3033: mapif_parse_GuildMasterChange(fd,RFIFOL(fd,4),(const char*)RFIFOP(fd,8),RFIFOW(fd,2)-8); break; - case 0x3034: mapif_parse_GuildLeave(fd, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10), RFIFOB(fd,14), (const char*)RFIFOP(fd,15)); break; - case 0x3035: mapif_parse_GuildChangeMemberInfoShort(fd, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10), RFIFOB(fd,14), RFIFOW(fd,15), RFIFOW(fd,17)); break; - case 0x3036: mapif_parse_BreakGuild(fd, RFIFOL(fd,2)); break; - case 0x3037: mapif_parse_GuildMessage(fd, RFIFOL(fd,4), RFIFOL(fd,8), (char*)RFIFOP(fd,12), RFIFOW(fd,2)-12); break; - case 0x3039: mapif_parse_GuildBasicInfoChange(fd, RFIFOL(fd,4), RFIFOW(fd,8), (const char*)RFIFOP(fd,10), RFIFOW(fd,2)-10); break; - case 0x303A: mapif_parse_GuildMemberInfoChange(fd, RFIFOL(fd,4), RFIFOL(fd,8), RFIFOL(fd,12), RFIFOW(fd,16), (const char*)RFIFOP(fd,18), RFIFOW(fd,2)-18); break; - case 0x303B: mapif_parse_GuildPosition(fd, RFIFOL(fd,4), RFIFOL(fd,8), (struct guild_position *)RFIFOP(fd,12)); break; - case 0x303C: mapif_parse_GuildSkillUp(fd, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10), RFIFOL(fd,14)); break; - case 0x303D: mapif_parse_GuildAlliance(fd, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10), RFIFOL(fd,14), RFIFOB(fd,18)); break; - case 0x303E: mapif_parse_GuildNotice(fd, RFIFOL(fd,2), (const char*)RFIFOP(fd,6), (const char*)RFIFOP(fd,66)); break; - case 0x303F: mapif_parse_GuildEmblem(fd, RFIFOW(fd,2)-12, RFIFOL(fd,4), RFIFOL(fd,8), (const char*)RFIFOP(fd,12)); break; - case 0x3040: mapif_parse_GuildCastleDataLoad(fd, RFIFOW(fd,2), RFIFOB(fd,4)); break; - case 0x3041: mapif_parse_GuildCastleDataSave(fd, RFIFOW(fd,2), RFIFOB(fd,4), RFIFOL(fd,5)); break; + case 0x3034: mapif_parse_GuildLeave(fd,RFIFOL(fd,2),RFIFOL(fd,6),RFIFOL(fd,10),RFIFOB(fd,14),(const char*)RFIFOP(fd,15)); break; + case 0x3035: mapif_parse_GuildChangeMemberInfoShort(fd,RFIFOL(fd,2),RFIFOL(fd,6),RFIFOL(fd,10),RFIFOB(fd,14),RFIFOW(fd,15),RFIFOW(fd,17)); break; + case 0x3036: mapif_parse_BreakGuild(fd,RFIFOL(fd,2)); break; + case 0x3037: mapif_parse_GuildMessage(fd,RFIFOL(fd,4),RFIFOL(fd,8),(char*)RFIFOP(fd,12),RFIFOW(fd,2)-12); break; + case 0x3039: mapif_parse_GuildBasicInfoChange(fd,RFIFOL(fd,4),RFIFOW(fd,8),(const char*)RFIFOP(fd,10),RFIFOW(fd,2)-10); break; + case 0x303A: mapif_parse_GuildMemberInfoChange(fd,RFIFOL(fd,4),RFIFOL(fd,8),RFIFOL(fd,12),RFIFOW(fd,16),(const char*)RFIFOP(fd,18),RFIFOW(fd,2)-18); break; + case 0x303B: mapif_parse_GuildPosition(fd,RFIFOL(fd,4),RFIFOL(fd,8),(struct guild_position *)RFIFOP(fd,12)); break; + case 0x303C: mapif_parse_GuildSkillUp(fd,RFIFOL(fd,2),RFIFOL(fd,6),RFIFOL(fd,10),RFIFOL(fd,14)); break; + case 0x303D: mapif_parse_GuildAlliance(fd,RFIFOL(fd,2),RFIFOL(fd,6),RFIFOL(fd,10),RFIFOL(fd,14),RFIFOB(fd,18)); break; + case 0x303E: mapif_parse_GuildNotice(fd,RFIFOL(fd,2),(const char*)RFIFOP(fd,6),(const char*)RFIFOP(fd,66)); break; + case 0x303F: mapif_parse_GuildEmblem(fd,RFIFOW(fd,2)-12,RFIFOL(fd,4),RFIFOL(fd,8),(const char*)RFIFOP(fd,12)); break; + case 0x3040: mapif_parse_GuildCastleDataLoad(fd,RFIFOW(fd,2),RFIFOB(fd,4)); break; + case 0x3041: mapif_parse_GuildCastleDataSave(fd,RFIFOW(fd,2),RFIFOB(fd,4),RFIFOL(fd,5)); break; default: return 0; @@ -1577,4 +1980,8 @@ int inter_guild_leave(int guild_id, int account_id, int char_id) { return mapif_parse_GuildLeave(-1, guild_id, account_id, char_id, 0, "** Character Deleted **"); } -#endif //TXT_SQL_CONVERT + +int inter_guild_broken(int guild_id) +{ + return mapif_guild_broken(guild_id, 0); +} diff --git a/src/char/int_guild.h b/src/char/int_guild.h index 0be6c50d9..4577357f3 100644 --- a/src/char/int_guild.h +++ b/src/char/int_guild.h @@ -1,26 +1,40 @@ // Copyright (c) Athena Dev Teams - Licensed under GNU GPL // For more information, see LICENCE in the main folder -#ifndef _INT_GUILD_H_ -#define _INT_GUILD_H_ +#ifndef _INT_GUILD_SQL_H_ +#define _INT_GUILD_SQL_H_ + +#define GS_BASIC 0x0001 +#define GS_MEMBER 0x0002 +#define GS_POSITION 0x0004 +#define GS_ALLIANCE 0x0008 +#define GS_EXPULSION 0x0010 +#define GS_SKILL 0x0020 +#define GS_EMBLEM 0x0040 +#define GS_CONNECT 0x0080 +#define GS_LEVEL 0x0100 +#define GS_MES 0x0200 +#define GS_MASK 0x03FF +#define GS_BASIC_MASK (GS_BASIC | GS_EMBLEM | GS_CONNECT | GS_LEVEL | GS_MES) +#define GS_REMOVE 0x8000 struct guild; struct guild_castle; -int inter_guild_init(void); -void inter_guild_final(void); -int inter_guild_save(void); int inter_guild_parse_frommap(int fd); -struct guild *inter_guild_search(int guild_id); +int inter_guild_sql_init(void); +void inter_guild_sql_final(void); int inter_guild_mapif_init(int fd); int inter_guild_leave(int guild_id,int account_id,int char_id); +int mapif_parse_BreakGuild(int fd,int guild_id); +int inter_guild_broken(int guild_id); int inter_guild_sex_changed(int guild_id,int account_id,int char_id, short gender); +int inter_guild_charname_changed(int guild_id,int account_id, int char_id, char *name); +int inter_guild_CharOnline(int char_id, int guild_id); +int inter_guild_CharOffline(int char_id, int guild_id); -extern char guild_txt[1024]; -extern char castle_txt[1024]; - -//For the TXT->SQL converter -int inter_guild_fromstr(char *str, struct guild *g); -int inter_guildcastle_fromstr(char *str, struct guild_castle *gc); +//For the TXT->SQL converter. +int inter_guild_tosql(struct guild *g,int flag); +int inter_guildcastle_tosql(struct guild_castle *gc); -#endif /* _INT_GUILD_H_ */ +#endif /* _INT_GUILD_SQL_H_ */ diff --git a/src/char/int_homun.c b/src/char/int_homun.c index ec22499d0..d5a928e59 100644 --- a/src/char/int_homun.c +++ b/src/char/int_homun.c @@ -3,363 +3,311 @@ #include "../common/mmo.h" #include "../common/malloc.h" -#include "../common/socket.h" -#include "../common/db.h" -#include "../common/lock.h" +#include "../common/strlib.h" #include "../common/showmsg.h" +#include "../common/socket.h" +#include "../common/utils.h" +#include "../common/sql.h" #include "char.h" #include "inter.h" -#include "int_homun.h" #include #include #include -char homun_txt[1024]="save/homun.txt"; -static DBMap* homun_db; // int hom_id -> struct s_homunculus* -static int homun_newid = 100; - -int inter_homun_tostr(char *str,struct s_homunculus *p) +int inter_homunculus_sql_init(void) { - int i; - - str+=sprintf(str,"%d,%d\t%s\t%d,%d,%d,%d,%d," - "%u,%d,%d,%d," - "%u,%d,%d," - "%d,%d,%d,%d,%d,%d\t", - p->hom_id, p->class_, p->name, - p->char_id, p->hp, p->max_hp, p->sp, p->max_sp, - p->intimacy, p->hunger, p->skillpts, p->level, - p->exp, p->rename_flag, p->vaporize, - p->str, p->agi, p->vit, p->int_, p->dex, p->luk); - - for (i = 0; i < MAX_HOMUNSKILL; i++) - { - if (p->hskill[i].id && p->hskill[i].flag == SKILL_FLAG_PERMANENT) - str+=sprintf(str,"%d,%d,", p->hskill[i].id, p->hskill[i].lv); - } - return 0; } - -int inter_homun_fromstr(char *str,struct s_homunculus *p) -{ - int i, next, len; - int tmp_int[25]; - unsigned int tmp_uint[5]; - char tmp_str[256]; - - memset(p,0,sizeof(struct s_homunculus)); - - i=sscanf(str,"%d,%d\t%127[^\t]\t%d,%d,%d,%d,%d," - "%u,%d,%d,%d," - "%u,%d,%d," - "%d,%d,%d,%d,%d,%d\t%n", - &tmp_int[0],&tmp_int[1],tmp_str, - &tmp_int[2],&tmp_int[3],&tmp_int[4],&tmp_int[5],&tmp_int[6], - &tmp_uint[0],&tmp_int[7],&tmp_int[8],&tmp_int[9], - &tmp_uint[1],&tmp_int[10],&tmp_int[11], - &tmp_int[12],&tmp_int[13],&tmp_int[14],&tmp_int[15],&tmp_int[16],&tmp_int[17], - &next); - - if(i!=21) - return 1; - - p->hom_id = tmp_int[0]; - p->class_ = tmp_int[1]; - memcpy(p->name, tmp_str, NAME_LENGTH); - - p->char_id = tmp_int[2]; - p->hp = tmp_int[3]; - p->max_hp = tmp_int[4]; - p->sp = tmp_int[5]; - p->max_sp = tmp_int[6]; - - p->intimacy = tmp_uint[0]; - p->hunger = tmp_int[7]; - p->skillpts = tmp_int[8]; - p->level = tmp_int[9]; - - p->exp = tmp_uint[1]; - p->rename_flag = tmp_int[10]; - p->vaporize = tmp_int[11]; - - p->str = tmp_int[12]; - p->agi = tmp_int[13]; - p->vit = tmp_int[14]; - p->int_= tmp_int[15]; - p->dex = tmp_int[16]; - p->luk = tmp_int[17]; - - //Read skills. - while(str[next] && str[next] != '\n' && str[next] != '\r') { - if (sscanf(str+next, "%d,%d,%n", &tmp_int[0], &tmp_int[1], &len) != 2) - return 2; - - if (tmp_int[0] >= HM_SKILLBASE && tmp_int[0] < HM_SKILLBASE+MAX_HOMUNSKILL) - { - i = tmp_int[0] - HM_SKILLBASE; - p->hskill[i].id = tmp_int[0]; - p->hskill[i].lv = tmp_int[1]; - } else - ShowError("Read Homun: Unsupported Skill ID %d for homunculus (Homun ID=%d)\n", tmp_int[0], p->hom_id); - next += len; - if (str[next] == ' ') - next++; - } - return 0; -} - -int inter_homun_init() +void inter_homunculus_sql_final(void) { - char line[8192]; - struct s_homunculus *p; - FILE *fp; - int c=0; - - homun_db= idb_alloc(DB_OPT_RELEASE_DATA); - - if( (fp=fopen(homun_txt,"r"))==NULL ) - return 1; - while(fgets(line, sizeof(line), fp)) - { - p = (struct s_homunculus*)aCalloc(sizeof(struct s_homunculus), 1); - if(p==NULL){ - ShowFatalError("int_homun: out of memory!\n"); - exit(EXIT_FAILURE); - } - if(inter_homun_fromstr(line,p)==0 && p->hom_id>0){ - if( p->hom_id >= homun_newid) - homun_newid=p->hom_id+1; - idb_put(homun_db,p->hom_id,p); - }else{ - ShowError("int_homun: broken data [%s] line %d\n",homun_txt,c); - aFree(p); - } - c++; - } - fclose(fp); - return 0; -} - -void inter_homun_final() -{ - homun_db->destroy(homun_db, NULL); return; } -int inter_homun_save_sub(DBKey key,void *data,va_list ap) -{ - char line[8192]; - FILE *fp; - inter_homun_tostr(line,(struct s_homunculus *)data); - fp=va_arg(ap,FILE *); - fprintf(fp,"%s\n",line); - return 0; -} - -int inter_homun_save() -{ - FILE *fp; - int lock; - if( (fp=lock_fopen(homun_txt,&lock))==NULL ){ - ShowError("int_homun: can't write [%s] !!! data is lost !!!\n",homun_txt); - return 1; - } - homun_db->foreach(homun_db,inter_homun_save_sub,fp); - lock_fclose(fp,homun_txt,&lock); - return 0; -} - -int inter_homun_delete(int hom_id) -{ - struct s_homunculus *p; - p = (struct s_homunculus*)idb_get(homun_db,hom_id); - if( p == NULL) - return 0; - idb_remove(homun_db,hom_id); - ShowInfo("Deleted homun (hom_id: %d)\n",hom_id); - return 1; -} - -int mapif_homun_created(int fd,int account_id, struct s_homunculus *p) +static void mapif_homunculus_created(int fd, int account_id, struct s_homunculus *sh, unsigned char flag) { WFIFOHEAD(fd, sizeof(struct s_homunculus)+9); - WFIFOW(fd, 0) =0x3890; + WFIFOW(fd,0) = 0x3890; WFIFOW(fd,2) = sizeof(struct s_homunculus)+9; WFIFOL(fd,4) = account_id; - WFIFOB(fd,8)= p->hom_id?1:0; - memcpy(WFIFOP(fd,9), p, sizeof(struct s_homunculus)); + WFIFOB(fd,8)= flag; + memcpy(WFIFOP(fd,9),sh,sizeof(struct s_homunculus)); WFIFOSET(fd, WFIFOW(fd,2)); - return 0; } -int mapif_homun_info(int fd,int account_id,struct s_homunculus *p) +static void mapif_homunculus_deleted(int fd, int flag) +{ + WFIFOHEAD(fd, 3); + WFIFOW(fd, 0) = 0x3893; + WFIFOB(fd,2) = flag; //Flag 1 = success + WFIFOSET(fd, 3); +} + +static void mapif_homunculus_loaded(int fd, int account_id, struct s_homunculus *hd) { WFIFOHEAD(fd, sizeof(struct s_homunculus)+9); WFIFOW(fd,0) = 0x3891; WFIFOW(fd,2) = sizeof(struct s_homunculus)+9; WFIFOL(fd,4) = account_id; - WFIFOB(fd,8) = 1; // account loaded with success - - memcpy(WFIFOP(fd,9), p, sizeof(struct s_homunculus)); - WFIFOSET(fd,WFIFOW(fd,2)); - return 0; -} - -int mapif_homun_noinfo(int fd,int account_id) -{ - WFIFOHEAD(fd,sizeof(struct s_homunculus) + 9); - WFIFOW(fd,0)=0x3891; - WFIFOW(fd,2)=sizeof(struct s_homunculus) + 9; - WFIFOL(fd,4)=account_id; - WFIFOB(fd,8)=0; - memset(WFIFOP(fd,9),0,sizeof(struct s_homunculus)); - WFIFOSET(fd,WFIFOW(fd,2)); - - return 0; + if( hd != NULL ) + { + WFIFOB(fd,8) = 1; // success + memcpy(WFIFOP(fd,9), hd, sizeof(struct s_homunculus)); + } + else + { + WFIFOB(fd,8) = 0; // not found. + memset(WFIFOP(fd,9), 0, sizeof(struct s_homunculus)); + } + WFIFOSET(fd, sizeof(struct s_homunculus)+9); } -int mapif_save_homun_ack(int fd,int account_id,int flag) +static void mapif_homunculus_saved(int fd, int account_id, bool flag) { WFIFOHEAD(fd, 7); - WFIFOW(fd,0)=0x3892; - WFIFOL(fd,2)=account_id; - WFIFOB(fd,6)=flag; - WFIFOSET(fd,7); - return 0; + WFIFOW(fd,0) = 0x3892; + WFIFOL(fd,2) = account_id; + WFIFOB(fd,6) = flag; // 1:success, 0:failure + WFIFOSET(fd, 7); } -int mapif_delete_homun_ack(int fd,int flag) +static void mapif_homunculus_renamed(int fd, int account_id, int char_id, unsigned char flag, char* name) { - WFIFOHEAD(fd, 3); - WFIFOW(fd,0)=0x3893; - WFIFOB(fd,2)=flag; - WFIFOSET(fd,3); - return 0; -} - -int mapif_rename_homun_ack(int fd, int account_id, int char_id, int flag, char *name){ WFIFOHEAD(fd, NAME_LENGTH+12); - WFIFOW(fd, 0) =0x3894; - WFIFOL(fd, 2) =account_id; - WFIFOL(fd, 6) =char_id; - WFIFOB(fd, 10) =flag; - memcpy(WFIFOP(fd, 11), name, NAME_LENGTH); + WFIFOW(fd, 0) = 0x3894; + WFIFOL(fd, 2) = account_id; + WFIFOL(fd, 6) = char_id; + WFIFOB(fd,10) = flag; + safestrncpy((char*)WFIFOP(fd,11), name, NAME_LENGTH); WFIFOSET(fd, NAME_LENGTH+12); - - return 0; } -int mapif_create_homun(int fd) +bool mapif_homunculus_save(struct s_homunculus* hd) { - struct s_homunculus *p; - p= (struct s_homunculus *) aCalloc(sizeof(struct s_homunculus), 1); - if(p==NULL){ - ShowFatalError("int_homun: out of memory !\n"); - //Sending the received data will pass hom_id == 0 <- fail. - mapif_homun_created(fd,RFIFOL(fd,4),(struct s_homunculus*)RFIFOP(fd,8)); - return 0; + bool flag = true; + char esc_name[NAME_LENGTH*2+1]; + + Sql_EscapeStringLen(sql_handle, esc_name, hd->name, strnlen(hd->name, NAME_LENGTH)); + + if( hd->hom_id == 0 ) + {// new homunculus + if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `homunculus` " + "(`char_id`, `class`,`name`,`level`,`exp`,`intimacy`,`hunger`, `str`, `agi`, `vit`, `int`, `dex`, `luk`, `hp`,`max_hp`,`sp`,`max_sp`,`skill_point`, `rename_flag`, `vaporize`) " + "VALUES ('%d', '%d', '%s', '%d', '%u', '%u', '%d', '%d', %d, '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d')", + hd->char_id, hd->class_, esc_name, hd->level, hd->exp, hd->intimacy, hd->hunger, hd->str, hd->agi, hd->vit, hd->int_, hd->dex, hd->luk, + hd->hp, hd->max_hp, hd->sp, hd->max_sp, hd->skillpts, hd->rename_flag, hd->vaporize) ) + { + Sql_ShowDebug(sql_handle); + flag = false; + } + else + { + hd->hom_id = (int)Sql_LastInsertId(sql_handle); + } } - memcpy(p, RFIFOP(fd,8), sizeof(struct s_homunculus)); - p->hom_id = homun_newid++; //New ID - idb_put(homun_db,p->hom_id,p); - mapif_homun_created(fd,RFIFOL(fd,4),p); - return 0; + else + { + if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `homunculus` SET `char_id`='%d', `class`='%d',`name`='%s',`level`='%d',`exp`='%u',`intimacy`='%u',`hunger`='%d', `str`='%d', `agi`='%d', `vit`='%d', `int`='%d', `dex`='%d', `luk`='%d', `hp`='%d',`max_hp`='%d',`sp`='%d',`max_sp`='%d',`skill_point`='%d', `rename_flag`='%d', `vaporize`='%d' WHERE `homun_id`='%d'", + hd->char_id, hd->class_, esc_name, hd->level, hd->exp, hd->intimacy, hd->hunger, hd->str, hd->agi, hd->vit, hd->int_, hd->dex, hd->luk, + hd->hp, hd->max_hp, hd->sp, hd->max_sp, hd->skillpts, hd->rename_flag, hd->vaporize, hd->hom_id) ) + { + Sql_ShowDebug(sql_handle); + flag = false; + } + else + { + SqlStmt* stmt; + int i; + + stmt = SqlStmt_Malloc(sql_handle); + if( SQL_ERROR == SqlStmt_Prepare(stmt, "REPLACE INTO `skill_homunculus` (`homun_id`, `id`, `lv`) VALUES (%d, ?, ?)", hd->hom_id) ) + SqlStmt_ShowDebug(stmt); + for( i = 0; i < MAX_HOMUNSKILL; ++i ) + { + if( hd->hskill[i].id > 0 && hd->hskill[i].lv != 0 ) + { + SqlStmt_BindParam(stmt, 0, SQLDT_USHORT, &hd->hskill[i].id, 0); + SqlStmt_BindParam(stmt, 1, SQLDT_USHORT, &hd->hskill[i].lv, 0); + if( SQL_ERROR == SqlStmt_Execute(stmt) ) + { + SqlStmt_ShowDebug(stmt); + SqlStmt_Free(stmt); + flag = false; + break; + } + } + } + SqlStmt_Free(stmt); + } + } + + return flag; } -int mapif_load_homun(int fd) + + +// Load an homunculus +bool mapif_homunculus_load(int homun_id, struct s_homunculus* hd) { - struct s_homunculus *p; - int account_id; - account_id = RFIFOL(fd,2); - - p = (struct s_homunculus*)idb_get(homun_db,RFIFOL(fd,6)); - if(p==NULL) { - mapif_homun_noinfo(fd,account_id); - return 0; + int i; + char* data; + size_t len; + + memset(hd, 0, sizeof(*hd)); + + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `homun_id`,`char_id`,`class`,`name`,`level`,`exp`,`intimacy`,`hunger`, `str`, `agi`, `vit`, `int`, `dex`, `luk`, `hp`,`max_hp`,`sp`,`max_sp`,`skill_point`,`rename_flag`, `vaporize` FROM `homunculus` WHERE `homun_id`='%u'", homun_id) ) + { + Sql_ShowDebug(sql_handle); + return false; } - mapif_homun_info(fd,account_id,p); - return 0; -} -static void* create_homun(DBKey key, va_list args) { - struct s_homunculus *p; - p=(struct s_homunculus *)aCalloc(sizeof(struct s_homunculus),1); - p->hom_id = key.i; - return p; -} -int mapif_save_homun(int fd,int account_id,struct s_homunculus *data) -{ - struct s_homunculus *p; - int hom_id; - - if (data->hom_id == 0) - data->hom_id = homun_newid++; - hom_id = data->hom_id; - p = (struct s_homunculus*)idb_ensure(homun_db,hom_id,create_homun); - memcpy(p,data,sizeof(struct s_homunculus)); - mapif_save_homun_ack(fd,account_id,1); - return 0; + if( !Sql_NumRows(sql_handle) ) + { //No homunculus found. + Sql_FreeResult(sql_handle); + return false; + } + if( SQL_SUCCESS != Sql_NextRow(sql_handle) ) + { + Sql_ShowDebug(sql_handle); + Sql_FreeResult(sql_handle); + return false; + } + + hd->hom_id = homun_id; + Sql_GetData(sql_handle, 1, &data, NULL); hd->char_id = atoi(data); + Sql_GetData(sql_handle, 2, &data, NULL); hd->class_ = atoi(data); + Sql_GetData(sql_handle, 3, &data, &len); safestrncpy(hd->name, data, sizeof(hd->name)); + Sql_GetData(sql_handle, 4, &data, NULL); hd->level = atoi(data); + Sql_GetData(sql_handle, 5, &data, NULL); hd->exp = atoi(data); + Sql_GetData(sql_handle, 6, &data, NULL); hd->intimacy = (unsigned int)strtoul(data, NULL, 10); + Sql_GetData(sql_handle, 7, &data, NULL); hd->hunger = atoi(data); + Sql_GetData(sql_handle, 8, &data, NULL); hd->str = atoi(data); + Sql_GetData(sql_handle, 9, &data, NULL); hd->agi = atoi(data); + Sql_GetData(sql_handle, 10, &data, NULL); hd->vit = atoi(data); + Sql_GetData(sql_handle, 11, &data, NULL); hd->int_ = atoi(data); + Sql_GetData(sql_handle, 12, &data, NULL); hd->dex = atoi(data); + Sql_GetData(sql_handle, 13, &data, NULL); hd->luk = atoi(data); + Sql_GetData(sql_handle, 14, &data, NULL); hd->hp = atoi(data); + Sql_GetData(sql_handle, 15, &data, NULL); hd->max_hp = atoi(data); + Sql_GetData(sql_handle, 16, &data, NULL); hd->sp = atoi(data); + Sql_GetData(sql_handle, 17, &data, NULL); hd->max_sp = atoi(data); + Sql_GetData(sql_handle, 18, &data, NULL); hd->skillpts = atoi(data); + Sql_GetData(sql_handle, 19, &data, NULL); hd->rename_flag = atoi(data); + Sql_GetData(sql_handle, 20, &data, NULL); hd->vaporize = atoi(data); + Sql_FreeResult(sql_handle); + + hd->intimacy = cap_value(hd->intimacy, 0, 100000); + hd->hunger = cap_value(hd->hunger, 0, 100); + + // Load Homunculus Skill + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `id`,`lv` FROM `skill_homunculus` WHERE `homun_id`=%d", homun_id) ) + { + Sql_ShowDebug(sql_handle); + return false; + } + while( SQL_SUCCESS == Sql_NextRow(sql_handle) ) + { + // id + Sql_GetData(sql_handle, 0, &data, NULL); + i = atoi(data); + if( i < HM_SKILLBASE || i >= HM_SKILLBASE + MAX_HOMUNSKILL ) + continue;// invalid skill id + i = i - HM_SKILLBASE; + hd->hskill[i].id = (unsigned short)atoi(data); + + // lv + Sql_GetData(sql_handle, 1, &data, NULL); + hd->hskill[i].lv = (unsigned char)atoi(data); + } + Sql_FreeResult(sql_handle); + + if( save_log ) + ShowInfo("Homunculus loaded (%d - %s).\n", hd->hom_id, hd->name); + + return true; } -int mapif_delete_homun(int fd,int hom_id) +bool mapif_homunculus_delete(int homun_id) { - mapif_delete_homun_ack(fd,inter_homun_delete(hom_id)); - return 0; + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `homunculus` WHERE `homun_id` = '%u'", homun_id) + || SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `skill_homunculus` WHERE `homun_id` = '%u'", homun_id) + ) { + Sql_ShowDebug(sql_handle); + return false; + } + return true; } -int mapif_rename_homun(int fd, int account_id, int char_id, char *name){ +bool mapif_homunculus_rename(char *name) +{ int i; // Check Authorised letters/symbols in the name of the homun - if (char_name_option == 1) { // only letters/symbols in char_name_letters are authorised - for (i = 0; i < NAME_LENGTH && name[i]; i++) - if (strchr(char_name_letters, name[i]) == NULL) { - mapif_rename_homun_ack(fd, account_id, char_id, 0, name); - return 0; - } - } else if (char_name_option == 2) { // letters/symbols in char_name_letters are forbidden - for (i = 0; i < NAME_LENGTH && name[i]; i++) - if (strchr(char_name_letters, name[i]) != NULL) { - mapif_rename_homun_ack(fd, account_id, char_id, 0, name); - return 0; - } + if( char_name_option == 1 ) + {// only letters/symbols in char_name_letters are authorised + for( i = 0; i < NAME_LENGTH && name[i]; i++ ) + if( strchr(char_name_letters, name[i]) == NULL ) + return false; + } else + if( char_name_option == 2 ) + {// letters/symbols in char_name_letters are forbidden + for( i = 0; i < NAME_LENGTH && name[i]; i++ ) + if( strchr(char_name_letters, name[i]) != NULL ) + return false; } - mapif_rename_homun_ack(fd, account_id, char_id, 1, name); - return 0; + return true; } -int mapif_parse_SaveHomun(int fd) + +static void mapif_parse_homunculus_create(int fd, int len, int account_id, struct s_homunculus* phd) { - mapif_save_homun(fd,RFIFOL(fd,4),(struct s_homunculus *)RFIFOP(fd,8)); - return 0; + bool result = mapif_homunculus_save(phd); + mapif_homunculus_created(fd, account_id, phd, result); } -int mapif_parse_DeleteHomun(int fd) +static void mapif_parse_homunculus_delete(int fd, int homun_id) { - mapif_delete_homun(fd,RFIFOL(fd,2)); - return 0; + bool result = mapif_homunculus_delete(homun_id); + mapif_homunculus_deleted(fd, result); } -int mapif_parse_RenameHomun(int fd) +static void mapif_parse_homunculus_load(int fd, int account_id, int homun_id) { - mapif_rename_homun(fd, RFIFOL(fd, 2), RFIFOL(fd, 6), (char*)RFIFOP(fd, 10)); - return 0; + struct s_homunculus hd; + bool result = mapif_homunculus_load(homun_id, &hd); + mapif_homunculus_loaded(fd, account_id, ( result ? &hd : NULL )); +} + +static void mapif_parse_homunculus_save(int fd, int len, int account_id, struct s_homunculus* phd) +{ + bool result = mapif_homunculus_save(phd); + mapif_homunculus_saved(fd, account_id, result); +} + +static void mapif_parse_homunculus_rename(int fd, int account_id, int char_id, char* name) +{ + bool result = mapif_homunculus_rename(name); + mapif_homunculus_renamed(fd, account_id, char_id, result, name); } -int inter_homun_parse_frommap(int fd) +/*========================================== + * Inter Packets + *------------------------------------------*/ +int inter_homunculus_parse_frommap(int fd) { - switch(RFIFOW(fd,0)){ - case 0x3090: mapif_create_homun(fd); break; - case 0x3091: mapif_load_homun(fd); break; - case 0x3092: mapif_parse_SaveHomun(fd); break; - case 0x3093: mapif_parse_DeleteHomun(fd); break; - case 0x3094: mapif_parse_RenameHomun(fd); break; - default: - return 0; + unsigned short cmd = RFIFOW(fd,0); + + switch( cmd ) + { + case 0x3090: mapif_parse_homunculus_create(fd, (int)RFIFOW(fd,2), (int)RFIFOL(fd,4), (struct s_homunculus*)RFIFOP(fd,8)); break; + case 0x3091: mapif_parse_homunculus_load (fd, (int)RFIFOL(fd,2), (int)RFIFOL(fd,6)); break; + case 0x3092: mapif_parse_homunculus_save (fd, (int)RFIFOW(fd,2), (int)RFIFOL(fd,4), (struct s_homunculus*)RFIFOP(fd,8)); break; + case 0x3093: mapif_parse_homunculus_delete(fd, (int)RFIFOL(fd,2)); break; + case 0x3094: mapif_parse_homunculus_rename(fd, (int)RFIFOL(fd,2), (int)RFIFOL(fd,6), (char*)RFIFOP(fd,10)); break; + default: + return 0; } return 1; } diff --git a/src/char/int_homun.h b/src/char/int_homun.h index 1858ed4ba..1c0d76269 100644 --- a/src/char/int_homun.h +++ b/src/char/int_homun.h @@ -1,15 +1,18 @@ // Copyright (c) Athena Dev Teams - Licensed under GNU GPL // For more information, see LICENCE in the main folder -#ifndef _INT_HOMUN_H_ -#define _INT_HOMUN_H_ +#ifndef _INT_HOMUN_SQL_H_ +#define _INT_HOMUN_SQL_H_ -int inter_homun_init(void); -void inter_homun_final(void); -int inter_homun_save(void); -int inter_homun_delete(int homun_id); -int inter_homun_parse_frommap(int fd); +struct s_homunculus; -extern char homun_txt[1024]; +int inter_homunculus_sql_init(void); +void inter_homunculus_sql_final(void); +int inter_homunculus_parse_frommap(int fd); -#endif /* _INT_HOMUN_H_ */ +bool mapif_homunculus_save(struct s_homunculus* hd); +bool mapif_homunculus_load(int homun_id, struct s_homunculus* hd); +bool mapif_homunculus_delete(int homun_id); +bool mapif_homunculus_rename(char *name); + +#endif /* _INT_HOMUN_SQL_H_ */ diff --git a/src/char/int_mail.c b/src/char/int_mail.c new file mode 100644 index 000000000..b19b732c7 --- /dev/null +++ b/src/char/int_mail.c @@ -0,0 +1,476 @@ +// Copyright (c) Athena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + +#include "../common/mmo.h" +#include "../common/malloc.h" +#include "../common/showmsg.h" +#include "../common/socket.h" +#include "../common/strlib.h" +#include "../common/sql.h" +#include "../common/timer.h" +#include "char.h" +#include "inter.h" + +#include +#include +#include + +static int mail_fromsql(int char_id, struct mail_data* md) +{ + int i, j; + struct mail_message *msg; + struct item *item; + char *data; + StringBuf buf; + + memset(md, 0, sizeof(struct mail_data)); + md->amount = 0; + md->full = false; + + StringBuf_Init(&buf); + StringBuf_AppendStr(&buf, "SELECT `id`,`send_name`,`send_id`,`dest_name`,`dest_id`,`title`,`message`,`time`,`status`," + "`zeny`,`amount`,`nameid`,`refine`,`attribute`,`identify`"); + for (i = 0; i < MAX_SLOTS; i++) + StringBuf_Printf(&buf, ",`card%d`", i); + + // I keep the `status` < 3 just in case someone forget to apply the sqlfix + StringBuf_Printf(&buf, " FROM `%s` WHERE `dest_id`='%d' AND `status` < 3 ORDER BY `id` LIMIT %d", + mail_db, char_id, MAIL_MAX_INBOX + 1); + + if( SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf)) ) + Sql_ShowDebug(sql_handle); + + StringBuf_Destroy(&buf); + + for (i = 0; i < MAIL_MAX_INBOX && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i ) + { + msg = &md->msg[i]; + Sql_GetData(sql_handle, 0, &data, NULL); msg->id = atoi(data); + Sql_GetData(sql_handle, 1, &data, NULL); safestrncpy(msg->send_name, data, NAME_LENGTH); + Sql_GetData(sql_handle, 2, &data, NULL); msg->send_id = atoi(data); + Sql_GetData(sql_handle, 3, &data, NULL); safestrncpy(msg->dest_name, data, NAME_LENGTH); + Sql_GetData(sql_handle, 4, &data, NULL); msg->dest_id = atoi(data); + Sql_GetData(sql_handle, 5, &data, NULL); safestrncpy(msg->title, data, MAIL_TITLE_LENGTH); + Sql_GetData(sql_handle, 6, &data, NULL); safestrncpy(msg->body, data, MAIL_BODY_LENGTH); + Sql_GetData(sql_handle, 7, &data, NULL); msg->timestamp = atoi(data); + Sql_GetData(sql_handle, 8, &data, NULL); msg->status = (mail_status)atoi(data); + Sql_GetData(sql_handle, 9, &data, NULL); msg->zeny = atoi(data); + item = &msg->item; + Sql_GetData(sql_handle,10, &data, NULL); item->amount = (short)atoi(data); + Sql_GetData(sql_handle,11, &data, NULL); item->nameid = atoi(data); + Sql_GetData(sql_handle,12, &data, NULL); item->refine = atoi(data); + Sql_GetData(sql_handle,13, &data, NULL); item->attribute = atoi(data); + Sql_GetData(sql_handle,14, &data, NULL); item->identify = atoi(data); + item->expire_time = 0; + + for (j = 0; j < MAX_SLOTS; j++) + { + Sql_GetData(sql_handle, 15 + j, &data, NULL); + item->card[j] = atoi(data); + } + } + + md->full = ( Sql_NumRows(sql_handle) > MAIL_MAX_INBOX ); + + md->amount = i; + Sql_FreeResult(sql_handle); + + md->unchecked = 0; + md->unread = 0; + for (i = 0; i < md->amount; i++) + { + msg = &md->msg[i]; + if( msg->status == MAIL_NEW ) + { + if ( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `status` = '%d' WHERE `id` = '%d'", mail_db, MAIL_UNREAD, msg->id) ) + Sql_ShowDebug(sql_handle); + + msg->status = MAIL_UNREAD; + md->unchecked++; + } + else if ( msg->status == MAIL_UNREAD ) + md->unread++; + } + + ShowInfo("mail load complete from DB - id: %d (total: %d)\n", char_id, md->amount); + return 1; +} + +/// Stores a single message in the database. +/// Returns the message's ID if successful (or 0 if it fails). +int mail_savemessage(struct mail_message* msg) +{ + StringBuf buf; + SqlStmt* stmt; + int j; + + // build message save query + StringBuf_Init(&buf); + StringBuf_Printf(&buf, "INSERT INTO `%s` (`send_name`, `send_id`, `dest_name`, `dest_id`, `title`, `message`, `time`, `status`, `zeny`, `amount`, `nameid`, `refine`, `attribute`, `identify`", mail_db); + for (j = 0; j < MAX_SLOTS; j++) + StringBuf_Printf(&buf, ", `card%d`", j); + StringBuf_Printf(&buf, ") VALUES (?, '%d', ?, '%d', ?, ?, '%lu', '%d', '%d', '%d', '%d', '%d', '%d', '%d'", + msg->send_id, msg->dest_id, (unsigned long)msg->timestamp, msg->status, msg->zeny, msg->item.amount, msg->item.nameid, msg->item.refine, msg->item.attribute, msg->item.identify); + for (j = 0; j < MAX_SLOTS; j++) + StringBuf_Printf(&buf, ", '%d'", msg->item.card[j]); + StringBuf_AppendStr(&buf, ")"); + + // prepare and execute query + stmt = SqlStmt_Malloc(sql_handle); + if( SQL_SUCCESS != SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_STRING, msg->send_name, strnlen(msg->send_name, NAME_LENGTH)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_STRING, msg->dest_name, strnlen(msg->dest_name, NAME_LENGTH)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 2, SQLDT_STRING, msg->title, strnlen(msg->title, MAIL_TITLE_LENGTH)) + || SQL_SUCCESS != SqlStmt_BindParam(stmt, 3, SQLDT_STRING, msg->body, strnlen(msg->body, MAIL_BODY_LENGTH)) + || SQL_SUCCESS != SqlStmt_Execute(stmt) ) + { + SqlStmt_ShowDebug(stmt); + msg->id = 0; + } else + msg->id = (int)SqlStmt_LastInsertId(stmt); + + SqlStmt_Free(stmt); + StringBuf_Destroy(&buf); + + return msg->id; +} + +/// Retrieves a single message from the database. +/// Returns true if the operation succeeds (or false if it fails). +static bool mail_loadmessage(int mail_id, struct mail_message* msg) +{ + int j; + StringBuf buf; + + StringBuf_Init(&buf); + StringBuf_AppendStr(&buf, "SELECT `id`,`send_name`,`send_id`,`dest_name`,`dest_id`,`title`,`message`,`time`,`status`," + "`zeny`,`amount`,`nameid`,`refine`,`attribute`,`identify`"); + for( j = 0; j < MAX_SLOTS; j++ ) + StringBuf_Printf(&buf, ",`card%d`", j); + StringBuf_Printf(&buf, " FROM `%s` WHERE `id` = '%d'", mail_db, mail_id); + + if( SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf)) + || SQL_SUCCESS != Sql_NextRow(sql_handle) ) + { + Sql_ShowDebug(sql_handle); + Sql_FreeResult(sql_handle); + StringBuf_Destroy(&buf); + return false; + } + else + { + char* data; + + Sql_GetData(sql_handle, 0, &data, NULL); msg->id = atoi(data); + Sql_GetData(sql_handle, 1, &data, NULL); safestrncpy(msg->send_name, data, NAME_LENGTH); + Sql_GetData(sql_handle, 2, &data, NULL); msg->send_id = atoi(data); + Sql_GetData(sql_handle, 3, &data, NULL); safestrncpy(msg->dest_name, data, NAME_LENGTH); + Sql_GetData(sql_handle, 4, &data, NULL); msg->dest_id = atoi(data); + Sql_GetData(sql_handle, 5, &data, NULL); safestrncpy(msg->title, data, MAIL_TITLE_LENGTH); + Sql_GetData(sql_handle, 6, &data, NULL); safestrncpy(msg->body, data, MAIL_BODY_LENGTH); + Sql_GetData(sql_handle, 7, &data, NULL); msg->timestamp = atoi(data); + Sql_GetData(sql_handle, 8, &data, NULL); msg->status = (mail_status)atoi(data); + Sql_GetData(sql_handle, 9, &data, NULL); msg->zeny = atoi(data); + Sql_GetData(sql_handle,10, &data, NULL); msg->item.amount = (short)atoi(data); + Sql_GetData(sql_handle,11, &data, NULL); msg->item.nameid = atoi(data); + Sql_GetData(sql_handle,12, &data, NULL); msg->item.refine = atoi(data); + Sql_GetData(sql_handle,13, &data, NULL); msg->item.attribute = atoi(data); + Sql_GetData(sql_handle,14, &data, NULL); msg->item.identify = atoi(data); + msg->item.expire_time = 0; + + for( j = 0; j < MAX_SLOTS; j++ ) + { + Sql_GetData(sql_handle,15 + j, &data, NULL); + msg->item.card[j] = atoi(data); + } + } + + StringBuf_Destroy(&buf); + Sql_FreeResult(sql_handle); + + return true; +} + +/*========================================== + * Client Inbox Request + *------------------------------------------*/ +static void mapif_Mail_sendinbox(int fd, int char_id, unsigned char flag) +{ + struct mail_data md; + mail_fromsql(char_id, &md); + + //FIXME: dumping the whole structure like this is unsafe [ultramage] + WFIFOHEAD(fd, sizeof(md) + 9); + WFIFOW(fd,0) = 0x3848; + WFIFOW(fd,2) = sizeof(md) + 9; + WFIFOL(fd,4) = char_id; + WFIFOB(fd,8) = flag; + memcpy(WFIFOP(fd,9),&md,sizeof(md)); + WFIFOSET(fd,WFIFOW(fd,2)); +} + +static void mapif_parse_Mail_requestinbox(int fd) +{ + mapif_Mail_sendinbox(fd, RFIFOL(fd,2), RFIFOB(fd,6)); +} + +/*========================================== + * Mark mail as 'Read' + *------------------------------------------*/ +static void mapif_parse_Mail_read(int fd) +{ + int mail_id = RFIFOL(fd,2); + if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `status` = '%d' WHERE `id` = '%d'", mail_db, MAIL_READ, mail_id) ) + Sql_ShowDebug(sql_handle); +} + +/*========================================== + * Client Attachment Request + *------------------------------------------*/ +static bool mail_DeleteAttach(int mail_id) +{ + StringBuf buf; + int i; + + StringBuf_Init(&buf); + StringBuf_Printf(&buf, "UPDATE `%s` SET `zeny` = '0', `nameid` = '0', `amount` = '0', `refine` = '0', `attribute` = '0', `identify` = '0'", mail_db); + for (i = 0; i < MAX_SLOTS; i++) + StringBuf_Printf(&buf, ", `card%d` = '0'", i); + StringBuf_Printf(&buf, " WHERE `id` = '%d'", mail_id); + + if( SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf)) ) + { + Sql_ShowDebug(sql_handle); + StringBuf_Destroy(&buf); + + return false; + } + + StringBuf_Destroy(&buf); + return true; +} + +static void mapif_Mail_getattach(int fd, int char_id, int mail_id) +{ + struct mail_message msg; + + if( !mail_loadmessage(mail_id, &msg) ) + return; + + if( msg.dest_id != char_id ) + return; + + if( msg.status != MAIL_READ ) + return; + + if( (msg.item.nameid < 1 || msg.item.amount < 1) && msg.zeny < 1 ) + return; // No Attachment + + if( !mail_DeleteAttach(mail_id) ) + return; + + WFIFOHEAD(fd, sizeof(struct item) + 12); + WFIFOW(fd,0) = 0x384a; + WFIFOW(fd,2) = sizeof(struct item) + 12; + WFIFOL(fd,4) = char_id; + WFIFOL(fd,8) = (msg.zeny > 0)?msg.zeny:0; + memcpy(WFIFOP(fd,12), &msg.item, sizeof(struct item)); + WFIFOSET(fd,WFIFOW(fd,2)); +} + +static void mapif_parse_Mail_getattach(int fd) +{ + mapif_Mail_getattach(fd, RFIFOL(fd,2), RFIFOL(fd,6)); +} + +/*========================================== + * Delete Mail + *------------------------------------------*/ +static void mapif_Mail_delete(int fd, int char_id, int mail_id) +{ + bool failed = false; + if ( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `id` = '%d'", mail_db, mail_id) ) + { + Sql_ShowDebug(sql_handle); + failed = true; + } + + WFIFOHEAD(fd,11); + WFIFOW(fd,0) = 0x384b; + WFIFOL(fd,2) = char_id; + WFIFOL(fd,6) = mail_id; + WFIFOB(fd,10) = failed; + WFIFOSET(fd,11); +} + +static void mapif_parse_Mail_delete(int fd) +{ + mapif_Mail_delete(fd, RFIFOL(fd,2), RFIFOL(fd,6)); +} + +/*========================================== + * Report New Mail to Map Server + *------------------------------------------*/ +void mapif_Mail_new(struct mail_message *msg) +{ + unsigned char buf[74]; + + if( !msg || !msg->id ) + return; + + WBUFW(buf,0) = 0x3849; + WBUFL(buf,2) = msg->dest_id; + WBUFL(buf,6) = msg->id; + memcpy(WBUFP(buf,10), msg->send_name, NAME_LENGTH); + memcpy(WBUFP(buf,34), msg->title, MAIL_TITLE_LENGTH); + mapif_sendall(buf, 74); +} + +/*========================================== + * Return Mail + *------------------------------------------*/ +static void mapif_Mail_return(int fd, int char_id, int mail_id) +{ + struct mail_message msg; + int new_mail = 0; + + if( mail_loadmessage(mail_id, &msg) ) + { + if( msg.dest_id != char_id) + return; + else if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `id` = '%d'", mail_db, mail_id) ) + Sql_ShowDebug(sql_handle); + else + { + char temp_[MAIL_TITLE_LENGTH]; + + // swap sender and receiver + swap(msg.send_id, msg.dest_id); + safestrncpy(temp_, msg.send_name, NAME_LENGTH); + safestrncpy(msg.send_name, msg.dest_name, NAME_LENGTH); + safestrncpy(msg.dest_name, temp_, NAME_LENGTH); + + // set reply message title + snprintf(temp_, MAIL_TITLE_LENGTH, "RE:%s", msg.title); + safestrncpy(msg.title, temp_, MAIL_TITLE_LENGTH); + + msg.status = MAIL_NEW; + msg.timestamp = time(NULL); + + new_mail = mail_savemessage(&msg); + mapif_Mail_new(&msg); + } + } + + WFIFOHEAD(fd,11); + WFIFOW(fd,0) = 0x384c; + WFIFOL(fd,2) = char_id; + WFIFOL(fd,6) = mail_id; + WFIFOB(fd,10) = (new_mail == 0); + WFIFOSET(fd,11); +} + +static void mapif_parse_Mail_return(int fd) +{ + mapif_Mail_return(fd, RFIFOL(fd,2), RFIFOL(fd,6)); +} + +/*========================================== + * Send Mail + *------------------------------------------*/ +static void mapif_Mail_send(int fd, struct mail_message* msg) +{ + int len = sizeof(struct mail_message) + 4; + + WFIFOHEAD(fd,len); + WFIFOW(fd,0) = 0x384d; + WFIFOW(fd,2) = len; + memcpy(WFIFOP(fd,4), msg, sizeof(struct mail_message)); + WFIFOSET(fd,len); +} + +static void mapif_parse_Mail_send(int fd) +{ + struct mail_message msg; + char esc_name[NAME_LENGTH*2+1]; + int account_id = 0; + + if(RFIFOW(fd,2) != 8 + sizeof(struct mail_message)) + return; + + account_id = RFIFOL(fd,4); + memcpy(&msg, RFIFOP(fd,8), sizeof(struct mail_message)); + + // Try to find the Dest Char by Name + Sql_EscapeStringLen(sql_handle, esc_name, msg.dest_name, strnlen(msg.dest_name, NAME_LENGTH)); + if ( SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id`, `char_id` FROM `%s` WHERE `name` = '%s'", char_db, esc_name) ) + Sql_ShowDebug(sql_handle); + else + if ( SQL_SUCCESS == Sql_NextRow(sql_handle) ) + { + char *data; + Sql_GetData(sql_handle, 0, &data, NULL); + if (atoi(data) != account_id) + { // Cannot send mail to char in the same account + Sql_GetData(sql_handle, 1, &data, NULL); + msg.dest_id = atoi(data); + } + } + Sql_FreeResult(sql_handle); + msg.status = MAIL_NEW; + + if( msg.dest_id > 0 ) + msg.id = mail_savemessage(&msg); + + mapif_Mail_send(fd, &msg); +} + +void mail_sendmail(int send_id, const char* send_name, int dest_id, const char* dest_name, const char* title, const char* body, int zeny, struct item *item) +{ + struct mail_message msg; + memset(&msg, 0, sizeof(struct mail_message)); + + msg.send_id = send_id; + safestrncpy(msg.send_name, send_name, NAME_LENGTH); + msg.dest_id = dest_id; + safestrncpy(msg.dest_name, dest_name, NAME_LENGTH); + safestrncpy(msg.title, title, MAIL_TITLE_LENGTH); + safestrncpy(msg.body, body, MAIL_BODY_LENGTH); + msg.zeny = zeny; + if( item != NULL ) + memcpy(&msg.item, item, sizeof(struct item)); + + msg.timestamp = time(NULL); + + mail_savemessage(&msg); + mapif_Mail_new(&msg); +} + +/*========================================== + * Packets From Map Server + *------------------------------------------*/ +int inter_mail_parse_frommap(int fd) +{ + switch(RFIFOW(fd,0)) + { + case 0x3048: mapif_parse_Mail_requestinbox(fd); break; + case 0x3049: mapif_parse_Mail_read(fd); break; + case 0x304a: mapif_parse_Mail_getattach(fd); break; + case 0x304b: mapif_parse_Mail_delete(fd); break; + case 0x304c: mapif_parse_Mail_return(fd); break; + case 0x304d: mapif_parse_Mail_send(fd); break; + default: + return 0; + } + return 1; +} + +int inter_mail_sql_init(void) +{ + return 1; +} + +void inter_mail_sql_final(void) +{ + return; +} diff --git a/src/char/int_mail.h b/src/char/int_mail.h new file mode 100644 index 000000000..77db51e5b --- /dev/null +++ b/src/char/int_mail.h @@ -0,0 +1,16 @@ +// Copyright (c) Athena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + +#ifndef _INT_MAIL_SQL_H_ +#define _INT_MAIL_SQL_H_ + +int inter_mail_parse_frommap(int fd); +void mail_sendmail(int send_id, const char* send_name, int dest_id, const char* dest_name, const char* title, const char* body, int zeny, struct item *item); + +int inter_mail_sql_init(void); +void inter_mail_sql_final(void); + +int mail_savemessage(struct mail_message* msg); +void mapif_Mail_new(struct mail_message *msg); + +#endif /* _INT_MAIL_SQL_H_ */ diff --git a/src/char/int_mercenary.c b/src/char/int_mercenary.c new file mode 100644 index 000000000..1b11878b8 --- /dev/null +++ b/src/char/int_mercenary.c @@ -0,0 +1,218 @@ +// Copyright (c) Athena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + +#include "../common/mmo.h" +#include "../common/malloc.h" +#include "../common/strlib.h" +#include "../common/showmsg.h" +#include "../common/socket.h" +#include "../common/utils.h" +#include "../common/sql.h" +#include "char.h" +#include "inter.h" + +#include +#include +#include + +bool mercenary_owner_fromsql(int char_id, struct mmo_charstatus *status) +{ + char* data; + + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `merc_id`, `arch_calls`, `arch_faith`, `spear_calls`, `spear_faith`, `sword_calls`, `sword_faith` FROM `mercenary_owner` WHERE `char_id` = '%d'", char_id) ) + { + Sql_ShowDebug(sql_handle); + return false; + } + + if( SQL_SUCCESS != Sql_NextRow(sql_handle) ) + { + Sql_FreeResult(sql_handle); + return false; + } + + Sql_GetData(sql_handle, 0, &data, NULL); status->mer_id = atoi(data); + Sql_GetData(sql_handle, 1, &data, NULL); status->arch_calls = atoi(data); + Sql_GetData(sql_handle, 2, &data, NULL); status->arch_faith = atoi(data); + Sql_GetData(sql_handle, 3, &data, NULL); status->spear_calls = atoi(data); + Sql_GetData(sql_handle, 4, &data, NULL); status->spear_faith = atoi(data); + Sql_GetData(sql_handle, 5, &data, NULL); status->sword_calls = atoi(data); + Sql_GetData(sql_handle, 6, &data, NULL); status->sword_faith = atoi(data); + Sql_FreeResult(sql_handle); + + return true; +} + +bool mercenary_owner_tosql(int char_id, struct mmo_charstatus *status) +{ + if( SQL_ERROR == Sql_Query(sql_handle, "REPLACE INTO `mercenary_owner` (`char_id`, `merc_id`, `arch_calls`, `arch_faith`, `spear_calls`, `spear_faith`, `sword_calls`, `sword_faith`) VALUES ('%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d')", + char_id, status->mer_id, status->arch_calls, status->arch_faith, status->spear_calls, status->spear_faith, status->sword_calls, status->sword_faith) ) + { + Sql_ShowDebug(sql_handle); + return false; + } + + return true; +} + +bool mercenary_owner_delete(int char_id) +{ + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `mercenary_owner` WHERE `char_id` = '%d'", char_id) ) + Sql_ShowDebug(sql_handle); + + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `mercenary` WHERE `char_id` = '%d'", char_id) ) + Sql_ShowDebug(sql_handle); + + return true; +} + +bool mapif_mercenary_save(struct s_mercenary* merc) +{ + bool flag = true; + + if( merc->mercenary_id == 0 ) + { // Create new DB entry + if( SQL_ERROR == Sql_Query(sql_handle, + "INSERT INTO `mercenary` (`char_id`,`class`,`hp`,`sp`,`kill_counter`,`life_time`) VALUES ('%d','%d','%d','%d','%u','%u')", + merc->char_id, merc->class_, merc->hp, merc->sp, merc->kill_count, merc->life_time) ) + { + Sql_ShowDebug(sql_handle); + flag = false; + } + else + merc->mercenary_id = (int)Sql_LastInsertId(sql_handle); + } + else if( SQL_ERROR == Sql_Query(sql_handle, + "UPDATE `mercenary` SET `char_id` = '%d', `class` = '%d', `hp` = '%d', `sp` = '%d', `kill_counter` = '%u', `life_time` = '%u' WHERE `mer_id` = '%d'", + merc->char_id, merc->class_, merc->hp, merc->sp, merc->kill_count, merc->life_time, merc->mercenary_id) ) + { // Update DB entry + Sql_ShowDebug(sql_handle); + flag = false; + } + + return flag; +} + +bool mapif_mercenary_load(int merc_id, int char_id, struct s_mercenary *merc) +{ + char* data; + + memset(merc, 0, sizeof(struct s_mercenary)); + merc->mercenary_id = merc_id; + merc->char_id = char_id; + + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `class`, `hp`, `sp`, `kill_counter`, `life_time` FROM `mercenary` WHERE `mer_id` = '%d' AND `char_id` = '%d'", merc_id, char_id) ) + { + Sql_ShowDebug(sql_handle); + return false; + } + + if( SQL_SUCCESS != Sql_NextRow(sql_handle) ) + { + Sql_FreeResult(sql_handle); + return false; + } + + Sql_GetData(sql_handle, 0, &data, NULL); merc->class_ = atoi(data); + Sql_GetData(sql_handle, 1, &data, NULL); merc->hp = atoi(data); + Sql_GetData(sql_handle, 2, &data, NULL); merc->sp = atoi(data); + Sql_GetData(sql_handle, 3, &data, NULL); merc->kill_count = atoi(data); + Sql_GetData(sql_handle, 4, &data, NULL); merc->life_time = atoi(data); + Sql_FreeResult(sql_handle); + if( save_log ) + ShowInfo("Mercenary loaded (%d - %d).\n", merc->mercenary_id, merc->char_id); + + return true; +} + +bool mapif_mercenary_delete(int merc_id) +{ + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `mercenary` WHERE `mer_id` = '%d'", merc_id) ) + { + Sql_ShowDebug(sql_handle); + return false; + } + + return true; +} + +static void mapif_mercenary_send(int fd, struct s_mercenary *merc, unsigned char flag) +{ + int size = sizeof(struct s_mercenary) + 5; + + WFIFOHEAD(fd,size); + WFIFOW(fd,0) = 0x3870; + WFIFOW(fd,2) = size; + WFIFOB(fd,4) = flag; + memcpy(WFIFOP(fd,5),merc,sizeof(struct s_mercenary)); + WFIFOSET(fd,size); +} + +static void mapif_parse_mercenary_create(int fd, struct s_mercenary* merc) +{ + bool result = mapif_mercenary_save(merc); + mapif_mercenary_send(fd, merc, result); +} + +static void mapif_parse_mercenary_load(int fd, int merc_id, int char_id) +{ + struct s_mercenary merc; + bool result = mapif_mercenary_load(merc_id, char_id, &merc); + mapif_mercenary_send(fd, &merc, result); +} + +static void mapif_mercenary_deleted(int fd, unsigned char flag) +{ + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x3871; + WFIFOB(fd,2) = flag; + WFIFOSET(fd,3); +} + +static void mapif_parse_mercenary_delete(int fd, int merc_id) +{ + bool result = mapif_mercenary_delete(merc_id); + mapif_mercenary_deleted(fd, result); +} + +static void mapif_mercenary_saved(int fd, unsigned char flag) +{ + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x3872; + WFIFOB(fd,2) = flag; + WFIFOSET(fd,3); +} + +static void mapif_parse_mercenary_save(int fd, struct s_mercenary* merc) +{ + bool result = mapif_mercenary_save(merc); + mapif_mercenary_saved(fd, result); +} + +int inter_mercenary_sql_init(void) +{ + return 0; +} +void inter_mercenary_sql_final(void) +{ + return; +} + +/*========================================== + * Inter Packets + *------------------------------------------*/ +int inter_mercenary_parse_frommap(int fd) +{ + unsigned short cmd = RFIFOW(fd,0); + + switch( cmd ) + { + case 0x3070: mapif_parse_mercenary_create(fd, (struct s_mercenary*)RFIFOP(fd,4)); break; + case 0x3071: mapif_parse_mercenary_load(fd, (int)RFIFOL(fd,2), (int)RFIFOL(fd,6)); break; + case 0x3072: mapif_parse_mercenary_delete(fd, (int)RFIFOL(fd,2)); break; + case 0x3073: mapif_parse_mercenary_save(fd, (struct s_mercenary*)RFIFOP(fd,4)); break; + default: + return 0; + } + return 1; +} diff --git a/src/char/int_mercenary.h b/src/char/int_mercenary.h new file mode 100644 index 000000000..01e4a841f --- /dev/null +++ b/src/char/int_mercenary.h @@ -0,0 +1,20 @@ +// Copyright (c) Athena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + +#ifndef _INT_MERCENARY_SQL_H_ +#define _INT_MERCENARY_SQL_H_ + +struct s_mercenary; + +int inter_mercenary_sql_init(void); +void inter_mercenary_sql_final(void); +int inter_mercenary_parse_frommap(int fd); + +// Mercenary Owner Database +bool mercenary_owner_fromsql(int char_id, struct mmo_charstatus *status); +bool mercenary_owner_tosql(int char_id, struct mmo_charstatus *status); +bool mercenary_owner_delete(int char_id); + +bool mapif_mercenary_delete(int merc_id); + +#endif /* _INT_MERCENARY_SQL_H_ */ diff --git a/src/char/int_party.c b/src/char/int_party.c index 2ae9e5319..7d0dd0b75 100644 --- a/src/char/int_party.c +++ b/src/char/int_party.c @@ -3,11 +3,13 @@ #include "../common/cbasetypes.h" #include "../common/mmo.h" +#include "../common/db.h" #include "../common/malloc.h" +#include "../common/strlib.h" #include "../common/socket.h" -#include "../common/db.h" -#include "../common/lock.h" #include "../common/showmsg.h" +#include "../common/mapindex.h" +#include "../common/sql.h" #include "char.h" #include "inter.h" #include "int_party.h" @@ -16,8 +18,6 @@ #include #include -char party_txt[1024] = "save/party.txt"; -#ifndef TXT_SQL_CONVERT struct party_data { struct party party; unsigned int min_lv, max_lv; @@ -25,11 +25,11 @@ struct party_data { unsigned char size; //Total size of party. }; -static DBMap* party_db; // int party_id -> struct party_data* -static int party_newid = 100; +static struct party_data *party_pt; +static DBMap* party_db_; // int party_id -> struct party_data* -int mapif_party_broken(int party_id, int flag); -int party_check_empty(struct party *p); +int mapif_party_broken(int party_id,int flag); +int party_check_empty(struct party_data *p); int mapif_parse_PartyLeave(int fd, int party_id, int account_id, int char_id); int party_check_exp_share(struct party_data *p); int mapif_party_optionchanged(int fd,struct party *p, int account_id, int flag); @@ -41,7 +41,10 @@ static int int_party_check_lv(struct party_data *p) { p->min_lv = UINT_MAX; p->max_lv = 0; for(i=0;iparty.member[i].online) + /** + * - If not online OR if it's a family party and this is the child (doesn't affect exp range) + **/ + if(!p->party.member[i].online || p->party.member[i].char_id == p->family ) continue; lv=p->party.member[i].lv; @@ -56,7 +59,6 @@ static int int_party_check_lv(struct party_data *p) { } return 1; } - //Calculates the state of a party. static void int_party_calc_state(struct party_data *p) { @@ -68,14 +70,20 @@ static void int_party_calc_state(struct party_data *p) p->size = p->family = 0; - //Check party size. + //Check party size for(i=0;iparty.member[i].lv) continue; p->size++; if(p->party.member[i].online) p->party.count++; } - if(p->size == 3) { + if( p->size == 2 && ( char_child(p->party.member[0].char_id,p->party.member[1].char_id) || char_child(p->party.member[1].char_id,p->party.member[0].char_id) ) ) { + //Child should be able to share with either of their parents [RoM] + if(p->party.member[0].class_&0x2000) //first slot is the child? + p->family = p->party.member[0].char_id; + else + p->family = p->party.member[1].char_id; + } else if( p->size == 3 ) { //Check Family State. p->family = char_family( p->party.member[0].char_id, @@ -103,212 +111,244 @@ static void int_party_calc_state(struct party_data *p) return; } -// パ?ティデ?タの文字列への?換 -int inter_party_tostr(char *str, struct party *p) { - int i, len; +// Save party to mysql +int inter_party_tosql(struct party *p, int flag, int index) +{ + // 'party' ('party_id','name','exp','item','leader_id','leader_char') + char esc_name[NAME_LENGTH*2+1];// escaped party name + int party_id; - len = sprintf(str, "%d\t%s\t%d,%d\t", p->party_id, p->name, p->exp, p->item); - for(i = 0; i < MAX_PARTY; i++) { - struct party_member *m = &p->member[i]; - len += sprintf(str + len, "%d,%d,%d\t", m->account_id, m->char_id, m->leader); - } + if( p == NULL || p->party_id == 0 ) + return 0; + party_id = p->party_id; - return 0; -} -#endif //TXT_SQL_CONVERT -// パ?ティデ?タの文字列からの?換 -int inter_party_fromstr(char *str, struct party *p) { - int i, j; - int tmp_int[16]; - char tmp_str[256]; -#ifndef TXT_SQL_CONVERT - struct mmo_charstatus* status; +#ifdef NOISY + ShowInfo("Save party request ("CL_BOLD"%d"CL_RESET" - %s).\n", party_id, p->name); #endif - - memset(p, 0, sizeof(struct party)); - - if (sscanf(str, "%d\t%255[^\t]\t%d,%d\t", &tmp_int[0], tmp_str, &tmp_int[1], &tmp_int[2]) != 4) + Sql_EscapeStringLen(sql_handle, esc_name, p->name, strnlen(p->name, NAME_LENGTH)); + + if( flag & PS_BREAK ) + {// Break the party + // we'll skip name-checking and just reset everyone with the same party id [celest] + if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `party_id`='0' WHERE `party_id`='%d'", char_db, party_id) ) + Sql_ShowDebug(sql_handle); + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `party_id`='%d'", party_db, party_id) ) + Sql_ShowDebug(sql_handle); + //Remove from memory + idb_remove(party_db_, party_id); return 1; + } - p->party_id = tmp_int[0]; - memcpy(p->name, tmp_str, NAME_LENGTH); - p->exp = tmp_int[1]?1:0; - p->item = tmp_int[2]; - - for(j = 0; j < 3 && str != NULL; j++) - str = strchr(str + 1, '\t'); - - for(i = 0; i < MAX_PARTY; i++) { - struct party_member *m = &p->member[i]; - if (str == NULL) - return 1; + if( flag & PS_CREATE ) + {// Create party + if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` " + "(`name`, `exp`, `item`, `leader_id`, `leader_char`) " + "VALUES ('%s', '%d', '%d', '%d', '%d')", + party_db, esc_name, p->exp, p->item, p->member[index].account_id, p->member[index].char_id) ) + { + Sql_ShowDebug(sql_handle); + return 0; + } + party_id = p->party_id = (int)Sql_LastInsertId(sql_handle); + } - if (sscanf(str + 1, "%d,%d,%d\t", &tmp_int[0], &tmp_int[1], &tmp_int[2]) != 3) - return 1; + if( flag & PS_BASIC ) + {// Update party info. + if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `name`='%s', `exp`='%d', `item`='%d' WHERE `party_id`='%d'", + party_db, esc_name, p->exp, p->item, party_id) ) + Sql_ShowDebug(sql_handle); + } - m->account_id = tmp_int[0]; - m->char_id = tmp_int[1]; - m->leader = tmp_int[2]?1:0; + if( flag & PS_LEADER ) + {// Update leader + if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `leader_id`='%d', `leader_char`='%d' WHERE `party_id`='%d'", + party_db, p->member[index].account_id, p->member[index].char_id, party_id) ) + Sql_ShowDebug(sql_handle); + } + + if( flag & PS_ADDMEMBER ) + {// Add one party member. + if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `party_id`='%d' WHERE `account_id`='%d' AND `char_id`='%d'", + char_db, party_id, p->member[index].account_id, p->member[index].char_id) ) + Sql_ShowDebug(sql_handle); + } - str = strchr(str + 1, '\t'); -#ifndef TXT_SQL_CONVERT - if (!m->account_id) continue; - //Lookup player for rest of data. - status = search_character(m->account_id, m->char_id); - if (!status) continue; - - memcpy(m->name, status->name, NAME_LENGTH); - m->class_ = status->class_; - m->map = status->last_point.map; - m->lv = status->base_level; -#endif //TXT_SQL_CONVERT + if( flag & PS_DELMEMBER ) + {// Remove one party member. + if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `party_id`='0' WHERE `party_id`='%d' AND `account_id`='%d' AND `char_id`='%d'", + char_db, party_id, p->member[index].account_id, p->member[index].char_id) ) + Sql_ShowDebug(sql_handle); } - return 0; + if( save_log ) + ShowInfo("Party Saved (%d - %s)\n", party_id, p->name); + return 1; } -#ifndef TXT_SQL_CONVERT -// パ?ティデ?タのロ?ド -int inter_party_init() { - char line[8192]; - struct party_data *p; - FILE *fp; - int c = 0; - int i, j; - party_db = idb_alloc(DB_OPT_RELEASE_DATA); +// Read party from mysql +struct party_data *inter_party_fromsql(int party_id) +{ + int leader_id = 0; + int leader_char = 0; + struct party_data* p; + struct party_member* m; + char* data; + size_t len; + int i; - if ((fp = fopen(party_txt, "r")) == NULL) - return 1; +#ifdef NOISY + ShowInfo("Load party request ("CL_BOLD"%d"CL_RESET")\n", party_id); +#endif + if( party_id <= 0 ) + return NULL; + + //Load from memory + p = (struct party_data*)idb_get(party_db_, party_id); + if( p != NULL ) + return p; - while(fgets(line, sizeof(line), fp)) - { - j = 0; - if (sscanf(line, "%d\t%%newid%%\n%n", &i, &j) == 1 && j > 0 && party_newid <= i) { - party_newid = i; - continue; - } + p = party_pt; + memset(p, 0, sizeof(struct party_data)); - p = (struct party_data*)aCalloc(sizeof(struct party_data), 1); - if (p == NULL){ - ShowFatalError("int_party: out of memory!\n"); - exit(EXIT_FAILURE); - } - memset(p, 0, sizeof(struct party_data)); - if (inter_party_fromstr(line, &p->party) == 0 && p->party.party_id > 0) { - int_party_calc_state(p); - if (p->party.party_id >= party_newid) - party_newid = p->party.party_id + 1; - idb_put(party_db, p->party.party_id, p); - party_check_empty(&p->party); - } else { - ShowError("int_party: broken data [%s] line %d\n", party_txt, c + 1); - aFree(p); - } - c++; + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `party_id`, `name`,`exp`,`item`, `leader_id`, `leader_char` FROM `%s` WHERE `party_id`='%d'", party_db, party_id) ) + { + Sql_ShowDebug(sql_handle); + return NULL; } - fclose(fp); - return 0; -} + if( SQL_SUCCESS != Sql_NextRow(sql_handle) ) + return NULL; -void inter_party_final() -{ - party_db->destroy(party_db, NULL); - return; -} + p->party.party_id = party_id; + Sql_GetData(sql_handle, 1, &data, &len); memcpy(p->party.name, data, min(len, NAME_LENGTH)); + Sql_GetData(sql_handle, 2, &data, NULL); p->party.exp = (atoi(data) ? 1 : 0); + Sql_GetData(sql_handle, 3, &data, NULL); p->party.item = atoi(data); + Sql_GetData(sql_handle, 4, &data, NULL); leader_id = atoi(data); + Sql_GetData(sql_handle, 5, &data, NULL); leader_char = atoi(data); + Sql_FreeResult(sql_handle); -// パ?ティ?デ?タのセ?ブ用 -int inter_party_save_sub(DBKey key, void *data, va_list ap) { - char line[8192]; - FILE *fp; + // Load members + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id`,`char_id`,`name`,`base_level`,`last_map`,`online`,`class` FROM `%s` WHERE `party_id`='%d'", char_db, party_id) ) + { + Sql_ShowDebug(sql_handle); + return NULL; + } + for( i = 0; i < MAX_PARTY && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i ) + { + m = &p->party.member[i]; + Sql_GetData(sql_handle, 0, &data, NULL); m->account_id = atoi(data); + Sql_GetData(sql_handle, 1, &data, NULL); m->char_id = atoi(data); + Sql_GetData(sql_handle, 2, &data, &len); memcpy(m->name, data, min(len, NAME_LENGTH)); + Sql_GetData(sql_handle, 3, &data, NULL); m->lv = atoi(data); + Sql_GetData(sql_handle, 4, &data, NULL); m->map = mapindex_name2id(data); + Sql_GetData(sql_handle, 5, &data, NULL); m->online = (atoi(data) ? 1 : 0); + Sql_GetData(sql_handle, 6, &data, NULL); m->class_ = atoi(data); + m->leader = (m->account_id == leader_id && m->char_id == leader_char ? 1 : 0); + } + Sql_FreeResult(sql_handle); + + if( save_log ) + ShowInfo("Party loaded (%d - %s).\n", party_id, p->party.name); + //Add party to memory. + CREATE(p, struct party_data, 1); + memcpy(p, party_pt, sizeof(struct party_data)); + //init state + int_party_calc_state(p); + idb_put(party_db_, party_id, p); + return p; +} - inter_party_tostr(line, &((struct party_data*)data)->party); - fp = va_arg(ap, FILE *); - fprintf(fp, "%s\n", line); +int inter_party_sql_init(void) +{ + //memory alloc + party_db_ = idb_alloc(DB_OPT_RELEASE_DATA); + party_pt = (struct party_data*)aCalloc(sizeof(struct party_data), 1); + if (!party_pt) { + ShowFatalError("inter_party_sql_init: Out of Memory!\n"); + exit(EXIT_FAILURE); + } + /* Uncomment the following if you want to do a party_db cleanup (remove parties with no members) on startup.[Skotlex] + ShowStatus("cleaning party table...\n"); + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` USING `%s` LEFT JOIN `%s` ON `%s`.leader_id =`%s`.account_id AND `%s`.leader_char = `%s`.char_id WHERE `%s`.account_id IS NULL", + party_db, party_db, char_db, party_db, char_db, party_db, char_db, char_db) ) + Sql_ShowDebug(sql_handle); + */ return 0; } -// パ?ティ?デ?タのセ?ブ -int inter_party_save() { - FILE *fp; - int lock; - - if ((fp = lock_fopen(party_txt, &lock)) == NULL) { - ShowError("int_party: can't write [%s] !!! data is lost !!!\n", party_txt); - return 1; - } - party_db->foreach(party_db, inter_party_save_sub, fp); - lock_fclose(fp,party_txt, &lock); - return 0; +void inter_party_sql_final(void) +{ + party_db_->destroy(party_db_, NULL); + aFree(party_pt); + return; } // Search for the party according to its name -struct party_data* search_partyname(char *str) +struct party_data* search_partyname(char* str) { - struct DBIterator* iter; - struct party_data* p; - struct party_data* result = NULL; - - iter = party_db->iterator(party_db); - for( p = (struct party_data*)iter->first(iter,NULL); iter->exists(iter); p = (struct party_data*)iter->next(iter,NULL) ) + char esc_name[NAME_LENGTH*2+1]; + char* data; + struct party_data* p = NULL; + + Sql_EscapeStringLen(sql_handle, esc_name, str, safestrnlen(str, NAME_LENGTH)); + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `party_id` FROM `%s` WHERE `name`='%s'", party_db, esc_name) ) + Sql_ShowDebug(sql_handle); + else if( SQL_SUCCESS == Sql_NextRow(sql_handle) ) { - if( strncmpi(p->party.name, str, NAME_LENGTH) == 0 ) - { - result = p; - break; - } + Sql_GetData(sql_handle, 0, &data, NULL); + p = inter_party_fromsql(atoi(data)); } - iter->destroy(iter); + Sql_FreeResult(sql_handle); - return result; + return p; } // Returns whether this party can keep having exp share or not. -int party_check_exp_share(struct party_data *p) { - return (p->party.count < 2|| p->max_lv - p->min_lv <= party_share_level); +int party_check_exp_share(struct party_data *p) +{ + return (p->party.count < 2 || p->max_lv - p->min_lv <= party_share_level); } -// パ?ティが空かどうかチェック -int party_check_empty(struct party *p) { +// Is there any member in the party? +int party_check_empty(struct party_data *p) +{ int i; - - for(i = 0; i < MAX_PARTY; i++) { - if (p->member[i].account_id > 0) { - return 0; - } - } - mapif_party_broken(p->party_id, 0); - idb_remove(party_db, p->party_id); - + if (p==NULL||p->party.party_id==0) return 1; + for(i=0;iparty.member[i].account_id;i++); + if (i < MAX_PARTY) return 0; + // If there is no member, then break the party + mapif_party_broken(p->party.party_id,0); + inter_party_tosql(&p->party, PS_BREAK, 0); return 1; } //------------------------------------------------------------------- // map serverへの通信 -// パ?ティ作成可否 -int mapif_party_created(int fd,int account_id, int char_id, struct party *p) +// パーティ作成可否 +int mapif_party_created(int fd,int account_id,int char_id,struct party *p) { WFIFOHEAD(fd, 39); - WFIFOW(fd,0) = 0x3820; - WFIFOL(fd,2) = account_id; - WFIFOL(fd,6) = char_id; - if (p != NULL) { - WFIFOB(fd,10) = 0; - WFIFOL(fd,11) = p->party_id; - memcpy(WFIFOP(fd,15), p->name, NAME_LENGTH); - ShowInfo("Created party (%d - %s)\n", p->party_id, p->name); - } else { - WFIFOB(fd,10) = 1; - WFIFOL(fd,11) = 0; - memset(WFIFOP(fd,15), 0, NAME_LENGTH); + WFIFOW(fd,0)=0x3820; + WFIFOL(fd,2)=account_id; + WFIFOL(fd,6)=char_id; + if(p!=NULL){ + WFIFOB(fd,10)=0; + WFIFOL(fd,11)=p->party_id; + memcpy(WFIFOP(fd,15),p->name,NAME_LENGTH); + ShowInfo("int_party: Party created (%d - %s)\n",p->party_id,p->name); + }else{ + WFIFOB(fd,10)=1; + WFIFOL(fd,11)=0; + memset(WFIFOP(fd,15),0,NAME_LENGTH); } WFIFOSET(fd,39); + return 0; } -// パ?ティ情報見つからず +// パーティ情報見つからず static void mapif_party_noinfo(int fd, int party_id, int char_id) { WFIFOHEAD(fd, 12); @@ -319,8 +359,7 @@ static void mapif_party_noinfo(int fd, int party_id, int char_id) WFIFOSET(fd,12); ShowWarning("int_party: info not found (party_id=%d char_id=%d)\n", party_id, char_id); } - -// パ?ティ情報まとめ送り +// パーティ情報まとめ送り static void mapif_party_info(int fd, struct party* p, int char_id) { unsigned char buf[8 + sizeof(struct party)]; @@ -328,13 +367,13 @@ static void mapif_party_info(int fd, struct party* p, int char_id) WBUFW(buf,2) = 8 + sizeof(struct party); WBUFL(buf,4) = char_id; memcpy(WBUFP(buf,8), p, sizeof(struct party)); - if (fd < 0) - mapif_sendall(buf, WBUFW(buf,2)); + + if(fd<0) + mapif_sendall(buf,WBUFW(buf,2)); else - mapif_send(fd, buf, WBUFW(buf,2)); + mapif_send(fd,buf,WBUFW(buf,2)); } - -// パ?ティメンバ追加可否 +// パーティメンバ追加可否 int mapif_party_memberadded(int fd, int party_id, int account_id, int char_id, int flag) { WFIFOHEAD(fd, 15); WFIFOW(fd,0) = 0x3822; @@ -347,24 +386,24 @@ int mapif_party_memberadded(int fd, int party_id, int account_id, int char_id, i return 0; } -// パ?ティ設定?更通知 -int mapif_party_optionchanged(int fd,struct party *p, int account_id, int flag) { - unsigned char buf[15]; - - WBUFW(buf,0) = 0x3823; - WBUFL(buf,2) = p->party_id; - WBUFL(buf,6) = account_id; - WBUFW(buf,10) = p->exp; - WBUFW(buf,12) = p->item; - WBUFB(buf,14) = flag; - if (flag == 0) - mapif_sendall(buf, 15); +// パーティ設定変更通知 +int mapif_party_optionchanged(int fd,struct party *p,int account_id,int flag) +{ + unsigned char buf[16]; + WBUFW(buf,0)=0x3823; + WBUFL(buf,2)=p->party_id; + WBUFL(buf,6)=account_id; + WBUFW(buf,10)=p->exp; + WBUFW(buf,12)=p->item; + WBUFB(buf,14)=flag; + if(flag==0) + mapif_sendall(buf,15); else - mapif_send(fd, buf, 15); + mapif_send(fd,buf,15); return 0; } -// パ?ティ?退通知 +// パーティ脱退通知 int mapif_party_withdraw(int party_id,int account_id, int char_id) { unsigned char buf[16]; @@ -376,8 +415,9 @@ int mapif_party_withdraw(int party_id,int account_id, int char_id) { return 0; } -// パ?ティマップ更新通知 -int mapif_party_membermoved(struct party *p, int idx) { +// パーティマップ更新通知 +int mapif_party_membermoved(struct party *p,int idx) +{ unsigned char buf[20]; WBUFW(buf,0) = 0x3825; @@ -391,29 +431,27 @@ int mapif_party_membermoved(struct party *p, int idx) { return 0; } -// パ?ティ解散通知 -int mapif_party_broken(int party_id, int flag) { - unsigned char buf[7]; - WBUFW(buf,0) = 0x3826; - WBUFL(buf,2) = party_id; - WBUFB(buf,6) = flag; - mapif_sendall(buf, 7); - ShowInfo("Party broken (%d)\n", party_id); - +// パーティ解散通知 +int mapif_party_broken(int party_id,int flag) +{ + unsigned char buf[16]; + WBUFW(buf,0)=0x3826; + WBUFL(buf,2)=party_id; + WBUFB(buf,6)=flag; + mapif_sendall(buf,7); + //printf("int_party: broken %d\n",party_id); return 0; } - -// パ?ティ??言 -int mapif_party_message(int party_id, int account_id, char *mes, int len, int sfd) { - unsigned char buf[2048]; - - WBUFW(buf,0) = 0x3827; - WBUFW(buf,2) = len + 12; - WBUFL(buf,4) = party_id; - WBUFL(buf,8) = account_id; - memcpy(WBUFP(buf,12), mes, len); - mapif_sendallwos(sfd, buf,len + 12); - +// パーティ内発言 +int mapif_party_message(int party_id,int account_id,char *mes,int len, int sfd) +{ + unsigned char buf[512]; + WBUFW(buf,0)=0x3827; + WBUFW(buf,2)=len+12; + WBUFL(buf,4)=party_id; + WBUFL(buf,8)=account_id; + memcpy(WBUFP(buf,12),mes,len); + mapif_sendallwos(sfd, buf,len+12); return 0; } @@ -421,83 +459,72 @@ int mapif_party_message(int party_id, int account_id, char *mes, int len, int sf // map serverからの通信 -// パ?ティ +// Create Party int mapif_parse_CreateParty(int fd, char *name, int item, int item2, struct party_member *leader) { struct party_data *p; int i; - - //FIXME: this should be removed once the savefiles can handle all symbols - for(i = 0; i < NAME_LENGTH && name[i]; i++) { - if (!(name[i] & 0xe0) || name[i] == 0x7f) { - ShowInfo("int_party: illegal party name [%s]\n", name); - mapif_party_created(fd, leader->account_id, leader->char_id, NULL); - return 0; - } - } - - if ((p = search_partyname(name)) != NULL) { - ShowInfo("int_party: same name party exists [%s]\n", name); - mapif_party_created(fd, leader->account_id, leader->char_id, NULL); + if( (p=search_partyname(name))!=NULL){ + mapif_party_created(fd,leader->account_id,leader->char_id,NULL); return 0; } - // Check Authorised letters/symbols in the name of the character if (char_name_option == 1) { // only letters/symbols in char_name_letters are authorised for (i = 0; i < NAME_LENGTH && name[i]; i++) if (strchr(char_name_letters, name[i]) == NULL) { - mapif_party_created(fd, leader->account_id, leader->char_id, NULL); + mapif_party_created(fd,leader->account_id,leader->char_id,NULL); return 0; } } else if (char_name_option == 2) { // letters/symbols in char_name_letters are forbidden for (i = 0; i < NAME_LENGTH && name[i]; i++) if (strchr(char_name_letters, name[i]) != NULL) { - mapif_party_created(fd, leader->account_id, leader->char_id, NULL); + mapif_party_created(fd,leader->account_id,leader->char_id,NULL); return 0; } } - p = (struct party_data *) aCalloc(sizeof(struct party_data), 1); - if (p == NULL) { - ShowFatalError("int_party: out of memory !\n"); - mapif_party_created(fd,leader->account_id,leader->char_id,NULL); - return 0; - } - p->party.party_id = party_newid++; - memcpy(p->party.name, name, NAME_LENGTH); - p->party.exp = 0; + p = (struct party_data*)aCalloc(1, sizeof(struct party_data)); + + memcpy(p->party.name,name,NAME_LENGTH); + p->party.exp=0; p->party.item=(item?1:0)|(item2?2:0); + memcpy(&p->party.member[0], leader, sizeof(struct party_member)); - p->party.member[0].leader = 1; - int_party_calc_state(p); - idb_put(party_db, p->party.party_id, p); + p->party.member[0].leader=1; + p->party.member[0].online=1; - mapif_party_info(fd, &p->party, 0); - mapif_party_created(fd, leader->account_id, leader->char_id, &p->party); + p->party.party_id=-1;//New party. + if (inter_party_tosql(&p->party,PS_CREATE|PS_ADDMEMBER,0)) { + //Add party to db + int_party_calc_state(p); + idb_put(party_db_, p->party.party_id, p); + mapif_party_info(fd, &p->party, 0); + mapif_party_created(fd,leader->account_id,leader->char_id,&p->party); + } else { //Failed to create party. + aFree(p); + mapif_party_created(fd,leader->account_id,leader->char_id,NULL); + } return 0; } - -// パ?ティ情報要求 +// パーティ情報要求 static void mapif_parse_PartyInfo(int fd, int party_id, int char_id) { struct party_data *p; + p = inter_party_fromsql(party_id); - p = (struct party_data*)idb_get(party_db, party_id); - if (p != NULL) + if (p) mapif_party_info(fd, &p->party, char_id); - else { + else mapif_party_noinfo(fd, party_id, char_id); - } } - -// パーティ追加要求 +// パーティ追加要求 int mapif_parse_PartyAddMember(int fd, int party_id, struct party_member *member) { struct party_data *p; int i; - p = (struct party_data*)idb_get(party_db, party_id); + p = inter_party_fromsql(party_id); if( p == NULL || p->size == MAX_PARTY ) { mapif_party_memberadded(fd, party_id, member->account_id, member->char_id, 1); return 0; @@ -514,7 +541,7 @@ int mapif_parse_PartyAddMember(int fd, int party_id, struct party_member *member p->party.member[i].leader = 0; if (p->party.member[i].online) p->party.count++; p->size++; - if (p->size == 3) //Check family state. + if (p->size == 2 || p->size == 3) // Check family state. And also accept either of their Parents. [RoM] int_party_calc_state(p); else //Check even share range. if (member->lv < p->min_lv || member->lv > p->max_lv || p->family) { @@ -524,67 +551,89 @@ int mapif_parse_PartyAddMember(int fd, int party_id, struct party_member *member mapif_party_info(-1, &p->party, 0); mapif_party_memberadded(fd, party_id, member->account_id, member->char_id, 0); + inter_party_tosql(&p->party, PS_ADDMEMBER, i); return 0; } -// パ?ティ?設定?更要求 -int mapif_parse_PartyChangeOption(int fd, int party_id, int account_id, int exp, int item) +// パーティー設定変更要求 +int mapif_parse_PartyChangeOption(int fd,int party_id,int account_id,int exp,int item) { struct party_data *p; int flag = 0; + p = inter_party_fromsql(party_id); - p = (struct party_data*)idb_get(party_db, party_id); - if (p == NULL) + if(!p) return 0; - p->party.exp = exp; - if (exp>0 && !party_check_exp_share(p)) { - flag |= 0x01; - p->party.exp = 0; + p->party.exp=exp; + if( exp && !party_check_exp_share(p) ){ + flag|=0x01; + p->party.exp=0; } - p->party.item = item&0x3; - mapif_party_optionchanged(fd, &p->party, account_id, flag); + p->party.item = item&0x3; //Filter out invalid values. + mapif_party_optionchanged(fd,&p->party,account_id,flag); + inter_party_tosql(&p->party, PS_BASIC, 0); return 0; } - -// パ?ティ?退要求 +// パーティ脱退要求 int mapif_parse_PartyLeave(int fd, int party_id, int account_id, int char_id) { struct party_data *p; - int i,lv; + int i,j=-1; - p = (struct party_data*)idb_get(party_db, party_id); - if (!p) return 0; + p = inter_party_fromsql(party_id); + if( p == NULL ) + {// Party does not exists? + if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `party_id`='0' WHERE `party_id`='%d'", char_db, party_id) ) + Sql_ShowDebug(sql_handle); + return 0; + } - for(i = 0; i < MAX_PARTY; i++) { + for (i = 0; i < MAX_PARTY; i++) { if(p->party.member[i].account_id == account_id && - p->party.member[i].char_id == char_id) + p->party.member[i].char_id == char_id) { + break; + } + } + if (i >= MAX_PARTY) + return 0; //Member not found? + + mapif_party_withdraw(party_id, account_id, char_id); + + if (p->party.member[i].leader){ + p->party.member[i].account_id = 0; + for (j = 0; j < MAX_PARTY; j++) { + if (!p->party.member[j].account_id) + continue; + mapif_party_withdraw(party_id, p->party.member[j].account_id, p->party.member[j].char_id); + p->party.member[j].account_id = 0; + } + //Party gets deleted on the check_empty call below. + } else { + inter_party_tosql(&p->party,PS_DELMEMBER,i); + j = p->party.member[i].lv; + if(p->party.member[i].online) p->party.count--; + memset(&p->party.member[i], 0, sizeof(struct party_member)); + p->size--; + if (j == p->min_lv || j == p->max_lv || p->family) { - mapif_party_withdraw(party_id, account_id, char_id); - lv = p->party.member[i].lv; - if(p->party.member[i].online) p->party.count--; - memset(&p->party.member[i], 0, sizeof(struct party_member)); - p->size--; - if (lv == p->min_lv || lv == p->max_lv || p->family) - { - if(p->family) p->family = 0; //Family state broken. - int_party_check_lv(p); - } - if (party_check_empty(&p->party) == 0) - mapif_party_info(-1, &p->party, 0); - return 0; + if(p->family) p->family = 0; //Family state broken. + int_party_check_lv(p); } } + + if (party_check_empty(p) == 0) + mapif_party_info(-1, &p->party, 0); return 0; } - +// When member goes to other map or levels up. int mapif_parse_PartyChangeMap(int fd, int party_id, int account_id, int char_id, unsigned short map, int online, unsigned int lv) { struct party_data *p; int i; - p = (struct party_data*)idb_get(party_db, party_id); + p = inter_party_fromsql(party_id); if (p == NULL) return 0; @@ -615,6 +664,7 @@ int mapif_parse_PartyChangeMap(int fd, int party_id, int account_id, int char_id //Send online/offline update. mapif_party_membermoved(&p->party, i); } + if (p->party.member[i].lv != lv) { if(p->party.member[i].lv == p->min_lv || p->party.member[i].lv == p->max_lv) @@ -626,6 +676,7 @@ int mapif_parse_PartyChangeMap(int fd, int party_id, int account_id, int char_id //There is no need to send level update to map servers //since they do nothing with it. } + if (p->party.member[i].map != map) { p->party.member[i].map = map; mapif_party_membermoved(&p->party, i); @@ -633,19 +684,23 @@ int mapif_parse_PartyChangeMap(int fd, int party_id, int account_id, int char_id return 0; } -// パ?ティ解散要求 -int mapif_parse_BreakParty(int fd, int party_id) { +// パーティ解散要求 +int mapif_parse_BreakParty(int fd,int party_id) +{ + struct party_data *p; - idb_remove(party_db, party_id); - mapif_party_broken(fd, party_id); + p = inter_party_fromsql(party_id); + if(!p) + return 0; + inter_party_tosql(&p->party,PS_BREAK,0); + mapif_party_broken(fd,party_id); return 0; } - -// パ?ティメッセ?ジ送信 -int mapif_parse_PartyMessage(int fd, int party_id, int account_id, char *mes, int len) +// パーティメッセージ送信 +int mapif_parse_PartyMessage(int fd,int party_id,int account_id,char *mes,int len) { - return mapif_party_message(party_id, account_id, mes, len, fd); + return mapif_party_message(party_id,account_id,mes,len, fd); } int mapif_parse_PartyLeaderChange(int fd,int party_id,int account_id,int char_id) @@ -653,8 +708,9 @@ int mapif_parse_PartyLeaderChange(int fd,int party_id,int account_id,int char_id struct party_data *p; int i; - p = (struct party_data*)idb_get(party_db, party_id); - if (p == NULL) + p = inter_party_fromsql(party_id); + + if(!p) return 0; for (i = 0; i < MAX_PARTY; i++) @@ -663,17 +719,21 @@ int mapif_parse_PartyLeaderChange(int fd,int party_id,int account_id,int char_id p->party.member[i].leader = 0; if(p->party.member[i].account_id == account_id && p->party.member[i].char_id == char_id) + { p->party.member[i].leader = 1; + inter_party_tosql(&p->party,PS_LEADER, i); + } } return 1; } // map server からの通信 -// ?1パケットのみ解析すること -// ?パケット長デ?タはinter.cにセットしておくこと -// ?パケット長チェックや、RFIFOSKIPは呼び出し元で行われるので行ってはならない -// ?エラ?なら0(false)、そうでないなら1(true)をかえさなければならない -int inter_party_parse_frommap(int fd) { +// ・1パケットのみ解析すること +// ・パケット長データはinter.cにセットしておくこと +// ・パケット長チェックや、RFIFOSKIPは呼び出し元で行われるので行ってはならない +// ・エラーなら0(false)、そうでないなら1(true)をかえさなければならない +int inter_party_parse_frommap(int fd) +{ RFIFOHEAD(fd); switch(RFIFOW(fd,0)) { case 0x3020: mapif_parse_CreateParty(fd, (char*)RFIFOP(fd,4), RFIFOB(fd,28), RFIFOB(fd,29), (struct party_member*)RFIFOP(fd,30)); break; @@ -688,12 +748,105 @@ int inter_party_parse_frommap(int fd) { default: return 0; } + return 1; +} + +// サーバーから脱退要求(キャラ削除用) +int inter_party_leave(int party_id,int account_id, int char_id) +{ + return mapif_parse_PartyLeave(-1,party_id,account_id, char_id); +} + +int inter_party_CharOnline(int char_id, int party_id) +{ + struct party_data* p; + int i; + + if( party_id == -1 ) + {// Get party_id from the database + char* data; + + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT party_id FROM `%s` WHERE char_id='%d'", char_db, char_id) ) + { + Sql_ShowDebug(sql_handle); + return 0; + } + if( SQL_SUCCESS != Sql_NextRow(sql_handle) ) + return 0; //Eh? No party? + + Sql_GetData(sql_handle, 0, &data, NULL); + party_id = atoi(data); + Sql_FreeResult(sql_handle); + } + if (party_id == 0) + return 0; //No party... + + p = inter_party_fromsql(party_id); + if(!p) { + ShowError("Character %d's party %d not found!\n", char_id, party_id); + return 0; + } + + //Set member online + for(i=0; iparty.member[i].char_id == char_id) { + if (!p->party.member[i].online) { + p->party.member[i].online = 1; + p->party.count++; + if (p->party.member[i].lv < p->min_lv || + p->party.member[i].lv > p->max_lv) + int_party_check_lv(p); + } + break; + } + } return 1; } -// サ?バ?から?退要求(キャラ削除用) -int inter_party_leave(int party_id, int account_id, int char_id) { - return mapif_parse_PartyLeave(-1, party_id, account_id, char_id); +int inter_party_CharOffline(int char_id, int party_id) { + struct party_data *p=NULL; + int i; + + if( party_id == -1 ) + {// Get guild_id from the database + char* data; + + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT party_id FROM `%s` WHERE char_id='%d'", char_db, char_id) ) + { + Sql_ShowDebug(sql_handle); + return 0; + } + + if( SQL_SUCCESS != Sql_NextRow(sql_handle) ) + return 0; //Eh? No party? + + Sql_GetData(sql_handle, 0, &data, NULL); + party_id = atoi(data); + Sql_FreeResult(sql_handle); + } + if (party_id == 0) + return 0; //No party... + + //Character has a party, set character offline and check if they were the only member online + if ((p = inter_party_fromsql(party_id)) == NULL) + return 0; + + //Set member offline + for(i=0; i< MAX_PARTY; i++) { + if(p->party.member[i].char_id == char_id) + { + p->party.member[i].online = 0; + p->party.count--; + if(p->party.member[i].lv == p->min_lv || + p->party.member[i].lv == p->max_lv) + int_party_check_lv(p); + break; + } + } + + if(!p->party.count) + //Parties don't have any data that needs be saved at this point... so just remove it from memory. + idb_remove(party_db_, party_id); + return 1; } -#endif //TXT_SQL_CONVERT diff --git a/src/char/int_party.h b/src/char/int_party.h index ad724e475..d7965c33b 100644 --- a/src/char/int_party.h +++ b/src/char/int_party.h @@ -1,20 +1,32 @@ // Copyright (c) Athena Dev Teams - Licensed under GNU GPL // For more information, see LICENCE in the main folder -#ifndef _INT_PARTY_H_ -#define _INT_PARTY_H_ +#ifndef _INT_PARTY_SQL_H_ +#define _INT_PARTY_SQL_H_ + +//Party Flags on what to save/delete. +//Create a new party entry (index holds leader's info) +#define PS_CREATE 0x01 +//Update basic party info. +#define PS_BASIC 0x02 +//Update party's leader +#define PS_LEADER 0x04 +//Specify new party member (index specifies which party member) +#define PS_ADDMEMBER 0x08 +//Specify member that left (index specifies which party member) +#define PS_DELMEMBER 0x10 +//Specify that this party must be deleted. +#define PS_BREAK 0x20 struct party; -int inter_party_init(void); -void inter_party_final(void); -int inter_party_save(void); int inter_party_parse_frommap(int fd); +int inter_party_sql_init(void); +void inter_party_sql_final(void); int inter_party_leave(int party_id,int account_id, int char_id); +int inter_party_CharOnline(int char_id, int party_id); +int inter_party_CharOffline(int char_id, int party_id); +//Required for the TXT->SQL converter +int inter_party_tosql(struct party *p, int flag, int index); -extern char party_txt[1024]; - -//For the TXT->SQL converter -int inter_party_fromstr(char *str, struct party *p); - -#endif /* _INT_PARTY_H_ */ +#endif /* _INT_PARTY_SQL_H_ */ diff --git a/src/char/int_pet.c b/src/char/int_pet.c index 41d61fbc3..114398290 100644 --- a/src/char/int_pet.c +++ b/src/char/int_pet.c @@ -4,307 +4,251 @@ #include "../common/mmo.h" #include "../common/malloc.h" #include "../common/socket.h" -#include "../common/db.h" -#include "../common/lock.h" +#include "../common/strlib.h" #include "../common/showmsg.h" +#include "../common/utils.h" +#include "../common/sql.h" #include "char.h" #include "inter.h" -#include "int_pet.h" #include #include #include -char pet_txt[1024]="save/pet.txt"; +struct s_pet *pet_pt; -#ifndef TXT_SQL_CONVERT -static DBMap* pet_db; // int pet_id -> struct s_pet* -static int pet_newid = 100; - -int inter_pet_tostr(char *str,struct s_pet *p) +//--------------------------------------------------------- +int inter_pet_tosql(int pet_id, struct s_pet* p) { - int len; - - if(p->hungry < 0) - p->hungry = 0; - else if(p->hungry > 100) - p->hungry = 100; - if(p->intimate < 0) - p->intimate = 0; - else if(p->intimate > 1000) - p->intimate = 1000; - - len=sprintf(str,"%d,%d,%s\t%d,%d,%d,%d,%d,%d,%d,%d,%d", - p->pet_id,p->class_,p->name,p->account_id,p->char_id,p->level,p->egg_id, - p->equip,p->intimate,p->hungry,p->rename_flag,p->incuvate); + //`pet` (`pet_id`, `class`,`name`,`account_id`,`char_id`,`level`,`egg_id`,`equip`,`intimate`,`hungry`,`rename_flag`,`incuvate`) + char esc_name[NAME_LENGTH*2+1];// escaped pet name + + Sql_EscapeStringLen(sql_handle, esc_name, p->name, strnlen(p->name, NAME_LENGTH)); + p->hungry = cap_value(p->hungry, 0, 100); + p->intimate = cap_value(p->intimate, 0, 1000); + + if( pet_id == -1 ) + {// New pet. + if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` " + "(`class`,`name`,`account_id`,`char_id`,`level`,`egg_id`,`equip`,`intimate`,`hungry`,`rename_flag`,`incuvate`) " + "VALUES ('%d', '%s', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d')", + pet_db, p->class_, esc_name, p->account_id, p->char_id, p->level, p->egg_id, + p->equip, p->intimate, p->hungry, p->rename_flag, p->incuvate) ) + { + Sql_ShowDebug(sql_handle); + return 0; + } + p->pet_id = (int)Sql_LastInsertId(sql_handle); + } + else + {// Update pet. + if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `class`='%d',`name`='%s',`account_id`='%d',`char_id`='%d',`level`='%d',`egg_id`='%d',`equip`='%d',`intimate`='%d',`hungry`='%d',`rename_flag`='%d',`incuvate`='%d' WHERE `pet_id`='%d'", + pet_db, p->class_, esc_name, p->account_id, p->char_id, p->level, p->egg_id, + p->equip, p->intimate, p->hungry, p->rename_flag, p->incuvate, p->pet_id) ) + { + Sql_ShowDebug(sql_handle); + return 0; + } + } - return 0; + if (save_log) + ShowInfo("Pet saved %d - %s.\n", pet_id, p->name); + return 1; } -#endif //TXT_SQL_CONVERT -int inter_pet_fromstr(char *str,struct s_pet *p) -{ - int s; - int tmp_int[16]; - char tmp_str[256]; - - memset(p,0,sizeof(struct s_pet)); - - s=sscanf(str,"%d,%d,%[^\t]\t%d,%d,%d,%d,%d,%d,%d,%d,%d",&tmp_int[0],&tmp_int[1],tmp_str,&tmp_int[2], - &tmp_int[3],&tmp_int[4],&tmp_int[5],&tmp_int[6],&tmp_int[7],&tmp_int[8],&tmp_int[9],&tmp_int[10]); - - if(s!=12) - return 1; - - p->pet_id = tmp_int[0]; - p->class_ = tmp_int[1]; - memcpy(p->name,tmp_str,NAME_LENGTH); - p->account_id = tmp_int[2]; - p->char_id = tmp_int[3]; - p->level = tmp_int[4]; - p->egg_id = tmp_int[5]; - p->equip = tmp_int[6]; - p->intimate = tmp_int[7]; - p->hungry = tmp_int[8]; - p->rename_flag = tmp_int[9]; - p->incuvate = tmp_int[10]; - - if(p->hungry < 0) - p->hungry = 0; - else if(p->hungry > 100) - p->hungry = 100; - if(p->intimate < 0) - p->intimate = 0; - else if(p->intimate > 1000) - p->intimate = 1000; - return 0; -} -#ifndef TXT_SQL_CONVERT -int inter_pet_init() +int inter_pet_fromsql(int pet_id, struct s_pet* p) { - char line[8192]; - struct s_pet *p; - FILE *fp; - int c=0; + char* data; + size_t len; - pet_db= idb_alloc(DB_OPT_RELEASE_DATA); +#ifdef NOISY + ShowInfo("Loading pet (%d)...\n",pet_id); +#endif + memset(p, 0, sizeof(struct s_pet)); - if( (fp=fopen(pet_txt,"r"))==NULL ) - return 1; - while(fgets(line, sizeof(line), fp)) + //`pet` (`pet_id`, `class`,`name`,`account_id`,`char_id`,`level`,`egg_id`,`equip`,`intimate`,`hungry`,`rename_flag`,`incuvate`) + + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `pet_id`, `class`,`name`,`account_id`,`char_id`,`level`,`egg_id`,`equip`,`intimate`,`hungry`,`rename_flag`,`incuvate` FROM `%s` WHERE `pet_id`='%d'", pet_db, pet_id) ) { - p = (struct s_pet*)aCalloc(sizeof(struct s_pet), 1); - if(p==NULL){ - ShowFatalError("int_pet: out of memory!\n"); - exit(EXIT_FAILURE); - } - memset(p,0,sizeof(struct s_pet)); - if(inter_pet_fromstr(line,p)==0 && p->pet_id>0){ - if( p->pet_id >= pet_newid) - pet_newid=p->pet_id+1; - idb_put(pet_db,p->pet_id,p); - }else{ - ShowError("int_pet: broken data [%s] line %d\n",pet_txt,c); - aFree(p); - } - c++; + Sql_ShowDebug(sql_handle); + return 0; } - fclose(fp); - return 0; -} - -void inter_pet_final() -{ - pet_db->destroy(pet_db, NULL); - return; -} -int inter_pet_save_sub(DBKey key,void *data,va_list ap) -{ - char line[8192]; - FILE *fp; - inter_pet_tostr(line,(struct s_pet *)data); - fp=va_arg(ap,FILE *); - fprintf(fp,"%s\n",line); + if( SQL_SUCCESS == Sql_NextRow(sql_handle) ) + { + p->pet_id = pet_id; + Sql_GetData(sql_handle, 1, &data, NULL); p->class_ = atoi(data); + Sql_GetData(sql_handle, 2, &data, &len); memcpy(p->name, data, min(len, NAME_LENGTH)); + Sql_GetData(sql_handle, 3, &data, NULL); p->account_id = atoi(data); + Sql_GetData(sql_handle, 4, &data, NULL); p->char_id = atoi(data); + Sql_GetData(sql_handle, 5, &data, NULL); p->level = atoi(data); + Sql_GetData(sql_handle, 6, &data, NULL); p->egg_id = atoi(data); + Sql_GetData(sql_handle, 7, &data, NULL); p->equip = atoi(data); + Sql_GetData(sql_handle, 8, &data, NULL); p->intimate = atoi(data); + Sql_GetData(sql_handle, 9, &data, NULL); p->hungry = atoi(data); + Sql_GetData(sql_handle, 10, &data, NULL); p->rename_flag = atoi(data); + Sql_GetData(sql_handle, 11, &data, NULL); p->incuvate = atoi(data); + + Sql_FreeResult(sql_handle); + + p->hungry = cap_value(p->hungry, 0, 100); + p->intimate = cap_value(p->intimate, 0, 1000); + + if( save_log ) + ShowInfo("Pet loaded (%d - %s).\n", pet_id, p->name); + } return 0; } +//---------------------------------------------- -int inter_pet_save() -{ - FILE *fp; - int lock; - if( (fp=lock_fopen(pet_txt,&lock))==NULL ){ - ShowError("int_pet: can't write [%s] !!! data is lost !!!\n",pet_txt); - return 1; - } - pet_db->foreach(pet_db,inter_pet_save_sub,fp); - lock_fclose(fp,pet_txt,&lock); +int inter_pet_sql_init(void){ + //memory alloc + pet_pt = (struct s_pet*)aCalloc(sizeof(struct s_pet), 1); return 0; } +void inter_pet_sql_final(void){ + if (pet_pt) aFree(pet_pt); + return; +} +//---------------------------------- +int inter_pet_delete(int pet_id){ + ShowInfo("delete pet request: %d...\n",pet_id); -int inter_pet_delete(int pet_id) -{ - struct s_pet *p; - p = (struct s_pet*)idb_get(pet_db,pet_id); - if( p == NULL) - return 1; - else { - idb_remove(pet_db,pet_id); - ShowInfo("Deleted pet (pet_id: %d)\n",pet_id); - } + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `pet_id`='%d'", pet_db, pet_id) ) + Sql_ShowDebug(sql_handle); return 0; } - -int mapif_pet_created(int fd,int account_id,struct s_pet *p) +//------------------------------------------------------ +int mapif_pet_created(int fd, int account_id, struct s_pet *p) { - WFIFOHEAD(fd, 11); - WFIFOW(fd,0)=0x3880; - WFIFOL(fd,2)=account_id; + WFIFOHEAD(fd, 11); + WFIFOW(fd, 0) =0x3880; + WFIFOL(fd, 2) =account_id; if(p!=NULL){ - WFIFOB(fd,6)=0; - WFIFOL(fd,7)=p->pet_id; - ShowInfo("Created pet (%d - %s)\n",p->pet_id,p->name); + WFIFOB(fd, 6)=0; + WFIFOL(fd, 7) =p->pet_id; + ShowInfo("int_pet: created pet %d - %s\n", p->pet_id, p->name); }else{ - WFIFOB(fd,6)=1; - WFIFOL(fd,7)=0; + WFIFOB(fd, 6)=1; + WFIFOL(fd, 7)=0; } - WFIFOSET(fd,11); + WFIFOSET(fd, 11); return 0; } -int mapif_pet_info(int fd,int account_id,struct s_pet *p) -{ +int mapif_pet_info(int fd, int account_id, struct s_pet *p){ WFIFOHEAD(fd, sizeof(struct s_pet) + 9); - WFIFOW(fd,0)=0x3881; - WFIFOW(fd,2)=sizeof(struct s_pet) + 9; - WFIFOL(fd,4)=account_id; - WFIFOB(fd,8)=0; - memcpy(WFIFOP(fd,9),p,sizeof(struct s_pet)); - WFIFOSET(fd,WFIFOW(fd,2)); + WFIFOW(fd, 0) =0x3881; + WFIFOW(fd, 2) =sizeof(struct s_pet) + 9; + WFIFOL(fd, 4) =account_id; + WFIFOB(fd, 8)=0; + memcpy(WFIFOP(fd, 9), p, sizeof(struct s_pet)); + WFIFOSET(fd, WFIFOW(fd, 2)); return 0; } -int mapif_pet_noinfo(int fd,int account_id) -{ - WFIFOHEAD(fd, sizeof(struct s_pet) + 9); - WFIFOW(fd,0)=0x3881; - WFIFOW(fd,2)=sizeof(struct s_pet) + 9; - WFIFOL(fd,4)=account_id; - WFIFOB(fd,8)=1; - memset(WFIFOP(fd,9),0,sizeof(struct s_pet)); - WFIFOSET(fd,WFIFOW(fd,2)); +int mapif_pet_noinfo(int fd, int account_id){ + WFIFOHEAD(fd, sizeof(struct s_pet) + 9); + WFIFOW(fd, 0) =0x3881; + WFIFOW(fd, 2) =sizeof(struct s_pet) + 9; + WFIFOL(fd, 4) =account_id; + WFIFOB(fd, 8)=1; + memset(WFIFOP(fd, 9), 0, sizeof(struct s_pet)); + WFIFOSET(fd, WFIFOW(fd, 2)); return 0; } -int mapif_save_pet_ack(int fd,int account_id,int flag) -{ - WFIFOHEAD(fd, 7); - WFIFOW(fd,0)=0x3882; - WFIFOL(fd,2)=account_id; - WFIFOB(fd,6)=flag; - WFIFOSET(fd,7); +int mapif_save_pet_ack(int fd, int account_id, int flag){ + WFIFOHEAD(fd, 7); + WFIFOW(fd, 0) =0x3882; + WFIFOL(fd, 2) =account_id; + WFIFOB(fd, 6) =flag; + WFIFOSET(fd, 7); return 0; } -int mapif_delete_pet_ack(int fd,int flag) -{ - WFIFOHEAD(fd, 3); - WFIFOW(fd,0)=0x3883; - WFIFOB(fd,2)=flag; - WFIFOSET(fd,3); +int mapif_delete_pet_ack(int fd, int flag){ + WFIFOHEAD(fd, 3); + WFIFOW(fd, 0) =0x3883; + WFIFOB(fd, 2) =flag; + WFIFOSET(fd, 3); return 0; } -int mapif_create_pet(int fd,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) +int mapif_create_pet(int fd, 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) { - struct s_pet *p; - p= (struct s_pet *) aCalloc(sizeof(struct s_pet), 1); - if(p==NULL){ - ShowFatalError("int_pet: out of memory !\n"); - mapif_pet_created(fd,account_id,NULL); - return 0; - } -// memset(p,0,sizeof(struct s_pet)); unnecessary after aCalloc [Skotlex] - p->pet_id = pet_newid++; - memcpy(p->name,pet_name,NAME_LENGTH); + memset(pet_pt, 0, sizeof(struct s_pet)); + strncpy(pet_pt->name, pet_name, NAME_LENGTH); if(incuvate == 1) - p->account_id = p->char_id = 0; + pet_pt->account_id = pet_pt->char_id = 0; else { - p->account_id = account_id; - p->char_id = char_id; + pet_pt->account_id = account_id; + pet_pt->char_id = char_id; } - p->class_ = pet_class; - p->level = pet_lv; - p->egg_id = pet_egg_id; - p->equip = pet_equip; - p->intimate = intimate; - p->hungry = hungry; - p->rename_flag = rename_flag; - p->incuvate = incuvate; - - if(p->hungry < 0) - p->hungry = 0; - else if(p->hungry > 100) - p->hungry = 100; - if(p->intimate < 0) - p->intimate = 0; - else if(p->intimate > 1000) - p->intimate = 1000; - - idb_put(pet_db,p->pet_id,p); - - mapif_pet_created(fd,account_id,p); + pet_pt->class_ = pet_class; + pet_pt->level = pet_lv; + pet_pt->egg_id = pet_egg_id; + pet_pt->equip = pet_equip; + pet_pt->intimate = intimate; + pet_pt->hungry = hungry; + pet_pt->rename_flag = rename_flag; + pet_pt->incuvate = incuvate; + + if(pet_pt->hungry < 0) + pet_pt->hungry = 0; + else if(pet_pt->hungry > 100) + pet_pt->hungry = 100; + if(pet_pt->intimate < 0) + pet_pt->intimate = 0; + else if(pet_pt->intimate > 1000) + pet_pt->intimate = 1000; + + pet_pt->pet_id = -1; //Signal NEW pet. + if (inter_pet_tosql(pet_pt->pet_id,pet_pt)) + mapif_pet_created(fd, account_id, pet_pt); + else //Failed... + mapif_pet_created(fd, account_id, NULL); return 0; } -int mapif_load_pet(int fd,int account_id,int char_id,int pet_id) -{ - struct s_pet *p; - p = (struct s_pet*)idb_get(pet_db,pet_id); - if(p!=NULL) { - if(p->incuvate == 1) { - p->account_id = p->char_id = 0; - mapif_pet_info(fd,account_id,p); +int mapif_load_pet(int fd, int account_id, int char_id, int pet_id){ + memset(pet_pt, 0, sizeof(struct s_pet)); + + inter_pet_fromsql(pet_id, pet_pt); + + if(pet_pt!=NULL) { + if(pet_pt->incuvate == 1) { + pet_pt->account_id = pet_pt->char_id = 0; + mapif_pet_info(fd, account_id, pet_pt); } - else if(account_id == p->account_id && char_id == p->char_id) - mapif_pet_info(fd,account_id,p); + else if(account_id == pet_pt->account_id && char_id == pet_pt->char_id) + mapif_pet_info(fd, account_id, pet_pt); else - mapif_pet_noinfo(fd,account_id); + mapif_pet_noinfo(fd, account_id); } else - mapif_pet_noinfo(fd,account_id); + mapif_pet_noinfo(fd, account_id); return 0; } -static void* create_pet(DBKey key, va_list args) { - struct s_pet *p; - p=(struct s_pet *)aCalloc(sizeof(struct s_pet),1); - p->pet_id = key.i; - return p; -} -int mapif_save_pet(int fd,int account_id,struct s_pet *data) -{ - struct s_pet *p; - int pet_id, len; +int mapif_save_pet(int fd, int account_id, struct s_pet *data) { + //here process pet save request. + int len; RFIFOHEAD(fd); - len=RFIFOW(fd,2); - + len=RFIFOW(fd, 2); if(sizeof(struct s_pet)!=len-8) { - ShowError("inter pet: data size error %d %d\n",sizeof(struct s_pet),len-8); + ShowError("inter pet: data size error %d %d\n", sizeof(struct s_pet), len-8); } + else{ - pet_id = data->pet_id; - if (pet_id == 0) - pet_id = data->pet_id = pet_newid++; - p = (struct s_pet*)idb_ensure(pet_db,pet_id,create_pet); if(data->hungry < 0) data->hungry = 0; else if(data->hungry > 100) @@ -313,61 +257,47 @@ int mapif_save_pet(int fd,int account_id,struct s_pet *data) data->intimate = 0; else if(data->intimate > 1000) data->intimate = 1000; - memcpy(p,data,sizeof(struct s_pet)); - if(p->incuvate == 1) - p->account_id = p->char_id = 0; - - mapif_save_pet_ack(fd,account_id,0); + inter_pet_tosql(data->pet_id,data); + mapif_save_pet_ack(fd, account_id, 0); } return 0; } -int mapif_delete_pet(int fd,int pet_id) -{ - mapif_delete_pet_ack(fd,inter_pet_delete(pet_id)); +int mapif_delete_pet(int fd, int pet_id){ + mapif_delete_pet_ack(fd, inter_pet_delete(pet_id)); return 0; } -int mapif_parse_CreatePet(int fd) -{ +int mapif_parse_CreatePet(int fd){ RFIFOHEAD(fd); - mapif_create_pet(fd,RFIFOL(fd,2),RFIFOL(fd,6),RFIFOW(fd,10),RFIFOW(fd,12),RFIFOW(fd,14),RFIFOW(fd,16),RFIFOW(fd,18), - RFIFOW(fd,20),RFIFOB(fd,22),RFIFOB(fd,23),(char*)RFIFOP(fd,24)); + mapif_create_pet(fd, RFIFOL(fd, 2), RFIFOL(fd, 6), RFIFOW(fd, 10), RFIFOW(fd, 12), RFIFOW(fd, 14), RFIFOW(fd, 16), RFIFOW(fd, 18), + RFIFOW(fd, 20), RFIFOB(fd, 22), RFIFOB(fd, 23), (char*)RFIFOP(fd, 24)); return 0; } -int mapif_parse_LoadPet(int fd) -{ +int mapif_parse_LoadPet(int fd){ RFIFOHEAD(fd); - mapif_load_pet(fd,RFIFOL(fd,2),RFIFOL(fd,6),RFIFOL(fd,10)); + mapif_load_pet(fd, RFIFOL(fd, 2), RFIFOL(fd, 6), RFIFOL(fd, 10)); return 0; } -int mapif_parse_SavePet(int fd) -{ +int mapif_parse_SavePet(int fd){ RFIFOHEAD(fd); - mapif_save_pet(fd,RFIFOL(fd,4),(struct s_pet *)RFIFOP(fd,8)); + mapif_save_pet(fd, RFIFOL(fd, 4), (struct s_pet *) RFIFOP(fd, 8)); return 0; } -int mapif_parse_DeletePet(int fd) -{ +int mapif_parse_DeletePet(int fd){ RFIFOHEAD(fd); - mapif_delete_pet(fd,RFIFOL(fd,2)); + mapif_delete_pet(fd, RFIFOL(fd, 2)); return 0; } -// map server からの通信 -// ・1パケットのみ解析すること -// ・パケット長データはinter.cにセットしておくこと -// ・パケット長チェックや、RFIFOSKIPは呼び出し元で行われるので行ってはならない -// ・エラーなら0(false)、そうでないなら1(true)をかえさなければならない -int inter_pet_parse_frommap(int fd) -{ +int inter_pet_parse_frommap(int fd){ RFIFOHEAD(fd); - switch(RFIFOW(fd,0)){ + switch(RFIFOW(fd, 0)){ case 0x3080: mapif_parse_CreatePet(fd); break; case 0x3081: mapif_parse_LoadPet(fd); break; case 0x3082: mapif_parse_SavePet(fd); break; @@ -377,4 +307,3 @@ int inter_pet_parse_frommap(int fd) } return 1; } -#endif //TXT_SQL_CONVERT diff --git a/src/char/int_pet.h b/src/char/int_pet.h index 9234af109..733468c77 100644 --- a/src/char/int_pet.h +++ b/src/char/int_pet.h @@ -1,21 +1,21 @@ // Copyright (c) Athena Dev Teams - Licensed under GNU GPL // For more information, see LICENCE in the main folder -#ifndef _INT_PET_H_ -#define _INT_PET_H_ +#ifndef _INT_PET_SQL_H_ +#define _INT_PET_SQL_H_ struct s_pet; int inter_pet_init(void); -void inter_pet_final(void); +void inter_pet_sql_final(void); int inter_pet_save(void); int inter_pet_delete(int pet_id); int inter_pet_parse_frommap(int fd); - -extern char pet_txt[1024]; +int inter_pet_sql_init(void); +//extern char pet_txt[256]; //Exported for use in the TXT-SQL converter. -int inter_pet_fromstr(char *str,struct s_pet *p); +int inter_pet_tosql(int pet_id, struct s_pet *p); -#endif /* _INT_PET_H_ */ +#endif /* _INT_PET_SQL_H_ */ diff --git a/src/char/int_quest.c b/src/char/int_quest.c new file mode 100644 index 000000000..224205412 --- /dev/null +++ b/src/char/int_quest.c @@ -0,0 +1,184 @@ +// Copyright (c) Athena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + +#include "../common/mmo.h" +#include "../common/db.h" +#include "../common/malloc.h" +#include "../common/showmsg.h" +#include "../common/socket.h" +#include "../common/strlib.h" +#include "../common/sql.h" +#include "../common/timer.h" + +#include "char.h" +#include "inter.h" +#include "int_quest.h" + +#include +#include +#include + +//Load entire questlog for a character +int mapif_quests_fromsql(int char_id, struct quest questlog[]) +{ + int i; + struct quest tmp_quest; + SqlStmt * stmt; + + stmt = SqlStmt_Malloc(sql_handle); + if( stmt == NULL ) + { + SqlStmt_ShowDebug(stmt); + return 0; + } + + memset(&tmp_quest, 0, sizeof(struct quest)); + + if( SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT `quest_id`, `state`, `time`, `count1`, `count2`, `count3` FROM `%s` WHERE `char_id`=? LIMIT %d", quest_db, MAX_QUEST_DB) + || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0) + || SQL_ERROR == SqlStmt_Execute(stmt) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &tmp_quest.quest_id, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_INT, &tmp_quest.state, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_UINT, &tmp_quest.time, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 3, SQLDT_INT, &tmp_quest.count[0], 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 4, SQLDT_INT, &tmp_quest.count[1], 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 5, SQLDT_INT, &tmp_quest.count[2], 0, NULL, NULL) ) + SqlStmt_ShowDebug(stmt); + + for( i = 0; i < MAX_QUEST_DB && SQL_SUCCESS == SqlStmt_NextRow(stmt); ++i ) + memcpy(&questlog[i], &tmp_quest, sizeof(tmp_quest)); + + SqlStmt_Free(stmt); + return i; +} + +//Delete a quest +bool mapif_quest_delete(int char_id, int quest_id) +{ + if ( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `quest_id` = '%d' AND `char_id` = '%d'", quest_db, quest_id, char_id) ) + { + Sql_ShowDebug(sql_handle); + return false; + } + + return true; +} + +//Add a quest to a questlog +bool mapif_quest_add(int char_id, struct quest qd) +{ + if ( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s`(`quest_id`, `char_id`, `state`, `time`, `count1`, `count2`, `count3`) VALUES ('%d', '%d', '%d','%d', '%d', '%d', '%d')", quest_db, qd.quest_id, char_id, qd.state, qd.time, qd.count[0], qd.count[1], qd.count[2]) ) + { + Sql_ShowDebug(sql_handle); + return false; + } + + return true; +} + +//Update a questlog +bool mapif_quest_update(int char_id, struct quest qd) +{ + if ( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `state`='%d', `count1`='%d', `count2`='%d', `count3`='%d' WHERE `quest_id` = '%d' AND `char_id` = '%d'", quest_db, qd.state, qd.count[0], qd.count[1], qd.count[2], qd.quest_id, char_id) ) + { + Sql_ShowDebug(sql_handle); + return false; + } + + return true; +} + +//Save quests +int mapif_parse_quest_save(int fd) +{ + int i, j, k, num2, num1 = (RFIFOW(fd,2)-8)/sizeof(struct quest); + int char_id = RFIFOL(fd,4); + struct quest qd1[MAX_QUEST_DB],qd2[MAX_QUEST_DB]; + bool success = true; + + memset(qd1, 0, sizeof(qd1)); + memset(qd2, 0, sizeof(qd2)); + if( num1 ) memcpy(&qd1, RFIFOP(fd,8), RFIFOW(fd,2)-8); + num2 = mapif_quests_fromsql(char_id, qd2); + + for( i = 0; i < num1; i++ ) + { + ARR_FIND( 0, num2, j, qd1[i].quest_id == qd2[j].quest_id ); + if( j < num2 ) // Update existed quests + { // Only states and counts are changable. + ARR_FIND( 0, MAX_QUEST_OBJECTIVES, k, qd1[i].count[k] != qd2[j].count[k] ); + if( k != MAX_QUEST_OBJECTIVES || qd1[i].state != qd2[j].state ) + success &= mapif_quest_update(char_id, qd1[i]); + + if( j < (--num2) ) + { + memmove(&qd2[j],&qd2[j+1],sizeof(struct quest)*(num2-j)); + memset(&qd2[num2], 0, sizeof(struct quest)); + } + + } + else // Add new quests + success &= mapif_quest_add(char_id, qd1[i]); + } + + for( i = 0; i < num2; i++ ) // Quests not in qd1 but in qd2 are to be erased. + success &= mapif_quest_delete(char_id, qd2[i].quest_id); + + WFIFOHEAD(fd,7); + WFIFOW(fd,0) = 0x3861; + WFIFOL(fd,2) = char_id; + WFIFOB(fd,6) = success?1:0; + WFIFOSET(fd,7); + + return 0; +} + +//Send questlog to map server +int mapif_parse_quest_load(int fd) +{ + int char_id = RFIFOL(fd,2); + struct quest tmp_questlog[MAX_QUEST_DB]; + int num_quests, i, num_complete = 0; + int complete[MAX_QUEST_DB]; + + memset(tmp_questlog, 0, sizeof(tmp_questlog)); + memset(complete, 0, sizeof(complete)); + + num_quests = mapif_quests_fromsql(char_id, tmp_questlog); + + WFIFOHEAD(fd,num_quests*sizeof(struct quest)+8); + WFIFOW(fd,0) = 0x3860; + WFIFOW(fd,2) = num_quests*sizeof(struct quest)+8; + WFIFOL(fd,4) = char_id; + + //Active and inactive quests + for( i = 0; i < num_quests; i++ ) + { + if( tmp_questlog[i].state == Q_COMPLETE ) + { + complete[num_complete++] = i; + continue; + } + memcpy(WFIFOP(fd,(i-num_complete)*sizeof(struct quest)+8), &tmp_questlog[i], sizeof(struct quest)); + } + + // Completed quests + for( i = num_quests - num_complete; i < num_quests; i++ ) + memcpy(WFIFOP(fd,i*sizeof(struct quest)+8), &tmp_questlog[complete[i-num_quests+num_complete]], sizeof(struct quest)); + + WFIFOSET(fd,num_quests*sizeof(struct quest)+8); + + return 0; +} + +int inter_quest_parse_frommap(int fd) +{ + switch(RFIFOW(fd,0)) + { + case 0x3060: mapif_parse_quest_load(fd); break; + case 0x3061: mapif_parse_quest_save(fd); break; + default: + return 0; + } + return 1; +} diff --git a/src/char/int_quest.h b/src/char/int_quest.h new file mode 100644 index 000000000..f2a0b626e --- /dev/null +++ b/src/char/int_quest.h @@ -0,0 +1,13 @@ +// Copyright (c) Athena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + +#ifndef _QUEST_H_ +#define _QUEST_H_ + +/*questlog system*/ +struct quest; + +int inter_quest_parse_frommap(int fd); + +#endif + diff --git a/src/char/int_status.c b/src/char/int_status.c deleted file mode 100644 index 769d35f65..000000000 --- a/src/char/int_status.c +++ /dev/null @@ -1,183 +0,0 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder - -#include "../common/mmo.h" -#include "../common/db.h" -#include "../common/lock.h" -#include "../common/malloc.h" -#include "../common/showmsg.h" -#include "int_status.h" - -#include - -// Contains all the status change data in-memory. [Skotlex] -static DBMap* scdata_db = NULL; // int char_id -> struct scdata* -char scdata_txt[1024]="save/scdata.txt"; //By [Skotlex] - -#ifdef ENABLE_SC_SAVING -static void* create_scdata(DBKey key, va_list args) -{ - struct scdata *data; - data = (struct scdata*)aCalloc(1, sizeof(struct scdata)); - data->account_id = va_arg(args, int); - data->char_id = key.i; - return data; -} - -/*========================================== - * Loads status change data of the player given. [Skotlex] - *------------------------------------------*/ -struct scdata* status_search_scdata(int aid, int cid) -{ - return (struct scdata*)scdata_db->ensure(scdata_db, db_i2key(cid), create_scdata, aid); -} - -/*========================================== - * Deletes status change data of the player given. [Skotlex] - * Should be invoked after the data of said player was successfully loaded. - *------------------------------------------*/ -void status_delete_scdata(int aid, int cid) -{ - struct scdata* scdata = (struct scdata*)idb_remove(scdata_db, cid); - if (scdata) - { - if (scdata->data) - aFree(scdata->data); - aFree(scdata); - } -} - - -static void inter_status_tostr(char* line, struct scdata *sc_data) -{ - int i, len; - - len = sprintf(line, "%d,%d,%d\t", sc_data->account_id, sc_data->char_id, sc_data->count); - for(i = 0; i < sc_data->count; i++) { - len += sprintf(line + len, "%d,%ld,%ld,%ld,%ld,%ld\t", sc_data->data[i].type, sc_data->data[i].tick, - sc_data->data[i].val1, sc_data->data[i].val2, sc_data->data[i].val3, sc_data->data[i].val4); - } - return; -} - -static int inter_scdata_fromstr(char *line, struct scdata *sc_data) -{ - int i, len, next; - - if (sscanf(line,"%d,%d,%d\t%n",&sc_data->account_id, &sc_data->char_id, &sc_data->count, &next) < 3) - return 0; - - if (sc_data->count < 1) - return 0; - - sc_data->data = (struct status_change_data*)aCalloc(sc_data->count, sizeof (struct status_change_data)); - - for (i = 0; i < sc_data->count; i++) - { - if (sscanf(line + next, "%hu,%ld,%ld,%ld,%ld,%ld\t%n", &sc_data->data[i].type, &sc_data->data[i].tick, - &sc_data->data[i].val1, &sc_data->data[i].val2, &sc_data->data[i].val3, &sc_data->data[i].val4, &len) < 6) - { - aFree(sc_data->data); - return 0; - } - next+=len; - } - return 1; -} -/*========================================== - * Loads all scdata from the given filename. - *------------------------------------------*/ -void status_load_scdata(const char* filename) -{ - FILE *fp; - int sd_count=0, sc_count=0; - char line[8192]; - struct scdata *sc; - - if ((fp = fopen(filename, "r")) == NULL) { - ShowError("status_load_scdata: Cannot open file %s!\n", filename); - return; - } - - while(fgets(line, sizeof(line), fp)) - { - sc = (struct scdata*)aCalloc(1, sizeof(struct scdata)); - if (inter_scdata_fromstr(line, sc)) { - sd_count++; - sc_count+= sc->count; - sc = (struct scdata*)idb_put(scdata_db, sc->char_id, sc); - if (sc) { - ShowError("Duplicate entry in %s for character %d\n", filename, sc->char_id); - if (sc->data) aFree(sc->data); - aFree(sc); - } - } else { - ShowError("status_load_scdata: Broken line data: %s\n", line); - aFree(sc); - } - } - fclose(fp); - ShowStatus("Loaded %d saved status changes for %d characters.\n", sc_count, sd_count); -} - -static int inter_status_save_sub(DBKey key, void *data, va_list ap) { - char line[8192]; - struct scdata * sc_data; - FILE *fp; - - sc_data = (struct scdata *)data; - if (sc_data->count < 1) - return 0; - - fp = va_arg(ap, FILE *); - inter_status_tostr(line, sc_data); - fprintf(fp, "%s\n", line); - return 0; -} - -/*========================================== - * Saves all scdata to the given filename. - *------------------------------------------*/ -void inter_status_save() -{ - FILE *fp; - int lock; - - if ((fp = lock_fopen(scdata_txt, &lock)) == NULL) { - ShowError("int_status: can't write [%s] !!! data is lost !!!\n", scdata_txt); - return; - } - scdata_db->foreach(scdata_db, inter_status_save_sub, fp); - lock_fclose(fp,scdata_txt, &lock); -} - -/*========================================== - * Initializes db. - *------------------------------------------*/ -void status_init() -{ - scdata_db = idb_alloc(DB_OPT_BASE); - status_load_scdata(scdata_txt); -} - -/*========================================== - * Frees up memory. - *------------------------------------------*/ -static int scdata_db_final(DBKey k,void *d,va_list ap) -{ - struct scdata *data = (struct scdata*)d; - if (data->data) - aFree(data->data); - aFree(data); - return 0; -} - -/*========================================== - * Final cleanup. - *------------------------------------------*/ -void status_final(void) -{ - scdata_db->destroy(scdata_db, scdata_db_final); -} - -#endif //ENABLE_SC_SAVING diff --git a/src/char/int_status.h b/src/char/int_status.h deleted file mode 100644 index 3202cd88e..000000000 --- a/src/char/int_status.h +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder - -#ifndef _INT_STATUS_H_ -#define _INT_STATUS_H_ - -struct status_change_data; - -struct scdata { - int account_id, char_id; - int count; - struct status_change_data* data; -}; - -extern char scdata_txt[1024]; - -struct scdata* status_search_scdata(int aid, int cid); -void status_delete_scdata(int aid, int cid); -void inter_status_save(void); -void status_init(void); -void status_final(void); - -#endif /* _INT_STATUS_H_ */ diff --git a/src/char/int_storage.c b/src/char/int_storage.c index 2a041b286..248a4521f 100644 --- a/src/char/int_storage.c +++ b/src/char/int_storage.c @@ -3,414 +3,184 @@ #include "../common/mmo.h" #include "../common/malloc.h" -#include "../common/socket.h" -#include "../common/db.h" -#include "../common/lock.h" #include "../common/showmsg.h" -#include "../common/utils.h" +#include "../common/socket.h" +#include "../common/strlib.h" // StringBuf +#include "../common/sql.h" #include "char.h" #include "inter.h" -#include "int_storage.h" -#include "int_pet.h" -#include "int_guild.h" #include #include #include -// ファイル名のデフォルト -// inter_config_read()で再設定される -char storage_txt[1024]="save/storage.txt"; -char guild_storage_txt[1024]="save/g_storage.txt"; -static DBMap* storage_db = NULL; // int account_id -> struct storage_data* -static DBMap* guild_storage_db = NULL; // int guild_id -> struct guild_storage* +#define STORAGE_MEMINC 16 -// 倉庫データを文字列に変換 -bool storage_tostr(char* str, int account_id, struct storage_data* p) +/// Save storage data to sql +int storage_tosql(int account_id, struct storage_data* p) { - int i,j; - char *str_p = str; - str_p += sprintf(str_p, "%d,%d\t", account_id, p->storage_amount); - - for( i = 0; i < MAX_STORAGE; i++ ) - if( p->items[i].nameid > 0 && p->items[i].amount > 0 ) - { - str_p += sprintf(str_p, "%d,%d,%d,%d,%d,%d,%d", - p->items[i].id,p->items[i].nameid,p->items[i].amount,p->items[i].equip, - p->items[i].identify,p->items[i].refine,p->items[i].attribute); - for(j=0; jitems[i].card[j]); - str_p += sprintf(str_p," "); - } - - *(str_p++)='\t'; - - *str_p='\0'; - - return true; -} - -// 文字列を倉庫データに変換 -bool storage_fromstr(char* str, int* account_id, struct storage_data* p) -{ - int tmp_int[256]; - char tmp_str[256]; - int next,len,i,j; - - if( sscanf(str, "%d,%d%n", &tmp_int[0], &tmp_int[1], &next) != 2 ) - return false; - - *account_id = tmp_int[0]; - p->storage_amount = tmp_int[1]; //FIXME: limit to MAX_STORAGE? - - next++; - for( i = 0; str[next] && str[next]!='\t' && i < MAX_STORAGE; i++ ) - { - if(sscanf(str + next, "%d,%d,%d,%d,%d,%d,%d%[0-9,-]%n", - &tmp_int[0], &tmp_int[1], &tmp_int[2], &tmp_int[3], - &tmp_int[4], &tmp_int[5], &tmp_int[6], tmp_str, &len) != 8) - return false; - - p->items[i].id = tmp_int[0]; - p->items[i].nameid = tmp_int[1]; - p->items[i].amount = tmp_int[2]; - p->items[i].equip = tmp_int[3]; - p->items[i].identify = tmp_int[4]; - p->items[i].refine = tmp_int[5]; - p->items[i].attribute = tmp_int[6]; - - for(j = 0; j < MAX_SLOTS && tmp_str[0] && sscanf(tmp_str, ",%d%[0-9,-]",&tmp_int[0], tmp_str) > 0; j++) - p->items[i].card[j] = tmp_int[0]; - - next += len; - if (str[next] == ' ') - next++; - } - - if( i >= MAX_STORAGE && str[next] && str[next] != '\t' ) - ShowWarning("storage_fromstr: Found a storage line with more items than MAX_STORAGE (%d), remaining items have been discarded!\n", MAX_STORAGE); - - return true; + memitemdata_to_sql(p->items, MAX_STORAGE, account_id, TABLE_STORAGE); + return 0; } -int guild_storage_tostr(char *str,struct guild_storage *p) +/// Load storage data to mem +int storage_fromsql(int account_id, struct storage_data* p) { - int i,j,f=0; - char *str_p = str; - str_p+=sprintf(str,"%d,%d\t",p->guild_id,p->storage_amount); + StringBuf buf; + struct item* item; + char* data; + int i; + int j; - for(i=0;iitems[i].nameid) && (p->items[i].amount) ){ - str_p += sprintf(str_p,"%d,%d,%d,%d,%d,%d,%d", - p->items[i].id,p->items[i].nameid,p->items[i].amount,p->items[i].equip, - p->items[i].identify,p->items[i].refine,p->items[i].attribute); - for(j=0; jitems[i].card[j]); - str_p += sprintf(str_p," "); - f++; - } - - *(str_p++)='\t'; + memset(p, 0, sizeof(struct storage_data)); //clean up memory + p->storage_amount = 0; - *str_p='\0'; - if(!f) - str[0]=0; - return 0; -} + // storage {`account_id`/`id`/`nameid`/`amount`/`equip`/`identify`/`refine`/`attribute`/`card0`/`card1`/`card2`/`card3`} + StringBuf_Init(&buf); + StringBuf_AppendStr(&buf, "SELECT `id`,`nameid`,`amount`,`equip`,`identify`,`refine`,`attribute`,`expire_time`"); + for( j = 0; j < MAX_SLOTS; ++j ) + StringBuf_Printf(&buf, ",`card%d`", j); + StringBuf_Printf(&buf, " FROM `%s` WHERE `account_id`='%d' ORDER BY `nameid`", storage_db, account_id); -int guild_storage_fromstr(char *str,struct guild_storage *p) -{ - int tmp_int[256]; - char tmp_str[256]; - int set,next,len,i,j; + if( SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf)) ) + Sql_ShowDebug(sql_handle); - set=sscanf(str,"%d,%d%n",&tmp_int[0],&tmp_int[1],&next); - p->storage_amount=tmp_int[1]; + StringBuf_Destroy(&buf); - if(set!=2) - return 1; - if(str[next]=='\n' || str[next]=='\r') - return 0; - next++; - for(i=0;str[next] && str[next]!='\t' && i < MAX_GUILD_STORAGE;i++){ - if(sscanf(str + next, "%d,%d,%d,%d,%d,%d,%d%[0-9,-]%n", - &tmp_int[0], &tmp_int[1], &tmp_int[2], &tmp_int[3], - &tmp_int[4], &tmp_int[5], &tmp_int[6], tmp_str, &len) == 8) + for( i = 0; i < MAX_STORAGE && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i ) + { + item = &p->items[i]; + Sql_GetData(sql_handle, 0, &data, NULL); item->id = atoi(data); + Sql_GetData(sql_handle, 1, &data, NULL); item->nameid = atoi(data); + Sql_GetData(sql_handle, 2, &data, NULL); item->amount = atoi(data); + Sql_GetData(sql_handle, 3, &data, NULL); item->equip = atoi(data); + Sql_GetData(sql_handle, 4, &data, NULL); item->identify = atoi(data); + Sql_GetData(sql_handle, 5, &data, NULL); item->refine = atoi(data); + Sql_GetData(sql_handle, 6, &data, NULL); item->attribute = atoi(data); + Sql_GetData(sql_handle, 7, &data, NULL); item->expire_time = (unsigned int)atoi(data); + for( j = 0; j < MAX_SLOTS; ++j ) { - p->items[i].id = tmp_int[0]; - p->items[i].nameid = tmp_int[1]; - p->items[i].amount = tmp_int[2]; - p->items[i].equip = tmp_int[3]; - p->items[i].identify = tmp_int[4]; - p->items[i].refine = tmp_int[5]; - p->items[i].attribute = tmp_int[6]; - for(j = 0; j < MAX_SLOTS && tmp_str[0] && sscanf(tmp_str, ",%d%[0-9,-]",&tmp_int[0], tmp_str) > 0; j++) - p->items[i].card[j] = tmp_int[0]; - next += len; - if (str[next] == ' ') - next++; + Sql_GetData(sql_handle, 8+j, &data, NULL); item->card[j] = atoi(data); } - else return 1; } - if (i >= MAX_GUILD_STORAGE && str[next] && str[next]!='\t') - ShowWarning("guild_storage_fromstr: Found a storage line with more items than MAX_GUILD_STORAGE (%d), remaining items have been discarded!\n", MAX_GUILD_STORAGE); - return 0; -} - -#ifndef TXT_SQL_CONVERT + p->storage_amount = i; + Sql_FreeResult(sql_handle); -static void* create_storage(DBKey key, va_list args) -{ - return (struct storage_data *) aCalloc(sizeof(struct storage_data), 1); + ShowInfo("storage load complete from DB - id: %d (total: %d)\n", account_id, p->storage_amount); + return 1; } -static void* create_guildstorage(DBKey key, va_list args) +/// Save guild_storage data to sql +int guild_storage_tosql(int guild_id, struct guild_storage* p) { - struct guild_storage* gs = NULL; - gs = (struct guild_storage *) aCalloc(sizeof(struct guild_storage), 1); - gs->guild_id=key.i; - return gs; + memitemdata_to_sql(p->items, MAX_GUILD_STORAGE, guild_id, TABLE_GUILD_STORAGE); + ShowInfo ("guild storage save to DB - guild: %d\n", guild_id); + return 0; } -/// Loads storage data into the provided data structure. -/// If data doesn't exist, the destination is zeroed and false is returned. -bool storage_load(int account_id, struct storage_data* storage) +/// Load guild_storage data to mem +int guild_storage_fromsql(int guild_id, struct guild_storage* p) { - struct storage_data* s = (struct storage_data*)idb_get(storage_db, account_id); + StringBuf buf; + struct item* item; + char* data; + int i; + int j; - if( s != NULL ) - memcpy(storage, s, sizeof(*storage)); - else - memset(storage, 0x00, sizeof(*storage)); - - return( s != NULL ); -} - -/// Writes provided data into storage cache. -/// If data contains 0 items, any existing entry in cache is destroyed. -/// If data contains 1+ items and no cache entry exists, a new one is created. -bool storage_save(int account_id, struct storage_data* storage) -{ - if( storage->storage_amount > 0 ) - { - struct storage_data* s = (struct storage_data*)idb_ensure(storage_db, account_id, create_storage); - memcpy(s, storage, sizeof(*storage)); - } - else - { - idb_remove(storage_db, account_id); - } + memset(p, 0, sizeof(struct guild_storage)); //clean up memory + p->storage_amount = 0; + p->guild_id = guild_id; - return true; -} + // storage {`guild_id`/`id`/`nameid`/`amount`/`equip`/`identify`/`refine`/`attribute`/`card0`/`card1`/`card2`/`card3`} + StringBuf_Init(&buf); + StringBuf_AppendStr(&buf, "SELECT `id`,`nameid`,`amount`,`equip`,`identify`,`refine`,`attribute`"); + for( j = 0; j < MAX_SLOTS; ++j ) + StringBuf_Printf(&buf, ",`card%d`", j); + StringBuf_Printf(&buf, " FROM `%s` WHERE `guild_id`='%d' ORDER BY `nameid`", guild_storage_db, guild_id); -//--------------------------------------------------------- -// 倉庫データを読み込む -int inter_storage_init() -{ - char line[65536]; - int c = 0; - FILE *fp; + if( SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf)) ) + Sql_ShowDebug(sql_handle); - storage_db = idb_alloc(DB_OPT_RELEASE_DATA); + StringBuf_Destroy(&buf); - fp=fopen(storage_txt,"r"); - if(fp==NULL){ - ShowError("can't read : %s\n",storage_txt); - return 1; - } - while( fgets(line, sizeof(line), fp) ) + for( i = 0; i < MAX_GUILD_STORAGE && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i ) { - int account_id; - struct storage_data *s; - - s = (struct storage_data*)aCalloc(sizeof(struct storage_data), 1); - if( s == NULL ) - { - ShowFatalError("int_storage: out of memory!\n"); - exit(EXIT_FAILURE); - } - - if( storage_fromstr(line,&account_id,s) ) + item = &p->items[i]; + Sql_GetData(sql_handle, 0, &data, NULL); item->id = atoi(data); + Sql_GetData(sql_handle, 1, &data, NULL); item->nameid = atoi(data); + Sql_GetData(sql_handle, 2, &data, NULL); item->amount = atoi(data); + Sql_GetData(sql_handle, 3, &data, NULL); item->equip = atoi(data); + Sql_GetData(sql_handle, 4, &data, NULL); item->identify = atoi(data); + Sql_GetData(sql_handle, 5, &data, NULL); item->refine = atoi(data); + Sql_GetData(sql_handle, 6, &data, NULL); item->attribute = atoi(data); + item->expire_time = 0; + for( j = 0; j < MAX_SLOTS; ++j ) { - idb_put(storage_db,account_id,s); - } - else{ - ShowError("int_storage: broken data in [%s] line %d\n",storage_txt,c); - aFree(s); + Sql_GetData(sql_handle, 7+j, &data, NULL); item->card[j] = atoi(data); } - c++; } - fclose(fp); - - c = 0; - guild_storage_db = idb_alloc(DB_OPT_RELEASE_DATA); - - fp=fopen(guild_storage_txt,"r"); - if(fp==NULL){ - ShowError("can't read : %s\n",guild_storage_txt); - return 1; - } - while(fgets(line, sizeof(line), fp)) - { - int tmp_int; - struct guild_storage *gs; - - sscanf(line,"%d",&tmp_int); - gs = (struct guild_storage*)aCalloc(sizeof(struct guild_storage), 1); - if(gs==NULL){ - ShowFatalError("int_storage: out of memory!\n"); - exit(EXIT_FAILURE); - } -// memset(gs,0,sizeof(struct guild_storage)); aCalloc... - gs->guild_id=tmp_int; - if(gs->guild_id > 0 && guild_storage_fromstr(line,gs) == 0) { - idb_put(guild_storage_db,gs->guild_id,gs); - } - else{ - ShowError("int_storage: broken data [%s] line %d\n",guild_storage_txt,c); - aFree(gs); - } - c++; - } - fclose(fp); + p->storage_amount = i; + Sql_FreeResult(sql_handle); + ShowInfo("guild storage load complete from DB - id: %d (total: %d)\n", guild_id, p->storage_amount); return 0; } -void inter_storage_final() { - if(storage_db) - { - storage_db->destroy(storage_db, NULL); - } - if(guild_storage_db) - { - guild_storage_db->destroy(guild_storage_db, NULL); - } - return; -} - //--------------------------------------------------------- -// 倉庫データを書き込む -int inter_storage_save() +// storage data initialize +int inter_storage_sql_init(void) { - struct DBIterator* iter; - DBKey key; - struct storage_data* data; - FILE *fp; - int lock; - if( (fp=lock_fopen(storage_txt,&lock))==NULL ){ - ShowError("int_storage: can't write [%s] !!! data is lost !!!\n",storage_txt); - return 1; - } - - iter = storage_db->iterator(storage_db); - for( data = (struct storage_data*)iter->first(iter,&key); iter->exists(iter); data = (struct storage_data*)iter->next(iter,&key) ) - { - int account_id = key.i; - char line[65536]; - storage_tostr(line,account_id,data); - fprintf(fp,"%s\n",line); - } - iter->destroy(iter); - - lock_fclose(fp,storage_txt,&lock); - return 0; + return 1; } - -//--------------------------------------------------------- -// 倉庫データを書き込む -int inter_guild_storage_save() +// storage data finalize +void inter_storage_sql_final(void) { - struct DBIterator* iter; - struct guild_storage* data; - FILE *fp; - int lock; - if( (fp=lock_fopen(guild_storage_txt,&lock))==NULL ){ - ShowError("int_storage: can't write [%s] !!! data is lost !!!\n",guild_storage_txt); - return 1; - } - - iter = guild_storage_db->iterator(guild_storage_db); - for( data = (struct guild_storage*)iter->first(iter,NULL); iter->exists(iter); data = (struct guild_storage*)iter->next(iter,NULL) ) - { - char line[65536]; - if(inter_guild_search(data->guild_id) != NULL) - { - guild_storage_tostr(line,data); - if(*line) - fprintf(fp,"%s\n",line); - } - } - iter->destroy(iter); - - lock_fclose(fp,guild_storage_txt,&lock); - return 0; + return; } -// 倉庫データ削除 +// q?f[^? int inter_storage_delete(int account_id) { - struct storage_data *s = (struct storage_data*)idb_get(storage_db,account_id); - if(s) { - int i; - for(i=0;istorage_amount;i++){ - if(s->items[i].card[0] == (short)0xff00) - inter_pet_delete( MakeDWord(s->items[i].card[1],s->items[i].card[2]) ); - } - idb_remove(storage_db,account_id); - } + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `account_id`='%d'", storage_db, account_id) ) + Sql_ShowDebug(sql_handle); return 0; } - -// ギルド倉庫データ削除 int inter_guild_storage_delete(int guild_id) { - struct guild_storage *gs = (struct guild_storage*)idb_get(guild_storage_db,guild_id); - if(gs) { - int i; - for(i=0;istorage_amount;i++){ - if(gs->items[i].card[0] == (short)0xff00) - inter_pet_delete( MakeDWord(gs->items[i].card[1],gs->items[i].card[2]) ); - } - idb_remove(guild_storage_db,guild_id); - } + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id`='%d'", guild_storage_db, guild_id) ) + Sql_ShowDebug(sql_handle); return 0; } -struct guild_storage *guild2storage(int guild_id) -{ - struct guild_storage* gs = NULL; - if(inter_guild_search(guild_id) != NULL) - gs = (struct guild_storage*)idb_ensure(guild_storage_db, guild_id, create_guildstorage); - return gs; -} - //--------------------------------------------------------- -// map serverへの通信 +// packet from map server int mapif_load_guild_storage(int fd,int account_id,int guild_id) { - struct guild_storage *gs=guild2storage(guild_id); - WFIFOHEAD(fd, sizeof(struct guild_storage)+12); - WFIFOW(fd,0)=0x3818; - if(gs) { - WFIFOW(fd,2)=sizeof(struct guild_storage)+12; - WFIFOL(fd,4)=account_id; - WFIFOL(fd,8)=guild_id; - memcpy(WFIFOP(fd,12),gs,sizeof(struct guild_storage)); - } - else { - WFIFOW(fd,2)=12; - WFIFOL(fd,4)=account_id; - WFIFOL(fd,8)=0; + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `guild_id` FROM `%s` WHERE `guild_id`='%d'", guild_db, guild_id) ) + Sql_ShowDebug(sql_handle); + else if( Sql_NumRows(sql_handle) > 0 ) + {// guild exists + WFIFOHEAD(fd, sizeof(struct guild_storage)+12); + WFIFOW(fd,0) = 0x3818; + WFIFOW(fd,2) = sizeof(struct guild_storage)+12; + WFIFOL(fd,4) = account_id; + WFIFOL(fd,8) = guild_id; + guild_storage_fromsql(guild_id, (struct guild_storage*)WFIFOP(fd,12)); + WFIFOSET(fd, WFIFOW(fd,2)); + return 0; } - WFIFOSET(fd,WFIFOW(fd,2)); - + // guild does not exist + Sql_FreeResult(sql_handle); + WFIFOHEAD(fd, 12); + WFIFOW(fd,0) = 0x3818; + WFIFOW(fd,2) = 12; + WFIFOL(fd,4) = account_id; + WFIFOL(fd,8) = 0; + WFIFOSET(fd, 12); return 0; } - int mapif_save_guild_storage_ack(int fd,int account_id,int guild_id,int fail) { WFIFOHEAD(fd,11); @@ -423,7 +193,7 @@ int mapif_save_guild_storage_ack(int fd,int account_id,int guild_id,int fail) } //--------------------------------------------------------- -// map serverからの通信 +// packet from map server int mapif_parse_LoadGuildStorage(int fd) { @@ -434,31 +204,35 @@ int mapif_parse_LoadGuildStorage(int fd) int mapif_parse_SaveGuildStorage(int fd) { - struct guild_storage *gs; - int guild_id, len; + int guild_id; + int len; + RFIFOHEAD(fd); - guild_id=RFIFOL(fd,8); - len=RFIFOW(fd,2); - if(sizeof(struct guild_storage)!=len-12){ - ShowError("inter storage: data size error %d %d\n",sizeof(struct guild_storage),len-12); + guild_id = RFIFOL(fd,8); + len = RFIFOW(fd,2); + + if( sizeof(struct guild_storage) != len - 12 ) + { + ShowError("inter storage: data size error %d != %d\n", sizeof(struct guild_storage), len - 12); } - else { - gs=guild2storage(guild_id); - if(gs) { - memcpy(gs,RFIFOP(fd,12),sizeof(struct guild_storage)); - mapif_save_guild_storage_ack(fd,RFIFOL(fd,4),guild_id,0); + else + { + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `guild_id` FROM `%s` WHERE `guild_id`='%d'", guild_db, guild_id) ) + Sql_ShowDebug(sql_handle); + else if( Sql_NumRows(sql_handle) > 0 ) + {// guild exists + Sql_FreeResult(sql_handle); + guild_storage_tosql(guild_id, (struct guild_storage*)RFIFOP(fd,12)); + mapif_save_guild_storage_ack(fd, RFIFOL(fd,4), guild_id, 0); + return 0; } - else - mapif_save_guild_storage_ack(fd,RFIFOL(fd,4),guild_id,1); + Sql_FreeResult(sql_handle); } + mapif_save_guild_storage_ack(fd, RFIFOL(fd,4), guild_id, 1); return 0; } -// map server からの通信 -// ・1パケットのみ解析すること -// ・パケット長データはinter.cにセットしておくこと -// ・パケット長チェックや、RFIFOSKIPは呼び出し元で行われるので行ってはならない -// ・エラーなら0(false)、そうでないなら1(true)をかえさなければならない + int inter_storage_parse_frommap(int fd) { RFIFOHEAD(fd); @@ -470,4 +244,3 @@ int inter_storage_parse_frommap(int fd) } return 1; } -#endif //TXT_SQL_CONVERT diff --git a/src/char/int_storage.h b/src/char/int_storage.h index fdd2a5f28..811608f82 100644 --- a/src/char/int_storage.h +++ b/src/char/int_storage.h @@ -1,28 +1,22 @@ // Copyright (c) Athena Dev Teams - Licensed under GNU GPL // For more information, see LICENCE in the main folder -#ifndef _INT_STORAGE_H_ -#define _INT_STORAGE_H_ +#ifndef _INT_STORAGE_SQL_H_ +#define _INT_STORAGE_SQL_H_ struct storage_data; struct guild_storage; -int inter_storage_init(void); -void inter_storage_final(void); -int inter_storage_save(void); -int inter_guild_storage_save(void); +int inter_storage_sql_init(void); +void inter_storage_sql_final(void); int inter_storage_delete(int account_id); int inter_guild_storage_delete(int guild_id); -int inter_storage_parse_frommap(int fd); -extern char storage_txt[1024]; -extern char guild_storage_txt[1024]; +int inter_storage_parse_frommap(int fd); //Exported for use in the TXT-SQL converter. -bool storage_fromstr(char* str, int* account_id, struct storage_data* p); -int guild_storage_fromstr(char *str,struct guild_storage *p); - -bool storage_load(int account_id, struct storage_data* storage); -bool storage_save(int account_id, struct storage_data* storage); +int storage_fromsql(int account_id, struct storage_data* p); +int storage_tosql(int account_id,struct storage_data *p); +int guild_storage_tosql(int guild_id, struct guild_storage *p); -#endif /* _INT_STORAGE_H_ */ +#endif /* _INT_STORAGE_SQL_H_ */ diff --git a/src/char/inter.c b/src/char/inter.c index 298ed38a5..2137579be 100644 --- a/src/char/inter.c +++ b/src/char/inter.c @@ -1,300 +1,327 @@ // Copyright (c) Athena Dev Teams - Licensed under GNU GPL // For more information, see LICENCE in the main folder -#include "../common/db.h" #include "../common/mmo.h" -#include "../common/socket.h" -#include "../common/timer.h" +#include "../common/db.h" #include "../common/malloc.h" -#include "../common/lock.h" -#include "../common/showmsg.h" #include "../common/strlib.h" +#include "../common/showmsg.h" +#include "../common/socket.h" +#include "../common/timer.h" #include "char.h" #include "inter.h" #include "int_party.h" #include "int_guild.h" -#include "int_status.h" #include "int_storage.h" #include "int_pet.h" #include "int_homun.h" +#include "int_mercenary.h" +#include "int_mail.h" +#include "int_auction.h" +#include "int_quest.h" #include #include #include -#define WISDATA_TTL (60*1000) // Existence time of Wisp/page data (60 seconds) - // that is the waiting time of answers of all map-servers -#define WISDELLIST_MAX 256 // Number of elements of Wisp/page data deletion list +#define WISDATA_TTL (60*1000) // Wisデータの生存時間(60秒) +#define WISDELLIST_MAX 256 // Wisデータ削除リストの要素数 -char accreg_txt[1024] = "save/accreg.txt"; -#ifndef TXT_SQL_CONVERT -char inter_log_filename[1024] = "log/inter.log"; -char main_chat_nick[16] = "Main"; -static DBMap* accreg_db = NULL; // int account_id -> struct accreg* +Sql* sql_handle = NULL; + +int char_server_port = 3306; +char char_server_ip[32] = "127.0.0.1"; +char char_server_id[32] = "ragnarok"; +char char_server_pw[32] = "ragnarok"; +char char_server_db[32] = "ragnarok"; +char default_codepage[32] = ""; //Feature by irmin. +static struct accreg *accreg_pt; unsigned int party_share_level = 10; +char main_chat_nick[16] = "Main"; -// sending packet list -// NOTE: This variable ain't used at all! And it's confusing.. where do I add that the length of packet 0x2b07 is 10? x.x [Skotlex] -int inter_send_packet_length[]={ - -1,-1,27,-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3000-0x300f - -1, 7, 0, 0, 0, 0, 0, 0, -1,11, 0, 0, 0, 0, 0, 0, - 35,-1,11,15, 34,29, 7,-1, 0, 0, 0, 0, 0, 0, 0, 0, - 10,-1,15, 0, 79,19, 7,-1, 0,-1,-1,-1, 14,67,186,-1, - 9, 9,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 11,-1, 7, 3, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; // recv. packet list -int inter_recv_packet_length[]={ - -1,-1, 7,-1, -1,13,36, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3000-0x300f - 6,-1, 0, 0, 0, 0, 0, 0, 10,-1, 0, 0, 0, 0, 0, 0, //0x3010-0x301f - -1,10,-1,14, 14,19, 6,-1, 14,14, 0, 0, 0, 0, 0, 0, //0x3020-0x302f Party - -1, 6,-1,-1, 55,19, 6,-1, 14,-1,-1,-1, 18,19,186,-1, //0x3030-0x303f - 5, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3040-0x304f - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3050-0x305f - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3060-0x306f - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3070-0x307f - 48,14,-1, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3080-0x308f - -1,10,-1, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3090-0x309f Homunculus packets [albator] +int inter_recv_packet_length[] = { + -1,-1, 7,-1, -1,13,36, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3000- + 6,-1, 0, 0, 0, 0, 0, 0, 10,-1, 0, 0, 0, 0, 0, 0, // 3010- + -1,10,-1,14, 14,19, 6,-1, 14,14, 0, 0, 0, 0, 0, 0, // 3020- Party + -1, 6,-1,-1, 55,19, 6,-1, 14,-1,-1,-1, 18,19,186,-1, // 3030- + 5, 9, 0, 0, 0, 0, 0, 0, 7, 6,10,10, 10,-1, 0, 0, // 3040- + -1,-1,10,10, 0,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3050- Auction System [Zephyrus] + 6,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3060- Quest system [Kevin] [Inkfish] + -1,10, 6,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3070- Mercenary packets [Zephyrus] + 48,14,-1, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3080- + -1,10,-1, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3090- Homunculus packets [albator] }; struct WisData { int id, fd, count, len; unsigned long tick; - unsigned char src[24], dst[24], msg[1024]; + unsigned char src[24], dst[24], msg[512]; }; static DBMap* wis_db = NULL; // int wis_id -> struct WisData* static int wis_dellist[WISDELLIST_MAX], wis_delnum; - //-------------------------------------------------------- +// Save registry to sql +int inter_accreg_tosql(int account_id, int char_id, struct accreg* reg, int type) +{ + struct global_reg* r; + SqlStmt* stmt; + int i; -// アカウント変数を文字列へ変換 -int inter_accreg_tostr(char *str, struct accreg *reg) { - int j; - char *p = str; - - p += sprintf(p, "%d\t", reg->account_id); - for(j = 0; j < reg->reg_num; j++) { - p += sprintf(p,"%s,%s ", reg->reg[j].str, reg->reg[j].value); - } - - return 0; -} -#endif //TXT_SQL_CONVERT -// アカウント変数を文字列から変換 -int inter_accreg_fromstr(const char *str, struct accreg *reg) { - int j, n; - const char *p = str; - - if (sscanf(p, "%d\t%n", ®->account_id, &n ) != 1 || reg->account_id <= 0) - return 1; + if( account_id <= 0 ) + return 0; + reg->account_id = account_id; + reg->char_id = char_id; - for(j = 0, p += n; j < ACCOUNT_REG_NUM; j++, p += n) { - if (sscanf(p, "%[^,],%[^ ] %n", reg->reg[j].str, reg->reg[j].value, &n) != 2) - break; + //`global_reg_value` (`type`, `account_id`, `char_id`, `str`, `value`) + switch( type ) + { + case 3: //Char Reg + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `type`=3 AND `char_id`='%d'", reg_db, char_id) ) + Sql_ShowDebug(sql_handle); + account_id = 0; + break; + case 2: //Account Reg + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `type`=2 AND `account_id`='%d'", reg_db, account_id) ) + Sql_ShowDebug(sql_handle); + char_id = 0; + break; + case 1: //Account2 Reg + ShowError("inter_accreg_tosql: Char server shouldn't handle type 1 registry values (##). That is the login server's work!\n"); + return 0; + default: + ShowError("inter_accreg_tosql: Invalid type %d\n", type); + return 0; } - reg->reg_num = j; - return 0; -} -#ifndef TXT_SQL_CONVERT -// アカウント変数の読み込み -int inter_accreg_init(void) { - char line[8192]; - FILE *fp; - int c = 0; - struct accreg *reg; - - accreg_db = idb_alloc(DB_OPT_RELEASE_DATA); + if( reg->reg_num <= 0 ) + return 0; - if( (fp = fopen(accreg_txt, "r")) == NULL) - return 1; - while(fgets(line, sizeof(line), fp)) + stmt = SqlStmt_Malloc(sql_handle); + if( SQL_ERROR == SqlStmt_Prepare(stmt, "INSERT INTO `%s` (`type`, `account_id`, `char_id`, `str`, `value`) VALUES ('%d','%d','%d',?,?)", reg_db, type, account_id, char_id) ) + SqlStmt_ShowDebug(stmt); + for( i = 0; i < reg->reg_num; ++i ) { - reg = (struct accreg*)aCalloc(sizeof(struct accreg), 1); - if (reg == NULL) { - ShowFatalError("inter: accreg: out of memory!\n"); - exit(EXIT_FAILURE); + r = ®->reg[i]; + if( r->str[0] != '\0' && r->value != '\0' ) + { + // str + SqlStmt_BindParam(stmt, 0, SQLDT_STRING, r->str, strnlen(r->str, sizeof(r->str))); + // value + SqlStmt_BindParam(stmt, 1, SQLDT_STRING, r->value, strnlen(r->value, sizeof(r->value))); + + if( SQL_ERROR == SqlStmt_Execute(stmt) ) + SqlStmt_ShowDebug(stmt); } - if (inter_accreg_fromstr(line, reg) == 0 && reg->account_id > 0) { - idb_put(accreg_db, reg->account_id, reg); - } else { - ShowError("inter: accreg: broken data [%s] line %d\n", accreg_txt, c); - aFree(reg); - } - c++; } - fclose(fp); - - return 0; + SqlStmt_Free(stmt); + return 1; } -// アカウント変数のセーブ用 -int inter_accreg_save_sub(DBKey key, void *data, va_list ap) { - char line[8192]; - FILE *fp; - struct accreg *reg = (struct accreg *)data; - - if (reg->reg_num > 0) { - inter_accreg_tostr(line,reg); - fp = va_arg(ap, FILE *); - fprintf(fp, "%s\n", line); - } +// Load account_reg from sql (type=2) +int inter_accreg_fromsql(int account_id,int char_id, struct accreg *reg, int type) +{ + struct global_reg* r; + char* data; + size_t len; + int i; - return 0; -} + if( reg == NULL) + return 0; -// アカウント変数のセーブ -int inter_accreg_save(void) { - FILE *fp; - int lock; + memset(reg, 0, sizeof(struct accreg)); + reg->account_id = account_id; + reg->char_id = char_id; - if ((fp = lock_fopen(accreg_txt,&lock)) == NULL) { - ShowError("int_accreg: can't write [%s] !!! data is lost !!!\n", accreg_txt); - return 1; + //`global_reg_value` (`type`, `account_id`, `char_id`, `str`, `value`) + switch( type ) + { + case 3: //char reg + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `str`, `value` FROM `%s` WHERE `type`=3 AND `char_id`='%d'", reg_db, char_id) ) + Sql_ShowDebug(sql_handle); + break; + case 2: //account reg + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `str`, `value` FROM `%s` WHERE `type`=2 AND `account_id`='%d'", reg_db, account_id) ) + Sql_ShowDebug(sql_handle); + break; + case 1: //account2 reg + ShowError("inter_accreg_fromsql: Char server shouldn't handle type 1 registry values (##). That is the login server's work!\n"); + return 0; + default: + ShowError("inter_accreg_fromsql: Invalid type %d\n", type); + return 0; + } + for( i = 0; i < MAX_REG_NUM && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i ) + { + r = ®->reg[i]; + // str + Sql_GetData(sql_handle, 0, &data, &len); + memcpy(r->str, data, min(len, sizeof(r->str))); + // value + Sql_GetData(sql_handle, 1, &data, &len); + memcpy(r->value, data, min(len, sizeof(r->value))); } - accreg_db->foreach(accreg_db, inter_accreg_save_sub,fp); - lock_fclose(fp, accreg_txt, &lock); + reg->reg_num = i; + Sql_FreeResult(sql_handle); + return 1; +} +// Initialize +int inter_accreg_sql_init(void) +{ + CREATE(accreg_pt, struct accreg, 1); return 0; + } -//-------------------------------------------------------- -#endif //TXT_SQL_CONVERT /*========================================== - * 設定ファイルを読み込む + * read config file *------------------------------------------*/ -static int inter_config_read(const char *cfgName) { +static int inter_config_read(const char* cfgName) +{ + int i; char line[1024], w1[1024], w2[1024]; - FILE *fp; + FILE* fp; fp = fopen(cfgName, "r"); - if (fp == NULL) { + if(fp == NULL) { ShowError("file not found: %s\n", cfgName); return 1; } + + ShowInfo("reading file %s...\n", cfgName); + while(fgets(line, sizeof(line), fp)) { - if (line[0] == '/' && line[1] == '/') + i = sscanf(line, "%[^:]: %[^\r\n]", w1, w2); + if(i != 2) continue; - if (sscanf(line,"%[^:]: %[^\r\n]", w1, w2) != 2) - continue; - - if (strcmpi(w1, "storage_txt") == 0) { - strncpy(storage_txt, w2, sizeof(storage_txt)); - } else if (strcmpi(w1, "party_txt") == 0) { - strncpy(party_txt, w2, sizeof(party_txt)); - } else if (strcmpi(w1, "pet_txt") == 0) { - strncpy(pet_txt, w2, sizeof(pet_txt)); - } else if (strcmpi(w1, "accreg_txt") == 0) { - strncpy(accreg_txt, w2, sizeof(accreg_txt)); - } else if (strcmpi(w1, "guild_txt") == 0) { - strncpy(guild_txt, w2, sizeof(guild_txt)); - } else if (strcmpi(w1, "castle_txt") == 0) { - strncpy(castle_txt, w2, sizeof(castle_txt)); - } else if (strcmpi(w1, "guild_storage_txt") == 0) { - strncpy(guild_storage_txt, w2, sizeof(guild_storage_txt)); -#ifndef TXT_SQL_CONVERT - } else if (strcmpi(w1, "homun_txt") == 0) { - strncpy(homun_txt, w2, sizeof(homun_txt)); - } else if (strcmpi(w1, "party_share_level") == 0) { - party_share_level = (unsigned int)atof(w2); - } else if (strcmpi(w1, "inter_log_filename") == 0) { - strncpy(inter_log_filename, w2, sizeof(inter_log_filename)); - } else if(strcmpi(w1,"log_inter")==0) { + if(!strcmpi(w1,"char_server_ip")) { + strcpy(char_server_ip,w2); + ShowStatus ("set char_server_ip : %s\n", w2); + } else + if(!strcmpi(w1,"char_server_port")) { + char_server_port = atoi(w2); + ShowStatus ("set char_server_port : %s\n", w2); + } else + if(!strcmpi(w1,"char_server_id")) { + strcpy(char_server_id,w2); + ShowStatus ("set char_server_id : %s\n", w2); + } else + if(!strcmpi(w1,"char_server_pw")) { + strcpy(char_server_pw,w2); + ShowStatus ("set char_server_pw : %s\n", w2); + } else + if(!strcmpi(w1,"char_server_db")) { + strcpy(char_server_db,w2); + ShowStatus ("set char_server_db : %s\n", w2); + } else + if(!strcmpi(w1,"default_codepage")) { + strcpy(default_codepage,w2); + ShowStatus ("set default_codepage : %s\n", w2); + } + else if(!strcmpi(w1,"party_share_level")) + party_share_level = atoi(w2); + else if(!strcmpi(w1,"log_inter")) log_inter = atoi(w2); - } else if(strcmpi(w1, "main_chat_nick")==0){ // Main chat nick [LuzZza] + else if(!strcmpi(w1,"main_chat_nick")) safestrncpy(main_chat_nick, w2, sizeof(main_chat_nick)); -#endif //TXT_SQL_CONVERT - } else if (strcmpi(w1, "import") == 0) { + else if(!strcmpi(w1,"import")) inter_config_read(w2); - } } fclose(fp); + ShowInfo ("done reading %s.\n", cfgName); + return 0; } -#ifndef TXT_SQL_CONVERT -// ログ書き出し -int inter_log(char *fmt,...) { - FILE *logfp; + +// Save interlog into sql +int inter_log(char* fmt, ...) +{ + char str[255]; + char esc_str[sizeof(str)*2+1];// escaped str va_list ap; va_start(ap,fmt); - logfp = fopen(inter_log_filename, "a"); - if (logfp) { - vfprintf(logfp, fmt, ap); - fclose(logfp); - } + vsnprintf(str, sizeof(str), fmt, ap); va_end(ap); - return 0; -} - -// セーブ -int inter_save(void) { -#ifdef ENABLE_SC_SAVING - inter_status_save(); -#endif - inter_party_save(); - inter_guild_save(); - inter_storage_save(); - inter_guild_storage_save(); - inter_pet_save(); - inter_homun_save(); - inter_accreg_save(); + Sql_EscapeStringLen(sql_handle, esc_str, str, strnlen(str, sizeof(str))); + if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`time`, `log`) VALUES (NOW(), '%s')", interlog_db, esc_str) ) + Sql_ShowDebug(sql_handle); return 0; } -#endif //TXT_SQL_CONVERT -// 初期化 -int inter_init_txt(const char *file) +// initialize +int inter_init_sql(const char *file) { + //int i; + + ShowInfo ("interserver initialize...\n"); inter_config_read(file); -#ifndef TXT_SQL_CONVERT + //DB connection initialized + sql_handle = Sql_Malloc(); + ShowInfo("Connect Character DB server.... (Character Server)\n"); + if( SQL_ERROR == Sql_Connect(sql_handle, char_server_id, char_server_pw, char_server_ip, (uint16)char_server_port, char_server_db) ) + { + Sql_ShowDebug(sql_handle); + Sql_Free(sql_handle); + exit(EXIT_FAILURE); + } + + if( *default_codepage ) { + if( SQL_ERROR == Sql_SetEncoding(sql_handle, default_codepage) ) + Sql_ShowDebug(sql_handle); + } + wis_db = idb_alloc(DB_OPT_RELEASE_DATA); + inter_guild_sql_init(); + inter_storage_sql_init(); + inter_party_sql_init(); + inter_pet_sql_init(); + inter_homunculus_sql_init(); + inter_mercenary_sql_init(); + inter_accreg_sql_init(); + inter_mail_sql_init(); + inter_auction_sql_init(); - inter_party_init(); - inter_guild_init(); - inter_storage_init(); - inter_pet_init(); - inter_homun_init(); - inter_accreg_init(); -#endif //TXT_SQL_CONVERT return 0; } -#ifndef TXT_SQL_CONVERT + // finalize -void inter_final(void) { - accreg_db->destroy(accreg_db, NULL); +void inter_final(void) +{ wis_db->destroy(wis_db, NULL); - inter_party_final(); - inter_guild_final(); - inter_storage_final(); - inter_pet_final(); - inter_homun_final(); - + inter_guild_sql_final(); + inter_storage_sql_final(); + inter_party_sql_final(); + inter_pet_sql_final(); + inter_homunculus_sql_final(); + inter_mercenary_sql_final(); + inter_mail_sql_final(); + inter_auction_sql_final(); + + if (accreg_pt) aFree(accreg_pt); return; } -// マップサーバー接続 -int inter_mapif_init(int fd) { +int inter_mapif_init(int fd) +{ inter_guild_mapif_init(fd); return 0; } + //-------------------------------------------------------- -// sended packets to map-server // broadcast sending int mapif_broadcast(unsigned char *mes, int len, unsigned long fontColor, short fontType, short fontSize, short fontAlign, short fontY, int sfd) @@ -316,56 +343,32 @@ int mapif_broadcast(unsigned char *mes, int len, unsigned long fontColor, short return 0; } -// Wisp/page transmission to one map-server -int mapif_wis_message2(struct WisData *wd, int fd) { - WFIFOHEAD(fd, 56+wd->len); - WFIFOW(fd, 0) = 0x3801; - WFIFOW(fd, 2) = 56 + wd->len; - WFIFOL(fd, 4) = wd->id; - memcpy(WFIFOP(fd, 8), wd->src, NAME_LENGTH); - memcpy(WFIFOP(fd,32), wd->dst, NAME_LENGTH); - memcpy(WFIFOP(fd,56), wd->msg, wd->len); - wd->count = 1; - WFIFOSET(fd,WFIFOW(fd,2)); - return 1; -} - -// Wisp/page transmission to all map-server -int mapif_wis_message(struct WisData *wd) { +// Wis sending +int mapif_wis_message(struct WisData *wd) +{ unsigned char buf[2048]; if (wd->len > 2047-56) wd->len = 2047-56; //Force it to fit to avoid crashes. [Skotlex] WBUFW(buf, 0) = 0x3801; - WBUFW(buf, 2) = 56 + wd->len; + WBUFW(buf, 2) = 56 +wd->len; WBUFL(buf, 4) = wd->id; memcpy(WBUFP(buf, 8), wd->src, NAME_LENGTH); memcpy(WBUFP(buf,32), wd->dst, NAME_LENGTH); memcpy(WBUFP(buf,56), wd->msg, wd->len); - wd->count = mapif_sendall(buf, WBUFW(buf,2)); + wd->count = mapif_sendall(buf,WBUFW(buf,2)); return 0; } -int mapif_wis_fail(int fd, char *src) { - unsigned char buf[27]; - WBUFW(buf, 0) = 0x3802; - memcpy(WBUFP(buf, 2), src, NAME_LENGTH); - WBUFB(buf,26) = 1; // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target - mapif_send(fd, buf, 27); - return 0; - -} - -// Wisp/page transmission result to map-server +// Wis sending result int mapif_wis_end(struct WisData *wd, int flag) { unsigned char buf[27]; - WBUFW(buf, 0) = 0x3802; - memcpy(WBUFP(buf, 2), wd->src, 24); - WBUFB(buf,26) = flag; // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target - mapif_send(wd->fd, buf, 27); - + WBUFW(buf, 0)=0x3802; + memcpy(WBUFP(buf, 2),wd->src,24); + WBUFB(buf,26)=flag; + mapif_send(wd->fd,buf,27); return 0; } @@ -376,25 +379,28 @@ static void mapif_account_reg(int fd, unsigned char *src) mapif_sendallwos(fd, src, WBUFW(src,2)); } -// アカウント変数要求返信 -int mapif_account_reg_reply(int fd,int account_id, int char_id) +// Send the requested account_reg +int mapif_account_reg_reply(int fd,int account_id,int char_id, int type) { - struct accreg *reg = (struct accreg*)idb_get(accreg_db,account_id); - - WFIFOHEAD(fd, ACCOUNT_REG_NUM * 288+ 13); - WFIFOW(fd,0) = 0x3804; - WFIFOL(fd,4) = account_id; - WFIFOL(fd,8) = char_id; - WFIFOB(fd,12) = 2; //Acc Reg - if (reg == NULL) { - WFIFOW(fd,2) = 13; - } else { - int i, p; - for (p=13,i = 0; i < reg->reg_num; i++) { + struct accreg *reg=accreg_pt; + WFIFOHEAD(fd, 13 + 5000); + inter_accreg_fromsql(account_id,char_id,reg,type); + + WFIFOW(fd,0)=0x3804; + WFIFOL(fd,4)=account_id; + WFIFOL(fd,8)=char_id; + WFIFOB(fd,12)=type; + if(reg->reg_num==0){ + WFIFOW(fd,2)=13; + }else{ + int i,p; + for (p=13,i = 0; i < reg->reg_num && p < 5000; i++) { p+= sprintf((char*)WFIFOP(fd,p), "%s", reg->reg[i].str)+1; //We add 1 to consider the '\0' in place. p+= sprintf((char*)WFIFOP(fd,p), "%s", reg->reg[i].value)+1; } WFIFOW(fd,2)=p; + if (p>= 5000) + ShowWarning("Too many acc regs for %d:%d, not all values were loaded.\n", account_id, char_id); } WFIFOSET(fd,WFIFOW(fd,2)); return 0; @@ -403,22 +409,23 @@ int mapif_account_reg_reply(int fd,int account_id, int char_id) //Request to kick char from a certain map server. [Skotlex] int mapif_disconnectplayer(int fd, int account_id, int char_id, int reason) { - if (fd < 0) - return -1; - - WFIFOHEAD(fd, 7); - WFIFOW(fd,0) = 0x2b1f; - WFIFOL(fd,2) = account_id; - WFIFOB(fd,6) = reason; - WFIFOSET(fd,7); - - return 0; + if (fd >= 0) + { + WFIFOHEAD(fd,7); + WFIFOW(fd,0) = 0x2b1f; + WFIFOL(fd,2) = account_id; + WFIFOB(fd,6) = reason; + WFIFOSET(fd,7); + return 0; + } + return -1; } //-------------------------------------------------------- // Existence check of WISP data -int check_ttl_wisdata_sub(DBKey key, void *data, va_list ap) { +int check_ttl_wisdata_sub(DBKey key, void *data, va_list ap) +{ unsigned long tick; struct WisData *wd = (struct WisData *)data; tick = va_arg(ap, unsigned long); @@ -429,7 +436,8 @@ int check_ttl_wisdata_sub(DBKey key, void *data, va_list ap) { return 0; } -int check_ttl_wisdata(void) { +int check_ttl_wisdata(void) +{ unsigned long tick = gettick(); int i; @@ -449,41 +457,27 @@ int check_ttl_wisdata(void) { } //-------------------------------------------------------- -// received packets from map-server // broadcast sending int mapif_parse_broadcast(int fd) { - RFIFOHEAD(fd); mapif_broadcast(RFIFOP(fd,16), RFIFOW(fd,2), RFIFOL(fd,4), RFIFOW(fd,8), RFIFOW(fd,10), RFIFOW(fd,12), RFIFOW(fd,14), fd); return 0; } -static struct WisData* mapif_create_whisper(int fd, char* src, char* dst, char* mes, int meslen) -{ - static int wisid = 0; - struct WisData* wd = (struct WisData *)aCalloc(sizeof(struct WisData), 1); - if (wd == NULL){ - ShowFatalError("inter: WisRequest: out of memory !\n"); - return NULL; - } - wd->id = ++wisid; - wd->fd = fd; - wd->len= meslen; - memcpy(wd->src, src, NAME_LENGTH); - memcpy(wd->dst, dst, NAME_LENGTH); - memcpy(wd->msg, mes, meslen); - wd->tick = gettick(); - return wd; -} // Wisp/page request to send int mapif_parse_WisRequest(int fd) { - struct mmo_charstatus* char_status; struct WisData* wd; + static int wisid = 0; char name[NAME_LENGTH]; - int fd2; + char esc_name[NAME_LENGTH*2+1];// escaped name + char* data; + size_t len; + + + if ( fd <= 0 ) {return 0;} // check if we have a valid fd if (RFIFOW(fd,2)-52 >= sizeof(wd->msg)) { ShowWarning("inter: Wis message size too long.\n"); @@ -492,46 +486,73 @@ int mapif_parse_WisRequest(int fd) ShowError("inter: Wis message doesn't exist.\n"); return 0; } - + safestrncpy(name, (char*)RFIFOP(fd,28), NAME_LENGTH); //Received name may be too large and not contain \0! [Skotlex] + Sql_EscapeStringLen(sql_handle, esc_name, name, strnlen(name, NAME_LENGTH)); + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `name` FROM `%s` WHERE `name`='%s'", char_db, esc_name) ) + Sql_ShowDebug(sql_handle); + // search if character exists before to ask all map-servers - char_status = search_character_byname(name); - if (char_status == NULL) - return mapif_wis_fail(fd, (char*)RFIFOP(fd, 4)); - - // Character exists. - // to be sure of the correct name, rewrite it - memset(name, 0, NAME_LENGTH); - strncpy(name, char_status->name, NAME_LENGTH); - // if source is destination, don't ask other servers. - if (strcmp((char*)RFIFOP(fd,4),name) == 0) - return mapif_wis_fail(fd, (char*)RFIFOP(fd, 4)); - - //Look for online character. - fd2 = search_character_online(char_status->account_id, char_status->char_id); - if (fd2 >= 0) { //Character online, send whisper. - wd = mapif_create_whisper(fd, (char*)RFIFOP(fd, 4), (char*)RFIFOP(fd,28), (char*)RFIFOP(fd,52), RFIFOW(fd,2)-52); - if (!wd) return 1; - idb_put(wis_db, wd->id, wd); - mapif_wis_message2(wd, fd2); - return 0; + if( SQL_SUCCESS != Sql_NextRow(sql_handle) ) + { + unsigned char buf[27]; + WBUFW(buf, 0) = 0x3802; + memcpy(WBUFP(buf, 2), RFIFOP(fd, 4), NAME_LENGTH); + WBUFB(buf,26) = 1; // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target + mapif_send(fd, buf, 27); + } + else + {// Character exists. So, ask all map-servers + // to be sure of the correct name, rewrite it + Sql_GetData(sql_handle, 0, &data, &len); + memset(name, 0, NAME_LENGTH); + memcpy(name, data, min(len, NAME_LENGTH)); + // if source is destination, don't ask other servers. + if( strncmp((const char*)RFIFOP(fd,4), name, NAME_LENGTH) == 0 ) + { + uint8 buf[27]; + WBUFW(buf, 0) = 0x3802; + memcpy(WBUFP(buf, 2), RFIFOP(fd, 4), NAME_LENGTH); + WBUFB(buf,26) = 1; // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target + mapif_send(fd, buf, 27); + } + else + { + + CREATE(wd, struct WisData, 1); + + // Whether the failure of previous wisp/page transmission (timeout) + check_ttl_wisdata(); + + wd->id = ++wisid; + wd->fd = fd; + wd->len= RFIFOW(fd,2)-52; + memcpy(wd->src, RFIFOP(fd, 4), NAME_LENGTH); + memcpy(wd->dst, RFIFOP(fd,28), NAME_LENGTH); + memcpy(wd->msg, RFIFOP(fd,52), wd->len); + wd->tick = gettick(); + idb_put(wis_db, wd->id, wd); + mapif_wis_message(wd); + } } - //Not found. - return mapif_wis_fail(fd, (char*)RFIFOP(fd,4)); + + Sql_FreeResult(sql_handle); + return 0; } + // Wisp/page transmission result -int mapif_parse_WisReply(int fd) { +int mapif_parse_WisReply(int fd) +{ int id, flag; struct WisData *wd; - RFIFOHEAD(fd); + id = RFIFOL(fd,2); flag = RFIFOB(fd,6); wd = (struct WisData*)idb_get(wis_db, id); - if (wd == NULL) - return 0; // This wisp was probably suppress before, because it was timeout or because of target was found on another map-server + return 0; // This wisp was probably suppress before, because it was timeout of because of target was found on another map-server if ((--wd->count) <= 0 || flag != 1) { mapif_wis_end(wd, flag); // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target @@ -542,10 +563,10 @@ int mapif_parse_WisReply(int fd) { } // Received wisp message from map-server for ALL gm (just copy the message and resends it to ALL map-servers) -int mapif_parse_WisToGM(int fd) { +int mapif_parse_WisToGM(int fd) +{ unsigned char buf[2048]; // 0x3003/0x3803 .w .24B .w .?B - - ShowDebug("Sent packet back!\n"); + memcpy(WBUFP(buf,0), RFIFOP(fd,0), RFIFOW(fd,2)); WBUFW(buf, 0) = 0x3803; mapif_sendall(buf, RFIFOW(fd,2)); @@ -553,32 +574,26 @@ int mapif_parse_WisToGM(int fd) { return 0; } -static void* create_accreg(DBKey key, va_list args) { - struct accreg *reg; - reg = (struct accreg*)aCalloc(sizeof(struct accreg), 1); - reg->account_id = key.i; - return reg; -} - -// アカウント変数保存要求 -int mapif_parse_Registry(int fd) { - int j, p, len; - struct accreg *reg; - RFIFOHEAD(fd); - - switch (RFIFOB(fd,12)) { - case 3: //Character registry - return char_parse_Registry(RFIFOL(fd,4), RFIFOL(fd,8), RFIFOP(fd,13), RFIFOW(fd,2)-13); - case 2: //Acc Reg - break; - case 1: //Acc Reg2, forward to login - return save_accreg2(RFIFOP(fd,4), RFIFOW(fd,2)-4); - default: //Error? - return 1; +// Save account_reg into sql (type=2) +int mapif_parse_Registry(int fd) +{ + int j,p,len, max; + struct accreg *reg=accreg_pt; + + memset(accreg_pt,0,sizeof(struct accreg)); + switch (RFIFOB(fd, 12)) { + case 3: //Character registry + max = GLOBAL_REG_NUM; + break; + case 2: //Account Registry + max = ACCOUNT_REG_NUM; + break; + case 1: //Account2 registry, must be sent over to login server. + return save_accreg2(RFIFOP(fd,4), RFIFOW(fd,2)-4); + default: + return 1; } - reg = (struct accreg*)idb_ensure(accreg_db, RFIFOL(fd,4), create_accreg); - - for(j=0,p=13;jreg[j].str,&len); reg->reg[j].str[len]='\0'; p +=len+1; //+1 to skip the '\0' between strings. @@ -587,34 +602,32 @@ int mapif_parse_Registry(int fd) { p +=len+1; } reg->reg_num=j; - mapif_account_reg(fd, RFIFOP(fd,0)); // 他のMAPサーバーに送信 + inter_accreg_tosql(RFIFOL(fd,4),RFIFOL(fd,8),reg, RFIFOB(fd,12)); + mapif_account_reg(fd,RFIFOP(fd,0)); // Send updated accounts to other map servers. return 0; } // Request the value of all registries. int mapif_parse_RegistryRequest(int fd) -{ - RFIFOHEAD(fd); +{ //Load Char Registry - if (RFIFOB(fd,12)) - char_account_reg_reply(fd,RFIFOL(fd,2),RFIFOL(fd,6)); + if (RFIFOB(fd,12)) mapif_account_reg_reply(fd,RFIFOL(fd,2),RFIFOL(fd,6),3); //Load Account Registry - if (RFIFOB(fd,11)) - mapif_account_reg_reply(fd,RFIFOL(fd,2),RFIFOL(fd,6)); + if (RFIFOB(fd,11)) mapif_account_reg_reply(fd,RFIFOL(fd,2),RFIFOL(fd,6),2); //Ask Login Server for Account2 values. - if (RFIFOB(fd,10)) - request_accreg2(RFIFOL(fd,2),RFIFOL(fd,6)); + if (RFIFOB(fd,10)) request_accreg2(RFIFOL(fd,2),RFIFOL(fd,6)); return 1; } -static void mapif_namechange_ack(int fd, int account_id, int char_id, int type, int flag, char *name){ +static void mapif_namechange_ack(int fd, int account_id, int char_id, int type, int flag, char *name) +{ WFIFOHEAD(fd, NAME_LENGTH+13); - WFIFOW(fd, 0) =0x3806; - WFIFOL(fd, 2) =account_id; - WFIFOL(fd, 6) =char_id; - WFIFOB(fd,10) =type; - WFIFOB(fd,11) =flag; + WFIFOW(fd, 0) = 0x3806; + WFIFOL(fd, 2) = account_id; + WFIFOL(fd, 6) = char_id; + WFIFOB(fd,10) = type; + WFIFOB(fd,11) = flag; memcpy(WFIFOP(fd, 12), name, NAME_LENGTH); WFIFOSET(fd, NAME_LENGTH+13); } @@ -625,11 +638,10 @@ int mapif_parse_NameChangeRequest(int fd) char* name; int i; - RFIFOHEAD(fd); - account_id = RFIFOL(fd, 2); - char_id = RFIFOL(fd, 6); - type = RFIFOB(fd, 10); - name = (char*)RFIFOP(fd, 11); + account_id = RFIFOL(fd,2); + char_id = RFIFOL(fd,6); + type = RFIFOB(fd,10); + name = (char*)RFIFOP(fd,11); // Check Authorised letters/symbols in the name if (char_name_option == 1) { // only letters/symbols in char_name_letters are authorised @@ -675,24 +687,17 @@ int inter_check_length(int fd, int length) return length; } -// map server からの通信(1パケットのみ解析すること) -// エラーなら0(false)、処理できたなら1、 -// パケット長が足りなければ2をかえさなければならない -int inter_parse_frommap(int fd) { - int cmd, len; - RFIFOHEAD(fd); +int inter_parse_frommap(int fd) +{ + int cmd; + int len = 0; cmd = RFIFOW(fd,0); - len = 0; - // inter鯖管轄かを調べる - if (cmd < 0x3000 || cmd >= 0x3000 + ARRAYLENGTH(inter_recv_packet_length)) - return 0; - - if (inter_recv_packet_length[cmd-0x3000] == 0) //This is necessary, because otherwise we return 2 and the char server will just hang waiting for packets! [Skotlex] + if(cmd < 0x3000 || cmd >= 0x3000 + ARRAYLENGTH(inter_recv_packet_length) || inter_recv_packet_length[cmd - 0x3000] == 0) return 0; // パケット長を調べる - if ((len = inter_check_length(fd, inter_recv_packet_length[cmd - 0x3000])) == 0) + if((len = inter_check_length(fd, inter_recv_packet_length[cmd - 0x3000])) == 0) return 2; switch(cmd) { @@ -704,20 +709,21 @@ int inter_parse_frommap(int fd) { case 0x3005: mapif_parse_RegistryRequest(fd); break; case 0x3006: mapif_parse_NameChangeRequest(fd); break; default: - if (inter_party_parse_frommap(fd)) - break; - if (inter_guild_parse_frommap(fd)) - break; - if (inter_storage_parse_frommap(fd)) - break; - if (inter_pet_parse_frommap(fd)) - break; - if (inter_homun_parse_frommap(fd)) + if( inter_party_parse_frommap(fd) + || inter_guild_parse_frommap(fd) + || inter_storage_parse_frommap(fd) + || inter_pet_parse_frommap(fd) + || inter_homunculus_parse_frommap(fd) + || inter_mercenary_parse_frommap(fd) + || inter_mail_parse_frommap(fd) + || inter_auction_parse_frommap(fd) + || inter_quest_parse_frommap(fd) + ) break; - return 0; + else + return 0; } + RFIFOSKIP(fd, len); return 1; } - -#endif //TXT_SQL_CONVERT diff --git a/src/char/inter.h b/src/char/inter.h index cf3eb4b2e..ac2e1785f 100644 --- a/src/char/inter.h +++ b/src/char/inter.h @@ -1,16 +1,17 @@ // Copyright (c) Athena Dev Teams - Licensed under GNU GPL // For more information, see LICENCE in the main folder -#ifndef _INTER_H_ -#define _INTER_H_ +#ifndef _INTER_SQL_H_ +#define _INTER_SQL_H_ struct accreg; +#include "../common/sql.h" -int inter_init_txt(const char *file); +int inter_init_sql(const char *file); void inter_final(void); -int inter_save(void); int inter_parse_frommap(int fd); int inter_mapif_init(int fd); +int mapif_send_gmaccounts(void); int mapif_disconnectplayer(int fd, int account_id, int char_id, int reason); int inter_log(char *fmt,...); @@ -18,10 +19,12 @@ int inter_log(char *fmt,...); #define inter_cfgName "conf/inter_athena.conf" extern unsigned int party_share_level; + +extern Sql* sql_handle; +extern Sql* lsql_handle; + extern char main_chat_nick[16]; -//For TXT->SQL conversion -extern char accreg_txt[]; -int inter_accreg_fromstr(const char *str, struct accreg *reg); +int inter_accreg_tosql(int account_id, int char_id, struct accreg *reg, int type); -#endif /* _INTER_H_ */ +#endif /* _INTER_SQL_H_ */ diff --git a/src/char_sql/CMakeLists.txt b/src/char_sql/CMakeLists.txt deleted file mode 100644 index 823939393..000000000 --- a/src/char_sql/CMakeLists.txt +++ /dev/null @@ -1,58 +0,0 @@ - -# -# setup -# -set( SQL_CHAR_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR} CACHE INTERNAL "" ) - - -# -# char sql -# -if( BUILD_SQL_SERVERS ) -message( STATUS "Creating target char-server_sql" ) -set( SQL_CHAR_HEADERS - "${CMAKE_CURRENT_SOURCE_DIR}/char.h" - "${CMAKE_CURRENT_SOURCE_DIR}/int_auction.h" - "${CMAKE_CURRENT_SOURCE_DIR}/int_guild.h" - "${CMAKE_CURRENT_SOURCE_DIR}/int_homun.h" - "${CMAKE_CURRENT_SOURCE_DIR}/int_mail.h" - "${CMAKE_CURRENT_SOURCE_DIR}/int_mercenary.h" - "${CMAKE_CURRENT_SOURCE_DIR}/int_party.h" - "${CMAKE_CURRENT_SOURCE_DIR}/int_pet.h" - "${CMAKE_CURRENT_SOURCE_DIR}/int_quest.h" - "${CMAKE_CURRENT_SOURCE_DIR}/int_storage.h" - "${CMAKE_CURRENT_SOURCE_DIR}/inter.h" - ) -set( SQL_CHAR_SOURCES - "${CMAKE_CURRENT_SOURCE_DIR}/char.c" - "${CMAKE_CURRENT_SOURCE_DIR}/int_auction.c" - "${CMAKE_CURRENT_SOURCE_DIR}/int_guild.c" - "${CMAKE_CURRENT_SOURCE_DIR}/int_homun.c" - "${CMAKE_CURRENT_SOURCE_DIR}/int_mail.c" - "${CMAKE_CURRENT_SOURCE_DIR}/int_mercenary.c" - "${CMAKE_CURRENT_SOURCE_DIR}/int_party.c" - "${CMAKE_CURRENT_SOURCE_DIR}/int_pet.c" - "${CMAKE_CURRENT_SOURCE_DIR}/int_quest.c" - "${CMAKE_CURRENT_SOURCE_DIR}/int_storage.c" - "${CMAKE_CURRENT_SOURCE_DIR}/inter.c" - ) -set( DEPENDENCIES common_sql ) -set( LIBRARIES ${GLOBAL_LIBRARIES} ) -set( INCLUDE_DIRS ${GLOBAL_INCLUDE_DIRS} ) -set( DEFINITIONS "${GLOBAL_DEFINITIONS}" ) -set( SOURCE_FILES ${COMMON_BASE_HEADERS} ${COMMON_SQL_HEADERS} ${SQL_CHAR_HEADERS} ${SQL_CHAR_SOURCES} ) -source_group( common FILES ${COMMON_BASE_HEADERS} ${COMMON_SQL_HEADERS} ) -source_group( char FILES ${SQL_CHAR_HEADERS} ${SQL_CHAR_SOURCES} ) -include_directories( ${INCLUDE_DIRS} ) -add_executable( char-server_sql ${SOURCE_FILES} ) -add_dependencies( char-server_sql ${DEPENDENCIES} ) -target_link_libraries( char-server_sql ${LIBRARIES} ${DEPENDENCIES} ) -set_target_properties( char-server_sql PROPERTIES COMPILE_FLAGS "${DEFINITIONS}" ) -if( INSTALL_COMPONENT_RUNTIME ) - cpack_add_component( Runtime_charserver_sql DESCRIPTION "char-server (sql version)" DISPLAY_NAME "char-server_sql" GROUP Runtime ) - install( TARGETS char-server_sql - DESTINATION "." - COMPONENT Runtime_charserver_sql ) -endif( INSTALL_COMPONENT_RUNTIME ) -message( STATUS "Creating target char-server_sql - done" ) -endif( BUILD_SQL_SERVERS ) diff --git a/src/char_sql/Makefile.in b/src/char_sql/Makefile.in deleted file mode 100644 index e96113f0e..000000000 --- a/src/char_sql/Makefile.in +++ /dev/null @@ -1,71 +0,0 @@ - -COMMON_OBJ = ../common/obj_all/core.o ../common/obj_all/socket.o ../common/obj_all/timer.o \ - ../common/obj_all/db.o ../common/obj_all/plugins.o ../common/obj_all/lock.o \ - ../common/obj_all/malloc.o ../common/obj_all/showmsg.o ../common/obj_all/utils.o \ - ../common/obj_all/strlib.o \ - ../common/obj_all/mapindex.o ../common/obj_all/ers.o ../common/obj_all/random.o -COMMON_H = ../common/core.h ../common/socket.h ../common/timer.h ../common/mmo.h \ - ../common/version.h ../common/db.h ../common/plugins.h ../common/lock.h \ - ../common/malloc.h ../common/showmsg.h ../common/utils.h \ - ../common/strlib.h \ - ../common/mapindex.h ../common/ers.h ../common/random.h - -MT19937AR_OBJ = ../../3rdparty/mt19937ar/mt19937ar.o -MT19937AR_H = ../../3rdparty/mt19937ar/mt19937ar.h -MT19937AR_INCLUDE = -I../../3rdparty/mt19937ar - -COMMON_SQL_OBJ = ../common/obj_sql/sql.o -COMMON_H = ../common/sql.h - -CHAR_OBJ = obj_sql/char.o obj_sql/inter.o obj_sql/int_party.o obj_sql/int_guild.o \ - obj_sql/int_storage.o obj_sql/int_pet.o obj_sql/int_homun.o obj_sql/int_mail.o obj_sql/int_auction.o obj_sql/int_quest.o obj_sql/int_mercenary.o -CHAR_H = char.h inter.h int_party.h int_guild.h int_storage.h int_pet.h int_homun.h int_mail.h int_auction.h int_quest.h int_mercenary.h - -HAVE_MYSQL=@HAVE_MYSQL@ -ifeq ($(HAVE_MYSQL),yes) - CHAR_SERVER_SQL_DEPENDS=obj_sql $(CHAR_OBJ) $(COMMON_OBJ) $(COMMON_SQL_OBJ) $(MT19937AR_OBJ) -else - CHAR_SERVER_SQL_DEPENDS=needs_mysql -endif - -@SET_MAKE@ - -##################################################################### -.PHONY : all char-server_sql clean help - -all: char-server_sql - -char-server_sql: $(CHAR_SERVER_SQL_DEPENDS) - @CC@ @LDFLAGS@ -o ../../char-server_sql@EXEEXT@ $(CHAR_OBJ) $(COMMON_OBJ) $(COMMON_SQL_OBJ) $(MT19937AR_OBJ) @LIBS@ @MYSQL_LIBS@ - -clean: - rm -rf *.o obj_sql ../../char-server_sql@EXEEXT@ - -help: - @echo "possible targets are 'char-server_sql' 'all' 'clean' 'help'" - @echo "'char-server_sql' - char server (SQL version)" - @echo "'all' - builds all above targets" - @echo "'clean' - cleans builds and objects" - @echo "'help' - outputs this message" - -##################################################################### - -needs_mysql: - @echo "MySQL not found or disabled by the configure script" - @exit 1 - -obj_sql: - -mkdir obj_sql - -obj_sql/%.o: %.c $(CHAR_H) $(COMMON_H) $(COMMON_SQL_H) $(MT19937AR_H) - @CC@ @CFLAGS@ $(MT19937AR_INCLUDE) @MYSQL_CFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $< - -# missing object files -../common/obj_all/%.o: - @$(MAKE) -C ../common sql - -../common/obj_sql/%.o: - @$(MAKE) -C ../common sql - -MT19937AR_OBJ: - @$(MAKE) -C ../../3rdparty/mt19937ar diff --git a/src/char_sql/char.c b/src/char_sql/char.c deleted file mode 100644 index 35154d3cf..000000000 --- a/src/char_sql/char.c +++ /dev/null @@ -1,4636 +0,0 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder - -#include "../common/cbasetypes.h" -#include "../common/core.h" -#include "../common/db.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/timer.h" -#include "../common/utils.h" -#include "../common/version.h" -#include "inter.h" -#include "int_guild.h" -#include "int_homun.h" -#include "int_mercenary.h" -#include "int_party.h" -#include "int_storage.h" -#include "char.h" - -#include -#include -#include -#include -#include -#include -#include - -// private declarations -#define CHAR_CONF_NAME "conf/char_athena.conf" -#define LAN_CONF_NAME "conf/subnet_athena.conf" -#define SQL_CONF_NAME "conf/inter_athena.conf" - -char char_db[256] = "char"; -char scdata_db[256] = "sc_data"; -char cart_db[256] = "cart_inventory"; -char inventory_db[256] = "inventory"; -char charlog_db[256] = "charlog"; -char storage_db[256] = "storage"; -char interlog_db[256] = "interlog"; -char reg_db[256] = "global_reg_value"; -char skill_db[256] = "skill"; -char memo_db[256] = "memo"; -char guild_db[256] = "guild"; -char guild_alliance_db[256] = "guild_alliance"; -char guild_castle_db[256] = "guild_castle"; -char guild_expulsion_db[256] = "guild_expulsion"; -char guild_member_db[256] = "guild_member"; -char guild_position_db[256] = "guild_position"; -char guild_skill_db[256] = "guild_skill"; -char guild_storage_db[256] = "guild_storage"; -char party_db[256] = "party"; -char pet_db[256] = "pet"; -char mail_db[256] = "mail"; // MAIL SYSTEM -char auction_db[256] = "auction"; // Auctions System -char friend_db[256] = "friends"; -char hotkey_db[256] = "hotkey"; -char quest_db[256] = "quest"; - -// show loading/saving messages -#ifdef TXT_SQL_CONVERT -int save_log = 0; //Have the logs be off by default when converting -#else -int save_log = 1; -#endif - -//If your code editor is having problems syntax highlighting this file, uncomment this and RECOMMENT IT BEFORE COMPILING -//#undef TXT_SQL_CONVERT -#ifndef TXT_SQL_CONVERT -static DBMap* char_db_; // int char_id -> struct mmo_charstatus* - -char db_path[1024] = "db"; - -int db_use_sqldbs; - -struct mmo_map_server { - int fd; - uint32 ip; - uint16 port; - int users; - unsigned short map[MAX_MAP_PER_SERVER]; -} server[MAX_MAP_SERVERS]; - -int login_fd=-1, char_fd=-1; -char userid[24]; -char passwd[24]; -char server_name[20]; -char wisp_server_name[NAME_LENGTH] = "Server"; -char login_ip_str[128]; -uint32 login_ip = 0; -uint16 login_port = 6900; -char char_ip_str[128]; -uint32 char_ip = 0; -char bind_ip_str[128]; -uint32 bind_ip = INADDR_ANY; -uint16 char_port = 6121; -int char_maintenance = 0; -bool char_new = true; -int char_new_display = 0; - -bool name_ignoring_case = false; // Allow or not identical name for characters but with a different case by [Yor] -int char_name_option = 0; // Option to know which letters/symbols are authorised in the name of a character (0: all, 1: only those in char_name_letters, 2: all EXCEPT those in char_name_letters) by [Yor] -char unknown_char_name[NAME_LENGTH] = "Unknown"; // Name to use when the requested name cannot be determined -#define TRIM_CHARS "\255\xA0\032\t\x0A\x0D " //The following characters are trimmed regardless because they cause confusion and problems on the servers. [Skotlex] -char char_name_letters[1024] = ""; // list of letters/symbols allowed (or not) in a character name. by [Yor] - -int char_per_account = 0; //Maximum charas per account (default unlimited) [Sirius] -int char_del_level = 0; //From which level u can delete character [Lupus] -int char_del_delay = 86400; - -int log_char = 1; // loggin char or not [devil] -int log_inter = 1; // loggin inter or not [devil] - -// Advanced subnet check [LuzZza] -struct s_subnet { - uint32 mask; - uint32 char_ip; - uint32 map_ip; -} subnet[16]; -int subnet_count = 0; - -struct char_session_data { - bool auth; // whether the session is authed or not - int account_id, login_id1, login_id2, sex; - int found_char[MAX_CHARS]; // ids of chars on this account - char email[40]; // e-mail (default: a@a.com) by [Yor] - time_t expiration_time; // # of seconds 1/1/1970 (timestamp): Validity limit of the account (0 = unlimited) - int gmlevel; - uint32 version; - uint8 clienttype; - char new_name[NAME_LENGTH]; - char birthdate[10+1]; // YYYY-MM-DD -}; - -int max_connect_user = 0; -int gm_allow_level = 99; -int autosave_interval = DEFAULT_AUTOSAVE_INTERVAL; -int start_zeny = 0; -int start_weapon = 1201; -int start_armor = 2301; -int guild_exp_rate = 100; - -//Custom limits for the fame lists. [Skotlex] -int fame_list_size_chemist = MAX_FAME_LIST; -int fame_list_size_smith = MAX_FAME_LIST; -int fame_list_size_taekwon = MAX_FAME_LIST; - -// Char-server-side stored fame lists [DracoRPG] -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]; - -// check for exit signal -// 0 is saving complete -// other is char_id -unsigned int save_flag = 0; - -// Initial position (it's possible to set it in conf file) -struct point start_point = { 0, 53, 111 }; - -int console = 0; - -//----------------------------------------------------- -// Auth database -//----------------------------------------------------- -#define AUTH_TIMEOUT 30000 - -struct auth_node { - int account_id; - int char_id; - uint32 login_id1; - uint32 login_id2; - uint32 ip; - int sex; - time_t expiration_time; // # of seconds 1/1/1970 (timestamp): Validity limit of the account (0 = unlimited) - int gmlevel; - unsigned changing_mapservers : 1; -}; - -static DBMap* auth_db; // int account_id -> struct auth_node* - -//----------------------------------------------------- -// Online User Database -//----------------------------------------------------- - -struct online_char_data { - int account_id; - int char_id; - int fd; - int waiting_disconnect; - short server; // -2: unknown server, -1: not connected, 0+: id of server -}; - -static DBMap* online_char_db; // int account_id -> struct online_char_data* -static int chardb_waiting_disconnect(int tid, unsigned int tick, int id, intptr_t data); -int delete_char_sql(int char_id); - -static void* create_online_char_data(DBKey key, va_list args) -{ - struct online_char_data* character; - CREATE(character, struct online_char_data, 1); - character->account_id = key.i; - character->char_id = -1; - character->server = -1; - character->fd = -1; - character->waiting_disconnect = INVALID_TIMER; - return character; -} - -void set_char_charselect(int account_id) -{ - struct online_char_data* character; - - character = (struct online_char_data*)idb_ensure(online_char_db, account_id, create_online_char_data); - - if( character->server > -1 ) - if( server[character->server].users > 0 ) // Prevent this value from going negative. - server[character->server].users--; - - character->char_id = -1; - character->server = -1; - - if(character->waiting_disconnect != INVALID_TIMER) { - delete_timer(character->waiting_disconnect, chardb_waiting_disconnect); - character->waiting_disconnect = INVALID_TIMER; - } - - if (login_fd > 0 && !session[login_fd]->flag.eof) - { - WFIFOHEAD(login_fd,6); - WFIFOW(login_fd,0) = 0x272b; - WFIFOL(login_fd,2) = account_id; - WFIFOSET(login_fd,6); - } - -} - -void set_char_online(int map_id, int char_id, int account_id) -{ - struct online_char_data* character; - struct mmo_charstatus *cp; - - //Update DB - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `online`='1' WHERE `char_id`='%d' LIMIT 1", char_db, char_id) ) - Sql_ShowDebug(sql_handle); - - //Check to see for online conflicts - character = (struct online_char_data*)idb_ensure(online_char_db, account_id, create_online_char_data); - if( character->char_id != -1 && character->server > -1 && character->server != map_id ) - { - ShowNotice("set_char_online: Character %d:%d marked in map server %d, but map server %d claims to have (%d:%d) online!\n", - character->account_id, character->char_id, character->server, map_id, account_id, char_id); - mapif_disconnectplayer(server[character->server].fd, character->account_id, character->char_id, 2); - } - - //Update state data - character->char_id = char_id; - character->server = map_id; - - if( character->server > -1 ) - server[character->server].users++; - - //Get rid of disconnect timer - if(character->waiting_disconnect != INVALID_TIMER) { - delete_timer(character->waiting_disconnect, chardb_waiting_disconnect); - character->waiting_disconnect = INVALID_TIMER; - } - - //Set char online in guild cache. If char is in memory, use the guild id on it, otherwise seek it. - cp = (struct mmo_charstatus*)idb_get(char_db_,char_id); - inter_guild_CharOnline(char_id, cp?cp->guild_id:-1); - - //Notify login server - if (login_fd > 0 && !session[login_fd]->flag.eof) - { - WFIFOHEAD(login_fd,6); - WFIFOW(login_fd,0) = 0x272b; - WFIFOL(login_fd,2) = account_id; - WFIFOSET(login_fd,6); - } -} - -void set_char_offline(int char_id, int account_id) -{ - struct online_char_data* character; - - if ( char_id == -1 ) - { - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `online`='0' WHERE `account_id`='%d'", char_db, account_id) ) - Sql_ShowDebug(sql_handle); - } - else - { - struct mmo_charstatus* cp = (struct mmo_charstatus*)idb_get(char_db_,char_id); - inter_guild_CharOffline(char_id, cp?cp->guild_id:-1); - if (cp) - idb_remove(char_db_,char_id); - - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `online`='0' WHERE `char_id`='%d' LIMIT 1", char_db, char_id) ) - Sql_ShowDebug(sql_handle); - } - - if ((character = (struct online_char_data*)idb_get(online_char_db, account_id)) != NULL) - { //We don't free yet to avoid aCalloc/aFree spamming during char change. [Skotlex] - if( character->server > -1 ) - if( server[character->server].users > 0 ) // Prevent this value from going negative. - server[character->server].users--; - - if(character->waiting_disconnect != INVALID_TIMER){ - delete_timer(character->waiting_disconnect, chardb_waiting_disconnect); - character->waiting_disconnect = INVALID_TIMER; - } - - if(character->char_id == char_id) - { - character->char_id = -1; - character->server = -1; - } - - //FIXME? Why Kevin free'd the online information when the char was effectively in the map-server? - } - - //Remove char if 1- Set all offline, or 2- character is no longer connected to char-server. - if (login_fd > 0 && !session[login_fd]->flag.eof && (char_id == -1 || character == NULL || character->fd == -1)) - { - WFIFOHEAD(login_fd,6); - WFIFOW(login_fd,0) = 0x272c; - WFIFOL(login_fd,2) = account_id; - WFIFOSET(login_fd,6); - } -} - -static int char_db_setoffline(DBKey key, void* data, va_list ap) -{ - struct online_char_data* character = (struct online_char_data*)data; - int server = va_arg(ap, int); - if (server == -1) { - character->char_id = -1; - character->server = -1; - if(character->waiting_disconnect != INVALID_TIMER){ - delete_timer(character->waiting_disconnect, chardb_waiting_disconnect); - character->waiting_disconnect = INVALID_TIMER; - } - } else if (character->server == server) - character->server = -2; //In some map server that we aren't connected to. - return 0; -} - -static int char_db_kickoffline(DBKey key, void* data, va_list ap) -{ - struct online_char_data* character = (struct online_char_data*)data; - int server_id = va_arg(ap, int); - - if (server_id > -1 && character->server != server_id) - return 0; - - //Kick out any connected characters, and set them offline as appropiate. - if (character->server > -1) - mapif_disconnectplayer(server[character->server].fd, character->account_id, character->char_id, 1); - else if (character->waiting_disconnect == INVALID_TIMER) - set_char_offline(character->char_id, character->account_id); - else - return 0; // fail - - return 1; -} - -void set_all_offline(int id) -{ - if (id < 0) - ShowNotice("Sending all users offline.\n"); - else - ShowNotice("Sending users of map-server %d offline.\n",id); - online_char_db->foreach(online_char_db,char_db_kickoffline,id); - - if (id >= 0 || login_fd <= 0 || session[login_fd]->flag.eof) - return; - //Tell login-server to also mark all our characters as offline. - WFIFOHEAD(login_fd,2); - WFIFOW(login_fd,0) = 0x2737; - WFIFOSET(login_fd,2); -} - -void set_all_offline_sql(void) -{ - //Set all players to 'OFFLINE' - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `online` = '0'", char_db) ) - Sql_ShowDebug(sql_handle); - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `online` = '0'", guild_member_db) ) - Sql_ShowDebug(sql_handle); - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `connect_member` = '0'", guild_db) ) - Sql_ShowDebug(sql_handle); -} - -static void* create_charstatus(DBKey key, va_list args) -{ - struct mmo_charstatus *cp; - cp = (struct mmo_charstatus *) aCalloc(1,sizeof(struct mmo_charstatus)); - cp->char_id = key.i; - return cp; -} -#endif //TXT_SQL_CONVERT - -int mmo_char_tosql(int char_id, struct mmo_charstatus* p) -{ - int i = 0; - int count = 0; - int diff = 0; - char save_status[128]; //For displaying save information. [Skotlex] - struct mmo_charstatus *cp; - int errors = 0; //If there are any errors while saving, "cp" will not be updated at the end. - StringBuf buf; - - if (char_id!=p->char_id) return 0; - -#ifndef TXT_SQL_CONVERT - cp = (struct mmo_charstatus*)idb_ensure(char_db_, char_id, create_charstatus); -#else - cp = (struct mmo_charstatus*)aCalloc(1, sizeof(struct mmo_charstatus)); -#endif - - StringBuf_Init(&buf); - memset(save_status, 0, sizeof(save_status)); - - //map inventory data - if( memcmp(p->inventory, cp->inventory, sizeof(p->inventory)) ) - { - if (!memitemdata_to_sql(p->inventory, MAX_INVENTORY, p->char_id, TABLE_INVENTORY)) - strcat(save_status, " inventory"); - else - errors++; - } - - //map cart data - if( memcmp(p->cart, cp->cart, sizeof(p->cart)) ) - { - if (!memitemdata_to_sql(p->cart, MAX_CART, p->char_id, TABLE_CART)) - strcat(save_status, " cart"); - else - errors++; - } - - //map storage data - if( memcmp(p->storage.items, cp->storage.items, sizeof(p->storage.items)) ) - { - if (!memitemdata_to_sql(p->storage.items, MAX_STORAGE, p->account_id, TABLE_STORAGE)) - strcat(save_status, " storage"); - else - errors++; - } - -#ifdef TXT_SQL_CONVERT -{ //Insert the barebones to then update the rest. - char esc_name[NAME_LENGTH*2+1]; - - Sql_EscapeStringLen(sql_handle, esc_name, p->name, strnlen(p->name, NAME_LENGTH)); - if( SQL_ERROR == Sql_Query(sql_handle, "REPLACE INTO `%s` (`char_id`, `account_id`, `char_num`, `name`) VALUES ('%d', '%d', '%d', '%s')", - char_db, p->char_id, p->account_id, p->slot, esc_name) ) - { - Sql_ShowDebug(sql_handle); - errors++; - } else - strcat(save_status, " creation"); -} -#endif - - if ( - (p->base_exp != cp->base_exp) || (p->base_level != cp->base_level) || - (p->job_level != cp->job_level) || (p->job_exp != cp->job_exp) || - (p->zeny != cp->zeny) || - (p->last_point.map != cp->last_point.map) || - (p->last_point.x != cp->last_point.x) || (p->last_point.y != cp->last_point.y) || - (p->max_hp != cp->max_hp) || (p->hp != cp->hp) || - (p->max_sp != cp->max_sp) || (p->sp != cp->sp) || - (p->status_point != cp->status_point) || (p->skill_point != cp->skill_point) || - (p->str != cp->str) || (p->agi != cp->agi) || (p->vit != cp->vit) || - (p->int_ != cp->int_) || (p->dex != cp->dex) || (p->luk != cp->luk) || - (p->option != cp->option) || - (p->party_id != cp->party_id) || (p->guild_id != cp->guild_id) || - (p->pet_id != cp->pet_id) || (p->weapon != cp->weapon) || (p->hom_id != cp->hom_id) || - (p->shield != cp->shield) || (p->head_top != cp->head_top) || - (p->head_mid != cp->head_mid) || (p->head_bottom != cp->head_bottom) || (p->delete_date != cp->delete_date) || - (p->rename != cp->rename) || (p->robe != cp->robe) - ) - { //Save status - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `base_level`='%d', `job_level`='%d'," - "`base_exp`='%u', `job_exp`='%u', `zeny`='%d'," - "`max_hp`='%d',`hp`='%d',`max_sp`='%d',`sp`='%d',`status_point`='%d',`skill_point`='%d'," - "`str`='%d',`agi`='%d',`vit`='%d',`int`='%d',`dex`='%d',`luk`='%d'," - "`option`='%d',`party_id`='%d',`guild_id`='%d',`pet_id`='%d',`homun_id`='%d'," - "`weapon`='%d',`shield`='%d',`head_top`='%d',`head_mid`='%d',`head_bottom`='%d'," - "`last_map`='%s',`last_x`='%d',`last_y`='%d',`save_map`='%s',`save_x`='%d',`save_y`='%d', `rename`='%d'," - "`delete_date`='%lu',`robe`='%d'" - " WHERE `account_id`='%d' AND `char_id` = '%d'", - char_db, p->base_level, p->job_level, - p->base_exp, p->job_exp, p->zeny, - p->max_hp, p->hp, p->max_sp, p->sp, p->status_point, p->skill_point, - p->str, p->agi, p->vit, p->int_, p->dex, p->luk, - p->option, p->party_id, p->guild_id, p->pet_id, p->hom_id, - p->weapon, p->shield, p->head_top, p->head_mid, p->head_bottom, - mapindex_id2name(p->last_point.map), p->last_point.x, p->last_point.y, - mapindex_id2name(p->save_point.map), p->save_point.x, p->save_point.y, p->rename, - (unsigned long)p->delete_date, // FIXME: platform-dependent size - p->robe, - p->account_id, p->char_id) ) - { - Sql_ShowDebug(sql_handle); - errors++; - } else - strcat(save_status, " status"); - } - - //Values that will seldom change (to speed up saving) - if ( - (p->hair != cp->hair) || (p->hair_color != cp->hair_color) || (p->clothes_color != cp->clothes_color) || - (p->class_ != cp->class_) || - (p->partner_id != cp->partner_id) || (p->father != cp->father) || - (p->mother != cp->mother) || (p->child != cp->child) || - (p->karma != cp->karma) || (p->manner != cp->manner) || - (p->fame != cp->fame) - ) - { - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `class`='%d'," - "`hair`='%d',`hair_color`='%d',`clothes_color`='%d'," - "`partner_id`='%d', `father`='%d', `mother`='%d', `child`='%d'," - "`karma`='%d',`manner`='%d', `fame`='%d'" - " WHERE `account_id`='%d' AND `char_id` = '%d'", - char_db, p->class_, - p->hair, p->hair_color, p->clothes_color, - p->partner_id, p->father, p->mother, p->child, - p->karma, p->manner, p->fame, - p->account_id, p->char_id) ) - { - Sql_ShowDebug(sql_handle); - errors++; - } else - strcat(save_status, " status2"); - } - - /* Mercenary Owner */ - if( (p->mer_id != cp->mer_id) || - (p->arch_calls != cp->arch_calls) || (p->arch_faith != cp->arch_faith) || - (p->spear_calls != cp->spear_calls) || (p->spear_faith != cp->spear_faith) || - (p->sword_calls != cp->sword_calls) || (p->sword_faith != cp->sword_faith) ) - { - if (mercenary_owner_tosql(char_id, p)) - strcat(save_status, " mercenary"); - else - errors++; - } - - //memo points - if( memcmp(p->memo_point, cp->memo_point, sizeof(p->memo_point)) ) - { - char esc_mapname[NAME_LENGTH*2+1]; - - //`memo` (`memo_id`,`char_id`,`map`,`x`,`y`) - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", memo_db, p->char_id) ) - { - Sql_ShowDebug(sql_handle); - errors++; - } - - //insert here. - StringBuf_Clear(&buf); - StringBuf_Printf(&buf, "INSERT INTO `%s`(`char_id`,`map`,`x`,`y`) VALUES ", memo_db); - for( i = 0, count = 0; i < MAX_MEMOPOINTS; ++i ) - { - if( p->memo_point[i].map ) - { - if( count ) - StringBuf_AppendStr(&buf, ","); - Sql_EscapeString(sql_handle, esc_mapname, mapindex_id2name(p->memo_point[i].map)); - StringBuf_Printf(&buf, "('%d', '%s', '%d', '%d')", char_id, esc_mapname, p->memo_point[i].x, p->memo_point[i].y); - ++count; - } - } - if( count ) - { - if( SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf)) ) - { - Sql_ShowDebug(sql_handle); - errors++; - } - } - strcat(save_status, " memo"); - } - - //FIXME: is this neccessary? [ultramage] - for(i=0;iskill[i].lv != 0) && (p->skill[i].id == 0)) - p->skill[i].id = i; // Fix skill tree - - - //skills - if( memcmp(p->skill, cp->skill, sizeof(p->skill)) ) - { - //`skill` (`char_id`, `id`, `lv`) - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", skill_db, p->char_id) ) - { - Sql_ShowDebug(sql_handle); - errors++; - } - - StringBuf_Clear(&buf); - StringBuf_Printf(&buf, "INSERT INTO `%s`(`char_id`,`id`,`lv`) VALUES ", skill_db); - //insert here. - for( i = 0, count = 0; i < MAX_SKILL; ++i ) - { - if( p->skill[i].id != 0 && p->skill[i].flag != SKILL_FLAG_TEMPORARY ) - { - if( p->skill[i].flag == SKILL_FLAG_PERMANENT && p->skill[i].lv == 0 ) - continue; - if( p->skill[i].flag != SKILL_FLAG_PERMANENT && (p->skill[i].flag - SKILL_FLAG_REPLACED_LV_0) == 0 ) - continue; - if( count ) - StringBuf_AppendStr(&buf, ","); - StringBuf_Printf(&buf, "('%d','%d','%d')", char_id, p->skill[i].id, (p->skill[i].flag == SKILL_FLAG_PERMANENT ? p->skill[i].lv : p->skill[i].flag - SKILL_FLAG_REPLACED_LV_0)); - ++count; - } - } - if( count ) - { - if( SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf)) ) - { - Sql_ShowDebug(sql_handle); - errors++; - } - } - - strcat(save_status, " skills"); - } - - diff = 0; - for(i = 0; i < MAX_FRIENDS; i++){ - if(p->friends[i].char_id != cp->friends[i].char_id || - p->friends[i].account_id != cp->friends[i].account_id){ - diff = 1; - break; - } - } - - if(diff == 1) - { //Save friends - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", friend_db, char_id) ) - { - Sql_ShowDebug(sql_handle); - errors++; - } - - StringBuf_Clear(&buf); - StringBuf_Printf(&buf, "INSERT INTO `%s` (`char_id`, `friend_account`, `friend_id`) VALUES ", friend_db); - for( i = 0, count = 0; i < MAX_FRIENDS; ++i ) - { - if( p->friends[i].char_id > 0 ) - { - if( count ) - StringBuf_AppendStr(&buf, ","); - StringBuf_Printf(&buf, "('%d','%d','%d')", char_id, p->friends[i].account_id, p->friends[i].char_id); - count++; - } - } - if( count ) - { - if( SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf)) ) - { - Sql_ShowDebug(sql_handle); - errors++; - } - } - strcat(save_status, " friends"); - } - -#ifdef HOTKEY_SAVING - // hotkeys - StringBuf_Clear(&buf); - StringBuf_Printf(&buf, "REPLACE INTO `%s` (`char_id`, `hotkey`, `type`, `itemskill_id`, `skill_lvl`) VALUES ", hotkey_db); - diff = 0; - for(i = 0; i < ARRAYLENGTH(p->hotkeys); i++){ - if(memcmp(&p->hotkeys[i], &cp->hotkeys[i], sizeof(struct hotkey))) - { - if( diff ) - StringBuf_AppendStr(&buf, ",");// not the first hotkey - StringBuf_Printf(&buf, "('%d','%u','%u','%u','%u')", char_id, (unsigned int)i, (unsigned int)p->hotkeys[i].type, p->hotkeys[i].id , (unsigned int)p->hotkeys[i].lv); - diff = 1; - } - } - if(diff) { - if( SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf)) ) - { - Sql_ShowDebug(sql_handle); - errors++; - } else - strcat(save_status, " hotkeys"); - } -#endif - StringBuf_Destroy(&buf); - if (save_status[0]!='\0' && save_log) - ShowInfo("Saved char %d - %s:%s.\n", char_id, p->name, save_status); -#ifndef TXT_SQL_CONVERT - if (!errors) - memcpy(cp, p, sizeof(struct mmo_charstatus)); -#else - aFree(cp); -#endif - return 0; -} - -/// Saves an array of 'item' entries into the specified table. -int memitemdata_to_sql(const struct item items[], int max, int id, int tableswitch) -{ - StringBuf buf; - SqlStmt* stmt; - int i; - int j; - const char* tablename; - const char* selectoption; - struct item item; // temp storage variable - bool* flag; // bit array for inventory matching - bool found; - int errors = 0; - - switch (tableswitch) { - case TABLE_INVENTORY: tablename = inventory_db; selectoption = "char_id"; break; - case TABLE_CART: tablename = cart_db; selectoption = "char_id"; break; - case TABLE_STORAGE: tablename = storage_db; selectoption = "account_id"; break; - case TABLE_GUILD_STORAGE: tablename = guild_storage_db; selectoption = "guild_id"; break; - default: - ShowError("Invalid table name!\n"); - return 1; - } - - - // The following code compares inventory with current database values - // and performs modification/deletion/insertion only on relevant rows. - // This approach is more complicated than a trivial delete&insert, but - // it significantly reduces cpu load on the database server. - - StringBuf_Init(&buf); - StringBuf_AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`"); - for( j = 0; j < MAX_SLOTS; ++j ) - StringBuf_Printf(&buf, ", `card%d`", j); - StringBuf_Printf(&buf, " FROM `%s` WHERE `%s`='%d'", tablename, selectoption, id); - - stmt = SqlStmt_Malloc(sql_handle); - if( SQL_ERROR == SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf)) - || SQL_ERROR == SqlStmt_Execute(stmt) ) - { - SqlStmt_ShowDebug(stmt); - SqlStmt_Free(stmt); - StringBuf_Destroy(&buf); - return 1; - } - - SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &item.id, 0, NULL, NULL); - SqlStmt_BindColumn(stmt, 1, SQLDT_SHORT, &item.nameid, 0, NULL, NULL); - SqlStmt_BindColumn(stmt, 2, SQLDT_SHORT, &item.amount, 0, NULL, NULL); - SqlStmt_BindColumn(stmt, 3, SQLDT_USHORT, &item.equip, 0, NULL, NULL); - SqlStmt_BindColumn(stmt, 4, SQLDT_CHAR, &item.identify, 0, NULL, NULL); - SqlStmt_BindColumn(stmt, 5, SQLDT_CHAR, &item.refine, 0, NULL, NULL); - SqlStmt_BindColumn(stmt, 6, SQLDT_CHAR, &item.attribute, 0, NULL, NULL); - SqlStmt_BindColumn(stmt, 7, SQLDT_UINT, &item.expire_time, 0, NULL, NULL); - for( j = 0; j < MAX_SLOTS; ++j ) - SqlStmt_BindColumn(stmt, 8+j, SQLDT_SHORT, &item.card[j], 0, NULL, NULL); - - // bit array indicating which inventory items have already been matched - flag = (bool*) aCallocA(max, sizeof(bool)); - - while( SQL_SUCCESS == SqlStmt_NextRow(stmt) ) - { - found = false; - // search for the presence of the item in the char's inventory - for( i = 0; i < max; ++i ) - { - // skip empty and already matched entries - if( items[i].nameid == 0 || flag[i] ) - continue; - - if( items[i].nameid == item.nameid - && items[i].card[0] == item.card[0] - && items[i].card[2] == item.card[2] - && items[i].card[3] == item.card[3] - ) { //They are the same item. - ARR_FIND( 0, MAX_SLOTS, j, items[i].card[j] != item.card[j] ); - if( j == MAX_SLOTS && - items[i].amount == item.amount && - items[i].equip == item.equip && - items[i].identify == item.identify && - items[i].refine == item.refine && - items[i].attribute == item.attribute && - items[i].expire_time == item.expire_time ) - ; //Do nothing. - else - { - // update all fields. - StringBuf_Clear(&buf); - StringBuf_Printf(&buf, "UPDATE `%s` SET `amount`='%d', `equip`='%d', `identify`='%d', `refine`='%d',`attribute`='%d', `expire_time`='%u'", - tablename, items[i].amount, items[i].equip, items[i].identify, items[i].refine, items[i].attribute, items[i].expire_time); - for( j = 0; j < MAX_SLOTS; ++j ) - StringBuf_Printf(&buf, ", `card%d`=%d", j, items[i].card[j]); - StringBuf_Printf(&buf, " WHERE `id`='%d' LIMIT 1", item.id); - - if( SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf)) ) - { - Sql_ShowDebug(sql_handle); - errors++; - } - } - - found = flag[i] = true; //Item dealt with, - break; //skip to next item in the db. - } - } - if( !found ) - {// Item not present in inventory, remove it. - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE from `%s` where `id`='%d' LIMIT 1", tablename, item.id) ) - { - Sql_ShowDebug(sql_handle); - errors++; - } - } - } - SqlStmt_Free(stmt); - - StringBuf_Clear(&buf); - StringBuf_Printf(&buf, "INSERT INTO `%s`(`%s`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`", tablename, selectoption); - for( j = 0; j < MAX_SLOTS; ++j ) - StringBuf_Printf(&buf, ", `card%d`", j); - StringBuf_AppendStr(&buf, ") VALUES "); - - found = false; - // insert non-matched items into the db as new items - for( i = 0; i < max; ++i ) - { - // skip empty and already matched entries - if( items[i].nameid == 0 || flag[i] ) - continue; - - if( found ) - StringBuf_AppendStr(&buf, ","); - else - found = true; - - StringBuf_Printf(&buf, "('%d', '%d', '%d', '%d', '%d', '%d', '%d', '%u'", - id, items[i].nameid, items[i].amount, items[i].equip, items[i].identify, items[i].refine, items[i].attribute, items[i].expire_time); - for( j = 0; j < MAX_SLOTS; ++j ) - StringBuf_Printf(&buf, ", '%d'", items[i].card[j]); - StringBuf_AppendStr(&buf, ")"); - } - - if( found && SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf)) ) - { - Sql_ShowDebug(sql_handle); - errors++; - } - - StringBuf_Destroy(&buf); - aFree(flag); - - return errors; -} - -int mmo_char_tobuf(uint8* buf, struct mmo_charstatus* p); - -#ifndef TXT_SQL_CONVERT -//===================================================================================================== -// Loads the basic character rooster for the given account. Returns total buffer used. -int mmo_chars_fromsql(struct char_session_data* sd, uint8* buf) -{ - SqlStmt* stmt; - struct mmo_charstatus p; - int j = 0, i; - char last_map[MAP_NAME_LENGTH_EXT]; - - stmt = SqlStmt_Malloc(sql_handle); - if( stmt == NULL ) - { - SqlStmt_ShowDebug(stmt); - return 0; - } - memset(&p, 0, sizeof(p)); - - // read char data - if( SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT " - "`char_id`,`char_num`,`name`,`class`,`base_level`,`job_level`,`base_exp`,`job_exp`,`zeny`," - "`str`,`agi`,`vit`,`int`,`dex`,`luk`,`max_hp`,`hp`,`max_sp`,`sp`," - "`status_point`,`skill_point`,`option`,`karma`,`manner`,`hair`,`hair_color`," - "`clothes_color`,`weapon`,`shield`,`head_top`,`head_mid`,`head_bottom`,`last_map`,`rename`,`delete_date`," - "`robe`" - " FROM `%s` WHERE `account_id`='%d' AND `char_num` < '%d'", char_db, sd->account_id, MAX_CHARS) - || SQL_ERROR == SqlStmt_Execute(stmt) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &p.char_id, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_UCHAR, &p.slot, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_STRING, &p.name, sizeof(p.name), NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 3, SQLDT_SHORT, &p.class_, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 4, SQLDT_UINT, &p.base_level, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 5, SQLDT_UINT, &p.job_level, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 6, SQLDT_UINT, &p.base_exp, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 7, SQLDT_UINT, &p.job_exp, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 8, SQLDT_INT, &p.zeny, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 9, SQLDT_SHORT, &p.str, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 10, SQLDT_SHORT, &p.agi, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 11, SQLDT_SHORT, &p.vit, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 12, SQLDT_SHORT, &p.int_, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 13, SQLDT_SHORT, &p.dex, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 14, SQLDT_SHORT, &p.luk, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 15, SQLDT_INT, &p.max_hp, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 16, SQLDT_INT, &p.hp, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 17, SQLDT_INT, &p.max_sp, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 18, SQLDT_INT, &p.sp, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 19, SQLDT_UINT, &p.status_point, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 20, SQLDT_UINT, &p.skill_point, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 21, SQLDT_UINT, &p.option, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 22, SQLDT_UCHAR, &p.karma, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 23, SQLDT_SHORT, &p.manner, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 24, SQLDT_SHORT, &p.hair, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 25, SQLDT_SHORT, &p.hair_color, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 26, SQLDT_SHORT, &p.clothes_color, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 27, SQLDT_SHORT, &p.weapon, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 28, SQLDT_SHORT, &p.shield, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 29, SQLDT_SHORT, &p.head_top, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 30, SQLDT_SHORT, &p.head_mid, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 31, SQLDT_SHORT, &p.head_bottom, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 32, SQLDT_STRING, &last_map, sizeof(last_map), NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 33, SQLDT_SHORT, &p.rename, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 34, SQLDT_UINT32, &p.delete_date, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 35, SQLDT_SHORT, &p.robe, 0, NULL, NULL) - ) - { - SqlStmt_ShowDebug(stmt); - SqlStmt_Free(stmt); - return 0; - } - for( i = 0; i < MAX_CHARS && SQL_SUCCESS == SqlStmt_NextRow(stmt); i++ ) - { - if( p.delete_date && p.delete_date < time(NULL) ) { - delete_char_sql(p.char_id); - i--; - continue; - } - p.last_point.map = mapindex_name2id(last_map); - sd->found_char[i] = p.char_id; - j += mmo_char_tobuf(WBUFP(buf, j), &p); - } - for( ; i < MAX_CHARS; i++ ) - sd->found_char[i] = -1; - - memset(sd->new_name,0,sizeof(sd->new_name)); - - SqlStmt_Free(stmt); - return j; -} - -//===================================================================================================== -int mmo_char_fromsql(int char_id, struct mmo_charstatus* p, bool load_everything) -{ - int i,j; - char t_msg[128] = ""; - struct mmo_charstatus* cp; - StringBuf buf; - SqlStmt* stmt; - char last_map[MAP_NAME_LENGTH_EXT]; - char save_map[MAP_NAME_LENGTH_EXT]; - char point_map[MAP_NAME_LENGTH_EXT]; - struct point tmp_point; - struct item tmp_item; - struct s_skill tmp_skill; - struct s_friend tmp_friend; -#ifdef HOTKEY_SAVING - struct hotkey tmp_hotkey; - int hotkey_num; -#endif - - memset(p, 0, sizeof(struct mmo_charstatus)); - - if (save_log) ShowInfo("Char load request (%d)\n", char_id); - - stmt = SqlStmt_Malloc(sql_handle); - if( stmt == NULL ) - { - SqlStmt_ShowDebug(stmt); - return 0; - } - - // read char data - if( SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT " - "`char_id`,`account_id`,`char_num`,`name`,`class`,`base_level`,`job_level`,`base_exp`,`job_exp`,`zeny`," - "`str`,`agi`,`vit`,`int`,`dex`,`luk`,`max_hp`,`hp`,`max_sp`,`sp`," - "`status_point`,`skill_point`,`option`,`karma`,`manner`,`party_id`,`guild_id`,`pet_id`,`homun_id`,`hair`," - "`hair_color`,`clothes_color`,`weapon`,`shield`,`head_top`,`head_mid`,`head_bottom`,`last_map`,`last_x`,`last_y`," - "`save_map`,`save_x`,`save_y`,`partner_id`,`father`,`mother`,`child`,`fame`,`rename`,`delete_date`,`robe`" - " FROM `%s` WHERE `char_id`=? LIMIT 1", char_db) - || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0) - || SQL_ERROR == SqlStmt_Execute(stmt) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &p->char_id, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_INT, &p->account_id, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_UCHAR, &p->slot, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 3, SQLDT_STRING, &p->name, sizeof(p->name), NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 4, SQLDT_SHORT, &p->class_, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 5, SQLDT_UINT, &p->base_level, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 6, SQLDT_UINT, &p->job_level, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 7, SQLDT_UINT, &p->base_exp, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 8, SQLDT_UINT, &p->job_exp, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 9, SQLDT_INT, &p->zeny, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 10, SQLDT_SHORT, &p->str, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 11, SQLDT_SHORT, &p->agi, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 12, SQLDT_SHORT, &p->vit, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 13, SQLDT_SHORT, &p->int_, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 14, SQLDT_SHORT, &p->dex, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 15, SQLDT_SHORT, &p->luk, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 16, SQLDT_INT, &p->max_hp, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 17, SQLDT_INT, &p->hp, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 18, SQLDT_INT, &p->max_sp, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 19, SQLDT_INT, &p->sp, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 20, SQLDT_UINT, &p->status_point, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 21, SQLDT_UINT, &p->skill_point, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 22, SQLDT_UINT, &p->option, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 23, SQLDT_UCHAR, &p->karma, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 24, SQLDT_SHORT, &p->manner, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 25, SQLDT_INT, &p->party_id, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 26, SQLDT_INT, &p->guild_id, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 27, SQLDT_INT, &p->pet_id, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 28, SQLDT_INT, &p->hom_id, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 29, SQLDT_SHORT, &p->hair, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 30, SQLDT_SHORT, &p->hair_color, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 31, SQLDT_SHORT, &p->clothes_color, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 32, SQLDT_SHORT, &p->weapon, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 33, SQLDT_SHORT, &p->shield, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 34, SQLDT_SHORT, &p->head_top, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 35, SQLDT_SHORT, &p->head_mid, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 36, SQLDT_SHORT, &p->head_bottom, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 37, SQLDT_STRING, &last_map, sizeof(last_map), NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 38, SQLDT_SHORT, &p->last_point.x, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 39, SQLDT_SHORT, &p->last_point.y, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 40, SQLDT_STRING, &save_map, sizeof(save_map), NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 41, SQLDT_SHORT, &p->save_point.x, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 42, SQLDT_SHORT, &p->save_point.y, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 43, SQLDT_INT, &p->partner_id, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 44, SQLDT_INT, &p->father, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 45, SQLDT_INT, &p->mother, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 46, SQLDT_INT, &p->child, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 47, SQLDT_INT, &p->fame, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 48, SQLDT_SHORT, &p->rename, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 49, SQLDT_UINT32, &p->delete_date, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 50, SQLDT_SHORT, &p->robe, 0, NULL, NULL) - ) - { - SqlStmt_ShowDebug(stmt); - SqlStmt_Free(stmt); - return 0; - } - if( SQL_ERROR == SqlStmt_NextRow(stmt) ) - { - ShowError("Requested non-existant character id: %d!\n", char_id); - SqlStmt_Free(stmt); - return 0; - } - p->last_point.map = mapindex_name2id(last_map); - p->save_point.map = mapindex_name2id(save_map); - - strcat(t_msg, " status"); - - if (!load_everything) // For quick selection of data when displaying the char menu - { - SqlStmt_Free(stmt); - return 1; - } - - //read memo data - //`memo` (`memo_id`,`char_id`,`map`,`x`,`y`) - if( SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT `map`,`x`,`y` FROM `%s` WHERE `char_id`=? ORDER by `memo_id` LIMIT %d", memo_db, MAX_MEMOPOINTS) - || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0) - || SQL_ERROR == SqlStmt_Execute(stmt) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_STRING, &point_map, sizeof(point_map), NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_SHORT, &tmp_point.x, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_SHORT, &tmp_point.y, 0, NULL, NULL) ) - SqlStmt_ShowDebug(stmt); - - for( i = 0; i < MAX_MEMOPOINTS && SQL_SUCCESS == SqlStmt_NextRow(stmt); ++i ) - { - tmp_point.map = mapindex_name2id(point_map); - memcpy(&p->memo_point[i], &tmp_point, sizeof(tmp_point)); - } - strcat(t_msg, " memo"); - - //read inventory - //`inventory` (`id`,`char_id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `card0`, `card1`, `card2`, `card3`) - StringBuf_Init(&buf); - StringBuf_AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`"); - for( i = 0; i < MAX_SLOTS; ++i ) - StringBuf_Printf(&buf, ", `card%d`", i); - StringBuf_Printf(&buf, " FROM `%s` WHERE `char_id`=? LIMIT %d", inventory_db, MAX_INVENTORY); - - if( SQL_ERROR == SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf)) - || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0) - || SQL_ERROR == SqlStmt_Execute(stmt) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &tmp_item.id, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_SHORT, &tmp_item.nameid, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_SHORT, &tmp_item.amount, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 3, SQLDT_USHORT, &tmp_item.equip, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 4, SQLDT_CHAR, &tmp_item.identify, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 5, SQLDT_CHAR, &tmp_item.refine, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 6, SQLDT_CHAR, &tmp_item.attribute, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 7, SQLDT_UINT, &tmp_item.expire_time, 0, NULL, NULL) ) - SqlStmt_ShowDebug(stmt); - for( i = 0; i < MAX_SLOTS; ++i ) - if( SQL_ERROR == SqlStmt_BindColumn(stmt, 8+i, SQLDT_SHORT, &tmp_item.card[i], 0, NULL, NULL) ) - SqlStmt_ShowDebug(stmt); - - for( i = 0; i < MAX_INVENTORY && SQL_SUCCESS == SqlStmt_NextRow(stmt); ++i ) - memcpy(&p->inventory[i], &tmp_item, sizeof(tmp_item)); - - strcat(t_msg, " inventory"); - - //read cart - //`cart_inventory` (`id`,`char_id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `card0`, `card1`, `card2`, `card3`) - StringBuf_Clear(&buf); - StringBuf_AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`"); - for( j = 0; j < MAX_SLOTS; ++j ) - StringBuf_Printf(&buf, ", `card%d`", j); - StringBuf_Printf(&buf, " FROM `%s` WHERE `char_id`=? LIMIT %d", cart_db, MAX_CART); - - if( SQL_ERROR == SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf)) - || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0) - || SQL_ERROR == SqlStmt_Execute(stmt) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &tmp_item.id, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_SHORT, &tmp_item.nameid, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_SHORT, &tmp_item.amount, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 3, SQLDT_USHORT, &tmp_item.equip, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 4, SQLDT_CHAR, &tmp_item.identify, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 5, SQLDT_CHAR, &tmp_item.refine, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 6, SQLDT_CHAR, &tmp_item.attribute, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 7, SQLDT_UINT, &tmp_item.expire_time, 0, NULL, NULL) ) - SqlStmt_ShowDebug(stmt); - for( i = 0; i < MAX_SLOTS; ++i ) - if( SQL_ERROR == SqlStmt_BindColumn(stmt, 8+i, SQLDT_SHORT, &tmp_item.card[i], 0, NULL, NULL) ) - SqlStmt_ShowDebug(stmt); - - for( i = 0; i < MAX_CART && SQL_SUCCESS == SqlStmt_NextRow(stmt); ++i ) - memcpy(&p->cart[i], &tmp_item, sizeof(tmp_item)); - strcat(t_msg, " cart"); - - //read storage - storage_fromsql(p->account_id, &p->storage); - strcat(t_msg, " storage"); - - //read skill - //`skill` (`char_id`, `id`, `lv`) - if( SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT `id`, `lv` FROM `%s` WHERE `char_id`=? LIMIT %d", skill_db, MAX_SKILL) - || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0) - || SQL_ERROR == SqlStmt_Execute(stmt) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_USHORT, &tmp_skill.id, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_USHORT, &tmp_skill.lv, 0, NULL, NULL) ) - SqlStmt_ShowDebug(stmt); - tmp_skill.flag = SKILL_FLAG_PERMANENT; - - for( i = 0; i < MAX_SKILL && SQL_SUCCESS == SqlStmt_NextRow(stmt); ++i ) - { - if( tmp_skill.id < ARRAYLENGTH(p->skill) ) - memcpy(&p->skill[tmp_skill.id], &tmp_skill, sizeof(tmp_skill)); - else - ShowWarning("mmo_char_fromsql: ignoring invalid skill (id=%u,lv=%u) of character %s (AID=%d,CID=%d)\n", tmp_skill.id, tmp_skill.lv, p->name, p->account_id, p->char_id); - } - strcat(t_msg, " skills"); - - //read friends - //`friends` (`char_id`, `friend_account`, `friend_id`) - if( SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT c.`account_id`, c.`char_id`, c.`name` FROM `%s` c LEFT JOIN `%s` f ON f.`friend_account` = c.`account_id` AND f.`friend_id` = c.`char_id` WHERE f.`char_id`=? LIMIT %d", char_db, friend_db, MAX_FRIENDS) - || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0) - || SQL_ERROR == SqlStmt_Execute(stmt) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &tmp_friend.account_id, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_INT, &tmp_friend.char_id, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_STRING, &tmp_friend.name, sizeof(tmp_friend.name), NULL, NULL) ) - SqlStmt_ShowDebug(stmt); - - for( i = 0; i < MAX_FRIENDS && SQL_SUCCESS == SqlStmt_NextRow(stmt); ++i ) - memcpy(&p->friends[i], &tmp_friend, sizeof(tmp_friend)); - strcat(t_msg, " friends"); - -#ifdef HOTKEY_SAVING - //read hotkeys - //`hotkey` (`char_id`, `hotkey`, `type`, `itemskill_id`, `skill_lvl` - if( SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT `hotkey`, `type`, `itemskill_id`, `skill_lvl` FROM `%s` WHERE `char_id`=?", hotkey_db) - || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0) - || SQL_ERROR == SqlStmt_Execute(stmt) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &hotkey_num, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_UCHAR, &tmp_hotkey.type, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_UINT, &tmp_hotkey.id, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 3, SQLDT_USHORT, &tmp_hotkey.lv, 0, NULL, NULL) ) - SqlStmt_ShowDebug(stmt); - - while( SQL_SUCCESS == SqlStmt_NextRow(stmt) ) - { - if( hotkey_num >= 0 && hotkey_num < MAX_HOTKEYS ) - memcpy(&p->hotkeys[hotkey_num], &tmp_hotkey, sizeof(tmp_hotkey)); - else - ShowWarning("mmo_char_fromsql: ignoring invalid hotkey (hotkey=%d,type=%u,id=%u,lv=%u) of character %s (AID=%d,CID=%d)\n", hotkey_num, tmp_hotkey.type, tmp_hotkey.id, tmp_hotkey.lv, p->name, p->account_id, p->char_id); - } - strcat(t_msg, " hotkeys"); -#endif - - /* Mercenary Owner DataBase */ - mercenary_owner_fromsql(char_id, p); - strcat(t_msg, " mercenary"); - - - if (save_log) ShowInfo("Loaded char (%d - %s): %s\n", char_id, p->name, t_msg); //ok. all data load successfuly! - SqlStmt_Free(stmt); - StringBuf_Destroy(&buf); - - cp = (struct mmo_charstatus*)idb_ensure(char_db_, char_id, create_charstatus); - memcpy(cp, p, sizeof(struct mmo_charstatus)); - return 1; -} - -//========================================================================================================== -int mmo_char_sql_init(void) -{ - ShowInfo("Begin Initializing.......\n"); - char_db_= idb_alloc(DB_OPT_RELEASE_DATA); - - if(char_per_account == 0){ - ShowStatus("Chars per Account: 'Unlimited'.......\n"); - }else{ - ShowStatus("Chars per Account: '%d'.......\n", char_per_account); - } - - //the 'set offline' part is now in check_login_conn ... - //if the server connects to loginserver - //it will dc all off players - //and send the loginserver the new state.... - - // Force all users offline in sql when starting char-server - // (useful when servers crashs and don't clean the database) - set_all_offline_sql(); - - ShowInfo("Finished initilizing.......\n"); - - return 0; -} - -//----------------------------------- -// Function to change chararcter's names -//----------------------------------- -int rename_char_sql(struct char_session_data *sd, int char_id) -{ - struct mmo_charstatus char_dat; - char esc_name[NAME_LENGTH*2+1]; - - if( sd->new_name[0] == 0 ) // Not ready for rename - return 2; - - if( !mmo_char_fromsql(char_id, &char_dat, false) ) // Only the short data is needed. - return 2; - - if( char_dat.rename == 0 ) - return 1; - - Sql_EscapeStringLen(sql_handle, esc_name, sd->new_name, strnlen(sd->new_name, NAME_LENGTH)); - - // check if the char exist - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT 1 FROM `%s` WHERE `name` LIKE '%s' LIMIT 1", char_db, esc_name) ) - { - Sql_ShowDebug(sql_handle); - return 4; - } - - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `name` = '%s', `rename` = '%d' WHERE `char_id` = '%d'", char_db, esc_name, --char_dat.rename, char_id) ) - { - Sql_ShowDebug(sql_handle); - return 3; - } - - // Change character's name into guild_db. - if( char_dat.guild_id ) - inter_guild_charname_changed(char_dat.guild_id, sd->account_id, char_id, sd->new_name); - - safestrncpy(char_dat.name, sd->new_name, NAME_LENGTH); - memset(sd->new_name,0,sizeof(sd->new_name)); - - // log change - if( log_char ) - { - if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`time`, `char_msg`,`account_id`,`char_num`,`name`,`str`,`agi`,`vit`,`int`,`dex`,`luk`,`hair`,`hair_color`)" - "VALUES (NOW(), '%s', '%d', '%d', '%s', '0', '0', '0', '0', '0', '0', '0', '0')", - charlog_db, "change char name", sd->account_id, char_dat.slot, esc_name) ) - Sql_ShowDebug(sql_handle); - } - - return 0; -} - -int check_char_name(char * name, char * esc_name) -{ - int i; - - // check length of character name - if( name[0] == '\0' ) - return -2; // empty character name - /** - * The client does not allow you to create names with less than 4 characters, however, - * the use of WPE can bypass this, and this fixes the exploit. - **/ - if( strlen( name ) < 4 ) - return -2; - // check content of character name - if( remove_control_chars(name) ) - return -2; // control chars in name - - // check for reserved names - if( strcmpi(name, main_chat_nick) == 0 || strcmpi(name, wisp_server_name) == 0 ) - return -1; // nick reserved for internal server messages - - // Check Authorised letters/symbols in the name of the character - if( char_name_option == 1 ) - { // only letters/symbols in char_name_letters are authorised - for( i = 0; i < NAME_LENGTH && name[i]; i++ ) - if( strchr(char_name_letters, name[i]) == NULL ) - return -2; - } - else if( char_name_option == 2 ) - { // letters/symbols in char_name_letters are forbidden - for( i = 0; i < NAME_LENGTH && name[i]; i++ ) - if( strchr(char_name_letters, name[i]) != NULL ) - return -2; - } - if( name_ignoring_case ) { - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT 1 FROM `%s` WHERE BINARY `name` = '%s' LIMIT 1", char_db, esc_name) ) { - Sql_ShowDebug(sql_handle); - return -2; - } - } else { - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT 1 FROM `%s` WHERE `name` = '%s' LIMIT 1", char_db, esc_name) ) { - Sql_ShowDebug(sql_handle); - return -2; - } - } - if( Sql_NumRows(sql_handle) > 0 ) - return -1; // name already exists - - return 0; -} - -//----------------------------------- -// Function to create a new character -//----------------------------------- -int make_new_char_sql(struct char_session_data* sd, char* name_, int str, int agi, int vit, int int_, int dex, int luk, int slot, int hair_color, int hair_style) -{ - char name[NAME_LENGTH]; - char esc_name[NAME_LENGTH*2+1]; - int char_id, flag; - - safestrncpy(name, name_, NAME_LENGTH); - normalize_name(name,TRIM_CHARS); - Sql_EscapeStringLen(sql_handle, esc_name, name, strnlen(name, NAME_LENGTH)); - - flag = check_char_name(name,esc_name); - if( flag < 0 ) - return flag; - - //check other inputs - if((slot >= MAX_CHARS) // slots - || (str + agi + vit + int_ + dex + luk != 6*5 ) // stats - || (str < 1 || str > 9 || agi < 1 || agi > 9 || vit < 1 || vit > 9 || int_ < 1 || int_ > 9 || dex < 1 || dex > 9 || luk < 1 || luk > 9) // individual stat values - || (str + int_ != 10 || agi + luk != 10 || vit + dex != 10) ) // pairs - return -2; // invalid input - - // check the number of already existing chars in this account - if( char_per_account != 0 ) { - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT 1 FROM `%s` WHERE `account_id` = '%d'", char_db, sd->account_id) ) - Sql_ShowDebug(sql_handle); - if( Sql_NumRows(sql_handle) >= char_per_account ) - return -2; // character account limit exceeded - } - - // check char slot - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT 1 FROM `%s` WHERE `account_id` = '%d' AND `char_num` = '%d' LIMIT 1", char_db, sd->account_id, slot) ) - Sql_ShowDebug(sql_handle); - if( Sql_NumRows(sql_handle) > 0 ) - return -2; // slot already in use - - // validation success, log result - if (log_char) { - if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`time`, `char_msg`,`account_id`,`char_num`,`name`,`str`,`agi`,`vit`,`int`,`dex`,`luk`,`hair`,`hair_color`)" - "VALUES (NOW(), '%s', '%d', '%d', '%s', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d')", - charlog_db, "make new char", sd->account_id, slot, esc_name, str, agi, vit, int_, dex, luk, hair_style, hair_color) ) - Sql_ShowDebug(sql_handle); - } - - //Insert the new char entry to the database - if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`account_id`, `char_num`, `name`, `zeny`, `str`, `agi`, `vit`, `int`, `dex`, `luk`, `max_hp`, `hp`," - "`max_sp`, `sp`, `hair`, `hair_color`, `last_map`, `last_x`, `last_y`, `save_map`, `save_x`, `save_y`) VALUES (" - "'%d', '%d', '%s', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d','%d', '%d','%d', '%d', '%s', '%d', '%d', '%s', '%d', '%d')", - char_db, sd->account_id , slot, esc_name, start_zeny, str, agi, vit, int_, dex, luk, - (40 * (100 + vit)/100) , (40 * (100 + vit)/100 ), (11 * (100 + int_)/100), (11 * (100 + int_)/100), hair_style, hair_color, - mapindex_id2name(start_point.map), start_point.x, start_point.y, mapindex_id2name(start_point.map), start_point.x, start_point.y) ) - { - Sql_ShowDebug(sql_handle); - return -2; //No, stop the procedure! - } - //Retrieve the newly auto-generated char id - char_id = (int)Sql_LastInsertId(sql_handle); - //Give the char the default items - if (start_weapon > 0) { //add Start Weapon (Knife?) - if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`char_id`,`nameid`, `amount`, `identify`) VALUES ('%d', '%d', '%d', '%d')", inventory_db, char_id, start_weapon, 1, 1) ) - Sql_ShowDebug(sql_handle); - } - if (start_armor > 0) { //Add default armor (cotton shirt?) - if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`char_id`,`nameid`, `amount`, `identify`) VALUES ('%d', '%d', '%d', '%d')", inventory_db, char_id, start_armor, 1, 1) ) - Sql_ShowDebug(sql_handle); - } - - ShowInfo("Created char: account: %d, char: %d, slot: %d, name: %s\n", sd->account_id, char_id, slot, name); - return char_id; -} - -/*----------------------------------------------------------------------------------------------------------*/ -/* Divorce Players */ -/*----------------------------------------------------------------------------------------------------------*/ -int divorce_char_sql(int partner_id1, int partner_id2) -{ - unsigned char buf[64]; - - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `partner_id`='0' WHERE `char_id`='%d' OR `char_id`='%d' LIMIT 2", char_db, partner_id1, partner_id2) ) - Sql_ShowDebug(sql_handle); - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE (`nameid`='%d' OR `nameid`='%d') AND (`char_id`='%d' OR `char_id`='%d') LIMIT 2", inventory_db, WEDDING_RING_M, WEDDING_RING_F, partner_id1, partner_id2) ) - Sql_ShowDebug(sql_handle); - - WBUFW(buf,0) = 0x2b12; - WBUFL(buf,2) = partner_id1; - WBUFL(buf,6) = partner_id2; - mapif_sendall(buf,10); - - return 0; -} - -/*----------------------------------------------------------------------------------------------------------*/ -/* Delete char - davidsiaw */ -/*----------------------------------------------------------------------------------------------------------*/ -/* Returns 0 if successful - * Returns < 0 for error - */ -int delete_char_sql(int char_id) -{ - char name[NAME_LENGTH]; - char esc_name[NAME_LENGTH*2+1]; //Name needs be escaped. - int account_id, party_id, guild_id, hom_id, base_level, partner_id, father_id, mother_id; - char* data; - size_t len; - - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `name`,`account_id`,`party_id`,`guild_id`,`base_level`,`homun_id`,`partner_id`,`father`,`mother` FROM `%s` WHERE `char_id`='%d'", char_db, char_id) ) - Sql_ShowDebug(sql_handle); - - if( SQL_SUCCESS != Sql_NextRow(sql_handle) ) - { - ShowError("delete_char_sql: Unable to fetch character data, deletion aborted.\n"); - Sql_FreeResult(sql_handle); - return -1; - } - - Sql_GetData(sql_handle, 0, &data, &len); safestrncpy(name, data, NAME_LENGTH); - Sql_GetData(sql_handle, 1, &data, NULL); account_id = atoi(data); - Sql_GetData(sql_handle, 2, &data, NULL); party_id = atoi(data); - Sql_GetData(sql_handle, 3, &data, NULL); guild_id = atoi(data); - Sql_GetData(sql_handle, 4, &data, NULL); base_level = atoi(data); - Sql_GetData(sql_handle, 5, &data, NULL); hom_id = atoi(data); - Sql_GetData(sql_handle, 6, &data, NULL); partner_id = atoi(data); - Sql_GetData(sql_handle, 7, &data, NULL); father_id = atoi(data); - Sql_GetData(sql_handle, 8, &data, NULL); mother_id = atoi(data); - - Sql_EscapeStringLen(sql_handle, esc_name, name, min(len, NAME_LENGTH)); - Sql_FreeResult(sql_handle); - - //check for config char del condition [Lupus] - // TODO: Move this out to packet processing (0x68/0x1fb). - if( ( char_del_level > 0 && base_level >= char_del_level ) - || ( char_del_level < 0 && base_level <= -char_del_level ) - ) { - ShowInfo("Char deletion aborted: %s, BaseLevel: %i\n", name, base_level); - return -1; - } - - /* Divorce [Wizputer] */ - if( partner_id ) - divorce_char_sql(char_id, partner_id); - - /* De-addopt [Zephyrus] */ - if( father_id || mother_id ) - { // Char is Baby - unsigned char buf[64]; - - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `child`='0' WHERE `char_id`='%d' OR `char_id`='%d'", char_db, father_id, mother_id) ) - Sql_ShowDebug(sql_handle); - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `id` = '410'AND (`char_id`='%d' OR `char_id`='%d')", skill_db, father_id, mother_id) ) - Sql_ShowDebug(sql_handle); - - WBUFW(buf,0) = 0x2b25; - WBUFL(buf,2) = father_id; - WBUFL(buf,6) = mother_id; - WBUFL(buf,10) = char_id; // Baby - mapif_sendall(buf,14); - } - - //Make the character leave the party [Skotlex] - if (party_id) - inter_party_leave(party_id, account_id, char_id); - - /* delete char's pet */ - //Delete the hatched pet if you have one... - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d' AND `incuvate` = '0'", pet_db, char_id) ) - Sql_ShowDebug(sql_handle); - - //Delete all pets that are stored in eggs (inventory + cart) - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` USING `%s` JOIN `%s` ON `pet_id` = `card1`|`card2`<<16 WHERE `%s`.char_id = '%d' AND card0 = -256", pet_db, pet_db, inventory_db, inventory_db, char_id) ) - Sql_ShowDebug(sql_handle); - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` USING `%s` JOIN `%s` ON `pet_id` = `card1`|`card2`<<16 WHERE `%s`.char_id = '%d' AND card0 = -256", pet_db, pet_db, cart_db, cart_db, char_id) ) - Sql_ShowDebug(sql_handle); - - /* remove homunculus */ - if( hom_id ) - mapif_homunculus_delete(hom_id); - - /* remove mercenary data */ - mercenary_owner_delete(char_id); - - /* delete char's friends list */ - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id` = '%d'", friend_db, char_id) ) - Sql_ShowDebug(sql_handle); - - /* delete char from other's friend list */ - //NOTE: Won't this cause problems for people who are already online? [Skotlex] - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `friend_id` = '%d'", friend_db, char_id) ) - Sql_ShowDebug(sql_handle); - -#ifdef HOTKEY_SAVING - /* delete hotkeys */ - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", hotkey_db, char_id) ) - Sql_ShowDebug(sql_handle); -#endif - - /* delete inventory */ - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", inventory_db, char_id) ) - Sql_ShowDebug(sql_handle); - - /* delete cart inventory */ - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", cart_db, char_id) ) - Sql_ShowDebug(sql_handle); - - /* delete memo areas */ - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", memo_db, char_id) ) - Sql_ShowDebug(sql_handle); - - /* delete character registry */ - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `type`=3 AND `char_id`='%d'", reg_db, char_id) ) - Sql_ShowDebug(sql_handle); - - /* delete skills */ - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", skill_db, char_id) ) - Sql_ShowDebug(sql_handle); - -#ifdef ENABLE_SC_SAVING - /* status changes */ - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `account_id` = '%d' AND `char_id`='%d'", scdata_db, account_id, char_id) ) - Sql_ShowDebug(sql_handle); -#endif - - if (log_char) { - if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s`(`time`, `account_id`,`char_num`,`char_msg`,`name`) VALUES (NOW(), '%d', '%d', 'Deleted char (CID %d)', '%s')", - charlog_db, account_id, 0, char_id, esc_name) ) - Sql_ShowDebug(sql_handle); - } - - /* delete character */ - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", char_db, char_id) ) - Sql_ShowDebug(sql_handle); - - /* No need as we used inter_guild_leave [Skotlex] - // Also delete info from guildtables. - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", guild_member_db, char_id) ) - Sql_ShowDebug(sql_handle); - */ - - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `guild_id` FROM `%s` WHERE `char_id` = '%d'", guild_db, char_id) ) - Sql_ShowDebug(sql_handle); - else if( Sql_NumRows(sql_handle) > 0 ) - mapif_parse_BreakGuild(0,guild_id); - else if( guild_id ) - inter_guild_leave(guild_id, account_id, char_id);// Leave your guild. - return 0; -} - -//--------------------------------------------------------------------- -// This function return the number of online players in all map-servers -//--------------------------------------------------------------------- -int count_users(void) -{ - int i, users; - - users = 0; - for(i = 0; i < ARRAYLENGTH(server); i++) { - if (server[i].fd > 0) { - users += server[i].users; - } - } - return users; -} - -// Writes char data to the buffer in the format used by the client. -// Used in packets 0x6b (chars info) and 0x6d (new char info) -// Returns the size -#define MAX_CHAR_BUF 144 //Max size (for WFIFOHEAD calls) -int mmo_char_tobuf(uint8* buffer, struct mmo_charstatus* p) -{ - unsigned short offset = 0; - uint8* buf; - - if( buffer == NULL || p == NULL ) - return 0; - - buf = WBUFP(buffer,0); - WBUFL(buf,0) = p->char_id; - WBUFL(buf,4) = min(p->base_exp, INT32_MAX); - WBUFL(buf,8) = p->zeny; - WBUFL(buf,12) = min(p->job_exp, INT32_MAX); - WBUFL(buf,16) = p->job_level; - WBUFL(buf,20) = 0; // probably opt1 - WBUFL(buf,24) = 0; // probably opt2 - WBUFL(buf,28) = p->option; - WBUFL(buf,32) = p->karma; - WBUFL(buf,36) = p->manner; - WBUFW(buf,40) = min(p->status_point, INT16_MAX); -#if PACKETVER > 20081217 - WBUFL(buf,42) = p->hp; - WBUFL(buf,46) = p->max_hp; - offset+=4; - buf = WBUFP(buffer,offset); -#else - WBUFW(buf,42) = min(p->hp, INT16_MAX); - WBUFW(buf,44) = min(p->max_hp, INT16_MAX); -#endif - WBUFW(buf,46) = min(p->sp, INT16_MAX); - WBUFW(buf,48) = min(p->max_sp, INT16_MAX); - WBUFW(buf,50) = DEFAULT_WALK_SPEED; // p->speed; - WBUFW(buf,52) = p->class_; - WBUFW(buf,54) = p->hair; - - //When the weapon is sent and your option is riding, the client crashes on login!? - WBUFW(buf,56) = p->option&(0x20|0x80000|0x100000|0x200000|0x400000|0x800000|0x1000000|0x2000000|0x4000000|0x8000000) ? 0 : p->weapon; - - WBUFW(buf,58) = p->base_level; - WBUFW(buf,60) = min(p->skill_point, INT16_MAX); - WBUFW(buf,62) = p->head_bottom; - WBUFW(buf,64) = p->shield; - WBUFW(buf,66) = p->head_top; - WBUFW(buf,68) = p->head_mid; - WBUFW(buf,70) = p->hair_color; - WBUFW(buf,72) = p->clothes_color; - memcpy(WBUFP(buf,74), p->name, NAME_LENGTH); - WBUFB(buf,98) = min(p->str, UINT8_MAX); - WBUFB(buf,99) = min(p->agi, UINT8_MAX); - WBUFB(buf,100) = min(p->vit, UINT8_MAX); - WBUFB(buf,101) = min(p->int_, UINT8_MAX); - WBUFB(buf,102) = min(p->dex, UINT8_MAX); - WBUFB(buf,103) = min(p->luk, UINT8_MAX); - WBUFW(buf,104) = p->slot; -#if PACKETVER >= 20061023 - WBUFW(buf,106) = ( p->rename > 0 ) ? 0 : 1; - offset += 2; -#endif -#if (PACKETVER >= 20100720 && PACKETVER <= 20100727) || PACKETVER >= 20100803 - mapindex_getmapname_ext(mapindex_id2name(p->last_point.map), (char*)WBUFP(buf,108)); - offset += MAP_NAME_LENGTH_EXT; -#endif -#if PACKETVER >= 20100803 - WBUFL(buf,124) = TOL(p->delete_date); - offset += 4; -#endif -#if PACKETVER >= 20110111 - WBUFL(buf,128) = p->robe; - offset += 4; -#endif -#if PACKETVER != 20111116 //2011-11-16 wants 136, ask gravity. - #if PACKETVER >= 20110928 - WBUFL(buf,132) = 0; // change slot feature (0 = disabled, otherwise enabled) - offset += 4; - #endif - #if PACKETVER >= 20111025 - WBUFL(buf,136) = 0; // unknown purpose (0 = disabled, otherwise displays "Add-Ons" sidebar) - offset += 4; - #endif -#endif - - return 106+offset; -} - -//---------------------------------------- -// Function to send characters to a player -//---------------------------------------- -int mmo_char_send006b(int fd, struct char_session_data* sd) -{ - int j, offset = 0; -#if PACKETVER >= 20100413 - offset += 3; -#endif - - if (save_log) - ShowInfo("Loading Char Data ("CL_BOLD"%d"CL_RESET")\n",sd->account_id); - - j = 24 + offset; // offset - WFIFOHEAD(fd,j + MAX_CHARS*MAX_CHAR_BUF); - WFIFOW(fd,0) = 0x6b; -#if PACKETVER >= 20100413 - WFIFOB(fd,4) = MAX_CHARS; // Max slots. - WFIFOB(fd,5) = MAX_CHARS; // Available slots. - WFIFOB(fd,6) = MAX_CHARS; // Premium slots. -#endif - memset(WFIFOP(fd,4 + offset), 0, 20); // unknown bytes - j+=mmo_chars_fromsql(sd, WFIFOP(fd,j)); - WFIFOW(fd,2) = j; // packet len - WFIFOSET(fd,j); - - return 0; -} - -int char_married(int pl1, int pl2) -{ - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `partner_id` FROM `%s` WHERE `char_id` = '%d'", char_db, pl1) ) - Sql_ShowDebug(sql_handle); - else if( SQL_SUCCESS == Sql_NextRow(sql_handle) ) - { - char* data; - - Sql_GetData(sql_handle, 0, &data, NULL); - if( pl2 == atoi(data) ) - { - Sql_FreeResult(sql_handle); - return 1; - } - } - Sql_FreeResult(sql_handle); - return 0; -} - -int char_child(int parent_id, int child_id) -{ - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `child` FROM `%s` WHERE `char_id` = '%d'", char_db, parent_id) ) - Sql_ShowDebug(sql_handle); - else if( SQL_SUCCESS == Sql_NextRow(sql_handle) ) - { - char* data; - - Sql_GetData(sql_handle, 0, &data, NULL); - if( child_id == atoi(data) ) - { - Sql_FreeResult(sql_handle); - return 1; - } - } - Sql_FreeResult(sql_handle); - return 0; -} - -int char_family(int cid1, int cid2, int cid3) -{ - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`,`partner_id`,`child` FROM `%s` WHERE `char_id` IN ('%d','%d','%d')", char_db, cid1, cid2, cid3) ) - Sql_ShowDebug(sql_handle); - else while( SQL_SUCCESS == Sql_NextRow(sql_handle) ) - { - int charid; - int partnerid; - int childid; - char* data; - - Sql_GetData(sql_handle, 0, &data, NULL); charid = atoi(data); - Sql_GetData(sql_handle, 1, &data, NULL); partnerid = atoi(data); - Sql_GetData(sql_handle, 2, &data, NULL); childid = atoi(data); - - if( (cid1 == charid && ((cid2 == partnerid && cid3 == childid ) || (cid2 == childid && cid3 == partnerid))) || - (cid1 == partnerid && ((cid2 == charid && cid3 == childid ) || (cid2 == childid && cid3 == charid ))) || - (cid1 == childid && ((cid2 == charid && cid3 == partnerid) || (cid2 == partnerid && cid3 == charid ))) ) - { - Sql_FreeResult(sql_handle); - return childid; - } - } - Sql_FreeResult(sql_handle); - return 0; -} - -//---------------------------------------------------------------------- -// Force disconnection of an online player (with account value) by [Yor] -//---------------------------------------------------------------------- -void disconnect_player(int account_id) -{ - int i; - struct char_session_data* sd; - - // disconnect player if online on char-server - ARR_FIND( 0, fd_max, i, session[i] && (sd = (struct char_session_data*)session[i]->session_data) && sd->account_id == account_id ); - if( i < fd_max ) - set_eof(i); -} - -static void char_auth_ok(int fd, struct char_session_data *sd) -{ - struct online_char_data* character; - - if( (character = (struct online_char_data*)idb_get(online_char_db, sd->account_id)) != NULL ) - { // check if character is not online already. [Skotlex] - if (character->server > -1) - { //Character already online. KICK KICK KICK - mapif_disconnectplayer(server[character->server].fd, character->account_id, character->char_id, 2); - if (character->waiting_disconnect == INVALID_TIMER) - character->waiting_disconnect = add_timer(gettick()+20000, chardb_waiting_disconnect, character->account_id, 0); - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x81; - WFIFOB(fd,2) = 8; - WFIFOSET(fd,3); - return; - } - if (character->fd >= 0 && character->fd != fd) - { //There's already a connection from this account that hasn't picked a char yet. - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x81; - WFIFOB(fd,2) = 8; - WFIFOSET(fd,3); - return; - } - character->fd = fd; - } - - if (login_fd > 0) { - // request account data - WFIFOHEAD(login_fd,6); - WFIFOW(login_fd,0) = 0x2716; - WFIFOL(login_fd,2) = sd->account_id; - WFIFOSET(login_fd,6); - } - - // mark session as 'authed' - sd->auth = true; - - // set char online on charserver - set_char_charselect(sd->account_id); - - // continues when account data is received... -} - -int send_accounts_tologin(int tid, unsigned int tick, int id, intptr_t data); -void mapif_server_reset(int id); - - -/// Resets all the data. -void loginif_reset(void) -{ - int id; - // TODO kick everyone out and reset everything or wait for connect and try to reaquire locks [FlavioJS] - for( id = 0; id < ARRAYLENGTH(server); ++id ) - mapif_server_reset(id); - flush_fifos(); - 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 loginif_check_shutdown(void) -{ - if( runflag != CHARSERVER_ST_SHUTDOWN ) - return; - runflag = CORE_ST_STOP; -} - - -/// Called when the connection to Login Server is disconnected. -void loginif_on_disconnect(void) -{ - ShowWarning("Connection to Login Server lost.\n\n"); -} - - -/// Called when all the connection steps are completed. -void loginif_on_ready(void) -{ - int i; - - loginif_check_shutdown(); - - //Send online accounts to login server. - send_accounts_tologin(INVALID_TIMER, gettick(), 0, 0); - - // if no map-server already connected, display a message... - ARR_FIND( 0, ARRAYLENGTH(server), i, server[i].fd > 0 && server[i].map[0] ); - if( i == ARRAYLENGTH(server) ) - ShowStatus("Awaiting maps from map-server.\n"); -} - - -int parse_fromlogin(int fd) -{ - struct char_session_data* sd = NULL; - int i; - - // only process data from the login-server - if( fd != login_fd ) - { - ShowDebug("parse_fromlogin: Disconnecting invalid session #%d (is not the login-server)\n", fd); - do_close(fd); - return 0; - } - - if( session[fd]->flag.eof ) - { - do_close(fd); - login_fd = -1; - loginif_on_disconnect(); - return 0; - } - - sd = (struct char_session_data*)session[fd]->session_data; - - while(RFIFOREST(fd) >= 2) - { - uint16 command = RFIFOW(fd,0); - - switch( command ) - { - - // acknowledgement of connect-to-loginserver request - case 0x2711: - if (RFIFOREST(fd) < 3) - return 0; - - if (RFIFOB(fd,2)) { - //printf("connect login server error : %d\n", RFIFOB(fd,2)); - ShowError("Can not connect to login-server.\n"); - ShowError("The server communication passwords (default s1/p1) are probably invalid.\n"); - ShowError("Also, please make sure your login db has the correct communication username/passwords and the gender of the account is S.\n"); - ShowError("The communication passwords are set in map_athena.conf and char_athena.conf\n"); - set_eof(fd); - return 0; - } else { - ShowStatus("Connected to login-server (connection #%d).\n", fd); - loginif_on_ready(); - } - RFIFOSKIP(fd,3); - break; - - // acknowledgement of account authentication request - case 0x2713: - if (RFIFOREST(fd) < 25) - return 0; - { - int account_id = RFIFOL(fd,2); - uint32 login_id1 = RFIFOL(fd,6); - uint32 login_id2 = RFIFOL(fd,10); - uint8 sex = RFIFOB(fd,14); - uint8 result = RFIFOB(fd,15); - int request_id = RFIFOL(fd,16); - uint32 version = RFIFOL(fd,20); - uint8 clienttype = RFIFOB(fd,24); - RFIFOSKIP(fd,25); - - if( session_isActive(request_id) && (sd=(struct char_session_data*)session[request_id]->session_data) && - !sd->auth && sd->account_id == account_id && sd->login_id1 == login_id1 && sd->login_id2 == login_id2 && sd->sex == sex ) - { - int client_fd = request_id; - sd->version = version; - sd->clienttype = clienttype; - switch( result ) - { - case 0:// ok - char_auth_ok(client_fd, sd); - break; - case 1:// auth failed - WFIFOHEAD(client_fd,3); - WFIFOW(client_fd,0) = 0x6c; - WFIFOB(client_fd,2) = 0;// rejected from server - WFIFOSET(client_fd,3); - break; - } - } - } - break; - - case 0x2717: // account data - if (RFIFOREST(fd) < 62) - return 0; - - // find the authenticated session with this account id - ARR_FIND( 0, fd_max, i, session[i] && (sd = (struct char_session_data*)session[i]->session_data) && sd->auth && sd->account_id == RFIFOL(fd,2) ); - if( i < fd_max ) - { - int server_id; - memcpy(sd->email, RFIFOP(fd,6), 40); - sd->expiration_time = (time_t)RFIFOL(fd,46); - sd->gmlevel = RFIFOB(fd,50); - safestrncpy(sd->birthdate, (const char*)RFIFOP(fd,51), sizeof(sd->birthdate)); - ARR_FIND( 0, ARRAYLENGTH(server), server_id, server[server_id].fd > 0 && server[server_id].map[0] ); - // continued from char_auth_ok... - if( server_id == ARRAYLENGTH(server) || //server not online, bugreport:2359 - ( max_connect_user && count_users() >= max_connect_user && sd->gmlevel < gm_allow_level ) ) { - // refuse connection (over populated) - WFIFOHEAD(i,3); - WFIFOW(i,0) = 0x6c; - WFIFOW(i,2) = 0; - WFIFOSET(i,3); - } else { - // send characters to player - mmo_char_send006b(i, sd); -#if PACKETVER >= 20110309 - // PIN code system, disabled - WFIFOHEAD(i, 12); - WFIFOW(i, 0) = 0x08B9; - WFIFOW(i, 2) = 0; - WFIFOW(i, 4) = 0; - WFIFOL(i, 6) = sd->account_id; - WFIFOW(i, 10) = 0; - WFIFOSET(i, 12); -#endif - } - } - RFIFOSKIP(fd,62); - break; - - // login-server alive packet - case 0x2718: - if (RFIFOREST(fd) < 2) - return 0; - RFIFOSKIP(fd,2); - break; - - // changesex reply - case 0x2723: - if (RFIFOREST(fd) < 7) - return 0; - { - unsigned char buf[7]; - - int acc = RFIFOL(fd,2); - int sex = RFIFOB(fd,6); - RFIFOSKIP(fd,7); - - if( acc > 0 ) - {// TODO: Is this even possible? - int char_id[MAX_CHARS]; - int class_[MAX_CHARS]; - int guild_id[MAX_CHARS]; - int num; - char* data; - - struct auth_node* node = (struct auth_node*)idb_get(auth_db, acc); - if( node != NULL ) - node->sex = sex; - - // get characters - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`,`class`,`guild_id` FROM `%s` WHERE `account_id` = '%d'", char_db, acc) ) - Sql_ShowDebug(sql_handle); - for( i = 0; i < MAX_CHARS && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i ) - { - Sql_GetData(sql_handle, 0, &data, NULL); char_id[i] = atoi(data); - Sql_GetData(sql_handle, 1, &data, NULL); class_[i] = atoi(data); - Sql_GetData(sql_handle, 2, &data, NULL); guild_id[i] = atoi(data); - } - num = i; - for( i = 0; i < num; ++i ) - { - if( class_[i] == JOB_BARD || class_[i] == JOB_DANCER || - class_[i] == JOB_CLOWN || class_[i] == JOB_GYPSY || - class_[i] == JOB_BABY_BARD || class_[i] == JOB_BABY_DANCER || - class_[i] == JOB_WANDERER || class_[i] == JOB_WANDERER_T || - class_[i] == JOB_MINSTREL || class_[i] == JOB_MINSTREL_T ) - { - // job modification - if( class_[i] == JOB_BARD || class_[i] == JOB_DANCER ) - class_[i] = (sex ? JOB_BARD : JOB_DANCER); - else if( class_[i] == JOB_CLOWN || class_[i] == JOB_GYPSY ) - class_[i] = (sex ? JOB_CLOWN : JOB_GYPSY); - else if( class_[i] == JOB_BABY_BARD || class_[i] == JOB_BABY_DANCER ) - class_[i] = (sex ? JOB_BABY_BARD : JOB_BABY_DANCER); - else if( class_[i] == JOB_MINSTREL || class_[i] == JOB_WANDERER ) - class_[i] = (sex ? JOB_MINSTREL : JOB_WANDERER); - else if( class_[i] == JOB_MINSTREL_T || class_[i] == JOB_WANDERER_T ) - class_[i] = (sex ? JOB_MINSTREL_T : JOB_WANDERER_T); - // remove specifical skills of classes 19,20 4020,4021 and 4042,4043 - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `skill_point` = `skill_point` +" - " (SELECT SUM(lv) FROM `%s` WHERE `char_id` = '%d' AND `id` >= '315' AND `id` <= '330' AND `lv` > '0')" - " WHERE `char_id` = '%d'", - char_db, skill_db, char_id[i], char_id[i]) ) - Sql_ShowDebug(sql_handle); - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id` = '%d' AND `id` >= '315' AND `id` <= '330'", skill_db, char_id[i]) ) - Sql_ShowDebug(sql_handle); - } - // to avoid any problem with equipment and invalid sex, equipment is unequiped. - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `equip` = '0' WHERE `char_id` = '%d'", inventory_db, char_id[i]) ) - Sql_ShowDebug(sql_handle); - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `class`='%d', `weapon`='0', `shield`='0', `head_top`='0', `head_mid`='0', `head_bottom`='0' WHERE `char_id`='%d'", char_db, class_[i], char_id[i]) ) - Sql_ShowDebug(sql_handle); - - if( guild_id[i] )// If there is a guild, update the guild_member data [Skotlex] - inter_guild_sex_changed(guild_id[i], acc, char_id[i], sex); - } - Sql_FreeResult(sql_handle); - - // disconnect player if online on char-server - disconnect_player(acc); - } - - // notify all mapservers about this change - WBUFW(buf,0) = 0x2b0d; - WBUFL(buf,2) = acc; - WBUFB(buf,6) = sex; - mapif_sendall(buf, 7); - } - break; - - // reply to an account_reg2 registry request - case 0x2729: - if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2)) - return 0; - - { //Receive account_reg2 registry, forward to map servers. - unsigned char buf[13+ACCOUNT_REG2_NUM*sizeof(struct global_reg)]; - memcpy(buf,RFIFOP(fd,0), RFIFOW(fd,2)); - WBUFW(buf,0) = 0x3804; //Map server can now receive all kinds of reg values with the same packet. [Skotlex] - mapif_sendall(buf, WBUFW(buf,2)); - RFIFOSKIP(fd, RFIFOW(fd,2)); - } - break; - - // State change of account/ban notification (from login-server) - case 0x2731: - if (RFIFOREST(fd) < 11) - return 0; - - { // send to all map-servers to disconnect the player - unsigned char buf[11]; - WBUFW(buf,0) = 0x2b14; - WBUFL(buf,2) = RFIFOL(fd,2); - WBUFB(buf,6) = RFIFOB(fd,6); // 0: change of statut, 1: ban - WBUFL(buf,7) = RFIFOL(fd,7); // status or final date of a banishment - mapif_sendall(buf, 11); - } - // disconnect player if online on char-server - disconnect_player(RFIFOL(fd,2)); - - RFIFOSKIP(fd,11); - break; - - // Login server request to kick a character out. [Skotlex] - case 0x2734: - if (RFIFOREST(fd) < 6) - return 0; - { - int aid = RFIFOL(fd,2); - struct online_char_data* character = (struct online_char_data*)idb_get(online_char_db, aid); - RFIFOSKIP(fd,6); - if( character != NULL ) - {// account is already marked as online! - if( character->server > -1 ) - { //Kick it from the map server it is on. - mapif_disconnectplayer(server[character->server].fd, character->account_id, character->char_id, 2); - if (character->waiting_disconnect == INVALID_TIMER) - character->waiting_disconnect = add_timer(gettick()+AUTH_TIMEOUT, chardb_waiting_disconnect, character->account_id, 0); - } - else - {// Manual kick from char server. - struct char_session_data *tsd; - int i; - ARR_FIND( 0, fd_max, i, session[i] && (tsd = (struct char_session_data*)session[i]->session_data) && tsd->account_id == aid ); - if( i < fd_max ) - { - WFIFOHEAD(i,3); - WFIFOW(i,0) = 0x81; - WFIFOB(i,2) = 2; // "Someone has already logged in with this id" - WFIFOSET(i,3); - set_eof(i); - } - else // still moving to the map-server - set_char_offline(-1, aid); - } - } - idb_remove(auth_db, aid);// reject auth attempts from map-server - } - break; - - // ip address update signal from login server - case 0x2735: - { - unsigned char buf[2]; - uint32 new_ip = 0; - - WBUFW(buf,0) = 0x2b1e; - mapif_sendall(buf, 2); - - new_ip = host2ip(login_ip_str); - if (new_ip && new_ip != login_ip) - login_ip = new_ip; //Update login ip, too. - - new_ip = host2ip(char_ip_str); - if (new_ip && new_ip != char_ip) - { //Update ip. - char_ip = new_ip; - ShowInfo("Updating IP for [%s].\n", char_ip_str); - // notify login server about the change - WFIFOHEAD(fd,6); - WFIFOW(fd,0) = 0x2736; - WFIFOL(fd,2) = htonl(char_ip); - WFIFOSET(fd,6); - } - - RFIFOSKIP(fd,2); - } - break; - - default: - ShowError("Unknown packet 0x%04x received from login-server, disconnecting.\n", command); - set_eof(fd); - return 0; - } - } - - RFIFOFLUSH(fd); - return 0; -} - -int check_connect_login_server(int tid, unsigned int tick, int id, intptr_t data); -int ping_login_server(int tid, unsigned int tick, int id, intptr_t data); -int send_accounts_tologin(int tid, unsigned int tick, int id, intptr_t data); - -void do_init_loginif(void) -{ - // establish char-login connection if not present - add_timer_func_list(check_connect_login_server, "check_connect_login_server"); - add_timer_interval(gettick() + 1000, check_connect_login_server, 0, 0, 10 * 1000); - - // keep the char-login connection alive - add_timer_func_list(ping_login_server, "ping_login_server"); - add_timer_interval(gettick() + 1000, ping_login_server, 0, 0, ((int)stall_time-2) * 1000); - - // send a list of all online account IDs to login server - add_timer_func_list(send_accounts_tologin, "send_accounts_tologin"); - add_timer_interval(gettick() + 1000, send_accounts_tologin, 0, 0, 3600 * 1000); //Sync online accounts every hour -} - -void do_final_loginif(void) -{ - if( login_fd != -1 ) - { - do_close(login_fd); - login_fd = -1; - } -} - -int request_accreg2(int account_id, int char_id) -{ - if (login_fd > 0) { - WFIFOHEAD(login_fd,10); - WFIFOW(login_fd,0) = 0x272e; - WFIFOL(login_fd,2) = account_id; - WFIFOL(login_fd,6) = char_id; - WFIFOSET(login_fd,10); - return 1; - } - return 0; -} - -//Send packet forward to login-server for account saving -int save_accreg2(unsigned char* buf, int len) -{ - if (login_fd > 0) { - WFIFOHEAD(login_fd,len+4); - memcpy(WFIFOP(login_fd,4), buf, len); - WFIFOW(login_fd,0) = 0x2728; - WFIFOW(login_fd,2) = len+4; - WFIFOSET(login_fd,len+4); - return 1; - } - return 0; -} - -void char_read_fame_list(void) -{ - int i; - char* data; - size_t len; - - // Empty ranking lists - 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)); - // Build Blacksmith ranking list - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`,`fame`,`name` FROM `%s` WHERE `fame`>0 AND (`class`='%d' OR `class`='%d' OR `class`='%d') ORDER BY `fame` DESC LIMIT 0,%d", char_db, JOB_BLACKSMITH, JOB_WHITESMITH, JOB_BABY_BLACKSMITH, fame_list_size_smith) ) - Sql_ShowDebug(sql_handle); - for( i = 0; i < fame_list_size_smith && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i ) - { - // char_id - Sql_GetData(sql_handle, 0, &data, NULL); - smith_fame_list[i].id = atoi(data); - // fame - Sql_GetData(sql_handle, 1, &data, &len); - smith_fame_list[i].fame = atoi(data); - // name - Sql_GetData(sql_handle, 2, &data, &len); - memcpy(smith_fame_list[i].name, data, min(len, NAME_LENGTH)); - } - // Build Alchemist ranking list - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`,`fame`,`name` FROM `%s` WHERE `fame`>0 AND (`class`='%d' OR `class`='%d' OR `class`='%d') ORDER BY `fame` DESC LIMIT 0,%d", char_db, JOB_ALCHEMIST, JOB_CREATOR, JOB_BABY_ALCHEMIST, fame_list_size_chemist) ) - Sql_ShowDebug(sql_handle); - for( i = 0; i < fame_list_size_chemist && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i ) - { - // char_id - Sql_GetData(sql_handle, 0, &data, NULL); - chemist_fame_list[i].id = atoi(data); - // fame - Sql_GetData(sql_handle, 1, &data, &len); - chemist_fame_list[i].fame = atoi(data); - // name - Sql_GetData(sql_handle, 2, &data, &len); - memcpy(chemist_fame_list[i].name, data, min(len, NAME_LENGTH)); - } - // Build Taekwon ranking list - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`,`fame`,`name` FROM `%s` WHERE `fame`>0 AND (`class`='%d') ORDER BY `fame` DESC LIMIT 0,%d", char_db, JOB_TAEKWON, fame_list_size_taekwon) ) - Sql_ShowDebug(sql_handle); - for( i = 0; i < fame_list_size_taekwon && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i ) - { - // char_id - Sql_GetData(sql_handle, 0, &data, NULL); - taekwon_fame_list[i].id = atoi(data); - // fame - Sql_GetData(sql_handle, 1, &data, &len); - taekwon_fame_list[i].fame = atoi(data); - // name - Sql_GetData(sql_handle, 2, &data, &len); - memcpy(taekwon_fame_list[i].name, data, min(len, NAME_LENGTH)); - } - Sql_FreeResult(sql_handle); -} - -// Send map-servers the fame ranking lists -int char_send_fame_list(int fd) -{ - int i, len = 8; - unsigned char buf[32000]; - - WBUFW(buf,0) = 0x2b1b; - - for(i = 0; i < fame_list_size_smith && smith_fame_list[i].id; i++) { - memcpy(WBUFP(buf, len), &smith_fame_list[i], sizeof(struct fame_list)); - len += sizeof(struct fame_list); - } - // add blacksmith's block length - WBUFW(buf, 6) = len; - - for(i = 0; i < fame_list_size_chemist && chemist_fame_list[i].id; i++) { - memcpy(WBUFP(buf, len), &chemist_fame_list[i], sizeof(struct fame_list)); - len += sizeof(struct fame_list); - } - // add alchemist's block length - WBUFW(buf, 4) = len; - - for(i = 0; i < fame_list_size_taekwon && taekwon_fame_list[i].id; i++) { - memcpy(WBUFP(buf, len), &taekwon_fame_list[i], sizeof(struct fame_list)); - len += sizeof(struct fame_list); - } - // add total packet length - WBUFW(buf, 2) = len; - - if (fd != -1) - mapif_send(fd, buf, len); - else - mapif_sendall(buf, len); - - return 0; -} - -void char_update_fame_list(int type, int index, int fame) -{ - unsigned char buf[8]; - WBUFW(buf,0) = 0x2b22; - WBUFB(buf,2) = type; - WBUFB(buf,3) = index; - WBUFL(buf,4) = fame; - mapif_sendall(buf, 8); -} - -//Loads a character's name and stores it in the buffer given (must be NAME_LENGTH in size) -//Returns 1 on found, 0 on not found (buffer is filled with Unknown char name) -int char_loadName(int char_id, char* name) -{ - char* data; - size_t len; - - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `name` FROM `%s` WHERE `char_id`='%d'", char_db, char_id) ) - Sql_ShowDebug(sql_handle); - else if( SQL_SUCCESS == Sql_NextRow(sql_handle) ) - { - Sql_GetData(sql_handle, 0, &data, &len); - safestrncpy(name, data, NAME_LENGTH); - return 1; - } - else - { - safestrncpy(name, unknown_char_name, NAME_LENGTH); - } - return 0; -} - -int search_mapserver(unsigned short map, uint32 ip, uint16 port); - - -/// Initializes a server structure. -void mapif_server_init(int id) -{ - memset(&server[id], 0, sizeof(server[id])); - server[id].fd = -1; -} - - -/// Destroys a server structure. -void mapif_server_destroy(int id) -{ - if( server[id].fd == -1 ) - { - do_close(server[id].fd); - server[id].fd = -1; - } -} - - -/// Resets all the data related to a server. -void mapif_server_reset(int id) -{ - int i,j; - unsigned char buf[16384]; - int fd = server[id].fd; - //Notify other map servers that this one is gone. [Skotlex] - WBUFW(buf,0) = 0x2b20; - WBUFL(buf,4) = htonl(server[id].ip); - WBUFW(buf,8) = htons(server[id].port); - j = 0; - for(i = 0; i < MAX_MAP_PER_SERVER; i++) - if (server[id].map[i]) - WBUFW(buf,10+(j++)*4) = server[id].map[i]; - if (j > 0) { - WBUFW(buf,2) = j * 4 + 10; - mapif_sendallwos(fd, buf, WBUFW(buf,2)); - } - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `ragsrvinfo` WHERE `index`='%d'", server[id].fd) ) - Sql_ShowDebug(sql_handle); - online_char_db->foreach(online_char_db,char_db_setoffline,id); //Tag relevant chars as 'in disconnected' server. - mapif_server_destroy(id); - mapif_server_init(id); -} - - -/// Called when the connection to a Map Server is disconnected. -void mapif_on_disconnect(int id) -{ - ShowStatus("Map-server #%d has disconnected.\n", id); - mapif_server_reset(id); -} - - -int parse_frommap(int fd) -{ - int i, j; - int id; - - ARR_FIND( 0, ARRAYLENGTH(server), id, server[id].fd == fd ); - if( id == ARRAYLENGTH(server) ) - {// not a map server - ShowDebug("parse_frommap: Disconnecting invalid session #%d (is not a map-server)\n", fd); - do_close(fd); - return 0; - } - if( session[fd]->flag.eof ) - { - do_close(fd); - server[id].fd = -1; - mapif_on_disconnect(id); - return 0; - } - - while(RFIFOREST(fd) >= 2) - { - switch(RFIFOW(fd,0)) - { - - case 0x2afa: // Receiving map names list from the map-server - if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2)) - return 0; - - memset(server[id].map, 0, sizeof(server[id].map)); - j = 0; - for(i = 4; i < RFIFOW(fd,2); i += 4) { - server[id].map[j] = RFIFOW(fd,i); - j++; - } - - ShowStatus("Map-Server %d connected: %d maps, from IP %d.%d.%d.%d port %d.\n", - id, j, CONVIP(server[id].ip), server[id].port); - ShowStatus("Map-server %d loading complete.\n", id); - - // send name for wisp to player - WFIFOHEAD(fd, 3 + NAME_LENGTH); - WFIFOW(fd,0) = 0x2afb; - WFIFOB(fd,2) = 0; - memcpy(WFIFOP(fd,3), wisp_server_name, NAME_LENGTH); - WFIFOSET(fd,3+NAME_LENGTH); - - char_send_fame_list(fd); //Send fame list. - - { - unsigned char buf[16384]; - int x; - if (j == 0) { - ShowWarning("Map-server %d has NO maps.\n", id); - } else { - // Transmitting maps information to the other map-servers - WBUFW(buf,0) = 0x2b04; - WBUFW(buf,2) = j * 4 + 10; - WBUFL(buf,4) = htonl(server[id].ip); - WBUFW(buf,8) = htons(server[id].port); - memcpy(WBUFP(buf,10), RFIFOP(fd,4), j * 4); - mapif_sendallwos(fd, buf, WBUFW(buf,2)); - } - // Transmitting the maps of the other map-servers to the new map-server - for(x = 0; x < ARRAYLENGTH(server); x++) { - if (server[x].fd > 0 && x != id) { - WFIFOHEAD(fd,10 +4*ARRAYLENGTH(server)); - WFIFOW(fd,0) = 0x2b04; - WFIFOL(fd,4) = htonl(server[x].ip); - WFIFOW(fd,8) = htons(server[x].port); - j = 0; - for(i = 0; i < ARRAYLENGTH(server); i++) - if (server[x].map[i]) - WFIFOW(fd,10+(j++)*4) = server[x].map[i]; - if (j > 0) { - WFIFOW(fd,2) = j * 4 + 10; - WFIFOSET(fd,WFIFOW(fd,2)); - } - } - } - } - RFIFOSKIP(fd,RFIFOW(fd,2)); - break; - - case 0x2afc: //Packet command is now used for sc_data request. [Skotlex] - if (RFIFOREST(fd) < 10) - return 0; - { -#ifdef ENABLE_SC_SAVING - int aid, cid; - aid = RFIFOL(fd,2); - cid = RFIFOL(fd,6); - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT type, tick, val1, val2, val3, val4 from `%s` WHERE `account_id` = '%d' AND `char_id`='%d'", - scdata_db, aid, cid) ) - { - Sql_ShowDebug(sql_handle); - break; - } - if( Sql_NumRows(sql_handle) > 0 ) - { - struct status_change_data scdata; - int count; - char* data; - - WFIFOHEAD(fd,14+50*sizeof(struct status_change_data)); - WFIFOW(fd,0) = 0x2b1d; - WFIFOL(fd,4) = aid; - WFIFOL(fd,8) = cid; - for( count = 0; count < 50 && SQL_SUCCESS == Sql_NextRow(sql_handle); ++count ) - { - Sql_GetData(sql_handle, 0, &data, NULL); scdata.type = atoi(data); - Sql_GetData(sql_handle, 1, &data, NULL); scdata.tick = atoi(data); - Sql_GetData(sql_handle, 2, &data, NULL); scdata.val1 = atoi(data); - Sql_GetData(sql_handle, 3, &data, NULL); scdata.val2 = atoi(data); - Sql_GetData(sql_handle, 4, &data, NULL); scdata.val3 = atoi(data); - Sql_GetData(sql_handle, 5, &data, NULL); scdata.val4 = atoi(data); - memcpy(WFIFOP(fd, 14+count*sizeof(struct status_change_data)), &scdata, sizeof(struct status_change_data)); - } - if (count >= 50) - ShowWarning("Too many status changes for %d:%d, some of them were not loaded.\n", aid, cid); - if (count > 0) - { - WFIFOW(fd,2) = 14 + count*sizeof(struct status_change_data); - WFIFOW(fd,12) = count; - WFIFOSET(fd,WFIFOW(fd,2)); - - //Clear the data once loaded. - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `account_id` = '%d' AND `char_id`='%d'", scdata_db, aid, cid) ) - Sql_ShowDebug(sql_handle); - } - } - Sql_FreeResult(sql_handle); -#endif - RFIFOSKIP(fd, 10); - } - break; - - case 0x2afe: //set MAP user count - if (RFIFOREST(fd) < 4) - return 0; - if (RFIFOW(fd,2) != server[id].users) { - server[id].users = RFIFOW(fd,2); - ShowInfo("User Count: %d (Server: %d)\n", server[id].users, id); - } - RFIFOSKIP(fd, 4); - break; - - case 0x2aff: //set MAP users - if (RFIFOREST(fd) < 6 || RFIFOREST(fd) < RFIFOW(fd,2)) - return 0; - { - //TODO: When data mismatches memory, update guild/party online/offline states. - int aid, cid; - struct online_char_data* character; - - server[id].users = RFIFOW(fd,4); - online_char_db->foreach(online_char_db,char_db_setoffline,id); //Set all chars from this server as 'unknown' - for(i = 0; i < server[id].users; i++) { - aid = RFIFOL(fd,6+i*8); - cid = RFIFOL(fd,6+i*8+4); - character = (struct online_char_data*)idb_ensure(online_char_db, aid, create_online_char_data); - if( character->server > -1 && character->server != id ) - { - ShowNotice("Set map user: Character (%d:%d) marked on map server %d, but map server %d claims to have (%d:%d) online!\n", - character->account_id, character->char_id, character->server, id, aid, cid); - mapif_disconnectplayer(server[character->server].fd, character->account_id, character->char_id, 2); - } - character->server = id; - character->char_id = cid; - } - //If any chars remain in -2, they will be cleaned in the cleanup timer. - RFIFOSKIP(fd,RFIFOW(fd,2)); - } - break; - - case 0x2b01: // Receive character data from map-server for saving - if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2)) - return 0; - { - int aid = RFIFOL(fd,4), cid = RFIFOL(fd,8), size = RFIFOW(fd,2); - struct online_char_data* character; - - if (size - 13 != sizeof(struct mmo_charstatus)) - { - ShowError("parse_from_map (save-char): Size mismatch! %d != %d\n", size-13, sizeof(struct mmo_charstatus)); - RFIFOSKIP(fd,size); - break; - } - //Check account only if this ain't final save. Final-save goes through because of the char-map reconnect - if (RFIFOB(fd,12) || ( - (character = (struct online_char_data*)idb_get(online_char_db, aid)) != NULL && - character->char_id == cid)) - { - struct mmo_charstatus char_dat; - memcpy(&char_dat, RFIFOP(fd,13), sizeof(struct mmo_charstatus)); - mmo_char_tosql(cid, &char_dat); - } else { //This may be valid on char-server reconnection, when re-sending characters that already logged off. - ShowError("parse_from_map (save-char): Received data for non-existant/offline character (%d:%d).\n", aid, cid); - set_char_online(id, cid, aid); - } - - if (RFIFOB(fd,12)) - { //Flag, set character offline after saving. [Skotlex] - set_char_offline(cid, aid); - WFIFOHEAD(fd,10); - WFIFOW(fd,0) = 0x2b21; //Save ack only needed on final save. - WFIFOL(fd,2) = aid; - WFIFOL(fd,6) = cid; - WFIFOSET(fd,10); - } - RFIFOSKIP(fd,size); - } - break; - - case 0x2b02: // req char selection - if( RFIFOREST(fd) < 18 ) - return 0; - { - struct auth_node* node; - - int account_id = RFIFOL(fd,2); - uint32 login_id1 = RFIFOL(fd,6); - uint32 login_id2 = RFIFOL(fd,10); - uint32 ip = RFIFOL(fd,14); - RFIFOSKIP(fd,18); - - if( runflag != CHARSERVER_ST_RUNNING ) - { - WFIFOHEAD(fd,7); - WFIFOW(fd,0) = 0x2b03; - WFIFOL(fd,2) = account_id; - WFIFOB(fd,6) = 0;// not ok - WFIFOSET(fd,7); - } - else - { - // create temporary auth entry - CREATE(node, struct auth_node, 1); - node->account_id = account_id; - node->char_id = 0; - node->login_id1 = login_id1; - node->login_id2 = login_id2; - //node->sex = 0; - node->ip = ntohl(ip); - //node->expiration_time = 0; // unlimited/unknown time by default (not display in map-server) - //node->gmlevel = 0; - idb_put(auth_db, account_id, node); - - //Set char to "@ char select" in online db [Kevin] - set_char_charselect(account_id); - - WFIFOHEAD(fd,7); - WFIFOW(fd,0) = 0x2b03; - WFIFOL(fd,2) = account_id; - WFIFOB(fd,6) = 1;// ok - WFIFOSET(fd,7); - } - } - break; - - case 0x2b05: // request "change map server" - if (RFIFOREST(fd) < 39) - return 0; - { - int map_id, map_fd = -1; - struct online_char_data* data; - struct mmo_charstatus* char_data; - struct mmo_charstatus char_dat; - - map_id = search_mapserver(RFIFOW(fd,18), ntohl(RFIFOL(fd,24)), ntohs(RFIFOW(fd,28))); //Locate mapserver by ip and port. - if (map_id >= 0) - map_fd = server[map_id].fd; - //Char should just had been saved before this packet, so this should be safe. [Skotlex] - char_data = (struct mmo_charstatus*)uidb_get(char_db_,RFIFOL(fd,14)); - if (char_data == NULL) - { //Really shouldn't happen. - mmo_char_fromsql(RFIFOL(fd,14), &char_dat, true); - char_data = (struct mmo_charstatus*)uidb_get(char_db_,RFIFOL(fd,14)); - } - - if( runflag == CHARSERVER_ST_RUNNING && - session_isActive(map_fd) && - char_data ) - { //Send the map server the auth of this player. - struct auth_node* node; - - //Update the "last map" as this is where the player must be spawned on the new map server. - char_data->last_point.map = RFIFOW(fd,18); - char_data->last_point.x = RFIFOW(fd,20); - char_data->last_point.y = RFIFOW(fd,22); - char_data->sex = RFIFOB(fd,30); - - // create temporary auth entry - CREATE(node, struct auth_node, 1); - node->account_id = RFIFOL(fd,2); - node->char_id = RFIFOL(fd,14); - node->login_id1 = RFIFOL(fd,6); - node->login_id2 = RFIFOL(fd,10); - node->sex = RFIFOB(fd,30); - node->expiration_time = 0; // FIXME (this thing isn't really supported we could as well purge it instead of fixing) - node->ip = ntohl(RFIFOL(fd,31)); - node->gmlevel = RFIFOL(fd,35); - node->changing_mapservers = 1; - idb_put(auth_db, RFIFOL(fd,2), node); - - data = (struct online_char_data*)idb_ensure(online_char_db, RFIFOL(fd,2), create_online_char_data); - data->char_id = char_data->char_id; - data->server = map_id; //Update server where char is. - - //Reply with an ack. - WFIFOHEAD(fd,30); - WFIFOW(fd,0) = 0x2b06; - memcpy(WFIFOP(fd,2), RFIFOP(fd,2), 28); - WFIFOSET(fd,30); - } else { //Reply with nak - WFIFOHEAD(fd,30); - WFIFOW(fd,0) = 0x2b06; - memcpy(WFIFOP(fd,2), RFIFOP(fd,2), 28); - WFIFOL(fd,6) = 0; //Set login1 to 0. - WFIFOSET(fd,30); - } - RFIFOSKIP(fd,35); - } - break; - - case 0x2b07: // Remove RFIFOL(fd,6) (friend_id) from RFIFOL(fd,2) (char_id) friend list [Ind] - if (RFIFOREST(fd) < 10) - return 0; - { - int char_id, friend_id; - char_id = RFIFOL(fd,2); - friend_id = RFIFOL(fd,6); - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d' AND `friend_id`='%d' LIMIT 1", - friend_db, char_id, friend_id) ) { - Sql_ShowDebug(sql_handle); - break; - } - RFIFOSKIP(fd,10); - } - break; - - case 0x2b08: // char name request - if (RFIFOREST(fd) < 6) - return 0; - - WFIFOHEAD(fd,30); - WFIFOW(fd,0) = 0x2b09; - WFIFOL(fd,2) = RFIFOL(fd,2); - char_loadName((int)RFIFOL(fd,2), (char*)WFIFOP(fd,6)); - WFIFOSET(fd,30); - - RFIFOSKIP(fd,6); - break; - - case 0x2b0c: // Map server send information to change an email of an account -> login-server - if (RFIFOREST(fd) < 86) - return 0; - if (login_fd > 0) { // don't send request if no login-server - WFIFOHEAD(login_fd,86); - memcpy(WFIFOP(login_fd,0), RFIFOP(fd,0),86); // 0x2722 .L .40B .40B - WFIFOW(login_fd,0) = 0x2722; - WFIFOSET(login_fd,86); - } - RFIFOSKIP(fd, 86); - break; - - case 0x2b0e: // Request from map-server to change an account's status (will just be forwarded to login server) - if (RFIFOREST(fd) < 44) - return 0; - { - int result = 0; // 0-login-server request done, 1-player not found, 2-gm level too low, 3-login-server offline - char esc_name[NAME_LENGTH*2+1]; - - int acc = RFIFOL(fd,2); // account_id of who ask (-1 if server itself made this request) - const char* name = (char*)RFIFOP(fd,6); // name of the target character - int type = RFIFOW(fd,30); // type of operation: 1-block, 2-ban, 3-unblock, 4-unban - short year = RFIFOW(fd,32); - short month = RFIFOW(fd,34); - short day = RFIFOW(fd,36); - short hour = RFIFOW(fd,38); - short minute = RFIFOW(fd,40); - short second = RFIFOW(fd,42); - RFIFOSKIP(fd,44); - - Sql_EscapeStringLen(sql_handle, esc_name, name, strnlen(name, NAME_LENGTH)); - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id`,`name` FROM `%s` WHERE `name` = '%s'", char_db, esc_name) ) - Sql_ShowDebug(sql_handle); - else - if( Sql_NumRows(sql_handle) == 0 ) - { - result = 1; // 1-player not found - } - else - if( SQL_SUCCESS != Sql_NextRow(sql_handle) ) - Sql_ShowDebug(sql_handle); - //FIXME: set proper result value? - else - { - char name[NAME_LENGTH]; - int account_id; - char* data; - - Sql_GetData(sql_handle, 0, &data, NULL); account_id = atoi(data); - Sql_GetData(sql_handle, 1, &data, NULL); safestrncpy(name, data, sizeof(name)); - - if( login_fd <= 0 ) - result = 3; // 3-login-server offline - //FIXME: need to move this check to login server [ultramage] -// else -// if( acc != -1 && isGM(acc) < isGM(account_id) ) -// result = 2; // 2-gm level too low - else - switch( type ) { - case 1: // block - WFIFOHEAD(login_fd,10); - WFIFOW(login_fd,0) = 0x2724; - WFIFOL(login_fd,2) = account_id; - WFIFOL(login_fd,6) = 5; // new account status - WFIFOSET(login_fd,10); - break; - case 2: // ban - WFIFOHEAD(login_fd,18); - WFIFOW(login_fd, 0) = 0x2725; - WFIFOL(login_fd, 2) = account_id; - WFIFOW(login_fd, 6) = year; - WFIFOW(login_fd, 8) = month; - WFIFOW(login_fd,10) = day; - WFIFOW(login_fd,12) = hour; - WFIFOW(login_fd,14) = minute; - WFIFOW(login_fd,16) = second; - WFIFOSET(login_fd,18); - break; - case 3: // unblock - WFIFOHEAD(login_fd,10); - WFIFOW(login_fd,0) = 0x2724; - WFIFOL(login_fd,2) = account_id; - WFIFOL(login_fd,6) = 0; // new account status - WFIFOSET(login_fd,10); - break; - case 4: // unban - WFIFOHEAD(login_fd,6); - WFIFOW(login_fd,0) = 0x272a; - WFIFOL(login_fd,2) = account_id; - WFIFOSET(login_fd,6); - break; - case 5: // changesex - WFIFOHEAD(login_fd,6); - WFIFOW(login_fd,0) = 0x2727; - WFIFOL(login_fd,2) = account_id; - WFIFOSET(login_fd,6); - break; - } - } - - Sql_FreeResult(sql_handle); - - // send answer if a player ask, not if the server ask - if( acc != -1 && type != 5) { // Don't send answer for changesex - WFIFOHEAD(fd,34); - WFIFOW(fd, 0) = 0x2b0f; - WFIFOL(fd, 2) = acc; - safestrncpy((char*)WFIFOP(fd,6), name, NAME_LENGTH); - WFIFOW(fd,30) = type; - WFIFOW(fd,32) = result; - WFIFOSET(fd,34); - } - } - break; - - case 0x2b10: // Update and send fame ranking list - if (RFIFOREST(fd) < 11) - return 0; - { - int cid = RFIFOL(fd, 2); - int fame = RFIFOL(fd, 6); - char type = RFIFOB(fd, 10); - int size; - struct fame_list* list; - int player_pos; - int fame_pos; - - switch(type) - { - case 1: size = fame_list_size_smith; list = smith_fame_list; break; - case 2: size = fame_list_size_chemist; list = chemist_fame_list; break; - case 3: size = fame_list_size_taekwon; list = taekwon_fame_list; break; - default: size = 0; list = NULL; break; - } - - ARR_FIND(0, size, player_pos, list[player_pos].id == cid);// position of the player - ARR_FIND(0, size, fame_pos, list[fame_pos].fame <= fame);// where the player should be - - if( player_pos == size && fame_pos == size ) - ;// not on list and not enough fame to get on it - else if( fame_pos == player_pos ) - {// same position - list[player_pos].fame = fame; - char_update_fame_list(type, player_pos, fame); - } - else - {// move in the list - if( player_pos == size ) - {// new ranker - not in the list - ARR_MOVE(size - 1, fame_pos, list, struct fame_list); - list[fame_pos].id = cid; - list[fame_pos].fame = fame; - char_loadName(cid, list[fame_pos].name); - } - else - {// already in the list - if( fame_pos == size ) - --fame_pos;// move to the end of the list - ARR_MOVE(player_pos, fame_pos, list, struct fame_list); - list[fame_pos].fame = fame; - } - char_send_fame_list(-1); - } - - RFIFOSKIP(fd,11); - } - break; - - // Divorce chars - case 0x2b11: - if( RFIFOREST(fd) < 10 ) - return 0; - - divorce_char_sql(RFIFOL(fd,2), RFIFOL(fd,6)); - RFIFOSKIP(fd,10); - break; - - case 0x2b16: // Receive rates [Wizputer] - if( RFIFOREST(fd) < 14 ) - return 0; - { - char esc_server_name[sizeof(server_name)*2+1]; - - Sql_EscapeString(sql_handle, esc_server_name, server_name); - - if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `ragsrvinfo` SET `index`='%d',`name`='%s',`exp`='%d',`jexp`='%d',`drop`='%d'", - fd, esc_server_name, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10)) ) - Sql_ShowDebug(sql_handle); - RFIFOSKIP(fd,14); - } - break; - - case 0x2b17: // Character disconnected set online 0 [Wizputer] - if (RFIFOREST(fd) < 6) - return 0; - set_char_offline(RFIFOL(fd,2),RFIFOL(fd,6)); - RFIFOSKIP(fd,10); - break; - - case 0x2b18: // Reset all chars to offline [Wizputer] - set_all_offline(id); - RFIFOSKIP(fd,2); - break; - - case 0x2b19: // Character set online [Wizputer] - if (RFIFOREST(fd) < 10) - return 0; - set_char_online(id, RFIFOL(fd,2),RFIFOL(fd,6)); - RFIFOSKIP(fd,10); - break; - - case 0x2b1a: // Build and send fame ranking lists [DracoRPG] - if (RFIFOREST(fd) < 2) - return 0; - char_read_fame_list(); - char_send_fame_list(-1); - RFIFOSKIP(fd,2); - break; - - case 0x2b1c: //Request to save status change data. [Skotlex] - if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2)) - return 0; - { -#ifdef ENABLE_SC_SAVING - int count, aid, cid; - - aid = RFIFOL(fd, 4); - cid = RFIFOL(fd, 8); - count = RFIFOW(fd, 12); - - if( count > 0 ) - { - struct status_change_data data; - StringBuf buf; - int i; - - StringBuf_Init(&buf); - StringBuf_Printf(&buf, "INSERT INTO `%s` (`account_id`, `char_id`, `type`, `tick`, `val1`, `val2`, `val3`, `val4`) VALUES ", scdata_db); - for( i = 0; i < count; ++i ) - { - memcpy (&data, RFIFOP(fd, 14+i*sizeof(struct status_change_data)), sizeof(struct status_change_data)); - if( i > 0 ) - StringBuf_AppendStr(&buf, ", "); - StringBuf_Printf(&buf, "('%d','%d','%hu','%d','%d','%d','%d','%d')", aid, cid, - data.type, data.tick, data.val1, data.val2, data.val3, data.val4); - } - if( SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf)) ) - Sql_ShowDebug(sql_handle); - StringBuf_Destroy(&buf); - } -#endif - RFIFOSKIP(fd, RFIFOW(fd, 2)); - } - break; - - case 0x2b23: // map-server alive packet - WFIFOHEAD(fd,2); - WFIFOW(fd,0) = 0x2b24; - WFIFOSET(fd,2); - RFIFOSKIP(fd,2); - break; - - case 0x2b26: // auth request from map-server - if (RFIFOREST(fd) < 19) - return 0; - - { - int account_id; - int char_id; - int login_id1; - char sex; - uint32 ip; - struct auth_node* node; - struct mmo_charstatus* cd; - struct mmo_charstatus char_dat; - - account_id = RFIFOL(fd,2); - char_id = RFIFOL(fd,6); - login_id1 = RFIFOL(fd,10); - sex = RFIFOB(fd,14); - ip = ntohl(RFIFOL(fd,15)); - RFIFOSKIP(fd,19); - - node = (struct auth_node*)idb_get(auth_db, account_id); - cd = (struct mmo_charstatus*)uidb_get(char_db_,char_id); - if( cd == NULL ) - { //Really shouldn't happen. - mmo_char_fromsql(char_id, &char_dat, true); - cd = (struct mmo_charstatus*)uidb_get(char_db_,char_id); - } - if( runflag == CHARSERVER_ST_RUNNING && - cd != NULL && - node != NULL && - node->account_id == account_id && - node->char_id == char_id && - node->login_id1 == login_id1 && - node->sex == sex /*&& - node->ip == ip*/ ) - {// auth ok - cd->sex = sex; - - WFIFOHEAD(fd,25 + sizeof(struct mmo_charstatus)); - WFIFOW(fd,0) = 0x2afd; - WFIFOW(fd,2) = 25 + sizeof(struct mmo_charstatus); - WFIFOL(fd,4) = account_id; - WFIFOL(fd,8) = node->login_id1; - WFIFOL(fd,12) = node->login_id2; - WFIFOL(fd,16) = (uint32)node->expiration_time; // FIXME: will wrap to negative after "19-Jan-2038, 03:14:07 AM GMT" - WFIFOL(fd,20) = node->gmlevel; - WFIFOB(fd,24) = node->changing_mapservers; - memcpy(WFIFOP(fd,25), cd, sizeof(struct mmo_charstatus)); - WFIFOSET(fd, WFIFOW(fd,2)); - - // only use the auth once and mark user online - idb_remove(auth_db, account_id); - set_char_online(id, char_id, account_id); - } - else - {// auth failed - WFIFOHEAD(fd,19); - WFIFOW(fd,0) = 0x2b27; - WFIFOL(fd,2) = account_id; - WFIFOL(fd,6) = char_id; - WFIFOL(fd,10) = login_id1; - WFIFOB(fd,14) = sex; - WFIFOL(fd,15) = htonl(ip); - WFIFOSET(fd,19); - } - } - break; - - case 0x2736: // ip address update - if (RFIFOREST(fd) < 6) return 0; - server[id].ip = ntohl(RFIFOL(fd, 2)); - ShowInfo("Updated IP address of map-server #%d to %d.%d.%d.%d.\n", id, CONVIP(server[id].ip)); - RFIFOSKIP(fd,6); - break; - - default: - { - // inter server - packet - int r = inter_parse_frommap(fd); - if (r == 1) break; // processed - if (r == 2) return 0; // need more packet - - // no inter server packet. no char server packet -> disconnect - ShowError("Unknown packet 0x%04x from map server, disconnecting.\n", RFIFOW(fd,0)); - set_eof(fd); - return 0; - } - } // switch - } // while - - return 0; -} - -void do_init_mapif(void) -{ - int i; - for( i = 0; i < ARRAYLENGTH(server); ++i ) - mapif_server_init(i); -} - -void do_final_mapif(void) -{ - int i; - for( i = 0; i < ARRAYLENGTH(server); ++i ) - mapif_server_destroy(i); -} - -// Searches for the mapserver that has a given map (and optionally ip/port, if not -1). -// If found, returns the server's index in the 'server' array (otherwise returns -1). -int search_mapserver(unsigned short map, uint32 ip, uint16 port) -{ - int i, j; - - for(i = 0; i < ARRAYLENGTH(server); i++) - { - if (server[i].fd > 0 - && (ip == (uint32)-1 || server[i].ip == ip) - && (port == (uint16)-1 || server[i].port == port)) - { - for (j = 0; server[i].map[j]; j++) - if (server[i].map[j] == map) - return i; - } - } - - return -1; -} - -// char_mapifの初期化処理(現在はinter_mapif初期化のみ) -static int char_mapif_init(int fd) -{ - return inter_mapif_init(fd); -} - -//-------------------------------------------- -// Test to know if an IP come from LAN or WAN. -//-------------------------------------------- -int lan_subnetcheck(uint32 ip) -{ - int i; - ARR_FIND( 0, subnet_count, i, (subnet[i].char_ip & subnet[i].mask) == (ip & subnet[i].mask) ); - if( i < subnet_count ) { - ShowInfo("Subnet check [%u.%u.%u.%u]: Matches "CL_CYAN"%u.%u.%u.%u/%u.%u.%u.%u"CL_RESET"\n", CONVIP(ip), CONVIP(subnet[i].char_ip & subnet[i].mask), CONVIP(subnet[i].mask)); - return subnet[i].char_ip; - } else { - ShowInfo("Subnet check [%u.%u.%u.%u]: "CL_CYAN"WAN"CL_RESET"\n", CONVIP(ip)); - return 0; - } -} - - -/// @param result -/// 0 (0x718): An unknown error has occurred. -/// 1: none/success -/// 3 (0x719): A database error occurred. -/// 4 (0x71a): To delete a character you must withdraw from the guild. -/// 5 (0x71b): To delete a character you must withdraw from the party. -/// Any (0x718): An unknown error has occurred. -void char_delete2_ack(int fd, int char_id, uint32 result, time_t delete_date) -{// HC: <0828>.W .L .L .L - WFIFOHEAD(fd,14); - WFIFOW(fd,0) = 0x828; - WFIFOL(fd,2) = char_id; - WFIFOL(fd,6) = result; - WFIFOL(fd,10) = TOL(delete_date); - WFIFOSET(fd,14); -} - - -/// @param result -/// 0 (0x718): An unknown error has occurred. -/// 1: none/success -/// 2 (0x71c): Due to system settings can not be deleted. -/// 3 (0x719): A database error occurred. -/// 4 (0x71d): Deleting not yet possible time. -/// 5 (0x71e): Date of birth do not match. -/// Any (0x718): An unknown error has occurred. -void char_delete2_accept_ack(int fd, int char_id, uint32 result) -{// HC: <082a>.W .L .L - WFIFOHEAD(fd,10); - WFIFOW(fd,0) = 0x82a; - WFIFOL(fd,2) = char_id; - WFIFOL(fd,6) = result; - WFIFOSET(fd,10); -} - - -/// @param result -/// 1 (0x718): none/success, (if char id not in deletion process): An unknown error has occurred. -/// 2 (0x719): A database error occurred. -/// Any (0x718): An unknown error has occurred. -void char_delete2_cancel_ack(int fd, int char_id, uint32 result) -{// HC: <082c>.W .L .L - WFIFOHEAD(fd,10); - WFIFOW(fd,0) = 0x82c; - WFIFOL(fd,2) = char_id; - WFIFOL(fd,6) = result; - WFIFOSET(fd,10); -} - - -static void char_delete2_req(int fd, struct char_session_data* sd) -{// CH: <0827>.W .L - int char_id, i, guild_id, party_id; - char* data; - time_t delete_date; - - char_id = RFIFOL(fd,2); - - ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == char_id ); - if( i == MAX_CHARS ) - {// character not found - char_delete2_ack(fd, char_id, 3, 0); - return; - } - - if( SQL_SUCCESS != Sql_Query(sql_handle, "SELECT `guild_id`,`party_id`,`delete_date` FROM `%s` WHERE `char_id`='%d'", char_db, char_id) || SQL_SUCCESS != Sql_NextRow(sql_handle) ) - { - Sql_ShowDebug(sql_handle); - char_delete2_ack(fd, char_id, 3, 0); - return; - } - - Sql_GetData(sql_handle, 0, &data, NULL); guild_id = atoi(data); - Sql_GetData(sql_handle, 1, &data, NULL); party_id = atoi(data); - Sql_GetData(sql_handle, 2, &data, NULL); delete_date = strtoul(data, NULL, 10); - - if( delete_date ) - {// character already queued for deletion - char_delete2_ack(fd, char_id, 0, 0); - return; - } - -/* - // Aegis imposes these checks probably to avoid dead member - // entries in guilds/parties, otherwise they are not required. - // TODO: Figure out how these are enforced during waiting. - if( guild_id ) - {// character in guild - char_delete2_ack(fd, char_id, 4, 0); - return; - } - - if( party_id ) - {// character in party - char_delete2_ack(fd, char_id, 5, 0); - return; - } -*/ - - // success - delete_date = time(NULL)+char_del_delay; - - if( SQL_SUCCESS != Sql_Query(sql_handle, "UPDATE `%s` SET `delete_date`='%lu' WHERE `char_id`='%d'", char_db, (unsigned long)delete_date, char_id) ) - { - Sql_ShowDebug(sql_handle); - char_delete2_ack(fd, char_id, 3, 0); - return; - } - - char_delete2_ack(fd, char_id, 1, delete_date); -} - - -static void char_delete2_accept(int fd, struct char_session_data* sd) -{// CH: <0829>.W .L .6B - char birthdate[8+1]; - int char_id, i, k; - unsigned int base_level; - char* data; - time_t delete_date; - - char_id = RFIFOL(fd,2); - - ShowInfo(CL_RED"Request Char Deletion: "CL_GREEN"%d (%d)"CL_RESET"\n", sd->account_id, char_id); - - // construct "YY-MM-DD" - birthdate[0] = RFIFOB(fd,6); - birthdate[1] = RFIFOB(fd,7); - birthdate[2] = '-'; - birthdate[3] = RFIFOB(fd,8); - birthdate[4] = RFIFOB(fd,9); - birthdate[5] = '-'; - birthdate[6] = RFIFOB(fd,10); - birthdate[7] = RFIFOB(fd,11); - birthdate[8] = 0; - - ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == char_id ); - if( i == MAX_CHARS ) - {// character not found - char_delete2_accept_ack(fd, char_id, 3); - return; - } - - if( SQL_SUCCESS != Sql_Query(sql_handle, "SELECT `base_level`,`delete_date` FROM `%s` WHERE `char_id`='%d'", char_db, char_id) || SQL_SUCCESS != Sql_NextRow(sql_handle) ) - {// data error - Sql_ShowDebug(sql_handle); - char_delete2_accept_ack(fd, char_id, 3); - return; - } - - Sql_GetData(sql_handle, 0, &data, NULL); base_level = (unsigned int)strtoul(data, NULL, 10); - Sql_GetData(sql_handle, 1, &data, NULL); delete_date = strtoul(data, NULL, 10); - - if( !delete_date || delete_date>time(NULL) ) - {// not queued or delay not yet passed - char_delete2_accept_ack(fd, char_id, 4); - return; - } - - if( strcmp(sd->birthdate+2, birthdate) ) // +2 to cut off the century - {// birth date is wrong - char_delete2_accept_ack(fd, char_id, 5); - return; - } - - if( ( char_del_level > 0 && base_level >= (unsigned int)char_del_level ) || ( char_del_level < 0 && base_level <= (unsigned int)(-char_del_level) ) ) - {// character level config restriction - char_delete2_accept_ack(fd, char_id, 2); - return; - } - - // success - if( delete_char_sql(char_id) < 0 ) - { - char_delete2_accept_ack(fd, char_id, 3); - return; - } - - // refresh character list cache - for(k = i; k < MAX_CHARS-1; k++) - { - sd->found_char[k] = sd->found_char[k+1]; - } - sd->found_char[MAX_CHARS-1] = -1; - - char_delete2_accept_ack(fd, char_id, 1); -} - - -static void char_delete2_cancel(int fd, struct char_session_data* sd) -{// CH: <082b>.W .L - int char_id, i; - - char_id = RFIFOL(fd,2); - - ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == char_id ); - if( i == MAX_CHARS ) - {// character not found - char_delete2_cancel_ack(fd, char_id, 2); - return; - } - - // there is no need to check, whether or not the character was - // queued for deletion, as the client prints an error message by - // itself, if it was not the case (@see char_delete2_cancel_ack) - if( SQL_SUCCESS != Sql_Query(sql_handle, "UPDATE `%s` SET `delete_date`='0' WHERE `char_id`='%d'", char_db, char_id) ) - { - Sql_ShowDebug(sql_handle); - char_delete2_cancel_ack(fd, char_id, 2); - return; - } - - char_delete2_cancel_ack(fd, char_id, 1); -} - - -int parse_char(int fd) -{ - int i, ch; - char email[40]; - unsigned short cmd; - int map_fd; - struct char_session_data* sd; - uint32 ipl = session[fd]->client_addr; - - sd = (struct char_session_data*)session[fd]->session_data; - - // disconnect any player if no login-server. - if(login_fd < 0) - set_eof(fd); - - if(session[fd]->flag.eof) - { - if( sd != NULL && sd->auth ) - { // already authed client - struct online_char_data* data = (struct online_char_data*)idb_get(online_char_db, sd->account_id); - if( data != NULL && data->fd == fd) - data->fd = -1; - if( data == NULL || data->server == -1) //If it is not in any server, send it offline. [Skotlex] - set_char_offline(-1,sd->account_id); - } - do_close(fd); - return 0; - } - - while( RFIFOREST(fd) >= 2 ) - { - //For use in packets that depend on an sd being present [Skotlex] - #define FIFOSD_CHECK(rest) { if(RFIFOREST(fd) < rest) return 0; if (sd==NULL || !sd->auth) { RFIFOSKIP(fd,rest); return 0; } } - - cmd = RFIFOW(fd,0); - switch( cmd ) - { - - // request to connect - // 0065 .L .L .L .W .B - case 0x65: - if( RFIFOREST(fd) < 17 ) - return 0; - { - struct auth_node* node; - - int account_id = RFIFOL(fd,2); - uint32 login_id1 = RFIFOL(fd,6); - uint32 login_id2 = RFIFOL(fd,10); - int sex = RFIFOB(fd,16); - RFIFOSKIP(fd,17); - - ShowInfo("request connect - account_id:%d/login_id1:%d/login_id2:%d\n", account_id, login_id1, login_id2); - - if (sd) { - //Received again auth packet for already authentified account?? Discard it. - //TODO: Perhaps log this as a hack attempt? - //TODO: and perhaps send back a reply? - break; - } - - CREATE(session[fd]->session_data, struct char_session_data, 1); - sd = (struct char_session_data*)session[fd]->session_data; - sd->account_id = account_id; - sd->login_id1 = login_id1; - sd->login_id2 = login_id2; - sd->sex = sex; - sd->auth = false; // not authed yet - - // send back account_id - WFIFOHEAD(fd,4); - WFIFOL(fd,0) = account_id; - WFIFOSET(fd,4); - - if( runflag != CHARSERVER_ST_RUNNING ) - { - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x6c; - WFIFOB(fd,2) = 0;// rejected from server - WFIFOSET(fd,3); - break; - } - - // search authentification - node = (struct auth_node*)idb_get(auth_db, account_id); - if( node != NULL && - node->account_id == account_id && - node->login_id1 == login_id1 && - node->login_id2 == login_id2 /*&& - node->ip == ipl*/ ) - {// authentication found (coming from map server) - idb_remove(auth_db, account_id); - char_auth_ok(fd, sd); - } - else - {// authentication not found (coming from login server) - if (login_fd > 0) { // don't send request if no login-server - WFIFOHEAD(login_fd,23); - WFIFOW(login_fd,0) = 0x2712; // ask login-server to authentify an account - WFIFOL(login_fd,2) = sd->account_id; - WFIFOL(login_fd,6) = sd->login_id1; - WFIFOL(login_fd,10) = sd->login_id2; - WFIFOB(login_fd,14) = sd->sex; - WFIFOL(login_fd,15) = htonl(ipl); - WFIFOL(login_fd,19) = fd; - WFIFOSET(login_fd,23); - } else { // if no login-server, we must refuse connection - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x6c; - WFIFOB(fd,2) = 0; - WFIFOSET(fd,3); - } - } - } - break; - - // char select - case 0x66: - FIFOSD_CHECK(3); - { - struct mmo_charstatus char_dat; - struct mmo_charstatus *cd; - char* data; - int char_id; - uint32 subnet_map_ip; - struct auth_node* node; - - int slot = RFIFOB(fd,2); - RFIFOSKIP(fd,3); - - if ( SQL_SUCCESS != Sql_Query(sql_handle, "SELECT `char_id` FROM `%s` WHERE `account_id`='%d' AND `char_num`='%d'", char_db, sd->account_id, slot) - || SQL_SUCCESS != Sql_NextRow(sql_handle) - || SQL_SUCCESS != Sql_GetData(sql_handle, 0, &data, NULL) ) - { //Not found?? May be forged packet. - Sql_ShowDebug(sql_handle); - Sql_FreeResult(sql_handle); - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x6c; - WFIFOB(fd,2) = 0; // rejected from server - WFIFOSET(fd,3); - break; - } - - char_id = atoi(data); - Sql_FreeResult(sql_handle); - mmo_char_fromsql(char_id, &char_dat, true); - - //Have to switch over to the DB instance otherwise data won't propagate [Kevin] - cd = (struct mmo_charstatus *)idb_get(char_db_, char_id); - cd->sex = sd->sex; - - if (log_char) { - char esc_name[NAME_LENGTH*2+1]; - - Sql_EscapeStringLen(sql_handle, esc_name, char_dat.name, strnlen(char_dat.name, NAME_LENGTH)); - if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s`(`time`, `account_id`,`char_num`,`name`) VALUES (NOW(), '%d', '%d', '%s')", - charlog_db, sd->account_id, slot, esc_name) ) - Sql_ShowDebug(sql_handle); - } - ShowInfo("Selected char: (Account %d: %d - %s)\n", sd->account_id, slot, char_dat.name); - - // searching map server - i = search_mapserver(cd->last_point.map, -1, -1); - - // if map is not found, we check major cities - if (i < 0) { - unsigned short j; - //First check that there's actually a map server online. - ARR_FIND( 0, ARRAYLENGTH(server), j, server[j].fd >= 0 && server[j].map[0] ); - if (j == ARRAYLENGTH(server)) { - ShowInfo("Connection Closed. No map servers available.\n"); - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x81; - WFIFOB(fd,2) = 1; // 01 = Server closed - WFIFOSET(fd,3); - break; - } - if ((i = search_mapserver((j=mapindex_name2id(MAP_PRONTERA)),-1,-1)) >= 0) { - cd->last_point.x = 273; - cd->last_point.y = 354; - } else if ((i = search_mapserver((j=mapindex_name2id(MAP_GEFFEN)),-1,-1)) >= 0) { - cd->last_point.x = 120; - cd->last_point.y = 100; - } else if ((i = search_mapserver((j=mapindex_name2id(MAP_MORROC)),-1,-1)) >= 0) { - cd->last_point.x = 160; - cd->last_point.y = 94; - } else if ((i = search_mapserver((j=mapindex_name2id(MAP_ALBERTA)),-1,-1)) >= 0) { - cd->last_point.x = 116; - cd->last_point.y = 57; - } else if ((i = search_mapserver((j=mapindex_name2id(MAP_PAYON)),-1,-1)) >= 0) { - cd->last_point.x = 87; - cd->last_point.y = 117; - } else if ((i = search_mapserver((j=mapindex_name2id(MAP_IZLUDE)),-1,-1)) >= 0) { - cd->last_point.x = 94; - cd->last_point.y = 103; - } else { - ShowInfo("Connection Closed. No map server available that has a major city, and unable to find map-server for '%s'.\n", mapindex_id2name(cd->last_point.map)); - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x81; - WFIFOB(fd,2) = 1; // 01 = Server closed - WFIFOSET(fd,3); - break; - } - ShowWarning("Unable to find map-server for '%s', sending to major city '%s'.\n", mapindex_id2name(cd->last_point.map), mapindex_id2name(j)); - cd->last_point.map = j; - } - - //Send NEW auth packet [Kevin] - //FIXME: is this case even possible? [ultramage] - if ((map_fd = server[i].fd) < 1 || session[map_fd] == NULL) - { - ShowError("parse_char: Attempting to write to invalid session %d! Map Server #%d disconnected.\n", map_fd, i); - server[i].fd = -1; - memset(&server[i], 0, sizeof(struct mmo_map_server)); - //Send server closed. - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x81; - WFIFOB(fd,2) = 1; // 01 = Server closed - WFIFOSET(fd,3); - break; - } - - //Send player to map - WFIFOHEAD(fd,28); - WFIFOW(fd,0) = 0x71; - WFIFOL(fd,2) = cd->char_id; - mapindex_getmapname_ext(mapindex_id2name(cd->last_point.map), (char*)WFIFOP(fd,6)); - subnet_map_ip = lan_subnetcheck(ipl); // Advanced subnet check [LuzZza] - WFIFOL(fd,22) = htonl((subnet_map_ip) ? subnet_map_ip : server[i].ip); - WFIFOW(fd,26) = ntows(htons(server[i].port)); // [!] LE byte order here [!] - WFIFOSET(fd,28); - - // create temporary auth entry - CREATE(node, struct auth_node, 1); - node->account_id = sd->account_id; - node->char_id = cd->char_id; - node->login_id1 = sd->login_id1; - node->login_id2 = sd->login_id2; - node->sex = sd->sex; - node->expiration_time = sd->expiration_time; - node->gmlevel = sd->gmlevel; - node->ip = ipl; - idb_put(auth_db, sd->account_id, node); - - set_char_online(-2,node->char_id,sd->account_id); - - } - break; - - // create new char - // S 0067 .24B .B .B .B .B .B .B .B .W .W - case 0x67: - FIFOSD_CHECK(37); - - if( !char_new ) //turn character creation on/off [Kevin] - i = -2; - else - i = make_new_char_sql(sd, (char*)RFIFOP(fd,2),RFIFOB(fd,26),RFIFOB(fd,27),RFIFOB(fd,28),RFIFOB(fd,29),RFIFOB(fd,30),RFIFOB(fd,31),RFIFOB(fd,32),RFIFOW(fd,33),RFIFOW(fd,35)); - - //'Charname already exists' (-1), 'Char creation denied' (-2) and 'You are underaged' (-3) - if (i < 0) - { - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x6e; - switch (i) { - case -1: WFIFOB(fd,2) = 0x00; break; - case -2: WFIFOB(fd,2) = 0xFF; break; - case -3: WFIFOB(fd,2) = 0x01; break; - } - WFIFOSET(fd,3); - } - else - { - int len; - // retrieve data - struct mmo_charstatus char_dat; - mmo_char_fromsql(i, &char_dat, false); //Only the short data is needed. - - // send to player - WFIFOHEAD(fd,2+MAX_CHAR_BUF); - WFIFOW(fd,0) = 0x6d; - len = 2 + mmo_char_tobuf(WFIFOP(fd,2), &char_dat); - WFIFOSET(fd,len); - - // add new entry to the chars list - ARR_FIND( 0, MAX_CHARS, ch, sd->found_char[ch] == -1 ); - if( ch < MAX_CHARS ) - sd->found_char[ch] = i; // the char_id of the new char - } - - RFIFOSKIP(fd,37); - break; - - // delete char - case 0x68: - // 2004-04-19aSakexe+ langtype 12 char deletion packet - case 0x1fb: - if (cmd == 0x68) FIFOSD_CHECK(46); - if (cmd == 0x1fb) FIFOSD_CHECK(56); - { - int cid = RFIFOL(fd,2); - - ShowInfo(CL_RED"Request Char Deletion: "CL_GREEN"%d (%d)"CL_RESET"\n", sd->account_id, cid); - memcpy(email, RFIFOP(fd,6), 40); - RFIFOSKIP(fd,( cmd == 0x68) ? 46 : 56); - - // Check if e-mail is correct - if(strcmpi(email, sd->email) && //email does not matches and - ( - strcmp("a@a.com", sd->email) || //it is not default email, or - (strcmp("a@a.com", email) && strcmp("", email)) //email sent does not matches default - )) { //Fail - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x70; - WFIFOB(fd,2) = 0; // 00 = Incorrect Email address - WFIFOSET(fd,3); - break; - } - - // check if this char exists - ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == cid ); - if( i == MAX_CHARS ) - { // Such a character does not exist in the account - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x70; - WFIFOB(fd,2) = 0; - WFIFOSET(fd,3); - break; - } - - // remove char from list and compact it - for(ch = i; ch < MAX_CHARS-1; ch++) - sd->found_char[ch] = sd->found_char[ch+1]; - sd->found_char[MAX_CHARS-1] = -1; - - /* Delete character */ - if(delete_char_sql(cid)<0){ - //can't delete the char - //either SQL error or can't delete by some CONFIG conditions - //del fail - WFIFOHEAD(fd,3); - WFIFOW(fd, 0) = 0x70; - WFIFOB(fd, 2) = 0; - WFIFOSET(fd, 3); - break; - } - /* Char successfully deleted.*/ - WFIFOHEAD(fd,2); - WFIFOW(fd,0) = 0x6f; - WFIFOSET(fd,2); - } - break; - - // client keep-alive packet (every 12 seconds) - // R 0187 .l - case 0x187: - if (RFIFOREST(fd) < 6) - return 0; - RFIFOSKIP(fd,6); - break; - - // char rename request - // R 028d .l .l .24B - case 0x28d: - FIFOSD_CHECK(34); - { - int i, aid = RFIFOL(fd,2), cid =RFIFOL(fd,6); - char name[NAME_LENGTH]; - char esc_name[NAME_LENGTH*2+1]; - safestrncpy(name, (char *)RFIFOP(fd,10), NAME_LENGTH); - RFIFOSKIP(fd,34); - - if( aid != sd->account_id ) - break; - ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == cid ); - if( i == MAX_CHARS ) - break; - - normalize_name(name,TRIM_CHARS); - Sql_EscapeStringLen(sql_handle, esc_name, name, strnlen(name, NAME_LENGTH)); - if( !check_char_name(name,esc_name) ) - { - i = 1; - safestrncpy(sd->new_name, name, NAME_LENGTH); - } - else - i = 0; - - WFIFOHEAD(fd, 4); - WFIFOW(fd,0) = 0x28e; - WFIFOW(fd,2) = i; - WFIFOSET(fd,4); - } - break; - //Confirm change name. - // 0x28f .L - case 0x28f: - // 0: Sucessfull - // 1: This character's name has already been changed. You cannot change a character's name more than once. - // 2: User information is not correct. - // 3: You have failed to change this character's name. - // 4: Another user is using this character name, so please select another one. - FIFOSD_CHECK(6); - { - int i; - int cid = RFIFOL(fd,2); - RFIFOSKIP(fd,6); - - ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == cid ); - if( i == MAX_CHARS ) - break; - i = rename_char_sql(sd, cid); - - WFIFOHEAD(fd, 4); - WFIFOW(fd,0) = 0x290; - WFIFOW(fd,2) = i; - WFIFOSET(fd,4); - } - break; - - // captcha code request (not implemented) - // R 07e5 .w .l - case 0x7e5: - WFIFOHEAD(fd,5); - WFIFOW(fd,0) = 0x7e9; - WFIFOW(fd,2) = 5; - WFIFOB(fd,4) = 1; - WFIFOSET(fd,5); - RFIFOSKIP(fd,8); - break; - - // captcha code check (not implemented) - // R 07e7 .w .l .b10 .b14 - case 0x7e7: - WFIFOHEAD(fd,5); - WFIFOW(fd,0) = 0x7e9; - WFIFOW(fd,2) = 5; - WFIFOB(fd,4) = 1; - WFIFOSET(fd,5); - RFIFOSKIP(fd,32); - break; - - // deletion timer request - case 0x827: - FIFOSD_CHECK(6); - char_delete2_req(fd, sd); - RFIFOSKIP(fd,6); - break; - - // deletion accept request - case 0x829: - FIFOSD_CHECK(12); - char_delete2_accept(fd, sd); - RFIFOSKIP(fd,12); - break; - - // deletion cancel request - case 0x82b: - FIFOSD_CHECK(6); - char_delete2_cancel(fd, sd); - RFIFOSKIP(fd,6); - break; - - // login as map-server - case 0x2af8: - if (RFIFOREST(fd) < 60) - return 0; - { - char* l_user = (char*)RFIFOP(fd,2); - char* l_pass = (char*)RFIFOP(fd,26); - l_user[23] = '\0'; - l_pass[23] = '\0'; - ARR_FIND( 0, ARRAYLENGTH(server), i, server[i].fd <= 0 ); - if( runflag != CHARSERVER_ST_RUNNING || - i == ARRAYLENGTH(server) || - strcmp(l_user, userid) != 0 || - strcmp(l_pass, passwd) != 0 ) - { - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x2af9; - WFIFOB(fd,2) = 3; - WFIFOSET(fd,3); - } else { - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x2af9; - WFIFOB(fd,2) = 0; - WFIFOSET(fd,3); - - server[i].fd = fd; - server[i].ip = ntohl(RFIFOL(fd,54)); - server[i].port = ntohs(RFIFOW(fd,58)); - server[i].users = 0; - memset(server[i].map, 0, sizeof(server[i].map)); - session[fd]->func_parse = parse_frommap; - session[fd]->flag.server = 1; - realloc_fifo(fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK); - char_mapif_init(fd); - } - - RFIFOSKIP(fd,60); - } - return 0; // avoid processing of followup packets here - - // unknown packet received - default: - ShowError("parse_char: Received unknown packet "CL_WHITE"0x%x"CL_RESET" from ip '"CL_WHITE"%s"CL_RESET"'! Disconnecting!\n", RFIFOW(fd,0), ip2str(ipl, NULL)); - set_eof(fd); - return 0; - } - } - - RFIFOFLUSH(fd); - return 0; -} - -// Console Command Parser [Wizputer] -int parse_console(const char* command) -{ - ShowNotice("Console command: %s\n", command); - - if( strcmpi("shutdown", command) == 0 || strcmpi("exit", command) == 0 || strcmpi("quit", command) == 0 || strcmpi("end", command) == 0 ) - runflag = 0; - else if( strcmpi("alive", command) == 0 || strcmpi("status", command) == 0 ) - ShowInfo(CL_CYAN"Console: "CL_BOLD"I'm Alive."CL_RESET"\n"); - else if( strcmpi("help", command) == 0 ) - { - ShowInfo("To shutdown the server:\n"); - ShowInfo(" 'shutdown|exit|quit|end'\n"); - ShowInfo("To know if server is alive:\n"); - ShowInfo(" 'alive|status'\n"); - } - - return 0; -} - -int mapif_sendall(unsigned char *buf, unsigned int len) -{ - int i, c; - - c = 0; - for(i = 0; i < ARRAYLENGTH(server); i++) { - int fd; - if ((fd = server[i].fd) > 0) { - WFIFOHEAD(fd,len); - memcpy(WFIFOP(fd,0), buf, len); - WFIFOSET(fd,len); - c++; - } - } - - return c; -} - -int mapif_sendallwos(int sfd, unsigned char *buf, unsigned int len) -{ - int i, c; - - c = 0; - for(i = 0; i < ARRAYLENGTH(server); i++) { - int fd; - if ((fd = server[i].fd) > 0 && fd != sfd) { - WFIFOHEAD(fd,len); - memcpy(WFIFOP(fd,0), buf, len); - WFIFOSET(fd,len); - c++; - } - } - - return c; -} - -int mapif_send(int fd, unsigned char *buf, unsigned int len) -{ - int i; - - if (fd >= 0) { - ARR_FIND( 0, ARRAYLENGTH(server), i, fd == server[i].fd ); - if( i < ARRAYLENGTH(server) ) - { - WFIFOHEAD(fd,len); - memcpy(WFIFOP(fd,0), buf, len); - WFIFOSET(fd,len); - return 1; - } - } - return 0; -} - -int broadcast_user_count(int tid, unsigned int tick, int id, intptr_t data) -{ - uint8 buf[6]; - int users = count_users(); - - // only send an update when needed - static int prev_users = 0; - if( prev_users == users ) - return 0; - prev_users = users; - - if( login_fd > 0 && session[login_fd] ) - { - // send number of user to login server - WFIFOHEAD(login_fd,6); - WFIFOW(login_fd,0) = 0x2714; - WFIFOL(login_fd,2) = users; - WFIFOSET(login_fd,6); - } - - // send number of players to all map-servers - WBUFW(buf,0) = 0x2b00; - WBUFL(buf,2) = users; - mapif_sendall(buf,6); - - return 0; -} - -/// load this char's account id into the 'online accounts' packet -static int send_accounts_tologin_sub(DBKey key, void* data, va_list ap) -{ - struct online_char_data* character = (struct online_char_data*)data; - int* i = va_arg(ap, int*); - - if(character->server > -1) - { - WFIFOL(login_fd,8+(*i)*4) = character->account_id; - (*i)++; - return 1; - } - return 0; -} - -int send_accounts_tologin(int tid, unsigned int tick, int id, intptr_t data) -{ - if (login_fd > 0 && session[login_fd]) - { - // send account list to login server - int users = online_char_db->size(online_char_db); - int i = 0; - - WFIFOHEAD(login_fd,8+users*4); - WFIFOW(login_fd,0) = 0x272d; - online_char_db->foreach(online_char_db, send_accounts_tologin_sub, &i, users); - WFIFOW(login_fd,2) = 8+ i*4; - WFIFOL(login_fd,4) = i; - WFIFOSET(login_fd,WFIFOW(login_fd,2)); - } - return 0; -} - -int check_connect_login_server(int tid, unsigned int tick, int id, intptr_t data) -{ - if (login_fd > 0 && session[login_fd] != NULL) - return 0; - - ShowInfo("Attempt to connect to login-server...\n"); - login_fd = make_connection(login_ip, login_port); - if (login_fd == -1) - { //Try again later. [Skotlex] - login_fd = 0; - return 0; - } - session[login_fd]->func_parse = parse_fromlogin; - session[login_fd]->flag.server = 1; - realloc_fifo(login_fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK); - - WFIFOHEAD(login_fd,86); - WFIFOW(login_fd,0) = 0x2710; - memcpy(WFIFOP(login_fd,2), userid, 24); - memcpy(WFIFOP(login_fd,26), passwd, 24); - WFIFOL(login_fd,50) = 0; - WFIFOL(login_fd,54) = htonl(char_ip); - WFIFOW(login_fd,58) = htons(char_port); - memcpy(WFIFOP(login_fd,60), server_name, 20); - WFIFOW(login_fd,80) = 0; - WFIFOW(login_fd,82) = char_maintenance; - WFIFOW(login_fd,84) = char_new_display; //only display (New) if they want to [Kevin] - WFIFOSET(login_fd,86); - - return 1; -} - -// sends a ping packet to login server (will receive pong 0x2718) -int ping_login_server(int tid, unsigned int tick, int id, intptr_t data) -{ - if (login_fd > 0 && session[login_fd] != NULL) - { - WFIFOHEAD(login_fd,2); - WFIFOW(login_fd,0) = 0x2719; - WFIFOSET(login_fd,2); - } - return 0; -} - -//------------------------------------------------ -//Invoked 15 seconds after mapif_disconnectplayer in case the map server doesn't -//replies/disconnect the player we tried to kick. [Skotlex] -//------------------------------------------------ -static int chardb_waiting_disconnect(int tid, unsigned int tick, int id, intptr_t data) -{ - struct online_char_data* character; - if ((character = (struct online_char_data*)idb_get(online_char_db, id)) != NULL && character->waiting_disconnect == tid) - { //Mark it offline due to timeout. - character->waiting_disconnect = INVALID_TIMER; - set_char_offline(character->char_id, character->account_id); - } - return 0; -} - -static int online_data_cleanup_sub(DBKey key, void *data, va_list ap) -{ - struct online_char_data *character= (struct online_char_data*)data; - if (character->fd != -1) - return 0; //Character still connected - if (character->server == -2) //Unknown server.. set them offline - set_char_offline(character->char_id, character->account_id); - if (character->server < 0) - //Free data from players that have not been online for a while. - db_remove(online_char_db, key); - return 0; -} - -static int online_data_cleanup(int tid, unsigned int tick, int id, intptr_t data) -{ - online_char_db->foreach(online_char_db, online_data_cleanup_sub); - return 0; -} - -//---------------------------------- -// Reading Lan Support configuration -// Rewrote: Anvanced subnet check [LuzZza] -//---------------------------------- -int char_lan_config_read(const char *lancfgName) -{ - FILE *fp; - int line_num = 0; - char line[1024], w1[64], w2[64], w3[64], w4[64]; - - if((fp = fopen(lancfgName, "r")) == NULL) { - ShowWarning("LAN Support configuration file is not found: %s\n", lancfgName); - return 1; - } - - ShowInfo("Reading the configuration file %s...\n", lancfgName); - - while(fgets(line, sizeof(line), fp)) - { - line_num++; - if ((line[0] == '/' && line[1] == '/') || line[0] == '\n' || line[1] == '\n') - continue; - - if(sscanf(line,"%[^:]: %[^:]:%[^:]:%[^\r\n]", w1, w2, w3, w4) != 4) { - - ShowWarning("Error syntax of configuration file %s in line %d.\n", lancfgName, line_num); - continue; - } - - remove_control_chars(w1); - remove_control_chars(w2); - remove_control_chars(w3); - remove_control_chars(w4); - - if( strcmpi(w1, "subnet") == 0 ) - { - subnet[subnet_count].mask = str2ip(w2); - subnet[subnet_count].char_ip = str2ip(w3); - subnet[subnet_count].map_ip = str2ip(w4); - - if( (subnet[subnet_count].char_ip & subnet[subnet_count].mask) != (subnet[subnet_count].map_ip & subnet[subnet_count].mask) ) - { - ShowError("%s: Configuration Error: The char server (%s) and map server (%s) belong to different subnetworks!\n", lancfgName, w3, w4); - continue; - } - - subnet_count++; - } - } - - ShowStatus("Read information about %d subnetworks.\n", subnet_count); - - fclose(fp); - return 0; -} -#endif //TXT_SQL_CONVERT - -void sql_config_read(const char* cfgName) -{ - char line[1024], w1[1024], w2[1024]; - FILE* fp; - - ShowInfo("Reading file %s...\n", cfgName); - - if ((fp = fopen(cfgName, "r")) == NULL) { - ShowError("file not found: %s\n", cfgName); - return; - } - - while(fgets(line, sizeof(line), fp)) - { - if(line[0] == '/' && line[1] == '/') - continue; - - if (sscanf(line, "%[^:]: %[^\r\n]", w1, w2) != 2) - continue; - - if(!strcmpi(w1,"char_db")) - safestrncpy(char_db, w2, sizeof(char_db)); - else if(!strcmpi(w1,"scdata_db")) - safestrncpy(scdata_db, w2, sizeof(scdata_db)); - else if(!strcmpi(w1,"cart_db")) - safestrncpy(cart_db, w2, sizeof(cart_db)); - else if(!strcmpi(w1,"inventory_db")) - safestrncpy(inventory_db, w2, sizeof(inventory_db)); - else if(!strcmpi(w1,"charlog_db")) - safestrncpy(charlog_db, w2, sizeof(charlog_db)); - else if(!strcmpi(w1,"storage_db")) - safestrncpy(storage_db, w2, sizeof(storage_db)); - else if(!strcmpi(w1,"reg_db")) - safestrncpy(reg_db, w2, sizeof(reg_db)); - else if(!strcmpi(w1,"skill_db")) - safestrncpy(skill_db, w2, sizeof(skill_db)); - else if(!strcmpi(w1,"interlog_db")) - safestrncpy(interlog_db, w2, sizeof(interlog_db)); - else if(!strcmpi(w1,"memo_db")) - safestrncpy(memo_db, w2, sizeof(memo_db)); - else if(!strcmpi(w1,"guild_db")) - safestrncpy(guild_db, w2, sizeof(guild_db)); - else if(!strcmpi(w1,"guild_alliance_db")) - safestrncpy(guild_alliance_db, w2, sizeof(guild_alliance_db)); - else if(!strcmpi(w1,"guild_castle_db")) - safestrncpy(guild_castle_db, w2, sizeof(guild_castle_db)); - else if(!strcmpi(w1,"guild_expulsion_db")) - safestrncpy(guild_expulsion_db, w2, sizeof(guild_expulsion_db)); - else if(!strcmpi(w1,"guild_member_db")) - safestrncpy(guild_member_db, w2, sizeof(guild_member_db)); - else if(!strcmpi(w1,"guild_skill_db")) - safestrncpy(guild_skill_db, w2, sizeof(guild_skill_db)); - else if(!strcmpi(w1,"guild_position_db")) - safestrncpy(guild_position_db, w2, sizeof(guild_position_db)); - else if(!strcmpi(w1,"guild_storage_db")) - safestrncpy(guild_storage_db, w2, sizeof(guild_storage_db)); - else if(!strcmpi(w1,"party_db")) - safestrncpy(party_db, w2, sizeof(party_db)); - else if(!strcmpi(w1,"pet_db")) - safestrncpy(pet_db, w2, sizeof(pet_db)); - else if(!strcmpi(w1,"mail_db")) - safestrncpy(mail_db, w2, sizeof(mail_db)); - else if(!strcmpi(w1,"auction_db")) - safestrncpy(auction_db, w2, sizeof(auction_db)); - else if(!strcmpi(w1,"friend_db")) - safestrncpy(friend_db, w2, sizeof(friend_db)); - else if(!strcmpi(w1,"hotkey_db")) - safestrncpy(hotkey_db, w2, sizeof(hotkey_db)); - else if(!strcmpi(w1,"quest_db")) - safestrncpy(quest_db,w2,sizeof(quest_db)); - //support the import command, just like any other config - else if(!strcmpi(w1,"import")) - sql_config_read(w2); - } - fclose(fp); - ShowInfo("Done reading %s.\n", cfgName); -} -#ifndef TXT_SQL_CONVERT - -int char_config_read(const char* cfgName) -{ - char line[1024], w1[1024], w2[1024]; - FILE* fp = fopen(cfgName, "r"); - - if (fp == NULL) { - ShowError("Configuration file not found: %s.\n", cfgName); - return 1; - } - - ShowInfo("Reading configuration file %s...\n", cfgName); - while(fgets(line, sizeof(line), fp)) - { - if (line[0] == '/' && line[1] == '/') - continue; - - if (sscanf(line, "%[^:]: %[^\r\n]", w1, w2) != 2) - continue; - - remove_control_chars(w1); - remove_control_chars(w2); - if(strcmpi(w1,"timestamp_format") == 0) { - safestrncpy(timestamp_format, w2, sizeof(timestamp_format)); - } else if(strcmpi(w1,"console_silent")==0){ - ShowInfo("Console Silent Setting: %d\n", atoi(w2)); - msg_silent = atoi(w2); - } else if(strcmpi(w1,"stdout_with_ansisequence")==0){ - stdout_with_ansisequence = config_switch(w2); - } else if (strcmpi(w1, "userid") == 0) { - safestrncpy(userid, w2, sizeof(userid)); - } else if (strcmpi(w1, "passwd") == 0) { - safestrncpy(passwd, w2, sizeof(passwd)); - } else if (strcmpi(w1, "server_name") == 0) { - safestrncpy(server_name, w2, sizeof(server_name)); - ShowStatus("%s server has been initialized\n", w2); - } else if (strcmpi(w1, "wisp_server_name") == 0) { - if (strlen(w2) >= 4) { - safestrncpy(wisp_server_name, w2, sizeof(wisp_server_name)); - } - } else if (strcmpi(w1, "login_ip") == 0) { - char ip_str[16]; - login_ip = host2ip(w2); - if (login_ip) { - safestrncpy(login_ip_str, w2, sizeof(login_ip_str)); - ShowStatus("Login server IP address : %s -> %s\n", w2, ip2str(login_ip, ip_str)); - } - } else if (strcmpi(w1, "login_port") == 0) { - login_port = atoi(w2); - } else if (strcmpi(w1, "char_ip") == 0) { - char ip_str[16]; - char_ip = host2ip(w2); - if (char_ip){ - safestrncpy(char_ip_str, w2, sizeof(char_ip_str)); - ShowStatus("Character server IP address : %s -> %s\n", w2, ip2str(char_ip, ip_str)); - } - } else if (strcmpi(w1, "bind_ip") == 0) { - char ip_str[16]; - bind_ip = host2ip(w2); - if (bind_ip) { - safestrncpy(bind_ip_str, w2, sizeof(bind_ip_str)); - ShowStatus("Character server binding IP address : %s -> %s\n", w2, ip2str(bind_ip, ip_str)); - } - } else if (strcmpi(w1, "char_port") == 0) { - char_port = atoi(w2); - } else if (strcmpi(w1, "char_maintenance") == 0) { - char_maintenance = atoi(w2); - } else if (strcmpi(w1, "char_new") == 0) { - char_new = (bool)atoi(w2); - } else if (strcmpi(w1, "char_new_display") == 0) { - char_new_display = atoi(w2); - } else if (strcmpi(w1, "max_connect_user") == 0) { - max_connect_user = atoi(w2); - if (max_connect_user < 0) - max_connect_user = 0; // unlimited online players - } else if(strcmpi(w1, "gm_allow_level") == 0) { - gm_allow_level = atoi(w2); - if(gm_allow_level < 0) - gm_allow_level = 99; - } else if (strcmpi(w1, "autosave_time") == 0) { - autosave_interval = atoi(w2)*1000; - if (autosave_interval <= 0) - autosave_interval = DEFAULT_AUTOSAVE_INTERVAL; - } else if (strcmpi(w1, "save_log") == 0) { - save_log = config_switch(w2); - } else if (strcmpi(w1, "start_point") == 0) { - char map[MAP_NAME_LENGTH_EXT]; - int x, y; - if (sscanf(w2, "%15[^,],%d,%d", map, &x, &y) < 3) - continue; - start_point.map = mapindex_name2id(map); - if (!start_point.map) - ShowError("Specified start_point %s not found in map-index cache.\n", map); - start_point.x = x; - start_point.y = y; - } else if (strcmpi(w1, "start_zeny") == 0) { - start_zeny = atoi(w2); - if (start_zeny < 0) - start_zeny = 0; - } else if (strcmpi(w1, "start_weapon") == 0) { - start_weapon = atoi(w2); - if (start_weapon < 0) - start_weapon = 0; - } else if (strcmpi(w1, "start_armor") == 0) { - start_armor = atoi(w2); - if (start_armor < 0) - start_armor = 0; - } else if(strcmpi(w1,"log_char")==0) { //log char or not [devil] - log_char = atoi(w2); - } else if (strcmpi(w1, "unknown_char_name") == 0) { - safestrncpy(unknown_char_name, w2, sizeof(unknown_char_name)); - unknown_char_name[NAME_LENGTH-1] = '\0'; - } else if (strcmpi(w1, "name_ignoring_case") == 0) { - name_ignoring_case = (bool)config_switch(w2); - } else if (strcmpi(w1, "char_name_option") == 0) { - char_name_option = atoi(w2); - } else if (strcmpi(w1, "char_name_letters") == 0) { - safestrncpy(char_name_letters, w2, sizeof(char_name_letters)); - } else if (strcmpi(w1, "chars_per_account") == 0) { //maxchars per account [Sirius] - char_per_account = atoi(w2); - } else if (strcmpi(w1, "char_del_level") == 0) { //disable/enable char deletion by its level condition [Lupus] - char_del_level = atoi(w2); - } else if (strcmpi(w1, "char_del_delay") == 0) { - char_del_delay = atoi(w2); - } else if(strcmpi(w1,"db_path")==0) { - safestrncpy(db_path, w2, sizeof(db_path)); - } else if (strcmpi(w1, "console") == 0) { - console = config_switch(w2); - } else if (strcmpi(w1, "fame_list_alchemist") == 0) { - fame_list_size_chemist = atoi(w2); - if (fame_list_size_chemist > MAX_FAME_LIST) { - ShowWarning("Max fame list size is %d (fame_list_alchemist)\n", MAX_FAME_LIST); - fame_list_size_chemist = MAX_FAME_LIST; - } - } else if (strcmpi(w1, "fame_list_blacksmith") == 0) { - fame_list_size_smith = atoi(w2); - if (fame_list_size_smith > MAX_FAME_LIST) { - ShowWarning("Max fame list size is %d (fame_list_blacksmith)\n", MAX_FAME_LIST); - fame_list_size_smith = MAX_FAME_LIST; - } - } else if (strcmpi(w1, "fame_list_taekwon") == 0) { - fame_list_size_taekwon = atoi(w2); - if (fame_list_size_taekwon > MAX_FAME_LIST) { - ShowWarning("Max fame list size is %d (fame_list_taekwon)\n", MAX_FAME_LIST); - fame_list_size_taekwon = MAX_FAME_LIST; - } - } else if (strcmpi(w1, "guild_exp_rate") == 0) { - guild_exp_rate = atoi(w2); - } else if (strcmpi(w1, "import") == 0) { - char_config_read(w2); - } - } - fclose(fp); - - ShowInfo("Done reading %s.\n", cfgName); - return 0; -} - -void do_final(void) -{ - ShowStatus("Terminating...\n"); - - set_all_offline(-1); - set_all_offline_sql(); - - inter_final(); - - flush_fifos(); - - do_final_mapif(); - do_final_loginif(); - - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `ragsrvinfo`") ) - Sql_ShowDebug(sql_handle); - - char_db_->destroy(char_db_, NULL); - online_char_db->destroy(online_char_db, NULL); - auth_db->destroy(auth_db, NULL); - - if( char_fd != -1 ) - { - do_close(char_fd); - char_fd = -1; - } - - Sql_Free(sql_handle); - mapindex_final(); - - ShowStatus("Finished.\n"); -} - -//------------------------------ -// Function called when the server -// has received a crash signal. -//------------------------------ -void do_abort(void) -{ -} - -void set_server_type(void) -{ - SERVER_TYPE = ATHENA_SERVER_CHAR; -} - - -/// Called when a terminate signal is received. -void do_shutdown(void) -{ - if( runflag != CHARSERVER_ST_SHUTDOWN ) - { - int id; - runflag = CHARSERVER_ST_SHUTDOWN; - ShowStatus("Shutting down...\n"); - // TODO proper shutdown procedure; wait for acks?, kick all characters, ... [FlavoJS] - for( id = 0; id < ARRAYLENGTH(server); ++id ) - mapif_server_reset(id); - loginif_check_shutdown(); - flush_fifos(); - runflag = CORE_ST_STOP; - } -} - - -int do_init(int argc, char **argv) -{ - //Read map indexes - mapindex_init(); - start_point.map = mapindex_name2id("new_zone01"); - - char_config_read((argc < 2) ? CHAR_CONF_NAME : argv[1]); - char_lan_config_read((argc > 3) ? argv[3] : LAN_CONF_NAME); - sql_config_read(SQL_CONF_NAME); - - if (strcmp(userid, "s1")==0 && strcmp(passwd, "p1")==0) { - ShowError("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 change the user/password to use in conf/char_athena.conf (or conf/import/char_conf.txt)\n"); - } - - ShowInfo("Finished reading the char-server configuration.\n"); - - inter_init_sql((argc > 2) ? argv[2] : inter_cfgName); // inter server テハア篳ュ - ShowInfo("Finished reading the inter-server configuration.\n"); - - ShowInfo("Initializing char server.\n"); - auth_db = idb_alloc(DB_OPT_RELEASE_DATA); - online_char_db = idb_alloc(DB_OPT_RELEASE_DATA); - mmo_char_sql_init(); - char_read_fame_list(); //Read fame lists. - ShowInfo("char server initialized.\n"); - - if ((naddr_ != 0) && (!login_ip || !char_ip)) - { - char ip_str[16]; - ip2str(addr_[0], ip_str); - - if (naddr_ > 1) - ShowStatus("Multiple interfaces detected.. using %s as our IP address\n", ip_str); - else - ShowStatus("Defaulting to %s as our IP address\n", ip_str); - if (!login_ip) { - safestrncpy(login_ip_str, ip_str, sizeof(login_ip_str)); - login_ip = str2ip(login_ip_str); - } - if (!char_ip) { - safestrncpy(char_ip_str, ip_str, sizeof(char_ip_str)); - char_ip = str2ip(char_ip_str); - } - } - - do_init_loginif(); - do_init_mapif(); - - // periodically update the overall user count on all mapservers + login server - add_timer_func_list(broadcast_user_count, "broadcast_user_count"); - add_timer_interval(gettick() + 1000, broadcast_user_count, 0, 0, 5 * 1000); - - // ??? - add_timer_func_list(chardb_waiting_disconnect, "chardb_waiting_disconnect"); - - // ??? - add_timer_func_list(online_data_cleanup, "online_data_cleanup"); - add_timer_interval(gettick() + 1000, online_data_cleanup, 0, 0, 600 * 1000); - - if( console ) - { - //##TODO invoke a CONSOLE_START plugin event - } - - //Cleaning the tables for NULL entrys @ startup [Sirius] - //Chardb clean - ShowInfo("Cleaning the '%s' table...\n", char_db); - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `account_id` = '0'", char_db) ) - Sql_ShowDebug(sql_handle); - - //guilddb clean - ShowInfo("Cleaning the '%s' table...\n", guild_db); - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_lv` = '0' AND `max_member` = '0' AND `exp` = '0' AND `next_exp` = '0' AND `average_lv` = '0'", guild_db) ) - Sql_ShowDebug(sql_handle); - - //guildmemberdb clean - ShowInfo("Cleaning the '%s' table...\n", guild_member_db); - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '0' AND `account_id` = '0' AND `char_id` = '0'", guild_member_db) ) - Sql_ShowDebug(sql_handle); - - ShowInfo("End of char server initilization function.\n"); - - set_defaultparse(parse_char); - ShowInfo("open port %d.....\n",char_port); - char_fd = make_listen_bind(bind_ip, char_port); - ShowStatus("The char-server is "CL_GREEN"ready"CL_RESET" (Server is listening on the port %d).\n\n", char_port); - - if( runflag != CORE_ST_STOP ) - { - shutdown_callback = do_shutdown; - runflag = CHARSERVER_ST_RUNNING; - } - - return 0; -} - -#endif //TXT_SQL_CONVERT diff --git a/src/char_sql/char.h b/src/char_sql/char.h deleted file mode 100644 index c9ec54a16..000000000 --- a/src/char_sql/char.h +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder - -#ifndef _CHAR_SQL_H_ -#define _CHAR_SQL_H_ - -#include "../common/core.h" // CORE_ST_LAST - -#ifndef TXT_SQL_CONVERT -enum E_CHARSERVER_ST -{ - CHARSERVER_ST_RUNNING = CORE_ST_LAST, - CHARSERVER_ST_SHUTDOWN, - CHARSERVER_ST_LAST -}; -#endif - -struct mmo_charstatus; - -#define MAX_MAP_SERVERS 30 - -#define DEFAULT_AUTOSAVE_INTERVAL 300*1000 - -enum { - TABLE_INVENTORY, - TABLE_CART, - TABLE_STORAGE, - TABLE_GUILD_STORAGE, -}; - -int memitemdata_to_sql(const struct item items[], int max, int id, int tableswitch); - -int mapif_sendall(unsigned char *buf,unsigned int len); -int mapif_sendallwos(int fd,unsigned char *buf,unsigned int len); -int mapif_send(int fd,unsigned char *buf,unsigned int len); - -int char_married(int pl1,int pl2); -int char_child(int parent_id, int child_id); -int char_family(int pl1,int pl2,int pl3); - -int request_accreg2(int account_id, int char_id); -int save_accreg2(unsigned char* buf, int len); - -extern int char_name_option; -extern char char_name_letters[]; -extern bool char_gm_read; -extern int autosave_interval; -extern int save_log; -extern char db_path[]; -extern char char_db[256]; -extern char scdata_db[256]; -extern char cart_db[256]; -extern char inventory_db[256]; -extern char charlog_db[256]; -extern char storage_db[256]; -extern char interlog_db[256]; -extern char reg_db[256]; -extern char skill_db[256]; -extern char memo_db[256]; -extern char guild_db[256]; -extern char guild_alliance_db[256]; -extern char guild_castle_db[256]; -extern char guild_expulsion_db[256]; -extern char guild_member_db[256]; -extern char guild_position_db[256]; -extern char guild_skill_db[256]; -extern char guild_storage_db[256]; -extern char party_db[256]; -extern char pet_db[256]; -extern char mail_db[256]; -extern char auction_db[256]; -extern char quest_db[256]; - -extern int db_use_sqldbs; // added for sql item_db read for char server [Valaris] - -extern int guild_exp_rate; -extern int log_inter; - -//Exported for use in the TXT-SQL converter. -int mmo_char_tosql(int char_id, struct mmo_charstatus *p); -void sql_config_read(const char *cfgName); - -#endif /* _CHAR_SQL_H_ */ diff --git a/src/char_sql/int_auction.c b/src/char_sql/int_auction.c deleted file mode 100644 index 04e321062..000000000 --- a/src/char_sql/int_auction.c +++ /dev/null @@ -1,494 +0,0 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder - -#include "../common/mmo.h" -#include "../common/malloc.h" -#include "../common/db.h" -#include "../common/showmsg.h" -#include "../common/socket.h" -#include "../common/strlib.h" -#include "../common/sql.h" -#include "../common/timer.h" -#include "char.h" -#include "inter.h" -#include "int_mail.h" -#include "int_auction.h" - -#include -#include -#include - -static DBMap* auction_db_ = NULL; // int auction_id -> struct auction_data* - -void auction_delete(struct auction_data *auction); -static int auction_end_timer(int tid, unsigned int tick, int id, intptr_t data); - -static int auction_count(int char_id, bool buy) -{ - int i = 0; - struct auction_data *auction; - DBIterator* iter; - DBKey key; - - iter = auction_db_->iterator(auction_db_); - for( auction = (struct auction_data*)iter->first(iter,&key); iter->exists(iter); auction = (struct auction_data*)iter->next(iter,&key) ) - { - if( (buy && auction->buyer_id == char_id) || (!buy && auction->seller_id == char_id) ) - i++; - } - iter->destroy(iter); - - return i; -} - -void auction_save(struct auction_data *auction) -{ - int j; - StringBuf buf; - SqlStmt* stmt; - - if( !auction ) - return; - - StringBuf_Init(&buf); - StringBuf_Printf(&buf, "UPDATE `%s` SET `seller_id` = '%d', `seller_name` = ?, `buyer_id` = '%d', `buyer_name` = ?, `price` = '%d', `buynow` = '%d', `hours` = '%d', `timestamp` = '%lu', `nameid` = '%d', `item_name` = ?, `type` = '%d', `refine` = '%d', `attribute` = '%d'", - auction_db, auction->seller_id, auction->buyer_id, auction->price, auction->buynow, auction->hours, (unsigned long)auction->timestamp, auction->item.nameid, auction->type, auction->item.refine, auction->item.attribute); - for( j = 0; j < MAX_SLOTS; j++ ) - StringBuf_Printf(&buf, ", `card%d` = '%d'", j, auction->item.card[j]); - StringBuf_Printf(&buf, " WHERE `auction_id` = '%d'", auction->auction_id); - - stmt = SqlStmt_Malloc(sql_handle); - if( SQL_SUCCESS != SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_STRING, auction->seller_name, strnlen(auction->seller_name, NAME_LENGTH)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_STRING, auction->buyer_name, strnlen(auction->buyer_name, NAME_LENGTH)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 2, SQLDT_STRING, auction->item_name, strnlen(auction->item_name, ITEM_NAME_LENGTH)) - || SQL_SUCCESS != SqlStmt_Execute(stmt) ) - { - SqlStmt_ShowDebug(stmt); - } - - SqlStmt_Free(stmt); - StringBuf_Destroy(&buf); -} - -unsigned int auction_create(struct auction_data *auction) -{ - int j; - StringBuf buf; - SqlStmt* stmt; - - if( !auction ) - return false; - - auction->timestamp = time(NULL) + (auction->hours * 3600); - - StringBuf_Init(&buf); - StringBuf_Printf(&buf, "INSERT INTO `%s` (`seller_id`,`seller_name`,`buyer_id`,`buyer_name`,`price`,`buynow`,`hours`,`timestamp`,`nameid`,`item_name`,`type`,`refine`,`attribute`", auction_db); - for( j = 0; j < MAX_SLOTS; j++ ) - StringBuf_Printf(&buf, ",`card%d`", j); - StringBuf_Printf(&buf, ") VALUES ('%d',?,'%d',?,'%d','%d','%d','%lu','%d',?,'%d','%d','%d'", - auction->seller_id, auction->buyer_id, auction->price, auction->buynow, auction->hours, (unsigned long)auction->timestamp, auction->item.nameid, auction->type, auction->item.refine, auction->item.attribute); - for( j = 0; j < MAX_SLOTS; j++ ) - StringBuf_Printf(&buf, ",'%d'", auction->item.card[j]); - StringBuf_AppendStr(&buf, ")"); - - stmt = SqlStmt_Malloc(sql_handle); - if( SQL_SUCCESS != SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_STRING, auction->seller_name, strnlen(auction->seller_name, NAME_LENGTH)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_STRING, auction->buyer_name, strnlen(auction->buyer_name, NAME_LENGTH)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 2, SQLDT_STRING, auction->item_name, strnlen(auction->item_name, ITEM_NAME_LENGTH)) - || SQL_SUCCESS != SqlStmt_Execute(stmt) ) - { - SqlStmt_ShowDebug(stmt); - auction->auction_id = 0; - } - else - { - struct auction_data *auction_; - unsigned int tick = auction->hours * 3600000; - - auction->item.amount = 1; - auction->item.identify = 1; - auction->item.expire_time = 0; - - auction->auction_id = (unsigned int)SqlStmt_LastInsertId(stmt); - auction->auction_end_timer = add_timer( gettick() + tick , auction_end_timer, auction->auction_id, 0); - ShowInfo("New Auction %u | time left %u ms | By %s.\n", auction->auction_id, tick, auction->seller_name); - - CREATE(auction_, struct auction_data, 1); - memcpy(auction_, auction, sizeof(struct auction_data)); - idb_put(auction_db_, auction_->auction_id, auction_); - } - - SqlStmt_Free(stmt); - StringBuf_Destroy(&buf); - - return auction->auction_id; -} - -static void mapif_Auction_message(int char_id, unsigned char result) -{ - unsigned char buf[74]; - - WBUFW(buf,0) = 0x3854; - WBUFL(buf,2) = char_id; - WBUFL(buf,6) = result; - mapif_sendall(buf,7); -} - -static int auction_end_timer(int tid, unsigned int tick, int id, intptr_t data) -{ - struct auction_data *auction; - if( (auction = (struct auction_data *)idb_get(auction_db_, id)) != NULL ) - { - if( auction->buyer_id ) - { - mail_sendmail(0, "Auction Manager", auction->buyer_id, auction->buyer_name, "Auction", "Thanks, you won the auction!.", 0, &auction->item); - mapif_Auction_message(auction->buyer_id, 6); // You have won the auction - mail_sendmail(0, "Auction Manager", auction->seller_id, auction->seller_name, "Auction", "Payment for your auction!.", auction->price, NULL); - } - else - mail_sendmail(0, "Auction Manager", auction->seller_id, auction->seller_name, "Auction", "No buyers have been found for your auction.", 0, &auction->item); - - ShowInfo("Auction End: id %u.\n", auction->auction_id); - - auction->auction_end_timer = INVALID_TIMER; - auction_delete(auction); - } - - return 0; -} - -void auction_delete(struct auction_data *auction) -{ - unsigned int auction_id = auction->auction_id; - - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `auction_id` = '%d'", auction_db, auction_id) ) - Sql_ShowDebug(sql_handle); - - if( auction->auction_end_timer != INVALID_TIMER ) - delete_timer(auction->auction_end_timer, auction_end_timer); - - idb_remove(auction_db_, auction_id); -} - -void inter_auctions_fromsql(void) -{ - int i; - struct auction_data *auction; - struct item *item; - char *data; - StringBuf buf; - unsigned int tick = gettick(), endtick; - time_t now = time(NULL); - - StringBuf_Init(&buf); - StringBuf_AppendStr(&buf, "SELECT `auction_id`,`seller_id`,`seller_name`,`buyer_id`,`buyer_name`," - "`price`,`buynow`,`hours`,`timestamp`,`nameid`,`item_name`,`type`,`refine`,`attribute`"); - for( i = 0; i < MAX_SLOTS; i++ ) - StringBuf_Printf(&buf, ",`card%d`", i); - StringBuf_Printf(&buf, " FROM `%s` ORDER BY `auction_id` DESC", auction_db); - - if( SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf)) ) - Sql_ShowDebug(sql_handle); - - StringBuf_Destroy(&buf); - - while( SQL_SUCCESS == Sql_NextRow(sql_handle) ) - { - CREATE(auction, struct auction_data, 1); - Sql_GetData(sql_handle, 0, &data, NULL); auction->auction_id = atoi(data); - Sql_GetData(sql_handle, 1, &data, NULL); auction->seller_id = atoi(data); - Sql_GetData(sql_handle, 2, &data, NULL); safestrncpy(auction->seller_name, data, NAME_LENGTH); - Sql_GetData(sql_handle, 3, &data, NULL); auction->buyer_id = atoi(data); - Sql_GetData(sql_handle, 4, &data, NULL); safestrncpy(auction->buyer_name, data, NAME_LENGTH); - Sql_GetData(sql_handle, 5, &data, NULL); auction->price = atoi(data); - Sql_GetData(sql_handle, 6, &data, NULL); auction->buynow = atoi(data); - Sql_GetData(sql_handle, 7, &data, NULL); auction->hours = atoi(data); - Sql_GetData(sql_handle, 8, &data, NULL); auction->timestamp = atoi(data); - - item = &auction->item; - Sql_GetData(sql_handle, 9, &data, NULL); item->nameid = atoi(data); - Sql_GetData(sql_handle,10, &data, NULL); safestrncpy(auction->item_name, data, ITEM_NAME_LENGTH); - Sql_GetData(sql_handle,11, &data, NULL); auction->type = atoi(data); - - Sql_GetData(sql_handle,12, &data, NULL); item->refine = atoi(data); - Sql_GetData(sql_handle,13, &data, NULL); item->attribute = atoi(data); - - item->identify = 1; - item->amount = 1; - item->expire_time = 0; - - for( i = 0; i < MAX_SLOTS; i++ ) - { - Sql_GetData(sql_handle, 14 + i, &data, NULL); - item->card[i] = atoi(data); - } - - if( auction->timestamp > now ) - endtick = ((unsigned int)(auction->timestamp - now) * 1000) + tick; - else - endtick = tick + 10000; // 10 Second's to process ended auctions - - auction->auction_end_timer = add_timer(endtick, auction_end_timer, auction->auction_id, 0); - idb_put(auction_db_, auction->auction_id, auction); - } - - Sql_FreeResult(sql_handle); -} - -static void mapif_Auction_sendlist(int fd, int char_id, short count, short pages, unsigned char *buf) -{ - int len = (sizeof(struct auction_data) * count) + 12; - - WFIFOHEAD(fd, len); - WFIFOW(fd,0) = 0x3850; - WFIFOW(fd,2) = len; - WFIFOL(fd,4) = char_id; - WFIFOW(fd,8) = count; - WFIFOW(fd,10) = pages; - memcpy(WFIFOP(fd,12), buf, len - 12); - WFIFOSET(fd,len); -} - -static void mapif_parse_Auction_requestlist(int fd) -{ - char searchtext[NAME_LENGTH]; - int char_id = RFIFOL(fd,4), len = sizeof(struct auction_data); - int price = RFIFOL(fd,10); - short type = RFIFOW(fd,8), page = max(1,RFIFOW(fd,14)); - unsigned char buf[5 * sizeof(struct auction_data)]; - DBIterator* iter; - DBKey key; - struct auction_data *auction; - short i = 0, j = 0, pages = 1; - - memcpy(searchtext, RFIFOP(fd,16), NAME_LENGTH); - - iter = auction_db_->iterator(auction_db_); - for( auction = (struct auction_data*)iter->first(iter,&key); iter->exists(iter); auction = (struct auction_data*)iter->next(iter,&key) ) - { - if( (type == 0 && auction->type != IT_ARMOR && auction->type != IT_PETARMOR) || - (type == 1 && auction->type != IT_WEAPON) || - (type == 2 && auction->type != IT_CARD) || - (type == 3 && auction->type != IT_ETC) || - (type == 4 && !strstr(auction->item_name, searchtext)) || - (type == 5 && auction->price > price) || - (type == 6 && auction->seller_id != char_id) || - (type == 7 && auction->buyer_id != char_id) ) - continue; - - i++; - if( i > 5 ) - { // Counting Pages of Total Results (5 Results per Page) - pages++; - i = 1; // First Result of This Page - } - - if( page != pages ) - continue; // This is not the requested Page - - memcpy(WBUFP(buf, j * len), auction, len); - j++; // Found Results - } - iter->destroy(iter); - - mapif_Auction_sendlist(fd, char_id, j, pages, buf); -} - -static void mapif_Auction_register(int fd, struct auction_data *auction) -{ - int len = sizeof(struct auction_data) + 4; - - WFIFOHEAD(fd,len); - WFIFOW(fd,0) = 0x3851; - WFIFOW(fd,2) = len; - memcpy(WFIFOP(fd,4), auction, sizeof(struct auction_data)); - WFIFOSET(fd,len); -} - -static void mapif_parse_Auction_register(int fd) -{ - struct auction_data auction; - if( RFIFOW(fd,2) != sizeof(struct auction_data) + 4 ) - return; - - memcpy(&auction, RFIFOP(fd,4), sizeof(struct auction_data)); - if( auction_count(auction.seller_id, false) < 5 ) - auction.auction_id = auction_create(&auction); - - mapif_Auction_register(fd, &auction); -} - -static void mapif_Auction_cancel(int fd, int char_id, unsigned char result) -{ - WFIFOHEAD(fd,7); - WFIFOW(fd,0) = 0x3852; - WFIFOL(fd,2) = char_id; - WFIFOB(fd,6) = result; - WFIFOSET(fd,7); -} - -static void mapif_parse_Auction_cancel(int fd) -{ - int char_id = RFIFOL(fd,2), auction_id = RFIFOL(fd,6); - struct auction_data *auction; - - if( (auction = (struct auction_data *)idb_get(auction_db_, auction_id)) == NULL ) - { - mapif_Auction_cancel(fd, char_id, 1); // Bid Number is Incorrect - return; - } - - if( auction->seller_id != char_id ) - { - mapif_Auction_cancel(fd, char_id, 2); // You cannot end the auction - return; - } - - if( auction->buyer_id > 0 ) - { - mapif_Auction_cancel(fd, char_id, 3); // An auction with at least one bidder cannot be canceled - return; - } - - mail_sendmail(0, "Auction Manager", auction->seller_id, auction->seller_name, "Auction", "Auction canceled.", 0, &auction->item); - auction_delete(auction); - - mapif_Auction_cancel(fd, char_id, 0); // The auction has been canceled -} - -static void mapif_Auction_close(int fd, int char_id, unsigned char result) -{ - WFIFOHEAD(fd,7); - WFIFOW(fd,0) = 0x3853; - WFIFOL(fd,2) = char_id; - WFIFOB(fd,6) = result; - WFIFOSET(fd,7); -} - -static void mapif_parse_Auction_close(int fd) -{ - int char_id = RFIFOL(fd,2), auction_id = RFIFOL(fd,6); - struct auction_data *auction; - - if( (auction = (struct auction_data *)idb_get(auction_db_, auction_id)) == NULL ) - { - mapif_Auction_close(fd, char_id, 2); // Bid Number is Incorrect - return; - } - - if( auction->seller_id != char_id ) - { - mapif_Auction_close(fd, char_id, 1); // You cannot end the auction - return; - } - - if( auction->buyer_id == 0 ) - { - mapif_Auction_close(fd, char_id, 1); // You cannot end the auction - return; - } - - // Send Money to Seller - mail_sendmail(0, "Auction Manager", auction->seller_id, auction->seller_name, "Auction", "Auction closed.", auction->price, NULL); - // Send Item to Buyer - mail_sendmail(0, "Auction Manager", auction->buyer_id, auction->buyer_name, "Auction", "Auction winner.", 0, &auction->item); - mapif_Auction_message(auction->buyer_id, 6); // You have won the auction - auction_delete(auction); - - mapif_Auction_close(fd, char_id, 0); // You have ended the auction -} - -static void mapif_Auction_bid(int fd, int char_id, int bid, unsigned char result) -{ - WFIFOHEAD(fd,11); - WFIFOW(fd,0) = 0x3855; - WFIFOL(fd,2) = char_id; - WFIFOL(fd,6) = bid; // To Return Zeny - WFIFOB(fd,10) = result; - WFIFOSET(fd,11); -} - -static void mapif_parse_Auction_bid(int fd) -{ - int char_id = RFIFOL(fd,4), bid = RFIFOL(fd,12); - unsigned int auction_id = RFIFOL(fd,8); - struct auction_data *auction; - - if( (auction = (struct auction_data *)idb_get(auction_db_, auction_id)) == NULL || auction->price >= bid || auction->seller_id == char_id ) - { - mapif_Auction_bid(fd, char_id, bid, 0); // You have failed to bid in the auction - return; - } - - if( auction_count(char_id, true) > 4 && bid < auction->buynow && auction->buyer_id != char_id ) - { - mapif_Auction_bid(fd, char_id, bid, 9); // You cannot place more than 5 bids at a time - return; - } - - if( auction->buyer_id > 0 ) - { // Send Money back to the previous Buyer - if( auction->buyer_id != char_id ) - { - mail_sendmail(0, "Auction Manager", auction->buyer_id, auction->buyer_name, "Auction", "Someone has placed a higher bid.", auction->price, NULL); - mapif_Auction_message(auction->buyer_id, 7); // You have failed to win the auction - } - else - mail_sendmail(0, "Auction Manager", auction->buyer_id, auction->buyer_name, "Auction", "You have placed a higher bid.", auction->price, NULL); - } - - auction->buyer_id = char_id; - safestrncpy(auction->buyer_name, (char*)RFIFOP(fd,16), NAME_LENGTH); - auction->price = bid; - - if( bid >= auction->buynow ) - { // Automatic won the auction - mapif_Auction_bid(fd, char_id, bid - auction->buynow, 1); // You have successfully bid in the auction - - mail_sendmail(0, "Auction Manager", auction->buyer_id, auction->buyer_name, "Auction", "You have won the auction.", 0, &auction->item); - mapif_Auction_message(char_id, 6); // You have won the auction - mail_sendmail(0, "Auction Manager", auction->seller_id, auction->seller_name, "Auction", "Payment for your auction!.", auction->buynow, NULL); - - auction_delete(auction); - return; - } - - auction_save(auction); - - mapif_Auction_bid(fd, char_id, 0, 1); // You have successfully bid in the auction -} - -/*========================================== - * Packets From Map Server - *------------------------------------------*/ -int inter_auction_parse_frommap(int fd) -{ - switch(RFIFOW(fd,0)) - { - case 0x3050: mapif_parse_Auction_requestlist(fd); break; - case 0x3051: mapif_parse_Auction_register(fd); break; - case 0x3052: mapif_parse_Auction_cancel(fd); break; - case 0x3053: mapif_parse_Auction_close(fd); break; - case 0x3055: mapif_parse_Auction_bid(fd); break; - default: - return 0; - } - return 1; -} - -int inter_auction_sql_init(void) -{ - auction_db_ = idb_alloc(DB_OPT_RELEASE_DATA); - inter_auctions_fromsql(); - - return 0; -} - -void inter_auction_sql_final(void) -{ - auction_db_->destroy(auction_db_,NULL); - - return; -} diff --git a/src/char_sql/int_auction.h b/src/char_sql/int_auction.h deleted file mode 100644 index bf26b152c..000000000 --- a/src/char_sql/int_auction.h +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder - -#ifndef _INT_AUCTION_SQL_H_ -#define _INT_AUCTION_SQL_H_ - -int inter_auction_parse_frommap(int fd); - -int inter_auction_sql_init(void); -void inter_auction_sql_final(void); - -#endif /* _INT_AUCTION_SQL_H_ */ diff --git a/src/char_sql/int_guild.c b/src/char_sql/int_guild.c deleted file mode 100644 index 7b467f92a..000000000 --- a/src/char_sql/int_guild.c +++ /dev/null @@ -1,2018 +0,0 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder - -#include "../common/cbasetypes.h" -#include "../common/mmo.h" -#include "../common/malloc.h" -#include "../common/socket.h" -#include "../common/db.h" -#include "../common/showmsg.h" -#include "../common/strlib.h" -#include "../common/timer.h" -#include "char.h" -#include "inter.h" -#include "int_guild.h" - -#include -#include -#include - -#define GS_MEMBER_UNMODIFIED 0x00 -#define GS_MEMBER_MODIFIED 0x01 -#define GS_MEMBER_NEW 0x02 - -#define GS_POSITION_UNMODIFIED 0x00 -#define GS_POSITION_MODIFIED 0x01 - -// LSB = 0 => Alliance, LSB = 1 => Opposition -#define GUILD_ALLIANCE_TYPE_MASK 0x01 -#define GUILD_ALLIANCE_REMOVE 0x08 - -static const char dataToHex[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; - -#ifndef TXT_SQL_CONVERT -//Guild cache -static DBMap* guild_db_; // int guild_id -> struct guild* - -struct guild_castle castles[MAX_GUILDCASTLE]; - -static unsigned int guild_exp[100]; - -int mapif_parse_GuildLeave(int fd,int guild_id,int account_id,int char_id,int flag,const char *mes); -int mapif_guild_broken(int guild_id,int flag); -static bool guild_check_empty(struct guild *g); -int guild_calcinfo(struct guild *g); -int mapif_guild_basicinfochanged(int guild_id,int type,const void *data,int len); -int mapif_guild_info(int fd,struct guild *g); -int guild_break_sub(int key,void *data,va_list ap); -int inter_guild_tosql(struct guild *g,int flag); - -static int guild_save_timer(int tid, unsigned int tick, int id, intptr_t data) -{ - static int last_id = 0; //To know in which guild we were. - int state = 0; //0: Have not reached last guild. 1: Reached last guild, ready for save. 2: Some guild saved, don't do further saving. - DBIterator* iter; - DBKey key; - struct guild* g; - - if( last_id == 0 ) //Save the first guild in the list. - state = 1; - - iter = guild_db_->iterator(guild_db_); - for( g = (struct guild*)iter->first(iter,&key); iter->exists(iter); g = (struct guild*)iter->next(iter,&key) ) - { - if( state == 0 && g->guild_id == last_id ) - state++; //Save next guild in the list. - else - if( state == 1 && g->save_flag&GS_MASK ) - { - inter_guild_tosql(g, g->save_flag&GS_MASK); - g->save_flag &= ~GS_MASK; - - //Some guild saved. - last_id = g->guild_id; - state++; - } - - if( g->save_flag == GS_REMOVE ) - {// Nothing to save, guild is ready for removal. - if (save_log) - ShowInfo("Guild Unloaded (%d - %s)\n", g->guild_id, g->name); - db_remove(guild_db_, key); - } - } - iter->destroy(iter); - - if( state != 2 ) //Reached the end of the guild db without saving. - last_id = 0; //Reset guild saved, return to beginning. - - state = guild_db_->size(guild_db_); - if( state < 1 ) state = 1; //Calculate the time slot for the next save. - add_timer(tick + autosave_interval/state, guild_save_timer, 0, 0); - return 0; -} - -int inter_guild_removemember_tosql(int account_id, int char_id) -{ - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE from `%s` where `account_id` = '%d' and `char_id` = '%d'", guild_member_db, account_id, char_id) ) - Sql_ShowDebug(sql_handle); - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `guild_id` = '0' WHERE `char_id` = '%d'", char_db, char_id) ) - Sql_ShowDebug(sql_handle); - return 0; -} -#endif //TXT_SQL_CONVERT - -// Save guild into sql -int inter_guild_tosql(struct guild *g,int flag) -{ - // Table guild (GS_BASIC_MASK) - // GS_EMBLEM `emblem_len`,`emblem_id`,`emblem_data` - // GS_CONNECT `connect_member`,`average_lv` - // GS_MES `mes1`,`mes2` - // GS_LEVEL `guild_lv`,`max_member`,`exp`,`next_exp`,`skill_point` - // GS_BASIC `name`,`master`,`char_id` - - // GS_MEMBER `guild_member` (`guild_id`,`account_id`,`char_id`,`hair`,`hair_color`,`gender`,`class`,`lv`,`exp`,`exp_payper`,`online`,`position`,`name`) - // GS_POSITION `guild_position` (`guild_id`,`position`,`name`,`mode`,`exp_mode`) - // GS_ALLIANCE `guild_alliance` (`guild_id`,`opposition`,`alliance_id`,`name`) - // GS_EXPULSION `guild_expulsion` (`guild_id`,`account_id`,`name`,`mes`) - // GS_SKILL `guild_skill` (`guild_id`,`id`,`lv`) - - // temporary storage for str convertion. They must be twice the size of the - // original string to ensure no overflows will occur. [Skotlex] - char t_info[256]; - char esc_name[NAME_LENGTH*2+1]; - char esc_master[NAME_LENGTH*2+1]; - char new_guild = 0; - int i=0; - - if (g->guild_id<=0 && g->guild_id != -1) return 0; - -#ifdef NOISY - ShowInfo("Save guild request ("CL_BOLD"%d"CL_RESET" - flag 0x%x).",g->guild_id, flag); -#endif - - Sql_EscapeStringLen(sql_handle, esc_name, g->name, strnlen(g->name, NAME_LENGTH)); - Sql_EscapeStringLen(sql_handle, esc_master, g->master, strnlen(g->master, NAME_LENGTH)); - *t_info = '\0'; - -#ifndef TXT_SQL_CONVERT - // Insert a new guild the guild - if (flag&GS_BASIC && g->guild_id == -1) - { - strcat(t_info, " guild_create"); - - // Create a new guild - if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` " - "(`name`,`master`,`guild_lv`,`max_member`,`average_lv`,`char_id`) " - "VALUES ('%s', '%s', '%d', '%d', '%d', '%d')", - guild_db, esc_name, esc_master, g->guild_lv, g->max_member, g->average_lv, g->member[0].char_id) ) - { - Sql_ShowDebug(sql_handle); - if (g->guild_id == -1) - return 0; //Failed to create guild! - } - else - { - g->guild_id = (int)Sql_LastInsertId(sql_handle); - new_guild = 1; - } - } -#else - // Insert a new guild the guild - if (flag&GS_BASIC) - { - strcat(t_info, " guild_create"); - // Since the PK is guild id + master id, a replace will not be enough if we are overwriting data, we need to wipe the previous guild. - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` where `guild_id` = '%d'", guild_db, g->guild_id) ) - Sql_ShowDebug(sql_handle); - // Create a new guild - if( SQL_ERROR == Sql_Query(sql_handle, "REPLACE INTO `%s` " - "(`guild_id`,`name`,`master`,`guild_lv`,`max_member`,`average_lv`,`char_id`) " - "VALUES ('%d', '%s', '%s', '%d', '%d', '%d', '%d')", - guild_db, g->guild_id, esc_name, esc_master, g->guild_lv, g->max_member, g->average_lv, g->member[0].char_id) ) - { - Sql_ShowDebug(sql_handle); - return 0; //Failed to create guild. - } - } -#endif //TXT_SQL_CONVERT - // If we need an update on an existing guild or more update on the new guild - if (((flag & GS_BASIC_MASK) && !new_guild) || ((flag & (GS_BASIC_MASK & ~GS_BASIC)) && new_guild)) - { - StringBuf buf; - bool add_comma = false; - - StringBuf_Init(&buf); - StringBuf_Printf(&buf, "UPDATE `%s` SET ", guild_db); - - if (flag & GS_EMBLEM) - { - char emblem_data[sizeof(g->emblem_data)*2+1]; - char* pData = emblem_data; - - strcat(t_info, " emblem"); - // Convert emblem_data to hex - //TODO: why not use binary directly? [ultramage] - for(i=0; iemblem_len; i++){ - *pData++ = dataToHex[(g->emblem_data[i] >> 4) & 0x0F]; - *pData++ = dataToHex[g->emblem_data[i] & 0x0F]; - } - *pData = 0; - StringBuf_Printf(&buf, "`emblem_len`=%d, `emblem_id`=%d, `emblem_data`='%s'", g->emblem_len, g->emblem_id, emblem_data); - add_comma = true; - } - if (flag & GS_BASIC) - { - strcat(t_info, " basic"); - if( add_comma ) - StringBuf_AppendStr(&buf, ", "); - else - add_comma = true; - StringBuf_Printf(&buf, "`name`='%s', `master`='%s', `char_id`=%d", esc_name, esc_master, g->member[0].char_id); - } - if (flag & GS_CONNECT) - { - strcat(t_info, " connect"); - if( add_comma ) - StringBuf_AppendStr(&buf, ", "); - else - add_comma = true; - StringBuf_Printf(&buf, "`connect_member`=%d, `average_lv`=%d", g->connect_member, g->average_lv); - } - if (flag & GS_MES) - { - char esc_mes1[sizeof(g->mes1)*2+1]; - char esc_mes2[sizeof(g->mes2)*2+1]; - - strcat(t_info, " mes"); - if( add_comma ) - StringBuf_AppendStr(&buf, ", "); - else - add_comma = true; - Sql_EscapeStringLen(sql_handle, esc_mes1, g->mes1, strnlen(g->mes1, sizeof(g->mes1))); - Sql_EscapeStringLen(sql_handle, esc_mes2, g->mes2, strnlen(g->mes2, sizeof(g->mes2))); - StringBuf_Printf(&buf, "`mes1`='%s', `mes2`='%s'", esc_mes1, esc_mes2); - } - if (flag & GS_LEVEL) - { - strcat(t_info, " level"); - if( add_comma ) - StringBuf_AppendStr(&buf, ", "); - else - add_comma = true; - StringBuf_Printf(&buf, "`guild_lv`=%d, `skill_point`=%d, `exp`=%"PRIu64", `next_exp`=%u, `max_member`=%d", g->guild_lv, g->skill_point, g->exp, g->next_exp, g->max_member); - } - StringBuf_Printf(&buf, " WHERE `guild_id`=%d", g->guild_id); - if( SQL_ERROR == Sql_Query(sql_handle, "%s", StringBuf_Value(&buf)) ) - Sql_ShowDebug(sql_handle); - StringBuf_Destroy(&buf); - } - - if (flag&GS_MEMBER) - { - struct guild_member *m; - - strcat(t_info, " members"); - // Update only needed players - for(i=0;imax_member;i++){ - m = &g->member[i]; -#ifndef TXT_SQL_CONVERT - if (!m->modified) - continue; -#endif - if(m->account_id) { - //Since nothing references guild member table as foreign keys, it's safe to use REPLACE INTO - Sql_EscapeStringLen(sql_handle, esc_name, m->name, strnlen(m->name, NAME_LENGTH)); - if( SQL_ERROR == Sql_Query(sql_handle, "REPLACE INTO `%s` (`guild_id`,`account_id`,`char_id`,`hair`,`hair_color`,`gender`,`class`,`lv`,`exp`,`exp_payper`,`online`,`position`,`name`) " - "VALUES ('%d','%d','%d','%d','%d','%d','%d','%d','%"PRIu64"','%d','%d','%d','%s')", - guild_member_db, g->guild_id, m->account_id, m->char_id, - m->hair, m->hair_color, m->gender, - m->class_, m->lv, m->exp, m->exp_payper, m->online, m->position, esc_name) ) - Sql_ShowDebug(sql_handle); - if (m->modified & GS_MEMBER_NEW) - { - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `guild_id` = '%d' WHERE `char_id` = '%d'", - char_db, g->guild_id, m->char_id) ) - Sql_ShowDebug(sql_handle); - } - m->modified = GS_MEMBER_UNMODIFIED; - } - } - } - - if (flag&GS_POSITION){ - strcat(t_info, " positions"); - //printf("- Insert guild %d to guild_position\n",g->guild_id); - for(i=0;iposition[i]; -#ifndef TXT_SQL_CONVERT - if (!p->modified) - continue; -#endif - Sql_EscapeStringLen(sql_handle, esc_name, p->name, strnlen(p->name, NAME_LENGTH)); - if( SQL_ERROR == Sql_Query(sql_handle, "REPLACE INTO `%s` (`guild_id`,`position`,`name`,`mode`,`exp_mode`) VALUES ('%d','%d','%s','%d','%d')", - guild_position_db, g->guild_id, i, esc_name, p->mode, p->exp_mode) ) - Sql_ShowDebug(sql_handle); - p->modified = GS_POSITION_UNMODIFIED; - } - } - - if (flag&GS_ALLIANCE) - { - // Delete current alliances - // NOTE: no need to do it on both sides since both guilds in memory had - // their info changed, not to mention this would also mess up oppositions! - // [Skotlex] - //if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id`='%d' OR `alliance_id`='%d'", guild_alliance_db, g->guild_id, g->guild_id) ) - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id`='%d'", guild_alliance_db, g->guild_id) ) - { - Sql_ShowDebug(sql_handle); - } - else - { - //printf("- Insert guild %d to guild_alliance\n",g->guild_id); - for(i=0;ialliance[i]; - if(a->guild_id>0) - { - Sql_EscapeStringLen(sql_handle, esc_name, a->name, strnlen(a->name, NAME_LENGTH)); - if( SQL_ERROR == Sql_Query(sql_handle, "REPLACE INTO `%s` (`guild_id`,`opposition`,`alliance_id`,`name`) " - "VALUES ('%d','%d','%d','%s')", - guild_alliance_db, g->guild_id, a->opposition, a->guild_id, esc_name) ) - Sql_ShowDebug(sql_handle); - } - } - } - } - - if (flag&GS_EXPULSION){ - strcat(t_info, " expulsions"); - //printf("- Insert guild %d to guild_expulsion\n",g->guild_id); - for(i=0;iexpulsion[i]; - if(e->account_id>0){ - char esc_mes[sizeof(e->mes)*2+1]; - - Sql_EscapeStringLen(sql_handle, esc_name, e->name, strnlen(e->name, NAME_LENGTH)); - Sql_EscapeStringLen(sql_handle, esc_mes, e->mes, strnlen(e->mes, sizeof(e->mes))); - if( SQL_ERROR == Sql_Query(sql_handle, "REPLACE INTO `%s` (`guild_id`,`account_id`,`name`,`mes`) " - "VALUES ('%d','%d','%s','%s')", guild_expulsion_db, g->guild_id, e->account_id, esc_name, esc_mes) ) - Sql_ShowDebug(sql_handle); - } - } - } - - if (flag&GS_SKILL){ - strcat(t_info, " skills"); - //printf("- Insert guild %d to guild_skill\n",g->guild_id); - for(i=0;iskill[i].id>0 && g->skill[i].lv>0){ - if( SQL_ERROR == Sql_Query(sql_handle, "REPLACE INTO `%s` (`guild_id`,`id`,`lv`) VALUES ('%d','%d','%d')", - guild_skill_db, g->guild_id, g->skill[i].id, g->skill[i].lv) ) - Sql_ShowDebug(sql_handle); - } - } - } - - if (save_log) - ShowInfo("Saved guild (%d - %s):%s\n",g->guild_id,g->name,t_info); - return 1; -} - -#ifndef TXT_SQL_CONVERT -// Read guild from sql -struct guild * inter_guild_fromsql(int guild_id) -{ - struct guild *g; - char* data; - size_t len; - char* p; - int i; - - if( guild_id <= 0 ) - return NULL; - - g = (struct guild*)idb_get(guild_db_, guild_id); - if( g ) - return g; - -#ifdef NOISY - ShowInfo("Guild load request (%d)...\n", guild_id); -#endif - - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT g.`name`,c.`name`,g.`guild_lv`,g.`connect_member`,g.`max_member`,g.`average_lv`,g.`exp`,g.`next_exp`,g.`skill_point`,g.`mes1`,g.`mes2`,g.`emblem_len`,g.`emblem_id`,g.`emblem_data` " - "FROM `%s` g LEFT JOIN `%s` c ON c.`char_id` = g.`char_id` WHERE g.`guild_id`='%d'", guild_db, char_db, guild_id) ) - { - Sql_ShowDebug(sql_handle); - return NULL; - } - - if( SQL_SUCCESS != Sql_NextRow(sql_handle) ) - return NULL;// Guild does not exists. - - CREATE(g, struct guild, 1); - - g->guild_id = guild_id; - Sql_GetData(sql_handle, 0, &data, &len); memcpy(g->name, data, min(len, NAME_LENGTH)); - Sql_GetData(sql_handle, 1, &data, &len); memcpy(g->master, data, min(len, NAME_LENGTH)); - Sql_GetData(sql_handle, 2, &data, NULL); g->guild_lv = atoi(data); - Sql_GetData(sql_handle, 3, &data, NULL); g->connect_member = atoi(data); - Sql_GetData(sql_handle, 4, &data, NULL); g->max_member = atoi(data); - if( g->max_member > MAX_GUILD ) - { // Fix reduction of MAX_GUILD [PoW] - ShowWarning("Guild %d:%s specifies higher capacity (%d) than MAX_GUILD (%d)\n", guild_id, g->name, g->max_member, MAX_GUILD); - g->max_member = MAX_GUILD; - } - Sql_GetData(sql_handle, 5, &data, NULL); g->average_lv = atoi(data); - Sql_GetData(sql_handle, 6, &data, NULL); g->exp = strtoull(data, NULL, 10); - Sql_GetData(sql_handle, 7, &data, NULL); g->next_exp = (unsigned int)strtoul(data, NULL, 10); - Sql_GetData(sql_handle, 8, &data, NULL); g->skill_point = atoi(data); - Sql_GetData(sql_handle, 9, &data, &len); memcpy(g->mes1, data, min(len, sizeof(g->mes1))); - Sql_GetData(sql_handle, 10, &data, &len); memcpy(g->mes2, data, min(len, sizeof(g->mes2))); - Sql_GetData(sql_handle, 11, &data, &len); g->emblem_len = atoi(data); - Sql_GetData(sql_handle, 12, &data, &len); g->emblem_id = atoi(data); - Sql_GetData(sql_handle, 13, &data, &len); - // convert emblem data from hexadecimal to binary - //TODO: why not store it in the db as binary directly? [ultramage] - for( i = 0, p = g->emblem_data; i < g->emblem_len; ++i, ++p ) - { - if( *data >= '0' && *data <= '9' ) - *p = *data - '0'; - else if( *data >= 'a' && *data <= 'f' ) - *p = *data - 'a' + 10; - else if( *data >= 'A' && *data <= 'F' ) - *p = *data - 'A' + 10; - *p <<= 4; - ++data; - - if( *data >= '0' && *data <= '9' ) - *p |= *data - '0'; - else if( *data >= 'a' && *data <= 'f' ) - *p |= *data - 'a' + 10; - else if( *data >= 'A' && *data <= 'F' ) - *p |= *data - 'A' + 10; - ++data; - } - - // load guild member info - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id`,`char_id`,`hair`,`hair_color`,`gender`,`class`,`lv`,`exp`,`exp_payper`,`online`,`position`,`name` " - "FROM `%s` WHERE `guild_id`='%d' ORDER BY `position`", guild_member_db, guild_id) ) - { - Sql_ShowDebug(sql_handle); - aFree(g); - return NULL; - } - for( i = 0; i < g->max_member && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i ) - { - struct guild_member* m = &g->member[i]; - - Sql_GetData(sql_handle, 0, &data, NULL); m->account_id = atoi(data); - Sql_GetData(sql_handle, 1, &data, NULL); m->char_id = atoi(data); - Sql_GetData(sql_handle, 2, &data, NULL); m->hair = atoi(data); - Sql_GetData(sql_handle, 3, &data, NULL); m->hair_color = atoi(data); - Sql_GetData(sql_handle, 4, &data, NULL); m->gender = atoi(data); - Sql_GetData(sql_handle, 5, &data, NULL); m->class_ = atoi(data); - Sql_GetData(sql_handle, 6, &data, NULL); m->lv = atoi(data); - Sql_GetData(sql_handle, 7, &data, NULL); m->exp = strtoull(data, NULL, 10); - Sql_GetData(sql_handle, 8, &data, NULL); m->exp_payper = (unsigned int)atoi(data); - Sql_GetData(sql_handle, 9, &data, NULL); m->online = atoi(data); - Sql_GetData(sql_handle, 10, &data, NULL); m->position = atoi(data); - if( m->position >= MAX_GUILDPOSITION ) // Fix reduction of MAX_GUILDPOSITION [PoW] - m->position = MAX_GUILDPOSITION - 1; - Sql_GetData(sql_handle, 11, &data, &len); memcpy(m->name, data, min(len, NAME_LENGTH)); - m->modified = GS_MEMBER_UNMODIFIED; - } - - //printf("- Read guild_position %d from sql \n",guild_id); - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `position`,`name`,`mode`,`exp_mode` FROM `%s` WHERE `guild_id`='%d'", guild_position_db, guild_id) ) - { - Sql_ShowDebug(sql_handle); - aFree(g); - return NULL; - } - while( SQL_SUCCESS == Sql_NextRow(sql_handle) ) - { - int position; - struct guild_position* p; - - Sql_GetData(sql_handle, 0, &data, NULL); position = atoi(data); - if( position < 0 || position >= MAX_GUILDPOSITION ) - continue;// invalid position - p = &g->position[position]; - Sql_GetData(sql_handle, 1, &data, &len); memcpy(p->name, data, min(len, NAME_LENGTH)); - Sql_GetData(sql_handle, 2, &data, NULL); p->mode = atoi(data); - Sql_GetData(sql_handle, 3, &data, NULL); p->exp_mode = atoi(data); - p->modified = GS_POSITION_UNMODIFIED; - } - - //printf("- Read guild_alliance %d from sql \n",guild_id); - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `opposition`,`alliance_id`,`name` FROM `%s` WHERE `guild_id`='%d'", guild_alliance_db, guild_id) ) - { - Sql_ShowDebug(sql_handle); - aFree(g); - return NULL; - } - for( i = 0; i < MAX_GUILDALLIANCE && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i ) - { - struct guild_alliance* a = &g->alliance[i]; - - Sql_GetData(sql_handle, 0, &data, NULL); a->opposition = atoi(data); - Sql_GetData(sql_handle, 1, &data, NULL); a->guild_id = atoi(data); - Sql_GetData(sql_handle, 2, &data, &len); memcpy(a->name, data, min(len, NAME_LENGTH)); - } - - //printf("- Read guild_expulsion %d from sql \n",guild_id); - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id`,`name`,`mes` FROM `%s` WHERE `guild_id`='%d'", guild_expulsion_db, guild_id) ) - { - Sql_ShowDebug(sql_handle); - aFree(g); - return NULL; - } - for( i = 0; i < MAX_GUILDEXPULSION && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i ) - { - struct guild_expulsion *e = &g->expulsion[i]; - - Sql_GetData(sql_handle, 0, &data, NULL); e->account_id = atoi(data); - Sql_GetData(sql_handle, 1, &data, &len); memcpy(e->name, data, min(len, NAME_LENGTH)); - Sql_GetData(sql_handle, 2, &data, &len); memcpy(e->mes, data, min(len, sizeof(e->mes))); - } - - //printf("- Read guild_skill %d from sql \n",guild_id); - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `id`,`lv` FROM `%s` WHERE `guild_id`='%d' ORDER BY `id`", guild_skill_db, guild_id) ) - { - Sql_ShowDebug(sql_handle); - aFree(g); - return NULL; - } - - for(i = 0; i < MAX_GUILDSKILL; i++) - { //Skill IDs must always be initialized. [Skotlex] - g->skill[i].id = i + GD_SKILLBASE; - } - - while( SQL_SUCCESS == Sql_NextRow(sql_handle) ) - { - int id; - Sql_GetData(sql_handle, 0, &data, NULL); id = atoi(data) - GD_SKILLBASE; - if( id < 0 && id >= MAX_GUILDSKILL ) - continue;// invalid guild skill - Sql_GetData(sql_handle, 1, &data, NULL); g->skill[id].lv = atoi(data); - } - Sql_FreeResult(sql_handle); - - idb_put(guild_db_, guild_id, g); //Add to cache - g->save_flag |= GS_REMOVE; //But set it to be removed, in case it is not needed for long. - - if (save_log) - ShowInfo("Guild loaded (%d - %s)\n", guild_id, g->name); - - return g; -} -#endif //TXT_SQL_CONVERT - -int inter_guildcastle_tosql(struct guild_castle *gc) -{ - // `guild_castle` (`castle_id`, `guild_id`, `economy`, `defense`, `triggerE`, `triggerD`, `nextTime`, `payTime`, `createTime`, `visibleC`, `visibleG0`, `visibleG1`, `visibleG2`, `visibleG3`, `visibleG4`, `visibleG5`, `visibleG6`, `visibleG7`) - - if (gc==NULL) return 0; - #ifdef GUILD_DEBUG -ShowDebug("Save guild_castle (%d)\n", gc->castle_id); - #endif - -// sql_query("DELETE FROM `%s` WHERE `castle_id`='%d'",guild_castle_db, gc->castle_id); - if( SQL_ERROR == Sql_Query(sql_handle, "REPLACE INTO `%s` " - "(`castle_id`, `guild_id`, `economy`, `defense`, `triggerE`, `triggerD`, `nextTime`, `payTime`, `createTime`," - "`visibleC`, `visibleG0`, `visibleG1`, `visibleG2`, `visibleG3`, `visibleG4`, `visibleG5`, `visibleG6`, `visibleG7`)" - "VALUES ('%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d')", - guild_castle_db, gc->castle_id, gc->guild_id, gc->economy, gc->defense, gc->triggerE, gc->triggerD, gc->nextTime, gc->payTime, gc->createTime, gc->visibleC, - gc->guardian[0].visible, gc->guardian[1].visible, gc->guardian[2].visible, gc->guardian[3].visible, gc->guardian[4].visible, gc->guardian[5].visible, gc->guardian[6].visible, gc->guardian[7].visible) ) - Sql_ShowDebug(sql_handle); - -#ifndef TXT_SQL_CONVERT - memcpy(&castles[gc->castle_id],gc,sizeof(struct guild_castle)); -#endif //TXT_SQL_CONVERT - return 0; -} - -#ifndef TXT_SQL_CONVERT -// Read guild_castle from sql -int inter_guildcastle_fromsql(int castle_id,struct guild_castle *gc) -{ - static int castles_init=0; - char* data; - - if (gc==NULL) return 0; - if (castle_id==-1) return 0; - - if(!castles_init) - { - int i; - for(i=0;icastle_id=castle_id; - if( SQL_SUCCESS != Sql_NextRow(sql_handle) ) - { - Sql_FreeResult(sql_handle); - return 1; //Assume empty castle. - } - - Sql_GetData(sql_handle, 1, &data, NULL); gc->guild_id = atoi(data); - Sql_GetData(sql_handle, 2, &data, NULL); gc->economy = atoi(data); - Sql_GetData(sql_handle, 3, &data, NULL); gc->defense = atoi(data); - Sql_GetData(sql_handle, 4, &data, NULL); gc->triggerE = atoi(data); - Sql_GetData(sql_handle, 5, &data, NULL); gc->triggerD = atoi(data); - Sql_GetData(sql_handle, 6, &data, NULL); gc->nextTime = atoi(data); - Sql_GetData(sql_handle, 7, &data, NULL); gc->payTime = atoi(data); - Sql_GetData(sql_handle, 8, &data, NULL); gc->createTime = atoi(data); - Sql_GetData(sql_handle, 9, &data, NULL); gc->visibleC = atoi(data); - Sql_GetData(sql_handle, 10, &data, NULL); gc->guardian[0].visible = atoi(data); - Sql_GetData(sql_handle, 11, &data, NULL); gc->guardian[1].visible = atoi(data); - Sql_GetData(sql_handle, 12, &data, NULL); gc->guardian[2].visible = atoi(data); - Sql_GetData(sql_handle, 13, &data, NULL); gc->guardian[3].visible = atoi(data); - Sql_GetData(sql_handle, 14, &data, NULL); gc->guardian[4].visible = atoi(data); - Sql_GetData(sql_handle, 15, &data, NULL); gc->guardian[5].visible = atoi(data); - Sql_GetData(sql_handle, 16, &data, NULL); gc->guardian[6].visible = atoi(data); - Sql_GetData(sql_handle, 17, &data, NULL); gc->guardian[7].visible = atoi(data); - - Sql_FreeResult(sql_handle); - memcpy(&castles[castle_id],gc,sizeof(struct guild_castle)); - - if( save_log ) - ShowInfo("Loaded Castle %d (guild %d)\n", castle_id, gc->guild_id); - - return 1; -} - - -// Read exp_guild.txt -int inter_guild_ReadEXP(void) -{ - int i; - FILE *fp; - char line[1024]; - for (i=0;i<100;i++) guild_exp[i]=0; - //this is going to be discussed, temp fix - sprintf(line, "%s/pre-re/exp_guild.txt", db_path); - fp=fopen(line,"r"); - if(fp==NULL){ - ShowError("can't read %s\n", line); - return 1; - } - i=0; - while(fgets(line, sizeof(line), fp) && i < 100) - { - if(line[0]=='/' && line[1]=='/') - continue; - guild_exp[i]=(unsigned int)atof(line); - i++; - } - fclose(fp); - - return 0; -} - - -int inter_guild_CharOnline(int char_id, int guild_id) -{ - struct guild *g; - int i; - - if (guild_id == -1) { - //Get guild_id from the database - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT guild_id FROM `%s` WHERE char_id='%d'", char_db, char_id) ) - { - Sql_ShowDebug(sql_handle); - return 0; - } - - if( SQL_SUCCESS == Sql_NextRow(sql_handle) ) - { - char* data; - - Sql_GetData(sql_handle, 0, &data, NULL); - guild_id = atoi(data); - } - else - { - guild_id = 0; - } - Sql_FreeResult(sql_handle); - } - if (guild_id == 0) - return 0; //No guild... - - g = inter_guild_fromsql(guild_id); - if(!g) { - ShowError("Character %d's guild %d not found!\n", char_id, guild_id); - return 0; - } - - //Member has logged in before saving, tell saver not to delete - if(g->save_flag & GS_REMOVE) - g->save_flag &= ~GS_REMOVE; - - //Set member online - ARR_FIND( 0, g->max_member, i, g->member[i].char_id == char_id ); - if( i < g->max_member ) - { - g->member[i].online = 1; - g->member[i].modified = GS_MEMBER_MODIFIED; - } - - return 1; -} - -int inter_guild_CharOffline(int char_id, int guild_id) -{ - struct guild *g=NULL; - int online_count, i; - - if (guild_id == -1) - { - //Get guild_id from the database - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT guild_id FROM `%s` WHERE char_id='%d'", char_db, char_id) ) - { - Sql_ShowDebug(sql_handle); - return 0; - } - - if( SQL_SUCCESS == Sql_NextRow(sql_handle) ) - { - char* data; - - Sql_GetData(sql_handle, 0, &data, NULL); - guild_id = atoi(data); - } - else - { - guild_id = 0; - } - Sql_FreeResult(sql_handle); - } - if (guild_id == 0) - return 0; //No guild... - - //Character has a guild, set character offline and check if they were the only member online - g = inter_guild_fromsql(guild_id); - if (g == NULL) //Guild not found? - return 0; - - //Set member offline - ARR_FIND( 0, g->max_member, i, g->member[i].char_id == char_id ); - if( i < g->max_member ) - { - g->member[i].online = 0; - g->member[i].modified = GS_MEMBER_MODIFIED; - } - - online_count = 0; - for( i = 0; i < g->max_member; i++ ) - if( g->member[i].online ) - online_count++; - - // Remove guild from memory if no players online - if( online_count == 0 ) - g->save_flag |= GS_REMOVE; - - return 1; -} - -// Initialize guild sql -int inter_guild_sql_init(void) -{ - //Initialize the guild cache - guild_db_= idb_alloc(DB_OPT_RELEASE_DATA); - - //Read exp file - inter_guild_ReadEXP(); - - add_timer_func_list(guild_save_timer, "guild_save_timer"); - add_timer(gettick() + 10000, guild_save_timer, 0, 0); - return 0; -} - -static int guild_db_final(DBKey key, void *data, va_list ap) -{ - struct guild *g = (struct guild*)data; - if (g->save_flag&GS_MASK) { - inter_guild_tosql(g, g->save_flag&GS_MASK); - return 1; - } - return 0; -} - -void inter_guild_sql_final(void) -{ - guild_db_->destroy(guild_db_, guild_db_final); - return; -} - -// Get guild_id by its name. Returns 0 if not found, -1 on error. -int search_guildname(char *str) -{ - int guild_id; - char esc_name[NAME_LENGTH*2+1]; - - Sql_EscapeStringLen(sql_handle, esc_name, str, safestrnlen(str, NAME_LENGTH)); - //Lookup guilds with the same name - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT guild_id FROM `%s` WHERE name='%s'", guild_db, esc_name) ) - { - Sql_ShowDebug(sql_handle); - return -1; - } - - if( SQL_SUCCESS == Sql_NextRow(sql_handle) ) - { - char* data; - - Sql_GetData(sql_handle, 0, &data, NULL); - guild_id = atoi(data); - } - else - { - guild_id = 0; - } - Sql_FreeResult(sql_handle); - return guild_id; -} - -// Check if guild is empty -static bool guild_check_empty(struct guild *g) -{ - int i; - ARR_FIND( 0, g->max_member, i, g->member[i].account_id > 0 ); - if( i < g->max_member) - return false; // not empty - - //Let the calling function handle the guild removal in case they need - //to do something else with it before freeing the data. [Skotlex] - return true; -} - -unsigned int guild_nextexp(int level) -{ - if (level == 0) - return 1; - if (level < 100 && level > 0) // Change by hack - return guild_exp[level-1]; - - return 0; -} - -int guild_checkskill(struct guild *g,int id) -{ - int idx = id - GD_SKILLBASE; - - if(idx < 0 || idx >= MAX_GUILDSKILL) - return 0; - - return g->skill[idx].lv; -} - -int guild_calcinfo(struct guild *g) -{ - int i,c; - unsigned int nextexp; - struct guild before = *g; // Save guild current values - - if(g->guild_lv<=0) - g->guild_lv = 1; - nextexp = guild_nextexp(g->guild_lv); - - // Consume guild exp and increase guild level - while(g->exp >= nextexp && nextexp > 0){ //fixed guild exp overflow [Kevin] - g->exp-=nextexp; - g->guild_lv++; - g->skill_point++; - nextexp = guild_nextexp(g->guild_lv); - } - - // Save next exp step - g->next_exp = nextexp; - - // Set the max number of members, Guild Extention skill - currently adds 6 to max per skill lv. - g->max_member = 16 + guild_checkskill(g, GD_EXTENSION) * 6; - if(g->max_member > MAX_GUILD) - { - ShowError("Guild %d:%s has capacity for too many guild members (%d), max supported is %d\n", g->guild_id, g->name, g->max_member, MAX_GUILD); - g->max_member = MAX_GUILD; - } - - // Compute the guild average level level - g->average_lv=0; - g->connect_member=0; - for(i=c=0;imax_member;i++) - { - if(g->member[i].account_id>0) - { - if (g->member[i].lv >= 0) - { - g->average_lv+=g->member[i].lv; - c++; - } - else - { - ShowWarning("Guild %d:%s, member %d:%s has an invalid level %d\n", g->guild_id, g->name, g->member[i].char_id, g->member[i].name, g->member[i].lv); - } - - if(g->member[i].online) - g->connect_member++; - } - } - if(c) - g->average_lv /= c; - - // Check if guild stats has change - if(g->max_member != before.max_member || g->guild_lv != before.guild_lv || g->skill_point != before.skill_point ) - { - g->save_flag |= GS_LEVEL; - mapif_guild_info(-1,g); - return 1; - } - - return 0; -} - -//------------------------------------------------------------------- -// Packet sent to map server - -int mapif_guild_created(int fd,int account_id,struct guild *g) -{ - WFIFOHEAD(fd, 10); - WFIFOW(fd,0)=0x3830; - WFIFOL(fd,2)=account_id; - if(g != NULL) - { - WFIFOL(fd,6)=g->guild_id; - ShowInfo("int_guild: Guild created (%d - %s)\n",g->guild_id,g->name); - } else - WFIFOL(fd,6)=0; - - WFIFOSET(fd,10); - return 0; -} - -// Guild not found -int mapif_guild_noinfo(int fd,int guild_id) -{ - unsigned char buf[12]; - WBUFW(buf,0)=0x3831; - WBUFW(buf,2)=8; - WBUFL(buf,4)=guild_id; - ShowWarning("int_guild: info not found %d\n",guild_id); - if(fd<0) - mapif_sendall(buf,8); - else - mapif_send(fd,buf,8); - return 0; -} - -// Send guild info -int mapif_guild_info(int fd,struct guild *g) -{ - unsigned char buf[8+sizeof(struct guild)]; - WBUFW(buf,0)=0x3831; - WBUFW(buf,2)=4+sizeof(struct guild); - memcpy(buf+4,g,sizeof(struct guild)); - if(fd<0) - mapif_sendall(buf,WBUFW(buf,2)); - else - mapif_send(fd,buf,WBUFW(buf,2)); - return 0; -} - -// ACK member add -int mapif_guild_memberadded(int fd,int guild_id,int account_id,int char_id,int flag) -{ - WFIFOHEAD(fd, 15); - WFIFOW(fd,0)=0x3832; - WFIFOL(fd,2)=guild_id; - WFIFOL(fd,6)=account_id; - WFIFOL(fd,10)=char_id; - WFIFOB(fd,14)=flag; - WFIFOSET(fd,15); - return 0; -} - -// ACK member leave -int mapif_guild_withdraw(int guild_id,int account_id,int char_id,int flag, const char *name, const char *mes) -{ - unsigned char buf[55+NAME_LENGTH]; - WBUFW(buf, 0)=0x3834; - WBUFL(buf, 2)=guild_id; - WBUFL(buf, 6)=account_id; - WBUFL(buf,10)=char_id; - WBUFB(buf,14)=flag; - memcpy(WBUFP(buf,15),mes,40); - memcpy(WBUFP(buf,55),name,NAME_LENGTH); - mapif_sendall(buf,55+NAME_LENGTH); - ShowInfo("int_guild: guild withdraw (%d - %d: %s - %s)\n",guild_id,account_id,name,mes); - return 0; -} - -// Send short member's info -int mapif_guild_memberinfoshort(struct guild *g,int idx) -{ - unsigned char buf[19]; - WBUFW(buf, 0)=0x3835; - WBUFL(buf, 2)=g->guild_id; - WBUFL(buf, 6)=g->member[idx].account_id; - WBUFL(buf,10)=g->member[idx].char_id; - WBUFB(buf,14)=(unsigned char)g->member[idx].online; - WBUFW(buf,15)=g->member[idx].lv; - WBUFW(buf,17)=g->member[idx].class_; - mapif_sendall(buf,19); - return 0; -} - -// Send guild broken -int mapif_guild_broken(int guild_id,int flag) -{ - unsigned char buf[7]; - WBUFW(buf,0)=0x3836; - WBUFL(buf,2)=guild_id; - WBUFB(buf,6)=flag; - mapif_sendall(buf,7); - ShowInfo("int_guild: Guild broken (%d)\n",guild_id); - return 0; -} - -// Send guild message -int mapif_guild_message(int guild_id,int account_id,char *mes,int len, int sfd) -{ - unsigned char buf[512]; - if (len > 500) - len = 500; - WBUFW(buf,0)=0x3837; - WBUFW(buf,2)=len+12; - WBUFL(buf,4)=guild_id; - WBUFL(buf,8)=account_id; - memcpy(WBUFP(buf,12),mes,len); - mapif_sendallwos(sfd, buf,len+12); - return 0; -} - -// Send basic info -int mapif_guild_basicinfochanged(int guild_id,int type,const void *data,int len) -{ - unsigned char buf[2048]; - if (len > 2038) - len = 2038; - WBUFW(buf, 0)=0x3839; - WBUFW(buf, 2)=len+10; - WBUFL(buf, 4)=guild_id; - WBUFW(buf, 8)=type; - memcpy(WBUFP(buf,10),data,len); - mapif_sendall(buf,len+10); - return 0; -} - -// Send member info -int mapif_guild_memberinfochanged(int guild_id,int account_id,int char_id, int type,const void *data,int len) -{ - unsigned char buf[2048]; - if (len > 2030) - len = 2030; - WBUFW(buf, 0)=0x383a; - WBUFW(buf, 2)=len+18; - WBUFL(buf, 4)=guild_id; - WBUFL(buf, 8)=account_id; - WBUFL(buf,12)=char_id; - WBUFW(buf,16)=type; - memcpy(WBUFP(buf,18),data,len); - mapif_sendall(buf,len+18); - return 0; -} - -// ACK guild skill up -int mapif_guild_skillupack(int guild_id,int skill_num,int account_id) -{ - unsigned char buf[14]; - WBUFW(buf, 0)=0x383c; - WBUFL(buf, 2)=guild_id; - WBUFL(buf, 6)=skill_num; - WBUFL(buf,10)=account_id; - mapif_sendall(buf,14); - return 0; -} - -// ACK guild alliance -int mapif_guild_alliance(int guild_id1,int guild_id2,int account_id1,int account_id2,int flag,const char *name1,const char *name2) -{ - unsigned char buf[19+2*NAME_LENGTH]; - WBUFW(buf, 0)=0x383d; - WBUFL(buf, 2)=guild_id1; - WBUFL(buf, 6)=guild_id2; - WBUFL(buf,10)=account_id1; - WBUFL(buf,14)=account_id2; - WBUFB(buf,18)=flag; - memcpy(WBUFP(buf,19),name1,NAME_LENGTH); - memcpy(WBUFP(buf,19+NAME_LENGTH),name2,NAME_LENGTH); - mapif_sendall(buf,19+2*NAME_LENGTH); - return 0; -} - -// Send a guild position desc -int mapif_guild_position(struct guild *g,int idx) -{ - unsigned char buf[12 + sizeof(struct guild_position)]; - WBUFW(buf,0)=0x383b; - WBUFW(buf,2)=sizeof(struct guild_position)+12; - WBUFL(buf,4)=g->guild_id; - WBUFL(buf,8)=idx; - memcpy(WBUFP(buf,12),&g->position[idx],sizeof(struct guild_position)); - mapif_sendall(buf,WBUFW(buf,2)); - return 0; -} - -// Send the guild notice -int mapif_guild_notice(struct guild *g) -{ - unsigned char buf[256]; - WBUFW(buf,0)=0x383e; - WBUFL(buf,2)=g->guild_id; - memcpy(WBUFP(buf,6),g->mes1,MAX_GUILDMES1); - memcpy(WBUFP(buf,66),g->mes2,MAX_GUILDMES2); - mapif_sendall(buf,186); - return 0; -} - -// Send emblem data -int mapif_guild_emblem(struct guild *g) -{ - unsigned char buf[12 + sizeof(g->emblem_data)]; - WBUFW(buf,0)=0x383f; - WBUFW(buf,2)=g->emblem_len+12; - WBUFL(buf,4)=g->guild_id; - WBUFL(buf,8)=g->emblem_id; - memcpy(WBUFP(buf,12),g->emblem_data,g->emblem_len); - mapif_sendall(buf,WBUFW(buf,2)); - return 0; -} - -int mapif_guild_master_changed(struct guild *g, int aid, int cid) -{ - unsigned char buf[14]; - WBUFW(buf,0)=0x3843; - WBUFL(buf,2)=g->guild_id; - WBUFL(buf,6)=aid; - WBUFL(buf,10)=cid; - mapif_sendall(buf,14); - return 0; -} - -int mapif_guild_castle_dataload(int castle_id,int index,int value) -{ - unsigned char buf[9]; - WBUFW(buf, 0)=0x3840; - WBUFW(buf, 2)=castle_id; - WBUFB(buf, 4)=index; - WBUFL(buf, 5)=value; - mapif_sendall(buf,9); - return 0; -} - -int mapif_guild_castle_datasave(int castle_id,int index,int value) -{ - unsigned char buf[9]; - WBUFW(buf, 0)=0x3841; - WBUFW(buf, 2)=castle_id; - WBUFB(buf, 4)=index; - WBUFL(buf, 5)=value; - mapif_sendall(buf,9); - return 0; -} - -int mapif_guild_castle_alldataload(int fd) -{ - struct guild_castle s_gc; - struct guild_castle* gc = &s_gc; - int i; - int len; - char* data; - - WFIFOHEAD(fd, 4 + MAX_GUILDCASTLE*sizeof(struct guild_castle)); - WFIFOW(fd, 0) = 0x3842; - if( SQL_ERROR == Sql_Query(sql_handle, - "SELECT `castle_id`, `guild_id`, `economy`, `defense`, `triggerE`, `triggerD`, `nextTime`, `payTime`, `createTime`," - " `visibleC`, `visibleG0`, `visibleG1`, `visibleG2`, `visibleG3`, `visibleG4`, `visibleG5`, `visibleG6`, `visibleG7`" - " FROM `%s` ORDER BY `castle_id`", guild_castle_db) ) - Sql_ShowDebug(sql_handle); - for( i = 0, len = 4; i < MAX_GUILDCASTLE && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i ) - { - memset(gc, 0, sizeof(struct guild_castle)); - - Sql_GetData(sql_handle, 0, &data, NULL); gc->castle_id = atoi(data); - Sql_GetData(sql_handle, 1, &data, NULL); gc->guild_id = atoi(data); - Sql_GetData(sql_handle, 2, &data, NULL); gc->economy = atoi(data); - Sql_GetData(sql_handle, 3, &data, NULL); gc->defense = atoi(data); - Sql_GetData(sql_handle, 4, &data, NULL); gc->triggerE = atoi(data); - Sql_GetData(sql_handle, 5, &data, NULL); gc->triggerD = atoi(data); - Sql_GetData(sql_handle, 6, &data, NULL); gc->nextTime = atoi(data); - Sql_GetData(sql_handle, 7, &data, NULL); gc->payTime = atoi(data); - Sql_GetData(sql_handle, 8, &data, NULL); gc->createTime = atoi(data); - Sql_GetData(sql_handle, 9, &data, NULL); gc->visibleC = atoi(data); - Sql_GetData(sql_handle, 10, &data, NULL); gc->guardian[0].visible = atoi(data); - Sql_GetData(sql_handle, 11, &data, NULL); gc->guardian[1].visible = atoi(data); - Sql_GetData(sql_handle, 12, &data, NULL); gc->guardian[2].visible = atoi(data); - Sql_GetData(sql_handle, 13, &data, NULL); gc->guardian[3].visible = atoi(data); - Sql_GetData(sql_handle, 14, &data, NULL); gc->guardian[4].visible = atoi(data); - Sql_GetData(sql_handle, 15, &data, NULL); gc->guardian[5].visible = atoi(data); - Sql_GetData(sql_handle, 16, &data, NULL); gc->guardian[6].visible = atoi(data); - Sql_GetData(sql_handle, 17, &data, NULL); gc->guardian[7].visible = atoi(data); - - memcpy(WFIFOP(fd, len), gc, sizeof(struct guild_castle)); - len += sizeof(struct guild_castle); - } - Sql_FreeResult(sql_handle); - WFIFOW(fd, 2) = len; - WFIFOSET(fd, len); - - return 0; -} - - -//------------------------------------------------------------------- -// Packet received from map server - - -// ギルド作成要求 -int mapif_parse_CreateGuild(int fd,int account_id,char *name,struct guild_member *master) -{ - struct guild *g; - int i=0; -#ifdef NOISY - ShowInfo("Creating Guild (%s)\n", name); -#endif - if(search_guildname(name) != 0){ - ShowInfo("int_guild: guild with same name exists [%s]\n",name); - mapif_guild_created(fd,account_id,NULL); - return 0; - } - // Check Authorised letters/symbols in the name of the character - if (char_name_option == 1) { // only letters/symbols in char_name_letters are authorised - for (i = 0; i < NAME_LENGTH && name[i]; i++) - if (strchr(char_name_letters, name[i]) == NULL) { - mapif_guild_created(fd,account_id,NULL); - return 0; - } - } else if (char_name_option == 2) { // letters/symbols in char_name_letters are forbidden - for (i = 0; i < NAME_LENGTH && name[i]; i++) - if (strchr(char_name_letters, name[i]) != NULL) { - mapif_guild_created(fd,account_id,NULL); - return 0; - } - } - - g = (struct guild *)aMalloc(sizeof(struct guild)); - memset(g,0,sizeof(struct guild)); - - memcpy(g->name,name,NAME_LENGTH); - memcpy(g->master,master->name,NAME_LENGTH); - memcpy(&g->member[0],master,sizeof(struct guild_member)); - g->member[0].modified = GS_MEMBER_MODIFIED; - - // Set default positions - g->position[0].mode=0x11; - strcpy(g->position[0].name,"GuildMaster"); - strcpy(g->position[MAX_GUILDPOSITION-1].name,"Newbie"); - g->position[0].modified = g->position[MAX_GUILDPOSITION-1].modified = GS_POSITION_MODIFIED; - for(i=1;iposition[i].name,"Position %d",i+1); - g->position[i].modified = GS_POSITION_MODIFIED; - } - - // Initialize guild property - g->max_member=16; - g->average_lv=master->lv; - g->connect_member=1; - - for(i=0;iskill[i].id=i + GD_SKILLBASE; - g->guild_id= -1; //Request to create guild. - - // Create the guild - if (!inter_guild_tosql(g,GS_BASIC|GS_POSITION|GS_SKILL)) { - //Failed to Create guild.... - ShowError("Failed to create Guild %s (Guild Master: %s)\n", g->name, g->master); - mapif_guild_created(fd,account_id,NULL); - aFree(g); - return 0; - } - ShowInfo("Created Guild %d - %s (Guild Master: %s)\n", g->guild_id, g->name, g->master); - - //Add to cache - idb_put(guild_db_, g->guild_id, g); - - // Report to client - mapif_guild_created(fd,account_id,g); - mapif_guild_info(fd,g); - - if(log_inter) - inter_log("guild %s (id=%d) created by master %s (id=%d)\n", - name, g->guild_id, master->name, master->account_id ); - - return 0; -} - -// Return guild info to client -int mapif_parse_GuildInfo(int fd,int guild_id) -{ - struct guild * g = inter_guild_fromsql(guild_id); //We use this because on start-up the info of castle-owned guilds is requied. [Skotlex] - if(g) - { - if (!guild_calcinfo(g)) - mapif_guild_info(fd,g); - } - else - mapif_guild_noinfo(fd,guild_id); // Failed to load info - return 0; -} - -// Add member to guild -int mapif_parse_GuildAddMember(int fd,int guild_id,struct guild_member *m) -{ - struct guild * g; - int i; - - g = inter_guild_fromsql(guild_id); - if(g==NULL){ - // Failed to add - mapif_guild_memberadded(fd,guild_id,m->account_id,m->char_id,1); - return 0; - } - - // Find an empty slot - for(i=0;imax_member;i++) - { - if(g->member[i].account_id==0) - { - memcpy(&g->member[i],m,sizeof(struct guild_member)); - g->member[i].modified = (GS_MEMBER_NEW | GS_MEMBER_MODIFIED); - mapif_guild_memberadded(fd,guild_id,m->account_id,m->char_id,0); - if (!guild_calcinfo(g)) //Send members if it was not invoked. - mapif_guild_info(-1,g); - - g->save_flag |= GS_MEMBER; - if (g->save_flag&GS_REMOVE) - g->save_flag&=~GS_REMOVE; - return 0; - } - } - - // Failed to add - mapif_guild_memberadded(fd,guild_id,m->account_id,m->char_id,1); - return 0; -} - -// Delete member from guild -int mapif_parse_GuildLeave(int fd, int guild_id, int account_id, int char_id, int flag, const char *mes) -{ - int i, j; - - struct guild* g = inter_guild_fromsql(guild_id); - if( g == NULL ) - { - // Unknown guild, just update the player - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `guild_id`='0' WHERE `account_id`='%d' AND `char_id`='%d'", char_db, account_id, char_id) ) - Sql_ShowDebug(sql_handle); - // mapif_guild_withdraw(guild_id,account_id,char_id,flag,g->member[i].name,mes); - return 0; - } - - // Find the member - ARR_FIND( 0, g->max_member, i, g->member[i].account_id == account_id && g->member[i].char_id == char_id ); - if( i == g->max_member ) - { - //TODO - return 0; - } - - if( flag ) - { // Write expulsion reason - // Find an empty slot - ARR_FIND( 0, MAX_GUILDEXPULSION, j, g->expulsion[j].account_id == 0 ); - if( j == MAX_GUILDEXPULSION ) - { - // Expulsion list is full, flush the oldest one - for( j = 0; j < MAX_GUILDEXPULSION - 1; j++ ) - g->expulsion[j] = g->expulsion[j+1]; - j = MAX_GUILDEXPULSION-1; - } - // Save the expulsion entry - g->expulsion[j].account_id = account_id; - safestrncpy(g->expulsion[j].name, g->member[i].name, NAME_LENGTH); - safestrncpy(g->expulsion[j].mes, mes, 40); - } - - mapif_guild_withdraw(guild_id,account_id,char_id,flag,g->member[i].name,mes); - inter_guild_removemember_tosql(g->member[i].account_id,g->member[i].char_id); - - memset(&g->member[i],0,sizeof(struct guild_member)); - - if( guild_check_empty(g) ) - mapif_parse_BreakGuild(-1,guild_id); //Break the guild. - else { - //Update member info. - if (!guild_calcinfo(g)) - mapif_guild_info(fd,g); - g->save_flag |= GS_EXPULSION; - } - - return 0; -} - -// Change member info -int mapif_parse_GuildChangeMemberInfoShort(int fd,int guild_id,int account_id,int char_id,int online,int lv,int class_) -{ - // Could speed up by manipulating only guild_member - struct guild * g; - int i,sum,c; - int prev_count, prev_alv; - - g = inter_guild_fromsql(guild_id); - if(g==NULL) - return 0; - - ARR_FIND( 0, g->max_member, i, g->member[i].account_id == account_id && g->member[i].char_id == char_id ); - if( i < g->max_member ) - { - g->member[i].online = online; - g->member[i].lv = lv; - g->member[i].class_ = class_; - g->member[i].modified = GS_MEMBER_MODIFIED; - mapif_guild_memberinfoshort(g,i); - } - - prev_count = g->connect_member; - prev_alv = g->average_lv; - - g->average_lv = 0; - g->connect_member = 0; - c = 0; - sum = 0; - - for( i = 0; i < g->max_member; i++ ) - { - if( g->member[i].account_id > 0 ) - { - sum += g->member[i].lv; - c++; - } - if( g->member[i].online ) - g->connect_member++; - } - - if( c ) // this check should always succeed... - { - g->average_lv = sum / c; - if( g->connect_member != prev_count || g->average_lv != prev_alv ) - g->save_flag |= GS_CONNECT; - if( g->save_flag & GS_REMOVE ) - g->save_flag &= ~GS_REMOVE; - } - g->save_flag |= GS_MEMBER; //Update guild member data - return 0; -} - -// BreakGuild -int mapif_parse_BreakGuild(int fd,int guild_id) -{ - struct guild * g; - - g = inter_guild_fromsql(guild_id); - if(g==NULL) - return 0; - - // Delete guild from sql - //printf("- Delete guild %d from guild\n",guild_id); - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d'", guild_db, guild_id) ) - Sql_ShowDebug(sql_handle); - - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d'", guild_member_db, guild_id) ) - Sql_ShowDebug(sql_handle); - - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d'", guild_castle_db, guild_id) ) - Sql_ShowDebug(sql_handle); - - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d'", guild_storage_db, guild_id) ) - Sql_ShowDebug(sql_handle); - - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d' OR `alliance_id` = '%d'", guild_alliance_db, guild_id, guild_id) ) - Sql_ShowDebug(sql_handle); - - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d'", guild_position_db, guild_id) ) - Sql_ShowDebug(sql_handle); - - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d'", guild_skill_db, guild_id) ) - Sql_ShowDebug(sql_handle); - - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id` = '%d'", guild_expulsion_db, guild_id) ) - Sql_ShowDebug(sql_handle); - - //printf("- Update guild %d of char\n",guild_id); - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `guild_id`='0' WHERE `guild_id`='%d'", char_db, guild_id) ) - Sql_ShowDebug(sql_handle); - - mapif_guild_broken(guild_id,0); - - if(log_inter) - inter_log("guild %s (id=%d) broken\n",g->name,guild_id); - - //Remove the guild from memory. [Skotlex] - idb_remove(guild_db_, guild_id); - return 0; -} - -// Forward Guild message to others map servers -int mapif_parse_GuildMessage(int fd,int guild_id,int account_id,char *mes,int len) -{ - return mapif_guild_message(guild_id,account_id,mes,len, fd); -} - -// Modification of the guild -int mapif_parse_GuildBasicInfoChange(int fd,int guild_id,int type,const char *data,int len) -{ - struct guild * g; - short dw=*((short *)data); - g = inter_guild_fromsql(guild_id); - if(g==NULL) - return 0; - - switch(type) - { - case GBI_GUILDLV: - if(dw>0 && g->guild_lv+dw<=50) - { - g->guild_lv+=dw; - g->skill_point+=dw; - } - else if(dw<0 && g->guild_lv+dw>=1) - g->guild_lv+=dw; - mapif_guild_info(-1,g); - g->save_flag |= GS_LEVEL; - return 0; - default: - ShowError("int_guild: GuildBasicInfoChange: Unknown type %d\n",type); - break; - } - mapif_guild_basicinfochanged(guild_id,type,data,len); - return 0; -} - -// Modification of the guild -int mapif_parse_GuildMemberInfoChange(int fd,int guild_id,int account_id,int char_id,int type,const char *data,int len) -{ - // Could make some improvement in speed, because only change guild_member - int i; - struct guild * g; - - g = inter_guild_fromsql(guild_id); - if(g==NULL) - return 0; - - // Search the member - for(i=0;imax_member;i++) - if( g->member[i].account_id==account_id && - g->member[i].char_id==char_id ) - break; - - // Not Found - if(i==g->max_member){ - ShowWarning("int_guild: GuildMemberChange: Not found %d,%d in guild (%d - %s)\n", - account_id,char_id,guild_id,g->name); - return 0; - } - - switch(type) - { - case GMI_POSITION: - { - g->member[i].position=*((short *)data); - g->member[i].modified = GS_MEMBER_MODIFIED; - mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len); - g->save_flag |= GS_MEMBER; - break; - } - case GMI_EXP: - { // EXP - uint64 exp, old_exp=g->member[i].exp; - g->member[i].exp=*((uint64 *)data); - g->member[i].modified = GS_MEMBER_MODIFIED; - if (g->member[i].exp > old_exp) - { - exp = g->member[i].exp - old_exp; - - // Compute gained exp - if (guild_exp_rate != 100) - exp = exp*guild_exp_rate/100; - - // Update guild exp - if (exp > UINT64_MAX - g->exp) - g->exp = UINT64_MAX; - else - g->exp+=exp; - - guild_calcinfo(g); - mapif_guild_basicinfochanged(guild_id,GBI_EXP,&g->exp,sizeof(g->exp)); - g->save_flag |= GS_LEVEL; - } - mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len); - g->save_flag |= GS_MEMBER; - break; - } - case GMI_HAIR: - { - g->member[i].hair=*((short *)data); - g->member[i].modified = GS_MEMBER_MODIFIED; - mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len); - g->save_flag |= GS_MEMBER; //Save new data. - break; - } - case GMI_HAIR_COLOR: - { - g->member[i].hair_color=*((short *)data); - g->member[i].modified = GS_MEMBER_MODIFIED; - mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len); - g->save_flag |= GS_MEMBER; //Save new data. - break; - } - case GMI_GENDER: - { - g->member[i].gender=*((short *)data); - g->member[i].modified = GS_MEMBER_MODIFIED; - mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len); - g->save_flag |= GS_MEMBER; //Save new data. - break; - } - case GMI_CLASS: - { - g->member[i].class_=*((short *)data); - g->member[i].modified = GS_MEMBER_MODIFIED; - mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len); - g->save_flag |= GS_MEMBER; //Save new data. - break; - } - case GMI_LEVEL: - { - g->member[i].lv=*((short *)data); - g->member[i].modified = GS_MEMBER_MODIFIED; - mapif_guild_memberinfochanged(guild_id,account_id,char_id,type,data,len); - g->save_flag |= GS_MEMBER; //Save new data. - break; - } - default: - ShowError("int_guild: GuildMemberInfoChange: Unknown type %d\n",type); - break; - } - return 0; -} - -int inter_guild_sex_changed(int guild_id,int account_id,int char_id, short gender) -{ - return mapif_parse_GuildMemberInfoChange(0, guild_id, account_id, char_id, GMI_GENDER, (const char*)&gender, sizeof(gender)); -} - -int inter_guild_charname_changed(int guild_id,int account_id, int char_id, char *name) -{ - struct guild *g; - int i, flag = 0; - - g = inter_guild_fromsql(guild_id); - if( g == NULL ) - { - ShowError("inter_guild_charrenamed: Can't find guild %d.\n", guild_id); - return 0; - } - - ARR_FIND(0, g->max_member, i, g->member[i].char_id == char_id); - if( i == g->max_member ) - { - ShowError("inter_guild_charrenamed: Can't find character %d in the guild\n", char_id); - return 0; - } - - if( !strcmp(g->member[i].name, g->master) ) - { - safestrncpy(g->master, name, NAME_LENGTH); - flag |= GS_BASIC; - } - safestrncpy(g->member[i].name, name, NAME_LENGTH); - g->member[i].modified = GS_MEMBER_MODIFIED; - flag |= GS_MEMBER; - - if( !inter_guild_tosql(g, flag) ) - return 0; - - mapif_guild_info(-1,g); - - return 0; -} - -// Change a position desc -int mapif_parse_GuildPosition(int fd,int guild_id,int idx,struct guild_position *p) -{ - // Could make some improvement in speed, because only change guild_position - struct guild * g; - - g = inter_guild_fromsql(guild_id); - if(g==NULL || idx<0 || idx>=MAX_GUILDPOSITION) - return 0; - - memcpy(&g->position[idx],p,sizeof(struct guild_position)); - mapif_guild_position(g,idx); - g->position[idx].modified = GS_POSITION_MODIFIED; - g->save_flag |= GS_POSITION; // Change guild_position - return 0; -} - -// Guild Skill UP -int mapif_parse_GuildSkillUp(int fd,int guild_id,int skill_num,int account_id,int max) -{ - struct guild * g; - int idx = skill_num - GD_SKILLBASE; - - g = inter_guild_fromsql(guild_id); - if(g == NULL || idx < 0 || idx >= MAX_GUILDSKILL) - return 0; - - if(g->skill_point>0 && g->skill[idx].id>0 && g->skill[idx].lvskill[idx].lv++; - g->skill_point--; - if (!guild_calcinfo(g)) - mapif_guild_info(-1,g); - mapif_guild_skillupack(guild_id,skill_num,account_id); - g->save_flag |= (GS_LEVEL|GS_SKILL); // Change guild & guild_skill - } - return 0; -} - -//Manual deletion of an alliance when partnering guild does not exists. [Skotlex] -static int mapif_parse_GuildDeleteAlliance(struct guild *g, int guild_id, int account_id1, int account_id2, int flag) -{ - int i; - char name[NAME_LENGTH]; - - ARR_FIND( 0, MAX_GUILDALLIANCE, i, g->alliance[i].guild_id == guild_id ); - if( i == MAX_GUILDALLIANCE ) - return -1; - - strcpy(name, g->alliance[i].name); - g->alliance[i].guild_id=0; - - mapif_guild_alliance(g->guild_id,guild_id,account_id1,account_id2,flag,g->name,name); - g->save_flag |= GS_ALLIANCE; - return 0; -} - -// Alliance modification -int mapif_parse_GuildAlliance(int fd,int guild_id1,int guild_id2,int account_id1,int account_id2,int flag) -{ - // Could speed up - struct guild *g[2]; - int j,i; - g[0] = inter_guild_fromsql(guild_id1); - g[1] = inter_guild_fromsql(guild_id2); - - if(g[0] && g[1]==NULL && (flag & GUILD_ALLIANCE_REMOVE)) //Requested to remove an alliance with a not found guild. - return mapif_parse_GuildDeleteAlliance(g[0], guild_id2, account_id1, account_id2, flag); //Try to do a manual removal of said guild. - - if(g[0]==NULL || g[1]==NULL) - return 0; - - if(flag&GUILD_ALLIANCE_REMOVE) - { - // Remove alliance/opposition, in case of alliance, remove on both side - for(i=0;i<2-(flag&GUILD_ALLIANCE_TYPE_MASK);i++) - { - ARR_FIND( 0, MAX_GUILDALLIANCE, j, g[i]->alliance[j].guild_id == g[1-i]->guild_id && g[i]->alliance[j].opposition == (flag&GUILD_ALLIANCE_TYPE_MASK) ); - if( j < MAX_GUILDALLIANCE ) - g[i]->alliance[j].guild_id = 0; - } - } - else - { - // Add alliance, in case of alliance, add on both side - for(i=0;i<2-(flag&GUILD_ALLIANCE_TYPE_MASK);i++) - { - // Search an empty slot - ARR_FIND( 0, MAX_GUILDALLIANCE, j, g[i]->alliance[j].guild_id == 0 ); - if( j < MAX_GUILDALLIANCE ) - { - g[i]->alliance[j].guild_id=g[1-i]->guild_id; - memcpy(g[i]->alliance[j].name,g[1-i]->name,NAME_LENGTH); - // Set alliance type - g[i]->alliance[j].opposition = flag&GUILD_ALLIANCE_TYPE_MASK; - } - } - } - - // Send on all map the new alliance/opposition - mapif_guild_alliance(guild_id1,guild_id2,account_id1,account_id2,flag,g[0]->name,g[1]->name); - - // Mark the two guild to be saved - g[0]->save_flag |= GS_ALLIANCE; - g[1]->save_flag |= GS_ALLIANCE; - return 0; -} - -// Change guild message -int mapif_parse_GuildNotice(int fd,int guild_id,const char *mes1,const char *mes2) -{ - struct guild *g; - - g = inter_guild_fromsql(guild_id); - if(g==NULL) - return 0; - - memcpy(g->mes1,mes1,MAX_GUILDMES1); - memcpy(g->mes2,mes2,MAX_GUILDMES2); - g->save_flag |= GS_MES; //Change mes of guild - return mapif_guild_notice(g); -} - -int mapif_parse_GuildEmblem(int fd,int len,int guild_id,int dummy,const char *data) -{ - struct guild * g; - - g = inter_guild_fromsql(guild_id); - if(g==NULL) - return 0; - - if (len > sizeof(g->emblem_data)) - len = sizeof(g->emblem_data); - - memcpy(g->emblem_data,data,len); - g->emblem_len=len; - g->emblem_id++; - g->save_flag |= GS_EMBLEM; //Change guild - return mapif_guild_emblem(g); -} - -int mapif_parse_GuildCastleDataLoad(int fd,int castle_id,int index) -{ - struct guild_castle gc; - if (!inter_guildcastle_fromsql(castle_id, &gc)) { - return mapif_guild_castle_dataload(castle_id,0,0); - } - switch(index){ - case 1: return mapif_guild_castle_dataload(gc.castle_id,index,gc.guild_id); break; - case 2: return mapif_guild_castle_dataload(gc.castle_id,index,gc.economy); break; - case 3: return mapif_guild_castle_dataload(gc.castle_id,index,gc.defense); break; - case 4: return mapif_guild_castle_dataload(gc.castle_id,index,gc.triggerE); break; - case 5: return mapif_guild_castle_dataload(gc.castle_id,index,gc.triggerD); break; - case 6: return mapif_guild_castle_dataload(gc.castle_id,index,gc.nextTime); break; - case 7: return mapif_guild_castle_dataload(gc.castle_id,index,gc.payTime); break; - case 8: return mapif_guild_castle_dataload(gc.castle_id,index,gc.createTime); break; - case 9: return mapif_guild_castle_dataload(gc.castle_id,index,gc.visibleC); break; - case 10: - case 11: - case 12: - case 13: - case 14: - case 15: - case 16: - case 17: - return mapif_guild_castle_dataload(gc.castle_id,index,gc.guardian[index-10].visible); break; - default: - ShowError("mapif_parse_GuildCastleDataLoad ERROR!! (Not found index=%d)\n", index); - return 0; - } -} - -int mapif_parse_GuildCastleDataSave(int fd,int castle_id,int index,int value) -{ - struct guild_castle gc; - if(!inter_guildcastle_fromsql(castle_id, &gc)) - return mapif_guild_castle_datasave(castle_id,index,value); - - switch(index){ - case 1: - if( gc.guild_id!=value ){ - int gid=(value)?value:gc.guild_id; - struct guild *g = (struct guild*)idb_get(guild_db_, gid); - if(log_inter) - inter_log("guild %s (id=%d) %s castle id=%d\n", - (g)?g->name:"??" ,gid, (value)?"occupy":"abandon", castle_id); - } - gc.guild_id = value; - if(gc.guild_id == 0) { - //Delete guardians. - memset(&gc.guardian, 0, sizeof(gc.guardian)); - } - break; - case 2: gc.economy = value; break; - case 3: gc.defense = value; break; - case 4: gc.triggerE = value; break; - case 5: gc.triggerD = value; break; - case 6: gc.nextTime = value; break; - case 7: gc.payTime = value; break; - case 8: gc.createTime = value; break; - case 9: gc.visibleC = value; break; - case 10: - case 11: - case 12: - case 13: - case 14: - case 15: - case 16: - case 17: - gc.guardian[index-10].visible = value; break; - default: - ShowError("mapif_parse_GuildCastleDataSave ERROR!! (Not found index=%d)\n", index); - return 0; - } - inter_guildcastle_tosql(&gc); - mapif_guild_castle_datasave(gc.castle_id,index,value); - return 0; -} - -int mapif_parse_GuildMasterChange(int fd, int guild_id, const char* name, int len) -{ - struct guild * g; - struct guild_member gm; - int pos; - - g = inter_guild_fromsql(guild_id); - - if(g==NULL || len > NAME_LENGTH) - return 0; - - // Find member (name) - for (pos = 0; pos < g->max_member && strncmp(g->member[pos].name, name, len); pos++); - - if (pos == g->max_member) - return 0; //Character not found?? - - // Switch current and old GM - memcpy(&gm, &g->member[pos], sizeof (struct guild_member)); - memcpy(&g->member[pos], &g->member[0], sizeof(struct guild_member)); - memcpy(&g->member[0], &gm, sizeof(struct guild_member)); - - // Switch positions - g->member[pos].position = g->member[0].position; - g->member[pos].modified = GS_MEMBER_MODIFIED; - g->member[0].position = 0; //Position 0: guild Master. - g->member[0].modified = GS_MEMBER_MODIFIED; - - strncpy(g->master, name, len); - if (len < NAME_LENGTH) - g->master[len] = '\0'; - - ShowInfo("int_guild: Guildmaster Changed to %s (Guild %d - %s)\n",g->master, guild_id, g->name); - g->save_flag |= (GS_BASIC|GS_MEMBER); //Save main data and member data. - return mapif_guild_master_changed(g, g->member[0].account_id, g->member[0].char_id); -} - -// map server からの通信 -// ・1パケットのみ解析すること -// ・パケット長データはinter.cにセットしておくこと -// ・パケット長チェックや、RFIFOSKIPは呼び出し元で行われるので行ってはならない -// ・エラーなら0(false)、そうでないなら1(true)をかえさなければならない -int inter_guild_parse_frommap(int fd) -{ - RFIFOHEAD(fd); - switch(RFIFOW(fd,0)) { - case 0x3030: mapif_parse_CreateGuild(fd,RFIFOL(fd,4),(char*)RFIFOP(fd,8),(struct guild_member *)RFIFOP(fd,32)); break; - case 0x3031: mapif_parse_GuildInfo(fd,RFIFOL(fd,2)); break; - case 0x3032: mapif_parse_GuildAddMember(fd,RFIFOL(fd,4),(struct guild_member *)RFIFOP(fd,8)); break; - case 0x3033: mapif_parse_GuildMasterChange(fd,RFIFOL(fd,4),(const char*)RFIFOP(fd,8),RFIFOW(fd,2)-8); break; - case 0x3034: mapif_parse_GuildLeave(fd,RFIFOL(fd,2),RFIFOL(fd,6),RFIFOL(fd,10),RFIFOB(fd,14),(const char*)RFIFOP(fd,15)); break; - case 0x3035: mapif_parse_GuildChangeMemberInfoShort(fd,RFIFOL(fd,2),RFIFOL(fd,6),RFIFOL(fd,10),RFIFOB(fd,14),RFIFOW(fd,15),RFIFOW(fd,17)); break; - case 0x3036: mapif_parse_BreakGuild(fd,RFIFOL(fd,2)); break; - case 0x3037: mapif_parse_GuildMessage(fd,RFIFOL(fd,4),RFIFOL(fd,8),(char*)RFIFOP(fd,12),RFIFOW(fd,2)-12); break; - case 0x3039: mapif_parse_GuildBasicInfoChange(fd,RFIFOL(fd,4),RFIFOW(fd,8),(const char*)RFIFOP(fd,10),RFIFOW(fd,2)-10); break; - case 0x303A: mapif_parse_GuildMemberInfoChange(fd,RFIFOL(fd,4),RFIFOL(fd,8),RFIFOL(fd,12),RFIFOW(fd,16),(const char*)RFIFOP(fd,18),RFIFOW(fd,2)-18); break; - case 0x303B: mapif_parse_GuildPosition(fd,RFIFOL(fd,4),RFIFOL(fd,8),(struct guild_position *)RFIFOP(fd,12)); break; - case 0x303C: mapif_parse_GuildSkillUp(fd,RFIFOL(fd,2),RFIFOL(fd,6),RFIFOL(fd,10),RFIFOL(fd,14)); break; - case 0x303D: mapif_parse_GuildAlliance(fd,RFIFOL(fd,2),RFIFOL(fd,6),RFIFOL(fd,10),RFIFOL(fd,14),RFIFOB(fd,18)); break; - case 0x303E: mapif_parse_GuildNotice(fd,RFIFOL(fd,2),(const char*)RFIFOP(fd,6),(const char*)RFIFOP(fd,66)); break; - case 0x303F: mapif_parse_GuildEmblem(fd,RFIFOW(fd,2)-12,RFIFOL(fd,4),RFIFOL(fd,8),(const char*)RFIFOP(fd,12)); break; - case 0x3040: mapif_parse_GuildCastleDataLoad(fd,RFIFOW(fd,2),RFIFOB(fd,4)); break; - case 0x3041: mapif_parse_GuildCastleDataSave(fd,RFIFOW(fd,2),RFIFOB(fd,4),RFIFOL(fd,5)); break; - - default: - return 0; - } - - return 1; -} - -// processes a mapserver connection event -int inter_guild_mapif_init(int fd) -{ - return mapif_guild_castle_alldataload(fd); -} - -// サーバーから脱退要求(キャラ削除用) -int inter_guild_leave(int guild_id, int account_id, int char_id) -{ - return mapif_parse_GuildLeave(-1, guild_id, account_id, char_id, 0, "** Character Deleted **"); -} - -int inter_guild_broken(int guild_id) -{ - return mapif_guild_broken(guild_id, 0); -} -#endif //TXT_SQL_CONVERT diff --git a/src/char_sql/int_guild.h b/src/char_sql/int_guild.h deleted file mode 100644 index 4577357f3..000000000 --- a/src/char_sql/int_guild.h +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder - -#ifndef _INT_GUILD_SQL_H_ -#define _INT_GUILD_SQL_H_ - -#define GS_BASIC 0x0001 -#define GS_MEMBER 0x0002 -#define GS_POSITION 0x0004 -#define GS_ALLIANCE 0x0008 -#define GS_EXPULSION 0x0010 -#define GS_SKILL 0x0020 -#define GS_EMBLEM 0x0040 -#define GS_CONNECT 0x0080 -#define GS_LEVEL 0x0100 -#define GS_MES 0x0200 -#define GS_MASK 0x03FF -#define GS_BASIC_MASK (GS_BASIC | GS_EMBLEM | GS_CONNECT | GS_LEVEL | GS_MES) -#define GS_REMOVE 0x8000 - -struct guild; -struct guild_castle; - -int inter_guild_parse_frommap(int fd); -int inter_guild_sql_init(void); -void inter_guild_sql_final(void); -int inter_guild_mapif_init(int fd); -int inter_guild_leave(int guild_id,int account_id,int char_id); -int mapif_parse_BreakGuild(int fd,int guild_id); -int inter_guild_broken(int guild_id); -int inter_guild_sex_changed(int guild_id,int account_id,int char_id, short gender); -int inter_guild_charname_changed(int guild_id,int account_id, int char_id, char *name); -int inter_guild_CharOnline(int char_id, int guild_id); -int inter_guild_CharOffline(int char_id, int guild_id); - -//For the TXT->SQL converter. -int inter_guild_tosql(struct guild *g,int flag); -int inter_guildcastle_tosql(struct guild_castle *gc); - -#endif /* _INT_GUILD_SQL_H_ */ diff --git a/src/char_sql/int_homun.c b/src/char_sql/int_homun.c deleted file mode 100644 index d5a928e59..000000000 --- a/src/char_sql/int_homun.c +++ /dev/null @@ -1,313 +0,0 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder - -#include "../common/mmo.h" -#include "../common/malloc.h" -#include "../common/strlib.h" -#include "../common/showmsg.h" -#include "../common/socket.h" -#include "../common/utils.h" -#include "../common/sql.h" -#include "char.h" -#include "inter.h" - -#include -#include -#include - - -int inter_homunculus_sql_init(void) -{ - return 0; -} -void inter_homunculus_sql_final(void) -{ - return; -} - -static void mapif_homunculus_created(int fd, int account_id, struct s_homunculus *sh, unsigned char flag) -{ - WFIFOHEAD(fd, sizeof(struct s_homunculus)+9); - WFIFOW(fd,0) = 0x3890; - WFIFOW(fd,2) = sizeof(struct s_homunculus)+9; - WFIFOL(fd,4) = account_id; - WFIFOB(fd,8)= flag; - memcpy(WFIFOP(fd,9),sh,sizeof(struct s_homunculus)); - WFIFOSET(fd, WFIFOW(fd,2)); -} - -static void mapif_homunculus_deleted(int fd, int flag) -{ - WFIFOHEAD(fd, 3); - WFIFOW(fd, 0) = 0x3893; - WFIFOB(fd,2) = flag; //Flag 1 = success - WFIFOSET(fd, 3); -} - -static void mapif_homunculus_loaded(int fd, int account_id, struct s_homunculus *hd) -{ - WFIFOHEAD(fd, sizeof(struct s_homunculus)+9); - WFIFOW(fd,0) = 0x3891; - WFIFOW(fd,2) = sizeof(struct s_homunculus)+9; - WFIFOL(fd,4) = account_id; - if( hd != NULL ) - { - WFIFOB(fd,8) = 1; // success - memcpy(WFIFOP(fd,9), hd, sizeof(struct s_homunculus)); - } - else - { - WFIFOB(fd,8) = 0; // not found. - memset(WFIFOP(fd,9), 0, sizeof(struct s_homunculus)); - } - WFIFOSET(fd, sizeof(struct s_homunculus)+9); -} - -static void mapif_homunculus_saved(int fd, int account_id, bool flag) -{ - WFIFOHEAD(fd, 7); - WFIFOW(fd,0) = 0x3892; - WFIFOL(fd,2) = account_id; - WFIFOB(fd,6) = flag; // 1:success, 0:failure - WFIFOSET(fd, 7); -} - -static void mapif_homunculus_renamed(int fd, int account_id, int char_id, unsigned char flag, char* name) -{ - WFIFOHEAD(fd, NAME_LENGTH+12); - WFIFOW(fd, 0) = 0x3894; - WFIFOL(fd, 2) = account_id; - WFIFOL(fd, 6) = char_id; - WFIFOB(fd,10) = flag; - safestrncpy((char*)WFIFOP(fd,11), name, NAME_LENGTH); - WFIFOSET(fd, NAME_LENGTH+12); -} - -bool mapif_homunculus_save(struct s_homunculus* hd) -{ - bool flag = true; - char esc_name[NAME_LENGTH*2+1]; - - Sql_EscapeStringLen(sql_handle, esc_name, hd->name, strnlen(hd->name, NAME_LENGTH)); - - if( hd->hom_id == 0 ) - {// new homunculus - if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `homunculus` " - "(`char_id`, `class`,`name`,`level`,`exp`,`intimacy`,`hunger`, `str`, `agi`, `vit`, `int`, `dex`, `luk`, `hp`,`max_hp`,`sp`,`max_sp`,`skill_point`, `rename_flag`, `vaporize`) " - "VALUES ('%d', '%d', '%s', '%d', '%u', '%u', '%d', '%d', %d, '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d')", - hd->char_id, hd->class_, esc_name, hd->level, hd->exp, hd->intimacy, hd->hunger, hd->str, hd->agi, hd->vit, hd->int_, hd->dex, hd->luk, - hd->hp, hd->max_hp, hd->sp, hd->max_sp, hd->skillpts, hd->rename_flag, hd->vaporize) ) - { - Sql_ShowDebug(sql_handle); - flag = false; - } - else - { - hd->hom_id = (int)Sql_LastInsertId(sql_handle); - } - } - else - { - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `homunculus` SET `char_id`='%d', `class`='%d',`name`='%s',`level`='%d',`exp`='%u',`intimacy`='%u',`hunger`='%d', `str`='%d', `agi`='%d', `vit`='%d', `int`='%d', `dex`='%d', `luk`='%d', `hp`='%d',`max_hp`='%d',`sp`='%d',`max_sp`='%d',`skill_point`='%d', `rename_flag`='%d', `vaporize`='%d' WHERE `homun_id`='%d'", - hd->char_id, hd->class_, esc_name, hd->level, hd->exp, hd->intimacy, hd->hunger, hd->str, hd->agi, hd->vit, hd->int_, hd->dex, hd->luk, - hd->hp, hd->max_hp, hd->sp, hd->max_sp, hd->skillpts, hd->rename_flag, hd->vaporize, hd->hom_id) ) - { - Sql_ShowDebug(sql_handle); - flag = false; - } - else - { - SqlStmt* stmt; - int i; - - stmt = SqlStmt_Malloc(sql_handle); - if( SQL_ERROR == SqlStmt_Prepare(stmt, "REPLACE INTO `skill_homunculus` (`homun_id`, `id`, `lv`) VALUES (%d, ?, ?)", hd->hom_id) ) - SqlStmt_ShowDebug(stmt); - for( i = 0; i < MAX_HOMUNSKILL; ++i ) - { - if( hd->hskill[i].id > 0 && hd->hskill[i].lv != 0 ) - { - SqlStmt_BindParam(stmt, 0, SQLDT_USHORT, &hd->hskill[i].id, 0); - SqlStmt_BindParam(stmt, 1, SQLDT_USHORT, &hd->hskill[i].lv, 0); - if( SQL_ERROR == SqlStmt_Execute(stmt) ) - { - SqlStmt_ShowDebug(stmt); - SqlStmt_Free(stmt); - flag = false; - break; - } - } - } - SqlStmt_Free(stmt); - } - } - - return flag; -} - - - -// Load an homunculus -bool mapif_homunculus_load(int homun_id, struct s_homunculus* hd) -{ - int i; - char* data; - size_t len; - - memset(hd, 0, sizeof(*hd)); - - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `homun_id`,`char_id`,`class`,`name`,`level`,`exp`,`intimacy`,`hunger`, `str`, `agi`, `vit`, `int`, `dex`, `luk`, `hp`,`max_hp`,`sp`,`max_sp`,`skill_point`,`rename_flag`, `vaporize` FROM `homunculus` WHERE `homun_id`='%u'", homun_id) ) - { - Sql_ShowDebug(sql_handle); - return false; - } - - if( !Sql_NumRows(sql_handle) ) - { //No homunculus found. - Sql_FreeResult(sql_handle); - return false; - } - if( SQL_SUCCESS != Sql_NextRow(sql_handle) ) - { - Sql_ShowDebug(sql_handle); - Sql_FreeResult(sql_handle); - return false; - } - - hd->hom_id = homun_id; - Sql_GetData(sql_handle, 1, &data, NULL); hd->char_id = atoi(data); - Sql_GetData(sql_handle, 2, &data, NULL); hd->class_ = atoi(data); - Sql_GetData(sql_handle, 3, &data, &len); safestrncpy(hd->name, data, sizeof(hd->name)); - Sql_GetData(sql_handle, 4, &data, NULL); hd->level = atoi(data); - Sql_GetData(sql_handle, 5, &data, NULL); hd->exp = atoi(data); - Sql_GetData(sql_handle, 6, &data, NULL); hd->intimacy = (unsigned int)strtoul(data, NULL, 10); - Sql_GetData(sql_handle, 7, &data, NULL); hd->hunger = atoi(data); - Sql_GetData(sql_handle, 8, &data, NULL); hd->str = atoi(data); - Sql_GetData(sql_handle, 9, &data, NULL); hd->agi = atoi(data); - Sql_GetData(sql_handle, 10, &data, NULL); hd->vit = atoi(data); - Sql_GetData(sql_handle, 11, &data, NULL); hd->int_ = atoi(data); - Sql_GetData(sql_handle, 12, &data, NULL); hd->dex = atoi(data); - Sql_GetData(sql_handle, 13, &data, NULL); hd->luk = atoi(data); - Sql_GetData(sql_handle, 14, &data, NULL); hd->hp = atoi(data); - Sql_GetData(sql_handle, 15, &data, NULL); hd->max_hp = atoi(data); - Sql_GetData(sql_handle, 16, &data, NULL); hd->sp = atoi(data); - Sql_GetData(sql_handle, 17, &data, NULL); hd->max_sp = atoi(data); - Sql_GetData(sql_handle, 18, &data, NULL); hd->skillpts = atoi(data); - Sql_GetData(sql_handle, 19, &data, NULL); hd->rename_flag = atoi(data); - Sql_GetData(sql_handle, 20, &data, NULL); hd->vaporize = atoi(data); - Sql_FreeResult(sql_handle); - - hd->intimacy = cap_value(hd->intimacy, 0, 100000); - hd->hunger = cap_value(hd->hunger, 0, 100); - - // Load Homunculus Skill - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `id`,`lv` FROM `skill_homunculus` WHERE `homun_id`=%d", homun_id) ) - { - Sql_ShowDebug(sql_handle); - return false; - } - while( SQL_SUCCESS == Sql_NextRow(sql_handle) ) - { - // id - Sql_GetData(sql_handle, 0, &data, NULL); - i = atoi(data); - if( i < HM_SKILLBASE || i >= HM_SKILLBASE + MAX_HOMUNSKILL ) - continue;// invalid skill id - i = i - HM_SKILLBASE; - hd->hskill[i].id = (unsigned short)atoi(data); - - // lv - Sql_GetData(sql_handle, 1, &data, NULL); - hd->hskill[i].lv = (unsigned char)atoi(data); - } - Sql_FreeResult(sql_handle); - - if( save_log ) - ShowInfo("Homunculus loaded (%d - %s).\n", hd->hom_id, hd->name); - - return true; -} - -bool mapif_homunculus_delete(int homun_id) -{ - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `homunculus` WHERE `homun_id` = '%u'", homun_id) - || SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `skill_homunculus` WHERE `homun_id` = '%u'", homun_id) - ) { - Sql_ShowDebug(sql_handle); - return false; - } - return true; -} - -bool mapif_homunculus_rename(char *name) -{ - int i; - - // Check Authorised letters/symbols in the name of the homun - if( char_name_option == 1 ) - {// only letters/symbols in char_name_letters are authorised - for( i = 0; i < NAME_LENGTH && name[i]; i++ ) - if( strchr(char_name_letters, name[i]) == NULL ) - return false; - } else - if( char_name_option == 2 ) - {// letters/symbols in char_name_letters are forbidden - for( i = 0; i < NAME_LENGTH && name[i]; i++ ) - if( strchr(char_name_letters, name[i]) != NULL ) - return false; - } - - return true; -} - - -static void mapif_parse_homunculus_create(int fd, int len, int account_id, struct s_homunculus* phd) -{ - bool result = mapif_homunculus_save(phd); - mapif_homunculus_created(fd, account_id, phd, result); -} - -static void mapif_parse_homunculus_delete(int fd, int homun_id) -{ - bool result = mapif_homunculus_delete(homun_id); - mapif_homunculus_deleted(fd, result); -} - -static void mapif_parse_homunculus_load(int fd, int account_id, int homun_id) -{ - struct s_homunculus hd; - bool result = mapif_homunculus_load(homun_id, &hd); - mapif_homunculus_loaded(fd, account_id, ( result ? &hd : NULL )); -} - -static void mapif_parse_homunculus_save(int fd, int len, int account_id, struct s_homunculus* phd) -{ - bool result = mapif_homunculus_save(phd); - mapif_homunculus_saved(fd, account_id, result); -} - -static void mapif_parse_homunculus_rename(int fd, int account_id, int char_id, char* name) -{ - bool result = mapif_homunculus_rename(name); - mapif_homunculus_renamed(fd, account_id, char_id, result, name); -} - -/*========================================== - * Inter Packets - *------------------------------------------*/ -int inter_homunculus_parse_frommap(int fd) -{ - unsigned short cmd = RFIFOW(fd,0); - - switch( cmd ) - { - case 0x3090: mapif_parse_homunculus_create(fd, (int)RFIFOW(fd,2), (int)RFIFOL(fd,4), (struct s_homunculus*)RFIFOP(fd,8)); break; - case 0x3091: mapif_parse_homunculus_load (fd, (int)RFIFOL(fd,2), (int)RFIFOL(fd,6)); break; - case 0x3092: mapif_parse_homunculus_save (fd, (int)RFIFOW(fd,2), (int)RFIFOL(fd,4), (struct s_homunculus*)RFIFOP(fd,8)); break; - case 0x3093: mapif_parse_homunculus_delete(fd, (int)RFIFOL(fd,2)); break; - case 0x3094: mapif_parse_homunculus_rename(fd, (int)RFIFOL(fd,2), (int)RFIFOL(fd,6), (char*)RFIFOP(fd,10)); break; - default: - return 0; - } - return 1; -} diff --git a/src/char_sql/int_homun.h b/src/char_sql/int_homun.h deleted file mode 100644 index 1c0d76269..000000000 --- a/src/char_sql/int_homun.h +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder - -#ifndef _INT_HOMUN_SQL_H_ -#define _INT_HOMUN_SQL_H_ - -struct s_homunculus; - -int inter_homunculus_sql_init(void); -void inter_homunculus_sql_final(void); -int inter_homunculus_parse_frommap(int fd); - -bool mapif_homunculus_save(struct s_homunculus* hd); -bool mapif_homunculus_load(int homun_id, struct s_homunculus* hd); -bool mapif_homunculus_delete(int homun_id); -bool mapif_homunculus_rename(char *name); - -#endif /* _INT_HOMUN_SQL_H_ */ diff --git a/src/char_sql/int_mail.c b/src/char_sql/int_mail.c deleted file mode 100644 index b19b732c7..000000000 --- a/src/char_sql/int_mail.c +++ /dev/null @@ -1,476 +0,0 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder - -#include "../common/mmo.h" -#include "../common/malloc.h" -#include "../common/showmsg.h" -#include "../common/socket.h" -#include "../common/strlib.h" -#include "../common/sql.h" -#include "../common/timer.h" -#include "char.h" -#include "inter.h" - -#include -#include -#include - -static int mail_fromsql(int char_id, struct mail_data* md) -{ - int i, j; - struct mail_message *msg; - struct item *item; - char *data; - StringBuf buf; - - memset(md, 0, sizeof(struct mail_data)); - md->amount = 0; - md->full = false; - - StringBuf_Init(&buf); - StringBuf_AppendStr(&buf, "SELECT `id`,`send_name`,`send_id`,`dest_name`,`dest_id`,`title`,`message`,`time`,`status`," - "`zeny`,`amount`,`nameid`,`refine`,`attribute`,`identify`"); - for (i = 0; i < MAX_SLOTS; i++) - StringBuf_Printf(&buf, ",`card%d`", i); - - // I keep the `status` < 3 just in case someone forget to apply the sqlfix - StringBuf_Printf(&buf, " FROM `%s` WHERE `dest_id`='%d' AND `status` < 3 ORDER BY `id` LIMIT %d", - mail_db, char_id, MAIL_MAX_INBOX + 1); - - if( SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf)) ) - Sql_ShowDebug(sql_handle); - - StringBuf_Destroy(&buf); - - for (i = 0; i < MAIL_MAX_INBOX && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i ) - { - msg = &md->msg[i]; - Sql_GetData(sql_handle, 0, &data, NULL); msg->id = atoi(data); - Sql_GetData(sql_handle, 1, &data, NULL); safestrncpy(msg->send_name, data, NAME_LENGTH); - Sql_GetData(sql_handle, 2, &data, NULL); msg->send_id = atoi(data); - Sql_GetData(sql_handle, 3, &data, NULL); safestrncpy(msg->dest_name, data, NAME_LENGTH); - Sql_GetData(sql_handle, 4, &data, NULL); msg->dest_id = atoi(data); - Sql_GetData(sql_handle, 5, &data, NULL); safestrncpy(msg->title, data, MAIL_TITLE_LENGTH); - Sql_GetData(sql_handle, 6, &data, NULL); safestrncpy(msg->body, data, MAIL_BODY_LENGTH); - Sql_GetData(sql_handle, 7, &data, NULL); msg->timestamp = atoi(data); - Sql_GetData(sql_handle, 8, &data, NULL); msg->status = (mail_status)atoi(data); - Sql_GetData(sql_handle, 9, &data, NULL); msg->zeny = atoi(data); - item = &msg->item; - Sql_GetData(sql_handle,10, &data, NULL); item->amount = (short)atoi(data); - Sql_GetData(sql_handle,11, &data, NULL); item->nameid = atoi(data); - Sql_GetData(sql_handle,12, &data, NULL); item->refine = atoi(data); - Sql_GetData(sql_handle,13, &data, NULL); item->attribute = atoi(data); - Sql_GetData(sql_handle,14, &data, NULL); item->identify = atoi(data); - item->expire_time = 0; - - for (j = 0; j < MAX_SLOTS; j++) - { - Sql_GetData(sql_handle, 15 + j, &data, NULL); - item->card[j] = atoi(data); - } - } - - md->full = ( Sql_NumRows(sql_handle) > MAIL_MAX_INBOX ); - - md->amount = i; - Sql_FreeResult(sql_handle); - - md->unchecked = 0; - md->unread = 0; - for (i = 0; i < md->amount; i++) - { - msg = &md->msg[i]; - if( msg->status == MAIL_NEW ) - { - if ( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `status` = '%d' WHERE `id` = '%d'", mail_db, MAIL_UNREAD, msg->id) ) - Sql_ShowDebug(sql_handle); - - msg->status = MAIL_UNREAD; - md->unchecked++; - } - else if ( msg->status == MAIL_UNREAD ) - md->unread++; - } - - ShowInfo("mail load complete from DB - id: %d (total: %d)\n", char_id, md->amount); - return 1; -} - -/// Stores a single message in the database. -/// Returns the message's ID if successful (or 0 if it fails). -int mail_savemessage(struct mail_message* msg) -{ - StringBuf buf; - SqlStmt* stmt; - int j; - - // build message save query - StringBuf_Init(&buf); - StringBuf_Printf(&buf, "INSERT INTO `%s` (`send_name`, `send_id`, `dest_name`, `dest_id`, `title`, `message`, `time`, `status`, `zeny`, `amount`, `nameid`, `refine`, `attribute`, `identify`", mail_db); - for (j = 0; j < MAX_SLOTS; j++) - StringBuf_Printf(&buf, ", `card%d`", j); - StringBuf_Printf(&buf, ") VALUES (?, '%d', ?, '%d', ?, ?, '%lu', '%d', '%d', '%d', '%d', '%d', '%d', '%d'", - msg->send_id, msg->dest_id, (unsigned long)msg->timestamp, msg->status, msg->zeny, msg->item.amount, msg->item.nameid, msg->item.refine, msg->item.attribute, msg->item.identify); - for (j = 0; j < MAX_SLOTS; j++) - StringBuf_Printf(&buf, ", '%d'", msg->item.card[j]); - StringBuf_AppendStr(&buf, ")"); - - // prepare and execute query - stmt = SqlStmt_Malloc(sql_handle); - if( SQL_SUCCESS != SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_STRING, msg->send_name, strnlen(msg->send_name, NAME_LENGTH)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_STRING, msg->dest_name, strnlen(msg->dest_name, NAME_LENGTH)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 2, SQLDT_STRING, msg->title, strnlen(msg->title, MAIL_TITLE_LENGTH)) - || SQL_SUCCESS != SqlStmt_BindParam(stmt, 3, SQLDT_STRING, msg->body, strnlen(msg->body, MAIL_BODY_LENGTH)) - || SQL_SUCCESS != SqlStmt_Execute(stmt) ) - { - SqlStmt_ShowDebug(stmt); - msg->id = 0; - } else - msg->id = (int)SqlStmt_LastInsertId(stmt); - - SqlStmt_Free(stmt); - StringBuf_Destroy(&buf); - - return msg->id; -} - -/// Retrieves a single message from the database. -/// Returns true if the operation succeeds (or false if it fails). -static bool mail_loadmessage(int mail_id, struct mail_message* msg) -{ - int j; - StringBuf buf; - - StringBuf_Init(&buf); - StringBuf_AppendStr(&buf, "SELECT `id`,`send_name`,`send_id`,`dest_name`,`dest_id`,`title`,`message`,`time`,`status`," - "`zeny`,`amount`,`nameid`,`refine`,`attribute`,`identify`"); - for( j = 0; j < MAX_SLOTS; j++ ) - StringBuf_Printf(&buf, ",`card%d`", j); - StringBuf_Printf(&buf, " FROM `%s` WHERE `id` = '%d'", mail_db, mail_id); - - if( SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf)) - || SQL_SUCCESS != Sql_NextRow(sql_handle) ) - { - Sql_ShowDebug(sql_handle); - Sql_FreeResult(sql_handle); - StringBuf_Destroy(&buf); - return false; - } - else - { - char* data; - - Sql_GetData(sql_handle, 0, &data, NULL); msg->id = atoi(data); - Sql_GetData(sql_handle, 1, &data, NULL); safestrncpy(msg->send_name, data, NAME_LENGTH); - Sql_GetData(sql_handle, 2, &data, NULL); msg->send_id = atoi(data); - Sql_GetData(sql_handle, 3, &data, NULL); safestrncpy(msg->dest_name, data, NAME_LENGTH); - Sql_GetData(sql_handle, 4, &data, NULL); msg->dest_id = atoi(data); - Sql_GetData(sql_handle, 5, &data, NULL); safestrncpy(msg->title, data, MAIL_TITLE_LENGTH); - Sql_GetData(sql_handle, 6, &data, NULL); safestrncpy(msg->body, data, MAIL_BODY_LENGTH); - Sql_GetData(sql_handle, 7, &data, NULL); msg->timestamp = atoi(data); - Sql_GetData(sql_handle, 8, &data, NULL); msg->status = (mail_status)atoi(data); - Sql_GetData(sql_handle, 9, &data, NULL); msg->zeny = atoi(data); - Sql_GetData(sql_handle,10, &data, NULL); msg->item.amount = (short)atoi(data); - Sql_GetData(sql_handle,11, &data, NULL); msg->item.nameid = atoi(data); - Sql_GetData(sql_handle,12, &data, NULL); msg->item.refine = atoi(data); - Sql_GetData(sql_handle,13, &data, NULL); msg->item.attribute = atoi(data); - Sql_GetData(sql_handle,14, &data, NULL); msg->item.identify = atoi(data); - msg->item.expire_time = 0; - - for( j = 0; j < MAX_SLOTS; j++ ) - { - Sql_GetData(sql_handle,15 + j, &data, NULL); - msg->item.card[j] = atoi(data); - } - } - - StringBuf_Destroy(&buf); - Sql_FreeResult(sql_handle); - - return true; -} - -/*========================================== - * Client Inbox Request - *------------------------------------------*/ -static void mapif_Mail_sendinbox(int fd, int char_id, unsigned char flag) -{ - struct mail_data md; - mail_fromsql(char_id, &md); - - //FIXME: dumping the whole structure like this is unsafe [ultramage] - WFIFOHEAD(fd, sizeof(md) + 9); - WFIFOW(fd,0) = 0x3848; - WFIFOW(fd,2) = sizeof(md) + 9; - WFIFOL(fd,4) = char_id; - WFIFOB(fd,8) = flag; - memcpy(WFIFOP(fd,9),&md,sizeof(md)); - WFIFOSET(fd,WFIFOW(fd,2)); -} - -static void mapif_parse_Mail_requestinbox(int fd) -{ - mapif_Mail_sendinbox(fd, RFIFOL(fd,2), RFIFOB(fd,6)); -} - -/*========================================== - * Mark mail as 'Read' - *------------------------------------------*/ -static void mapif_parse_Mail_read(int fd) -{ - int mail_id = RFIFOL(fd,2); - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `status` = '%d' WHERE `id` = '%d'", mail_db, MAIL_READ, mail_id) ) - Sql_ShowDebug(sql_handle); -} - -/*========================================== - * Client Attachment Request - *------------------------------------------*/ -static bool mail_DeleteAttach(int mail_id) -{ - StringBuf buf; - int i; - - StringBuf_Init(&buf); - StringBuf_Printf(&buf, "UPDATE `%s` SET `zeny` = '0', `nameid` = '0', `amount` = '0', `refine` = '0', `attribute` = '0', `identify` = '0'", mail_db); - for (i = 0; i < MAX_SLOTS; i++) - StringBuf_Printf(&buf, ", `card%d` = '0'", i); - StringBuf_Printf(&buf, " WHERE `id` = '%d'", mail_id); - - if( SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf)) ) - { - Sql_ShowDebug(sql_handle); - StringBuf_Destroy(&buf); - - return false; - } - - StringBuf_Destroy(&buf); - return true; -} - -static void mapif_Mail_getattach(int fd, int char_id, int mail_id) -{ - struct mail_message msg; - - if( !mail_loadmessage(mail_id, &msg) ) - return; - - if( msg.dest_id != char_id ) - return; - - if( msg.status != MAIL_READ ) - return; - - if( (msg.item.nameid < 1 || msg.item.amount < 1) && msg.zeny < 1 ) - return; // No Attachment - - if( !mail_DeleteAttach(mail_id) ) - return; - - WFIFOHEAD(fd, sizeof(struct item) + 12); - WFIFOW(fd,0) = 0x384a; - WFIFOW(fd,2) = sizeof(struct item) + 12; - WFIFOL(fd,4) = char_id; - WFIFOL(fd,8) = (msg.zeny > 0)?msg.zeny:0; - memcpy(WFIFOP(fd,12), &msg.item, sizeof(struct item)); - WFIFOSET(fd,WFIFOW(fd,2)); -} - -static void mapif_parse_Mail_getattach(int fd) -{ - mapif_Mail_getattach(fd, RFIFOL(fd,2), RFIFOL(fd,6)); -} - -/*========================================== - * Delete Mail - *------------------------------------------*/ -static void mapif_Mail_delete(int fd, int char_id, int mail_id) -{ - bool failed = false; - if ( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `id` = '%d'", mail_db, mail_id) ) - { - Sql_ShowDebug(sql_handle); - failed = true; - } - - WFIFOHEAD(fd,11); - WFIFOW(fd,0) = 0x384b; - WFIFOL(fd,2) = char_id; - WFIFOL(fd,6) = mail_id; - WFIFOB(fd,10) = failed; - WFIFOSET(fd,11); -} - -static void mapif_parse_Mail_delete(int fd) -{ - mapif_Mail_delete(fd, RFIFOL(fd,2), RFIFOL(fd,6)); -} - -/*========================================== - * Report New Mail to Map Server - *------------------------------------------*/ -void mapif_Mail_new(struct mail_message *msg) -{ - unsigned char buf[74]; - - if( !msg || !msg->id ) - return; - - WBUFW(buf,0) = 0x3849; - WBUFL(buf,2) = msg->dest_id; - WBUFL(buf,6) = msg->id; - memcpy(WBUFP(buf,10), msg->send_name, NAME_LENGTH); - memcpy(WBUFP(buf,34), msg->title, MAIL_TITLE_LENGTH); - mapif_sendall(buf, 74); -} - -/*========================================== - * Return Mail - *------------------------------------------*/ -static void mapif_Mail_return(int fd, int char_id, int mail_id) -{ - struct mail_message msg; - int new_mail = 0; - - if( mail_loadmessage(mail_id, &msg) ) - { - if( msg.dest_id != char_id) - return; - else if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `id` = '%d'", mail_db, mail_id) ) - Sql_ShowDebug(sql_handle); - else - { - char temp_[MAIL_TITLE_LENGTH]; - - // swap sender and receiver - swap(msg.send_id, msg.dest_id); - safestrncpy(temp_, msg.send_name, NAME_LENGTH); - safestrncpy(msg.send_name, msg.dest_name, NAME_LENGTH); - safestrncpy(msg.dest_name, temp_, NAME_LENGTH); - - // set reply message title - snprintf(temp_, MAIL_TITLE_LENGTH, "RE:%s", msg.title); - safestrncpy(msg.title, temp_, MAIL_TITLE_LENGTH); - - msg.status = MAIL_NEW; - msg.timestamp = time(NULL); - - new_mail = mail_savemessage(&msg); - mapif_Mail_new(&msg); - } - } - - WFIFOHEAD(fd,11); - WFIFOW(fd,0) = 0x384c; - WFIFOL(fd,2) = char_id; - WFIFOL(fd,6) = mail_id; - WFIFOB(fd,10) = (new_mail == 0); - WFIFOSET(fd,11); -} - -static void mapif_parse_Mail_return(int fd) -{ - mapif_Mail_return(fd, RFIFOL(fd,2), RFIFOL(fd,6)); -} - -/*========================================== - * Send Mail - *------------------------------------------*/ -static void mapif_Mail_send(int fd, struct mail_message* msg) -{ - int len = sizeof(struct mail_message) + 4; - - WFIFOHEAD(fd,len); - WFIFOW(fd,0) = 0x384d; - WFIFOW(fd,2) = len; - memcpy(WFIFOP(fd,4), msg, sizeof(struct mail_message)); - WFIFOSET(fd,len); -} - -static void mapif_parse_Mail_send(int fd) -{ - struct mail_message msg; - char esc_name[NAME_LENGTH*2+1]; - int account_id = 0; - - if(RFIFOW(fd,2) != 8 + sizeof(struct mail_message)) - return; - - account_id = RFIFOL(fd,4); - memcpy(&msg, RFIFOP(fd,8), sizeof(struct mail_message)); - - // Try to find the Dest Char by Name - Sql_EscapeStringLen(sql_handle, esc_name, msg.dest_name, strnlen(msg.dest_name, NAME_LENGTH)); - if ( SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id`, `char_id` FROM `%s` WHERE `name` = '%s'", char_db, esc_name) ) - Sql_ShowDebug(sql_handle); - else - if ( SQL_SUCCESS == Sql_NextRow(sql_handle) ) - { - char *data; - Sql_GetData(sql_handle, 0, &data, NULL); - if (atoi(data) != account_id) - { // Cannot send mail to char in the same account - Sql_GetData(sql_handle, 1, &data, NULL); - msg.dest_id = atoi(data); - } - } - Sql_FreeResult(sql_handle); - msg.status = MAIL_NEW; - - if( msg.dest_id > 0 ) - msg.id = mail_savemessage(&msg); - - mapif_Mail_send(fd, &msg); -} - -void mail_sendmail(int send_id, const char* send_name, int dest_id, const char* dest_name, const char* title, const char* body, int zeny, struct item *item) -{ - struct mail_message msg; - memset(&msg, 0, sizeof(struct mail_message)); - - msg.send_id = send_id; - safestrncpy(msg.send_name, send_name, NAME_LENGTH); - msg.dest_id = dest_id; - safestrncpy(msg.dest_name, dest_name, NAME_LENGTH); - safestrncpy(msg.title, title, MAIL_TITLE_LENGTH); - safestrncpy(msg.body, body, MAIL_BODY_LENGTH); - msg.zeny = zeny; - if( item != NULL ) - memcpy(&msg.item, item, sizeof(struct item)); - - msg.timestamp = time(NULL); - - mail_savemessage(&msg); - mapif_Mail_new(&msg); -} - -/*========================================== - * Packets From Map Server - *------------------------------------------*/ -int inter_mail_parse_frommap(int fd) -{ - switch(RFIFOW(fd,0)) - { - case 0x3048: mapif_parse_Mail_requestinbox(fd); break; - case 0x3049: mapif_parse_Mail_read(fd); break; - case 0x304a: mapif_parse_Mail_getattach(fd); break; - case 0x304b: mapif_parse_Mail_delete(fd); break; - case 0x304c: mapif_parse_Mail_return(fd); break; - case 0x304d: mapif_parse_Mail_send(fd); break; - default: - return 0; - } - return 1; -} - -int inter_mail_sql_init(void) -{ - return 1; -} - -void inter_mail_sql_final(void) -{ - return; -} diff --git a/src/char_sql/int_mail.h b/src/char_sql/int_mail.h deleted file mode 100644 index 77db51e5b..000000000 --- a/src/char_sql/int_mail.h +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder - -#ifndef _INT_MAIL_SQL_H_ -#define _INT_MAIL_SQL_H_ - -int inter_mail_parse_frommap(int fd); -void mail_sendmail(int send_id, const char* send_name, int dest_id, const char* dest_name, const char* title, const char* body, int zeny, struct item *item); - -int inter_mail_sql_init(void); -void inter_mail_sql_final(void); - -int mail_savemessage(struct mail_message* msg); -void mapif_Mail_new(struct mail_message *msg); - -#endif /* _INT_MAIL_SQL_H_ */ diff --git a/src/char_sql/int_mercenary.c b/src/char_sql/int_mercenary.c deleted file mode 100644 index c7d7b687d..000000000 --- a/src/char_sql/int_mercenary.c +++ /dev/null @@ -1,221 +0,0 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder - -#include "../common/mmo.h" -#include "../common/malloc.h" -#include "../common/strlib.h" -#include "../common/showmsg.h" -#include "../common/socket.h" -#include "../common/utils.h" -#include "../common/sql.h" -#include "char.h" -#include "inter.h" - -#include -#include -#include - -bool mercenary_owner_fromsql(int char_id, struct mmo_charstatus *status) -{ - char* data; - - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `merc_id`, `arch_calls`, `arch_faith`, `spear_calls`, `spear_faith`, `sword_calls`, `sword_faith` FROM `mercenary_owner` WHERE `char_id` = '%d'", char_id) ) - { - Sql_ShowDebug(sql_handle); - return false; - } - - if( SQL_SUCCESS != Sql_NextRow(sql_handle) ) - { - Sql_FreeResult(sql_handle); - return false; - } - - Sql_GetData(sql_handle, 0, &data, NULL); status->mer_id = atoi(data); - Sql_GetData(sql_handle, 1, &data, NULL); status->arch_calls = atoi(data); - Sql_GetData(sql_handle, 2, &data, NULL); status->arch_faith = atoi(data); - Sql_GetData(sql_handle, 3, &data, NULL); status->spear_calls = atoi(data); - Sql_GetData(sql_handle, 4, &data, NULL); status->spear_faith = atoi(data); - Sql_GetData(sql_handle, 5, &data, NULL); status->sword_calls = atoi(data); - Sql_GetData(sql_handle, 6, &data, NULL); status->sword_faith = atoi(data); - Sql_FreeResult(sql_handle); - - return true; -} - -bool mercenary_owner_tosql(int char_id, struct mmo_charstatus *status) -{ - if( SQL_ERROR == Sql_Query(sql_handle, "REPLACE INTO `mercenary_owner` (`char_id`, `merc_id`, `arch_calls`, `arch_faith`, `spear_calls`, `spear_faith`, `sword_calls`, `sword_faith`) VALUES ('%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d')", - char_id, status->mer_id, status->arch_calls, status->arch_faith, status->spear_calls, status->spear_faith, status->sword_calls, status->sword_faith) ) - { - Sql_ShowDebug(sql_handle); - return false; - } - - return true; -} - -bool mercenary_owner_delete(int char_id) -{ - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `mercenary_owner` WHERE `char_id` = '%d'", char_id) ) - Sql_ShowDebug(sql_handle); - - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `mercenary` WHERE `char_id` = '%d'", char_id) ) - Sql_ShowDebug(sql_handle); - - return true; -} - -bool mapif_mercenary_save(struct s_mercenary* merc) -{ - bool flag = true; - - if( merc->mercenary_id == 0 ) - { // Create new DB entry - if( SQL_ERROR == Sql_Query(sql_handle, - "INSERT INTO `mercenary` (`char_id`,`class`,`hp`,`sp`,`kill_counter`,`life_time`) VALUES ('%d','%d','%d','%d','%u','%u')", - merc->char_id, merc->class_, merc->hp, merc->sp, merc->kill_count, merc->life_time) ) - { - Sql_ShowDebug(sql_handle); - flag = false; - } - else - merc->mercenary_id = (int)Sql_LastInsertId(sql_handle); - } - else if( SQL_ERROR == Sql_Query(sql_handle, - "UPDATE `mercenary` SET `char_id` = '%d', `class` = '%d', `hp` = '%d', `sp` = '%d', `kill_counter` = '%u', `life_time` = '%u' WHERE `mer_id` = '%d'", - merc->char_id, merc->class_, merc->hp, merc->sp, merc->kill_count, merc->life_time, merc->mercenary_id) ) - { // Update DB entry - Sql_ShowDebug(sql_handle); - flag = false; - } - - return flag; -} - -bool mapif_mercenary_load(int merc_id, int char_id, struct s_mercenary *merc) -{ - char* data; - - memset(merc, 0, sizeof(struct s_mercenary)); - merc->mercenary_id = merc_id; - merc->char_id = char_id; - - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `class`, `hp`, `sp`, `kill_counter`, `life_time` FROM `mercenary` WHERE `mer_id` = '%d' AND `char_id` = '%d'", merc_id, char_id) ) - { - Sql_ShowDebug(sql_handle); - return false; - } - - if( SQL_SUCCESS != Sql_NextRow(sql_handle) ) - { - Sql_FreeResult(sql_handle); - return false; - } - - Sql_GetData(sql_handle, 0, &data, NULL); merc->class_ = atoi(data); - Sql_GetData(sql_handle, 1, &data, NULL); merc->hp = atoi(data); - Sql_GetData(sql_handle, 2, &data, NULL); merc->sp = atoi(data); - Sql_GetData(sql_handle, 3, &data, NULL); merc->kill_count = atoi(data); - Sql_GetData(sql_handle, 4, &data, NULL); merc->life_time = atoi(data); - Sql_FreeResult(sql_handle); - if( save_log ) - ShowInfo("Mercenary loaded (%d - %d).\n", merc->mercenary_id, merc->char_id); - - return true; -} - -bool mapif_mercenary_delete(int merc_id) -{ - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `mercenary` WHERE `mer_id` = '%d'", merc_id) ) - { - Sql_ShowDebug(sql_handle); - return false; - } - - return true; -} - -#ifndef TXT_SQL_CONVERT - -static void mapif_mercenary_send(int fd, struct s_mercenary *merc, unsigned char flag) -{ - int size = sizeof(struct s_mercenary) + 5; - - WFIFOHEAD(fd,size); - WFIFOW(fd,0) = 0x3870; - WFIFOW(fd,2) = size; - WFIFOB(fd,4) = flag; - memcpy(WFIFOP(fd,5),merc,sizeof(struct s_mercenary)); - WFIFOSET(fd,size); -} - -static void mapif_parse_mercenary_create(int fd, struct s_mercenary* merc) -{ - bool result = mapif_mercenary_save(merc); - mapif_mercenary_send(fd, merc, result); -} - -static void mapif_parse_mercenary_load(int fd, int merc_id, int char_id) -{ - struct s_mercenary merc; - bool result = mapif_mercenary_load(merc_id, char_id, &merc); - mapif_mercenary_send(fd, &merc, result); -} - -static void mapif_mercenary_deleted(int fd, unsigned char flag) -{ - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x3871; - WFIFOB(fd,2) = flag; - WFIFOSET(fd,3); -} - -static void mapif_parse_mercenary_delete(int fd, int merc_id) -{ - bool result = mapif_mercenary_delete(merc_id); - mapif_mercenary_deleted(fd, result); -} - -static void mapif_mercenary_saved(int fd, unsigned char flag) -{ - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x3872; - WFIFOB(fd,2) = flag; - WFIFOSET(fd,3); -} - -static void mapif_parse_mercenary_save(int fd, struct s_mercenary* merc) -{ - bool result = mapif_mercenary_save(merc); - mapif_mercenary_saved(fd, result); -} - -int inter_mercenary_sql_init(void) -{ - return 0; -} -void inter_mercenary_sql_final(void) -{ - return; -} - -/*========================================== - * Inter Packets - *------------------------------------------*/ -int inter_mercenary_parse_frommap(int fd) -{ - unsigned short cmd = RFIFOW(fd,0); - - switch( cmd ) - { - case 0x3070: mapif_parse_mercenary_create(fd, (struct s_mercenary*)RFIFOP(fd,4)); break; - case 0x3071: mapif_parse_mercenary_load(fd, (int)RFIFOL(fd,2), (int)RFIFOL(fd,6)); break; - case 0x3072: mapif_parse_mercenary_delete(fd, (int)RFIFOL(fd,2)); break; - case 0x3073: mapif_parse_mercenary_save(fd, (struct s_mercenary*)RFIFOP(fd,4)); break; - default: - return 0; - } - return 1; -} -#endif //TXT_SQL_CONVERT diff --git a/src/char_sql/int_mercenary.h b/src/char_sql/int_mercenary.h deleted file mode 100644 index 01e4a841f..000000000 --- a/src/char_sql/int_mercenary.h +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder - -#ifndef _INT_MERCENARY_SQL_H_ -#define _INT_MERCENARY_SQL_H_ - -struct s_mercenary; - -int inter_mercenary_sql_init(void); -void inter_mercenary_sql_final(void); -int inter_mercenary_parse_frommap(int fd); - -// Mercenary Owner Database -bool mercenary_owner_fromsql(int char_id, struct mmo_charstatus *status); -bool mercenary_owner_tosql(int char_id, struct mmo_charstatus *status); -bool mercenary_owner_delete(int char_id); - -bool mapif_mercenary_delete(int merc_id); - -#endif /* _INT_MERCENARY_SQL_H_ */ diff --git a/src/char_sql/int_party.c b/src/char_sql/int_party.c deleted file mode 100644 index 14cef56e5..000000000 --- a/src/char_sql/int_party.c +++ /dev/null @@ -1,870 +0,0 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder - -#include "../common/cbasetypes.h" -#include "../common/mmo.h" -#include "../common/db.h" -#include "../common/malloc.h" -#include "../common/strlib.h" -#include "../common/socket.h" -#include "../common/showmsg.h" -#include "../common/mapindex.h" -#include "../common/sql.h" -#include "char.h" -#include "inter.h" -#include "int_party.h" - -#include -#include -#include - -#ifndef TXT_SQL_CONVERT -struct party_data { - struct party party; - unsigned int min_lv, max_lv; - int family; //Is this party a family? if so, this holds the child id. - unsigned char size; //Total size of party. -}; - -static struct party_data *party_pt; -static DBMap* party_db_; // int party_id -> struct party_data* - -int mapif_party_broken(int party_id,int flag); -int party_check_empty(struct party_data *p); -int mapif_parse_PartyLeave(int fd, int party_id, int account_id, int char_id); -int party_check_exp_share(struct party_data *p); -int mapif_party_optionchanged(int fd,struct party *p, int account_id, int flag); - -//Updates party's level range and unsets even share if broken. -static int int_party_check_lv(struct party_data *p) { - int i; - unsigned int lv; - p->min_lv = UINT_MAX; - p->max_lv = 0; - for(i=0;iparty.member[i].online || p->party.member[i].char_id == p->family ) - continue; - - lv=p->party.member[i].lv; - if (lv < p->min_lv) p->min_lv = lv; - if (lv > p->max_lv) p->max_lv = lv; - } - - if (p->party.exp && !party_check_exp_share(p)) { - p->party.exp = 0; - mapif_party_optionchanged(0, &p->party, 0, 0); - return 0; - } - return 1; -} -//Calculates the state of a party. -static void int_party_calc_state(struct party_data *p) -{ - int i; - unsigned int lv; - p->min_lv = UINT_MAX; - p->max_lv = 0; - p->party.count = - p->size = - p->family = 0; - - //Check party size - for(i=0;iparty.member[i].lv) continue; - p->size++; - if(p->party.member[i].online) - p->party.count++; - } - if( p->size == 2 && ( char_child(p->party.member[0].char_id,p->party.member[1].char_id) || char_child(p->party.member[1].char_id,p->party.member[0].char_id) ) ) { - //Child should be able to share with either of their parents [RoM] - if(p->party.member[0].class_&0x2000) //first slot is the child? - p->family = p->party.member[0].char_id; - else - p->family = p->party.member[1].char_id; - } else if( p->size == 3 ) { - //Check Family State. - p->family = char_family( - p->party.member[0].char_id, - p->party.member[1].char_id, - p->party.member[2].char_id - ); - } - //max/min levels. - for(i=0;iparty.member[i].lv; - if (!lv) continue; - if(p->party.member[i].online && - //On families, the kid is not counted towards exp share rules. - p->party.member[i].char_id != p->family) - { - if( lv < p->min_lv ) p->min_lv=lv; - if( p->max_lv < lv ) p->max_lv=lv; - } - } - - if (p->party.exp && !party_check_exp_share(p)) { - p->party.exp = 0; //Set off even share. - mapif_party_optionchanged(0, &p->party, 0, 0); - } - return; -} -#endif //TXT_SQL_CONVERT -// Save party to mysql -int inter_party_tosql(struct party *p, int flag, int index) -{ - // 'party' ('party_id','name','exp','item','leader_id','leader_char') - char esc_name[NAME_LENGTH*2+1];// escaped party name - int party_id; - - if( p == NULL || p->party_id == 0 ) - return 0; - party_id = p->party_id; - -#ifdef NOISY - ShowInfo("Save party request ("CL_BOLD"%d"CL_RESET" - %s).\n", party_id, p->name); -#endif - Sql_EscapeStringLen(sql_handle, esc_name, p->name, strnlen(p->name, NAME_LENGTH)); - -#ifndef TXT_SQL_CONVERT - if( flag & PS_BREAK ) - {// Break the party - // we'll skip name-checking and just reset everyone with the same party id [celest] - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `party_id`='0' WHERE `party_id`='%d'", char_db, party_id) ) - Sql_ShowDebug(sql_handle); - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `party_id`='%d'", party_db, party_id) ) - Sql_ShowDebug(sql_handle); - //Remove from memory - idb_remove(party_db_, party_id); - return 1; - } -#endif //TXT_SQL_CONVERT - if( flag & PS_CREATE ) - {// Create party -#ifndef TXT_SQL_CONVERT - if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` " - "(`name`, `exp`, `item`, `leader_id`, `leader_char`) " - "VALUES ('%s', '%d', '%d', '%d', '%d')", - party_db, esc_name, p->exp, p->item, p->member[index].account_id, p->member[index].char_id) ) - { - Sql_ShowDebug(sql_handle); - return 0; - } - party_id = p->party_id = (int)Sql_LastInsertId(sql_handle); -#else - //During conversion, you want to specify the id, and allow overwriting - //(in case someone is re-running the process. - - if( SQL_ERROR == Sql_Query(sql_handle, "REPLACE INTO `%s` " - "(`party_id`, `name`, `exp`, `item`, `leader_id`, `leader_char`) " - "VALUES ('%d', '%s', '%d', '%d', '%d', '%d')", - party_db, p->party_id, esc_name, p->exp, p->item, p->member[index].account_id, p->member[index].char_id) ) - { - Sql_ShowDebug(sql_handle); - return 0; - } -#endif - } - -#ifndef TXT_SQL_CONVERT - if( flag & PS_BASIC ) - {// Update party info. - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `name`='%s', `exp`='%d', `item`='%d' WHERE `party_id`='%d'", - party_db, esc_name, p->exp, p->item, party_id) ) - Sql_ShowDebug(sql_handle); - } - - if( flag & PS_LEADER ) - {// Update leader - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `leader_id`='%d', `leader_char`='%d' WHERE `party_id`='%d'", - party_db, p->member[index].account_id, p->member[index].char_id, party_id) ) - Sql_ShowDebug(sql_handle); - } - - if( flag & PS_ADDMEMBER ) - {// Add one party member. - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `party_id`='%d' WHERE `account_id`='%d' AND `char_id`='%d'", - char_db, party_id, p->member[index].account_id, p->member[index].char_id) ) - Sql_ShowDebug(sql_handle); - } - - if( flag & PS_DELMEMBER ) - {// Remove one party member. - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `party_id`='0' WHERE `party_id`='%d' AND `account_id`='%d' AND `char_id`='%d'", - char_db, party_id, p->member[index].account_id, p->member[index].char_id) ) - Sql_ShowDebug(sql_handle); - } -#endif //TXT_SQL_CONVERT - if( save_log ) - ShowInfo("Party Saved (%d - %s)\n", party_id, p->name); - return 1; -} -#ifndef TXT_SQL_CONVERT -// Read party from mysql -struct party_data *inter_party_fromsql(int party_id) -{ - int leader_id = 0; - int leader_char = 0; - struct party_data* p; - struct party_member* m; - char* data; - size_t len; - int i; - -#ifdef NOISY - ShowInfo("Load party request ("CL_BOLD"%d"CL_RESET")\n", party_id); -#endif - if( party_id <= 0 ) - return NULL; - - //Load from memory - p = (struct party_data*)idb_get(party_db_, party_id); - if( p != NULL ) - return p; - - p = party_pt; - memset(p, 0, sizeof(struct party_data)); - - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `party_id`, `name`,`exp`,`item`, `leader_id`, `leader_char` FROM `%s` WHERE `party_id`='%d'", party_db, party_id) ) - { - Sql_ShowDebug(sql_handle); - return NULL; - } - - if( SQL_SUCCESS != Sql_NextRow(sql_handle) ) - return NULL; - - p->party.party_id = party_id; - Sql_GetData(sql_handle, 1, &data, &len); memcpy(p->party.name, data, min(len, NAME_LENGTH)); - Sql_GetData(sql_handle, 2, &data, NULL); p->party.exp = (atoi(data) ? 1 : 0); - Sql_GetData(sql_handle, 3, &data, NULL); p->party.item = atoi(data); - Sql_GetData(sql_handle, 4, &data, NULL); leader_id = atoi(data); - Sql_GetData(sql_handle, 5, &data, NULL); leader_char = atoi(data); - Sql_FreeResult(sql_handle); - - // Load members - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `account_id`,`char_id`,`name`,`base_level`,`last_map`,`online`,`class` FROM `%s` WHERE `party_id`='%d'", char_db, party_id) ) - { - Sql_ShowDebug(sql_handle); - return NULL; - } - for( i = 0; i < MAX_PARTY && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i ) - { - m = &p->party.member[i]; - Sql_GetData(sql_handle, 0, &data, NULL); m->account_id = atoi(data); - Sql_GetData(sql_handle, 1, &data, NULL); m->char_id = atoi(data); - Sql_GetData(sql_handle, 2, &data, &len); memcpy(m->name, data, min(len, NAME_LENGTH)); - Sql_GetData(sql_handle, 3, &data, NULL); m->lv = atoi(data); - Sql_GetData(sql_handle, 4, &data, NULL); m->map = mapindex_name2id(data); - Sql_GetData(sql_handle, 5, &data, NULL); m->online = (atoi(data) ? 1 : 0); - Sql_GetData(sql_handle, 6, &data, NULL); m->class_ = atoi(data); - m->leader = (m->account_id == leader_id && m->char_id == leader_char ? 1 : 0); - } - Sql_FreeResult(sql_handle); - - if( save_log ) - ShowInfo("Party loaded (%d - %s).\n", party_id, p->party.name); - //Add party to memory. - CREATE(p, struct party_data, 1); - memcpy(p, party_pt, sizeof(struct party_data)); - //init state - int_party_calc_state(p); - idb_put(party_db_, party_id, p); - return p; -} - -int inter_party_sql_init(void) -{ - //memory alloc - party_db_ = idb_alloc(DB_OPT_RELEASE_DATA); - party_pt = (struct party_data*)aCalloc(sizeof(struct party_data), 1); - if (!party_pt) { - ShowFatalError("inter_party_sql_init: Out of Memory!\n"); - exit(EXIT_FAILURE); - } - - /* Uncomment the following if you want to do a party_db cleanup (remove parties with no members) on startup.[Skotlex] - ShowStatus("cleaning party table...\n"); - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` USING `%s` LEFT JOIN `%s` ON `%s`.leader_id =`%s`.account_id AND `%s`.leader_char = `%s`.char_id WHERE `%s`.account_id IS NULL", - party_db, party_db, char_db, party_db, char_db, party_db, char_db, char_db) ) - Sql_ShowDebug(sql_handle); - */ - return 0; -} - -void inter_party_sql_final(void) -{ - party_db_->destroy(party_db_, NULL); - aFree(party_pt); - return; -} - -// Search for the party according to its name -struct party_data* search_partyname(char* str) -{ - char esc_name[NAME_LENGTH*2+1]; - char* data; - struct party_data* p = NULL; - - Sql_EscapeStringLen(sql_handle, esc_name, str, safestrnlen(str, NAME_LENGTH)); - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `party_id` FROM `%s` WHERE `name`='%s'", party_db, esc_name) ) - Sql_ShowDebug(sql_handle); - else if( SQL_SUCCESS == Sql_NextRow(sql_handle) ) - { - Sql_GetData(sql_handle, 0, &data, NULL); - p = inter_party_fromsql(atoi(data)); - } - Sql_FreeResult(sql_handle); - - return p; -} - -// Returns whether this party can keep having exp share or not. -int party_check_exp_share(struct party_data *p) -{ - return (p->party.count < 2 || p->max_lv - p->min_lv <= party_share_level); -} - -// Is there any member in the party? -int party_check_empty(struct party_data *p) -{ - int i; - if (p==NULL||p->party.party_id==0) return 1; - for(i=0;iparty.member[i].account_id;i++); - if (i < MAX_PARTY) return 0; - // If there is no member, then break the party - mapif_party_broken(p->party.party_id,0); - inter_party_tosql(&p->party, PS_BREAK, 0); - return 1; -} - -//------------------------------------------------------------------- -// map serverへの通信 - -// パーティ作成可否 -int mapif_party_created(int fd,int account_id,int char_id,struct party *p) -{ - WFIFOHEAD(fd, 39); - WFIFOW(fd,0)=0x3820; - WFIFOL(fd,2)=account_id; - WFIFOL(fd,6)=char_id; - if(p!=NULL){ - WFIFOB(fd,10)=0; - WFIFOL(fd,11)=p->party_id; - memcpy(WFIFOP(fd,15),p->name,NAME_LENGTH); - ShowInfo("int_party: Party created (%d - %s)\n",p->party_id,p->name); - }else{ - WFIFOB(fd,10)=1; - WFIFOL(fd,11)=0; - memset(WFIFOP(fd,15),0,NAME_LENGTH); - } - WFIFOSET(fd,39); - - return 0; -} - -// パーティ情報見つからず -static void mapif_party_noinfo(int fd, int party_id, int char_id) -{ - WFIFOHEAD(fd, 12); - WFIFOW(fd,0) = 0x3821; - WFIFOW(fd,2) = 12; - WFIFOL(fd,4) = char_id; - WFIFOL(fd,8) = party_id; - WFIFOSET(fd,12); - ShowWarning("int_party: info not found (party_id=%d char_id=%d)\n", party_id, char_id); -} -// パーティ情報まとめ送り -static void mapif_party_info(int fd, struct party* p, int char_id) -{ - unsigned char buf[8 + sizeof(struct party)]; - WBUFW(buf,0) = 0x3821; - WBUFW(buf,2) = 8 + sizeof(struct party); - WBUFL(buf,4) = char_id; - memcpy(WBUFP(buf,8), p, sizeof(struct party)); - - if(fd<0) - mapif_sendall(buf,WBUFW(buf,2)); - else - mapif_send(fd,buf,WBUFW(buf,2)); -} -// パーティメンバ追加可否 -int mapif_party_memberadded(int fd, int party_id, int account_id, int char_id, int flag) { - WFIFOHEAD(fd, 15); - WFIFOW(fd,0) = 0x3822; - WFIFOL(fd,2) = party_id; - WFIFOL(fd,6) = account_id; - WFIFOL(fd,10) = char_id; - WFIFOB(fd,14) = flag; - WFIFOSET(fd,15); - - return 0; -} - -// パーティ設定変更通知 -int mapif_party_optionchanged(int fd,struct party *p,int account_id,int flag) -{ - unsigned char buf[16]; - WBUFW(buf,0)=0x3823; - WBUFL(buf,2)=p->party_id; - WBUFL(buf,6)=account_id; - WBUFW(buf,10)=p->exp; - WBUFW(buf,12)=p->item; - WBUFB(buf,14)=flag; - if(flag==0) - mapif_sendall(buf,15); - else - mapif_send(fd,buf,15); - return 0; -} - -// パーティ脱退通知 -int mapif_party_withdraw(int party_id,int account_id, int char_id) { - unsigned char buf[16]; - - WBUFW(buf,0) = 0x3824; - WBUFL(buf,2) = party_id; - WBUFL(buf,6) = account_id; - WBUFL(buf,10) = char_id; - mapif_sendall(buf, 14); - return 0; -} - -// パーティマップ更新通知 -int mapif_party_membermoved(struct party *p,int idx) -{ - unsigned char buf[20]; - - WBUFW(buf,0) = 0x3825; - WBUFL(buf,2) = p->party_id; - WBUFL(buf,6) = p->member[idx].account_id; - WBUFL(buf,10) = p->member[idx].char_id; - WBUFW(buf,14) = p->member[idx].map; - WBUFB(buf,16) = p->member[idx].online; - WBUFW(buf,17) = p->member[idx].lv; - mapif_sendall(buf, 19); - return 0; -} - -// パーティ解散通知 -int mapif_party_broken(int party_id,int flag) -{ - unsigned char buf[16]; - WBUFW(buf,0)=0x3826; - WBUFL(buf,2)=party_id; - WBUFB(buf,6)=flag; - mapif_sendall(buf,7); - //printf("int_party: broken %d\n",party_id); - return 0; -} -// パーティ内発言 -int mapif_party_message(int party_id,int account_id,char *mes,int len, int sfd) -{ - unsigned char buf[512]; - WBUFW(buf,0)=0x3827; - WBUFW(buf,2)=len+12; - WBUFL(buf,4)=party_id; - WBUFL(buf,8)=account_id; - memcpy(WBUFP(buf,12),mes,len); - mapif_sendallwos(sfd, buf,len+12); - return 0; -} - -//------------------------------------------------------------------- -// map serverからの通信 - - -// Create Party -int mapif_parse_CreateParty(int fd, char *name, int item, int item2, struct party_member *leader) -{ - struct party_data *p; - int i; - if( (p=search_partyname(name))!=NULL){ - mapif_party_created(fd,leader->account_id,leader->char_id,NULL); - return 0; - } - // Check Authorised letters/symbols in the name of the character - if (char_name_option == 1) { // only letters/symbols in char_name_letters are authorised - for (i = 0; i < NAME_LENGTH && name[i]; i++) - if (strchr(char_name_letters, name[i]) == NULL) { - mapif_party_created(fd,leader->account_id,leader->char_id,NULL); - return 0; - } - } else if (char_name_option == 2) { // letters/symbols in char_name_letters are forbidden - for (i = 0; i < NAME_LENGTH && name[i]; i++) - if (strchr(char_name_letters, name[i]) != NULL) { - mapif_party_created(fd,leader->account_id,leader->char_id,NULL); - return 0; - } - } - - p = (struct party_data*)aCalloc(1, sizeof(struct party_data)); - - memcpy(p->party.name,name,NAME_LENGTH); - p->party.exp=0; - p->party.item=(item?1:0)|(item2?2:0); - - memcpy(&p->party.member[0], leader, sizeof(struct party_member)); - p->party.member[0].leader=1; - p->party.member[0].online=1; - - p->party.party_id=-1;//New party. - if (inter_party_tosql(&p->party,PS_CREATE|PS_ADDMEMBER,0)) { - //Add party to db - int_party_calc_state(p); - idb_put(party_db_, p->party.party_id, p); - mapif_party_info(fd, &p->party, 0); - mapif_party_created(fd,leader->account_id,leader->char_id,&p->party); - } else { //Failed to create party. - aFree(p); - mapif_party_created(fd,leader->account_id,leader->char_id,NULL); - } - - return 0; -} -// パーティ情報要求 -static void mapif_parse_PartyInfo(int fd, int party_id, int char_id) -{ - struct party_data *p; - p = inter_party_fromsql(party_id); - - if (p) - mapif_party_info(fd, &p->party, char_id); - else - mapif_party_noinfo(fd, party_id, char_id); -} -// パーティ追加要求 -int mapif_parse_PartyAddMember(int fd, int party_id, struct party_member *member) -{ - struct party_data *p; - int i; - - p = inter_party_fromsql(party_id); - if( p == NULL || p->size == MAX_PARTY ) { - mapif_party_memberadded(fd, party_id, member->account_id, member->char_id, 1); - return 0; - } - - ARR_FIND( 0, MAX_PARTY, i, p->party.member[i].account_id == 0 ); - if( i == MAX_PARTY ) - {// Party full - mapif_party_memberadded(fd, party_id, member->account_id, member->char_id, 1); - return 0; - } - - memcpy(&p->party.member[i], member, sizeof(struct party_member)); - p->party.member[i].leader = 0; - if (p->party.member[i].online) p->party.count++; - p->size++; - if (p->size == 2 || p->size == 3) // Check family state. And also accept either of their Parents. [RoM] - int_party_calc_state(p); - else //Check even share range. - if (member->lv < p->min_lv || member->lv > p->max_lv || p->family) { - if (p->family) p->family = 0; //Family state broken. - int_party_check_lv(p); - } - - mapif_party_info(-1, &p->party, 0); - mapif_party_memberadded(fd, party_id, member->account_id, member->char_id, 0); - inter_party_tosql(&p->party, PS_ADDMEMBER, i); - - return 0; -} - -// パーティー設定変更要求 -int mapif_parse_PartyChangeOption(int fd,int party_id,int account_id,int exp,int item) -{ - struct party_data *p; - int flag = 0; - p = inter_party_fromsql(party_id); - - if(!p) - return 0; - - p->party.exp=exp; - if( exp && !party_check_exp_share(p) ){ - flag|=0x01; - p->party.exp=0; - } - p->party.item = item&0x3; //Filter out invalid values. - mapif_party_optionchanged(fd,&p->party,account_id,flag); - inter_party_tosql(&p->party, PS_BASIC, 0); - return 0; -} -// パーティ脱退要求 -int mapif_parse_PartyLeave(int fd, int party_id, int account_id, int char_id) -{ - struct party_data *p; - int i,j=-1; - - p = inter_party_fromsql(party_id); - if( p == NULL ) - {// Party does not exists? - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `party_id`='0' WHERE `party_id`='%d'", char_db, party_id) ) - Sql_ShowDebug(sql_handle); - return 0; - } - - for (i = 0; i < MAX_PARTY; i++) { - if(p->party.member[i].account_id == account_id && - p->party.member[i].char_id == char_id) { - break; - } - } - if (i >= MAX_PARTY) - return 0; //Member not found? - - mapif_party_withdraw(party_id, account_id, char_id); - - if (p->party.member[i].leader){ - p->party.member[i].account_id = 0; - for (j = 0; j < MAX_PARTY; j++) { - if (!p->party.member[j].account_id) - continue; - mapif_party_withdraw(party_id, p->party.member[j].account_id, p->party.member[j].char_id); - p->party.member[j].account_id = 0; - } - //Party gets deleted on the check_empty call below. - } else { - inter_party_tosql(&p->party,PS_DELMEMBER,i); - j = p->party.member[i].lv; - if(p->party.member[i].online) p->party.count--; - memset(&p->party.member[i], 0, sizeof(struct party_member)); - p->size--; - if (j == p->min_lv || j == p->max_lv || p->family) - { - if(p->family) p->family = 0; //Family state broken. - int_party_check_lv(p); - } - } - - if (party_check_empty(p) == 0) - mapif_party_info(-1, &p->party, 0); - return 0; -} -// When member goes to other map or levels up. -int mapif_parse_PartyChangeMap(int fd, int party_id, int account_id, int char_id, unsigned short map, int online, unsigned int lv) -{ - struct party_data *p; - int i; - - p = inter_party_fromsql(party_id); - if (p == NULL) - return 0; - - for(i = 0; i < MAX_PARTY && - (p->party.member[i].account_id != account_id || - p->party.member[i].char_id != char_id); i++); - - if (i == MAX_PARTY) return 0; - - if (p->party.member[i].online != online) - { - p->party.member[i].online = online; - if (online) - p->party.count++; - else - p->party.count--; - // Even share check situations: Family state (always breaks) - // character logging on/off is max/min level (update level range) - // or character logging on/off has a different level (update level range using new level) - if (p->family || - (p->party.member[i].lv <= p->min_lv || p->party.member[i].lv >= p->max_lv) || - (p->party.member[i].lv != lv && (lv <= p->min_lv || lv >= p->max_lv)) - ) - { - p->party.member[i].lv = lv; - int_party_check_lv(p); - } - //Send online/offline update. - mapif_party_membermoved(&p->party, i); - } - - if (p->party.member[i].lv != lv) { - if(p->party.member[i].lv == p->min_lv || - p->party.member[i].lv == p->max_lv) - { - p->party.member[i].lv = lv; - int_party_check_lv(p); - } else - p->party.member[i].lv = lv; - //There is no need to send level update to map servers - //since they do nothing with it. - } - - if (p->party.member[i].map != map) { - p->party.member[i].map = map; - mapif_party_membermoved(&p->party, i); - } - return 0; -} - -// パーティ解散要求 -int mapif_parse_BreakParty(int fd,int party_id) -{ - struct party_data *p; - - p = inter_party_fromsql(party_id); - - if(!p) - return 0; - inter_party_tosql(&p->party,PS_BREAK,0); - mapif_party_broken(fd,party_id); - return 0; -} -// パーティメッセージ送信 -int mapif_parse_PartyMessage(int fd,int party_id,int account_id,char *mes,int len) -{ - return mapif_party_message(party_id,account_id,mes,len, fd); -} - -int mapif_parse_PartyLeaderChange(int fd,int party_id,int account_id,int char_id) -{ - struct party_data *p; - int i; - - p = inter_party_fromsql(party_id); - - if(!p) - return 0; - - for (i = 0; i < MAX_PARTY; i++) - { - if(p->party.member[i].leader) - p->party.member[i].leader = 0; - if(p->party.member[i].account_id == account_id && - p->party.member[i].char_id == char_id) - { - p->party.member[i].leader = 1; - inter_party_tosql(&p->party,PS_LEADER, i); - } - } - return 1; -} - -// map server からの通信 -// ・1パケットのみ解析すること -// ・パケット長データはinter.cにセットしておくこと -// ・パケット長チェックや、RFIFOSKIPは呼び出し元で行われるので行ってはならない -// ・エラーなら0(false)、そうでないなら1(true)をかえさなければならない -int inter_party_parse_frommap(int fd) -{ - RFIFOHEAD(fd); - switch(RFIFOW(fd,0)) { - case 0x3020: mapif_parse_CreateParty(fd, (char*)RFIFOP(fd,4), RFIFOB(fd,28), RFIFOB(fd,29), (struct party_member*)RFIFOP(fd,30)); break; - case 0x3021: mapif_parse_PartyInfo(fd, RFIFOL(fd,2), RFIFOL(fd,6)); break; - case 0x3022: mapif_parse_PartyAddMember(fd, RFIFOL(fd,4), (struct party_member*)RFIFOP(fd,8)); break; - case 0x3023: mapif_parse_PartyChangeOption(fd, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOW(fd,10), RFIFOW(fd,12)); break; - case 0x3024: mapif_parse_PartyLeave(fd, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10)); break; - case 0x3025: mapif_parse_PartyChangeMap(fd, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10), RFIFOW(fd,14), RFIFOB(fd,16), RFIFOW(fd,17)); break; - case 0x3026: mapif_parse_BreakParty(fd, RFIFOL(fd,2)); break; - case 0x3027: mapif_parse_PartyMessage(fd, RFIFOL(fd,4), RFIFOL(fd,8), (char*)RFIFOP(fd,12), RFIFOW(fd,2)-12); break; - case 0x3029: mapif_parse_PartyLeaderChange(fd, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10)); break; - default: - return 0; - } - return 1; -} - -// サーバーから脱退要求(キャラ削除用) -int inter_party_leave(int party_id,int account_id, int char_id) -{ - return mapif_parse_PartyLeave(-1,party_id,account_id, char_id); -} - -int inter_party_CharOnline(int char_id, int party_id) -{ - struct party_data* p; - int i; - - if( party_id == -1 ) - {// Get party_id from the database - char* data; - - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT party_id FROM `%s` WHERE char_id='%d'", char_db, char_id) ) - { - Sql_ShowDebug(sql_handle); - return 0; - } - - if( SQL_SUCCESS != Sql_NextRow(sql_handle) ) - return 0; //Eh? No party? - - Sql_GetData(sql_handle, 0, &data, NULL); - party_id = atoi(data); - Sql_FreeResult(sql_handle); - } - if (party_id == 0) - return 0; //No party... - - p = inter_party_fromsql(party_id); - if(!p) { - ShowError("Character %d's party %d not found!\n", char_id, party_id); - return 0; - } - - //Set member online - for(i=0; iparty.member[i].char_id == char_id) { - if (!p->party.member[i].online) { - p->party.member[i].online = 1; - p->party.count++; - if (p->party.member[i].lv < p->min_lv || - p->party.member[i].lv > p->max_lv) - int_party_check_lv(p); - } - break; - } - } - return 1; -} - -int inter_party_CharOffline(int char_id, int party_id) { - struct party_data *p=NULL; - int i; - - if( party_id == -1 ) - {// Get guild_id from the database - char* data; - - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT party_id FROM `%s` WHERE char_id='%d'", char_db, char_id) ) - { - Sql_ShowDebug(sql_handle); - return 0; - } - - if( SQL_SUCCESS != Sql_NextRow(sql_handle) ) - return 0; //Eh? No party? - - Sql_GetData(sql_handle, 0, &data, NULL); - party_id = atoi(data); - Sql_FreeResult(sql_handle); - } - if (party_id == 0) - return 0; //No party... - - //Character has a party, set character offline and check if they were the only member online - if ((p = inter_party_fromsql(party_id)) == NULL) - return 0; - - //Set member offline - for(i=0; i< MAX_PARTY; i++) { - if(p->party.member[i].char_id == char_id) - { - p->party.member[i].online = 0; - p->party.count--; - if(p->party.member[i].lv == p->min_lv || - p->party.member[i].lv == p->max_lv) - int_party_check_lv(p); - break; - } - } - - if(!p->party.count) - //Parties don't have any data that needs be saved at this point... so just remove it from memory. - idb_remove(party_db_, party_id); - return 1; -} -#endif //TXT_SQL_CONVERT diff --git a/src/char_sql/int_party.h b/src/char_sql/int_party.h deleted file mode 100644 index d7965c33b..000000000 --- a/src/char_sql/int_party.h +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder - -#ifndef _INT_PARTY_SQL_H_ -#define _INT_PARTY_SQL_H_ - -//Party Flags on what to save/delete. -//Create a new party entry (index holds leader's info) -#define PS_CREATE 0x01 -//Update basic party info. -#define PS_BASIC 0x02 -//Update party's leader -#define PS_LEADER 0x04 -//Specify new party member (index specifies which party member) -#define PS_ADDMEMBER 0x08 -//Specify member that left (index specifies which party member) -#define PS_DELMEMBER 0x10 -//Specify that this party must be deleted. -#define PS_BREAK 0x20 - -struct party; - -int inter_party_parse_frommap(int fd); -int inter_party_sql_init(void); -void inter_party_sql_final(void); -int inter_party_leave(int party_id,int account_id, int char_id); -int inter_party_CharOnline(int char_id, int party_id); -int inter_party_CharOffline(int char_id, int party_id); -//Required for the TXT->SQL converter -int inter_party_tosql(struct party *p, int flag, int index); - -#endif /* _INT_PARTY_SQL_H_ */ diff --git a/src/char_sql/int_pet.c b/src/char_sql/int_pet.c deleted file mode 100644 index 3ce7c4559..000000000 --- a/src/char_sql/int_pet.c +++ /dev/null @@ -1,310 +0,0 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder - -#include "../common/mmo.h" -#include "../common/malloc.h" -#include "../common/socket.h" -#include "../common/strlib.h" -#include "../common/showmsg.h" -#include "../common/utils.h" -#include "../common/sql.h" -#include "char.h" -#include "inter.h" - -#include -#include -#include - -struct s_pet *pet_pt; - -//--------------------------------------------------------- -int inter_pet_tosql(int pet_id, struct s_pet* p) -{ - //`pet` (`pet_id`, `class`,`name`,`account_id`,`char_id`,`level`,`egg_id`,`equip`,`intimate`,`hungry`,`rename_flag`,`incuvate`) - char esc_name[NAME_LENGTH*2+1];// escaped pet name - - Sql_EscapeStringLen(sql_handle, esc_name, p->name, strnlen(p->name, NAME_LENGTH)); - p->hungry = cap_value(p->hungry, 0, 100); - p->intimate = cap_value(p->intimate, 0, 1000); - - if( pet_id == -1 ) - {// New pet. - if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` " - "(`class`,`name`,`account_id`,`char_id`,`level`,`egg_id`,`equip`,`intimate`,`hungry`,`rename_flag`,`incuvate`) " - "VALUES ('%d', '%s', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d')", - pet_db, p->class_, esc_name, p->account_id, p->char_id, p->level, p->egg_id, - p->equip, p->intimate, p->hungry, p->rename_flag, p->incuvate) ) - { - Sql_ShowDebug(sql_handle); - return 0; - } - p->pet_id = (int)Sql_LastInsertId(sql_handle); - } - else - {// Update pet. - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `class`='%d',`name`='%s',`account_id`='%d',`char_id`='%d',`level`='%d',`egg_id`='%d',`equip`='%d',`intimate`='%d',`hungry`='%d',`rename_flag`='%d',`incuvate`='%d' WHERE `pet_id`='%d'", - pet_db, p->class_, esc_name, p->account_id, p->char_id, p->level, p->egg_id, - p->equip, p->intimate, p->hungry, p->rename_flag, p->incuvate, p->pet_id) ) - { - Sql_ShowDebug(sql_handle); - return 0; - } - } - - if (save_log) - ShowInfo("Pet saved %d - %s.\n", pet_id, p->name); - return 1; -} -#ifndef TXT_SQL_CONVERT -int inter_pet_fromsql(int pet_id, struct s_pet* p) -{ - char* data; - size_t len; - -#ifdef NOISY - ShowInfo("Loading pet (%d)...\n",pet_id); -#endif - memset(p, 0, sizeof(struct s_pet)); - - //`pet` (`pet_id`, `class`,`name`,`account_id`,`char_id`,`level`,`egg_id`,`equip`,`intimate`,`hungry`,`rename_flag`,`incuvate`) - - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `pet_id`, `class`,`name`,`account_id`,`char_id`,`level`,`egg_id`,`equip`,`intimate`,`hungry`,`rename_flag`,`incuvate` FROM `%s` WHERE `pet_id`='%d'", pet_db, pet_id) ) - { - Sql_ShowDebug(sql_handle); - return 0; - } - - if( SQL_SUCCESS == Sql_NextRow(sql_handle) ) - { - p->pet_id = pet_id; - Sql_GetData(sql_handle, 1, &data, NULL); p->class_ = atoi(data); - Sql_GetData(sql_handle, 2, &data, &len); memcpy(p->name, data, min(len, NAME_LENGTH)); - Sql_GetData(sql_handle, 3, &data, NULL); p->account_id = atoi(data); - Sql_GetData(sql_handle, 4, &data, NULL); p->char_id = atoi(data); - Sql_GetData(sql_handle, 5, &data, NULL); p->level = atoi(data); - Sql_GetData(sql_handle, 6, &data, NULL); p->egg_id = atoi(data); - Sql_GetData(sql_handle, 7, &data, NULL); p->equip = atoi(data); - Sql_GetData(sql_handle, 8, &data, NULL); p->intimate = atoi(data); - Sql_GetData(sql_handle, 9, &data, NULL); p->hungry = atoi(data); - Sql_GetData(sql_handle, 10, &data, NULL); p->rename_flag = atoi(data); - Sql_GetData(sql_handle, 11, &data, NULL); p->incuvate = atoi(data); - - Sql_FreeResult(sql_handle); - - p->hungry = cap_value(p->hungry, 0, 100); - p->intimate = cap_value(p->intimate, 0, 1000); - - if( save_log ) - ShowInfo("Pet loaded (%d - %s).\n", pet_id, p->name); - } - return 0; -} -//---------------------------------------------- - -int inter_pet_sql_init(void){ - //memory alloc - pet_pt = (struct s_pet*)aCalloc(sizeof(struct s_pet), 1); - return 0; -} -void inter_pet_sql_final(void){ - if (pet_pt) aFree(pet_pt); - return; -} -//---------------------------------- -int inter_pet_delete(int pet_id){ - ShowInfo("delete pet request: %d...\n",pet_id); - - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `pet_id`='%d'", pet_db, pet_id) ) - Sql_ShowDebug(sql_handle); - return 0; -} -//------------------------------------------------------ -int mapif_pet_created(int fd, int account_id, struct s_pet *p) -{ - WFIFOHEAD(fd, 11); - WFIFOW(fd, 0) =0x3880; - WFIFOL(fd, 2) =account_id; - if(p!=NULL){ - WFIFOB(fd, 6)=0; - WFIFOL(fd, 7) =p->pet_id; - ShowInfo("int_pet: created pet %d - %s\n", p->pet_id, p->name); - }else{ - WFIFOB(fd, 6)=1; - WFIFOL(fd, 7)=0; - } - WFIFOSET(fd, 11); - - return 0; -} - -int mapif_pet_info(int fd, int account_id, struct s_pet *p){ - WFIFOHEAD(fd, sizeof(struct s_pet) + 9); - WFIFOW(fd, 0) =0x3881; - WFIFOW(fd, 2) =sizeof(struct s_pet) + 9; - WFIFOL(fd, 4) =account_id; - WFIFOB(fd, 8)=0; - memcpy(WFIFOP(fd, 9), p, sizeof(struct s_pet)); - WFIFOSET(fd, WFIFOW(fd, 2)); - - return 0; -} - -int mapif_pet_noinfo(int fd, int account_id){ - WFIFOHEAD(fd, sizeof(struct s_pet) + 9); - WFIFOW(fd, 0) =0x3881; - WFIFOW(fd, 2) =sizeof(struct s_pet) + 9; - WFIFOL(fd, 4) =account_id; - WFIFOB(fd, 8)=1; - memset(WFIFOP(fd, 9), 0, sizeof(struct s_pet)); - WFIFOSET(fd, WFIFOW(fd, 2)); - - return 0; -} - -int mapif_save_pet_ack(int fd, int account_id, int flag){ - WFIFOHEAD(fd, 7); - WFIFOW(fd, 0) =0x3882; - WFIFOL(fd, 2) =account_id; - WFIFOB(fd, 6) =flag; - WFIFOSET(fd, 7); - - return 0; -} - -int mapif_delete_pet_ack(int fd, int flag){ - WFIFOHEAD(fd, 3); - WFIFOW(fd, 0) =0x3883; - WFIFOB(fd, 2) =flag; - WFIFOSET(fd, 3); - - return 0; -} - -int mapif_create_pet(int fd, 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) -{ - memset(pet_pt, 0, sizeof(struct s_pet)); - strncpy(pet_pt->name, pet_name, NAME_LENGTH); - if(incuvate == 1) - pet_pt->account_id = pet_pt->char_id = 0; - else { - pet_pt->account_id = account_id; - pet_pt->char_id = char_id; - } - pet_pt->class_ = pet_class; - pet_pt->level = pet_lv; - pet_pt->egg_id = pet_egg_id; - pet_pt->equip = pet_equip; - pet_pt->intimate = intimate; - pet_pt->hungry = hungry; - pet_pt->rename_flag = rename_flag; - pet_pt->incuvate = incuvate; - - if(pet_pt->hungry < 0) - pet_pt->hungry = 0; - else if(pet_pt->hungry > 100) - pet_pt->hungry = 100; - if(pet_pt->intimate < 0) - pet_pt->intimate = 0; - else if(pet_pt->intimate > 1000) - pet_pt->intimate = 1000; - - pet_pt->pet_id = -1; //Signal NEW pet. - if (inter_pet_tosql(pet_pt->pet_id,pet_pt)) - mapif_pet_created(fd, account_id, pet_pt); - else //Failed... - mapif_pet_created(fd, account_id, NULL); - - return 0; -} - -int mapif_load_pet(int fd, int account_id, int char_id, int pet_id){ - memset(pet_pt, 0, sizeof(struct s_pet)); - - inter_pet_fromsql(pet_id, pet_pt); - - if(pet_pt!=NULL) { - if(pet_pt->incuvate == 1) { - pet_pt->account_id = pet_pt->char_id = 0; - mapif_pet_info(fd, account_id, pet_pt); - } - else if(account_id == pet_pt->account_id && char_id == pet_pt->char_id) - mapif_pet_info(fd, account_id, pet_pt); - else - mapif_pet_noinfo(fd, account_id); - } - else - mapif_pet_noinfo(fd, account_id); - - return 0; -} - -int mapif_save_pet(int fd, int account_id, struct s_pet *data) { - //here process pet save request. - int len; - RFIFOHEAD(fd); - len=RFIFOW(fd, 2); - if(sizeof(struct s_pet)!=len-8) { - ShowError("inter pet: data size error %d %d\n", sizeof(struct s_pet), len-8); - } - - else{ - if(data->hungry < 0) - data->hungry = 0; - else if(data->hungry > 100) - data->hungry = 100; - if(data->intimate < 0) - data->intimate = 0; - else if(data->intimate > 1000) - data->intimate = 1000; - inter_pet_tosql(data->pet_id,data); - mapif_save_pet_ack(fd, account_id, 0); - } - - return 0; -} - -int mapif_delete_pet(int fd, int pet_id){ - mapif_delete_pet_ack(fd, inter_pet_delete(pet_id)); - - return 0; -} - -int mapif_parse_CreatePet(int fd){ - RFIFOHEAD(fd); - mapif_create_pet(fd, RFIFOL(fd, 2), RFIFOL(fd, 6), RFIFOW(fd, 10), RFIFOW(fd, 12), RFIFOW(fd, 14), RFIFOW(fd, 16), RFIFOW(fd, 18), - RFIFOW(fd, 20), RFIFOB(fd, 22), RFIFOB(fd, 23), (char*)RFIFOP(fd, 24)); - return 0; -} - -int mapif_parse_LoadPet(int fd){ - RFIFOHEAD(fd); - mapif_load_pet(fd, RFIFOL(fd, 2), RFIFOL(fd, 6), RFIFOL(fd, 10)); - return 0; -} - -int mapif_parse_SavePet(int fd){ - RFIFOHEAD(fd); - mapif_save_pet(fd, RFIFOL(fd, 4), (struct s_pet *) RFIFOP(fd, 8)); - return 0; -} - -int mapif_parse_DeletePet(int fd){ - RFIFOHEAD(fd); - mapif_delete_pet(fd, RFIFOL(fd, 2)); - return 0; -} - -int inter_pet_parse_frommap(int fd){ - RFIFOHEAD(fd); - switch(RFIFOW(fd, 0)){ - case 0x3080: mapif_parse_CreatePet(fd); break; - case 0x3081: mapif_parse_LoadPet(fd); break; - case 0x3082: mapif_parse_SavePet(fd); break; - case 0x3083: mapif_parse_DeletePet(fd); break; - default: - return 0; - } - return 1; -} -#endif //TXT_SQL_CONVERT diff --git a/src/char_sql/int_pet.h b/src/char_sql/int_pet.h deleted file mode 100644 index 733468c77..000000000 --- a/src/char_sql/int_pet.h +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder - -#ifndef _INT_PET_SQL_H_ -#define _INT_PET_SQL_H_ - -struct s_pet; - -int inter_pet_init(void); -void inter_pet_sql_final(void); -int inter_pet_save(void); -int inter_pet_delete(int pet_id); - -int inter_pet_parse_frommap(int fd); -int inter_pet_sql_init(void); -//extern char pet_txt[256]; - -//Exported for use in the TXT-SQL converter. -int inter_pet_tosql(int pet_id, struct s_pet *p); - -#endif /* _INT_PET_SQL_H_ */ diff --git a/src/char_sql/int_quest.c b/src/char_sql/int_quest.c deleted file mode 100644 index 224205412..000000000 --- a/src/char_sql/int_quest.c +++ /dev/null @@ -1,184 +0,0 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder - -#include "../common/mmo.h" -#include "../common/db.h" -#include "../common/malloc.h" -#include "../common/showmsg.h" -#include "../common/socket.h" -#include "../common/strlib.h" -#include "../common/sql.h" -#include "../common/timer.h" - -#include "char.h" -#include "inter.h" -#include "int_quest.h" - -#include -#include -#include - -//Load entire questlog for a character -int mapif_quests_fromsql(int char_id, struct quest questlog[]) -{ - int i; - struct quest tmp_quest; - SqlStmt * stmt; - - stmt = SqlStmt_Malloc(sql_handle); - if( stmt == NULL ) - { - SqlStmt_ShowDebug(stmt); - return 0; - } - - memset(&tmp_quest, 0, sizeof(struct quest)); - - if( SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT `quest_id`, `state`, `time`, `count1`, `count2`, `count3` FROM `%s` WHERE `char_id`=? LIMIT %d", quest_db, MAX_QUEST_DB) - || SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0) - || SQL_ERROR == SqlStmt_Execute(stmt) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &tmp_quest.quest_id, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_INT, &tmp_quest.state, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_UINT, &tmp_quest.time, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 3, SQLDT_INT, &tmp_quest.count[0], 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 4, SQLDT_INT, &tmp_quest.count[1], 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 5, SQLDT_INT, &tmp_quest.count[2], 0, NULL, NULL) ) - SqlStmt_ShowDebug(stmt); - - for( i = 0; i < MAX_QUEST_DB && SQL_SUCCESS == SqlStmt_NextRow(stmt); ++i ) - memcpy(&questlog[i], &tmp_quest, sizeof(tmp_quest)); - - SqlStmt_Free(stmt); - return i; -} - -//Delete a quest -bool mapif_quest_delete(int char_id, int quest_id) -{ - if ( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `quest_id` = '%d' AND `char_id` = '%d'", quest_db, quest_id, char_id) ) - { - Sql_ShowDebug(sql_handle); - return false; - } - - return true; -} - -//Add a quest to a questlog -bool mapif_quest_add(int char_id, struct quest qd) -{ - if ( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s`(`quest_id`, `char_id`, `state`, `time`, `count1`, `count2`, `count3`) VALUES ('%d', '%d', '%d','%d', '%d', '%d', '%d')", quest_db, qd.quest_id, char_id, qd.state, qd.time, qd.count[0], qd.count[1], qd.count[2]) ) - { - Sql_ShowDebug(sql_handle); - return false; - } - - return true; -} - -//Update a questlog -bool mapif_quest_update(int char_id, struct quest qd) -{ - if ( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `state`='%d', `count1`='%d', `count2`='%d', `count3`='%d' WHERE `quest_id` = '%d' AND `char_id` = '%d'", quest_db, qd.state, qd.count[0], qd.count[1], qd.count[2], qd.quest_id, char_id) ) - { - Sql_ShowDebug(sql_handle); - return false; - } - - return true; -} - -//Save quests -int mapif_parse_quest_save(int fd) -{ - int i, j, k, num2, num1 = (RFIFOW(fd,2)-8)/sizeof(struct quest); - int char_id = RFIFOL(fd,4); - struct quest qd1[MAX_QUEST_DB],qd2[MAX_QUEST_DB]; - bool success = true; - - memset(qd1, 0, sizeof(qd1)); - memset(qd2, 0, sizeof(qd2)); - if( num1 ) memcpy(&qd1, RFIFOP(fd,8), RFIFOW(fd,2)-8); - num2 = mapif_quests_fromsql(char_id, qd2); - - for( i = 0; i < num1; i++ ) - { - ARR_FIND( 0, num2, j, qd1[i].quest_id == qd2[j].quest_id ); - if( j < num2 ) // Update existed quests - { // Only states and counts are changable. - ARR_FIND( 0, MAX_QUEST_OBJECTIVES, k, qd1[i].count[k] != qd2[j].count[k] ); - if( k != MAX_QUEST_OBJECTIVES || qd1[i].state != qd2[j].state ) - success &= mapif_quest_update(char_id, qd1[i]); - - if( j < (--num2) ) - { - memmove(&qd2[j],&qd2[j+1],sizeof(struct quest)*(num2-j)); - memset(&qd2[num2], 0, sizeof(struct quest)); - } - - } - else // Add new quests - success &= mapif_quest_add(char_id, qd1[i]); - } - - for( i = 0; i < num2; i++ ) // Quests not in qd1 but in qd2 are to be erased. - success &= mapif_quest_delete(char_id, qd2[i].quest_id); - - WFIFOHEAD(fd,7); - WFIFOW(fd,0) = 0x3861; - WFIFOL(fd,2) = char_id; - WFIFOB(fd,6) = success?1:0; - WFIFOSET(fd,7); - - return 0; -} - -//Send questlog to map server -int mapif_parse_quest_load(int fd) -{ - int char_id = RFIFOL(fd,2); - struct quest tmp_questlog[MAX_QUEST_DB]; - int num_quests, i, num_complete = 0; - int complete[MAX_QUEST_DB]; - - memset(tmp_questlog, 0, sizeof(tmp_questlog)); - memset(complete, 0, sizeof(complete)); - - num_quests = mapif_quests_fromsql(char_id, tmp_questlog); - - WFIFOHEAD(fd,num_quests*sizeof(struct quest)+8); - WFIFOW(fd,0) = 0x3860; - WFIFOW(fd,2) = num_quests*sizeof(struct quest)+8; - WFIFOL(fd,4) = char_id; - - //Active and inactive quests - for( i = 0; i < num_quests; i++ ) - { - if( tmp_questlog[i].state == Q_COMPLETE ) - { - complete[num_complete++] = i; - continue; - } - memcpy(WFIFOP(fd,(i-num_complete)*sizeof(struct quest)+8), &tmp_questlog[i], sizeof(struct quest)); - } - - // Completed quests - for( i = num_quests - num_complete; i < num_quests; i++ ) - memcpy(WFIFOP(fd,i*sizeof(struct quest)+8), &tmp_questlog[complete[i-num_quests+num_complete]], sizeof(struct quest)); - - WFIFOSET(fd,num_quests*sizeof(struct quest)+8); - - return 0; -} - -int inter_quest_parse_frommap(int fd) -{ - switch(RFIFOW(fd,0)) - { - case 0x3060: mapif_parse_quest_load(fd); break; - case 0x3061: mapif_parse_quest_save(fd); break; - default: - return 0; - } - return 1; -} diff --git a/src/char_sql/int_quest.h b/src/char_sql/int_quest.h deleted file mode 100644 index f2a0b626e..000000000 --- a/src/char_sql/int_quest.h +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder - -#ifndef _QUEST_H_ -#define _QUEST_H_ - -/*questlog system*/ -struct quest; - -int inter_quest_parse_frommap(int fd); - -#endif - diff --git a/src/char_sql/int_storage.c b/src/char_sql/int_storage.c deleted file mode 100644 index e4d2395f1..000000000 --- a/src/char_sql/int_storage.c +++ /dev/null @@ -1,250 +0,0 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder - -#include "../common/mmo.h" -#include "../common/malloc.h" -#include "../common/showmsg.h" -#include "../common/socket.h" -#include "../common/strlib.h" // StringBuf -#include "../common/sql.h" -#include "char.h" -#include "inter.h" - -#include -#include -#include - - -#define STORAGE_MEMINC 16 - -/// Save storage data to sql -int storage_tosql(int account_id, struct storage_data* p) -{ - memitemdata_to_sql(p->items, MAX_STORAGE, account_id, TABLE_STORAGE); - return 0; -} - -#ifndef TXT_SQL_CONVERT -/// Load storage data to mem -int storage_fromsql(int account_id, struct storage_data* p) -{ - StringBuf buf; - struct item* item; - char* data; - int i; - int j; - - memset(p, 0, sizeof(struct storage_data)); //clean up memory - p->storage_amount = 0; - - // storage {`account_id`/`id`/`nameid`/`amount`/`equip`/`identify`/`refine`/`attribute`/`card0`/`card1`/`card2`/`card3`} - StringBuf_Init(&buf); - StringBuf_AppendStr(&buf, "SELECT `id`,`nameid`,`amount`,`equip`,`identify`,`refine`,`attribute`,`expire_time`"); - for( j = 0; j < MAX_SLOTS; ++j ) - StringBuf_Printf(&buf, ",`card%d`", j); - StringBuf_Printf(&buf, " FROM `%s` WHERE `account_id`='%d' ORDER BY `nameid`", storage_db, account_id); - - if( SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf)) ) - Sql_ShowDebug(sql_handle); - - StringBuf_Destroy(&buf); - - for( i = 0; i < MAX_STORAGE && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i ) - { - item = &p->items[i]; - Sql_GetData(sql_handle, 0, &data, NULL); item->id = atoi(data); - Sql_GetData(sql_handle, 1, &data, NULL); item->nameid = atoi(data); - Sql_GetData(sql_handle, 2, &data, NULL); item->amount = atoi(data); - Sql_GetData(sql_handle, 3, &data, NULL); item->equip = atoi(data); - Sql_GetData(sql_handle, 4, &data, NULL); item->identify = atoi(data); - Sql_GetData(sql_handle, 5, &data, NULL); item->refine = atoi(data); - Sql_GetData(sql_handle, 6, &data, NULL); item->attribute = atoi(data); - Sql_GetData(sql_handle, 7, &data, NULL); item->expire_time = (unsigned int)atoi(data); - for( j = 0; j < MAX_SLOTS; ++j ) - { - Sql_GetData(sql_handle, 8+j, &data, NULL); item->card[j] = atoi(data); - } - } - p->storage_amount = i; - Sql_FreeResult(sql_handle); - - ShowInfo("storage load complete from DB - id: %d (total: %d)\n", account_id, p->storage_amount); - return 1; -} -#endif //TXT_SQL_CONVERT - -/// Save guild_storage data to sql -int guild_storage_tosql(int guild_id, struct guild_storage* p) -{ - memitemdata_to_sql(p->items, MAX_GUILD_STORAGE, guild_id, TABLE_GUILD_STORAGE); - ShowInfo ("guild storage save to DB - guild: %d\n", guild_id); - return 0; -} - -#ifndef TXT_SQL_CONVERT -/// Load guild_storage data to mem -int guild_storage_fromsql(int guild_id, struct guild_storage* p) -{ - StringBuf buf; - struct item* item; - char* data; - int i; - int j; - - memset(p, 0, sizeof(struct guild_storage)); //clean up memory - p->storage_amount = 0; - p->guild_id = guild_id; - - // storage {`guild_id`/`id`/`nameid`/`amount`/`equip`/`identify`/`refine`/`attribute`/`card0`/`card1`/`card2`/`card3`} - StringBuf_Init(&buf); - StringBuf_AppendStr(&buf, "SELECT `id`,`nameid`,`amount`,`equip`,`identify`,`refine`,`attribute`"); - for( j = 0; j < MAX_SLOTS; ++j ) - StringBuf_Printf(&buf, ",`card%d`", j); - StringBuf_Printf(&buf, " FROM `%s` WHERE `guild_id`='%d' ORDER BY `nameid`", guild_storage_db, guild_id); - - if( SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf)) ) - Sql_ShowDebug(sql_handle); - - StringBuf_Destroy(&buf); - - for( i = 0; i < MAX_GUILD_STORAGE && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i ) - { - item = &p->items[i]; - Sql_GetData(sql_handle, 0, &data, NULL); item->id = atoi(data); - Sql_GetData(sql_handle, 1, &data, NULL); item->nameid = atoi(data); - Sql_GetData(sql_handle, 2, &data, NULL); item->amount = atoi(data); - Sql_GetData(sql_handle, 3, &data, NULL); item->equip = atoi(data); - Sql_GetData(sql_handle, 4, &data, NULL); item->identify = atoi(data); - Sql_GetData(sql_handle, 5, &data, NULL); item->refine = atoi(data); - Sql_GetData(sql_handle, 6, &data, NULL); item->attribute = atoi(data); - item->expire_time = 0; - for( j = 0; j < MAX_SLOTS; ++j ) - { - Sql_GetData(sql_handle, 7+j, &data, NULL); item->card[j] = atoi(data); - } - } - p->storage_amount = i; - Sql_FreeResult(sql_handle); - - ShowInfo("guild storage load complete from DB - id: %d (total: %d)\n", guild_id, p->storage_amount); - return 0; -} - -//--------------------------------------------------------- -// storage data initialize -int inter_storage_sql_init(void) -{ - return 1; -} -// storage data finalize -void inter_storage_sql_final(void) -{ - return; -} - -// q?f[^? -int inter_storage_delete(int account_id) -{ - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `account_id`='%d'", storage_db, account_id) ) - Sql_ShowDebug(sql_handle); - return 0; -} -int inter_guild_storage_delete(int guild_id) -{ - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id`='%d'", guild_storage_db, guild_id) ) - Sql_ShowDebug(sql_handle); - return 0; -} - -//--------------------------------------------------------- -// packet from map server - -int mapif_load_guild_storage(int fd,int account_id,int guild_id) -{ - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `guild_id` FROM `%s` WHERE `guild_id`='%d'", guild_db, guild_id) ) - Sql_ShowDebug(sql_handle); - else if( Sql_NumRows(sql_handle) > 0 ) - {// guild exists - WFIFOHEAD(fd, sizeof(struct guild_storage)+12); - WFIFOW(fd,0) = 0x3818; - WFIFOW(fd,2) = sizeof(struct guild_storage)+12; - WFIFOL(fd,4) = account_id; - WFIFOL(fd,8) = guild_id; - guild_storage_fromsql(guild_id, (struct guild_storage*)WFIFOP(fd,12)); - WFIFOSET(fd, WFIFOW(fd,2)); - return 0; - } - // guild does not exist - Sql_FreeResult(sql_handle); - WFIFOHEAD(fd, 12); - WFIFOW(fd,0) = 0x3818; - WFIFOW(fd,2) = 12; - WFIFOL(fd,4) = account_id; - WFIFOL(fd,8) = 0; - WFIFOSET(fd, 12); - return 0; -} -int mapif_save_guild_storage_ack(int fd,int account_id,int guild_id,int fail) -{ - WFIFOHEAD(fd,11); - WFIFOW(fd,0)=0x3819; - WFIFOL(fd,2)=account_id; - WFIFOL(fd,6)=guild_id; - WFIFOB(fd,10)=fail; - WFIFOSET(fd,11); - return 0; -} - -//--------------------------------------------------------- -// packet from map server - -int mapif_parse_LoadGuildStorage(int fd) -{ - RFIFOHEAD(fd); - mapif_load_guild_storage(fd,RFIFOL(fd,2),RFIFOL(fd,6)); - return 0; -} - -int mapif_parse_SaveGuildStorage(int fd) -{ - int guild_id; - int len; - - RFIFOHEAD(fd); - guild_id = RFIFOL(fd,8); - len = RFIFOW(fd,2); - - if( sizeof(struct guild_storage) != len - 12 ) - { - ShowError("inter storage: data size error %d != %d\n", sizeof(struct guild_storage), len - 12); - } - else - { - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `guild_id` FROM `%s` WHERE `guild_id`='%d'", guild_db, guild_id) ) - Sql_ShowDebug(sql_handle); - else if( Sql_NumRows(sql_handle) > 0 ) - {// guild exists - Sql_FreeResult(sql_handle); - guild_storage_tosql(guild_id, (struct guild_storage*)RFIFOP(fd,12)); - mapif_save_guild_storage_ack(fd, RFIFOL(fd,4), guild_id, 0); - return 0; - } - Sql_FreeResult(sql_handle); - } - mapif_save_guild_storage_ack(fd, RFIFOL(fd,4), guild_id, 1); - return 0; -} - - -int inter_storage_parse_frommap(int fd) -{ - RFIFOHEAD(fd); - switch(RFIFOW(fd,0)){ - case 0x3018: mapif_parse_LoadGuildStorage(fd); break; - case 0x3019: mapif_parse_SaveGuildStorage(fd); break; - default: - return 0; - } - return 1; -} -#endif //TXT_SQL_CONVERT diff --git a/src/char_sql/int_storage.h b/src/char_sql/int_storage.h deleted file mode 100644 index 811608f82..000000000 --- a/src/char_sql/int_storage.h +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder - -#ifndef _INT_STORAGE_SQL_H_ -#define _INT_STORAGE_SQL_H_ - -struct storage_data; -struct guild_storage; - -int inter_storage_sql_init(void); -void inter_storage_sql_final(void); -int inter_storage_delete(int account_id); -int inter_guild_storage_delete(int guild_id); - -int inter_storage_parse_frommap(int fd); - -//Exported for use in the TXT-SQL converter. -int storage_fromsql(int account_id, struct storage_data* p); -int storage_tosql(int account_id,struct storage_data *p); -int guild_storage_tosql(int guild_id, struct guild_storage *p); - -#endif /* _INT_STORAGE_SQL_H_ */ diff --git a/src/char_sql/inter.c b/src/char_sql/inter.c deleted file mode 100644 index 50f05f6a3..000000000 --- a/src/char_sql/inter.c +++ /dev/null @@ -1,744 +0,0 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder - -#include "../common/mmo.h" -#include "../common/db.h" -#include "../common/malloc.h" -#include "../common/strlib.h" -#include "../common/showmsg.h" -#include "../common/socket.h" -#include "../common/timer.h" -#include "char.h" -#include "inter.h" -#include "int_party.h" -#include "int_guild.h" -#include "int_storage.h" -#include "int_pet.h" -#include "int_homun.h" -#include "int_mercenary.h" -#include "int_mail.h" -#include "int_auction.h" -#include "int_quest.h" - -#include -#include -#include - -#define WISDATA_TTL (60*1000) // Wisデータの生存時間(60秒) -#define WISDELLIST_MAX 256 // Wisデータ削除リストの要素数 - - -Sql* sql_handle = NULL; - -int char_server_port = 3306; -char char_server_ip[32] = "127.0.0.1"; -char char_server_id[32] = "ragnarok"; -char char_server_pw[32] = "ragnarok"; -char char_server_db[32] = "ragnarok"; -char default_codepage[32] = ""; //Feature by irmin. - -#ifndef TXT_SQL_CONVERT - -static struct accreg *accreg_pt; -unsigned int party_share_level = 10; -char main_chat_nick[16] = "Main"; - -// recv. packet list -int inter_recv_packet_length[] = { - -1,-1, 7,-1, -1,13,36, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3000- - 6,-1, 0, 0, 0, 0, 0, 0, 10,-1, 0, 0, 0, 0, 0, 0, // 3010- - -1,10,-1,14, 14,19, 6,-1, 14,14, 0, 0, 0, 0, 0, 0, // 3020- Party - -1, 6,-1,-1, 55,19, 6,-1, 14,-1,-1,-1, 18,19,186,-1, // 3030- - 5, 9, 0, 0, 0, 0, 0, 0, 7, 6,10,10, 10,-1, 0, 0, // 3040- - -1,-1,10,10, 0,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3050- Auction System [Zephyrus] - 6,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3060- Quest system [Kevin] [Inkfish] - -1,10, 6,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3070- Mercenary packets [Zephyrus] - 48,14,-1, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3080- - -1,10,-1, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3090- Homunculus packets [albator] -}; - -struct WisData { - int id, fd, count, len; - unsigned long tick; - unsigned char src[24], dst[24], msg[512]; -}; -static DBMap* wis_db = NULL; // int wis_id -> struct WisData* -static int wis_dellist[WISDELLIST_MAX], wis_delnum; - -#endif //TXT_SQL_CONVERT -//-------------------------------------------------------- -// Save registry to sql -int inter_accreg_tosql(int account_id, int char_id, struct accreg* reg, int type) -{ - struct global_reg* r; - SqlStmt* stmt; - int i; - - if( account_id <= 0 ) - return 0; - reg->account_id = account_id; - reg->char_id = char_id; - - //`global_reg_value` (`type`, `account_id`, `char_id`, `str`, `value`) - switch( type ) - { - case 3: //Char Reg - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `type`=3 AND `char_id`='%d'", reg_db, char_id) ) - Sql_ShowDebug(sql_handle); - account_id = 0; - break; - case 2: //Account Reg - if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `type`=2 AND `account_id`='%d'", reg_db, account_id) ) - Sql_ShowDebug(sql_handle); - char_id = 0; - break; - case 1: //Account2 Reg - ShowError("inter_accreg_tosql: Char server shouldn't handle type 1 registry values (##). That is the login server's work!\n"); - return 0; - default: - ShowError("inter_accreg_tosql: Invalid type %d\n", type); - return 0; - } - - if( reg->reg_num <= 0 ) - return 0; - - stmt = SqlStmt_Malloc(sql_handle); - if( SQL_ERROR == SqlStmt_Prepare(stmt, "INSERT INTO `%s` (`type`, `account_id`, `char_id`, `str`, `value`) VALUES ('%d','%d','%d',?,?)", reg_db, type, account_id, char_id) ) - SqlStmt_ShowDebug(stmt); - for( i = 0; i < reg->reg_num; ++i ) - { - r = ®->reg[i]; - if( r->str[0] != '\0' && r->value != '\0' ) - { - // str - SqlStmt_BindParam(stmt, 0, SQLDT_STRING, r->str, strnlen(r->str, sizeof(r->str))); - // value - SqlStmt_BindParam(stmt, 1, SQLDT_STRING, r->value, strnlen(r->value, sizeof(r->value))); - - if( SQL_ERROR == SqlStmt_Execute(stmt) ) - SqlStmt_ShowDebug(stmt); - } - } - SqlStmt_Free(stmt); - return 1; -} -#ifndef TXT_SQL_CONVERT - -// Load account_reg from sql (type=2) -int inter_accreg_fromsql(int account_id,int char_id, struct accreg *reg, int type) -{ - struct global_reg* r; - char* data; - size_t len; - int i; - - if( reg == NULL) - return 0; - - memset(reg, 0, sizeof(struct accreg)); - reg->account_id = account_id; - reg->char_id = char_id; - - //`global_reg_value` (`type`, `account_id`, `char_id`, `str`, `value`) - switch( type ) - { - case 3: //char reg - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `str`, `value` FROM `%s` WHERE `type`=3 AND `char_id`='%d'", reg_db, char_id) ) - Sql_ShowDebug(sql_handle); - break; - case 2: //account reg - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `str`, `value` FROM `%s` WHERE `type`=2 AND `account_id`='%d'", reg_db, account_id) ) - Sql_ShowDebug(sql_handle); - break; - case 1: //account2 reg - ShowError("inter_accreg_fromsql: Char server shouldn't handle type 1 registry values (##). That is the login server's work!\n"); - return 0; - default: - ShowError("inter_accreg_fromsql: Invalid type %d\n", type); - return 0; - } - for( i = 0; i < MAX_REG_NUM && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i ) - { - r = ®->reg[i]; - // str - Sql_GetData(sql_handle, 0, &data, &len); - memcpy(r->str, data, min(len, sizeof(r->str))); - // value - Sql_GetData(sql_handle, 1, &data, &len); - memcpy(r->value, data, min(len, sizeof(r->value))); - } - reg->reg_num = i; - Sql_FreeResult(sql_handle); - return 1; -} - -// Initialize -int inter_accreg_sql_init(void) -{ - CREATE(accreg_pt, struct accreg, 1); - return 0; - -} -#endif //TXT_SQL_CONVERT - -/*========================================== - * read config file - *------------------------------------------*/ -static int inter_config_read(const char* cfgName) -{ - int i; - char line[1024], w1[1024], w2[1024]; - FILE* fp; - - fp = fopen(cfgName, "r"); - if(fp == NULL) { - ShowError("file not found: %s\n", cfgName); - return 1; - } - - ShowInfo("reading file %s...\n", cfgName); - - while(fgets(line, sizeof(line), fp)) - { - i = sscanf(line, "%[^:]: %[^\r\n]", w1, w2); - if(i != 2) - continue; - - if(!strcmpi(w1,"char_server_ip")) { - strcpy(char_server_ip,w2); - ShowStatus ("set char_server_ip : %s\n", w2); - } else - if(!strcmpi(w1,"char_server_port")) { - char_server_port = atoi(w2); - ShowStatus ("set char_server_port : %s\n", w2); - } else - if(!strcmpi(w1,"char_server_id")) { - strcpy(char_server_id,w2); - ShowStatus ("set char_server_id : %s\n", w2); - } else - if(!strcmpi(w1,"char_server_pw")) { - strcpy(char_server_pw,w2); - ShowStatus ("set char_server_pw : %s\n", w2); - } else - if(!strcmpi(w1,"char_server_db")) { - strcpy(char_server_db,w2); - ShowStatus ("set char_server_db : %s\n", w2); - } else - if(!strcmpi(w1,"default_codepage")) { - strcpy(default_codepage,w2); - ShowStatus ("set default_codepage : %s\n", w2); - } -#ifndef TXT_SQL_CONVERT - else if(!strcmpi(w1,"party_share_level")) - party_share_level = atoi(w2); - else if(!strcmpi(w1,"log_inter")) - log_inter = atoi(w2); - else if(!strcmpi(w1,"main_chat_nick")) - safestrncpy(main_chat_nick, w2, sizeof(main_chat_nick)); -#endif //TXT_SQL_CONVERT - else if(!strcmpi(w1,"import")) - inter_config_read(w2); - } - fclose(fp); - - ShowInfo ("done reading %s.\n", cfgName); - - return 0; -} -#ifndef TXT_SQL_CONVERT - -// Save interlog into sql -int inter_log(char* fmt, ...) -{ - char str[255]; - char esc_str[sizeof(str)*2+1];// escaped str - va_list ap; - - va_start(ap,fmt); - vsnprintf(str, sizeof(str), fmt, ap); - va_end(ap); - - Sql_EscapeStringLen(sql_handle, esc_str, str, strnlen(str, sizeof(str))); - if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`time`, `log`) VALUES (NOW(), '%s')", interlog_db, esc_str) ) - Sql_ShowDebug(sql_handle); - - return 0; -} - -#endif //TXT_SQL_CONVERT - -// initialize -int inter_init_sql(const char *file) -{ - //int i; - - ShowInfo ("interserver initialize...\n"); - inter_config_read(file); - - //DB connection initialized - sql_handle = Sql_Malloc(); - ShowInfo("Connect Character DB server.... (Character Server)\n"); - if( SQL_ERROR == Sql_Connect(sql_handle, char_server_id, char_server_pw, char_server_ip, (uint16)char_server_port, char_server_db) ) - { - Sql_ShowDebug(sql_handle); - Sql_Free(sql_handle); - exit(EXIT_FAILURE); - } - - if( *default_codepage ) { - if( SQL_ERROR == Sql_SetEncoding(sql_handle, default_codepage) ) - Sql_ShowDebug(sql_handle); - } - -#ifndef TXT_SQL_CONVERT - wis_db = idb_alloc(DB_OPT_RELEASE_DATA); - inter_guild_sql_init(); - inter_storage_sql_init(); - inter_party_sql_init(); - inter_pet_sql_init(); - inter_homunculus_sql_init(); - inter_mercenary_sql_init(); - inter_accreg_sql_init(); - inter_mail_sql_init(); - inter_auction_sql_init(); - -#endif //TXT_SQL_CONVERT - return 0; -} -#ifndef TXT_SQL_CONVERT - -// finalize -void inter_final(void) -{ - wis_db->destroy(wis_db, NULL); - - inter_guild_sql_final(); - inter_storage_sql_final(); - inter_party_sql_final(); - inter_pet_sql_final(); - inter_homunculus_sql_final(); - inter_mercenary_sql_final(); - inter_mail_sql_final(); - inter_auction_sql_final(); - - if (accreg_pt) aFree(accreg_pt); - return; -} - -int inter_mapif_init(int fd) -{ - inter_guild_mapif_init(fd); - - return 0; -} - - -//-------------------------------------------------------- - -// broadcast sending -int mapif_broadcast(unsigned char *mes, int len, unsigned long fontColor, short fontType, short fontSize, short fontAlign, short fontY, int sfd) -{ - unsigned char *buf = (unsigned char*)aMallocA((len)*sizeof(unsigned char)); - - WBUFW(buf,0) = 0x3800; - WBUFW(buf,2) = len; - WBUFL(buf,4) = fontColor; - WBUFW(buf,8) = fontType; - WBUFW(buf,10) = fontSize; - WBUFW(buf,12) = fontAlign; - WBUFW(buf,14) = fontY; - memcpy(WBUFP(buf,16), mes, len - 16); - mapif_sendallwos(sfd, buf, len); - - if (buf) - aFree(buf); - return 0; -} - -// Wis sending -int mapif_wis_message(struct WisData *wd) -{ - unsigned char buf[2048]; - if (wd->len > 2047-56) wd->len = 2047-56; //Force it to fit to avoid crashes. [Skotlex] - - WBUFW(buf, 0) = 0x3801; - WBUFW(buf, 2) = 56 +wd->len; - WBUFL(buf, 4) = wd->id; - memcpy(WBUFP(buf, 8), wd->src, NAME_LENGTH); - memcpy(WBUFP(buf,32), wd->dst, NAME_LENGTH); - memcpy(WBUFP(buf,56), wd->msg, wd->len); - wd->count = mapif_sendall(buf,WBUFW(buf,2)); - - return 0; -} - -// Wis sending result -int mapif_wis_end(struct WisData *wd, int flag) -{ - unsigned char buf[27]; - - WBUFW(buf, 0)=0x3802; - memcpy(WBUFP(buf, 2),wd->src,24); - WBUFB(buf,26)=flag; - mapif_send(wd->fd,buf,27); - return 0; -} - -// Account registry transfer to map-server -static void mapif_account_reg(int fd, unsigned char *src) -{ - WBUFW(src,0)=0x3804; //NOTE: writing to RFIFO - mapif_sendallwos(fd, src, WBUFW(src,2)); -} - -// Send the requested account_reg -int mapif_account_reg_reply(int fd,int account_id,int char_id, int type) -{ - struct accreg *reg=accreg_pt; - WFIFOHEAD(fd, 13 + 5000); - inter_accreg_fromsql(account_id,char_id,reg,type); - - WFIFOW(fd,0)=0x3804; - WFIFOL(fd,4)=account_id; - WFIFOL(fd,8)=char_id; - WFIFOB(fd,12)=type; - if(reg->reg_num==0){ - WFIFOW(fd,2)=13; - }else{ - int i,p; - for (p=13,i = 0; i < reg->reg_num && p < 5000; i++) { - p+= sprintf((char*)WFIFOP(fd,p), "%s", reg->reg[i].str)+1; //We add 1 to consider the '\0' in place. - p+= sprintf((char*)WFIFOP(fd,p), "%s", reg->reg[i].value)+1; - } - WFIFOW(fd,2)=p; - if (p>= 5000) - ShowWarning("Too many acc regs for %d:%d, not all values were loaded.\n", account_id, char_id); - } - WFIFOSET(fd,WFIFOW(fd,2)); - return 0; -} - -//Request to kick char from a certain map server. [Skotlex] -int mapif_disconnectplayer(int fd, int account_id, int char_id, int reason) -{ - if (fd >= 0) - { - WFIFOHEAD(fd,7); - WFIFOW(fd,0) = 0x2b1f; - WFIFOL(fd,2) = account_id; - WFIFOB(fd,6) = reason; - WFIFOSET(fd,7); - return 0; - } - return -1; -} - -//-------------------------------------------------------- - -// Existence check of WISP data -int check_ttl_wisdata_sub(DBKey key, void *data, va_list ap) -{ - unsigned long tick; - struct WisData *wd = (struct WisData *)data; - tick = va_arg(ap, unsigned long); - - if (DIFF_TICK(tick, wd->tick) > WISDATA_TTL && wis_delnum < WISDELLIST_MAX) - wis_dellist[wis_delnum++] = wd->id; - - return 0; -} - -int check_ttl_wisdata(void) -{ - unsigned long tick = gettick(); - int i; - - do { - wis_delnum = 0; - wis_db->foreach(wis_db, check_ttl_wisdata_sub, tick); - for(i = 0; i < wis_delnum; i++) { - struct WisData *wd = (struct WisData*)idb_get(wis_db, wis_dellist[i]); - ShowWarning("inter: wis data id=%d time out : from %s to %s\n", wd->id, wd->src, wd->dst); - // removed. not send information after a timeout. Just no answer for the player - //mapif_wis_end(wd, 1); // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target - idb_remove(wis_db, wd->id); - } - } while(wis_delnum >= WISDELLIST_MAX); - - return 0; -} - -//-------------------------------------------------------- - -// broadcast sending -int mapif_parse_broadcast(int fd) -{ - mapif_broadcast(RFIFOP(fd,16), RFIFOW(fd,2), RFIFOL(fd,4), RFIFOW(fd,8), RFIFOW(fd,10), RFIFOW(fd,12), RFIFOW(fd,14), fd); - return 0; -} - - -// Wisp/page request to send -int mapif_parse_WisRequest(int fd) -{ - struct WisData* wd; - static int wisid = 0; - char name[NAME_LENGTH]; - char esc_name[NAME_LENGTH*2+1];// escaped name - char* data; - size_t len; - - - if ( fd <= 0 ) {return 0;} // check if we have a valid fd - - if (RFIFOW(fd,2)-52 >= sizeof(wd->msg)) { - ShowWarning("inter: Wis message size too long.\n"); - return 0; - } else if (RFIFOW(fd,2)-52 <= 0) { // normaly, impossible, but who knows... - ShowError("inter: Wis message doesn't exist.\n"); - return 0; - } - - safestrncpy(name, (char*)RFIFOP(fd,28), NAME_LENGTH); //Received name may be too large and not contain \0! [Skotlex] - - Sql_EscapeStringLen(sql_handle, esc_name, name, strnlen(name, NAME_LENGTH)); - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `name` FROM `%s` WHERE `name`='%s'", char_db, esc_name) ) - Sql_ShowDebug(sql_handle); - - // search if character exists before to ask all map-servers - if( SQL_SUCCESS != Sql_NextRow(sql_handle) ) - { - unsigned char buf[27]; - WBUFW(buf, 0) = 0x3802; - memcpy(WBUFP(buf, 2), RFIFOP(fd, 4), NAME_LENGTH); - WBUFB(buf,26) = 1; // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target - mapif_send(fd, buf, 27); - } - else - {// Character exists. So, ask all map-servers - // to be sure of the correct name, rewrite it - Sql_GetData(sql_handle, 0, &data, &len); - memset(name, 0, NAME_LENGTH); - memcpy(name, data, min(len, NAME_LENGTH)); - // if source is destination, don't ask other servers. - if( strncmp((const char*)RFIFOP(fd,4), name, NAME_LENGTH) == 0 ) - { - uint8 buf[27]; - WBUFW(buf, 0) = 0x3802; - memcpy(WBUFP(buf, 2), RFIFOP(fd, 4), NAME_LENGTH); - WBUFB(buf,26) = 1; // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target - mapif_send(fd, buf, 27); - } - else - { - - CREATE(wd, struct WisData, 1); - - // Whether the failure of previous wisp/page transmission (timeout) - check_ttl_wisdata(); - - wd->id = ++wisid; - wd->fd = fd; - wd->len= RFIFOW(fd,2)-52; - memcpy(wd->src, RFIFOP(fd, 4), NAME_LENGTH); - memcpy(wd->dst, RFIFOP(fd,28), NAME_LENGTH); - memcpy(wd->msg, RFIFOP(fd,52), wd->len); - wd->tick = gettick(); - idb_put(wis_db, wd->id, wd); - mapif_wis_message(wd); - } - } - - Sql_FreeResult(sql_handle); - return 0; -} - - -// Wisp/page transmission result -int mapif_parse_WisReply(int fd) -{ - int id, flag; - struct WisData *wd; - - id = RFIFOL(fd,2); - flag = RFIFOB(fd,6); - wd = (struct WisData*)idb_get(wis_db, id); - if (wd == NULL) - return 0; // This wisp was probably suppress before, because it was timeout of because of target was found on another map-server - - if ((--wd->count) <= 0 || flag != 1) { - mapif_wis_end(wd, flag); // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target - idb_remove(wis_db, id); - } - - return 0; -} - -// Received wisp message from map-server for ALL gm (just copy the message and resends it to ALL map-servers) -int mapif_parse_WisToGM(int fd) -{ - unsigned char buf[2048]; // 0x3003/0x3803 .w .24B .w .?B - - memcpy(WBUFP(buf,0), RFIFOP(fd,0), RFIFOW(fd,2)); - WBUFW(buf, 0) = 0x3803; - mapif_sendall(buf, RFIFOW(fd,2)); - - return 0; -} - -// Save account_reg into sql (type=2) -int mapif_parse_Registry(int fd) -{ - int j,p,len, max; - struct accreg *reg=accreg_pt; - - memset(accreg_pt,0,sizeof(struct accreg)); - switch (RFIFOB(fd, 12)) { - case 3: //Character registry - max = GLOBAL_REG_NUM; - break; - case 2: //Account Registry - max = ACCOUNT_REG_NUM; - break; - case 1: //Account2 registry, must be sent over to login server. - return save_accreg2(RFIFOP(fd,4), RFIFOW(fd,2)-4); - default: - return 1; - } - for(j=0,p=13;jreg[j].str,&len); - reg->reg[j].str[len]='\0'; - p +=len+1; //+1 to skip the '\0' between strings. - sscanf((char*)RFIFOP(fd,p), "%255c%n",reg->reg[j].value,&len); - reg->reg[j].value[len]='\0'; - p +=len+1; - } - reg->reg_num=j; - - inter_accreg_tosql(RFIFOL(fd,4),RFIFOL(fd,8),reg, RFIFOB(fd,12)); - mapif_account_reg(fd,RFIFOP(fd,0)); // Send updated accounts to other map servers. - return 0; -} - -// Request the value of all registries. -int mapif_parse_RegistryRequest(int fd) -{ - //Load Char Registry - if (RFIFOB(fd,12)) mapif_account_reg_reply(fd,RFIFOL(fd,2),RFIFOL(fd,6),3); - //Load Account Registry - if (RFIFOB(fd,11)) mapif_account_reg_reply(fd,RFIFOL(fd,2),RFIFOL(fd,6),2); - //Ask Login Server for Account2 values. - if (RFIFOB(fd,10)) request_accreg2(RFIFOL(fd,2),RFIFOL(fd,6)); - return 1; -} - -static void mapif_namechange_ack(int fd, int account_id, int char_id, int type, int flag, char *name) -{ - WFIFOHEAD(fd, NAME_LENGTH+13); - WFIFOW(fd, 0) = 0x3806; - WFIFOL(fd, 2) = account_id; - WFIFOL(fd, 6) = char_id; - WFIFOB(fd,10) = type; - WFIFOB(fd,11) = flag; - memcpy(WFIFOP(fd, 12), name, NAME_LENGTH); - WFIFOSET(fd, NAME_LENGTH+13); -} - -int mapif_parse_NameChangeRequest(int fd) -{ - int account_id, char_id, type; - char* name; - int i; - - account_id = RFIFOL(fd,2); - char_id = RFIFOL(fd,6); - type = RFIFOB(fd,10); - name = (char*)RFIFOP(fd,11); - - // Check Authorised letters/symbols in the name - if (char_name_option == 1) { // only letters/symbols in char_name_letters are authorised - for (i = 0; i < NAME_LENGTH && name[i]; i++) - if (strchr(char_name_letters, name[i]) == NULL) { - mapif_namechange_ack(fd, account_id, char_id, type, 0, name); - return 0; - } - } else if (char_name_option == 2) { // letters/symbols in char_name_letters are forbidden - for (i = 0; i < NAME_LENGTH && name[i]; i++) - if (strchr(char_name_letters, name[i]) != NULL) { - mapif_namechange_ack(fd, account_id, char_id, type, 0, name); - return 0; - } - } - //TODO: type holds the type of object to rename. - //If it were a player, it needs to have the guild information and db information - //updated here, because changing it on the map won't make it be saved [Skotlex] - - //name allowed. - mapif_namechange_ack(fd, account_id, char_id, type, 1, name); - return 0; -} - -//-------------------------------------------------------- - -/// Returns the length of the next complete packet to process, -/// or 0 if no complete packet exists in the queue. -/// -/// @param length The minimum allowed length, or -1 for dynamic lookup -int inter_check_length(int fd, int length) -{ - if( length == -1 ) - {// variable-length packet - if( RFIFOREST(fd) < 4 ) - return 0; - length = RFIFOW(fd,2); - } - - if( (int)RFIFOREST(fd) < length ) - return 0; - - return length; -} - -int inter_parse_frommap(int fd) -{ - int cmd; - int len = 0; - cmd = RFIFOW(fd,0); - // inter鯖管轄かを調べる - if(cmd < 0x3000 || cmd >= 0x3000 + ARRAYLENGTH(inter_recv_packet_length) || inter_recv_packet_length[cmd - 0x3000] == 0) - return 0; - - // パケット長を調べる - if((len = inter_check_length(fd, inter_recv_packet_length[cmd - 0x3000])) == 0) - return 2; - - switch(cmd) { - case 0x3000: mapif_parse_broadcast(fd); break; - case 0x3001: mapif_parse_WisRequest(fd); break; - case 0x3002: mapif_parse_WisReply(fd); break; - case 0x3003: mapif_parse_WisToGM(fd); break; - case 0x3004: mapif_parse_Registry(fd); break; - case 0x3005: mapif_parse_RegistryRequest(fd); break; - case 0x3006: mapif_parse_NameChangeRequest(fd); break; - default: - if( inter_party_parse_frommap(fd) - || inter_guild_parse_frommap(fd) - || inter_storage_parse_frommap(fd) - || inter_pet_parse_frommap(fd) - || inter_homunculus_parse_frommap(fd) - || inter_mercenary_parse_frommap(fd) - || inter_mail_parse_frommap(fd) - || inter_auction_parse_frommap(fd) - || inter_quest_parse_frommap(fd) - ) - break; - else - return 0; - } - - RFIFOSKIP(fd, len); - return 1; -} - -#endif //TXT_SQL_CONVERT diff --git a/src/char_sql/inter.h b/src/char_sql/inter.h deleted file mode 100644 index ac2e1785f..000000000 --- a/src/char_sql/inter.h +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder - -#ifndef _INTER_SQL_H_ -#define _INTER_SQL_H_ - -struct accreg; -#include "../common/sql.h" - -int inter_init_sql(const char *file); -void inter_final(void); -int inter_parse_frommap(int fd); -int inter_mapif_init(int fd); -int mapif_send_gmaccounts(void); -int mapif_disconnectplayer(int fd, int account_id, int char_id, int reason); - -int inter_log(char *fmt,...); - -#define inter_cfgName "conf/inter_athena.conf" - -extern unsigned int party_share_level; - -extern Sql* sql_handle; -extern Sql* lsql_handle; - -extern char main_chat_nick[16]; - -int inter_accreg_tosql(int account_id, int char_id, struct accreg *reg, int type); - -#endif /* _INTER_SQL_H_ */ diff --git a/src/login/CMakeLists.txt b/src/login/CMakeLists.txt index eabc47eac..fa657f8fd 100644 --- a/src/login/CMakeLists.txt +++ b/src/login/CMakeLists.txt @@ -3,12 +3,10 @@ # setup # set( LOGIN_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR} CACHE INTERNAL "" ) -set( TXT_LOGIN_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR} CACHE INTERNAL "" ) set( SQL_LOGIN_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR} CACHE INTERNAL "" ) # # targets # -add_subdirectory( txt ) add_subdirectory( sql ) diff --git a/src/login/Makefile.in b/src/login/Makefile.in index dd7bc3b48..7dfe085c0 100644 --- a/src/login/Makefile.in +++ b/src/login/Makefile.in @@ -18,8 +18,6 @@ MT19937AR_H = ../../3rdparty/mt19937ar/mt19937ar.h MT19937AR_INCLUDE = -I../../3rdparty/mt19937ar LOGIN_OBJ = login.o -LOGIN_TXT_OBJ = $(LOGIN_OBJ:%=obj_txt/%) \ - obj_txt/account_txt.o obj_txt/ipban_txt.o obj_txt/loginlog_txt.o LOGIN_SQL_OBJ = $(LOGIN_OBJ:%=obj_sql/%) \ obj_sql/account_sql.o obj_sql/ipban_sql.o obj_sql/loginlog_sql.o LOGIN_H = login.h account.h ipban.h loginlog.h @@ -30,26 +28,22 @@ ifeq ($(HAVE_MYSQL),yes) else LOGIN_SERVER_SQL_DEPENDS=needs_mysql endif -LOGIN_SERVER_TXT_DEPENDS=obj_txt $(LOGIN_TXT_OBJ) $(COMMON_OBJ) $(MT19937AR_OBJ) @SET_MAKE@ ##################################################################### -.PHONY :all txt sql clean help +.PHONY :all sql clean help -all: txt sql - -txt: obj_txt login-server +all: sql sql: obj_sql login-server_sql clean: - rm -rf *.o obj_txt obj_sql ../../login-server@EXEEXT@ ../../login-server_sql@EXEEXT@ + rm -rf *.o obj_sql ../../login-server@EXEEXT@ ../../login-server_sql@EXEEXT@ help: - @echo "possible targets are 'sql' 'txt' 'all' 'clean' 'help'" + @echo "possible targets are 'sql' 'all' 'clean' 'help'" @echo "'sql' - login server (SQL version)" - @echo "'txt' - login server (TXT version)" @echo "'all' - builds all above targets" @echo "'clean' - cleans builds and objects" @echo "'help' - outputs this message" @@ -61,29 +55,23 @@ needs_mysql: @exit 1 # object directories -obj_txt: - test -d obj_txt || mkdir obj_txt obj_sql: test -d obj_sql || mkdir obj_sql #executables -login-server: $(LOGIN_SERVER_TXT_DEPENDS) - @CC@ @LDFLAGS@ -o ../../login-server@EXEEXT@ $(LOGIN_TXT_OBJ) $(COMMON_OBJ) $(MT19937AR_OBJ) @LIBS@ login-server_sql: $(LOGIN_SERVER_SQL_DEPENDS) @CC@ @LDFLAGS@ -o ../../login-server_sql@EXEEXT@ $(LOGIN_SQL_OBJ) $(COMMON_OBJ) $(COMMON_SQL_OBJ) $(MT19937AR_OBJ) @LIBS@ @MYSQL_LIBS@ # login object files -obj_txt/%.o: %.c $(LOGIN_H) $(COMMON_H) $(MT19937AR_H) - @CC@ @CFLAGS@ $(MT19937AR_INCLUDE) -DWITH_TXT @CPPFLAGS@ -c $(OUTPUT_OPTION) $< obj_sql/%.o: %.c $(LOGIN_H) $(COMMON_H) $(MT19937AR_H) @CC@ @CFLAGS@ $(MT19937AR_INCLUDE) -DWITH_SQL @MYSQL_CFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $< # missing object files ../common/obj_all/%.o: - @$(MAKE) -C ../common txt + @$(MAKE) -C ../common sql ../common/obj_sql/%.o: @$(MAKE) -C ../common sql diff --git a/src/login/account.h b/src/login/account.h index 650f2c661..170d60aca 100644 --- a/src/login/account.h +++ b/src/login/account.h @@ -12,12 +12,8 @@ typedef struct AccountDBIterator AccountDBIterator; // standard engines -#ifdef WITH_TXT -AccountDB* account_db_txt(void); -#endif -#ifdef WITH_SQL AccountDB* account_db_sql(void); -#endif + // extra engines (will probably use the other txt functions) #define ACCOUNTDB_CONSTRUCTOR_(engine) account_db_##engine #define ACCOUNTDB_CONSTRUCTOR(engine) ACCOUNTDB_CONSTRUCTOR_(engine) diff --git a/src/login/account_txt.c b/src/login/account_txt.c deleted file mode 100644 index 79e22ac3b..000000000 --- a/src/login/account_txt.c +++ /dev/null @@ -1,645 +0,0 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder - -#include "../common/db.h" -#include "../common/lock.h" -#include "../common/malloc.h" -#include "../common/mmo.h" -#include "../common/showmsg.h" -#include "../common/strlib.h" -#include "../common/timer.h" -#include "account.h" -#include -#include -#include - -/// global defines -#define ACCOUNT_TXT_DB_VERSION 20110114 -#define AUTHS_BEFORE_SAVE 10 // flush every 10 saves -#define AUTH_SAVING_INTERVAL 60000 // flush every 10 minutes - -/// internal structure -typedef struct AccountDB_TXT -{ - AccountDB vtable; // public interface - - DBMap* accounts; // in-memory accounts storage - int next_account_id; // auto_increment - int auths_before_save; // prevents writing to disk too often - int save_timer; // save timer id - - char account_db[1024]; // account data storage file - bool case_sensitive; // how to look up usernames - -} AccountDB_TXT; - -/// internal structure -typedef struct AccountDBIterator_TXT -{ - AccountDBIterator vtable; // public interface - - DBIterator* iter; -} AccountDBIterator_TXT; - -/// internal functions -static bool account_db_txt_init(AccountDB* self); -static void account_db_txt_destroy(AccountDB* self); -static bool account_db_txt_get_property(AccountDB* self, const char* key, char* buf, size_t buflen); -static bool account_db_txt_set_property(AccountDB* self, const char* option, const char* value); -static bool account_db_txt_create(AccountDB* self, struct mmo_account* acc); -static bool account_db_txt_remove(AccountDB* self, const int account_id); -static bool account_db_txt_save(AccountDB* self, const struct mmo_account* acc); -static bool account_db_txt_load_num(AccountDB* self, struct mmo_account* acc, const int account_id); -static bool account_db_txt_load_str(AccountDB* self, struct mmo_account* acc, const char* userid); -static AccountDBIterator* account_db_txt_iterator(AccountDB* self); -static void account_db_txt_iter_destroy(AccountDBIterator* self); -static bool account_db_txt_iter_next(AccountDBIterator* self, struct mmo_account* acc); - -static bool mmo_auth_fromstr(struct mmo_account* acc, char* str, unsigned int version); -static bool mmo_auth_tostr(const struct mmo_account* acc, char* str); -static void mmo_auth_sync(AccountDB_TXT* self); -static int mmo_auth_sync_timer(int tid, unsigned int tick, int id, intptr_t data); - -/// public constructor -AccountDB* account_db_txt(void) -{ - AccountDB_TXT* db = (AccountDB_TXT*)aCalloc(1, sizeof(AccountDB_TXT)); - - // set up the vtable - db->vtable.init = &account_db_txt_init; - db->vtable.destroy = &account_db_txt_destroy; - db->vtable.get_property = &account_db_txt_get_property; - db->vtable.set_property = &account_db_txt_set_property; - db->vtable.save = &account_db_txt_save; - db->vtable.create = &account_db_txt_create; - db->vtable.remove = &account_db_txt_remove; - db->vtable.load_num = &account_db_txt_load_num; - db->vtable.load_str = &account_db_txt_load_str; - db->vtable.iterator = &account_db_txt_iterator; - - // initialize to default values - db->accounts = NULL; - db->next_account_id = START_ACCOUNT_NUM; - db->auths_before_save = AUTHS_BEFORE_SAVE; - db->save_timer = INVALID_TIMER; - safestrncpy(db->account_db, "save/account.txt", sizeof(db->account_db)); - db->case_sensitive = false; - - return &db->vtable; -} - - -/* ------------------------------------------------------------------------- */ - - -/// opens accounts file, loads it, and starts a periodic saving timer -static bool account_db_txt_init(AccountDB* self) -{ - AccountDB_TXT* db = (AccountDB_TXT*)self; - DBMap* accounts; - FILE* fp; - char line[2048]; - unsigned int version = 0; - - // create accounts database - db->accounts = idb_alloc(DB_OPT_RELEASE_DATA); - accounts = db->accounts; - - // open data file - fp = fopen(db->account_db, "r"); - if( fp == NULL ) - { - // no account file -> no account -> no login, including char-server (ERROR) - ShowError(CL_RED"account_db_txt_init: Accounts file [%s] not found."CL_RESET"\n", db->account_db); - return false; - } - - // load data file - while( fgets(line, sizeof(line), fp) != NULL ) - { - int account_id, n; - unsigned int v; - struct mmo_account acc; - struct mmo_account* tmp; - struct DBIterator* iter; - int (*compare)(const char* str1, const char* str2) = ( db->case_sensitive ) ? strcmp : stricmp; - - if( line[0] == '/' && line[1] == '/' ) - continue; - - n = 0; - if( sscanf(line, "%d%n", &v, &n) == 1 && (line[n] == '\n' || line[n] == '\r') ) - {// format version definition - version = v; - continue; - } - - n = 0; - if( sscanf(line, "%d\t%%newid%%%n", &account_id, &n) == 1 && (line[n] == '\n' || line[n] == '\r') ) - {// auto-increment - if( account_id > db->next_account_id ) - db->next_account_id = account_id; - continue; - } - - if( !mmo_auth_fromstr(&acc, line, version) ) - { - ShowError("account_db_txt_init: skipping invalid data: %s", line); - continue; - } - - // apply constraints & checks here - if( acc.sex != 'S' && (acc.account_id < START_ACCOUNT_NUM || acc.account_id > END_ACCOUNT_NUM) ) - ShowWarning("account_db_txt_init: account %d:'%s' has ID outside of the defined range for accounts (min:%d max:%d)!\n", acc.account_id, acc.userid, START_ACCOUNT_NUM, END_ACCOUNT_NUM); - - iter = accounts->iterator(accounts); - for( tmp = (struct mmo_account*)iter->first(iter,NULL); iter->exists(iter); tmp = (struct mmo_account*)iter->next(iter,NULL) ) - if( compare(acc.userid, tmp->userid) == 0 ) - break; - iter->destroy(iter); - - if( tmp != NULL ) - {// entry with identical username - ShowWarning("account_db_txt_init: account %d:'%s' has same username as account %d. The account will be inaccessible!\n", acc.account_id, acc.userid, tmp->account_id); - } - - if( idb_get(accounts, acc.account_id) != NULL ) - {// account id already occupied - ShowError("account_db_txt_init: ID collision for account id %d! Discarding data for account '%s'...\n", acc.account_id, acc.userid); - continue; - } - - // record entry in db - tmp = (struct mmo_account*)aMalloc(sizeof(struct mmo_account)); - memcpy(tmp, &acc, sizeof(struct mmo_account)); - idb_put(accounts, acc.account_id, tmp); - - if( acc.account_id >= db->next_account_id ) - db->next_account_id = acc.account_id + 1; - } - - // close data file - fclose(fp); - - // initialize data saving timer - add_timer_func_list(mmo_auth_sync_timer, "mmo_auth_sync_timer"); - db->save_timer = add_timer_interval(gettick() + AUTH_SAVING_INTERVAL, mmo_auth_sync_timer, 0, (intptr_t)db, AUTH_SAVING_INTERVAL); - - return true; -} - -/// flush accounts db, close savefile and deallocate structures -static void account_db_txt_destroy(AccountDB* self) -{ - AccountDB_TXT* db = (AccountDB_TXT*)self; - DBMap* accounts = db->accounts; - - // stop saving timer - delete_timer(db->save_timer, mmo_auth_sync_timer); - - // write data - mmo_auth_sync(db); - - // delete accounts database - accounts->destroy(accounts, NULL); - db->accounts = NULL; - - // delete entire structure - aFree(db); -} - -/// Gets a property from this database. -static bool account_db_txt_get_property(AccountDB* self, const char* key, char* buf, size_t buflen) -{ - AccountDB_TXT* db = (AccountDB_TXT*)self; - const char* signature = "account.txt."; - - if( strcmp(key, "engine.name") == 0 ) - { - safesnprintf(buf, buflen, "txt"); - return true; - } - if( strcmp(key, "engine.version") == 0 ) - { - safesnprintf(buf, buflen, "%d", ACCOUNT_TXT_DB_VERSION); - return true; - } - if( strcmp(key, "engine.comment") == 0 ) - { - safesnprintf(buf, buflen, "TXT Account Database %d", ACCOUNT_TXT_DB_VERSION); - return true; - } - - if( strncmp(key, signature, strlen(signature)) != 0 ) - return false; - - key += strlen(signature); - - if( strcmpi(key, "account_db") == 0 ) - safesnprintf(buf, buflen, "%s", db->account_db); - else if( strcmpi(key, "case_sensitive") == 0 ) - safesnprintf(buf, buflen, "%d", (db->case_sensitive ? 1 : 0)); - else - return false;// not found - - return true; -} - -/// Sets a property in this database. -static bool account_db_txt_set_property(AccountDB* self, const char* key, const char* value) -{ - AccountDB_TXT* db = (AccountDB_TXT*)self; - const char* signature = "account.txt."; - - if( strncmp(key, signature, strlen(signature)) != 0 ) - return false; - - key += strlen(signature); - - if( strcmpi(key, "account_db") == 0 ) - safestrncpy(db->account_db, value, sizeof(db->account_db)); - else if( strcmpi(key, "case_sensitive") == 0 ) - db->case_sensitive = config_switch(value); - else // no match - return false; - - return true; -} - -/// Add a new entry for this account to the account db and save it. -/// If acc->account_id is -1, the account id will be auto-generated, -/// and its value will be written to acc->account_id if everything succeeds. -static bool account_db_txt_create(AccountDB* self, struct mmo_account* acc) -{ - AccountDB_TXT* db = (AccountDB_TXT*)self; - DBMap* accounts = db->accounts; - struct mmo_account* tmp; - - // decide on the account id to assign - int account_id = ( acc->account_id != -1 ) ? acc->account_id : db->next_account_id; - - // absolute maximum - if( account_id > END_ACCOUNT_NUM ) - return false; - - // check if the account_id is free - tmp = (struct mmo_account*)idb_get(accounts, account_id); - if( tmp != NULL ) - {// error condition - entry already present - ShowError("account_db_txt_create: cannot create account %d:'%s', this id is already occupied by %d:'%s'!\n", account_id, acc->userid, account_id, tmp->userid); - return false; - } - - // copy the data and store it in the db - CREATE(tmp, struct mmo_account, 1); - memcpy(tmp, acc, sizeof(struct mmo_account)); - tmp->account_id = account_id; - idb_put(accounts, account_id, tmp); - - // increment the auto_increment value - if( account_id >= db->next_account_id ) - db->next_account_id = account_id + 1; - - // flush data - mmo_auth_sync(db); - - // write output - acc->account_id = account_id; - - return true; -} - -/// find an existing entry for this account id and delete it -static bool account_db_txt_remove(AccountDB* self, const int account_id) -{ - AccountDB_TXT* db = (AccountDB_TXT*)self; - DBMap* accounts = db->accounts; - - //TODO: find out if this really works - struct mmo_account* tmp = (struct mmo_account*)idb_remove(accounts, account_id); - if( tmp == NULL ) - {// error condition - entry not present - ShowError("account_db_txt_remove: no such account with id %d\n", account_id); - return false; - } - - // flush data - mmo_auth_sync(db); - - return true; -} - -/// rewrite the data stored in the account_db with the one provided -static bool account_db_txt_save(AccountDB* self, const struct mmo_account* acc) -{ - AccountDB_TXT* db = (AccountDB_TXT*)self; - DBMap* accounts = db->accounts; - int account_id = acc->account_id; - - // retrieve previous data - struct mmo_account* tmp = (struct mmo_account*)idb_get(accounts, account_id); - if( tmp == NULL ) - {// error condition - entry not found - return false; - } - - // overwrite with new data - memcpy(tmp, acc, sizeof(struct mmo_account)); - - // modify save counter and save if needed - if( --db->auths_before_save == 0 ) - mmo_auth_sync(db); - - return true; -} - -/// retrieve data from db and store it in the provided data structure -static bool account_db_txt_load_num(AccountDB* self, struct mmo_account* acc, const int account_id) -{ - AccountDB_TXT* db = (AccountDB_TXT*)self; - DBMap* accounts = db->accounts; - - // retrieve data - struct mmo_account* tmp = (struct mmo_account*)idb_get(accounts, account_id); - if( tmp == NULL ) - {// entry not found - return false; - } - - // store it - memcpy(acc, tmp, sizeof(struct mmo_account)); - - return true; -} - -/// retrieve data from db and store it in the provided data structure -static bool account_db_txt_load_str(AccountDB* self, struct mmo_account* acc, const char* userid) -{ - AccountDB_TXT* db = (AccountDB_TXT*)self; - DBMap* accounts = db->accounts; - - // retrieve data - struct DBIterator* iter = accounts->iterator(accounts); - struct mmo_account* tmp; - int (*compare)(const char* str1, const char* str2) = ( db->case_sensitive ) ? strcmp : stricmp; - - for( tmp = (struct mmo_account*)iter->first(iter,NULL); iter->exists(iter); tmp = (struct mmo_account*)iter->next(iter,NULL) ) - if( compare(userid, tmp->userid) == 0 ) - break; - iter->destroy(iter); - - if( tmp == NULL ) - {// entry not found - return false; - } - - // store it - memcpy(acc, tmp, sizeof(struct mmo_account)); - - return true; -} - - -/// Returns a new forward iterator. -static AccountDBIterator* account_db_txt_iterator(AccountDB* self) -{ - AccountDB_TXT* db = (AccountDB_TXT*)self; - DBMap* accounts = db->accounts; - AccountDBIterator_TXT* iter = (AccountDBIterator_TXT*)aCalloc(1, sizeof(AccountDBIterator_TXT)); - - // set up the vtable - iter->vtable.destroy = &account_db_txt_iter_destroy; - iter->vtable.next = &account_db_txt_iter_next; - - // fill data - iter->iter = db_iterator(accounts); - - return &iter->vtable; -} - - -/// Destroys this iterator, releasing all allocated memory (including itself). -static void account_db_txt_iter_destroy(AccountDBIterator* self) -{ - AccountDBIterator_TXT* iter = (AccountDBIterator_TXT*)self; - dbi_destroy(iter->iter); - aFree(iter); -} - - -/// Fetches the next account in the database. -static bool account_db_txt_iter_next(AccountDBIterator* self, struct mmo_account* acc) -{ - AccountDBIterator_TXT* iter = (AccountDBIterator_TXT*)self; - struct mmo_account* tmp = (struct mmo_account*)dbi_next(iter->iter); - if( dbi_exists(iter->iter) ) - { - memcpy(acc, tmp, sizeof(struct mmo_account)); - return true; - } - return false; -} - - -/// parse input string into the provided account data structure -static bool mmo_auth_fromstr(struct mmo_account* a, char* str, unsigned int version) -{ - char* fields[32]; - int count; - char* regs; - int i, n; - - // zero out the destination first - memset(a, 0x00, sizeof(struct mmo_account)); - - // defaults for older format versions - safestrncpy(a->birthdate, "0000-00-00", sizeof(a->birthdate)); - - // extract tab-separated columns from line - count = sv_split(str, strlen(str), 0, '\t', fields, ARRAYLENGTH(fields), (e_svopt)(SV_TERMINATE_LF|SV_TERMINATE_CRLF)); - - if( version == ACCOUNT_TXT_DB_VERSION && count == 14 ) - { - a->account_id = strtol(fields[1], NULL, 10); - safestrncpy(a->userid, fields[2], sizeof(a->userid)); - safestrncpy(a->pass, fields[3], sizeof(a->pass)); - a->sex = fields[4][0]; - safestrncpy(a->email, fields[5], sizeof(a->email)); - a->level = strtoul(fields[6], NULL, 10); - a->state = strtoul(fields[7], NULL, 10); - a->unban_time = strtol(fields[8], NULL, 10); - a->expiration_time = strtol(fields[9], NULL, 10); - a->logincount = strtoul(fields[10], NULL, 10); - safestrncpy(a->lastlogin, fields[11], sizeof(a->lastlogin)); - safestrncpy(a->last_ip, fields[12], sizeof(a->last_ip)); - safestrncpy(a->birthdate, fields[13], sizeof(a->birthdate)); - regs = fields[14]; - } - else - if( version == 20080409 && count == 13 ) - { - a->account_id = strtol(fields[1], NULL, 10); - safestrncpy(a->userid, fields[2], sizeof(a->userid)); - safestrncpy(a->pass, fields[3], sizeof(a->pass)); - a->sex = fields[4][0]; - safestrncpy(a->email, fields[5], sizeof(a->email)); - a->level = strtoul(fields[6], NULL, 10); - a->state = strtoul(fields[7], NULL, 10); - a->unban_time = strtol(fields[8], NULL, 10); - a->expiration_time = strtol(fields[9], NULL, 10); - a->logincount = strtoul(fields[10], NULL, 10); - safestrncpy(a->lastlogin, fields[11], sizeof(a->lastlogin)); - safestrncpy(a->last_ip, fields[12], sizeof(a->last_ip)); - regs = fields[13]; - } - else - if( version == 0 && count == 14 ) - { - a->account_id = strtol(fields[1], NULL, 10); - safestrncpy(a->userid, fields[2], sizeof(a->userid)); - safestrncpy(a->pass, fields[3], sizeof(a->pass)); - safestrncpy(a->lastlogin, fields[4], sizeof(a->lastlogin)); - a->sex = fields[5][0]; - a->logincount = strtoul(fields[6], NULL, 10); - a->state = strtoul(fields[7], NULL, 10); - safestrncpy(a->email, fields[8], sizeof(a->email)); - //safestrncpy(a->error_message, fields[9], sizeof(a->error_message)); - a->expiration_time = strtol(fields[10], NULL, 10); - safestrncpy(a->last_ip, fields[11], sizeof(a->last_ip)); - //safestrncpy(a->memo, fields[12], sizeof(a->memo)); - a->unban_time = strtol(fields[13], NULL, 10); - regs = fields[14]; - } - else - if( version == 0 && count == 13 ) - { - a->account_id = strtol(fields[1], NULL, 10); - safestrncpy(a->userid, fields[2], sizeof(a->userid)); - safestrncpy(a->pass, fields[3], sizeof(a->pass)); - safestrncpy(a->lastlogin, fields[4], sizeof(a->lastlogin)); - a->sex = fields[5][0]; - a->logincount = strtoul(fields[6], NULL, 10); - a->state = strtoul(fields[7], NULL, 10); - safestrncpy(a->email, fields[8], sizeof(a->email)); - //safestrncpy(a->error_message, fields[9], sizeof(a->error_message)); - a->expiration_time = strtol(fields[10], NULL, 10); - safestrncpy(a->last_ip, fields[11], sizeof(a->last_ip)); - //safestrncpy(a->memo, fields[12], sizeof(a->memo)); - regs = fields[13]; - } - else - if( version == 0 && count == 8 ) - { - a->account_id = strtol(fields[1], NULL, 10); - safestrncpy(a->userid, fields[2], sizeof(a->userid)); - safestrncpy(a->pass, fields[3], sizeof(a->pass)); - safestrncpy(a->lastlogin, fields[4], sizeof(a->lastlogin)); - a->sex = fields[5][0]; - a->logincount = strtoul(fields[6], NULL, 10); - a->state = strtoul(fields[7], NULL, 10); - regs = fields[8]; - } - else - {// unmatched row - return false; - } - - // extract account regs - // {reg namereg value}* - n = 0; - for( i = 0; i < ACCOUNT_REG2_NUM; ++i ) - { - char key[32]; - char value[256]; - - regs += n; - - if (sscanf(regs, "%31[^\t,],%255[^\t ] %n", key, value, &n) != 2) - { - // We must check if a str is void. If it's, we can continue to read other REG2. - // Account line will have something like: str2,9 ,9 str3,1 (here, ,9 is not good) - if (regs[0] == ',' && sscanf(regs, ",%[^\t ] %n", value, &n) == 1) { - i--; - continue; - } else - break; - } - - safestrncpy(a->account_reg2[i].str, key, 32); - safestrncpy(a->account_reg2[i].value, value, 256); - } - a->account_reg2_num = i; - - return true; -} - -/// dump the contents of the account data structure into the provided string buffer -static bool mmo_auth_tostr(const struct mmo_account* a, char* str) -{ - int i; - char* str_p = str; - - str_p += sprintf(str_p, "%d\t%s\t%s\t%c\t%s\t%u\t%u\t%ld\t%ld\t%u\t%s\t%s\t%s\t", - a->account_id, a->userid, a->pass, a->sex, a->email, a->level, - a->state, (long)a->unban_time, (long)a->expiration_time, - a->logincount, a->lastlogin, a->last_ip, a->birthdate); - - for( i = 0; i < a->account_reg2_num; ++i ) - if( a->account_reg2[i].str[0] ) - str_p += sprintf(str_p, "%s,%s ", a->account_reg2[i].str, a->account_reg2[i].value); - - return true; -} - -/// dump the entire account db to disk -static void mmo_auth_sync(AccountDB_TXT* db) -{ - int lock; - FILE *fp; - struct DBIterator* iter; - struct mmo_account* acc; - - fp = lock_fopen(db->account_db, &lock); - if( fp == NULL ) - { - return; - } - - fprintf(fp, "%d\n", ACCOUNT_TXT_DB_VERSION); // savefile version - - fprintf(fp, "// Accounts file: here are saved all information about the accounts.\n"); - fprintf(fp, "// Structure: account ID, username, password, sex, email, level, state, unban time, expiration time, # of logins, last login time, last (accepted) login ip, birth date, repeated(register key, register value)\n"); - fprintf(fp, "// where:\n"); - fprintf(fp, "// sex : M or F for normal accounts, S for server accounts\n"); - fprintf(fp, "// level : this account's gm level\n"); - fprintf(fp, "// state : 0: account is ok, 1 to 256: error code of packet 0x006a + 1\n"); - fprintf(fp, "// unban time : 0: no ban, : banned until the date (unix timestamp)\n"); - fprintf(fp, "// expiration time : 0: unlimited account, : account expires on the date (unix timestamp)\n"); - - //TODO: sort? - - iter = db->accounts->iterator(db->accounts); - for( acc = (struct mmo_account*)iter->first(iter,NULL); iter->exists(iter); acc = (struct mmo_account*)iter->next(iter,NULL) ) - { - char buf[2048]; // ought to be big enough ^^ - mmo_auth_tostr(acc, buf); - fprintf(fp, "%s\n", buf); - } - fprintf(fp, "%d\t%%newid%%\n", db->next_account_id); - iter->destroy(iter); - - lock_fclose(fp, db->account_db, &lock); - - // reset save counter - db->auths_before_save = AUTHS_BEFORE_SAVE; -} - -static int mmo_auth_sync_timer(int tid, unsigned int tick, int id, intptr_t data) -{ - AccountDB_TXT* db = (AccountDB_TXT*)data; - - if( db->auths_before_save < AUTHS_BEFORE_SAVE ) - mmo_auth_sync(db); // db was modified, flush it - - return 0; -} diff --git a/src/login/ipban_txt.c b/src/login/ipban_txt.c deleted file mode 100644 index 6fee15c28..000000000 --- a/src/login/ipban_txt.c +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder - -#include "../common/cbasetypes.h" -#include "../common/strlib.h" -#include "login.h" -#include "ipban.h" -#include -#include - -void ipban_init(void) -{ -} - -void ipban_final(void) -{ -} - -bool ipban_check(uint32 ip) -{ - return false; -} - -void ipban_log(uint32 ip) -{ -} - -bool ipban_config_read(const char* key, const char* value) -{ - // login server settings - if( strcmpi(key, "ipban.enable") == 0 ) - login_config.ipban = (bool)config_switch(value); - else - if( strcmpi(key, "ipban.dynamic_pass_failure_ban") == 0 ) - login_config.dynamic_pass_failure_ban = (bool)config_switch(value); - else - if( strcmpi(key, "ipban.dynamic_pass_failure_ban_interval") == 0 ) - login_config.dynamic_pass_failure_ban_interval = atoi(value); - else - if( strcmpi(key, "ipban.dynamic_pass_failure_ban_limit") == 0 ) - login_config.dynamic_pass_failure_ban_limit = atoi(value); - else - if( strcmpi(key, "ipban.dynamic_pass_failure_ban_duration") == 0 ) - login_config.dynamic_pass_failure_ban_duration = atoi(value); - else - return false; - - return true; -} - diff --git a/src/login/login.c b/src/login/login.c index 53f36c270..e2c16eaed 100644 --- a/src/login/login.c +++ b/src/login/login.c @@ -30,12 +30,7 @@ static struct{ AccountDB* (*constructor)(void); AccountDB* db; } account_engines[] = { -#ifdef WITH_TXT - {account_db_txt, NULL}, -#endif -#ifdef WITH_SQL {account_db_sql, NULL}, -#endif #ifdef ACCOUNTDB_ENGINE_0 {ACCOUNTDB_CONSTRUCTOR(ACCOUNTDB_ENGINE_0), NULL}, #endif diff --git a/src/login/loginlog_txt.c b/src/login/loginlog_txt.c deleted file mode 100644 index 76ad08c54..000000000 --- a/src/login/loginlog_txt.c +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder - -#include "../common/cbasetypes.h" -#include "../common/mmo.h" -#include "../common/core.h" -#include "../common/malloc.h" -#include "../common/socket.h" -#include "../common/strlib.h" -#include "../common/showmsg.h" -#include "account.h" -#include "login.h" - -#include -#include -#include - -char login_log_filename[1024] = "log/login.log"; - - -// Returns the number of failed login attemps by the ip in the last minutes. -unsigned long loginlog_failedattempts(uint32 ip, unsigned int minutes) -{ - // XXX not implemented - return 0; -} - - -/*============================================= - * Records an event in the login log - *---------------------------------------------*/ -void login_log(uint32 ip, const char* username, int rcode, const char* message) -{ - FILE* log_fp; - - if( !login_config.log_login ) - return; - - log_fp = fopen(login_log_filename, "a"); - if( log_fp != NULL ) - { - char esc_username[NAME_LENGTH*4+1]; - char esc_message[255*4+1]; - time_t raw_time; - char str_time[24]; - - sv_escape_c(esc_username, username, safestrnlen(username,NAME_LENGTH), NULL); - sv_escape_c(esc_message, message, safestrnlen(message,255), NULL); - - time(&raw_time); - strftime(str_time, 24, login_config.date_format, localtime(&raw_time)); - str_time[23] = '\0'; - - fprintf(log_fp, "%s\t%s\t%s\t%d\t%s\n", str_time, ip2str(ip,NULL), esc_username, rcode, esc_message); - - fclose(log_fp); - } -} - - -bool loginlog_config_read(const char* w1, const char* w2) -{ - if(!strcmpi(w1, "login_log_filename")) - safestrncpy(login_log_filename, w2, sizeof(login_log_filename)); - else - return false; - - return true; -} - - -bool loginlog_init(void) -{ - return true; -} - - -bool loginlog_final(void) -{ - return true; -} diff --git a/src/login/txt/CMakeLists.txt b/src/login/txt/CMakeLists.txt deleted file mode 100644 index 1df5b32a9..000000000 --- a/src/login/txt/CMakeLists.txt +++ /dev/null @@ -1,39 +0,0 @@ - -# -# login txt -# -if( BUILD_TXT_SERVERS ) -message( STATUS "Creating target login-server" ) -set( TXT_LOGIN_HEADERS - "${TXT_LOGIN_SOURCE_DIR}/account.h" - "${TXT_LOGIN_SOURCE_DIR}/ipban.h" - "${TXT_LOGIN_SOURCE_DIR}/login.h" - "${TXT_LOGIN_SOURCE_DIR}/loginlog.h" - ) -set( TXT_LOGIN_SOURCES - "${TXT_LOGIN_SOURCE_DIR}/account_txt.c" - "${TXT_LOGIN_SOURCE_DIR}/ipban_txt.c" - "${TXT_LOGIN_SOURCE_DIR}/login.c" - "${TXT_LOGIN_SOURCE_DIR}/loginlog_txt.c" - ) -set( DEPENDENCIES common_base ) -set( LIBRARIES ${GLOBAL_LIBRARIES} ) -set( INCLUDE_DIRS ${GLOBAL_INCLUDE_DIRS} ) -set( DEFINITIONS "${GLOBAL_DEFINITIONS} -DWITH_TXT" ) -set( SOURCE_FILES ${COMMON_BASE_HEADERS} ${TXT_LOGIN_HEADERS} ${TXT_LOGIN_SOURCES} ) -source_group( common FILES ${COMMON_BASE_HEADERS} ) -source_group( login FILES ${TXT_LOGIN_HEADERS} ${TXT_LOGIN_SOURCES} ) -include_directories( ${INCLUDE_DIRS} ) -add_executable( login-server ${SOURCE_FILES} ) -add_dependencies( login-server ${DEPENDENCIES} ) -target_link_libraries( login-server ${LIBRARIES} ${DEPENDENCIES} ) -set_target_properties( login-server PROPERTIES COMPILE_FLAGS "${DEFINITIONS}" ) -if( INSTALL_COMPONENT_RUNTIME ) - cpack_add_component( Runtime_loginserver_txt DESCRIPTION "login-server (txt version)" DISPLAY_NAME "login-server" GROUP Runtime ) - install( TARGETS login-server - DESTINATION "." - COMPONENT Runtime_loginserver_txt ) -endif( INSTALL_COMPONENT_RUNTIME ) -set( TARGET_LIST ${TARGET_LIST} login-server CACHE INTERNAL "" ) -message( STATUS "Creating target login-server - done" ) -endif( BUILD_TXT_SERVERS ) diff --git a/src/map/CMakeLists.txt b/src/map/CMakeLists.txt index 1d82fc2ca..51c3538ef 100644 --- a/src/map/CMakeLists.txt +++ b/src/map/CMakeLists.txt @@ -3,12 +3,10 @@ # setup # set( MAP_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR} CACHE INTERNAL "" ) -set( TXT_MAP_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR} CACHE INTERNAL "" ) set( SQL_MAP_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR} CACHE INTERNAL "" ) # # targets # -add_subdirectory( txt ) add_subdirectory( sql ) diff --git a/src/map/Makefile.in b/src/map/Makefile.in index 3f64942e0..dc0e48bf9 100644 --- a/src/map/Makefile.in +++ b/src/map/Makefile.in @@ -25,8 +25,6 @@ MAP_OBJ = map.o chrif.o clif.o pc.o status.o npc.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 -MAP_TXT_OBJ = $(MAP_OBJ:%=obj_txt/%) \ - obj_txt/mapreg_txt.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 \ @@ -95,22 +93,18 @@ obj_sql: -mkdir obj_sql # executables -map-server: obj_txt $(MAP_TXT_OBJ) $(COMMON_OBJ) - @CC@ @LDFLAGS@ -o ../../map-server@EXEEXT@ $(MAP_TXT_OBJ) $(COMMON_OBJ) $(MT19937AR_OBJ) @LIBS@ @PCRE_LIBS@ map-server_sql: obj_sql $(MAP_SQL_OBJ) $(COMMON_OBJ) $(COMMON_SQL_OBJ) @CC@ @LDFLAGS@ -o ../../map-server_sql@EXEEXT@ $(MAP_SQL_OBJ) $(COMMON_OBJ) $(COMMON_SQL_OBJ) $(MT19937AR_OBJ) @LIBS@ @PCRE_LIBS@ @MYSQL_LIBS@ # map object files -obj_txt/%.o: %.c $(MAP_H) $(COMMON_H) $(MT19937AR_H) - @CC@ @CFLAGS@ $(MT19937AR_INCLUDE) $(PCRE_CFLAGS) -DTXT_ONLY @CPPFLAGS@ -c $(OUTPUT_OPTION) $< obj_sql/%.o: %.c $(MAP_H) $(COMMON_H) $(COMMON_SQL_H) $(MT19937AR_H) @CC@ @CFLAGS@ $(MT19937AR_INCLUDE) $(PCRE_CFLAGS) @MYSQL_CFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $< # missing object files ../common/obj_all/%.o: - @$(MAKE) -C ../common txt + @$(MAKE) -C ../common sql ../common/obj_sql/%.o: @$(MAKE) -C ../common sql diff --git a/src/map/atcommand.c b/src/map/atcommand.c index ab5d632ff..de5d4549b 100644 --- a/src/map/atcommand.c +++ b/src/map/atcommand.c @@ -30,6 +30,7 @@ #include "npc.h" #include "pet.h" #include "homunculus.h" +#include "mail.h" #include "mercenary.h" #include "party.h" #include "guild.h" @@ -38,9 +39,6 @@ #include "trade.h" #include "unit.h" -#ifndef TXT_ONLY -#include "mail.h" -#endif #include #include @@ -4333,9 +4331,7 @@ ACMD_FUNC(reloadbattleconf) ) { // Exp or Drop rates changed. mob_reload(); //Needed as well so rate changes take effect. -#ifndef TXT_ONLY chrif_ragsrvinfo(battle_config.base_exp_rate, battle_config.job_exp_rate, battle_config.item_rate_common); -#endif } clif_displaymessage(fd, msg_txt(255)); return 0; @@ -7112,9 +7108,7 @@ ACMD_FUNC(misceffect) ACMD_FUNC(mail) { nullpo_ret(sd); -#ifndef TXT_ONLY mail_openmail(sd); -#endif return 0; } @@ -8434,9 +8428,7 @@ ACMD_FUNC(auction) { nullpo_ret(sd); -#ifndef TXT_ONLY clif_Auction_openwindow(sd); -#endif return 0; } diff --git a/src/map/chrif.c b/src/map/chrif.c index ebafdf0da..03b4baeb0 100644 --- a/src/map/chrif.c +++ b/src/map/chrif.c @@ -225,11 +225,7 @@ void chrif_checkdefaultlogin(void) { if (strcmp(userid, "s1")==0 && strcmp(passwd, "p1")==0) { ShowError("Using the default user/password s1/p1 is NOT RECOMMENDED.\n"); -#ifdef TXT_ONLY - ShowNotice("Please edit your save/account.txt file to create a proper inter-server user/password (gender 'S')\n"); -#else ShowNotice("Please edit your 'login' table to create a proper inter-server user/password (gender 'S')\n"); -#endif ShowNotice("and then edit your user/password in conf/map_athena.conf (or conf/import/map_conf.txt)\n"); } } @@ -312,10 +308,8 @@ int chrif_save(struct map_session_data *sd, int flag) merc_save(sd->hd); if( sd->md && mercenary_get_lifetime(sd->md) > 0 ) mercenary_save(sd->md); -#ifndef TXT_ONLY if( sd->save_quest ) intif_quest_save(sd); -#endif return 0; } @@ -1536,16 +1530,12 @@ static int check_connect_char_server(int tid, unsigned int tick, int id, intptr_ chrif_connect(char_fd); chrif_connected = (chrif_state == 2); -#ifndef TXT_ONLY srvinfo = 0; -#endif /* not TXT_ONLY */ } else { -#ifndef TXT_ONLY if (srvinfo == 0) { chrif_ragsrvinfo(battle_config.base_exp_rate, battle_config.job_exp_rate, battle_config.item_rate_common); srvinfo = 1; } -#endif /* not TXT_ONLY */ } if (chrif_isconnected()) displayed = 0; return 0; @@ -1555,7 +1545,7 @@ 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) { -#ifndef TXT_ONLY + chrif_check(-1); WFIFOHEAD(char_fd,10); @@ -1563,7 +1553,7 @@ int chrif_removefriend(int char_id, int friend_id) { WFIFOL(char_fd,2) = char_id; WFIFOL(char_fd,6) = friend_id; WFIFOSET(char_fd,10); -#endif + return 0; } diff --git a/src/map/clif.c b/src/map/clif.c index 48aca796d..e102fc169 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -8137,9 +8137,7 @@ void clif_refresh(struct map_session_data *sd) // unlike vending, resuming buyingstore crashes the client. buyingstore_close(sd); -#ifndef TXT_ONLY mail_clear(sd); -#endif } @@ -9205,9 +9203,7 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd) sd->state.changemap = false; } -#ifndef TXT_ONLY mail_clear(sd); -#endif if(map[sd->bl.m].flag.loadevent) // Lance npc_script_event(sd, NPCE_LOADMAP); @@ -13425,7 +13421,6 @@ void clif_parse_Check(int fd, struct map_session_data *sd) } -#ifndef TXT_ONLY /// MAIL SYSTEM /// By Zephyrus @@ -14205,8 +14200,6 @@ void clif_parse_Auction_buysell(int fd, struct map_session_data* sd) intif_Auction_requestlist(sd->status.char_id, type, 0, "", 1); } -#endif - /// CASH/POINT SHOP /// @@ -16515,7 +16508,6 @@ static int packetdb_readdb(void) {clif_parse_Check,"check"}, {clif_parse_Adopt_request,"adoptrequest"}, {clif_parse_Adopt_reply,"adoptreply"}, -#ifndef TXT_ONLY // MAIL SYSTEM {clif_parse_Mail_refreshinbox,"mailrefresh"}, {clif_parse_Mail_read,"mailread"}, @@ -16536,7 +16528,6 @@ static int packetdb_readdb(void) {clif_parse_Auction_bid,"auctionbid"}, // Quest Log System {clif_parse_questStateAck,"queststate"}, -#endif {clif_parse_cashshop_buy,"cashshopbuy"}, {clif_parse_ViewPlayerEquip,"viewplayerequip"}, {clif_parse_EquipTick,"equiptickbox"}, diff --git a/src/map/clif.h b/src/map/clif.h index efe85cefc..206b7d68e 100644 --- a/src/map/clif.h +++ b/src/map/clif.h @@ -641,7 +641,6 @@ void clif_displayexp(struct map_session_data *sd, unsigned int exp, char type, b int clif_send(const uint8* buf, int len, struct block_list* bl, enum send_target type); int do_init_clif(void); -#ifndef TXT_ONLY // MAIL SYSTEM void clif_Mail_window(int fd, int flag); void clif_Mail_read(struct map_session_data *sd, int mail_id); @@ -657,7 +656,6 @@ void clif_Auction_results(struct map_session_data *sd, short count, short pages, void clif_Auction_message(int fd, unsigned char flag); void clif_Auction_close(int fd, unsigned char flag); void clif_parse_Auction_cancelreg(int fd, struct map_session_data *sd); -#endif void clif_bossmapinfo(int fd, struct mob_data *md, short flag); void clif_cashshop_show(struct map_session_data *sd, struct npc_data *nd); diff --git a/src/map/intif.c b/src/map/intif.c index 20623a146..51002f027 100644 --- a/src/map/intif.c +++ b/src/map/intif.c @@ -1412,8 +1412,6 @@ int intif_quest_save(TBL_PC *sd) return 0; } -#ifndef TXT_ONLY - /*========================================== * MAIL SYSTEM * By Zephyrus @@ -1888,8 +1886,6 @@ static void intif_parse_Auction_message(int fd) clif_Auction_message(sd->fd, result); } -#endif - /*========================================== * Mercenary's System *------------------------------------------*/ @@ -2049,7 +2045,6 @@ int intif_parse(int fd) case 0x3860: intif_parse_questlog(fd); break; case 0x3861: intif_parse_questsave(fd); break; -#ifndef TXT_ONLY // Mail System case 0x3848: intif_parse_Mail_inboxreceived(fd); break; case 0x3849: intif_parse_Mail_new(fd); break; @@ -2064,7 +2059,7 @@ int intif_parse(int fd) case 0x3853: intif_parse_Auction_close(fd); break; case 0x3854: intif_parse_Auction_message(fd); break; case 0x3855: intif_parse_Auction_bid(fd); break; -#endif + // Mercenary System case 0x3870: intif_parse_mercenary_received(fd); break; case 0x3871: intif_parse_mercenary_deleted(fd); break; diff --git a/src/map/intif.h b/src/map/intif.h index 1df990108..88e1f1ce7 100644 --- a/src/map/intif.h +++ b/src/map/intif.h @@ -83,7 +83,6 @@ 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); -#ifndef TXT_ONLY // MAIL SYSTEM int intif_Mail_requestinbox(int char_id, unsigned char flag); int intif_Mail_read(int mail_id); @@ -97,7 +96,6 @@ 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); -#endif int CheckForCharServer(void); diff --git a/src/map/itemdb.c b/src/map/itemdb.c index 3c2e75810..8043c965d 100644 --- a/src/map/itemdb.c +++ b/src/map/itemdb.c @@ -984,7 +984,6 @@ static int itemdb_readdb(void) return 0; } -#ifndef TXT_ONLY /*====================================== * item_db table reading *======================================*/ @@ -1034,18 +1033,15 @@ static int itemdb_read_sqldb(void) return 0; } -#endif /* not TXT_ONLY */ /*==================================== * read all item-related databases *------------------------------------*/ static void itemdb_read(void) { -#ifndef TXT_ONLY if (db_use_sqldbs) itemdb_read_sqldb(); else -#endif itemdb_readdb(); itemdb_read_itemgroup(); diff --git a/src/map/log.c b/src/map/log.c index fb1aa11a1..76497db3c 100644 --- a/src/map/log.c +++ b/src/map/log.c @@ -136,7 +136,6 @@ void log_branch(struct map_session_data* sd) if( !log_config.branch ) return; -#ifndef TXT_ONLY if( log_config.sql_logs ) { SqlStmt* stmt; @@ -152,7 +151,6 @@ void log_branch(struct map_session_data* sd) SqlStmt_Free(stmt); } else -#endif { char timestring[255]; time_t curtime; @@ -179,7 +177,6 @@ void log_pick(int id, int m, e_log_pick_type type, int amount, struct item* itm) if( !should_log_item(itm->nameid, amount, itm->refine) ) return; //we skip logging this item set - it doesn't meet our logging conditions [Lupus] -#ifndef TXT_ONLY if( log_config.sql_logs ) { if( SQL_ERROR == Sql_Query(logmysql_handle, LOG_QUERY " INTO `%s` (`time`, `char_id`, `type`, `nameid`, `amount`, `refine`, `card0`, `card1`, `card2`, `card3`, `map`) VALUES (NOW(), '%d', '%c', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%s')", @@ -190,7 +187,6 @@ void log_pick(int id, int m, e_log_pick_type type, int amount, struct item* itm) } } else -#endif { char timestring[255]; time_t curtime; @@ -228,7 +224,6 @@ void log_zeny(struct map_session_data* sd, e_log_pick_type type, struct map_sess if( !log_config.zeny || ( log_config.zeny != 1 && abs(amount) < log_config.zeny ) ) return; -#ifndef TXT_ONLY if( log_config.sql_logs ) { 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')", @@ -239,7 +234,6 @@ void log_zeny(struct map_session_data* sd, e_log_pick_type type, struct map_sess } } else -#endif { char timestring[255]; time_t curtime; @@ -263,7 +257,6 @@ void log_mvpdrop(struct map_session_data* sd, int monster_id, int* log_mvp) if( !log_config.mvpdrop ) return; -#ifndef TXT_ONLY if( log_config.sql_logs ) { 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') ", @@ -274,7 +267,6 @@ void log_mvpdrop(struct map_session_data* sd, int monster_id, int* log_mvp) } } else -#endif { char timestring[255]; time_t curtime; @@ -298,7 +290,6 @@ void log_atcommand(struct map_session_data* sd, int cmdlvl, const char* message) if( cmdlvl < log_config.gm ) return; -#ifndef TXT_ONLY if( log_config.sql_logs ) { SqlStmt* stmt; @@ -316,7 +307,6 @@ void log_atcommand(struct map_session_data* sd, int cmdlvl, const char* message) SqlStmt_Free(stmt); } else -#endif { char timestring[255]; time_t curtime; @@ -340,7 +330,6 @@ void log_npc(struct map_session_data* sd, const char* message) if( !log_config.npc ) return; -#ifndef TXT_ONLY if( log_config.sql_logs ) { SqlStmt* stmt; @@ -357,7 +346,6 @@ void log_npc(struct map_session_data* sd, const char* message) SqlStmt_Free(stmt); } else -#endif { char timestring[255]; time_t curtime; @@ -386,7 +374,6 @@ void log_chat(e_log_chat_type type, int type_id, int src_charid, int src_accid, return; } -#ifndef TXT_ONLY if( log_config.sql_logs ) { SqlStmt* stmt; @@ -404,7 +391,6 @@ void log_chat(e_log_chat_type type, int type_id, int src_charid, int src_accid, SqlStmt_Free(stmt); } else -#endif { char timestring[255]; time_t curtime; @@ -457,16 +443,7 @@ int log_config_read(const char* cfgName) if( strcmpi(w1, "enable_logs") == 0 ) log_config.enable_logs = (e_log_pick_type)config_switch(w2); else if( strcmpi(w1, "sql_logs") == 0 ) - { log_config.sql_logs = (bool)config_switch(w2); -#ifdef TXT_ONLY - if( log_config.sql_logs ) - { - ShowWarning("log_config_read: SQL logging is not supported on this server.\n"); - log_config.sql_logs = false; - } -#endif - } //start of common filter settings else if( strcmpi(w1, "rare_items_log") == 0 ) log_config.rare_items_log = atoi(w2); diff --git a/src/map/mail.c b/src/map/mail.c index d410faf28..bb1063fbf 100644 --- a/src/map/mail.c +++ b/src/map/mail.c @@ -1,8 +1,6 @@ // Copyright (c) Athena Dev Teams - Licensed under GNU GPL // For more information, see LICENCE in the main folder -#ifndef TXT_ONLY - #include "../common/nullpo.h" #include "../common/showmsg.h" @@ -194,5 +192,3 @@ bool mail_invalid_operation(struct map_session_data *sd) return false; } - -#endif diff --git a/src/map/map.c b/src/map/map.c index fee813241..841e95df1 100644 --- a/src/map/map.c +++ b/src/map/map.c @@ -44,9 +44,7 @@ #include "mercenary.h" #include "atcommand.h" #include "log.h" -#ifndef TXT_ONLY #include "mail.h" -#endif #include #include #include @@ -56,7 +54,6 @@ #include #endif -#ifndef TXT_ONLY char default_codepage[32] = ""; int map_server_port = 3306; @@ -83,8 +80,6 @@ char log_db_pw[32] = "ragnarok"; char log_db_db[32] = "log"; Sql* logmysql_handle; -#endif /* not TXT_ONLY */ - // This param using for sending mainchat // messages like whispers to this nick. [LuzZza] char main_chat_nick[16] = "Main"; @@ -3240,8 +3235,6 @@ int inter_config_read(char *cfgName) if(strcmpi(w1, "main_chat_nick")==0) safestrncpy(main_chat_nick, w2, sizeof(main_chat_nick)); - - #ifndef TXT_ONLY else if(strcmpi(w1,"item_db_db")==0) strcpy(item_db_db,w2); @@ -3295,7 +3288,6 @@ int inter_config_read(char *cfgName) else if(strcmpi(w1,"log_db_db")==0) strcpy(log_db_db, w2); - #endif else if( mapreg_config_read(w1,w2) ) continue; @@ -3309,7 +3301,6 @@ int inter_config_read(char *cfgName) return 0; } -#ifndef TXT_ONLY /*======================================= * MySQL Init *---------------------------------------*/ @@ -3363,8 +3354,6 @@ int log_sql_init(void) return 0; } -#endif /* not TXT_ONLY */ - int map_db_final(DBKey k,void *d,va_list ap) { struct map_data_other_server *mdos = (struct map_data_other_server*)d; @@ -3498,9 +3487,8 @@ void do_final(void) iwall_db->destroy(iwall_db, NULL); regen_db->destroy(regen_db, NULL); -#ifndef TXT_ONLY map_sql_close(); -#endif /* not TXT_ONLY */ + ShowStatus("Finished.\n"); } @@ -3762,11 +3750,9 @@ int do_init(int argc, char *argv[]) iwall_db = strdb_alloc(DB_OPT_RELEASE_DATA,2*NAME_LENGTH+2+1); // [Zephyrus] Invisible Walls -#ifndef TXT_ONLY map_sql_init(); if (log_config.sql_logs) log_sql_init(); -#endif /* not TXT_ONLY */ mapindex_init(); if(enable_grf) diff --git a/src/map/map.h b/src/map/map.h index afd7aa883..2dece688d 100644 --- a/src/map/map.h +++ b/src/map/map.h @@ -709,8 +709,6 @@ typedef struct mercenary_data TBL_MER; extern char main_chat_nick[16]; -#ifndef TXT_ONLY - #include "../common/sql.h" extern int db_use_sqldbs; @@ -726,8 +724,6 @@ extern char mob_db2_db[32]; extern char mob_skill_db_db[32]; extern char mob_skill_db2_db[32]; -#endif /* not TXT_ONLY */ - void do_shutdown(void); #endif /* _MAP_H_ */ diff --git a/src/map/mapreg_txt.c b/src/map/mapreg_txt.c deleted file mode 100644 index 95be201e2..000000000 --- a/src/map/mapreg_txt.c +++ /dev/null @@ -1,202 +0,0 @@ -// Copyright (c) Athena Dev Teams - Licensed under GNU GPL -// For more information, see LICENCE in the main folder - -#include "../common/cbasetypes.h" -#include "../common/db.h" -#include "../common/lock.h" -#include "../common/malloc.h" -#include "../common/showmsg.h" -#include "../common/strlib.h" -#include "../common/timer.h" -#include "script.h" -#include -#include -#include - -static DBMap* mapreg_db = NULL; // int var_id -> int value -static DBMap* mapregstr_db = NULL; // int var_id -> char* value - -static char mapreg_txt[256] = "save/mapreg.txt"; -static bool mapreg_dirty = false; -#define MAPREG_AUTOSAVE_INTERVAL (300*1000) - - -/// Looks up the value of an integer variable using its uid. -int mapreg_readreg(int uid) -{ - return (int)idb_get(mapreg_db, uid); -} - -/// Looks up the value of a string variable using its uid. -char* mapreg_readregstr(int uid) -{ - return (char*)idb_get(mapregstr_db, uid); -} - -/// Modifies the value of an integer variable. -bool mapreg_setreg(int uid, int val) -{ - if( val != 0 ) - idb_put(mapreg_db,uid,(void*)val); - else - idb_remove(mapreg_db,uid); - - mapreg_dirty = true; - return true; -} - -/// Modifies the value of a string variable. -bool mapreg_setregstr(int uid, const char* str) -{ - if( str == NULL || *str == 0 ) - idb_remove(mapregstr_db,uid); - else - idb_put(mapregstr_db,uid,aStrdup(str)); - - mapreg_dirty = true; - return true; -} - -/// Loads permanent variables from savefile -static void script_load_mapreg(void) -{ - FILE* fp; - char line[1024]; - - fp = fopen(mapreg_txt,"rt"); - if( fp == NULL ) - return; - - while( fgets(line,sizeof(line),fp) ) - { - char varname[32+1]; - char value[255+1]; - int n,s,i; - - // read name and index - if( sscanf(line, "%32[^,],%d\t%n", varname,&i,&n) != 2 && - (i = 0, sscanf(line,"%[^\t]\t%n", varname,&n) != 1) ) - continue; - - // read value - if( sscanf(line + n, "%[^\n\r]", value) != 1 ) - { - ShowError("%s: %s broken data !\n", mapreg_txt, varname); - continue; - } - - s = add_str(varname); - if( varname[strlen(varname)-1] == '$' ) - idb_put(mapregstr_db, (i<<24)|s, aStrdup(value)); - else - idb_put(mapreg_db, (i<<24)|s, (void*)atoi(value)); - } - fclose(fp); - - mapreg_dirty = false; -} - -/// Saves permanent variables to savefile -static void script_save_mapreg(void) -{ - FILE *fp; - int lock; - DBIterator* iter; - void* data; - DBKey key; - - fp = lock_fopen(mapreg_txt,&lock); - if( fp == NULL ) - { - ShowError("script_save_mapreg: Unable to lock-open file [%s]!\n", mapreg_txt); - return; - } - - iter = mapreg_db->iterator(mapreg_db); - for( data = iter->first(iter,&key); iter->exists(iter); data = iter->next(iter,&key) ) - { - int num = (key.i & 0x00ffffff); - int i = (key.i & 0xff000000) >> 24; - const char* name = get_str(num); - - if( name[1] == '@' ) - continue; - - if( i == 0 ) - fprintf(fp, "%s\t%d\n", name, (int)data); - else - fprintf(fp, "%s,%d\t%d\n", name, i, (int)data); - } - iter->destroy(iter); - - iter = mapregstr_db->iterator(mapregstr_db); - for( data = iter->first(iter,&key); iter->exists(iter); data = iter->next(iter,&key) ) - { - int num = (key.i & 0x00ffffff); - int i = (key.i & 0xff000000) >> 24; - const char* name = get_str(num); - - if( name[1] == '@' ) - continue; - - if( i == 0 ) - fprintf(fp, "%s\t%s\n", name, (char *)data); - else - fprintf(fp, "%s,%d\t%s\n", name, i, (char *)data); - } - iter->destroy(iter); - - lock_fclose(fp,mapreg_txt,&lock); - - mapreg_dirty = false; -} - -static int script_autosave_mapreg(int tid, unsigned int tick, int id, intptr_t data) -{ - if( mapreg_dirty ) - script_save_mapreg(); - - return 0; -} - - -void mapreg_reload(void) -{ - if( mapreg_dirty ) - script_save_mapreg(); - - mapreg_db->clear(mapreg_db, NULL); - mapregstr_db->clear(mapregstr_db, NULL); - - script_load_mapreg(); -} - -void mapreg_final(void) -{ - if( mapreg_dirty ) - script_save_mapreg(); - - mapreg_db->destroy(mapreg_db,NULL); - mapregstr_db->destroy(mapregstr_db,NULL); -} - -void mapreg_init(void) -{ - mapreg_db = idb_alloc(DB_OPT_BASE); - mapregstr_db = idb_alloc(DB_OPT_RELEASE_DATA); - - script_load_mapreg(); - - add_timer_func_list(script_autosave_mapreg, "script_autosave_mapreg"); - add_timer_interval(gettick() + MAPREG_AUTOSAVE_INTERVAL, script_autosave_mapreg, 0, 0, MAPREG_AUTOSAVE_INTERVAL); -} - -bool mapreg_config_read(const char* w1, const char* w2) -{ - if(!strcmpi(w1, "mapreg_txt")) - safestrncpy(mapreg_txt, w2, sizeof(mapreg_txt)); - else - return false; - - return true; -} diff --git a/src/map/mob.c b/src/map/mob.c index 6f0bd859d..acdfd5049 100644 --- a/src/map/mob.c +++ b/src/map/mob.c @@ -3719,7 +3719,6 @@ static void mob_readdb(void) } } -#ifndef TXT_ONLY /*========================================== * mob_db table reading *------------------------------------------*/ @@ -3774,7 +3773,6 @@ static int mob_read_sqldb(void) } return 0; } -#endif /* not TXT_ONLY */ /*========================================== * MOB display graphic change data reading @@ -4301,7 +4299,6 @@ static void mob_readskilldb(void) { } } -#ifndef TXT_ONLY /** * mob_skill_db table reading [CalciumKid] * not overly sure if this is all correct @@ -4358,7 +4355,6 @@ static int mob_read_sqlskilldb(void) } return 0; } -#endif /* not TXT_ONLY */ /*========================================== * mob_race2_db.txt reading @@ -4393,14 +4389,12 @@ static bool mob_readdb_race2(char* fields[], int columns, int current) */ static void mob_load(void) { -#ifndef TXT_ONLY if (db_use_sqldbs) { mob_read_sqldb(); mob_read_sqlskilldb(); } else -#endif { mob_readdb(); mob_readskilldb(); diff --git a/src/map/pc.c b/src/map/pc.c index 17a695fff..3155484dd 100644 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -1188,10 +1188,8 @@ int pc_reg_received(struct map_session_data *sd) status_calc_pc(sd,1); chrif_scdata_request(sd->status.account_id, sd->status.char_id); -#ifndef TXT_ONLY intif_Mail_requestinbox(sd->status.char_id, 0); // MAIL SYSTEM - Request Mail Inbox intif_request_questlog(sd); -#endif if (sd->state.connect_new == 0 && sd->fd) { //Character already loaded map! Gotta trigger LoadEndAck manually. @@ -1199,9 +1197,8 @@ int pc_reg_received(struct map_session_data *sd) clif_parse_LoadEndAck(sd->fd, sd); } -#ifndef TXT_ONLY pc_inventory_rentals(sd); -#endif + return 1; } @@ -7962,15 +7959,10 @@ int pc_divorce(struct map_session_data *sd) if( (p_sd = map_charid2sd(sd->status.partner_id)) == NULL ) { // Lets char server do the divorce -#ifndef TXT_ONLY if( chrif_divorce(sd->status.char_id, sd->status.partner_id) ) return -1; // No char server connected return 0; -#else - ShowError("pc_divorce: p_sd nullpo\n"); - return -1; -#endif } // Both players online, lets do the divorce manually diff --git a/src/map/script.c b/src/map/script.c index c06a69a60..d9f2bc2e0 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -13543,7 +13543,6 @@ BUILDIN_FUNC(setd) return 0; } -#ifndef TXT_ONLY int buildin_query_sql_sub(struct script_state* st, Sql* handle) { int i, j; @@ -13643,22 +13642,14 @@ int buildin_query_sql_sub(struct script_state* st, Sql* handle) script_pushint(st, i); return 0; } -#endif BUILDIN_FUNC(query_sql) { -#ifndef TXT_ONLY return buildin_query_sql_sub(st, mmysql_handle); -#else - //for TXT version, we always return -1 - script_pushint(st,-1); - return 0; -#endif } BUILDIN_FUNC(query_logsql) { -#ifndef TXT_ONLY if( !log_config.sql_logs ) {// logmysql_handle == NULL ShowWarning("buildin_query_logsql: SQL logs are disabled, query '%s' will not be executed.\n", script_getstr(st,2)); @@ -13667,11 +13658,6 @@ BUILDIN_FUNC(query_logsql) } return buildin_query_sql_sub(st, logmysql_handle); -#else - //for TXT version, we always return -1 - script_pushint(st,-1); - return 0; -#endif } //Allows escaping of a given string. @@ -13684,11 +13670,7 @@ BUILDIN_FUNC(escape_sql) str = script_getstr(st,2); len = strlen(str); esc_str = (char*)aMallocA(len*2+1); -#if defined(TXT_ONLY) - jstrescapecpy(esc_str, str); -#else Sql_EscapeStringLen(mmysql_handle, esc_str, str, len); -#endif script_pushstr(st, esc_str); return 0; } @@ -14709,9 +14691,8 @@ BUILDIN_FUNC(openmail) if( sd == NULL ) return 0; -#ifndef TXT_ONLY mail_openmail(sd); -#endif + return 0; } @@ -14723,9 +14704,8 @@ BUILDIN_FUNC(openauction) if( sd == NULL ) return 0; -#ifndef TXT_ONLY clif_Auction_openwindow(sd); -#endif + return 0; } @@ -14778,7 +14758,6 @@ BUILDIN_FUNC(setcell) *------------------------------------------*/ BUILDIN_FUNC(mercenary_create) { -#ifndef TXT_ONLY struct map_session_data *sd; int class_, contract_time; @@ -14792,7 +14771,6 @@ BUILDIN_FUNC(mercenary_create) contract_time = script_getnum(st,3); merc_create(sd, class_, contract_time); -#endif return 0; } diff --git a/src/map/txt/CMakeLists.txt b/src/map/txt/CMakeLists.txt deleted file mode 100644 index b2634000a..000000000 --- a/src/map/txt/CMakeLists.txt +++ /dev/null @@ -1,108 +0,0 @@ - -# -# map txt -# -if( BUILD_TXT_SERVERS ) -message( STATUS "Creating target map-server" ) -set( TXT_MAP_HEADERS - "${TXT_MAP_SOURCE_DIR}/atcommand.h" - "${TXT_MAP_SOURCE_DIR}/battle.h" - "${TXT_MAP_SOURCE_DIR}/battleground.h" - "${TXT_MAP_SOURCE_DIR}/buyingstore.h" - "${TXT_MAP_SOURCE_DIR}/chat.h" - "${TXT_MAP_SOURCE_DIR}/chrif.h" - "${TXT_MAP_SOURCE_DIR}/clif.h" - "${TXT_MAP_SOURCE_DIR}/date.h" - "${TXT_MAP_SOURCE_DIR}/duel.h" - "${TXT_MAP_SOURCE_DIR}/guild.h" - "${TXT_MAP_SOURCE_DIR}/homunculus.h" - "${TXT_MAP_SOURCE_DIR}/instance.h" - "${TXT_MAP_SOURCE_DIR}/intif.h" - "${TXT_MAP_SOURCE_DIR}/itemdb.h" - "${TXT_MAP_SOURCE_DIR}/log.h" - "${TXT_MAP_SOURCE_DIR}/mail.h" - "${TXT_MAP_SOURCE_DIR}/map.h" - "${TXT_MAP_SOURCE_DIR}/mapreg.h" - "${TXT_MAP_SOURCE_DIR}/mercenary.h" - "${TXT_MAP_SOURCE_DIR}/mob.h" - "${TXT_MAP_SOURCE_DIR}/npc.h" - "${TXT_MAP_SOURCE_DIR}/party.h" - "${TXT_MAP_SOURCE_DIR}/path.h" - "${TXT_MAP_SOURCE_DIR}/pc.h" - "${TXT_MAP_SOURCE_DIR}/pet.h" - "${TXT_MAP_SOURCE_DIR}/quest.h" - "${TXT_MAP_SOURCE_DIR}/script.h" - "${TXT_MAP_SOURCE_DIR}/searchstore.h" - "${TXT_MAP_SOURCE_DIR}/skill.h" - "${TXT_MAP_SOURCE_DIR}/status.h" - "${TXT_MAP_SOURCE_DIR}/storage.h" - "${TXT_MAP_SOURCE_DIR}/trade.h" - "${TXT_MAP_SOURCE_DIR}/unit.h" - "${TXT_MAP_SOURCE_DIR}/vending.h" - ) -set( TXT_MAP_SOURCES - "${TXT_MAP_SOURCE_DIR}/atcommand.c" - "${TXT_MAP_SOURCE_DIR}/battle.c" - "${TXT_MAP_SOURCE_DIR}/battleground.c" - "${TXT_MAP_SOURCE_DIR}/buyingstore.c" - "${TXT_MAP_SOURCE_DIR}/chat.c" - "${TXT_MAP_SOURCE_DIR}/chrif.c" - "${TXT_MAP_SOURCE_DIR}/clif.c" - "${TXT_MAP_SOURCE_DIR}/date.c" - "${TXT_MAP_SOURCE_DIR}/duel.c" - "${TXT_MAP_SOURCE_DIR}/guild.c" - "${TXT_MAP_SOURCE_DIR}/homunculus.c" - "${TXT_MAP_SOURCE_DIR}/instance.c" - "${TXT_MAP_SOURCE_DIR}/intif.c" - "${TXT_MAP_SOURCE_DIR}/itemdb.c" - "${TXT_MAP_SOURCE_DIR}/log.c" - "${TXT_MAP_SOURCE_DIR}/mail.c" - "${TXT_MAP_SOURCE_DIR}/map.c" - "${TXT_MAP_SOURCE_DIR}/mapreg_txt.c" - "${TXT_MAP_SOURCE_DIR}/mercenary.c" - "${TXT_MAP_SOURCE_DIR}/mob.c" - "${TXT_MAP_SOURCE_DIR}/npc.c" - "${TXT_MAP_SOURCE_DIR}/npc_chat.c" - "${TXT_MAP_SOURCE_DIR}/party.c" - "${TXT_MAP_SOURCE_DIR}/path.c" - "${TXT_MAP_SOURCE_DIR}/pc.c" - "${TXT_MAP_SOURCE_DIR}/pet.c" - "${TXT_MAP_SOURCE_DIR}/quest.c" - "${TXT_MAP_SOURCE_DIR}/script.c" - "${TXT_MAP_SOURCE_DIR}/searchstore.c" - "${TXT_MAP_SOURCE_DIR}/skill.c" - "${TXT_MAP_SOURCE_DIR}/status.c" - "${TXT_MAP_SOURCE_DIR}/storage.c" - "${TXT_MAP_SOURCE_DIR}/trade.c" - "${TXT_MAP_SOURCE_DIR}/unit.c" - "${TXT_MAP_SOURCE_DIR}/vending.c" - ) -set( DEPENDENCIES common_base ) -set( LIBRARIES ${GLOBAL_LIBRARIES} ) -set( INCLUDE_DIRS ${GLOBAL_INCLUDE_DIRS} ) -set( DEFINITIONS "${GLOBAL_DEFINITIONS} -DTXT_ONLY" ) -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} ${TXT_MAP_HEADERS} ${TXT_MAP_SOURCES} ) -source_group( common FILES ${COMMON_BASE_HEADERS} ) -source_group( map FILES ${TXT_MAP_HEADERS} ${TXT_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_txt DESCRIPTION "map-server (txt version)" DISPLAY_NAME "map-server" GROUP Runtime ) - install( TARGETS map-server - DESTINATION "." - COMPONENT Runtime_mapserver_txt ) -endif( INSTALL_COMPONENT_RUNTIME ) -set( TARGET_LIST ${TARGET_LIST} map-server CACHE INTERNAL "" ) -message( STATUS "Creating target map-server - done" ) -endif( BUILD_TXT_SERVERS ) diff --git a/src/txt-converter/CMakeLists.txt b/src/txt-converter/CMakeLists.txt deleted file mode 100644 index 7b1cfb6a8..000000000 --- a/src/txt-converter/CMakeLists.txt +++ /dev/null @@ -1,17 +0,0 @@ - -# -# setup -# -set( CONVERTER_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR} CACHE INTERNAL "" ) -if( WITH_MYSQL ) - option( BUILD_CONVERTERS "build converter executables" OFF ) -else() - message( STATUS "Disabled converter targets (requires MYSQL)" ) -endif() - - -# -# targets -# -add_subdirectory( login ) -add_subdirectory( char ) diff --git a/src/txt-converter/Makefile.in b/src/txt-converter/Makefile.in deleted file mode 100644 index 50e89e34e..000000000 --- a/src/txt-converter/Makefile.in +++ /dev/null @@ -1,150 +0,0 @@ -LOGIN_CONVERTER_OBJ = \ - obj_login/login-converter.o \ - ../login/obj_txt/account_txt.o \ - ../login/obj_sql/account_sql.o \ - ../common/obj_all/minicore.o \ - ../common/obj_all/db.o \ - ../common/obj_all/ers.o \ - ../common/obj_all/lock.o \ - ../common/obj_all/malloc.o \ - ../common/obj_all/showmsg.o \ - ../common/obj_all/strlib.o \ - ../common/obj_all/timer.o \ - ../common/obj_all/utils.o \ - ../common/obj_sql/sql.o -LOGIN_CONVERTER_H = \ - ../login/account.h \ - ../common/cbasetypes.h \ - ../common/mmo.h \ - ../common/core.h \ - ../common/db.h \ - ../common/ers.h \ - ../common/lock.h \ - ../common/malloc.h \ - ../common/showmsg.h \ - ../common/strlib.h \ - ../common/timer.h \ - ../common/utils.h \ - ../common/sql.h - -CHAR_CONVERTER_OBJ = \ - obj_char/char-converter.o \ - obj_char/txt-char.o \ - obj_char/txt-int_pet.o \ - obj_char/txt-int_storage.o \ - obj_char/txt-inter.o \ - obj_char/txt-int_party.o \ - obj_char/txt-int_guild.o \ - obj_char/sql-char.o \ - obj_char/sql-int_pet.o \ - obj_char/sql-int_storage.o \ - obj_char/sql-inter.o \ - obj_char/sql-int_party.o \ - obj_char/sql-int_guild.o \ - obj_char/sql-int_mercenary.o \ - ../common/obj_all/minicore.o \ - ../common/obj_all/malloc.o \ - ../common/obj_all/strlib.o \ - ../common/obj_all/showmsg.o \ - ../common/obj_all/utils.o \ - ../common/obj_all/timer.o \ - ../common/obj_all/ers.o \ - ../common/obj_all/mapindex.o \ - ../common/obj_sql/sql.o - -CHAR_CONVERTER_H = \ - ../char/char.h \ - ../char/int_pet.h \ - ../char/int_storage.h \ - ../char/inter.h \ - ../char/int_party.h \ - ../char/int_guild.h \ - ../char_sql/char.h \ - ../char_sql/int_pet.h \ - ../char_sql/int_storage.h \ - ../char_sql/inter.h \ - ../char_sql/int_party.h \ - ../char_sql/int_guild.h \ - ../char_sql/int_mercenary.h \ - ../common/cbasetypes.h \ - ../common/mmo.h \ - ../common/core.h \ - ../common/malloc.h \ - ../common/strlib.h \ - ../common/showmsg.h \ - ../common/timer.h \ - ../common/utils.h \ - ../common/ers.h \ - ../common/mapindex.h \ - ../common/sql.h - -HAVE_MYSQL=@HAVE_MYSQL@ -ifeq ($(HAVE_MYSQL),yes) - LOGIN_CONVERTER_DEPENDS=obj_login $(LOGIN_CONVERTER_OBJ) - CHAR_CONVERTER_DEPENDS=obj_char $(CHAR_CONVERTER_OBJ) -else - LOGIN_CONVERTER_DEPENDS=needs_mysql - CHAR_CONVERTER_DEPENDS=needs_mysql -endif - -@SET_MAKE@ - -##################################################################### -.PHONY : all login-converter char-converter clean help - -all: login-converter char-converter - -login-converter: $(LOGIN_CONVERTER_DEPENDS) - @CC@ @LDFLAGS@ -o ../../tools/login-converter@EXEEXT@ $(LOGIN_CONVERTER_OBJ) @LIBS@ @MYSQL_LIBS@ - -char-converter: $(CHAR_CONVERTER_DEPENDS) - @CC@ @LDFLAGS@ -o ../../tools/char-converter@EXEEXT@ $(CHAR_CONVERTER_OBJ) @LIBS@ @MYSQL_LIBS@ - -clean: - rm -rf *.o obj_login obj_char ../../tools/login-converter@EXEEXT@ ../../tools/char-converter@EXEEXT@ - -help: - @echo "possible targets are 'login-converter' 'char-converter' 'all' 'clean' 'help'" - @echo "'login-converter' - login server converter" - @echo "'char-converter' - char server converter" - @echo "'all' - builds all above targets" - @echo "'clean' - cleans builds and objects" - @echo "'help' - outputs this message" - -##################################################################### - -needs_mysql: - @echo "MySQL not found or disabled by the configure script" - @exit 1 - -obj_login: - -mkdir obj_login - -obj_char: - -mkdir obj_char - -obj_login/%.o: %.c $(LOGIN_CONVERTER_H) - @CC@ @CFLAGS@ @MYSQL_CFLAGS@ @CPPFLAGS@ -DWITH_TXT -DWITH_SQL -c $(OUTPUT_OPTION) $< - -obj_char/%.o: %.c $(CHAR_CONVERTER_H) - @CC@ @CFLAGS@ @MYSQL_CFLAGS@ @CPPFLAGS@ -DTXT_SQL_CONVERT -c $(OUTPUT_OPTION) $< - -obj_char/txt-%.o: ../char/%.c $(CHAR_CONVERTER_H) - @CC@ @CFLAGS@ @MYSQL_CFLAGS@ @CPPFLAGS@ -DTXT_SQL_CONVERT -c $(OUTPUT_OPTION) $< - -obj_char/sql-%.o: ../char_sql/%.c $(CHAR_CONVERTER_H) - @CC@ @CFLAGS@ @MYSQL_CFLAGS@ @CPPFLAGS@ -DTXT_SQL_CONVERT -c $(OUTPUT_OPTION) $< - -# missing common object files -../common/obj_all/%.o: - @$(MAKE) -C ../common sql - -../common/obj_sql/%.o: - @$(MAKE) -C ../common sql - -# missing login server files -../login/obj_txt/%.o: - @$(MAKE) -C ../login txt - -../login/obj_sql/%.o: - @$(MAKE) -C ../login sql diff --git a/src/txt-converter/char-converter.c b/src/txt-converter/char-converter.c deleted file mode 100644 index 0d6ecea25..000000000 --- a/src/txt-converter/char-converter.c +++ /dev/null @@ -1,303 +0,0 @@ -// (c) eAthena Dev Team - Licensed under GNU GPL -// For more information, see LICENCE in the main folder - -#include "../common/cbasetypes.h" -#include "../common/mmo.h" -#include "../common/core.h" -#include "../common/strlib.h" -#include "../common/showmsg.h" -#include "../common/mapindex.h" -#include "../common/utils.h" - -#include "../char/char.h" -#include "../char/int_storage.h" -#include "../char/int_pet.h" -#include "../char/int_party.h" -#include "../char/int_guild.h" -#include "../char/inter.h" - -#include "../char_sql/char.h" -#include "../char_sql/int_storage.h" -#include "../char_sql/int_pet.h" -#include "../char_sql/int_party.h" -#include "../char_sql/int_guild.h" -#include "../char_sql/inter.h" - -#include -#include -#include - -#define CHAR_CONF_NAME "conf/char_athena.conf" -#define SQL_CONF_NAME "conf/inter_athena.conf" -#define INTER_CONF_NAME "conf/inter_athena.conf" -//-------------------------------------------------------- - -int convert_init(void) -{ - char line[65536]; - int ret; - int tmp_int[2], lineno, count; - char input; - FILE *fp; - - ShowWarning("Make sure you backup your databases before continuing!\n"); - ShowMessage("\n"); - - ShowNotice("Do you wish to convert your Character Database to SQL? (y/n) : "); - input = getchar(); - if(input == 'y' || input == 'Y') - { - struct character_data char_dat; - struct accreg reg; - - ShowStatus("Converting Character Database...\n"); - if( (fp = fopen(char_txt, "r")) == NULL ) - { - ShowError("Unable to open file [%s]!\n", char_txt); - return 0; - } - lineno = count = 0; - while(fgets(line, sizeof(line), fp)) - { - lineno++; - memset(&char_dat, 0, sizeof(struct character_data)); - ret=mmo_char_fromstr(line, &char_dat.status, char_dat.global, &char_dat.global_num); - if(ret > 0) { - count++; - parse_friend_txt(&char_dat.status); //Retrieve friends. - mmo_char_tosql(char_dat.status.char_id , &char_dat.status); - - memset(®, 0, sizeof(reg)); - reg.account_id = char_dat.status.account_id; - reg.char_id = char_dat.status.char_id; - reg.reg_num = char_dat.global_num; - memcpy(®.reg, &char_dat.global, reg.reg_num*sizeof(struct global_reg)); - inter_accreg_tosql(reg.account_id, reg.char_id, ®, 3); //Type 3: Character regs - } else { - ShowError("Error %d converting character line [%s] (at %s:%d).\n", ret, line, char_txt, lineno); - } - } - ShowStatus("Converted %d characters.\n", count); - fclose(fp); - ShowStatus("Converting Account variables Database...\n"); - if( (fp = fopen(accreg_txt, "r")) == NULL ) - { - ShowError("Unable to open file %s!", accreg_txt); - return 1; - } - lineno = count = 0; - while(fgets(line, sizeof(line), fp)) - { - lineno++; - memset (®, 0, sizeof(struct accreg)); - if(inter_accreg_fromstr(line, ®) == 0 && reg.account_id > 0) { - count++; - inter_accreg_tosql(reg.account_id, 0, ®, 2); //Type 2: Account regs - } else { - ShowError("accreg reading: broken data [%s] at %s:%d\n", line, accreg_txt, lineno); - } - } - ShowStatus("Converted %d account registries.\n", count); - fclose(fp); - } - - while(getchar() != '\n'); - ShowMessage("\n"); - ShowNotice("Do you wish to convert your Storage Database to SQL? (y/n) : "); - input = getchar(); - if(input == 'y' || input == 'Y') - { - struct storage_data storage; - ShowMessage("\n"); - ShowStatus("Converting Storage Database...\n"); - if( (fp = fopen(storage_txt,"r")) == NULL ) - { - ShowError("can't read : %s\n", storage_txt); - return 0; - } - lineno = count = 0; - while(fgets(line, sizeof(line), fp)) - { - int account_id; - - lineno++; - if( sscanf(line,"%d,%d",&tmp_int[0],&tmp_int[1]) != 2 ) - continue; - - memset(&storage, 0, sizeof(struct storage_data)); - if( storage_fromstr(line,&account_id,&storage) ) - { - count++; - storage_tosql(account_id,&storage); //to sql. (dump) - } else - ShowError("Error parsing storage line [%s] (at %s:%d)\n", line, storage_txt, lineno); - } - ShowStatus("Converted %d storages.\n", count); - fclose(fp); - } - - //FIXME: CONVERT STATUS DATA HERE!!! - - while(getchar() != '\n'); - ShowMessage("\n"); - ShowNotice("Do you wish to convert your Pet Database to SQL? (y/n) : "); - input=getchar(); - if(input == 'y' || input == 'Y') - { - struct s_pet p; - ShowMessage("\n"); - ShowStatus("Converting Pet Database...\n"); - if( (fp = fopen(pet_txt, "r")) == NULL ) - { - ShowError("Unable to open file %s!", pet_txt); - return 1; - } - lineno = count = 0; - while(fgets(line, sizeof(line), fp)) - { - lineno++; - memset (&p, 0, sizeof(struct s_pet)); - if(inter_pet_fromstr(line, &p)==0 && p.pet_id>0) { - count++; - inter_pet_tosql(p.pet_id,&p); - } else { - ShowError("pet reading: broken data [%s] at %s:%d\n", line, pet_txt, lineno); - } - } - ShowStatus("Converted %d pets.\n", count); - fclose(fp); - } - - //FIXME: CONVERT HOMUNCULUS DATA AND SKILLS HERE!!! - - while(getchar() != '\n'); - ShowMessage("\n"); - ShowNotice("Do you wish to convert your Party Database to SQL? (y/n) : "); - input=getchar(); - if(input == 'y' || input == 'Y') - { - struct party p; - ShowMessage("\n"); - ShowStatus("Converting Party Database...\n"); - if( (fp = fopen(party_txt, "r")) == NULL ) - { - ShowError("Unable to open file %s!", party_txt); - return 1; - } - lineno = count = 0; - while(fgets(line, sizeof(line), fp)) - { - lineno++; - memset (&p, 0, sizeof(struct party)); - if(inter_party_fromstr(line, &p) == 0 && - p.party_id > 0 && - inter_party_tosql(&p, PS_CREATE, 0)) - count++; - else{ - ShowError("party reading: broken data [%s] at %s:%d\n", line, pet_txt, lineno); - } - } - ShowStatus("Converted %d parties.\n", count); - fclose(fp); - } - - while(getchar() != '\n'); - ShowMessage("\n"); - ShowNotice("Do you wish to convert your Guilds and Castles Database to SQL? (y/n) : "); - input=getchar(); - if(input == 'y' || input == 'Y') - { - struct guild g; - struct guild_castle gc; - ShowMessage("\n"); - ShowStatus("Converting Guild Database...\n"); - if( (fp = fopen(guild_txt, "r")) == NULL ) - { - ShowError("Unable to open file %s!", guild_txt); - return 1; - } - lineno = count = 0; - while(fgets(line, sizeof(line), fp)) - { - lineno++; - memset (&g, 0, sizeof(struct guild)); - if (inter_guild_fromstr(line, &g) == 0 && - g.guild_id > 0 && - inter_guild_tosql(&g,GS_MASK)) - count++; - else - ShowError("guild reading: broken data [%s] at %s:%d\n", line, guild_txt, lineno); - } - ShowStatus("Converted %d guilds.\n", count); - fclose(fp); - ShowStatus("Converting Guild Castles Database...\n"); - if( (fp = fopen(castle_txt, "r")) == NULL ) - { - ShowError("Unable to open file %s!", castle_txt); - return 1; - } - lineno = count = 0; - while(fgets(line, sizeof(line), fp)) - { - lineno++; - memset(&gc, 0, sizeof(struct guild_castle)); - if (inter_guildcastle_fromstr(line, &gc) == 0) { - inter_guildcastle_tosql(&gc); - count++; - } - else - ShowError("guild castle reading: broken data [%s] at %s:%d\n", line, castle_txt, lineno); - } - ShowStatus("Converted %d guild castles.\n", count); - fclose(fp); - } - - while(getchar() != '\n'); - ShowMessage("\n"); - ShowNotice("Do you wish to convert your Guild Storage Database to SQL? (y/n) : "); - input=getchar(); - if(input == 'y' || input == 'Y') - { - struct guild_storage storage_; - ShowMessage("\n"); - ShowStatus("Converting Guild Storage Database...\n"); - if( (fp = fopen(guild_storage_txt, "r")) == NULL ) - { - ShowError("can't read : %s\n", guild_storage_txt); - return 0; - } - lineno = count = 0; - while(fgets(line, sizeof(line), fp)) - { - lineno++; - memset(&storage_, 0, sizeof(struct guild_storage)); - if (sscanf(line,"%d",&storage_.guild_id) == 1 && - storage_.guild_id > 0 && - guild_storage_fromstr(line,&storage_) == 0 - ) { - count++; - guild_storage_tosql(storage_.guild_id, &storage_); - } else - ShowError("Error parsing guild storage line [%s] (at %s:%d)\n", line, guild_storage_txt, lineno); - } - ShowStatus("Converted %d guild storages.\n", count); - fclose(fp); - } - - return 0; -} - -int do_init(int argc, char** argv) -{ - char_config_read( (argc > 1) ? argv[1] : CHAR_CONF_NAME); - mapindex_init(); - sql_config_read( (argc > 2) ? argv[2] : SQL_CONF_NAME); - inter_init_txt( (argc > 3) ? argv[3] : INTER_CONF_NAME); - inter_init_sql( (argc > 3) ? argv[3] : INTER_CONF_NAME); - convert_init(); - ShowStatus("Everything's been converted!\n"); - mapindex_final(); - return 0; -} - -void do_final(void) {} diff --git a/src/txt-converter/char/CMakeLists.txt b/src/txt-converter/char/CMakeLists.txt deleted file mode 100644 index ad3970d77..000000000 --- a/src/txt-converter/char/CMakeLists.txt +++ /dev/null @@ -1,76 +0,0 @@ - -# -# char-converter -# -if( BUILD_CONVERTERS ) -message( STATUS "Creating target char-converter" ) -set( COMMON_HEADERS - ${COMMON_MINI_HEADERS} - "${COMMON_SOURCE_DIR}/mapindex.h" - "${COMMON_SOURCE_DIR}/sql.h" - "${COMMON_SOURCE_DIR}/timer.h" - ) -set( COMMON_SOURCES - ${COMMON_MINI_SOURCES} - "${COMMON_SOURCE_DIR}/mapindex.c" - "${COMMON_SOURCE_DIR}/sql.c" - "${COMMON_SOURCE_DIR}/timer.c" - ) -set( TXT_HEADERS - "${TXT_CHAR_SOURCE_DIR}/char.h" - "${TXT_CHAR_SOURCE_DIR}/int_pet.h" - "${TXT_CHAR_SOURCE_DIR}/int_storage.h" - "${TXT_CHAR_SOURCE_DIR}/inter.h" - "${TXT_CHAR_SOURCE_DIR}/int_party.h" - "${TXT_CHAR_SOURCE_DIR}/int_guild.h" - ) -set( TXT_SOURCES - "${TXT_CHAR_SOURCE_DIR}/char.c" - "${TXT_CHAR_SOURCE_DIR}/int_pet.c" - "${TXT_CHAR_SOURCE_DIR}/int_storage.c" - "${TXT_CHAR_SOURCE_DIR}/inter.c" - "${TXT_CHAR_SOURCE_DIR}/int_party.c" - "${TXT_CHAR_SOURCE_DIR}/int_guild.c" - ) -set( SQL_HEADERS - "${SQL_CHAR_SOURCE_DIR}/char.h" - "${SQL_CHAR_SOURCE_DIR}/int_pet.h" - "${SQL_CHAR_SOURCE_DIR}/int_storage.h" - "${SQL_CHAR_SOURCE_DIR}/inter.h" - "${SQL_CHAR_SOURCE_DIR}/int_party.h" - "${SQL_CHAR_SOURCE_DIR}/int_guild.h" - "${SQL_CHAR_SOURCE_DIR}/int_mercenary.h" - ) -set( SQL_SOURCES - "${SQL_CHAR_SOURCE_DIR}/char.c" - "${SQL_CHAR_SOURCE_DIR}/int_pet.c" - "${SQL_CHAR_SOURCE_DIR}/int_storage.c" - "${SQL_CHAR_SOURCE_DIR}/inter.c" - "${SQL_CHAR_SOURCE_DIR}/int_party.c" - "${SQL_CHAR_SOURCE_DIR}/int_guild.c" - "${SQL_CHAR_SOURCE_DIR}/int_mercenary.c" - ) -set( CONVERTER_SOURCES - "${CONVERTER_SOURCE_DIR}/char-converter.c" - ) -set( LIBRARIES ${GLOBAL_LIBRARIES} ${MYSQL_LIBRARIES} ) -set( INCLUDE_DIRS ${GLOBAL_INCLUDE_DIRS} ${MYSQL_INCLUDE_DIRS} ) -set( DEFINITIONS "${GLOBAL_DEFINITIONS} ${COMMON_MINI_DEFINITIONS} -DTXT_SQL_CONVERT" ) -set( SOURCE_FILES ${COMMON_HEADERS} ${COMMON_SOURCES} ${TXT_HEADERS} ${TXT_SOURCES} ${SQL_HEADERS} ${SQL_SOURCES} ${CONVERTER_SOURCES} ) -source_group( common FILES ${COMMON_HEADERS} ${COMMON_SOURCES} ) -source_group( txt FILES ${TXT_HEADERS} ${TXT_SOURCES} ) -source_group( sql FILES ${SQL_HEADERS} ${SQL_SOURCES} ) -source_group( converter FILES ${CONVERTER_SOURCES} ) -include_directories( ${INCLUDE_DIRS} ) -add_executable( char-converter ${SOURCE_FILES} ) -target_link_libraries( char-converter ${LIBRARIES} ) -set_target_properties( char-converter PROPERTIES COMPILE_FLAGS "${DEFINITIONS}" ) -if( INSTALL_COMPONENT_RUNTIME ) - cpack_add_component( Runtime_charconverter DESCRIPTION "char-converter" DISPLAY_NAME "char-converter" GROUP Runtime ) - install( TARGETS char-converter - DESTINATION "tools" - COMPONENT Runtime_charconverter ) -endif( INSTALL_COMPONENT_RUNTIME ) -set( TARGET_LIST ${TARGET_LIST} char-converter CACHE INTERNAL "" ) -message( STATUS "Creating target char-converter - done" ) -endif( BUILD_CONVERTERS ) diff --git a/src/txt-converter/login-converter.c b/src/txt-converter/login-converter.c deleted file mode 100644 index d72d35ae2..000000000 --- a/src/txt-converter/login-converter.c +++ /dev/null @@ -1,108 +0,0 @@ -// (c) eAthena Dev Team - Licensed under GNU GPL -// For more information, see LICENCE in the main folder - -#include "../common/cbasetypes.h" -#include "../common/mmo.h" // struct mmo_account -#include "../common/core.h" -#include "../common/showmsg.h" -#include "../login/account.h" -#include -#include - -#define LOGIN_CONF_NAME "conf/login_athena.conf" - -AccountDB* txtdb = NULL; -AccountDB* sqldb = NULL; - -//-------------------------------------------------------- - -int convert_login(void) -{ - AccountDBIterator* iter; - struct mmo_account acc; - - if( !txtdb->init(txtdb) || !sqldb->init(sqldb) ) - { - ShowFatalError("Initialization failed, unable to start conversion.\n"); - return 0; - } - - ShowStatus("Conversion started...\n"); - //TODO: do some counting & statistics - - iter = txtdb->iterator(txtdb); - while( iter->next(iter, &acc) ) - { - ShowInfo("Converting user (id: %d, name: %s, gm level: %d)...", acc.account_id, acc.userid, acc.level); - if( sqldb->create(sqldb, &acc) ) - ShowMessage(CL_GREEN "success.\n"); - else - ShowMessage(CL_RED "failed!\n"); - } - iter->destroy(iter); - - ShowStatus("Conversion finished.\n"); - - return 0; -} - -int login_config_read(const char* cfgName) -{ - int i; - char line[1024], w1[1024], w2[1024]; - FILE *fp; - - ShowStatus("Start reading login server configuration: %s\n", cfgName); - - fp=fopen(cfgName,"r"); - if(fp==NULL){ - ShowError("File not found: %s\n", cfgName); - return 1; - } - - while(fgets(line, sizeof(line), fp)) - { - if(line[0] == '/' && line[1] == '/') - continue; - - i=sscanf(line,"%[^:]:%s", w1, w2); - if(i!=2) - continue; - - txtdb->set_property(txtdb, w1, w2); - sqldb->set_property(sqldb, w1, w2); - - //support the import command, just like any other config - if( strcmpi(w1,"import") == 0 ) - login_config_read(w2); - } - - fclose(fp); - ShowStatus("End reading login server configuration...\n"); - return 0; -} - -int do_init(int argc, char** argv) -{ - int input; - - txtdb = account_db_txt(); - sqldb = account_db_sql(); - - login_config_read( (argc > 1) ? argv[1] : LOGIN_CONF_NAME ); - - ShowInfo("\nWarning : Make sure you backup your databases before continuing!\n"); - ShowInfo("\nDo you wish to convert your Login Database to SQL? (y/n) : "); - input = getchar(); - - if(input == 'y' || input == 'Y') - convert_login(); - - return 0; -} - -void do_final(void) -{ - txtdb->destroy(txtdb); - sqldb->destroy(sqldb); -} diff --git a/src/txt-converter/login/CMakeLists.txt b/src/txt-converter/login/CMakeLists.txt deleted file mode 100644 index 605050d60..000000000 --- a/src/txt-converter/login/CMakeLists.txt +++ /dev/null @@ -1,60 +0,0 @@ - -# -# login-converter -# -if( BUILD_CONVERTERS ) -message( STATUS "Creating target login-converter" ) -set( COMMON_HEADERS - ${COMMON_MINI_HEADERS} - "${COMMON_SOURCE_DIR}/db.h" - "${COMMON_SOURCE_DIR}/ers.h" - "${COMMON_SOURCE_DIR}/lock.h" - "${COMMON_SOURCE_DIR}/sql.h" - "${COMMON_SOURCE_DIR}/timer.h" - "${COMMON_SOURCE_DIR}/utils.h" - ) -set( COMMON_SOURCES - ${COMMON_MINI_SOURCES} - "${COMMON_SOURCE_DIR}/db.c" - "${COMMON_SOURCE_DIR}/ers.c" - "${COMMON_SOURCE_DIR}/lock.c" - "${COMMON_SOURCE_DIR}/sql.c" - "${COMMON_SOURCE_DIR}/timer.c" - "${COMMON_SOURCE_DIR}/utils.c" - ) -set( TXT_HEADERS - "${TXT_LOGIN_SOURCE_DIR}/account.h" - ) -set( TXT_SOURCES - "${TXT_LOGIN_SOURCE_DIR}/account_txt.c" - ) -set( SQL_HEADERS - "${SQL_LOGIN_SOURCE_DIR}/account.h" - ) -set( SQL_SOURCES - "${SQL_LOGIN_SOURCE_DIR}/account_sql.c" - ) -set( CONVERTER_SOURCES - "${CONVERTER_SOURCE_DIR}/login-converter.c" - ) -set( LIBRARIES ${GLOBAL_LIBRARIES} ${MYSQL_LIBRARIES} ) -set( INCLUDE_DIRS ${GLOBAL_INCLUDE_DIRS} ${MYSQL_INCLUDE_DIRS} ) -set( DEFINITIONS "${GLOBAL_DEFINITIONS} ${COMMON_MINI_DEFINITIONS} -DWITH_TXT -DWITH_SQL" ) -set( SOURCE_FILES ${COMMON_HEADERS} ${COMMON_SOURCES} ${TXT_HEADERS} ${TXT_SOURCES} ${SQL_HEADERS} ${SQL_SOURCES} ${CONVERTER_SOURCES} ) -source_group( common FILES ${COMMON_HEADERS} ${COMMON_SOURCES} ) -source_group( txt FILES ${TXT_HEADERS} ${TXT_SOURCES} ) -source_group( sql FILES ${SQL_HEADERS} ${SQL_SOURCES} ) -source_group( converter FILES ${CONVERTER_SOURCES} ) -include_directories( ${INCLUDE_DIRS} ) -add_executable( login-converter ${SOURCE_FILES} ) -target_link_libraries( login-converter ${LIBRARIES} ) -set_target_properties( login-converter PROPERTIES COMPILE_FLAGS "${DEFINITIONS}" ) -if( INSTALL_COMPONENT_RUNTIME ) - cpack_add_component( Runtime_loginconverter DESCRIPTION "login-converter" DISPLAY_NAME "login-converter" GROUP Runtime ) - install( TARGETS login-converter - DESTINATION "tools" - COMPONENT Runtime_loginconverter ) -endif( INSTALL_COMPONENT_RUNTIME ) -set( TARGET_LIST ${TARGET_LIST} login-converter CACHE INTERNAL "" ) -message( STATUS "Creating target login-converter - done" ) -endif( BUILD_CONVERTERS ) diff --git a/vcproj-10/char-server_sql.vcxproj b/vcproj-10/char-server_sql.vcxproj index 1ed50b62f..e7fd17017 100644 --- a/vcproj-10/char-server_sql.vcxproj +++ b/vcproj-10/char-server_sql.vcxproj @@ -146,17 +146,17 @@ - - - - - - - - - - - + + + + + + + + + + +
@@ -174,17 +174,17 @@ - - - - - - - - - - - + + + + + + + + + + + diff --git a/vcproj-10/char-server_sql.vcxproj.filters b/vcproj-10/char-server_sql.vcxproj.filters index a2bbf2d15..189c72e79 100644 --- a/vcproj-10/char-server_sql.vcxproj.filters +++ b/vcproj-10/char-server_sql.vcxproj.filters @@ -46,37 +46,37 @@ common - + char_sql - + char_sql - + char_sql - + char_sql - + char_sql - + char_sql - + char_sql - + char_sql - + char_sql - + char_sql - + char_sql
@@ -138,37 +138,37 @@ common - + char_sql - + char_sql - + char_sql - + char_sql - + char_sql - + char_sql - + char_sql - + char_sql - + char_sql - + char_sql - + char_sql diff --git a/vcproj-10/char-server_txt.vcxproj b/vcproj-10/char-server_txt.vcxproj deleted file mode 100644 index ab79961a3..000000000 --- a/vcproj-10/char-server_txt.vcxproj +++ /dev/null @@ -1,184 +0,0 @@ -サソ - - - - Debug - Win32 - - - Release - Win32 - - - - {D356871D-58E1-450B-967A-E3E9646175AF} - char-server_txt - Win32Proj - - - - Application - MultiByte - true - - - Application - MultiByte - - - - - - - - - - - - - - - <_ProjectFileVersion>10.0.30319.1 - ..\ - $(ProjectName)\$(Configuration)\ - true - ..\ - $(ProjectName)\$(Configuration)\ - false - char-server - char-server - - - - Disabled - ..\3rdparty\msinttypes\include;..\3rdparty\mt19937ar;%(AdditionalIncludeDirectories) - WIN32;_WIN32;__WIN32;_DEBUG;TXT_ONLY;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;FD_SETSIZE=4096;%(PreprocessorDefinitions) - false - false - - - EnableFastChecks - MultiThreadedDebug - true - - - - - Level3 - EditAndContinue - CompileAsC - 4800;%(DisableSpecificWarnings) - true - - - libcmtd.lib;oldnames.lib;ws2_32.lib;%(AdditionalDependencies) - $(OutDir)char-server.exe - %(AdditionalLibraryDirectories) - true - true - $(OutDir)char-server.pdb - Console - false - - - MachineX86 - - - - - MaxSpeed - AnySuitable - true - Speed - true - true - true - ..\3rdparty\msinttypes\include;..\3rdparty\mt19937ar;%(AdditionalIncludeDirectories) - WIN32;_WIN32;__WIN32;NDEBUG;TXT_ONLY;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;FD_SETSIZE=4096;%(PreprocessorDefinitions) - true - MultiThreaded - - - - - Level3 - ProgramDatabase - CompileAsC - 4800;%(DisableSpecificWarnings) - true - - - libcmt.lib;oldnames.lib;ws2_32.lib;%(AdditionalDependencies) - $(OutDir)char-server.exe - %(AdditionalLibraryDirectories) - true - true - $(OutDir)char-server.pdb - Console - true - true - UseLinkTimeCodeGeneration - false - - - MachineX86 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/vcproj-10/char-server_txt.vcxproj.filters b/vcproj-10/char-server_txt.vcxproj.filters deleted file mode 100644 index 0bb9773de..000000000 --- a/vcproj-10/char-server_txt.vcxproj.filters +++ /dev/null @@ -1,168 +0,0 @@ -サソ - - - - 3rdparty - - - common - - - common - - - common - - - common - - - common - - - common - - - common - - - common - - - common - - - common - - - common - - - common - - - common - - - common - - - char_txt - - - char_txt - - - char_txt - - - char_txt - - - char_txt - - - char_txt - - - char_txt - - - char_txt - - - - - 3rdparty - - - common - - - common - - - common - - - common - - - common - - - common - - - common - - - common - - - common - - - common - - - common - - - common - - - common - - - common - - - common - - - common - - - common - - - common - - - char_txt - - - char_txt - - - char_txt - - - char_txt - - - char_txt - - - char_txt - - - char_txt - - - char_txt - - - - - {3426d3df-b8f8-421a-9ecf-5929f527ebcd} - - - {ecf20235-c0df-43f9-a4c0-f2f992b3330f} - - - {36b5e281-2a86-4c66-bc78-f56c54f0b3c2} - - - \ No newline at end of file diff --git a/vcproj-10/login-server_txt.vcxproj b/vcproj-10/login-server_txt.vcxproj deleted file mode 100644 index f80d368b5..000000000 --- a/vcproj-10/login-server_txt.vcxproj +++ /dev/null @@ -1,175 +0,0 @@ -サソ - - - - Debug - Win32 - - - Release - Win32 - - - - {D356871D-58E1-450B-967A-E2E9646175AF} - login-server_txt - Win32Proj - - - - Application - MultiByte - true - - - Application - MultiByte - - - - - - - - - - - - - <_ProjectFileVersion>10.0.30319.1 - ..\ - $(ProjectName)\$(Configuration)\ - true - ..\ - $(ProjectName)\$(Configuration)\ - false - login-server - login-server - - - - Disabled - ..\3rdparty\msinttypes\include;..\3rdparty\mt19937ar;%(AdditionalIncludeDirectories) - WIN32;_WIN32;__WIN32;_DEBUG;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;FD_SETSIZE=4096;WITH_TXT;%(PreprocessorDefinitions) - false - false - - - EnableFastChecks - MultiThreadedDebug - true - - - - - Level3 - EditAndContinue - CompileAsC - 4100;4800;%(DisableSpecificWarnings) - true - - - libcmtd.lib;oldnames.lib;ws2_32.lib;%(AdditionalDependencies) - NotSet - $(OutDir)login-server.exe - %(AdditionalLibraryDirectories) - true - true - $(OutDir)login-server.pdb - Console - false - - - MachineX86 - - - - - MaxSpeed - AnySuitable - true - Speed - true - true - true - ..\3rdparty\msinttypes\include;..\3rdparty\mt19937ar;%(AdditionalIncludeDirectories) - WIN32;_WIN32;__WIN32;NDEBUG;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;FD_SETSIZE=4096;WITH_TXT;%(PreprocessorDefinitions) - true - MultiThreaded - - - - - Level3 - ProgramDatabase - CompileAsC - 4100;4800;%(DisableSpecificWarnings) - true - - - libcmt.lib;oldnames.lib;ws2_32.lib;%(AdditionalDependencies) - $(OutDir)login-server.exe - %(AdditionalLibraryDirectories) - true - true - $(OutDir)login-server.pdb - Console - true - true - UseLinkTimeCodeGeneration - false - - - MachineX86 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/vcproj-10/login-server_txt.vcxproj.filters b/vcproj-10/login-server_txt.vcxproj.filters deleted file mode 100644 index 447e7e772..000000000 --- a/vcproj-10/login-server_txt.vcxproj.filters +++ /dev/null @@ -1,144 +0,0 @@ -サソ - - - - 3rdparty - - - login_txt - - - login_txt - - - login_txt - - - login_txt - - - common - - - common - - - common - - - common - - - common - - - common - - - common - - - common - - - common - - - common - - - common - - - common - - - common - - - common - - - - - 3rdparty - - - login_txt - - - login_txt - - - login_txt - - - login_txt - - - common - - - common - - - common - - - common - - - common - - - common - - - common - - - common - - - common - - - common - - - common - - - common - - - common - - - common - - - common - - - common - - - common - - - common - - - - - {be8a59c3-07c1-4edd-9114-964892214f9e} - - - {2b1ebf8e-ab6f-49be-b1f0-52d695ac9282} - - - {0719c3dc-e4e3-4235-b6d6-bbd3e7c258a5} - - - \ No newline at end of file diff --git a/vcproj-10/map-server_txt.vcxproj b/vcproj-10/map-server_txt.vcxproj deleted file mode 100644 index 83f16a8b5..000000000 --- a/vcproj-10/map-server_txt.vcxproj +++ /dev/null @@ -1,250 +0,0 @@ -サソ - - - - Debug - Win32 - - - Release - Win32 - - - - {D356871D-58E1-450B-967A-E1E9646175AF} - map-server_txt - Win32Proj - - - - Application - MultiByte - true - - - Application - MultiByte - - - - - - - - - - - - - <_ProjectFileVersion>10.0.30319.1 - ..\ - $(ProjectName)\$(Configuration)\ - true - ..\ - $(ProjectName)\$(Configuration)\ - false - map-server - map-server - - - - Disabled - ..\3rdparty\zlib\include;..\3rdparty\pcre\include;..\3rdparty\msinttypes\include;..\3rdparty\mt19937ar;%(AdditionalIncludeDirectories) - WIN32;_WIN32;__WIN32;_DEBUG;PCRE_SUPPORT;TXT_ONLY;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;FD_SETSIZE=4096;%(PreprocessorDefinitions) - false - false - - - EnableFastChecks - MultiThreadedDebug - true - - - - - Level3 - EditAndContinue - CompileAsC - 4018;4100;4800;%(DisableSpecificWarnings) - true - - - /FIXED:NO %(AdditionalOptions) - libcmtd.lib;oldnames.lib;ws2_32.lib;zdll.lib;pcre.lib;%(AdditionalDependencies) - $(OutDir)map-server.exe - ..\3rdparty\zlib\lib;..\3rdparty\pcre\lib;%(AdditionalLibraryDirectories) - true - true - $(OutDir)map-server.pdb - Console - false - - - MachineX86 - - - - - MaxSpeed - AnySuitable - true - Speed - true - true - true - ..\3rdparty\zlib\include;..\3rdparty\pcre\include;..\3rdparty\msinttypes\include;..\3rdparty\mt19937ar;%(AdditionalIncludeDirectories) - WIN32;_WIN32;__WIN32;NDEBUG;PCRE_SUPPORT;TXT_ONLY;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;FD_SETSIZE=4096;%(PreprocessorDefinitions) - true - MultiThreaded - false - - - - - Level3 - ProgramDatabase - CompileAsC - 4018;4100;4800;%(DisableSpecificWarnings) - true - - - libcmt.lib;oldnames.lib;ws2_32.lib;zdll.lib;pcre.lib;%(AdditionalDependencies) - $(OutDir)map-server.exe - ..\3rdparty\zlib\lib;..\3rdparty\pcre\lib;%(AdditionalLibraryDirectories) - true - true - $(OutDir)map-server.pdb - Console - true - true - UseLinkTimeCodeGeneration - false - - - MachineX86 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/vcproj-10/map-server_txt.vcxproj.filters b/vcproj-10/map-server_txt.vcxproj.filters deleted file mode 100644 index a90302f0c..000000000 --- a/vcproj-10/map-server_txt.vcxproj.filters +++ /dev/null @@ -1,345 +0,0 @@ -サソ - - - - map_txt - - - map_txt - - - map_txt - - - map_txt - - - map_txt - - - map_txt - - - map_txt - - - common - - - common - - - common - - - common - - - common - - - common - - - map_txt - - - map_txt - - - map_txt - - - map_txt - - - map_txt - - - map_txt - - - map_txt - - - map_txt - - - map_txt - - - common - - - common - - - common - - - common - - - common - - - common - - - common - - - common - - - common - - - common - - - common - - - map_txt - - - map_txt - - - map_txt - - - map_txt - - - map_txt - - - map_txt - - - map_txt - - - map_txt - - - map_txt - - - map_txt - - - map_txt - - - map_txt - - - map_txt - - - map_txt - - - map_txt - - - map_txt - - - map_txt - - - map_txt - - - map_txt - - - 3rdparty - - - - - map_txt - - - map_txt - - - map_txt - - - map_txt - - - common - - - map_txt - - - map_txt - - - map_txt - - - common - - - common - - - common - - - common - - - common - - - common - - - map_txt - - - map_txt - - - map_txt - - - map_txt - - - map_txt - - - map_txt - - - map_txt - - - map_txt - - - map_txt - - - common - - - common - - - common - - - common - - - common - - - common - - - common - - - common - - - common - - - common - - - common - - - common - - - common - - - common - - - map_txt - - - map_txt - - - map_txt - - - map_txt - - - map_txt - - - map_txt - - - map_txt - - - map_txt - - - map_txt - - - map_txt - - - map_txt - - - map_txt - - - map_txt - - - map_txt - - - map_txt - - - map_txt - - - map_txt - - - map_txt - - - 3rdparty - - - - - {1a14e4e3-9844-4386-bf22-dd1fe7732bb5} - - - {3c87ae01-115b-4d3b-a856-a3b96ca7b469} - - - {b4ec69ed-50dd-4ac0-885f-a88bd617ebac} - - - \ No newline at end of file diff --git a/vcproj-10/txt-converter-char.vcxproj b/vcproj-10/txt-converter-char.vcxproj deleted file mode 100644 index 7064df852..000000000 --- a/vcproj-10/txt-converter-char.vcxproj +++ /dev/null @@ -1,204 +0,0 @@ -サソ - - - - Debug - Win32 - - - Release - Win32 - - - - {D356871D-58E1-450B-967A-EAE9646175AF} - txt-converter-char - Win32Proj - - - - Application - MultiByte - true - - - Application - MultiByte - - - - - - - - - - - - - - - <_ProjectFileVersion>10.0.30319.1 - ..\tools\ - $(ProjectName)\$(Configuration)\ - true - ..\tools\ - $(ProjectName)\$(Configuration)\ - false - char-converter - char-converter - - - - Disabled - ..\3rdparty\mysql\include;..\3rdparty\msinttypes\include;%(AdditionalIncludeDirectories) - WIN32;_WIN32;__WIN32;_DEBUG;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;FD_SETSIZE=4096;MINICORE;TXT_SQL_CONVERT;%(PreprocessorDefinitions) - false - false - - - EnableFastChecks - MultiThreadedDebug - true - - - - - Level3 - EditAndContinue - CompileAsC - true - - - libcmtd.lib;oldnames.lib;ws2_32.lib;libmysql.lib;%(AdditionalDependencies) - $(OutDir)char-converter.exe - ..\3rdparty\mysql\lib;%(AdditionalLibraryDirectories) - true - %(IgnoreSpecificDefaultLibraries) - true - $(OutDir)char-converter.pdb - Console - false - - - MachineX86 - - - - - MaxSpeed - AnySuitable - true - Speed - true - true - true - ..\3rdparty\mysql\include;..\3rdparty\msinttypes\include;%(AdditionalIncludeDirectories) - WIN32;_WIN32;__WIN32;NDEBUG;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;FD_SETSIZE=4096;MINICORE;TXT_SQL_CONVERT;%(PreprocessorDefinitions) - true - MultiThreaded - - - - - - - - - Level3 - ProgramDatabase - CompileAsC - true - - - libcmt.lib;oldnames.lib;ws2_32.lib;libmysql.lib;%(AdditionalDependencies) - $(OutDir)char-converter.exe - ..\3rdparty\mysql\lib;%(AdditionalLibraryDirectories) - true - %(IgnoreSpecificDefaultLibraries) - true - $(OutDir)char-converter.pdb - Console - true - true - UseLinkTimeCodeGeneration - false - - - MachineX86 - - - - - - - - - - - - - - - - - - - - $(IntDir)%(Filename)_sql.obj - $(IntDir)%(Filename)_sql.obj - - - $(IntDir)%(Filename)_sql.obj - $(IntDir)%(Filename)_sql.obj - - - $(IntDir)%(Filename)_sql.obj - $(IntDir)%(Filename)_sql.obj - - - $(IntDir)%(Filename)_sql.obj - $(IntDir)%(Filename)_sql.obj - - - $(IntDir)%(Filename)_sql.obj - $(IntDir)%(Filename)_sql.obj - - - $(IntDir)%(Filename)_sql.obj - $(IntDir)%(Filename)_sql.obj - - - $(IntDir)%(Filename)_sql.obj - $(IntDir)%(Filename)_sql.obj - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/vcproj-10/txt-converter-char.vcxproj.filters b/vcproj-10/txt-converter-char.vcxproj.filters deleted file mode 100644 index 4068225e6..000000000 --- a/vcproj-10/txt-converter-char.vcxproj.filters +++ /dev/null @@ -1,156 +0,0 @@ -サソ - - - - converter - - - char - - - char_sql - - - common - - - common - - - common - - - common - - - common - - - common - - - common - - - common - - - common - - - char_sql - - - char - - - char_sql - - - char_sql - - - char_sql - - - char - - - char_sql - - - char - - - char - - - char_sql - - - char - - - - - char_sql - - - char - - - common - - - common - - - common - - - common - - - common - - - common - - - common - - - common - - - common - - - char_sql - - - char - - - char_sql - - - char_sql - - - char_sql - - - char_sql - - - char - - - char - - - char - - - char_sql - - - char - - - - - {8cd3ef2c-94f8-4117-9456-0718099b6cff} - - - {39dba2e0-24d6-4e27-bca0-512f4124aafd} - - - {9ff3fa33-e859-4bec-8ef5-f4b35906784c} - - - {9b273f25-9226-4784-8e88-3085194c0c8a} - - - \ No newline at end of file diff --git a/vcproj-10/txt-converter-login.vcxproj b/vcproj-10/txt-converter-login.vcxproj deleted file mode 100644 index 06c3a8b6c..000000000 --- a/vcproj-10/txt-converter-login.vcxproj +++ /dev/null @@ -1,162 +0,0 @@ -サソ - - - - Debug - Win32 - - - Release - Win32 - - - - {D356871D-58E1-450B-967A-E9E9646175AF} - txt-converter-login - Win32Proj - - - - Application - MultiByte - true - - - Application - MultiByte - - - - - - - - - - - - - - - <_ProjectFileVersion>10.0.30319.1 - ..\tools\ - $(ProjectName)\$(Configuration)\ - true - ..\tools\ - $(ProjectName)\$(Configuration)\ - false - login-converter - login-converter - - - - Disabled - ..\3rdparty\mysql\include;..\3rdparty\msinttypes\include;%(AdditionalIncludeDirectories) - WIN32;_WIN32;__WIN32;_DEBUG;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;FD_SETSIZE=4096;MINICORE;WITH_TXT;WITH_SQL;%(PreprocessorDefinitions) - false - false - - - EnableFastChecks - MultiThreadedDebug - true - - - - - Level3 - EditAndContinue - CompileAsC - true - - - libcmtd.lib;oldnames.lib;ws2_32.lib;libmysql.lib;%(AdditionalDependencies) - $(OutDir)login-converter.exe - ..\3rdparty\mysql\lib;%(AdditionalLibraryDirectories) - true - %(IgnoreSpecificDefaultLibraries) - true - $(OutDir)login-converter.pdb - Console - false - - - MachineX86 - - - - - MaxSpeed - AnySuitable - true - Speed - true - true - true - ..\3rdparty\mysql\include;..\3rdparty\msinttypes\include;%(AdditionalIncludeDirectories) - WIN32;_WIN32;__WIN32;NDEBUG;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;FD_SETSIZE=4096;MINICORE;WITH_TXT;WITH_SQL;%(PreprocessorDefinitions) - true - MultiThreaded - - - - - - - - - Level3 - ProgramDatabase - CompileAsC - true - - - libcmt.lib;oldnames.lib;ws2_32.lib;libmysql.lib;%(AdditionalDependencies) - $(OutDir)login-converter.exe - ..\3rdparty\mysql\lib;%(AdditionalLibraryDirectories) - true - %(IgnoreSpecificDefaultLibraries) - true - $(OutDir)login-converter.pdb - Console - true - true - UseLinkTimeCodeGeneration - false - - - MachineX86 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/vcproj-10/txt-converter-login.vcxproj.filters b/vcproj-10/txt-converter-login.vcxproj.filters deleted file mode 100644 index 668acec99..000000000 --- a/vcproj-10/txt-converter-login.vcxproj.filters +++ /dev/null @@ -1,90 +0,0 @@ -サソ - - - - login - - - login - - - common - - - common - - - common - - - common - - - common - - - common - - - common - - - common - - - common - - - common - - - converter - - - - - login - - - common - - - common - - - common - - - common - - - common - - - common - - - common - - - common - - - common - - - common - - - - - {23e12c5b-4a3f-49aa-880b-3cdd20026aaa} - - - {47a4218f-2ab2-4032-b56d-70593a821fb0} - - - {6d4aed21-4896-4192-8133-dd5f7ab3fb6d} - - - \ No newline at end of file diff --git a/vcproj-9/char-server_sql.vcproj b/vcproj-9/char-server_sql.vcproj index 557b6e149..06c006cd4 100644 --- a/vcproj-9/char-server_sql.vcproj +++ b/vcproj-9/char-server_sql.vcproj @@ -357,91 +357,91 @@ Name="char_sql" > diff --git a/vcproj-9/char-server_txt.vcproj b/vcproj-9/char-server_txt.vcproj deleted file mode 100644 index be7ada4fc..000000000 --- a/vcproj-9/char-server_txt.vcproj +++ /dev/null @@ -1,417 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vcproj-9/login-server_txt.vcproj b/vcproj-9/login-server_txt.vcproj deleted file mode 100644 index 39c4bfdf5..000000000 --- a/vcproj-9/login-server_txt.vcproj +++ /dev/null @@ -1,380 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vcproj-9/map-server_txt.vcproj b/vcproj-9/map-server_txt.vcproj deleted file mode 100644 index e499c9035..000000000 --- a/vcproj-9/map-server_txt.vcproj +++ /dev/null @@ -1,681 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vcproj-9/txt-converter-char.vcproj b/vcproj-9/txt-converter-char.vcproj deleted file mode 100644 index ea0ee49eb..000000000 --- a/vcproj-9/txt-converter-char.vcproj +++ /dev/null @@ -1,513 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vcproj-9/txt-converter-login.vcproj b/vcproj-9/txt-converter-login.vcproj deleted file mode 100644 index 26e640e6f..000000000 --- a/vcproj-9/txt-converter-login.vcproj +++ /dev/null @@ -1,309 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -- cgit v1.2.3-70-g09d2 From 526217d77d50dc27b0815e3d5895df7bfa38ff76 Mon Sep 17 00:00:00 2001 From: gepard1984 Date: Mon, 13 Feb 2012 01:19:04 +0000 Subject: - Added `libconfig` (configuration file library: http://www.hyperrealm.com/libconfig/): - Updated VS9/10 project files. - Updated `configure` & `Makefile`s. - New GM, Commands & Permissions system: - '''This is a backwards compatibility breaking update''', please read tid:58877 - Replaced GM levels with Player Groups. - Commands permissions & other privileges now depend on group, not GM level. - `@help` command improvements: requires "commandname" param and shows more detailed info about commands. - Modified GM whisper system to deliver messages basing on permissions, not GM level. - Remote trade request is now possible only if player is allowed to use `@trade` command as well. - Added a proper permission to use `/changemaptype` command. - `clif_displaymessage` is now capable of displaying multiline messages. - All `ACMD_FUNC`s are static now, and the only way to invoke them is with `is_atcommand()`; all client commands (starting with `/`) are now translated into corresponding atcommands (with exception of `/kick` used on monster, as there is no atcommand to kill single monster). - Removed nonsense "bot check" triggering when player blocked (`/ex`) Server. - Merged `@monster`, `@monsterbig` and `@monstersmall`. - Improved flow of atcommand execution to avoid revealing info about online players or existing commands to non-privileged players. - Merged `atcommand` and `charcommand` script functions (`charcommand` is aliased to `atcommand`). - Fixed `atcommand` script function reading unknown memory area (possible access violation). git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@15572 54d463be-8e91-2dee-dedb-b68131a5f0ec --- 3rdparty/libconfig/LICENSE | 674 ++++++++ 3rdparty/libconfig/Makefile.in | 24 + 3rdparty/libconfig/grammar.c | 2001 +++++++++++++++++++++++ 3rdparty/libconfig/grammar.h | 113 ++ 3rdparty/libconfig/libconfig-1.4.8 | 0 3rdparty/libconfig/libconfig.c | 1615 +++++++++++++++++++ 3rdparty/libconfig/libconfig.h | 320 ++++ 3rdparty/libconfig/parsectx.h | 47 + 3rdparty/libconfig/scanctx.c | 170 ++ 3rdparty/libconfig/scanctx.h | 61 + 3rdparty/libconfig/scanner.c | 2362 ++++++++++++++++++++++++++++ 3rdparty/libconfig/scanner.h | 326 ++++ 3rdparty/libconfig/strbuf.c | 57 + 3rdparty/libconfig/strbuf.h | 39 + 3rdparty/libconfig/wincompat.h | 89 ++ Makefile.in | 13 +- conf/atcommand_athena.conf | 813 +--------- conf/battle/gm.conf | 87 - conf/char_athena.conf | 6 +- conf/groups.conf | 274 ++++ conf/help.txt | 402 +++-- conf/help2.txt | 94 -- conf/import-tmpl/atcommand_conf.txt | 0 conf/log_athena.conf | 6 +- conf/login_athena.conf | 7 +- conf/msg_athena.conf | 12 +- configure | 288 +++- configure.in | 6 +- doc/atcommands.txt | 213 +++ doc/permissions.txt | 21 + sql-files/upgrade_svn15572.sql | 3 + src/char/Makefile.in | 20 +- src/char/char.c | 22 +- src/common/Makefile.in | 30 +- src/common/conf.c | 109 ++ src/common/conf.h | 13 + src/common/showmsg.c | 16 + src/common/showmsg.h | 3 + src/login/Makefile.in | 21 +- src/login/account.h | 2 +- src/login/account_sql.c | 12 +- src/login/login.c | 24 +- src/login/login.h | 4 +- src/map/Makefile.in | 24 +- src/map/atcommand.c | 1587 ++++++++----------- src/map/atcommand.h | 30 +- src/map/battle.c | 26 - src/map/battle.h | 27 - src/map/buyingstore.c | 10 +- src/map/chat.c | 4 +- src/map/chrif.c | 8 +- src/map/clif.c | 499 ++---- src/map/clif.h | 2 - src/map/intif.c | 34 +- src/map/intif.h | 2 +- src/map/log.c | 15 +- src/map/log.h | 4 +- src/map/mail.c | 8 +- src/map/party.c | 8 +- src/map/pc.c | 144 +- src/map/pc.h | 37 +- src/map/pc_groups.c | 459 ++++++ src/map/pc_groups.h | 20 + src/map/script.c | 59 +- src/map/skill.c | 13 +- src/map/storage.c | 8 +- src/map/trade.c | 30 +- src/map/vending.c | 4 +- src/tool/Makefile.in | 14 +- vcproj-10/char-server_sql.vcxproj | 20 +- vcproj-10/char-server_sql.vcxproj.filters | 54 +- vcproj-10/login-server_sql.vcxproj | 20 +- vcproj-10/login-server_sql.vcxproj.filters | 54 +- vcproj-10/map-server_sql.vcxproj | 24 +- vcproj-10/map-server_sql.vcxproj.filters | 85 +- vcproj-10/mapcache.vcxproj | 8 +- vcproj-9/char-server_sql.vcproj | 86 +- vcproj-9/login-server_sql.vcproj | 88 +- vcproj-9/map-server_sql.vcproj | 140 +- vcproj-9/mapcache.vcproj | 12 +- 80 files changed, 11240 insertions(+), 2846 deletions(-) create mode 100644 3rdparty/libconfig/LICENSE create mode 100644 3rdparty/libconfig/Makefile.in create mode 100644 3rdparty/libconfig/grammar.c create mode 100644 3rdparty/libconfig/grammar.h create mode 100644 3rdparty/libconfig/libconfig-1.4.8 create mode 100644 3rdparty/libconfig/libconfig.c create mode 100644 3rdparty/libconfig/libconfig.h create mode 100644 3rdparty/libconfig/parsectx.h create mode 100644 3rdparty/libconfig/scanctx.c create mode 100644 3rdparty/libconfig/scanctx.h create mode 100644 3rdparty/libconfig/scanner.c create mode 100644 3rdparty/libconfig/scanner.h create mode 100644 3rdparty/libconfig/strbuf.c create mode 100644 3rdparty/libconfig/strbuf.h create mode 100644 3rdparty/libconfig/wincompat.h create mode 100644 conf/groups.conf delete mode 100644 conf/help2.txt delete mode 100644 conf/import-tmpl/atcommand_conf.txt create mode 100644 doc/atcommands.txt create mode 100644 doc/permissions.txt create mode 100644 sql-files/upgrade_svn15572.sql create mode 100644 src/common/conf.c create mode 100644 src/common/conf.h create mode 100644 src/map/pc_groups.c create mode 100644 src/map/pc_groups.h (limited to 'src/char/Makefile.in') diff --git a/3rdparty/libconfig/LICENSE b/3rdparty/libconfig/LICENSE new file mode 100644 index 000000000..94a9ed024 --- /dev/null +++ b/3rdparty/libconfig/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/3rdparty/libconfig/Makefile.in b/3rdparty/libconfig/Makefile.in new file mode 100644 index 000000000..22642413d --- /dev/null +++ b/3rdparty/libconfig/Makefile.in @@ -0,0 +1,24 @@ + +LIBCONFIG_OBJ = libconfig.o grammar.o scanctx.o scanner.o strbuf.o +LIBCONFIG_H = libconfig.h grammar.h parsectx.h scanctx.h scanner.h strbuf.h wincompat.h + +@SET_MAKE@ + +##################################################################### +.PHONY : all clean help + +all: $(LIBCONFIG_OBJ) + +clean: + rm -rf *.o + +help: + @echo "possible targets are 'all' 'clean' 'help'" + @echo "'all' - builds $(LIBCONFIG_OBJ)" + @echo "'clean' - deletes $(LIBCONFIG_OBJ)" + @echo "'help' - outputs this message" + +##################################################################### + +%.o: %.c $(LIBCONFIG_H) + @CC@ @CFLAGS@ @LDFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $< diff --git a/3rdparty/libconfig/grammar.c b/3rdparty/libconfig/grammar.c new file mode 100644 index 000000000..e95a569f6 --- /dev/null +++ b/3rdparty/libconfig/grammar.c @@ -0,0 +1,2001 @@ + +/* A Bison parser, made by GNU Bison 2.4.1. */ + +/* Skeleton implementation for Bison's Yacc-like parsers in C + + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 + Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +/* C LALR(1) parser skeleton written by Richard Stallman, by + simplifying the original so-called "semantic" parser. */ + +/* All symbols defined below should begin with yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +/* Identify Bison output. */ +#define YYBISON 1 + +/* Bison version. */ +#define YYBISON_VERSION "2.4.1" + +/* Skeleton name. */ +#define YYSKELETON_NAME "yacc.c" + +/* Pure parsers. */ +#define YYPURE 1 + +/* Push parsers. */ +#define YYPUSH 0 + +/* Pull parsers. */ +#define YYPULL 1 + +/* Using locations. */ +#define YYLSP_NEEDED 0 + +/* Substitute the variable and function names. */ +#define yyparse libconfig_yyparse +#define yylex libconfig_yylex +#define yyerror libconfig_yyerror +#define yylval libconfig_yylval +#define yychar libconfig_yychar +#define yydebug libconfig_yydebug +#define yynerrs libconfig_yynerrs + + +/* Copy the first part of user declarations. */ + +/* Line 189 of yacc.c */ +#line 32 "grammar.y" + +#include +#include +#include "libconfig.h" +#ifdef WIN32 +#include "wincompat.h" + +/* prevent warnings about redefined malloc/free in generated code: */ +#ifndef _STDLIB_H +#define _STDLIB_H +#endif + +#include +#endif +#include "parsectx.h" +#include "scanctx.h" + +/* these delcarations are provided to suppress compiler warnings */ +extern int libconfig_yylex(); +extern int libconfig_yyget_lineno(); + +static const char *err_array_elem_type = "mismatched element type in array"; +static const char *err_duplicate_setting = "duplicate setting name"; + +#define _delete(P) free((void *)(P)) + +#define IN_ARRAY() \ + (ctx->parent && (ctx->parent->type == CONFIG_TYPE_ARRAY)) + +#define IN_LIST() \ + (ctx->parent && (ctx->parent->type == CONFIG_TYPE_LIST)) + +static void capture_parse_pos(void *scanner, struct scan_context *scan_ctx, + config_setting_t *setting) +{ + setting->line = (unsigned int)libconfig_yyget_lineno(scanner); + setting->file = scanctx_current_filename(scan_ctx); +} + +#define CAPTURE_PARSE_POS(S) \ + capture_parse_pos(scanner, scan_ctx, (S)) + +void libconfig_yyerror(void *scanner, struct parse_context *ctx, + struct scan_context *scan_ctx, char const *s) +{ + if(ctx->config->error_text) return; + ctx->config->error_line = libconfig_yyget_lineno(scanner); + ctx->config->error_text = s; +} + + + +/* Line 189 of yacc.c */ +#line 134 "grammar.c" + +/* Enabling traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif + +/* Enabling verbose error messages. */ +#ifdef YYERROR_VERBOSE +# undef YYERROR_VERBOSE +# define YYERROR_VERBOSE 1 +#else +# define YYERROR_VERBOSE 0 +#endif + +/* Enabling the token table. */ +#ifndef YYTOKEN_TABLE +# define YYTOKEN_TABLE 0 +#endif + + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + TOK_BOOLEAN = 258, + TOK_INTEGER = 259, + TOK_HEX = 260, + TOK_INTEGER64 = 261, + TOK_HEX64 = 262, + TOK_FLOAT = 263, + TOK_STRING = 264, + TOK_NAME = 265, + TOK_EQUALS = 266, + TOK_NEWLINE = 267, + TOK_ARRAY_START = 268, + TOK_ARRAY_END = 269, + TOK_LIST_START = 270, + TOK_LIST_END = 271, + TOK_COMMA = 272, + TOK_GROUP_START = 273, + TOK_GROUP_END = 274, + TOK_SEMICOLON = 275, + TOK_GARBAGE = 276, + TOK_ERROR = 277 + }; +#endif +/* Tokens. */ +#define TOK_BOOLEAN 258 +#define TOK_INTEGER 259 +#define TOK_HEX 260 +#define TOK_INTEGER64 261 +#define TOK_HEX64 262 +#define TOK_FLOAT 263 +#define TOK_STRING 264 +#define TOK_NAME 265 +#define TOK_EQUALS 266 +#define TOK_NEWLINE 267 +#define TOK_ARRAY_START 268 +#define TOK_ARRAY_END 269 +#define TOK_LIST_START 270 +#define TOK_LIST_END 271 +#define TOK_COMMA 272 +#define TOK_GROUP_START 273 +#define TOK_GROUP_END 274 +#define TOK_SEMICOLON 275 +#define TOK_GARBAGE 276 +#define TOK_ERROR 277 + + + + +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +typedef union YYSTYPE +{ + +/* Line 214 of yacc.c */ +#line 85 "grammar.y" + + int ival; + long long llval; + double fval; + char *sval; + + + +/* Line 214 of yacc.c */ +#line 223 "grammar.c" +} YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +#endif + + +/* Copy the second part of user declarations. */ + + +/* Line 264 of yacc.c */ +#line 235 "grammar.c" + +#ifdef short +# undef short +#endif + +#ifdef YYTYPE_UINT8 +typedef YYTYPE_UINT8 yytype_uint8; +#else +typedef unsigned char yytype_uint8; +#endif + +#ifdef YYTYPE_INT8 +typedef YYTYPE_INT8 yytype_int8; +#elif (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +typedef signed char yytype_int8; +#else +typedef short int yytype_int8; +#endif + +#ifdef YYTYPE_UINT16 +typedef YYTYPE_UINT16 yytype_uint16; +#else +typedef unsigned short int yytype_uint16; +#endif + +#ifdef YYTYPE_INT16 +typedef YYTYPE_INT16 yytype_int16; +#else +typedef short int yytype_int16; +#endif + +#ifndef YYSIZE_T +# ifdef __SIZE_TYPE__ +# define YYSIZE_T __SIZE_TYPE__ +# elif defined size_t +# define YYSIZE_T size_t +# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +# include /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# else +# define YYSIZE_T unsigned int +# endif +#endif + +#define YYSIZE_MAXIMUM ((YYSIZE_T) -1) + +#ifndef YY_ +# if YYENABLE_NLS +# if ENABLE_NLS +# include /* INFRINGES ON USER NAME SPACE */ +# define YY_(msgid) dgettext ("bison-runtime", msgid) +# endif +# endif +# ifndef YY_ +# define YY_(msgid) msgid +# endif +#endif + +/* Suppress unused-variable warnings by "using" E. */ +#if ! defined lint || defined __GNUC__ +# define YYUSE(e) ((void) (e)) +#else +# define YYUSE(e) /* empty */ +#endif + +/* Identity function, used to suppress warnings about constant conditions. */ +#ifndef lint +# define YYID(n) (n) +#else +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static int +YYID (int yyi) +#else +static int +YYID (yyi) + int yyi; +#endif +{ + return yyi; +} +#endif + +#if ! defined yyoverflow || YYERROR_VERBOSE + +/* The parser invokes alloca or malloc; define the necessary symbols. */ + +# ifdef YYSTACK_USE_ALLOCA +# if YYSTACK_USE_ALLOCA +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# elif defined __BUILTIN_VA_ARG_INCR +# include /* INFRINGES ON USER NAME SPACE */ +# elif defined _AIX +# define YYSTACK_ALLOC __alloca +# elif defined _MSC_VER +# include /* INFRINGES ON USER NAME SPACE */ +# define alloca _alloca +# else +# define YYSTACK_ALLOC alloca +# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +# include /* INFRINGES ON USER NAME SPACE */ +# ifndef _STDLIB_H +# define _STDLIB_H 1 +# endif +# endif +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's `empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0)) +# ifndef YYSTACK_ALLOC_MAXIMUM + /* The OS might guarantee only one guard page at the bottom of the stack, + and a page size can be as small as 4096 bytes. So we cannot safely + invoke alloca (N) if N exceeds 4096. Use a slightly smaller number + to allow for a few compiler-allocated temporary stack slots. */ +# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ +# endif +# else +# define YYSTACK_ALLOC YYMALLOC +# define YYSTACK_FREE YYFREE +# ifndef YYSTACK_ALLOC_MAXIMUM +# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM +# endif +# if (defined __cplusplus && ! defined _STDLIB_H \ + && ! ((defined YYMALLOC || defined malloc) \ + && (defined YYFREE || defined free))) +# include /* INFRINGES ON USER NAME SPACE */ +# ifndef _STDLIB_H +# define _STDLIB_H 1 +# endif +# endif +# ifndef YYMALLOC +# define YYMALLOC malloc +# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# ifndef YYFREE +# define YYFREE free +# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +void free (void *); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# endif +#endif /* ! defined yyoverflow || YYERROR_VERBOSE */ + + +#if (! defined yyoverflow \ + && (! defined __cplusplus \ + || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union yyalloc +{ + yytype_int16 yyss_alloc; + YYSTYPE yyvs_alloc; +}; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ + + YYSTACK_GAP_MAXIMUM) + +/* Copy COUNT objects from FROM to TO. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if defined __GNUC__ && 1 < __GNUC__ +# define YYCOPY(To, From, Count) \ + __builtin_memcpy (To, From, (Count) * sizeof (*(From))) +# else +# define YYCOPY(To, From, Count) \ + do \ + { \ + YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (To)[yyi] = (From)[yyi]; \ + } \ + while (YYID (0)) +# endif +# endif + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack_alloc, Stack) \ + do \ + { \ + YYSIZE_T yynewbytes; \ + YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ + Stack = &yyptr->Stack_alloc; \ + yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / sizeof (*yyptr); \ + } \ + while (YYID (0)) + +#endif + +/* YYFINAL -- State number of the termination state. */ +#define YYFINAL 6 +/* YYLAST -- Last index in YYTABLE. */ +#define YYLAST 35 + +/* YYNTOKENS -- Number of terminals. */ +#define YYNTOKENS 23 +/* YYNNTS -- Number of nonterminals. */ +#define YYNNTS 20 +/* YYNRULES -- Number of rules. */ +#define YYNRULES 39 +/* YYNRULES -- Number of states. */ +#define YYNSTATES 47 + +/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ +#define YYUNDEFTOK 2 +#define YYMAXUTOK 277 + +#define YYTRANSLATE(YYX) \ + ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) + +/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ +static const yytype_uint8 yytranslate[] = +{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22 +}; + +#if YYDEBUG +/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in + YYRHS. */ +static const yytype_uint8 yyprhs[] = +{ + 0, 0, 3, 4, 6, 8, 11, 12, 14, 15, + 17, 19, 20, 26, 27, 32, 33, 38, 40, 42, + 44, 46, 48, 51, 53, 55, 57, 59, 61, 63, + 65, 67, 71, 72, 74, 76, 80, 81, 83, 84 +}; + +/* YYRHS -- A `-1'-separated list of the rules' RHS. */ +static const yytype_int8 yyrhs[] = +{ + 24, 0, -1, -1, 25, -1, 28, -1, 25, 28, + -1, -1, 25, -1, -1, 20, -1, 17, -1, -1, + 10, 29, 11, 34, 27, -1, -1, 13, 31, 40, + 14, -1, -1, 15, 33, 38, 16, -1, 36, -1, + 30, -1, 32, -1, 41, -1, 9, -1, 35, 9, + -1, 3, -1, 4, -1, 6, -1, 5, -1, 7, + -1, 8, -1, 35, -1, 34, -1, 37, 17, 34, + -1, -1, 37, -1, 36, -1, 39, 17, 36, -1, + -1, 39, -1, -1, 18, 42, 26, 19, -1 +}; + +/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ +static const yytype_uint16 yyrline[] = +{ + 0, 100, 100, 102, 106, 107, 110, 112, 115, 117, + 118, 123, 122, 142, 141, 165, 164, 187, 188, 189, + 190, 194, 195, 199, 219, 241, 263, 285, 307, 325, + 353, 354, 357, 359, 363, 364, 367, 369, 374, 373 +}; +#endif + +#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE +/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. + First, the terminals, then, starting at YYNTOKENS, nonterminals. */ +static const char *const yytname[] = +{ + "$end", "error", "$undefined", "TOK_BOOLEAN", "TOK_INTEGER", "TOK_HEX", + "TOK_INTEGER64", "TOK_HEX64", "TOK_FLOAT", "TOK_STRING", "TOK_NAME", + "TOK_EQUALS", "TOK_NEWLINE", "TOK_ARRAY_START", "TOK_ARRAY_END", + "TOK_LIST_START", "TOK_LIST_END", "TOK_COMMA", "TOK_GROUP_START", + "TOK_GROUP_END", "TOK_SEMICOLON", "TOK_GARBAGE", "TOK_ERROR", "$accept", + "configuration", "setting_list", "setting_list_optional", + "setting_terminator", "setting", "$@1", "array", "$@2", "list", "$@3", + "value", "string", "simple_value", "value_list", "value_list_optional", + "simple_value_list", "simple_value_list_optional", "group", "$@4", 0 +}; +#endif + +# ifdef YYPRINT +/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to + token YYLEX-NUM. */ +static const yytype_uint16 yytoknum[] = +{ + 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, + 275, 276, 277 +}; +# endif + +/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +static const yytype_uint8 yyr1[] = +{ + 0, 23, 24, 24, 25, 25, 26, 26, 27, 27, + 27, 29, 28, 31, 30, 33, 32, 34, 34, 34, + 34, 35, 35, 36, 36, 36, 36, 36, 36, 36, + 37, 37, 38, 38, 39, 39, 40, 40, 42, 41 +}; + +/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ +static const yytype_uint8 yyr2[] = +{ + 0, 2, 0, 1, 1, 2, 0, 1, 0, 1, + 1, 0, 5, 0, 4, 0, 4, 1, 1, 1, + 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, + 1, 3, 0, 1, 1, 3, 0, 1, 0, 4 +}; + +/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state + STATE-NUM when YYTABLE doesn't specify something else to do. Zero + means the default is an error. */ +static const yytype_uint8 yydefact[] = +{ + 2, 11, 0, 3, 4, 0, 1, 5, 0, 23, + 24, 26, 25, 27, 28, 21, 13, 15, 38, 18, + 19, 8, 29, 17, 20, 36, 32, 6, 10, 9, + 12, 22, 34, 37, 0, 30, 33, 0, 7, 0, + 0, 14, 0, 16, 39, 35, 31 +}; + +/* YYDEFGOTO[NTERM-NUM]. */ +static const yytype_int8 yydefgoto[] = +{ + -1, 2, 3, 39, 30, 4, 5, 19, 25, 20, + 26, 21, 22, 23, 36, 37, 33, 34, 24, 27 +}; + +/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + STATE-NUM. */ +#define YYPACT_NINF -26 +static const yytype_int8 yypact[] = +{ + -8, -26, 12, -8, -26, 5, -26, -26, 0, -26, + -26, -26, -26, -26, -26, -26, -26, -26, -26, -26, + -26, -6, 10, -26, -26, 23, 0, -8, -26, -26, + -26, -26, -26, 3, 7, -26, 6, 8, -8, 14, + 23, -26, 0, -26, -26, -26, -26 +}; + +/* YYPGOTO[NTERM-NUM]. */ +static const yytype_int8 yypgoto[] = +{ + -26, -26, -5, -26, -26, -3, -26, -26, -26, -26, + -26, -25, -26, -15, -26, -26, -26, -26, -26, -26 +}; + +/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If + positive, shift that token. If negative, reduce the rule which + number is the opposite. If zero, do what YYDEFACT says. + If YYTABLE_NINF, syntax error. */ +#define YYTABLE_NINF -1 +static const yytype_uint8 yytable[] = +{ + 7, 35, 1, 9, 10, 11, 12, 13, 14, 15, + 32, 28, 6, 16, 29, 17, 8, 46, 18, 31, + 40, 41, 38, 42, 43, 45, 9, 10, 11, 12, + 13, 14, 15, 44, 0, 7 +}; + +static const yytype_int8 yycheck[] = +{ + 3, 26, 10, 3, 4, 5, 6, 7, 8, 9, + 25, 17, 0, 13, 20, 15, 11, 42, 18, 9, + 17, 14, 27, 17, 16, 40, 3, 4, 5, 6, + 7, 8, 9, 19, -1, 38 +}; + +/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing + symbol of state STATE-NUM. */ +static const yytype_uint8 yystos[] = +{ + 0, 10, 24, 25, 28, 29, 0, 28, 11, 3, + 4, 5, 6, 7, 8, 9, 13, 15, 18, 30, + 32, 34, 35, 36, 41, 31, 33, 42, 17, 20, + 27, 9, 36, 39, 40, 34, 37, 38, 25, 26, + 17, 14, 17, 16, 19, 36, 34 +}; + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY (-2) +#define YYEOF 0 + +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrorlab + + +/* Like YYERROR except do call yyerror. This remains here temporarily + to ease the transition to the new meaning of YYERROR, for GCC. + Once GCC version 2 has supplanted version 1, this can go. */ + +#define YYFAIL goto yyerrlab + +#define YYRECOVERING() (!!yyerrstatus) + +#define YYBACKUP(Token, Value) \ +do \ + if (yychar == YYEMPTY && yylen == 1) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + yytoken = YYTRANSLATE (yychar); \ + YYPOPSTACK (1); \ + goto yybackup; \ + } \ + else \ + { \ + yyerror (scanner, ctx, scan_ctx, YY_("syntax error: cannot back up")); \ + YYERROR; \ + } \ +while (YYID (0)) + + +#define YYTERROR 1 +#define YYERRCODE 256 + + +/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. + If N is 0, then set CURRENT to the empty location which ends + the previous symbol: RHS[0] (always defined). */ + +#define YYRHSLOC(Rhs, K) ((Rhs)[K]) +#ifndef YYLLOC_DEFAULT +# define YYLLOC_DEFAULT(Current, Rhs, N) \ + do \ + if (YYID (N)) \ + { \ + (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ + (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ + (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ + (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ + } \ + else \ + { \ + (Current).first_line = (Current).last_line = \ + YYRHSLOC (Rhs, 0).last_line; \ + (Current).first_column = (Current).last_column = \ + YYRHSLOC (Rhs, 0).last_column; \ + } \ + while (YYID (0)) +#endif + + +/* YY_LOCATION_PRINT -- Print the location on the stream. + This macro was not mandated originally: define only if we know + we won't break user code: when these are the locations we know. */ + +#ifndef YY_LOCATION_PRINT +# if YYLTYPE_IS_TRIVIAL +# define YY_LOCATION_PRINT(File, Loc) \ + fprintf (File, "%d.%d-%d.%d", \ + (Loc).first_line, (Loc).first_column, \ + (Loc).last_line, (Loc).last_column) +# else +# define YY_LOCATION_PRINT(File, Loc) ((void) 0) +# endif +#endif + + +/* YYLEX -- calling `yylex' with the right arguments. */ + +#ifdef YYLEX_PARAM +# define YYLEX yylex (&yylval, YYLEX_PARAM) +#else +# define YYLEX yylex (&yylval, scanner) +#endif + +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (YYID (0)) + +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ +do { \ + if (yydebug) \ + { \ + YYFPRINTF (stderr, "%s ", Title); \ + yy_symbol_print (stderr, \ + Type, Value, scanner, ctx, scan_ctx); \ + YYFPRINTF (stderr, "\n"); \ + } \ +} while (YYID (0)) + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +/*ARGSUSED*/ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, void *scanner, struct parse_context *ctx, struct scan_context *scan_ctx) +#else +static void +yy_symbol_value_print (yyoutput, yytype, yyvaluep, scanner, ctx, scan_ctx) + FILE *yyoutput; + int yytype; + YYSTYPE const * const yyvaluep; + void *scanner; + struct parse_context *ctx; + struct scan_context *scan_ctx; +#endif +{ + if (!yyvaluep) + return; + YYUSE (scanner); + YYUSE (ctx); + YYUSE (scan_ctx); +# ifdef YYPRINT + if (yytype < YYNTOKENS) + YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); +# else + YYUSE (yyoutput); +# endif + switch (yytype) + { + default: + break; + } +} + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, void *scanner, struct parse_context *ctx, struct scan_context *scan_ctx) +#else +static void +yy_symbol_print (yyoutput, yytype, yyvaluep, scanner, ctx, scan_ctx) + FILE *yyoutput; + int yytype; + YYSTYPE const * const yyvaluep; + void *scanner; + struct parse_context *ctx; + struct scan_context *scan_ctx; +#endif +{ + if (yytype < YYNTOKENS) + YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); + else + YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); + + yy_symbol_value_print (yyoutput, yytype, yyvaluep, scanner, ctx, scan_ctx); + YYFPRINTF (yyoutput, ")"); +} + +/*------------------------------------------------------------------. +| yy_stack_print -- Print the state stack from its BOTTOM up to its | +| TOP (included). | +`------------------------------------------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) +#else +static void +yy_stack_print (yybottom, yytop) + yytype_int16 *yybottom; + yytype_int16 *yytop; +#endif +{ + YYFPRINTF (stderr, "Stack now"); + for (; yybottom <= yytop; yybottom++) + { + int yybot = *yybottom; + YYFPRINTF (stderr, " %d", yybot); + } + YYFPRINTF (stderr, "\n"); +} + +# define YY_STACK_PRINT(Bottom, Top) \ +do { \ + if (yydebug) \ + yy_stack_print ((Bottom), (Top)); \ +} while (YYID (0)) + + +/*------------------------------------------------. +| Report that the YYRULE is going to be reduced. | +`------------------------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_reduce_print (YYSTYPE *yyvsp, int yyrule, void *scanner, struct parse_context *ctx, struct scan_context *scan_ctx) +#else +static void +yy_reduce_print (yyvsp, yyrule, scanner, ctx, scan_ctx) + YYSTYPE *yyvsp; + int yyrule; + void *scanner; + struct parse_context *ctx; + struct scan_context *scan_ctx; +#endif +{ + int yynrhs = yyr2[yyrule]; + int yyi; + unsigned long int yylno = yyrline[yyrule]; + YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", + yyrule - 1, yylno); + /* The symbols being reduced. */ + for (yyi = 0; yyi < yynrhs; yyi++) + { + YYFPRINTF (stderr, " $%d = ", yyi + 1); + yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi], + &(yyvsp[(yyi + 1) - (yynrhs)]) + , scanner, ctx, scan_ctx); + YYFPRINTF (stderr, "\n"); + } +} + +# define YY_REDUCE_PRINT(Rule) \ +do { \ + if (yydebug) \ + yy_reduce_print (yyvsp, Rule, scanner, ctx, scan_ctx); \ +} while (YYID (0)) + +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) +# define YY_STACK_PRINT(Bottom, Top) +# define YY_REDUCE_PRINT(Rule) +#endif /* !YYDEBUG */ + + +/* YYINITDEPTH -- initial size of the parser's stacks. */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). + + Do not make this value too large; the results are undefined if + YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + + + +#if YYERROR_VERBOSE + +# ifndef yystrlen +# if defined __GLIBC__ && defined _STRING_H +# define yystrlen strlen +# else +/* Return the length of YYSTR. */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static YYSIZE_T +yystrlen (const char *yystr) +#else +static YYSIZE_T +yystrlen (yystr) + const char *yystr; +#endif +{ + YYSIZE_T yylen; + for (yylen = 0; yystr[yylen]; yylen++) + continue; + return yylen; +} +# endif +# endif + +# ifndef yystpcpy +# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE +# define yystpcpy stpcpy +# else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in + YYDEST. */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static char * +yystpcpy (char *yydest, const char *yysrc) +#else +static char * +yystpcpy (yydest, yysrc) + char *yydest; + const char *yysrc; +#endif +{ + char *yyd = yydest; + const char *yys = yysrc; + + while ((*yyd++ = *yys++) != '\0') + continue; + + return yyd - 1; +} +# endif +# endif + +# ifndef yytnamerr +/* Copy to YYRES the contents of YYSTR after stripping away unnecessary + quotes and backslashes, so that it's suitable for yyerror. The + heuristic is that double-quoting is unnecessary unless the string + contains an apostrophe, a comma, or backslash (other than + backslash-backslash). YYSTR is taken from yytname. If YYRES is + null, do not copy; instead, return the length of what the result + would have been. */ +static YYSIZE_T +yytnamerr (char *yyres, const char *yystr) +{ + if (*yystr == '"') + { + YYSIZE_T yyn = 0; + char const *yyp = yystr; + + for (;;) + switch (*++yyp) + { + case '\'': + case ',': + goto do_not_strip_quotes; + + case '\\': + if (*++yyp != '\\') + goto do_not_strip_quotes; + /* Fall through. */ + default: + if (yyres) + yyres[yyn] = *yyp; + yyn++; + break; + + case '"': + if (yyres) + yyres[yyn] = '\0'; + return yyn; + } + do_not_strip_quotes: ; + } + + if (! yyres) + return yystrlen (yystr); + + return yystpcpy (yyres, yystr) - yyres; +} +# endif + +/* Copy into YYRESULT an error message about the unexpected token + YYCHAR while in state YYSTATE. Return the number of bytes copied, + including the terminating null byte. If YYRESULT is null, do not + copy anything; just return the number of bytes that would be + copied. As a special case, return 0 if an ordinary "syntax error" + message will do. Return YYSIZE_MAXIMUM if overflow occurs during + size calculation. */ +static YYSIZE_T +yysyntax_error (char *yyresult, int yystate, int yychar) +{ + int yyn = yypact[yystate]; + + if (! (YYPACT_NINF < yyn && yyn <= YYLAST)) + return 0; + else + { + int yytype = YYTRANSLATE (yychar); + YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]); + YYSIZE_T yysize = yysize0; + YYSIZE_T yysize1; + int yysize_overflow = 0; + enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; + char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; + int yyx; + +# if 0 + /* This is so xgettext sees the translatable formats that are + constructed on the fly. */ + YY_("syntax error, unexpected %s"); + YY_("syntax error, unexpected %s, expecting %s"); + YY_("syntax error, unexpected %s, expecting %s or %s"); + YY_("syntax error, unexpected %s, expecting %s or %s or %s"); + YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"); +# endif + char *yyfmt; + char const *yyf; + static char const yyunexpected[] = "syntax error, unexpected %s"; + static char const yyexpecting[] = ", expecting %s"; + static char const yyor[] = " or %s"; + char yyformat[sizeof yyunexpected + + sizeof yyexpecting - 1 + + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2) + * (sizeof yyor - 1))]; + char const *yyprefix = yyexpecting; + + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. */ + int yyxbegin = yyn < 0 ? -yyn : 0; + + /* Stay within bounds of both yycheck and yytname. */ + int yychecklim = YYLAST - yyn + 1; + int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; + int yycount = 1; + + yyarg[0] = yytname[yytype]; + yyfmt = yystpcpy (yyformat, yyunexpected); + + for (yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) + { + if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) + { + yycount = 1; + yysize = yysize0; + yyformat[sizeof yyunexpected - 1] = '\0'; + break; + } + yyarg[yycount++] = yytname[yyx]; + yysize1 = yysize + yytnamerr (0, yytname[yyx]); + yysize_overflow |= (yysize1 < yysize); + yysize = yysize1; + yyfmt = yystpcpy (yyfmt, yyprefix); + yyprefix = yyor; + } + + yyf = YY_(yyformat); + yysize1 = yysize + yystrlen (yyf); + yysize_overflow |= (yysize1 < yysize); + yysize = yysize1; + + if (yysize_overflow) + return YYSIZE_MAXIMUM; + + if (yyresult) + { + /* Avoid sprintf, as that infringes on the user's name space. + Don't have undefined behavior even if the translation + produced a string with the wrong number of "%s"s. */ + char *yyp = yyresult; + int yyi = 0; + while ((*yyp = *yyf) != '\0') + { + if (*yyp == '%' && yyf[1] == 's' && yyi < yycount) + { + yyp += yytnamerr (yyp, yyarg[yyi++]); + yyf += 2; + } + else + { + yyp++; + yyf++; + } + } + } + return yysize; + } +} +#endif /* YYERROR_VERBOSE */ + + +/*-----------------------------------------------. +| Release the memory associated to this symbol. | +`-----------------------------------------------*/ + +/*ARGSUSED*/ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, void *scanner, struct parse_context *ctx, struct scan_context *scan_ctx) +#else +static void +yydestruct (yymsg, yytype, yyvaluep, scanner, ctx, scan_ctx) + const char *yymsg; + int yytype; + YYSTYPE *yyvaluep; + void *scanner; + struct parse_context *ctx; + struct scan_context *scan_ctx; +#endif +{ + YYUSE (yyvaluep); + YYUSE (scanner); + YYUSE (ctx); + YYUSE (scan_ctx); + + if (!yymsg) + yymsg = "Deleting"; + YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); + + switch (yytype) + { + + default: + break; + } +} + +/* Prevent warnings from -Wmissing-prototypes. */ +#ifdef YYPARSE_PARAM +#if defined __STDC__ || defined __cplusplus +int yyparse (void *YYPARSE_PARAM); +#else +int yyparse (); +#endif +#else /* ! YYPARSE_PARAM */ +#if defined __STDC__ || defined __cplusplus +int yyparse (void *scanner, struct parse_context *ctx, struct scan_context *scan_ctx); +#else +int yyparse (); +#endif +#endif /* ! YYPARSE_PARAM */ + + + + + +/*-------------------------. +| yyparse or yypush_parse. | +`-------------------------*/ + +#ifdef YYPARSE_PARAM +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +int +yyparse (void *YYPARSE_PARAM) +#else +int +yyparse (YYPARSE_PARAM) + void *YYPARSE_PARAM; +#endif +#else /* ! YYPARSE_PARAM */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +int +yyparse (void *scanner, struct parse_context *ctx, struct scan_context *scan_ctx) +#else +int +yyparse (scanner, ctx, scan_ctx) + void *scanner; + struct parse_context *ctx; + struct scan_context *scan_ctx; +#endif +#endif +{ +/* The lookahead symbol. */ +int yychar; + +/* The semantic value of the lookahead symbol. */ +YYSTYPE yylval; + + /* Number of syntax errors so far. */ + int yynerrs; + + int yystate; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; + + /* The stacks and their tools: + `yyss': related to states. + `yyvs': related to semantic values. + + Refer to the stacks thru separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* The state stack. */ + yytype_int16 yyssa[YYINITDEPTH]; + yytype_int16 *yyss; + yytype_int16 *yyssp; + + /* The semantic value stack. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs; + YYSTYPE *yyvsp; + + YYSIZE_T yystacksize; + + int yyn; + int yyresult; + /* Lookahead token as an internal (translated) token number. */ + int yytoken; + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; + +#if YYERROR_VERBOSE + /* Buffer for error messages, and its allocated size. */ + char yymsgbuf[128]; + char *yymsg = yymsgbuf; + YYSIZE_T yymsg_alloc = sizeof yymsgbuf; +#endif + +#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) + + /* The number of symbols on the RHS of the reduced rule. + Keep to zero when no symbol should be popped. */ + int yylen = 0; + + yytoken = 0; + yyss = yyssa; + yyvs = yyvsa; + yystacksize = YYINITDEPTH; + + YYDPRINTF ((stderr, "Starting parse\n")); + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + + /* Initialize stack pointers. + Waste one element of value and location stack + so that they stay on the same level as the state stack. + The wasted elements are never initialized. */ + yyssp = yyss; + yyvsp = yyvs; + + goto yysetstate; + +/*------------------------------------------------------------. +| yynewstate -- Push a new state, which is found in yystate. | +`------------------------------------------------------------*/ + yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. So pushing a state here evens the stacks. */ + yyssp++; + + yysetstate: + *yyssp = yystate; + + if (yyss + yystacksize - 1 <= yyssp) + { + /* Get the current used size of the three stacks, in elements. */ + YYSIZE_T yysize = yyssp - yyss + 1; + +#ifdef yyoverflow + { + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + YYSTYPE *yyvs1 = yyvs; + yytype_int16 *yyss1 = yyss; + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. This used to be a + conditional around just the two extra args, but that might + be undefined if yyoverflow is a macro. */ + yyoverflow (YY_("memory exhausted"), + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + &yystacksize); + + yyss = yyss1; + yyvs = yyvs1; + } +#else /* no yyoverflow */ +# ifndef YYSTACK_RELOCATE + goto yyexhaustedlab; +# else + /* Extend the stack our own way. */ + if (YYMAXDEPTH <= yystacksize) + goto yyexhaustedlab; + yystacksize *= 2; + if (YYMAXDEPTH < yystacksize) + yystacksize = YYMAXDEPTH; + + { + yytype_int16 *yyss1 = yyss; + union yyalloc *yyptr = + (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); + if (! yyptr) + goto yyexhaustedlab; + YYSTACK_RELOCATE (yyss_alloc, yyss); + YYSTACK_RELOCATE (yyvs_alloc, yyvs); +# undef YYSTACK_RELOCATE + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); + } +# endif +#endif /* no yyoverflow */ + + yyssp = yyss + yysize - 1; + yyvsp = yyvs + yysize - 1; + + YYDPRINTF ((stderr, "Stack size increased to %lu\n", + (unsigned long int) yystacksize)); + + if (yyss + yystacksize - 1 <= yyssp) + YYABORT; + } + + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + + if (yystate == YYFINAL) + YYACCEPT; + + goto yybackup; + +/*-----------. +| yybackup. | +`-----------*/ +yybackup: + + /* Do appropriate processing given the current state. Read a + lookahead token if we need one and don't already have one. */ + + /* First try to decide what to do without reference to lookahead token. */ + yyn = yypact[yystate]; + if (yyn == YYPACT_NINF) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ + if (yychar == YYEMPTY) + { + YYDPRINTF ((stderr, "Reading a token: ")); + yychar = YYLEX; + } + + if (yychar <= YYEOF) + { + yychar = yytoken = YYEOF; + YYDPRINTF ((stderr, "Now at end of input.\n")); + } + else + { + yytoken = YYTRANSLATE (yychar); + YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); + } + + /* If the proper action on seeing token YYTOKEN is to reduce or to + detect an error, take that action. */ + yyn += yytoken; + if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) + goto yydefault; + yyn = yytable[yyn]; + if (yyn <= 0) + { + if (yyn == 0 || yyn == YYTABLE_NINF) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus) + yyerrstatus--; + + /* Shift the lookahead token. */ + YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); + + /* Discard the shifted token. */ + yychar = YYEMPTY; + + yystate = yyn; + *++yyvsp = yylval; + + goto yynewstate; + + +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +yydefault: + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + +/*-----------------------------. +| yyreduce -- Do a reduction. | +`-----------------------------*/ +yyreduce: + /* yyn is the number of a rule to reduce with. */ + yylen = yyr2[yyn]; + + /* If YYLEN is nonzero, implement the default value of the action: + `$$ = $1'. + + Otherwise, the following line sets YYVAL to garbage. + This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + yyval = yyvsp[1-yylen]; + + + YY_REDUCE_PRINT (yyn); + switch (yyn) + { + case 11: + +/* Line 1455 of yacc.c */ +#line 123 "grammar.y" + { + ctx->setting = config_setting_add(ctx->parent, (yyvsp[(1) - (1)].sval), CONFIG_TYPE_NONE); + + if(ctx->setting == NULL) + { + libconfig_yyerror(scanner, ctx, scan_ctx, err_duplicate_setting); + YYABORT; + } + else + { + CAPTURE_PARSE_POS(ctx->setting); + } + } + break; + + case 13: + +/* Line 1455 of yacc.c */ +#line 142 "grammar.y" + { + if(IN_LIST()) + { + ctx->parent = config_setting_add(ctx->parent, NULL, CONFIG_TYPE_ARRAY); + CAPTURE_PARSE_POS(ctx->parent); + } + else + { + ctx->setting->type = CONFIG_TYPE_ARRAY; + ctx->parent = ctx->setting; + ctx->setting = NULL; + } + } + break; + + case 14: + +/* Line 1455 of yacc.c */ +#line 157 "grammar.y" + { + if(ctx->parent) + ctx->parent = ctx->parent->parent; + } + break; + + case 15: + +/* Line 1455 of yacc.c */ +#line 165 "grammar.y" + { + if(IN_LIST()) + { + ctx->parent = config_setting_add(ctx->parent, NULL, CONFIG_TYPE_LIST); + CAPTURE_PARSE_POS(ctx->parent); + } + else + { + ctx->setting->type = CONFIG_TYPE_LIST; + ctx->parent = ctx->setting; + ctx->setting = NULL; + } + } + break; + + case 16: + +/* Line 1455 of yacc.c */ +#line 180 "grammar.y" + { + if(ctx->parent) + ctx->parent = ctx->parent->parent; + } + break; + + case 21: + +/* Line 1455 of yacc.c */ +#line 194 "grammar.y" + { parsectx_append_string(ctx, (yyvsp[(1) - (1)].sval)); free((yyvsp[(1) - (1)].sval)); } + break; + + case 22: + +/* Line 1455 of yacc.c */ +#line 195 "grammar.y" + { parsectx_append_string(ctx, (yyvsp[(2) - (2)].sval)); free((yyvsp[(2) - (2)].sval)); } + break; + + case 23: + +/* Line 1455 of yacc.c */ +#line 200 "grammar.y" + { + if(IN_ARRAY() || IN_LIST()) + { + config_setting_t *e = config_setting_set_bool_elem(ctx->parent, -1, + (int)(yyvsp[(1) - (1)].ival)); + + if(! e) + { + libconfig_yyerror(scanner, ctx, scan_ctx, err_array_elem_type); + YYABORT; + } + else + { + CAPTURE_PARSE_POS(e); + } + } + else + config_setting_set_bool(ctx->setting, (int)(yyvsp[(1) - (1)].ival)); + } + break; + + case 24: + +/* Line 1455 of yacc.c */ +#line 220 "grammar.y" + { + if(IN_ARRAY() || IN_LIST()) + { + config_setting_t *e = config_setting_set_int_elem(ctx->parent, -1, (yyvsp[(1) - (1)].ival)); + if(! e) + { + libconfig_yyerror(scanner, ctx, scan_ctx, err_array_elem_type); + YYABORT; + } + else + { + config_setting_set_format(e, CONFIG_FORMAT_DEFAULT); + CAPTURE_PARSE_POS(e); + } + } + else + { + config_setting_set_int(ctx->setting, (yyvsp[(1) - (1)].ival)); + config_setting_set_format(ctx->setting, CONFIG_FORMAT_DEFAULT); + } + } + break; + + case 25: + +/* Line 1455 of yacc.c */ +#line 242 "grammar.y" + { + if(IN_ARRAY() || IN_LIST()) + { + config_setting_t *e = config_setting_set_int64_elem(ctx->parent, -1, (yyvsp[(1) - (1)].llval)); + if(! e) + { + libconfig_yyerror(scanner, ctx, scan_ctx, err_array_elem_type); + YYABORT; + } + else + { + config_setting_set_format(e, CONFIG_FORMAT_DEFAULT); + CAPTURE_PARSE_POS(e); + } + } + else + { + config_setting_set_int64(ctx->setting, (yyvsp[(1) - (1)].llval)); + config_setting_set_format(ctx->setting, CONFIG_FORMAT_DEFAULT); + } + } + break; + + case 26: + +/* Line 1455 of yacc.c */ +#line 264 "grammar.y" + { + if(IN_ARRAY() || IN_LIST()) + { + config_setting_t *e = config_setting_set_int_elem(ctx->parent, -1, (yyvsp[(1) - (1)].ival)); + if(! e) + { + libconfig_yyerror(scanner, ctx, scan_ctx, err_array_elem_type); + YYABORT; + } + else + { + config_setting_set_format(e, CONFIG_FORMAT_HEX); + CAPTURE_PARSE_POS(e); + } + } + else + { + config_setting_set_int(ctx->setting, (yyvsp[(1) - (1)].ival)); + config_setting_set_format(ctx->setting, CONFIG_FORMAT_HEX); + } + } + break; + + case 27: + +/* Line 1455 of yacc.c */ +#line 286 "grammar.y" + { + if(IN_ARRAY() || IN_LIST()) + { + config_setting_t *e = config_setting_set_int64_elem(ctx->parent, -1, (yyvsp[(1) - (1)].llval)); + if(! e) + { + libconfig_yyerror(scanner, ctx, scan_ctx, err_array_elem_type); + YYABORT; + } + else + { + config_setting_set_format(e, CONFIG_FORMAT_HEX); + CAPTURE_PARSE_POS(e); + } + } + else + { + config_setting_set_int64(ctx->setting, (yyvsp[(1) - (1)].llval)); + config_setting_set_format(ctx->setting, CONFIG_FORMAT_HEX); + } + } + break; + + case 28: + +/* Line 1455 of yacc.c */ +#line 308 "grammar.y" + { + if(IN_ARRAY() || IN_LIST()) + { + config_setting_t *e = config_setting_set_float_elem(ctx->parent, -1, (yyvsp[(1) - (1)].fval)); + if(! e) + { + libconfig_yyerror(scanner, ctx, scan_ctx, err_array_elem_type); + YYABORT; + } + else + { + CAPTURE_PARSE_POS(e); + } + } + else + config_setting_set_float(ctx->setting, (yyvsp[(1) - (1)].fval)); + } + break; + + case 29: + +/* Line 1455 of yacc.c */ +#line 326 "grammar.y" + { + if(IN_ARRAY() || IN_LIST()) + { + const char *s = parsectx_take_string(ctx); + config_setting_t *e = config_setting_set_string_elem(ctx->parent, -1, s); + _delete(s); + + if(! e) + { + libconfig_yyerror(scanner, ctx, scan_ctx, err_array_elem_type); + YYABORT; + } + else + { + CAPTURE_PARSE_POS(e); + } + } + else + { + const char *s = parsectx_take_string(ctx); + config_setting_set_string(ctx->setting, s); + _delete(s); + } + } + break; + + case 38: + +/* Line 1455 of yacc.c */ +#line 374 "grammar.y" + { + if(IN_LIST()) + { + ctx->parent = config_setting_add(ctx->parent, NULL, CONFIG_TYPE_GROUP); + CAPTURE_PARSE_POS(ctx->parent); + } + else + { + ctx->setting->type = CONFIG_TYPE_GROUP; + ctx->parent = ctx->setting; + ctx->setting = NULL; + } + } + break; + + case 39: + +/* Line 1455 of yacc.c */ +#line 389 "grammar.y" + { + if(ctx->parent) + ctx->parent = ctx->parent->parent; + } + break; + + + +/* Line 1455 of yacc.c */ +#line 1788 "grammar.c" + default: break; + } + YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); + + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + + *++yyvsp = yyval; + + /* Now `shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; + if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTOKENS]; + + goto yynewstate; + + +/*------------------------------------. +| yyerrlab -- here on detecting error | +`------------------------------------*/ +yyerrlab: + /* If not already recovering from an error, report this error. */ + if (!yyerrstatus) + { + ++yynerrs; +#if ! YYERROR_VERBOSE + yyerror (scanner, ctx, scan_ctx, YY_("syntax error")); +#else + { + YYSIZE_T yysize = yysyntax_error (0, yystate, yychar); + if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM) + { + YYSIZE_T yyalloc = 2 * yysize; + if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM)) + yyalloc = YYSTACK_ALLOC_MAXIMUM; + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); + yymsg = (char *) YYSTACK_ALLOC (yyalloc); + if (yymsg) + yymsg_alloc = yyalloc; + else + { + yymsg = yymsgbuf; + yymsg_alloc = sizeof yymsgbuf; + } + } + + if (0 < yysize && yysize <= yymsg_alloc) + { + (void) yysyntax_error (yymsg, yystate, yychar); + yyerror (scanner, ctx, scan_ctx, yymsg); + } + else + { + yyerror (scanner, ctx, scan_ctx, YY_("syntax error")); + if (yysize != 0) + goto yyexhaustedlab; + } + } +#endif + } + + + + if (yyerrstatus == 3) + { + /* If just tried and failed to reuse lookahead token after an + error, discard it. */ + + if (yychar <= YYEOF) + { + /* Return failure if at end of input. */ + if (yychar == YYEOF) + YYABORT; + } + else + { + yydestruct ("Error: discarding", + yytoken, &yylval, scanner, ctx, scan_ctx); + yychar = YYEMPTY; + } + } + + /* Else will try to reuse lookahead token after shifting the error + token. */ + goto yyerrlab1; + + +/*---------------------------------------------------. +| yyerrorlab -- error raised explicitly by YYERROR. | +`---------------------------------------------------*/ +yyerrorlab: + + /* Pacify compilers like GCC when the user code never invokes + YYERROR and the label yyerrorlab therefore never appears in user + code. */ + if (/*CONSTCOND*/ 0) + goto yyerrorlab; + + /* Do not reclaim the symbols of the rule which action triggered + this YYERROR. */ + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + yystate = *yyssp; + goto yyerrlab1; + + +/*-------------------------------------------------------------. +| yyerrlab1 -- common code for both syntax error and YYERROR. | +`-------------------------------------------------------------*/ +yyerrlab1: + yyerrstatus = 3; /* Each real token shifted decrements this. */ + + for (;;) + { + yyn = yypact[yystate]; + if (yyn != YYPACT_NINF) + { + yyn += YYTERROR; + if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) + { + yyn = yytable[yyn]; + if (0 < yyn) + break; + } + } + + /* Pop the current state because it cannot handle the error token. */ + if (yyssp == yyss) + YYABORT; + + + yydestruct ("Error: popping", + yystos[yystate], yyvsp, scanner, ctx, scan_ctx); + YYPOPSTACK (1); + yystate = *yyssp; + YY_STACK_PRINT (yyss, yyssp); + } + + *++yyvsp = yylval; + + + /* Shift the error token. */ + YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); + + yystate = yyn; + goto yynewstate; + + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +yyacceptlab: + yyresult = 0; + goto yyreturn; + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +yyabortlab: + yyresult = 1; + goto yyreturn; + +#if !defined(yyoverflow) || YYERROR_VERBOSE +/*-------------------------------------------------. +| yyexhaustedlab -- memory exhaustion comes here. | +`-------------------------------------------------*/ +yyexhaustedlab: + yyerror (scanner, ctx, scan_ctx, YY_("memory exhausted")); + yyresult = 2; + /* Fall through. */ +#endif + +yyreturn: + if (yychar != YYEMPTY) + yydestruct ("Cleanup: discarding lookahead", + yytoken, &yylval, scanner, ctx, scan_ctx); + /* Do not reclaim the symbols of the rule which action triggered + this YYABORT or YYACCEPT. */ + YYPOPSTACK (yylen); + YY_STACK_PRINT (yyss, yyssp); + while (yyssp != yyss) + { + yydestruct ("Cleanup: popping", + yystos[*yyssp], yyvsp, scanner, ctx, scan_ctx); + YYPOPSTACK (1); + } +#ifndef yyoverflow + if (yyss != yyssa) + YYSTACK_FREE (yyss); +#endif +#if YYERROR_VERBOSE + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); +#endif + /* Make sure YYID is used. */ + return YYID (yyresult); +} + + + +/* Line 1675 of yacc.c */ +#line 395 "grammar.y" + + diff --git a/3rdparty/libconfig/grammar.h b/3rdparty/libconfig/grammar.h new file mode 100644 index 000000000..2ce199dde --- /dev/null +++ b/3rdparty/libconfig/grammar.h @@ -0,0 +1,113 @@ + +/* A Bison parser, made by GNU Bison 2.4.1. */ + +/* Skeleton interface for Bison's Yacc-like parsers in C + + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 + Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + TOK_BOOLEAN = 258, + TOK_INTEGER = 259, + TOK_HEX = 260, + TOK_INTEGER64 = 261, + TOK_HEX64 = 262, + TOK_FLOAT = 263, + TOK_STRING = 264, + TOK_NAME = 265, + TOK_EQUALS = 266, + TOK_NEWLINE = 267, + TOK_ARRAY_START = 268, + TOK_ARRAY_END = 269, + TOK_LIST_START = 270, + TOK_LIST_END = 271, + TOK_COMMA = 272, + TOK_GROUP_START = 273, + TOK_GROUP_END = 274, + TOK_SEMICOLON = 275, + TOK_GARBAGE = 276, + TOK_ERROR = 277 + }; +#endif +/* Tokens. */ +#define TOK_BOOLEAN 258 +#define TOK_INTEGER 259 +#define TOK_HEX 260 +#define TOK_INTEGER64 261 +#define TOK_HEX64 262 +#define TOK_FLOAT 263 +#define TOK_STRING 264 +#define TOK_NAME 265 +#define TOK_EQUALS 266 +#define TOK_NEWLINE 267 +#define TOK_ARRAY_START 268 +#define TOK_ARRAY_END 269 +#define TOK_LIST_START 270 +#define TOK_LIST_END 271 +#define TOK_COMMA 272 +#define TOK_GROUP_START 273 +#define TOK_GROUP_END 274 +#define TOK_SEMICOLON 275 +#define TOK_GARBAGE 276 +#define TOK_ERROR 277 + + + + +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +typedef union YYSTYPE +{ + +/* Line 1676 of yacc.c */ +#line 85 "grammar.y" + + int ival; + long long llval; + double fval; + char *sval; + + + +/* Line 1676 of yacc.c */ +#line 105 "grammar.h" +} YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +#endif + + + + diff --git a/3rdparty/libconfig/libconfig-1.4.8 b/3rdparty/libconfig/libconfig-1.4.8 new file mode 100644 index 000000000..e69de29bb diff --git a/3rdparty/libconfig/libconfig.c b/3rdparty/libconfig/libconfig.c new file mode 100644 index 000000000..e64213c16 --- /dev/null +++ b/3rdparty/libconfig/libconfig.c @@ -0,0 +1,1615 @@ +/* ---------------------------------------------------------------------------- + libconfig - A library for processing structured configuration files + Copyright (C) 2005-2010 Mark A Lindner + + This file is part of libconfig. + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this library. If not, see . + ---------------------------------------------------------------------------- +*/ + +#ifdef HAVE_CONFIG_H +#include "ac_config.h" +#endif + +#include "libconfig.h" +#include "grammar.h" +#include "scanner.h" +#include "scanctx.h" +#include "parsectx.h" +#include "wincompat.h" + +#include + +#ifdef HAVE_XLOCALE_H +#include +#endif + +#include +#include +#include + +#define PATH_TOKENS ":./" +#define CHUNK_SIZE 16 +#define FLOAT_PRECISION 10 + +#define _new(T) (T *)calloc(sizeof(T), 1) /* zeroed */ +#define _delete(P) free((void *)(P)) + +/* ------------------------------------------------------------------------- */ + +#ifndef LIBCONFIG_STATIC +#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__)) + +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +{ + return(TRUE); +} + +#endif /* WIN32 */ +#endif /* LIBCONFIG_STATIC */ + +/* ------------------------------------------------------------------------- */ + +static const char *__io_error = "file I/O error"; + +static void __config_list_destroy(config_list_t *list); +static void __config_write_setting(const config_setting_t *setting, + FILE *stream, int depth, + unsigned short tab_width); + +extern int libconfig_yyparse(void *scanner, struct parse_context *ctx, + struct scan_context *scan_ctx); +extern int libconfig_yylex_init_extra(struct scan_context *scan_ctx, + yyscan_t *scanner); + +/* ------------------------------------------------------------------------- */ + +static void __config_locale_override(void) +{ +#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__)) \ + && ! defined(__MINGW32__) + + _configthreadlocale(_ENABLE_PER_THREAD_LOCALE); + setlocale(LC_NUMERIC, "C"); + +#elif defined(__APPLE__) + + locale_t loc = newlocale(LC_NUMERIC_MASK, "C", NULL); + uselocale(loc); + +#elif ((defined HAVE_NEWLOCALE) && (defined HAVE_USELOCALE)) + + locale_t loc = newlocale(LC_NUMERIC, "C", NULL); + uselocale(loc); + +#else + +#warning "No way to modify calling thread's locale!" + +#endif +} + +/* ------------------------------------------------------------------------- */ + +static void __config_locale_restore(void) +{ +#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__)) \ + && ! defined(__MINGW32__) + + _configthreadlocale(_DISABLE_PER_THREAD_LOCALE); + +#elif ((defined HAVE_USELOCALE) && (defined HAVE_FREELOCALE)) + + locale_t loc = uselocale(LC_GLOBAL_LOCALE); + freelocale(loc); + +#else + +#warning "No way to modify calling thread's locale!" + +#endif +} + +/* ------------------------------------------------------------------------- */ + +static int __config_name_compare(const char *a, const char *b) +{ + const char *p, *q; + + for(p = a, q = b; ; p++, q++) + { + int pd = ((! *p) || strchr(PATH_TOKENS, *p)); + int qd = ((! *q) || strchr(PATH_TOKENS, *q)); + + if(pd && qd) + break; + else if(pd) + return(-1); + else if(qd) + return(1); + else if(*p < *q) + return(-1); + else if(*p > *q) + return(1); + } + + return(0); +} + +/* ------------------------------------------------------------------------- */ + +static void __config_indent(FILE *stream, int depth, unsigned short w) +{ + if(w) + fprintf(stream, "%*s", (depth - 1) * w, " "); + else + { + int i; + for(i = 0; i < (depth - 1); ++i) + fputc('\t', stream); + } +} + +/* ------------------------------------------------------------------------- */ + +static void __config_write_value(const config_value_t *value, int type, + int format, int depth, + unsigned short tab_width, FILE *stream) +{ + char fbuf[64]; + + switch(type) + { + /* boolean */ + case CONFIG_TYPE_BOOL: + fputs(value->ival ? "true" : "false", stream); + break; + + /* int */ + case CONFIG_TYPE_INT: + switch(format) + { + case CONFIG_FORMAT_HEX: + fprintf(stream, "0x%X", value->ival); + break; + + case CONFIG_FORMAT_DEFAULT: + default: + fprintf(stream, "%d", value->ival); + break; + } + break; + + /* 64-bit int */ + case CONFIG_TYPE_INT64: + switch(format) + { + case CONFIG_FORMAT_HEX: + fprintf(stream, "0x" INT64_HEX_FMT "L", value->llval); + break; + + case CONFIG_FORMAT_DEFAULT: + default: + fprintf(stream, INT64_FMT "L", value->llval); + break; + } + break; + + /* float */ + case CONFIG_TYPE_FLOAT: + { + char *q; + + snprintf(fbuf, sizeof(fbuf) - 3, "%.*g", FLOAT_PRECISION, value->fval); + + /* check for exponent */ + q = strchr(fbuf, 'e'); + if(! q) + { + /* no exponent */ + if(! strchr(fbuf, '.')) /* no decimal point */ + strcat(fbuf, ".0"); + else + { + /* has decimal point */ + char *p; + + for(p = fbuf + strlen(fbuf) - 1; p > fbuf; --p) + { + if(*p != '0') + { + *(++p) = '\0'; + break; + } + } + } + } + + fputs(fbuf, stream); + break; + } + + /* string */ + case CONFIG_TYPE_STRING: + { + char *p; + + fputc('\"', stream); + + if(value->sval) + { + for(p = value->sval; *p; p++) + { + int c = (int)*p & 0xFF; + switch(c) + { + case '\"': + case '\\': + fputc('\\', stream); + fputc(c, stream); + break; + + case '\n': + fputs("\\n", stream); + break; + + case '\r': + fputs("\\r", stream); + break; + + case '\f': + fputs("\\f", stream); + break; + + case '\t': + fputs("\\t", stream); + break; + + default: + if(c >= ' ') + fputc(c, stream); + else + fprintf(stream, "\\x%02X", c); + } + } + } + fputc('\"', stream); + break; + } + + /* list */ + case CONFIG_TYPE_LIST: + { + config_list_t *list = value->list; + + fprintf(stream, "( "); + + if(list) + { + int len = list->length; + config_setting_t **s; + + for(s = list->elements; len--; s++) + { + __config_write_value(&((*s)->value), (*s)->type, + config_setting_get_format(*s), + depth + 1, tab_width, stream); + + if(len) + fputc(',', stream); + + fputc(' ', stream); + } + } + + fputc(')', stream); + break; + } + + /* array */ + case CONFIG_TYPE_ARRAY: + { + config_list_t *list = value->list; + + fprintf(stream, "[ "); + + if(list) + { + int len = list->length; + config_setting_t **s; + + for(s = list->elements; len--; s++) + { + __config_write_value(&((*s)->value), (*s)->type, + config_setting_get_format(*s), + depth + 1, tab_width, stream); + + if(len) + fputc(',', stream); + + fputc(' ', stream); + } + } + + fputc(']', stream); + break; + } + + /* group */ + case CONFIG_TYPE_GROUP: + { + config_list_t *list = value->list; + + if(depth > 0) + { +#ifdef K_AND_R_STYLE /* Horrendous, but many people like it. */ + fputc(' ', stream); +#else + fputc('\n', stream); + + if(depth > 1) + __config_indent(stream, depth, tab_width); +#endif + fprintf(stream, "{\n"); + } + + if(list) + { + int len = list->length; + config_setting_t **s; + + for(s = list->elements; len--; s++) + __config_write_setting(*s, stream, depth + 1, tab_width); + } + + if(depth > 1) + __config_indent(stream, depth, tab_width); + + if(depth > 0) + fputc('}', stream); + + break; + } + + default: + /* this shouldn't happen, but handle it gracefully... */ + fputs("???", stream); + break; + } +} + +/* ------------------------------------------------------------------------- */ + +static void __config_list_add(config_list_t *list, config_setting_t *setting) +{ + if((list->length % CHUNK_SIZE) == 0) + { + list->elements = (config_setting_t **)realloc( + list->elements, + (list->length + CHUNK_SIZE) * sizeof(config_setting_t *)); + } + + list->elements[list->length] = setting; + list->length++; +} + +/* ------------------------------------------------------------------------- */ + +static config_setting_t *__config_list_search(config_list_t *list, + const char *name, + unsigned int *idx) +{ + config_setting_t **found = NULL; + unsigned int i; + + if(! list) + return(NULL); + + for(i = 0, found = list->elements; i < list->length; i++, found++) + { + if(! (*found)->name) + continue; + + if(! __config_name_compare(name, (*found)->name)) + { + if(idx) + *idx = i; + + return(*found); + } + } + + return(NULL); +} + +/* ------------------------------------------------------------------------- */ + +static config_setting_t *__config_list_remove(config_list_t *list, int idx) +{ + config_setting_t *removed = *(list->elements + idx); + int offset = (idx * sizeof(config_setting_t *)); + int len = list->length - 1 - idx; + char *base = (char *)list->elements + offset; + + memmove(base, base + sizeof(config_setting_t *), + len * sizeof(config_setting_t *)); + + list->length--; + + /* possibly realloc smaller? */ + + return(removed); +} + +/* ------------------------------------------------------------------------- */ + +static void __config_setting_destroy(config_setting_t *setting) +{ + if(setting) + { + if(setting->name) + _delete(setting->name); + + if(setting->type == CONFIG_TYPE_STRING) + _delete(setting->value.sval); + + else if((setting->type == CONFIG_TYPE_GROUP) + || (setting->type == CONFIG_TYPE_ARRAY) + || (setting->type == CONFIG_TYPE_LIST)) + { + if(setting->value.list) + __config_list_destroy(setting->value.list); + } + + if(setting->hook && setting->config->destructor) + setting->config->destructor(setting->hook); + + _delete(setting); + } +} + +/* ------------------------------------------------------------------------- */ + +static void __config_list_destroy(config_list_t *list) +{ + config_setting_t **p; + unsigned int i; + + if(! list) + return; + + if(list->elements) + { + for(p = list->elements, i = 0; i < list->length; p++, i++) + __config_setting_destroy(*p); + + _delete(list->elements); + } + + _delete(list); +} + +/* ------------------------------------------------------------------------- */ + +static int __config_vector_checktype(const config_setting_t *vector, int type) +{ + /* if the array is empty, then it has no type yet */ + + if(! vector->value.list) + return(CONFIG_TRUE); + + if(vector->value.list->length == 0) + return(CONFIG_TRUE); + + /* if it's a list, any type is allowed */ + + if(vector->type == CONFIG_TYPE_LIST) + return(CONFIG_TRUE); + + /* otherwise the first element added determines the type of the array */ + + return((vector->value.list->elements[0]->type == type) + ? CONFIG_TRUE : CONFIG_FALSE); +} + +/* ------------------------------------------------------------------------- */ + +static int __config_validate_name(const char *name) +{ + const char *p = name; + + if(*p == '\0') + return(CONFIG_FALSE); + + if(! isalpha(*p) && (*p != '*')) + return(CONFIG_FALSE); + + for(++p; *p; ++p) + { + if(! (isalpha(*p) || isdigit(*p) || strchr("*_-", (int)*p))) + return(CONFIG_FALSE); + } + + return(CONFIG_TRUE); +} + +/* ------------------------------------------------------------------------- */ + +static int __config_read(config_t *config, FILE *stream, const char *filename, + const char *str) +{ + yyscan_t scanner; + struct scan_context scan_ctx; + struct parse_context parse_ctx; + YY_BUFFER_STATE buffer = NULL; + int r; + + /* Reinitialize the config */ + void (*destructor)(void *) = config->destructor; + const char *include_dir = config->include_dir; + unsigned short tab_width = config->tab_width; + unsigned short flags = config->flags; + + config->include_dir = NULL; + config_destroy(config); + config_init(config); + + config->destructor = destructor; + config->include_dir = include_dir; + config->tab_width = tab_width; + config->flags = flags; + + parsectx_init(&parse_ctx); + parse_ctx.config = config; + parse_ctx.parent = config->root; + parse_ctx.setting = config->root; + + __config_locale_override(); + + scanctx_init(&scan_ctx, filename); + scan_ctx.config = config; + libconfig_yylex_init_extra(&scan_ctx, &scanner); + + if(stream) + libconfig_yyrestart(stream, scanner); + else /* read from string */ + buffer = libconfig_yy_scan_string(str, scanner); + + libconfig_yyset_lineno(1, scanner); + r = libconfig_yyparse(scanner, &parse_ctx, &scan_ctx); + + if(r != 0) + { + YY_BUFFER_STATE buf; + + config->error_file = scanctx_current_filename(&scan_ctx); + config->error_type = CONFIG_ERR_PARSE; + + /* Unwind the include stack, freeing the buffers and closing the files. */ + while((buf = (YY_BUFFER_STATE)scanctx_pop_include(&scan_ctx)) != NULL) + libconfig_yy_delete_buffer(buf, scanner); + } + + libconfig_yylex_destroy(scanner); + config->filenames = scanctx_cleanup(&scan_ctx, &(config->num_filenames)); + parsectx_cleanup(&parse_ctx); + + __config_locale_restore(); + + return(r == 0 ? CONFIG_TRUE : CONFIG_FALSE); +} + +/* ------------------------------------------------------------------------- */ + +int config_read(config_t *config, FILE *stream) +{ + return(__config_read(config, stream, NULL, NULL)); +} + +/* ------------------------------------------------------------------------- */ + +int config_read_string(config_t *config, const char *str) +{ + return(__config_read(config, NULL, NULL, str)); +} + +/* ------------------------------------------------------------------------- */ + +static void __config_write_setting(const config_setting_t *setting, + FILE *stream, int depth, + unsigned short tab_width) +{ + if(depth > 1) + __config_indent(stream, depth, tab_width); + + if(setting->name) + { + fputs(setting->name, stream); + fprintf(stream, " %c ", (setting->type == CONFIG_TYPE_GROUP ? ':' : '=')); + } + + __config_write_value(&(setting->value), setting->type, + config_setting_get_format(setting), + depth, tab_width, stream); + + if(depth > 0) + { + fputc(';', stream); + fputc('\n', stream); + } +} + +/* ------------------------------------------------------------------------- */ + +void config_write(const config_t *config, FILE *stream) +{ + __config_locale_override(); + + __config_write_setting(config->root, stream, 0, config->tab_width); + + __config_locale_restore(); +} + +/* ------------------------------------------------------------------------- */ + +int config_read_file(config_t *config, const char *filename) +{ + int ret; + FILE *stream = fopen(filename, "rt"); + if(! stream) + { + config->error_text = __io_error; + config->error_type = CONFIG_ERR_FILE_IO; + return(CONFIG_FALSE); + } + + ret = __config_read(config, stream, filename, NULL); + fclose(stream); + + return(ret); +} + +/* ------------------------------------------------------------------------- */ + +int config_write_file(config_t *config, const char *filename) +{ + FILE *f = fopen(filename, "wt"); + if(! f) + { + config->error_text = __io_error; + config->error_type = CONFIG_ERR_FILE_IO; + return(CONFIG_FALSE); + } + + config_write(config, f); + fclose(f); + config->error_type = CONFIG_ERR_NONE; + return(CONFIG_TRUE); +} + +/* ------------------------------------------------------------------------- */ + +void config_destroy(config_t *config) +{ + unsigned int count = config->num_filenames; + const char **f; + + __config_setting_destroy(config->root); + + for(f = config->filenames; count > 0; ++f, --count) + _delete(*f); + + _delete(config->filenames); + _delete(config->include_dir); + + memset((void *)config, 0, sizeof(config_t)); +} + +/* ------------------------------------------------------------------------- */ + +void config_init(config_t *config) +{ + memset((void *)config, 0, sizeof(config_t)); + + config->root = _new(config_setting_t); + config->root->type = CONFIG_TYPE_GROUP; + config->root->config = config; + config->tab_width = 2; +} + +/* ------------------------------------------------------------------------- */ + +void config_set_auto_convert(config_t *config, int flag) +{ + if(flag) + config->flags |= CONFIG_OPTION_AUTOCONVERT; + else + config->flags &= ~CONFIG_OPTION_AUTOCONVERT; +} + +/* ------------------------------------------------------------------------- */ + +int config_get_auto_convert(const config_t *config) +{ + return((config->flags & CONFIG_OPTION_AUTOCONVERT) != 0); +} + +/* ------------------------------------------------------------------------- */ + +static config_setting_t *config_setting_create(config_setting_t *parent, + const char *name, int type) +{ + config_setting_t *setting; + config_list_t *list; + + if((parent->type != CONFIG_TYPE_GROUP) + && (parent->type != CONFIG_TYPE_ARRAY) + && (parent->type != CONFIG_TYPE_LIST)) + return(NULL); + + setting = _new(config_setting_t); + setting->parent = parent; + setting->name = (name == NULL) ? NULL : strdup(name); + setting->type = type; + setting->config = parent->config; + setting->hook = NULL; + setting->line = 0; + + list = parent->value.list; + + if(! list) + list = parent->value.list = _new(config_list_t); + + __config_list_add(list, setting); + + return(setting); +} + +/* ------------------------------------------------------------------------- */ + +static int __config_setting_get_int(const config_setting_t *setting, + int *value) +{ + switch(setting->type) + { + case CONFIG_TYPE_INT: + *value = setting->value.ival; + return(CONFIG_TRUE); + + case CONFIG_TYPE_INT64: + if((setting->value.llval > INT32_MAX) + || (setting->value.llval < INT32_MIN)) + *value = 0; + else + *value = (int)(setting->value.llval); + return(CONFIG_TRUE); + + case CONFIG_TYPE_FLOAT: + if((setting->config->flags & CONFIG_OPTION_AUTOCONVERT) != 0) + { + *value = (int)(setting->value.fval); + return(CONFIG_TRUE); + } + else + { /* fall through */ } + + default: + return(CONFIG_FALSE); + } +} + +/* ------------------------------------------------------------------------- */ + +int config_setting_get_int(const config_setting_t *setting) +{ + int value = 0; + __config_setting_get_int(setting, &value); + return(value); +} + +/* ------------------------------------------------------------------------- */ + +static int __config_setting_get_int64(const config_setting_t *setting, + long long *value) +{ + switch(setting->type) + { + case CONFIG_TYPE_INT64: + *value = setting->value.llval; + return(CONFIG_TRUE); + + case CONFIG_TYPE_INT: + *value = (long long)(setting->value.ival); + return(CONFIG_TRUE); + + case CONFIG_TYPE_FLOAT: + if((setting->config->flags & CONFIG_OPTION_AUTOCONVERT) != 0) + { + *value = (long long)(setting->value.fval); + return(CONFIG_TRUE); + } + else + { /* fall through */ } + + default: + return(CONFIG_FALSE); + } +} + +/* ------------------------------------------------------------------------- */ + +long long config_setting_get_int64(const config_setting_t *setting) +{ + long long value = 0; + __config_setting_get_int64(setting, &value); + return(value); +} + +/* ------------------------------------------------------------------------- */ + +int config_setting_lookup_int(const config_setting_t *setting, + const char *name, int *value) +{ + config_setting_t *member = config_setting_get_member(setting, name); + if(! member) + return(CONFIG_FALSE); + + return(__config_setting_get_int(member, value)); +} + +/* ------------------------------------------------------------------------- */ + +int config_setting_lookup_int64(const config_setting_t *setting, + const char *name, long long *value) +{ + config_setting_t *member = config_setting_get_member(setting, name); + if(! member) + return(CONFIG_FALSE); + + return(__config_setting_get_int64(member, value)); +} + +/* ------------------------------------------------------------------------- */ + +static int __config_setting_get_float(const config_setting_t *setting, + double *value) +{ + switch(setting->type) + { + case CONFIG_TYPE_FLOAT: + *value = setting->value.fval; + return(CONFIG_TRUE); + + case CONFIG_TYPE_INT: + if(config_get_auto_convert(setting->config)) + { + *value = (double)(setting->value.ival); + return(CONFIG_TRUE); + } + else + return(CONFIG_FALSE); + + case CONFIG_TYPE_INT64: + if(config_get_auto_convert(setting->config)) + { + *value = (double)(setting->value.llval); + return(CONFIG_TRUE); + } + else + { /* fall through */ } + + default: + return(CONFIG_FALSE); + } +} + +/* ------------------------------------------------------------------------- */ + +double config_setting_get_float(const config_setting_t *setting) +{ + double value = 0.0; + __config_setting_get_float(setting, &value); + return(value); +} + +/* ------------------------------------------------------------------------- */ + +int config_setting_lookup_float(const config_setting_t *setting, + const char *name, double *value) +{ + config_setting_t *member = config_setting_get_member(setting, name); + if(! member) + return(CONFIG_FALSE); + + return(__config_setting_get_float(member, value)); +} + +/* ------------------------------------------------------------------------- */ + +int config_setting_lookup_string(const config_setting_t *setting, + const char *name, const char **value) +{ + config_setting_t *member = config_setting_get_member(setting, name); + if(! member) + return(CONFIG_FALSE); + + if(config_setting_type(member) != CONFIG_TYPE_STRING) + return(CONFIG_FALSE); + + *value = config_setting_get_string(member); + return(CONFIG_TRUE); +} + +/* ------------------------------------------------------------------------- */ + +int config_setting_lookup_bool(const config_setting_t *setting, + const char *name, int *value) +{ + config_setting_t *member = config_setting_get_member(setting, name); + if(! member) + return(CONFIG_FALSE); + + if(config_setting_type(member) != CONFIG_TYPE_BOOL) + return(CONFIG_FALSE); + + *value = config_setting_get_bool(member); + return(CONFIG_TRUE); +} + +/* ------------------------------------------------------------------------- */ + +int config_setting_set_int(config_setting_t *setting, int value) +{ + switch(setting->type) + { + case CONFIG_TYPE_NONE: + setting->type = CONFIG_TYPE_INT; + /* fall through */ + + case CONFIG_TYPE_INT: + setting->value.ival = value; + return(CONFIG_TRUE); + + case CONFIG_TYPE_FLOAT: + if(config_get_auto_convert(setting->config)) + { + setting->value.fval = (float)value; + return(CONFIG_TRUE); + } + else + return(CONFIG_FALSE); + + default: + return(CONFIG_FALSE); + } +} + +/* ------------------------------------------------------------------------- */ + +int config_setting_set_int64(config_setting_t *setting, long long value) +{ + switch(setting->type) + { + case CONFIG_TYPE_NONE: + setting->type = CONFIG_TYPE_INT64; + /* fall through */ + + case CONFIG_TYPE_INT64: + setting->value.llval = value; + return(CONFIG_TRUE); + + case CONFIG_TYPE_INT: + if((value > INT32_MAX) || (value < INT32_MIN)) + setting->value.ival = 0; + else + setting->value.ival = (int)value; + return(CONFIG_TRUE); + + case CONFIG_TYPE_FLOAT: + if(config_get_auto_convert(setting->config)) + { + setting->value.fval = (float)value; + return(CONFIG_TRUE); + } + else + return(CONFIG_FALSE); + + default: + return(CONFIG_FALSE); + } +} + +/* ------------------------------------------------------------------------- */ + +int config_setting_set_float(config_setting_t *setting, double value) +{ + switch(setting->type) + { + case CONFIG_TYPE_NONE: + setting->type = CONFIG_TYPE_FLOAT; + /* fall through */ + + case CONFIG_TYPE_FLOAT: + setting->value.fval = value; + return(CONFIG_TRUE); + + case CONFIG_TYPE_INT: + if((setting->config->flags & CONFIG_OPTION_AUTOCONVERT) != 0) + { + setting->value.ival = (int)value; + return(CONFIG_TRUE); + } + else + return(CONFIG_FALSE); + + case CONFIG_TYPE_INT64: + if((setting->config->flags & CONFIG_OPTION_AUTOCONVERT) != 0) + { + setting->value.llval = (long long)value; + return(CONFIG_TRUE); + } + else + return(CONFIG_FALSE); + + default: + return(CONFIG_FALSE); + } +} + +/* ------------------------------------------------------------------------- */ + +int config_setting_get_bool(const config_setting_t *setting) +{ + return((setting->type == CONFIG_TYPE_BOOL) ? setting->value.ival : 0); +} + +/* ------------------------------------------------------------------------- */ + +int config_setting_set_bool(config_setting_t *setting, int value) +{ + if(setting->type == CONFIG_TYPE_NONE) + setting->type = CONFIG_TYPE_BOOL; + else if(setting->type != CONFIG_TYPE_BOOL) + return(CONFIG_FALSE); + + setting->value.ival = value; + return(CONFIG_TRUE); +} + +/* ------------------------------------------------------------------------- */ + +const char *config_setting_get_string(const config_setting_t *setting) +{ + return((setting->type == CONFIG_TYPE_STRING) ? setting->value.sval : NULL); +} + +/* ------------------------------------------------------------------------- */ + +int config_setting_set_string(config_setting_t *setting, const char *value) +{ + if(setting->type == CONFIG_TYPE_NONE) + setting->type = CONFIG_TYPE_STRING; + else if(setting->type != CONFIG_TYPE_STRING) + return(CONFIG_FALSE); + + if(setting->value.sval) + _delete(setting->value.sval); + + setting->value.sval = (value == NULL) ? NULL : strdup(value); + return(CONFIG_TRUE); +} + +/* ------------------------------------------------------------------------- */ + +int config_setting_set_format(config_setting_t *setting, short format) +{ + if(((setting->type != CONFIG_TYPE_INT) + && (setting->type != CONFIG_TYPE_INT64)) + || ((format != CONFIG_FORMAT_DEFAULT) && (format != CONFIG_FORMAT_HEX))) + return(CONFIG_FALSE); + + setting->format = format; + + return(CONFIG_TRUE); +} + +/* ------------------------------------------------------------------------- */ + +short config_setting_get_format(const config_setting_t *setting) +{ + return(setting->format != 0 ? setting->format + : setting->config->default_format); +} + +/* ------------------------------------------------------------------------- */ + +config_setting_t *config_lookup_from(config_setting_t *setting, + const char *path) +{ + const char *p = path; + config_setting_t *found; + + for(;;) + { + while(*p && strchr(PATH_TOKENS, *p)) + p++; + + if(! *p) + break; + + if(*p == '[') + found = config_setting_get_elem(setting, atoi(++p)); + else + found = config_setting_get_member(setting, p); + + if(! found) + break; + + setting = found; + + while(! strchr(PATH_TOKENS, *p)) + p++; + } + + return(*p ? NULL : setting); +} + +/* ------------------------------------------------------------------------- */ + +config_setting_t *config_lookup(const config_t *config, const char *path) +{ + return(config_lookup_from(config->root, path)); +} + +/* ------------------------------------------------------------------------- */ + +int config_lookup_string(const config_t *config, const char *path, + const char **value) +{ + const config_setting_t *s = config_lookup(config, path); + if(! s) + return(CONFIG_FALSE); + + if(config_setting_type(s) != CONFIG_TYPE_STRING) + return(CONFIG_FALSE); + + *value = config_setting_get_string(s); + + return(CONFIG_TRUE); +} + +/* ------------------------------------------------------------------------- */ + +int config_lookup_int(const config_t *config, const char *path, + int *value) +{ + const config_setting_t *s = config_lookup(config, path); + if(! s) + return(CONFIG_FALSE); + + return(__config_setting_get_int(s, value)); +} + +/* ------------------------------------------------------------------------- */ + +int config_lookup_int64(const config_t *config, const char *path, + long long *value) +{ + const config_setting_t *s = config_lookup(config, path); + if(! s) + return(CONFIG_FALSE); + + return(__config_setting_get_int64(s, value)); +} + +/* ------------------------------------------------------------------------- */ + +int config_lookup_float(const config_t *config, const char *path, + double *value) +{ + const config_setting_t *s = config_lookup(config, path); + if(! s) + return(CONFIG_FALSE); + + return(__config_setting_get_float(s, value)); +} + +/* ------------------------------------------------------------------------- */ + +int config_lookup_bool(const config_t *config, const char *path, int *value) +{ + const config_setting_t *s = config_lookup(config, path); + if(! s) + return(CONFIG_FALSE); + + if(config_setting_type(s) != CONFIG_TYPE_BOOL) + return(CONFIG_FALSE); + + *value = config_setting_get_bool(s); + return(CONFIG_TRUE); +} + +/* ------------------------------------------------------------------------- */ + +int config_setting_get_int_elem(const config_setting_t *vector, int idx) +{ + const config_setting_t *element = config_setting_get_elem(vector, idx); + + return(element ? config_setting_get_int(element) : 0); +} + +/* ------------------------------------------------------------------------- */ + +config_setting_t *config_setting_set_int_elem(config_setting_t *vector, + int idx, int value) +{ + config_setting_t *element = NULL; + + if((vector->type != CONFIG_TYPE_ARRAY) && (vector->type != CONFIG_TYPE_LIST)) + return(NULL); + + if(idx < 0) + { + if(! __config_vector_checktype(vector, CONFIG_TYPE_INT)) + return(NULL); + + element = config_setting_create(vector, NULL, CONFIG_TYPE_INT); + } + else + { + element = config_setting_get_elem(vector, idx); + + if(! element) + return(NULL); + } + + if(! config_setting_set_int(element, value)) + return(NULL); + + return(element); +} + +/* ------------------------------------------------------------------------- */ + +long long config_setting_get_int64_elem(const config_setting_t *vector, + int idx) +{ + const config_setting_t *element = config_setting_get_elem(vector, idx); + + return(element ? config_setting_get_int64(element) : 0); +} + +/* ------------------------------------------------------------------------- */ + +config_setting_t *config_setting_set_int64_elem(config_setting_t *vector, + int idx, long long value) +{ + config_setting_t *element = NULL; + + if((vector->type != CONFIG_TYPE_ARRAY) && (vector->type != CONFIG_TYPE_LIST)) + return(NULL); + + if(idx < 0) + { + if(! __config_vector_checktype(vector, CONFIG_TYPE_INT64)) + return(NULL); + + element = config_setting_create(vector, NULL, CONFIG_TYPE_INT64); + } + else + { + element = config_setting_get_elem(vector, idx); + + if(! element) + return(NULL); + } + + if(! config_setting_set_int64(element, value)) + return(NULL); + + return(element); +} + +/* ------------------------------------------------------------------------- */ + +double config_setting_get_float_elem(const config_setting_t *vector, int idx) +{ + config_setting_t *element = config_setting_get_elem(vector, idx); + + return(element ? config_setting_get_float(element) : 0.0); +} + +/* ------------------------------------------------------------------------- */ + +config_setting_t *config_setting_set_float_elem(config_setting_t *vector, + int idx, double value) +{ + config_setting_t *element = NULL; + + if((vector->type != CONFIG_TYPE_ARRAY) && (vector->type != CONFIG_TYPE_LIST)) + return(NULL); + + if(idx < 0) + { + if(! __config_vector_checktype(vector, CONFIG_TYPE_FLOAT)) + return(NULL); + + element = config_setting_create(vector, NULL, CONFIG_TYPE_FLOAT); + } + else + element = config_setting_get_elem(vector, idx); + + if(! element) + return(NULL); + + if(! config_setting_set_float(element, value)) + return(NULL); + + return(element); +} + +/* ------------------------------------------------------------------------- */ + +int config_setting_get_bool_elem(const config_setting_t *vector, int idx) +{ + config_setting_t *element = config_setting_get_elem(vector, idx); + + if(! element) + return(CONFIG_FALSE); + + if(element->type != CONFIG_TYPE_BOOL) + return(CONFIG_FALSE); + + return(element->value.ival); +} + +/* ------------------------------------------------------------------------- */ + +config_setting_t *config_setting_set_bool_elem(config_setting_t *vector, + int idx, int value) +{ + config_setting_t *element = NULL; + + if((vector->type != CONFIG_TYPE_ARRAY) && (vector->type != CONFIG_TYPE_LIST)) + return(NULL); + + if(idx < 0) + { + if(! __config_vector_checktype(vector, CONFIG_TYPE_BOOL)) + return(NULL); + + element = config_setting_create(vector, NULL, CONFIG_TYPE_BOOL); + } + else + element = config_setting_get_elem(vector, idx); + + if(! element) + return(NULL); + + if(! config_setting_set_bool(element, value)) + return(NULL); + + return(element); +} + +/* ------------------------------------------------------------------------- */ + +const char *config_setting_get_string_elem(const config_setting_t *vector, + int idx) +{ + config_setting_t *element = config_setting_get_elem(vector, idx); + + if(! element) + return(NULL); + + if(element->type != CONFIG_TYPE_STRING) + return(NULL); + + return(element->value.sval); +} + +/* ------------------------------------------------------------------------- */ + +config_setting_t *config_setting_set_string_elem(config_setting_t *vector, + int idx, const char *value) +{ + config_setting_t *element = NULL; + + if((vector->type != CONFIG_TYPE_ARRAY) && (vector->type != CONFIG_TYPE_LIST)) + return(NULL); + + if(idx < 0) + { + if(! __config_vector_checktype(vector, CONFIG_TYPE_STRING)) + return(NULL); + + element = config_setting_create(vector, NULL, CONFIG_TYPE_STRING); + } + else + element = config_setting_get_elem(vector, idx); + + if(! element) + return(NULL); + + if(! config_setting_set_string(element, value)) + return(NULL); + + return(element); +} + +/* ------------------------------------------------------------------------- */ + +config_setting_t *config_setting_get_elem(const config_setting_t *vector, + unsigned int idx) +{ + config_list_t *list = vector->value.list; + + if(((vector->type != CONFIG_TYPE_ARRAY) + && (vector->type != CONFIG_TYPE_LIST) + && (vector->type != CONFIG_TYPE_GROUP)) || ! list) + return(NULL); + + if(idx >= list->length) + return(NULL); + + return(list->elements[idx]); +} + +/* ------------------------------------------------------------------------- */ + +config_setting_t *config_setting_get_member(const config_setting_t *setting, + const char *name) +{ + if(setting->type != CONFIG_TYPE_GROUP) + return(NULL); + + return(__config_list_search(setting->value.list, name, NULL)); +} + +/* ------------------------------------------------------------------------- */ + +void config_set_destructor(config_t *config, void (*destructor)(void *)) +{ + config->destructor = destructor; +} + +/* ------------------------------------------------------------------------- */ + +void config_set_include_dir(config_t *config, const char *include_dir) +{ + _delete(config->include_dir); + config->include_dir = strdup(include_dir); +} + +/* ------------------------------------------------------------------------- */ + +int config_setting_length(const config_setting_t *setting) +{ + if((setting->type != CONFIG_TYPE_GROUP) + && (setting->type != CONFIG_TYPE_ARRAY) + && (setting->type != CONFIG_TYPE_LIST)) + return(0); + + if(! setting->value.list) + return(0); + + return(setting->value.list->length); +} + +/* ------------------------------------------------------------------------- */ + +void config_setting_set_hook(config_setting_t *setting, void *hook) +{ + setting->hook = hook; +} + +/* ------------------------------------------------------------------------- */ + +config_setting_t *config_setting_add(config_setting_t *parent, + const char *name, int type) +{ + if((type < CONFIG_TYPE_NONE) || (type > CONFIG_TYPE_LIST)) + return(NULL); + + if(! parent) + return(NULL); + + if((parent->type == CONFIG_TYPE_ARRAY) || (parent->type == CONFIG_TYPE_LIST)) + name = NULL; + + if(name) + { + if(! __config_validate_name(name)) + return(NULL); + } + + if(config_setting_get_member(parent, name) != NULL) + return(NULL); /* already exists */ + + return(config_setting_create(parent, name, type)); +} + +/* ------------------------------------------------------------------------- */ + +int config_setting_remove(config_setting_t *parent, const char *name) +{ + unsigned int idx; + config_setting_t *setting; + + if(! parent) + return(CONFIG_FALSE); + + if(parent->type != CONFIG_TYPE_GROUP) + return(CONFIG_FALSE); + + if(! (setting = __config_list_search(parent->value.list, name, &idx))) + return(CONFIG_FALSE); + + __config_list_remove(parent->value.list, idx); + __config_setting_destroy(setting); + + return(CONFIG_TRUE); +} + +/* ------------------------------------------------------------------------- */ + +int config_setting_remove_elem(config_setting_t *parent, unsigned int idx) +{ + config_list_t *list; + config_setting_t *removed = NULL; + + if(! parent) + return(CONFIG_FALSE); + + list = parent->value.list; + + if(((parent->type != CONFIG_TYPE_ARRAY) + && (parent->type != CONFIG_TYPE_LIST) + && (parent->type != CONFIG_TYPE_GROUP)) || ! list) + return(CONFIG_FALSE); + + if(idx >= list->length) + return(CONFIG_FALSE); + + removed = __config_list_remove(list, idx); + __config_setting_destroy(removed); + + return(CONFIG_TRUE); +} + +/* ------------------------------------------------------------------------- */ + +int config_setting_index(const config_setting_t *setting) +{ + config_setting_t **found = NULL; + config_list_t *list; + int i; + + if(! setting->parent) + return(-1); + + list = setting->parent->value.list; + + for(i = 0, found = list->elements; i < (int)list->length; ++i, ++found) + { + if(*found == setting) + return(i); + } + + return(-1); +} + +/* ------------------------------------------------------------------------- */ +/* eof */ diff --git a/3rdparty/libconfig/libconfig.h b/3rdparty/libconfig/libconfig.h new file mode 100644 index 000000000..683bda80b --- /dev/null +++ b/3rdparty/libconfig/libconfig.h @@ -0,0 +1,320 @@ +/* ---------------------------------------------------------------------------- + libconfig - A library for processing structured configuration files + Copyright (C) 2005-2010 Mark A Lindner + + This file is part of libconfig. + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this library. If not, see . + ---------------------------------------------------------------------------- +*/ + +#ifndef __libconfig_h +#define __libconfig_h + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) +#if defined(LIBCONFIG_STATIC) +#define LIBCONFIG_API +#elif defined(LIBCONFIG_EXPORTS) +#define LIBCONFIG_API __declspec(dllexport) +#else /* ! LIBCONFIG_EXPORTS */ +#define LIBCONFIG_API __declspec(dllimport) +#endif /* LIBCONFIG_STATIC */ +#else /* ! WIN32 */ +#define LIBCONFIG_API +#endif /* WIN32 */ + +#define LIBCONFIG_VER_MAJOR 1 +#define LIBCONFIG_VER_MINOR 4 +#define LIBCONFIG_VER_REVISION 8 + +#include + +#define CONFIG_TYPE_NONE 0 +#define CONFIG_TYPE_GROUP 1 +#define CONFIG_TYPE_INT 2 +#define CONFIG_TYPE_INT64 3 +#define CONFIG_TYPE_FLOAT 4 +#define CONFIG_TYPE_STRING 5 +#define CONFIG_TYPE_BOOL 6 +#define CONFIG_TYPE_ARRAY 7 +#define CONFIG_TYPE_LIST 8 + +#define CONFIG_FORMAT_DEFAULT 0 +#define CONFIG_FORMAT_HEX 1 + +#define CONFIG_OPTION_AUTOCONVERT 0x01 + +#define CONFIG_TRUE (1) +#define CONFIG_FALSE (0) + +typedef union config_value_t +{ + int ival; + long long llval; + double fval; + char *sval; + struct config_list_t *list; +} config_value_t; + +typedef struct config_setting_t +{ + char *name; + short type; + short format; + config_value_t value; + struct config_setting_t *parent; + struct config_t *config; + void *hook; + unsigned int line; + const char *file; +} config_setting_t; + +typedef enum +{ + CONFIG_ERR_NONE = 0, + CONFIG_ERR_FILE_IO = 1, + CONFIG_ERR_PARSE = 2 +} config_error_t; + +typedef struct config_list_t +{ + unsigned int length; + config_setting_t **elements; +} config_list_t; + +typedef struct config_t +{ + config_setting_t *root; + void (*destructor)(void *); + unsigned short flags; + unsigned short tab_width; + short default_format; + const char *include_dir; + const char *error_text; + const char *error_file; + int error_line; + config_error_t error_type; + const char **filenames; + unsigned int num_filenames; +} config_t; + +extern LIBCONFIG_API int config_read(config_t *config, FILE *stream); +extern LIBCONFIG_API void config_write(const config_t *config, FILE *stream); + +extern LIBCONFIG_API void config_set_default_format(config_t *config, + short format); + +extern LIBCONFIG_API void config_set_auto_convert(config_t *config, int flag); +extern LIBCONFIG_API int config_get_auto_convert(const config_t *config); + +extern LIBCONFIG_API int config_read_string(config_t *config, const char *str); + +extern LIBCONFIG_API int config_read_file(config_t *config, + const char *filename); +extern LIBCONFIG_API int config_write_file(config_t *config, + const char *filename); + +extern LIBCONFIG_API void config_set_destructor(config_t *config, + void (*destructor)(void *)); +extern LIBCONFIG_API void config_set_include_dir(config_t *config, + const char *include_dir); + +extern LIBCONFIG_API void config_init(config_t *config); +extern LIBCONFIG_API void config_destroy(config_t *config); + +extern LIBCONFIG_API int config_setting_get_int( + const config_setting_t *setting); +extern LIBCONFIG_API long long config_setting_get_int64( + const config_setting_t *setting); +extern LIBCONFIG_API double config_setting_get_float( + const config_setting_t *setting); +extern LIBCONFIG_API int config_setting_get_bool( + const config_setting_t *setting); +extern LIBCONFIG_API const char *config_setting_get_string( + const config_setting_t *setting); + +extern LIBCONFIG_API int config_setting_lookup_int( + const config_setting_t *setting, const char *name, int *value); +extern LIBCONFIG_API int config_setting_lookup_int64( + const config_setting_t *setting, const char *name, long long *value); +extern LIBCONFIG_API int config_setting_lookup_float( + const config_setting_t *setting, const char *name, double *value); +extern LIBCONFIG_API int config_setting_lookup_bool( + const config_setting_t *setting, const char *name, int *value); +extern LIBCONFIG_API int config_setting_lookup_string( + const config_setting_t *setting, const char *name, const char **value); + +extern LIBCONFIG_API int config_setting_set_int(config_setting_t *setting, + int value); +extern LIBCONFIG_API int config_setting_set_int64(config_setting_t *setting, + long long value); +extern LIBCONFIG_API int config_setting_set_float(config_setting_t *setting, + double value); +extern LIBCONFIG_API int config_setting_set_bool(config_setting_t *setting, + int value); +extern LIBCONFIG_API int config_setting_set_string(config_setting_t *setting, + const char *value); + +extern LIBCONFIG_API int config_setting_set_format(config_setting_t *setting, + short format); +extern LIBCONFIG_API short config_setting_get_format( + const config_setting_t *setting); + +extern LIBCONFIG_API int config_setting_get_int_elem( + const config_setting_t *setting, int idx); +extern LIBCONFIG_API long long config_setting_get_int64_elem( + const config_setting_t *setting, int idx); +extern LIBCONFIG_API double config_setting_get_float_elem( + const config_setting_t *setting, int idx); +extern LIBCONFIG_API int config_setting_get_bool_elem( + const config_setting_t *setting, int idx); +extern LIBCONFIG_API const char *config_setting_get_string_elem( + const config_setting_t *setting, int idx); + +extern LIBCONFIG_API config_setting_t *config_setting_set_int_elem( + config_setting_t *setting, int idx, int value); +extern LIBCONFIG_API config_setting_t *config_setting_set_int64_elem( + config_setting_t *setting, int idx, long long value); +extern LIBCONFIG_API config_setting_t *config_setting_set_float_elem( + config_setting_t *setting, int idx, double value); +extern LIBCONFIG_API config_setting_t *config_setting_set_bool_elem( + config_setting_t *setting, int idx, int value); +extern LIBCONFIG_API config_setting_t *config_setting_set_string_elem( + config_setting_t *setting, int idx, const char *value); + +#define /* const char * */ config_get_include_dir(/* const config_t * */ C) \ + ((C)->include_dir) + +#define /* int */ config_setting_type(/* const config_setting_t * */ S) \ + ((S)->type) + +#define /* int */ config_setting_is_group(/* const config_setting_t * */ S) \ + ((S)->type == CONFIG_TYPE_GROUP) +#define /* int */ config_setting_is_array(/* const config_setting_t * */ S) \ + ((S)->type == CONFIG_TYPE_ARRAY) +#define /* int */ config_setting_is_list(/* const config_setting_t * */ S) \ + ((S)->type == CONFIG_TYPE_LIST) + +#define /* int */ config_setting_is_aggregate( \ + /* const config_setting_t * */ S) \ + (((S)->type == CONFIG_TYPE_GROUP) || ((S)->type == CONFIG_TYPE_LIST) \ + || ((S)->type == CONFIG_TYPE_ARRAY)) + +#define /* int */ config_setting_is_number(/* const config_setting_t * */ S) \ + (((S)->type == CONFIG_TYPE_INT) \ + || ((S)->type == CONFIG_TYPE_INT64) \ + || ((S)->type == CONFIG_TYPE_FLOAT)) + +#define /* int */ config_setting_is_scalar(/* const config_setting_t * */ S) \ + (((S)->type == CONFIG_TYPE_BOOL) || ((S)->type == CONFIG_TYPE_STRING) \ + || config_setting_is_number(S)) + +#define /* const char * */ config_setting_name( \ + /* const config_setting_t * */ S) \ + ((S)->name) + +#define /* config_setting_t * */ config_setting_parent( \ + /* const config_setting_t * */ S) \ + ((S)->parent) + +#define /* int */ config_setting_is_root( \ + /* const config_setting_t * */ S) \ + ((S)->parent ? CONFIG_FALSE : CONFIG_TRUE) + +extern LIBCONFIG_API int config_setting_index(const config_setting_t *setting); + +extern LIBCONFIG_API int config_setting_length( + const config_setting_t *setting); +extern LIBCONFIG_API config_setting_t *config_setting_get_elem( + const config_setting_t *setting, unsigned int idx); + +extern LIBCONFIG_API config_setting_t *config_setting_get_member( + const config_setting_t *setting, const char *name); + +extern LIBCONFIG_API config_setting_t *config_setting_add( + config_setting_t *parent, const char *name, int type); +extern LIBCONFIG_API int config_setting_remove(config_setting_t *parent, + const char *name); +extern LIBCONFIG_API int config_setting_remove_elem(config_setting_t *parent, + unsigned int idx); +extern LIBCONFIG_API void config_setting_set_hook(config_setting_t *setting, + void *hook); + +#define config_setting_get_hook(S) ((S)->hook) + +extern LIBCONFIG_API config_setting_t *config_lookup(const config_t *config, + const char *path); +extern LIBCONFIG_API config_setting_t *config_lookup_from( + config_setting_t *setting, const char *path); + +extern LIBCONFIG_API int config_lookup_int(const config_t *config, + const char *path, int *value); +extern LIBCONFIG_API int config_lookup_int64(const config_t *config, + const char *path, + long long *value); +extern LIBCONFIG_API int config_lookup_float(const config_t *config, + const char *path, double *value); +extern LIBCONFIG_API int config_lookup_bool(const config_t *config, + const char *path, int *value); +extern LIBCONFIG_API int config_lookup_string(const config_t *config, + const char *path, + const char **value); + +#define /* config_setting_t * */ config_root_setting( \ + /* const config_t * */ C) \ + ((C)->root) + +#define /* void */ config_set_default_format(/* config_t * */ C, \ + /* short */ F) \ + (C)->default_format = (F) + +#define /* short */ config_get_default_format(/* config_t * */ C) \ + ((C)->default_format) + +#define /* void */ config_set_tab_width(/* config_t * */ C, \ + /* unsigned short */ W) \ + (C)->tab_width = ((W) & 0x0F) + +#define /* unsigned char */ config_get_tab_width(/* const config_t * */ C) \ + ((C)->tab_width) + +#define /* unsigned short */ config_setting_source_line( \ + /* const config_setting_t * */ S) \ + ((S)->line) + +#define /* const char */ config_setting_source_file( \ + /* const config_setting_t * */ S) \ + ((S)->file) + +#define /* const char * */ config_error_text(/* const config_t * */ C) \ + ((C)->error_text) + +#define /* const char * */ config_error_file(/* const config_t * */ C) \ + ((C)->error_file) + +#define /* int */ config_error_line(/* const config_t * */ C) \ + ((C)->error_line) + +#define /* config_error_t */ config_error_type(/* const config_t * */ C) \ + ((C)->error_type) + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __libconfig_h */ diff --git a/3rdparty/libconfig/parsectx.h b/3rdparty/libconfig/parsectx.h new file mode 100644 index 000000000..0beb1111c --- /dev/null +++ b/3rdparty/libconfig/parsectx.h @@ -0,0 +1,47 @@ +/* ---------------------------------------------------------------------------- + libconfig - A library for processing structured configuration files + Copyright (C) 2005-2010 Mark A Lindner + + This file is part of libconfig. + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this library. If not, see . + ---------------------------------------------------------------------------- +*/ + +#ifndef __libconfig_parsectx_h +#define __libconfig_parsectx_h + +#include "libconfig.h" +#include "strbuf.h" + +struct parse_context +{ + config_t *config; + config_setting_t *parent; + config_setting_t *setting; + char *name; + strbuf_t string; +}; + +#define parsectx_init(C) \ + memset((C), 0, sizeof(struct parse_context)) +#define parsectx_cleanup(C) \ + free((void *)(strbuf_release(&((C)->string)))) + +#define parsectx_append_string(C, S) \ + strbuf_append(&((C)->string), (S)) +#define parsectx_take_string(C) \ + strbuf_release(&((C)->string)) + +#endif /* __libconfig_parsectx_h */ diff --git a/3rdparty/libconfig/scanctx.c b/3rdparty/libconfig/scanctx.c new file mode 100644 index 000000000..7d7f4994c --- /dev/null +++ b/3rdparty/libconfig/scanctx.c @@ -0,0 +1,170 @@ +/* ---------------------------------------------------------------------------- + libconfig - A library for processing structured configuration files + Copyright (C) 2005-2010 Mark A Lindner + + This file is part of libconfig. + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this library. If not, see . + ---------------------------------------------------------------------------- +*/ + +#include "scanctx.h" +#include "wincompat.h" + +#include +#include +#include + +#define STRING_BLOCK_SIZE 64 +#define CHUNK_SIZE 32 + +/* ------------------------------------------------------------------------- */ + +static const char *err_bad_include = "cannot open include file"; +static const char *err_include_too_deep = "include file nesting too deep"; + +/* ------------------------------------------------------------------------- */ + +static const char *__scanctx_add_filename(struct scan_context *ctx, + const char *filename) +{ + unsigned int count = ctx->num_filenames; + const char **f; + + for(f = ctx->filenames; count > 0; ++f, --count) + { + if(!strcmp(*f, filename)) + { + free((void *)filename); + return(*f); /* already in list */ + } + } + + if((ctx->num_filenames % CHUNK_SIZE) == 0) + { + ctx->filenames = (const char **)realloc( + (void *)ctx->filenames, + (ctx->num_filenames + CHUNK_SIZE) * sizeof(const char *)); + } + + ctx->filenames[ctx->num_filenames] = filename; + ++ctx->num_filenames; + return(filename); +} + +/* ------------------------------------------------------------------------- */ + +void scanctx_init(struct scan_context *ctx, const char *top_filename) +{ + memset(ctx, 0, sizeof(struct scan_context)); + if(top_filename) + ctx->top_filename = __scanctx_add_filename(ctx, strdup(top_filename)); +} + +/* ------------------------------------------------------------------------- */ + +const char **scanctx_cleanup(struct scan_context *ctx, + unsigned int *num_filenames) +{ + int i; + + for(i = 0; i < ctx->depth; ++i) + fclose(ctx->streams[i]); + + free((void *)(strbuf_release(&(ctx->string)))); + + *num_filenames = ctx->num_filenames; + return(ctx->filenames); +} + +/* ------------------------------------------------------------------------- */ + +FILE *scanctx_push_include(struct scan_context *ctx, void *buffer, + const char **error) +{ + FILE *fp = NULL; + const char *file; + char *full_file = NULL; + + *error = NULL; + + if(ctx->depth == MAX_INCLUDE_DEPTH) + { + *error = err_include_too_deep; + return(NULL); + } + + file = scanctx_take_string(ctx); + if(ctx->config->include_dir) + { + full_file = (char *)malloc(strlen(ctx->config->include_dir) + strlen(file) + + 2); + strcpy(full_file, ctx->config->include_dir); + strcat(full_file, FILE_SEPARATOR); + strcat(full_file, file); + } + + fp = fopen(full_file ? full_file : file, "rt"); + free((void *)full_file); + + if(fp) + { + ctx->streams[ctx->depth] = fp; + ctx->files[ctx->depth] = __scanctx_add_filename(ctx, file); + ctx->buffers[ctx->depth] = buffer; + ++(ctx->depth); + } + else + { + free((void *)file); + *error = err_bad_include; + } + + return(fp); +} + +/* ------------------------------------------------------------------------- */ + +void *scanctx_pop_include(struct scan_context *ctx) +{ + void *buffer; + + if(ctx->depth == 0) + return(NULL); /* stack underflow */ + + --(ctx->depth); + buffer = ctx->buffers[ctx->depth]; + fclose(ctx->streams[ctx->depth]); + + return(buffer); +} + +/* ------------------------------------------------------------------------- */ + +char *scanctx_take_string(struct scan_context *ctx) +{ + char *r = strbuf_release(&(ctx->string)); + + return(r ? r : strdup("")); +} + +/* ------------------------------------------------------------------------- */ + +const char *scanctx_current_filename(struct scan_context *ctx) +{ + return((ctx->depth == 0) ? ctx->top_filename : ctx->files[ctx->depth - 1]); +} + +/* ------------------------------------------------------------------------- */ +/* eof */ diff --git a/3rdparty/libconfig/scanctx.h b/3rdparty/libconfig/scanctx.h new file mode 100644 index 000000000..b8cc11e3d --- /dev/null +++ b/3rdparty/libconfig/scanctx.h @@ -0,0 +1,61 @@ +/* ---------------------------------------------------------------------------- + libconfig - A library for processing structured configuration files + Copyright (C) 2005-2010 Mark A Lindner + + This file is part of libconfig. + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this library. If not, see . + ---------------------------------------------------------------------------- +*/ + +#ifndef __libconfig_scanctx_h +#define __libconfig_scanctx_h + +#include "libconfig.h" +#include "strbuf.h" + +#include +#include + +#define MAX_INCLUDE_DEPTH 10 + +struct scan_context +{ + config_t *config; + const char *top_filename; + const char *files[MAX_INCLUDE_DEPTH]; + void *buffers[MAX_INCLUDE_DEPTH]; + FILE *streams[MAX_INCLUDE_DEPTH]; + int depth; + strbuf_t string; + const char **filenames; + unsigned int num_filenames; +}; + +extern void scanctx_init(struct scan_context *ctx, const char *top_filename); +extern const char **scanctx_cleanup(struct scan_context *ctx, + unsigned int *num_filenames); + +extern FILE *scanctx_push_include(struct scan_context *ctx, void *prev_buffer, + const char **error); +extern void *scanctx_pop_include(struct scan_context *ctx); + +#define scanctx_append_string(C, S) \ + strbuf_append(&((C)->string), (S)) + +extern char *scanctx_take_string(struct scan_context *ctx); + +extern const char *scanctx_current_filename(struct scan_context *ctx); + +#endif /* __libconfig_scanctx_h */ diff --git a/3rdparty/libconfig/scanner.c b/3rdparty/libconfig/scanner.c new file mode 100644 index 000000000..c2eb7d188 --- /dev/null +++ b/3rdparty/libconfig/scanner.c @@ -0,0 +1,2362 @@ +#line 2 "scanner.c" + +#line 4 "scanner.c" + +#define YY_INT_ALIGNED short int + +/* A lexical scanner generated by flex */ + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 5 +#define YY_FLEX_SUBMINOR_VERSION 35 +#if YY_FLEX_SUBMINOR_VERSION > 0 +#define FLEX_BETA +#endif + +/* First, we deal with platform-specific or compiler-specific issues. */ + +/* begin standard C headers. */ +#include +#include +#include +#include + +/* end standard C headers. */ + +/* flex integer type definitions */ + +#ifndef FLEXINT_H +#define FLEXINT_H + +/* C99 systems have . Non-C99 systems may or may not. */ + +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + +/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, + * if you want the limit (max/min) macros for int types. + */ +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS 1 +#endif + +#include +typedef int8_t flex_int8_t; +typedef uint8_t flex_uint8_t; +typedef int16_t flex_int16_t; +typedef uint16_t flex_uint16_t; +typedef int32_t flex_int32_t; +typedef uint32_t flex_uint32_t; +#else +typedef signed char flex_int8_t; +typedef short int flex_int16_t; +typedef int flex_int32_t; +typedef unsigned char flex_uint8_t; +typedef unsigned short int flex_uint16_t; +typedef unsigned int flex_uint32_t; + +/* Limits of integral types. */ +#ifndef INT8_MIN +#define INT8_MIN (-128) +#endif +#ifndef INT16_MIN +#define INT16_MIN (-32767-1) +#endif +#ifndef INT32_MIN +#define INT32_MIN (-2147483647-1) +#endif +#ifndef INT8_MAX +#define INT8_MAX (127) +#endif +#ifndef INT16_MAX +#define INT16_MAX (32767) +#endif +#ifndef INT32_MAX +#define INT32_MAX (2147483647) +#endif +#ifndef UINT8_MAX +#define UINT8_MAX (255U) +#endif +#ifndef UINT16_MAX +#define UINT16_MAX (65535U) +#endif +#ifndef UINT32_MAX +#define UINT32_MAX (4294967295U) +#endif + +#endif /* ! C99 */ + +#endif /* ! FLEXINT_H */ + +#ifdef __cplusplus + +/* The "const" storage-class-modifier is valid. */ +#define YY_USE_CONST + +#else /* ! __cplusplus */ + +/* C99 requires __STDC__ to be defined as 1. */ +#if defined (__STDC__) + +#define YY_USE_CONST + +#endif /* defined (__STDC__) */ +#endif /* ! __cplusplus */ + +#ifdef YY_USE_CONST +#define yyconst const +#else +#define yyconst +#endif + +/* Returned upon end-of-file. */ +#define YY_NULL 0 + +/* Promotes a possibly negative, possibly signed char to an unsigned + * integer for use as an array index. If the signed char is negative, + * we want to instead treat it as an 8-bit unsigned char, hence the + * double cast. + */ +#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) + +/* An opaque pointer. */ +#ifndef YY_TYPEDEF_YY_SCANNER_T +#define YY_TYPEDEF_YY_SCANNER_T +typedef void* yyscan_t; +#endif + +/* For convenience, these vars (plus the bison vars far below) + are macros in the reentrant scanner. */ +#define yyin yyg->yyin_r +#define yyout yyg->yyout_r +#define yyextra yyg->yyextra_r +#define yyleng yyg->yyleng_r +#define yytext yyg->yytext_r +#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno) +#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column) +#define yy_flex_debug yyg->yy_flex_debug_r + +/* Enter a start condition. This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN. + */ +#define BEGIN yyg->yy_start = 1 + 2 * + +/* Translate the current start state into a value that can be later handed + * to BEGIN to return to the state. The YYSTATE alias is for lex + * compatibility. + */ +#define YY_START ((yyg->yy_start - 1) / 2) +#define YYSTATE YY_START + +/* Action number for EOF rule of a given start state. */ +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) + +/* Special action meaning "start processing a new file". */ +#define YY_NEW_FILE libconfig_yyrestart(yyin ,yyscanner ) + +#define YY_END_OF_BUFFER_CHAR 0 + +/* Size of default input buffer. */ +#ifndef YY_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k. + * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. + * Ditto for the __ia64__ case accordingly. + */ +#define YY_BUF_SIZE 32768 +#else +#define YY_BUF_SIZE 16384 +#endif /* __ia64__ */ +#endif + +/* The state buf must be large enough to hold one state per character in the main buffer. + */ +#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) + +#ifndef YY_TYPEDEF_YY_BUFFER_STATE +#define YY_TYPEDEF_YY_BUFFER_STATE +typedef struct yy_buffer_state *YY_BUFFER_STATE; +#endif + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + + /* Note: We specifically omit the test for yy_rule_can_match_eol because it requires + * access to the local variable yy_act. Since yyless() is a macro, it would break + * existing scanners that call yyless() from OUTSIDE libconfig_yylex. + * One obvious solution it to make yy_act a global. I tried that, and saw + * a 5% performance hit in a non-yylineno scanner, because yy_act is + * normally declared as a register variable-- so it is not worth it. + */ + #define YY_LESS_LINENO(n) \ + do { \ + int yyl;\ + for ( yyl = n; yyl < yyleng; ++yyl )\ + if ( yytext[yyl] == '\n' )\ + --yylineno;\ + }while(0) + +/* Return all but the first "n" matched characters back to the input stream. */ +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + *yy_cp = yyg->yy_hold_char; \ + YY_RESTORE_YY_MORE_OFFSET \ + yyg->yy_c_buf_p = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ + YY_DO_BEFORE_ACTION; /* set up yytext again */ \ + } \ + while ( 0 ) + +#define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner ) + +#ifndef YY_TYPEDEF_YY_SIZE_T +#define YY_TYPEDEF_YY_SIZE_T +typedef size_t yy_size_t; +#endif + +#ifndef YY_STRUCT_YY_BUFFER_STATE +#define YY_STRUCT_YY_BUFFER_STATE +struct yy_buffer_state + { + FILE *yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + yy_size_t yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + int yy_bs_lineno; /**< The line count. */ + int yy_bs_column; /**< The column count. */ + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; + +#define YY_BUFFER_NEW 0 +#define YY_BUFFER_NORMAL 1 + /* When an EOF's been seen but there's still some text to process + * then we mark the buffer as YY_EOF_PENDING, to indicate that we + * shouldn't try reading from the input source any more. We might + * still have a bunch of tokens to match, though, because of + * possible backing-up. + * + * When we actually see the EOF, we change the status to "new" + * (via libconfig_yyrestart()), so that the user can continue scanning by + * just pointing yyin at a new input file. + */ +#define YY_BUFFER_EOF_PENDING 2 + + }; +#endif /* !YY_STRUCT_YY_BUFFER_STATE */ + +/* We provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general + * "scanner state". + * + * Returns the top of the stack, or NULL. + */ +#define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \ + ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \ + : NULL) + +/* Same as previous macro, but useful when we know that the buffer stack is not + * NULL or when we need an lvalue. For internal use only. + */ +#define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] + +void libconfig_yyrestart (FILE *input_file ,yyscan_t yyscanner ); +void libconfig_yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner ); +YY_BUFFER_STATE libconfig_yy_create_buffer (FILE *file,int size ,yyscan_t yyscanner ); +void libconfig_yy_delete_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner ); +void libconfig_yy_flush_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner ); +void libconfig_yypush_buffer_state (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner ); +void libconfig_yypop_buffer_state (yyscan_t yyscanner ); + +static void libconfig_yyensure_buffer_stack (yyscan_t yyscanner ); +static void libconfig_yy_load_buffer_state (yyscan_t yyscanner ); +static void libconfig_yy_init_buffer (YY_BUFFER_STATE b,FILE *file ,yyscan_t yyscanner ); + +#define YY_FLUSH_BUFFER libconfig_yy_flush_buffer(YY_CURRENT_BUFFER ,yyscanner) + +YY_BUFFER_STATE libconfig_yy_scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner ); +YY_BUFFER_STATE libconfig_yy_scan_string (yyconst char *yy_str ,yyscan_t yyscanner ); +YY_BUFFER_STATE libconfig_yy_scan_bytes (yyconst char *bytes,int len ,yyscan_t yyscanner ); + +void *libconfig_yyalloc (yy_size_t ,yyscan_t yyscanner ); +void *libconfig_yyrealloc (void *,yy_size_t ,yyscan_t yyscanner ); +void libconfig_yyfree (void * ,yyscan_t yyscanner ); + +#define yy_new_buffer libconfig_yy_create_buffer + +#define yy_set_interactive(is_interactive) \ + { \ + if ( ! YY_CURRENT_BUFFER ){ \ + libconfig_yyensure_buffer_stack (yyscanner); \ + YY_CURRENT_BUFFER_LVALUE = \ + libconfig_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ + } + +#define yy_set_bol(at_bol) \ + { \ + if ( ! YY_CURRENT_BUFFER ){\ + libconfig_yyensure_buffer_stack (yyscanner); \ + YY_CURRENT_BUFFER_LVALUE = \ + libconfig_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ + } + +#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) + +#define libconfig_yywrap(n) 1 +#define YY_SKIP_YYWRAP + +typedef unsigned char YY_CHAR; + +typedef int yy_state_type; + +#define yytext_ptr yytext_r + +static yy_state_type yy_get_previous_state (yyscan_t yyscanner ); +static yy_state_type yy_try_NUL_trans (yy_state_type current_state ,yyscan_t yyscanner); +static int yy_get_next_buffer (yyscan_t yyscanner ); +static void yy_fatal_error (yyconst char msg[] ,yyscan_t yyscanner ); + +/* Done after the current pattern has been matched and before the + * corresponding action - sets up yytext. + */ +#define YY_DO_BEFORE_ACTION \ + yyg->yytext_ptr = yy_bp; \ + yyleng = (size_t) (yy_cp - yy_bp); \ + yyg->yy_hold_char = *yy_cp; \ + *yy_cp = '\0'; \ + yyg->yy_c_buf_p = yy_cp; + +#define YY_NUM_RULES 41 +#define YY_END_OF_BUFFER 42 +/* This struct is not used in this scanner, + but its presence is necessary. */ +struct yy_trans_info + { + flex_int32_t yy_verify; + flex_int32_t yy_nxt; + }; +static yyconst flex_int16_t yy_accept[103] = + { 0, + 0, 0, 0, 0, 0, 0, 0, 0, 42, 40, + 21, 20, 20, 5, 40, 36, 37, 28, 40, 23, + 29, 40, 30, 30, 22, 38, 28, 28, 34, 35, + 24, 25, 21, 40, 3, 4, 3, 6, 14, 41, + 16, 19, 41, 21, 0, 39, 28, 29, 30, 29, + 0, 1, 0, 29, 0, 31, 0, 28, 28, 21, + 0, 0, 2, 6, 12, 0, 11, 10, 7, 8, + 9, 16, 18, 17, 0, 29, 29, 0, 0, 29, + 31, 32, 28, 28, 0, 0, 0, 29, 33, 28, + 26, 0, 13, 33, 27, 0, 0, 0, 0, 0, + + 15, 0 + } ; + +static yyconst flex_int32_t yy_ec[256] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, + 1, 4, 5, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 1, 6, 7, 1, 1, 1, 1, 8, + 9, 10, 11, 12, 13, 14, 15, 16, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 18, 19, 1, + 20, 1, 1, 21, 22, 23, 23, 23, 24, 25, + 26, 26, 26, 26, 26, 27, 26, 26, 26, 26, + 26, 28, 29, 30, 31, 26, 26, 32, 26, 26, + 33, 34, 35, 1, 36, 1, 22, 23, 37, 38, + + 39, 40, 26, 26, 41, 26, 26, 42, 26, 43, + 26, 26, 26, 44, 29, 45, 46, 26, 26, 32, + 26, 26, 47, 1, 48, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1 + } ; + +static yyconst flex_int32_t yy_meta[49] = + { 0, + 1, 1, 1, 1, 1, 2, 1, 1, 1, 3, + 1, 1, 3, 1, 1, 4, 4, 1, 1, 1, + 1, 4, 4, 4, 4, 3, 3, 3, 3, 3, + 3, 3, 1, 2, 1, 3, 4, 4, 4, 4, + 3, 3, 3, 3, 3, 3, 1, 1 + } ; + +static yyconst flex_int16_t yy_base[113] = + { 0, + 0, 47, 47, 48, 46, 47, 48, 49, 203, 204, + 200, 204, 204, 204, 198, 204, 204, 0, 45, 204, + 47, 50, 60, 74, 204, 204, 178, 28, 204, 204, + 204, 204, 64, 158, 204, 204, 183, 0, 204, 63, + 0, 204, 83, 195, 193, 204, 0, 88, 102, 98, + 62, 204, 190, 104, 119, 162, 0, 67, 65, 121, + 127, 124, 204, 0, 204, 0, 204, 204, 204, 204, + 204, 0, 204, 204, 108, 117, 122, 134, 132, 136, + 204, 139, 136, 116, 126, 0, 140, 142, 135, 130, + 0, 102, 204, 204, 0, 85, 72, 63, 98, 158, + + 204, 204, 169, 173, 177, 181, 183, 187, 191, 89, + 66, 63 + } ; + +static yyconst flex_int16_t yy_def[113] = + { 0, + 102, 1, 103, 103, 104, 104, 105, 105, 102, 102, + 102, 102, 102, 102, 106, 102, 102, 107, 102, 102, + 102, 102, 102, 102, 102, 102, 107, 107, 102, 102, + 102, 102, 102, 102, 102, 102, 102, 108, 102, 102, + 109, 102, 102, 102, 106, 102, 107, 102, 102, 102, + 102, 102, 106, 102, 102, 102, 110, 107, 107, 102, + 102, 102, 102, 108, 102, 111, 102, 102, 102, 102, + 102, 109, 102, 102, 102, 102, 102, 102, 102, 102, + 102, 110, 107, 107, 102, 112, 102, 102, 102, 107, + 107, 102, 102, 102, 107, 102, 102, 102, 102, 102, + + 102, 0, 102, 102, 102, 102, 102, 102, 102, 102, + 102, 102 + } ; + +static yyconst flex_int16_t yy_nxt[253] = + { 0, + 10, 11, 12, 13, 13, 14, 15, 16, 17, 18, + 19, 20, 19, 21, 22, 23, 24, 25, 26, 25, + 10, 18, 18, 18, 27, 18, 18, 18, 18, 28, + 18, 18, 29, 10, 30, 10, 18, 18, 18, 27, + 18, 18, 18, 18, 28, 18, 31, 32, 33, 36, + 36, 39, 39, 42, 42, 59, 37, 37, 48, 52, + 49, 49, 50, 50, 53, 60, 93, 34, 65, 86, + 51, 59, 75, 54, 75, 49, 49, 76, 76, 40, + 40, 43, 43, 55, 61, 51, 56, 54, 73, 49, + 49, 57, 82, 83, 66, 84, 67, 55, 55, 100, + + 56, 99, 68, 50, 50, 69, 70, 71, 83, 98, + 84, 51, 55, 50, 50, 54, 74, 49, 49, 77, + 77, 51, 60, 76, 76, 55, 51, 78, 56, 79, + 97, 79, 76, 76, 80, 80, 51, 77, 77, 91, + 55, 61, 78, 96, 87, 78, 87, 80, 80, 88, + 88, 80, 80, 95, 91, 88, 88, 88, 88, 100, + 78, 94, 92, 101, 90, 89, 85, 62, 95, 35, + 35, 35, 35, 38, 38, 38, 38, 41, 41, 41, + 41, 45, 45, 45, 45, 47, 47, 64, 81, 64, + 64, 72, 46, 72, 72, 46, 44, 63, 62, 58, + + 46, 44, 102, 9, 102, 102, 102, 102, 102, 102, + 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, + 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, + 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, + 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, + 102, 102 + } ; + +static yyconst flex_int16_t yy_chk[253] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, + 4, 5, 6, 7, 8, 28, 3, 4, 19, 22, + 19, 19, 21, 21, 22, 33, 112, 2, 40, 111, + 21, 28, 51, 23, 51, 23, 23, 51, 51, 5, + 6, 7, 8, 23, 33, 21, 23, 24, 43, 24, + 24, 23, 110, 58, 40, 59, 40, 24, 23, 99, + + 24, 98, 40, 48, 48, 40, 40, 40, 58, 97, + 59, 48, 24, 50, 50, 49, 43, 49, 49, 54, + 54, 50, 60, 75, 75, 49, 48, 54, 49, 55, + 96, 55, 76, 76, 55, 55, 50, 77, 77, 84, + 49, 60, 54, 92, 78, 77, 78, 79, 79, 78, + 78, 80, 80, 90, 84, 87, 87, 88, 88, 100, + 77, 89, 85, 100, 83, 82, 62, 61, 90, 103, + 103, 103, 103, 104, 104, 104, 104, 105, 105, 105, + 105, 106, 106, 106, 106, 107, 107, 108, 56, 108, + 108, 109, 53, 109, 109, 45, 44, 37, 34, 27, + + 15, 11, 9, 102, 102, 102, 102, 102, 102, 102, + 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, + 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, + 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, + 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, + 102, 102 + } ; + +/* Table of booleans, true if rule could match eol. */ +static yyconst flex_int32_t yy_rule_can_match_eol[42] = + { 0, +0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, }; + +/* The intent behind this definition is that it'll catch + * any uses of REJECT which flex missed. + */ +#define REJECT reject_used_but_not_detected +#define yymore() yymore_used_but_not_detected +#define YY_MORE_ADJ 0 +#define YY_RESTORE_YY_MORE_OFFSET +#line 1 "scanner.l" +/* -*- mode: C -*- */ +/* -------------------------------------------------------------------------- + libconfig - A library for processing structured configuration files + Copyright (C) 2005-2010 Mark A Lindner + + This file is part of libconfig. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License + as published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, see + . + ---------------------------------------------------------------------------- +*/ +#define YY_NO_UNISTD_H 1 +#line 35 "scanner.l" + +#ifdef _MSC_VER +#pragma warning (disable: 4996) +#endif + +#include +#include +#include +#include "grammar.h" +#include "wincompat.h" +#include "parsectx.h" +#include "scanctx.h" + +#define YY_NO_INPUT // Suppress generation of useless input() function + +static unsigned long long fromhex(const char *s) +{ +#ifdef __MINGW32__ + + /* MinGW's strtoull() seems to be broken; it only returns the lower + * 32 bits... + */ + + const char *p = s; + unsigned long long val = 0; + + if(*p != '0') + return(0); + + ++p; + + if(*p != 'x' && *p != 'X') + return(0); + + for(++p; isxdigit(*p); ++p) + { + val <<= 4; + val |= ((*p < 'A') ? (*p & 0xF) : (9 + (*p & 0x7))); + } + + return(val); + +#else /* ! __MINGW32__ */ + + return(strtoull(s, NULL, 16)); + +#endif /* __MINGW32__ */ +} + + +#line 626 "scanner.c" + +#define INITIAL 0 +#define COMMENT 1 +#define STRING 2 +#define INCLUDE 3 + +#ifndef YY_NO_UNISTD_H +/* Special case for "unistd.h", since it is non-ANSI. We include it way + * down here because we want the user's section 1 to have been scanned first. + * The user has a chance to override it with an option. + */ +#include +#endif + +#define YY_EXTRA_TYPE struct scan_context * + +/* Holds the entire state of the reentrant scanner. */ +struct yyguts_t + { + + /* User-defined. Not touched by flex. */ + YY_EXTRA_TYPE yyextra_r; + + /* The rest are the same as the globals declared in the non-reentrant scanner. */ + FILE *yyin_r, *yyout_r; + size_t yy_buffer_stack_top; /**< index of top of stack. */ + size_t yy_buffer_stack_max; /**< capacity of stack. */ + YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */ + char yy_hold_char; + int yy_n_chars; + int yyleng_r; + char *yy_c_buf_p; + int yy_init; + int yy_start; + int yy_did_buffer_switch_on_eof; + int yy_start_stack_ptr; + int yy_start_stack_depth; + int *yy_start_stack; + yy_state_type yy_last_accepting_state; + char* yy_last_accepting_cpos; + + int yylineno_r; + int yy_flex_debug_r; + + char *yytext_r; + int yy_more_flag; + int yy_more_len; + + YYSTYPE * yylval_r; + + }; /* end struct yyguts_t */ + +static int yy_init_globals (yyscan_t yyscanner ); + + /* This must go here because YYSTYPE and YYLTYPE are included + * from bison output in section 1.*/ + # define yylval yyg->yylval_r + +int libconfig_yylex_init (yyscan_t* scanner); + +int libconfig_yylex_init_extra (YY_EXTRA_TYPE user_defined,yyscan_t* scanner); + +/* Accessor methods to globals. + These are made visible to non-reentrant scanners for convenience. */ + +int libconfig_yylex_destroy (yyscan_t yyscanner ); + +int libconfig_yyget_debug (yyscan_t yyscanner ); + +void libconfig_yyset_debug (int debug_flag ,yyscan_t yyscanner ); + +YY_EXTRA_TYPE libconfig_yyget_extra (yyscan_t yyscanner ); + +void libconfig_yyset_extra (YY_EXTRA_TYPE user_defined ,yyscan_t yyscanner ); + +FILE *libconfig_yyget_in (yyscan_t yyscanner ); + +void libconfig_yyset_in (FILE * in_str ,yyscan_t yyscanner ); + +FILE *libconfig_yyget_out (yyscan_t yyscanner ); + +void libconfig_yyset_out (FILE * out_str ,yyscan_t yyscanner ); + +int libconfig_yyget_leng (yyscan_t yyscanner ); + +char *libconfig_yyget_text (yyscan_t yyscanner ); + +int libconfig_yyget_lineno (yyscan_t yyscanner ); + +void libconfig_yyset_lineno (int line_number ,yyscan_t yyscanner ); + +YYSTYPE * libconfig_yyget_lval (yyscan_t yyscanner ); + +void libconfig_yyset_lval (YYSTYPE * yylval_param ,yyscan_t yyscanner ); + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int libconfig_yywrap (yyscan_t yyscanner ); +#else +extern int libconfig_yywrap (yyscan_t yyscanner ); +#endif +#endif + +#ifndef yytext_ptr +static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner); +#endif + +#ifndef YY_NO_INPUT + +#ifdef __cplusplus +static int yyinput (yyscan_t yyscanner ); +#else +static int input (yyscan_t yyscanner ); +#endif + +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k */ +#define YY_READ_BUF_SIZE 16384 +#else +#define YY_READ_BUF_SIZE 8192 +#endif /* __ia64__ */ +#endif + +/* Copy whatever the last rule matched to the standard output. */ +#ifndef ECHO +/* This used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite(). + */ +#define ECHO do { if (fwrite( yytext, yyleng, 1, yyout )) {} } while (0) +#endif + +/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#ifndef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ + { \ + int c = '*'; \ + size_t n; \ + for ( n = 0; n < max_size && \ + (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ + buf[n] = (char) c; \ + if ( c == '\n' ) \ + buf[n++] = (char) c; \ + if ( c == EOF && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + result = n; \ + } \ + else \ + { \ + errno=0; \ + while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \ + { \ + if( errno != EINTR) \ + { \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + break; \ + } \ + errno=0; \ + clearerr(yyin); \ + } \ + }\ +\ + +#endif + +/* No semi-colon after return; correct usage is to write "yyterminate();" - + * we don't want an extra ';' after the "return" because that will cause + * some compilers to complain about unreachable statements. + */ +#ifndef yyterminate +#define yyterminate() return YY_NULL +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Report a fatal error. */ +#ifndef YY_FATAL_ERROR +#define YY_FATAL_ERROR(msg) yy_fatal_error( msg , yyscanner) +#endif + +/* end tables serialization structures and prototypes */ + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL_IS_OURS 1 + +extern int libconfig_yylex \ + (YYSTYPE * yylval_param ,yyscan_t yyscanner); + +#define YY_DECL int libconfig_yylex \ + (YYSTYPE * yylval_param , yyscan_t yyscanner) +#endif /* !YY_DECL */ + +/* Code executed at the beginning of each rule, after yytext and yyleng + * have been set up. + */ +#ifndef YY_USER_ACTION +#define YY_USER_ACTION +#endif + +/* Code executed at the end of each rule. */ +#ifndef YY_BREAK +#define YY_BREAK break; +#endif + +#define YY_RULE_SETUP \ + if ( yyleng > 0 ) \ + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = \ + (yytext[yyleng - 1] == '\n'); \ + YY_USER_ACTION + +/** The main scanner function which does all the work. + */ +YY_DECL +{ + register yy_state_type yy_current_state; + register char *yy_cp, *yy_bp; + register int yy_act; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + +#line 100 "scanner.l" + + +#line 869 "scanner.c" + + yylval = yylval_param; + + if ( !yyg->yy_init ) + { + yyg->yy_init = 1; + +#ifdef YY_USER_INIT + YY_USER_INIT; +#endif + + if ( ! yyg->yy_start ) + yyg->yy_start = 1; /* first start state */ + + if ( ! yyin ) + yyin = stdin; + + if ( ! yyout ) + yyout = stdout; + + if ( ! YY_CURRENT_BUFFER ) { + libconfig_yyensure_buffer_stack (yyscanner); + YY_CURRENT_BUFFER_LVALUE = + libconfig_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); + } + + libconfig_yy_load_buffer_state(yyscanner ); + } + + while ( 1 ) /* loops until end-of-file is reached */ + { + yy_cp = yyg->yy_c_buf_p; + + /* Support of yytext. */ + *yy_cp = yyg->yy_hold_char; + + /* yy_bp points to the position in yy_ch_buf of the start of + * the current run. + */ + yy_bp = yy_cp; + + yy_current_state = yyg->yy_start; + yy_current_state += YY_AT_BOL(); +yy_match: + do + { + register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; + if ( yy_accept[yy_current_state] ) + { + yyg->yy_last_accepting_state = yy_current_state; + yyg->yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 103 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + ++yy_cp; + } + while ( yy_base[yy_current_state] != 204 ); + +yy_find_action: + yy_act = yy_accept[yy_current_state]; + if ( yy_act == 0 ) + { /* have to back up */ + yy_cp = yyg->yy_last_accepting_cpos; + yy_current_state = yyg->yy_last_accepting_state; + yy_act = yy_accept[yy_current_state]; + } + + YY_DO_BEFORE_ACTION; + + if ( yy_act != YY_END_OF_BUFFER && yy_rule_can_match_eol[yy_act] ) + { + int yyl; + for ( yyl = 0; yyl < yyleng; ++yyl ) + if ( yytext[yyl] == '\n' ) + + do{ yylineno++; + yycolumn=0; + }while(0) +; + } + +do_action: /* This label is used only to access EOF actions. */ + + switch ( yy_act ) + { /* beginning of action switch */ + case 0: /* must back up */ + /* undo the effects of YY_DO_BEFORE_ACTION */ + *yy_cp = yyg->yy_hold_char; + yy_cp = yyg->yy_last_accepting_cpos; + yy_current_state = yyg->yy_last_accepting_state; + goto yy_find_action; + +case 1: +YY_RULE_SETUP +#line 102 "scanner.l" +{ BEGIN COMMENT; } + YY_BREAK +case 2: +YY_RULE_SETUP +#line 103 "scanner.l" +{ BEGIN INITIAL; } + YY_BREAK +case 3: +YY_RULE_SETUP +#line 104 "scanner.l" +{ /* ignore */ } + YY_BREAK +case 4: +/* rule 4 can match eol */ +YY_RULE_SETUP +#line 105 "scanner.l" +{ /* ignore */ } + YY_BREAK +case 5: +YY_RULE_SETUP +#line 107 "scanner.l" +{ BEGIN STRING; } + YY_BREAK +case 6: +/* rule 6 can match eol */ +YY_RULE_SETUP +#line 108 "scanner.l" +{ scanctx_append_string(yyextra, yytext); } + YY_BREAK +case 7: +YY_RULE_SETUP +#line 109 "scanner.l" +{ scanctx_append_string(yyextra, "\n"); } + YY_BREAK +case 8: +YY_RULE_SETUP +#line 110 "scanner.l" +{ scanctx_append_string(yyextra, "\r"); } + YY_BREAK +case 9: +YY_RULE_SETUP +#line 111 "scanner.l" +{ scanctx_append_string(yyextra, "\t"); } + YY_BREAK +case 10: +YY_RULE_SETUP +#line 112 "scanner.l" +{ scanctx_append_string(yyextra, "\f"); } + YY_BREAK +case 11: +YY_RULE_SETUP +#line 113 "scanner.l" +{ scanctx_append_string(yyextra, "\\"); } + YY_BREAK +case 12: +YY_RULE_SETUP +#line 114 "scanner.l" +{ scanctx_append_string(yyextra, "\""); } + YY_BREAK +case 13: +YY_RULE_SETUP +#line 115 "scanner.l" +{ + char c[2] = { (char)(strtol(yytext + 2, NULL, 16) & 0xFF), + 0 }; + scanctx_append_string(yyextra, c); + } + YY_BREAK +case 14: +YY_RULE_SETUP +#line 120 "scanner.l" +{ + yylval->sval = scanctx_take_string(yyextra); + BEGIN INITIAL; + return(TOK_STRING); + } + YY_BREAK +case 15: +YY_RULE_SETUP +#line 126 "scanner.l" +{ BEGIN INCLUDE; } + YY_BREAK +case 16: +/* rule 16 can match eol */ +YY_RULE_SETUP +#line 127 "scanner.l" +{ scanctx_append_string(yyextra, yytext); } + YY_BREAK +case 17: +YY_RULE_SETUP +#line 128 "scanner.l" +{ scanctx_append_string(yyextra, "\\"); } + YY_BREAK +case 18: +YY_RULE_SETUP +#line 129 "scanner.l" +{ scanctx_append_string(yyextra, "\""); } + YY_BREAK +case 19: +YY_RULE_SETUP +#line 130 "scanner.l" +{ + const char *error; + FILE *fp = scanctx_push_include(yyextra, + (void *)YY_CURRENT_BUFFER, + &error); + if(fp) + { + yyin = fp; + libconfig_yy_switch_to_buffer(libconfig_yy_create_buffer(yyin,YY_BUF_SIZE,yyscanner),yyscanner); + } + else + { + yyextra->config->error_text = error; + yyextra->config->error_file = scanctx_current_filename( + yyextra); + yyextra->config->error_line = libconfig_yyget_lineno( + yyscanner); + return TOK_ERROR; + } + BEGIN INITIAL; + } + YY_BREAK +case 20: +/* rule 20 can match eol */ +YY_RULE_SETUP +#line 154 "scanner.l" +{ /* ignore */ } + YY_BREAK +case 21: +YY_RULE_SETUP +#line 155 "scanner.l" +{ /* ignore */ } + YY_BREAK +case 22: +YY_RULE_SETUP +#line 157 "scanner.l" +{ return(TOK_EQUALS); } + YY_BREAK +case 23: +YY_RULE_SETUP +#line 158 "scanner.l" +{ return(TOK_COMMA); } + YY_BREAK +case 24: +YY_RULE_SETUP +#line 159 "scanner.l" +{ return(TOK_GROUP_START); } + YY_BREAK +case 25: +YY_RULE_SETUP +#line 160 "scanner.l" +{ return(TOK_GROUP_END); } + YY_BREAK +case 26: +YY_RULE_SETUP +#line 161 "scanner.l" +{ yylval->ival = 1; return(TOK_BOOLEAN); } + YY_BREAK +case 27: +YY_RULE_SETUP +#line 162 "scanner.l" +{ yylval->ival = 0; return(TOK_BOOLEAN); } + YY_BREAK +case 28: +YY_RULE_SETUP +#line 163 "scanner.l" +{ yylval->sval = yytext; return(TOK_NAME); } + YY_BREAK +case 29: +YY_RULE_SETUP +#line 164 "scanner.l" +{ yylval->fval = atof(yytext); return(TOK_FLOAT); } + YY_BREAK +case 30: +YY_RULE_SETUP +#line 165 "scanner.l" +{ yylval->ival = atoi(yytext); return(TOK_INTEGER); } + YY_BREAK +case 31: +YY_RULE_SETUP +#line 166 "scanner.l" +{ yylval->llval = atoll(yytext); return(TOK_INTEGER64); } + YY_BREAK +case 32: +YY_RULE_SETUP +#line 167 "scanner.l" +{ + yylval->ival = strtoul(yytext, NULL, 16); + return(TOK_HEX); + } + YY_BREAK +case 33: +YY_RULE_SETUP +#line 171 "scanner.l" +{ yylval->llval = fromhex(yytext); return(TOK_HEX64); } + YY_BREAK +case 34: +YY_RULE_SETUP +#line 172 "scanner.l" +{ return(TOK_ARRAY_START); } + YY_BREAK +case 35: +YY_RULE_SETUP +#line 173 "scanner.l" +{ return(TOK_ARRAY_END); } + YY_BREAK +case 36: +YY_RULE_SETUP +#line 174 "scanner.l" +{ return(TOK_LIST_START); } + YY_BREAK +case 37: +YY_RULE_SETUP +#line 175 "scanner.l" +{ return(TOK_LIST_END); } + YY_BREAK +case 38: +YY_RULE_SETUP +#line 176 "scanner.l" +{ return(TOK_SEMICOLON); } + YY_BREAK +case 39: +*yy_cp = yyg->yy_hold_char; /* undo effects of setting up yytext */ +yyg->yy_c_buf_p = yy_cp -= 1; +YY_DO_BEFORE_ACTION; /* set up yytext again */ +YY_RULE_SETUP +#line 177 "scanner.l" +{ /* ignore */ } + YY_BREAK +case 40: +YY_RULE_SETUP +#line 178 "scanner.l" +{ return(TOK_GARBAGE); } + YY_BREAK +case YY_STATE_EOF(INITIAL): +case YY_STATE_EOF(COMMENT): +case YY_STATE_EOF(STRING): +case YY_STATE_EOF(INCLUDE): +#line 180 "scanner.l" +{ + YY_BUFFER_STATE buf = (YY_BUFFER_STATE)scanctx_pop_include( + yyextra); + if(buf) + { + libconfig_yy_delete_buffer(YY_CURRENT_BUFFER,yyscanner); + libconfig_yy_switch_to_buffer(buf,yyscanner); + } + else + yyterminate(); + } + YY_BREAK +case 41: +YY_RULE_SETUP +#line 191 "scanner.l" +ECHO; + YY_BREAK +#line 1227 "scanner.c" + + case YY_END_OF_BUFFER: + { + /* Amount of text matched not including the EOB char. */ + int yy_amount_of_matched_text = (int) (yy_cp - yyg->yytext_ptr) - 1; + + /* Undo the effects of YY_DO_BEFORE_ACTION. */ + *yy_cp = yyg->yy_hold_char; + YY_RESTORE_YY_MORE_OFFSET + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) + { + /* We're scanning a new file or input source. It's + * possible that this happened because the user + * just pointed yyin at a new source and called + * libconfig_yylex(). If so, then we have to assure + * consistency between YY_CURRENT_BUFFER and our + * globals. Here is the right place to do so, because + * this is the first action (other than possibly a + * back-up) that will match for the new input source. + */ + yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; + } + + /* Note that here we test for yy_c_buf_p "<=" to the position + * of the first EOB in the buffer, since yy_c_buf_p will + * already have been incremented past the NUL character + * (since all states make transitions on EOB to the + * end-of-buffer state). Contrast this with the test + * in input(). + */ + if ( yyg->yy_c_buf_p <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) + { /* This was really a NUL. */ + yy_state_type yy_next_state; + + yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( yyscanner ); + + /* Okay, we're now positioned to make the NUL + * transition. We couldn't have + * yy_get_previous_state() go ahead and do it + * for us because it doesn't know how to deal + * with the possibility of jamming (and we don't + * want to build jamming into it because then it + * will run more slowly). + */ + + yy_next_state = yy_try_NUL_trans( yy_current_state , yyscanner); + + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + + if ( yy_next_state ) + { + /* Consume the NUL. */ + yy_cp = ++yyg->yy_c_buf_p; + yy_current_state = yy_next_state; + goto yy_match; + } + + else + { + yy_cp = yyg->yy_c_buf_p; + goto yy_find_action; + } + } + + else switch ( yy_get_next_buffer( yyscanner ) ) + { + case EOB_ACT_END_OF_FILE: + { + yyg->yy_did_buffer_switch_on_eof = 0; + + if ( libconfig_yywrap(yyscanner ) ) + { + /* Note: because we've taken care in + * yy_get_next_buffer() to have set up + * yytext, we can now set up + * yy_c_buf_p so that if some total + * hoser (like flex itself) wants to + * call the scanner after we return the + * YY_NULL, it'll still work - another + * YY_NULL will get returned. + */ + yyg->yy_c_buf_p = yyg->yytext_ptr + YY_MORE_ADJ; + + yy_act = YY_STATE_EOF(YY_START); + goto do_action; + } + + else + { + if ( ! yyg->yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; + } + break; + } + + case EOB_ACT_CONTINUE_SCAN: + yyg->yy_c_buf_p = + yyg->yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( yyscanner ); + + yy_cp = yyg->yy_c_buf_p; + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + goto yy_match; + + case EOB_ACT_LAST_MATCH: + yyg->yy_c_buf_p = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars]; + + yy_current_state = yy_get_previous_state( yyscanner ); + + yy_cp = yyg->yy_c_buf_p; + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + goto yy_find_action; + } + break; + } + + default: + YY_FATAL_ERROR( + "fatal flex scanner internal error--no action found" ); + } /* end of action switch */ + } /* end of scanning one token */ +} /* end of libconfig_yylex */ + +/* yy_get_next_buffer - try to read in a new buffer + * + * Returns a code representing an action: + * EOB_ACT_LAST_MATCH - + * EOB_ACT_CONTINUE_SCAN - continue scanning from current position + * EOB_ACT_END_OF_FILE - end of file + */ +static int yy_get_next_buffer (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; + register char *source = yyg->yytext_ptr; + register int number_to_move, i; + int ret_val; + + if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] ) + YY_FATAL_ERROR( + "fatal flex scanner internal error--end of buffer missed" ); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) + { /* Don't try to fill the buffer, so this is an EOF. */ + if ( yyg->yy_c_buf_p - yyg->yytext_ptr - YY_MORE_ADJ == 1 ) + { + /* We matched a single character, the EOB, so + * treat this as a final EOF. + */ + return EOB_ACT_END_OF_FILE; + } + + else + { + /* We matched some text prior to the EOB, first + * process it. + */ + return EOB_ACT_LAST_MATCH; + } + } + + /* Try to read more data. */ + + /* First move last chars to start of buffer. */ + number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr) - 1; + + for ( i = 0; i < number_to_move; ++i ) + *(dest++) = *(source++); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) + /* don't do the read, it's not guaranteed to return an EOF, + * just force an EOF + */ + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = 0; + + else + { + int num_to_read = + YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; + + while ( num_to_read <= 0 ) + { /* Not enough room in the buffer - grow it. */ + + /* just a shorter name for the current buffer */ + YY_BUFFER_STATE b = YY_CURRENT_BUFFER; + + int yy_c_buf_p_offset = + (int) (yyg->yy_c_buf_p - b->yy_ch_buf); + + if ( b->yy_is_our_buffer ) + { + int new_size = b->yy_buf_size * 2; + + if ( new_size <= 0 ) + b->yy_buf_size += b->yy_buf_size / 8; + else + b->yy_buf_size *= 2; + + b->yy_ch_buf = (char *) + /* Include room in for 2 EOB chars. */ + libconfig_yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ,yyscanner ); + } + else + /* Can't grow it, we don't own it. */ + b->yy_ch_buf = 0; + + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( + "fatal error - scanner input buffer overflow" ); + + yyg->yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset]; + + num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - + number_to_move - 1; + + } + + if ( num_to_read > YY_READ_BUF_SIZE ) + num_to_read = YY_READ_BUF_SIZE; + + /* Read in more data. */ + YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), + yyg->yy_n_chars, (size_t) num_to_read ); + + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + if ( yyg->yy_n_chars == 0 ) + { + if ( number_to_move == YY_MORE_ADJ ) + { + ret_val = EOB_ACT_END_OF_FILE; + libconfig_yyrestart(yyin ,yyscanner); + } + + else + { + ret_val = EOB_ACT_LAST_MATCH; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = + YY_BUFFER_EOF_PENDING; + } + } + + else + ret_val = EOB_ACT_CONTINUE_SCAN; + + if ((yy_size_t) (yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { + /* Extend the array by 50%, plus the number we really need. */ + yy_size_t new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1); + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) libconfig_yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ,yyscanner ); + if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); + } + + yyg->yy_n_chars += number_to_move; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] = YY_END_OF_BUFFER_CHAR; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; + + yyg->yytext_ptr = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; + + return ret_val; +} + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + + static yy_state_type yy_get_previous_state (yyscan_t yyscanner) +{ + register yy_state_type yy_current_state; + register char *yy_cp; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + yy_current_state = yyg->yy_start; + yy_current_state += YY_AT_BOL(); + + for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp ) + { + register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); + if ( yy_accept[yy_current_state] ) + { + yyg->yy_last_accepting_state = yy_current_state; + yyg->yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 103 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + } + + return yy_current_state; +} + +/* yy_try_NUL_trans - try to make a transition on the NUL character + * + * synopsis + * next_state = yy_try_NUL_trans( current_state ); + */ + static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state , yyscan_t yyscanner) +{ + register int yy_is_jam; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */ + register char *yy_cp = yyg->yy_c_buf_p; + + register YY_CHAR yy_c = 1; + if ( yy_accept[yy_current_state] ) + { + yyg->yy_last_accepting_state = yy_current_state; + yyg->yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 103 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + yy_is_jam = (yy_current_state == 102); + + return yy_is_jam ? 0 : yy_current_state; +} + +#ifndef YY_NO_INPUT +#ifdef __cplusplus + static int yyinput (yyscan_t yyscanner) +#else + static int input (yyscan_t yyscanner) +#endif + +{ + int c; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + *yyg->yy_c_buf_p = yyg->yy_hold_char; + + if ( *yyg->yy_c_buf_p == YY_END_OF_BUFFER_CHAR ) + { + /* yy_c_buf_p now points to the character we want to return. + * If this occurs *before* the EOB characters, then it's a + * valid NUL; if not, then we've hit the end of the buffer. + */ + if ( yyg->yy_c_buf_p < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) + /* This was really a NUL. */ + *yyg->yy_c_buf_p = '\0'; + + else + { /* need more input */ + int offset = yyg->yy_c_buf_p - yyg->yytext_ptr; + ++yyg->yy_c_buf_p; + + switch ( yy_get_next_buffer( yyscanner ) ) + { + case EOB_ACT_LAST_MATCH: + /* This happens because yy_g_n_b() + * sees that we've accumulated a + * token and flags that we need to + * try matching the token before + * proceeding. But for input(), + * there's no matching to consider. + * So convert the EOB_ACT_LAST_MATCH + * to EOB_ACT_END_OF_FILE. + */ + + /* Reset buffer status. */ + libconfig_yyrestart(yyin ,yyscanner); + + /*FALLTHROUGH*/ + + case EOB_ACT_END_OF_FILE: + { + if ( libconfig_yywrap(yyscanner ) ) + return EOF; + + if ( ! yyg->yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; +#ifdef __cplusplus + return yyinput(yyscanner); +#else + return input(yyscanner); +#endif + } + + case EOB_ACT_CONTINUE_SCAN: + yyg->yy_c_buf_p = yyg->yytext_ptr + offset; + break; + } + } + } + + c = *(unsigned char *) yyg->yy_c_buf_p; /* cast for 8-bit char's */ + *yyg->yy_c_buf_p = '\0'; /* preserve yytext */ + yyg->yy_hold_char = *++yyg->yy_c_buf_p; + + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = (c == '\n'); + if ( YY_CURRENT_BUFFER_LVALUE->yy_at_bol ) + + do{ yylineno++; + yycolumn=0; + }while(0) +; + + return c; +} +#endif /* ifndef YY_NO_INPUT */ + +/** Immediately switch to a different input stream. + * @param input_file A readable stream. + * @param yyscanner The scanner object. + * @note This function does not reset the start condition to @c INITIAL . + */ + void libconfig_yyrestart (FILE * input_file , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if ( ! YY_CURRENT_BUFFER ){ + libconfig_yyensure_buffer_stack (yyscanner); + YY_CURRENT_BUFFER_LVALUE = + libconfig_yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); + } + + libconfig_yy_init_buffer(YY_CURRENT_BUFFER,input_file ,yyscanner); + libconfig_yy_load_buffer_state(yyscanner ); +} + +/** Switch to a different input buffer. + * @param new_buffer The new input buffer. + * @param yyscanner The scanner object. + */ + void libconfig_yy_switch_to_buffer (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* TODO. We should be able to replace this entire function body + * with + * libconfig_yypop_buffer_state(); + * libconfig_yypush_buffer_state(new_buffer); + */ + libconfig_yyensure_buffer_stack (yyscanner); + if ( YY_CURRENT_BUFFER == new_buffer ) + return; + + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *yyg->yy_c_buf_p = yyg->yy_hold_char; + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + YY_CURRENT_BUFFER_LVALUE = new_buffer; + libconfig_yy_load_buffer_state(yyscanner ); + + /* We don't actually know whether we did this switch during + * EOF (libconfig_yywrap()) processing, but the only time this flag + * is looked at is after libconfig_yywrap() is called, so it's safe + * to go ahead and always set it. + */ + yyg->yy_did_buffer_switch_on_eof = 1; +} + +static void libconfig_yy_load_buffer_state (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + yyg->yytext_ptr = yyg->yy_c_buf_p = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; + yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; + yyg->yy_hold_char = *yyg->yy_c_buf_p; +} + +/** Allocate and initialize an input buffer state. + * @param file A readable stream. + * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. + * @param yyscanner The scanner object. + * @return the allocated buffer state. + */ + YY_BUFFER_STATE libconfig_yy_create_buffer (FILE * file, int size , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + + b = (YY_BUFFER_STATE) libconfig_yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in libconfig_yy_create_buffer()" ); + + b->yy_buf_size = size; + + /* yy_ch_buf has to be 2 characters longer than the size given because + * we need to put in 2 end-of-buffer characters. + */ + b->yy_ch_buf = (char *) libconfig_yyalloc(b->yy_buf_size + 2 ,yyscanner ); + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in libconfig_yy_create_buffer()" ); + + b->yy_is_our_buffer = 1; + + libconfig_yy_init_buffer(b,file ,yyscanner); + + return b; +} + +/** Destroy the buffer. + * @param b a buffer created with libconfig_yy_create_buffer() + * @param yyscanner The scanner object. + */ + void libconfig_yy_delete_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if ( ! b ) + return; + + if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ + YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; + + if ( b->yy_is_our_buffer ) + libconfig_yyfree((void *) b->yy_ch_buf ,yyscanner ); + + libconfig_yyfree((void *) b ,yyscanner ); +} + +#ifndef __cplusplus +extern int isatty (int ); +#endif /* __cplusplus */ + +/* Initializes or reinitializes a buffer. + * This function is sometimes called more than once on the same buffer, + * such as during a libconfig_yyrestart() or at EOF. + */ + static void libconfig_yy_init_buffer (YY_BUFFER_STATE b, FILE * file , yyscan_t yyscanner) + +{ + int oerrno = errno; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + libconfig_yy_flush_buffer(b ,yyscanner); + + b->yy_input_file = file; + b->yy_fill_buffer = 1; + + /* If b is the current buffer, then libconfig_yy_init_buffer was _probably_ + * called from libconfig_yyrestart() or through yy_get_next_buffer. + * In that case, we don't want to reset the lineno or column. + */ + if (b != YY_CURRENT_BUFFER){ + b->yy_bs_lineno = 1; + b->yy_bs_column = 0; + } + + b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; + + errno = oerrno; +} + +/** Discard all buffered characters. On the next scan, YY_INPUT will be called. + * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. + * @param yyscanner The scanner object. + */ + void libconfig_yy_flush_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if ( ! b ) + return; + + b->yy_n_chars = 0; + + /* We always need two end-of-buffer characters. The first causes + * a transition to the end-of-buffer state. The second causes + * a jam in that state. + */ + b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; + b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + + b->yy_buf_pos = &b->yy_ch_buf[0]; + + b->yy_at_bol = 1; + b->yy_buffer_status = YY_BUFFER_NEW; + + if ( b == YY_CURRENT_BUFFER ) + libconfig_yy_load_buffer_state(yyscanner ); +} + +/** Pushes the new state onto the stack. The new state becomes + * the current state. This function will allocate the stack + * if necessary. + * @param new_buffer The new state. + * @param yyscanner The scanner object. + */ +void libconfig_yypush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if (new_buffer == NULL) + return; + + libconfig_yyensure_buffer_stack(yyscanner); + + /* This block is copied from libconfig_yy_switch_to_buffer. */ + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *yyg->yy_c_buf_p = yyg->yy_hold_char; + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + /* Only push if top exists. Otherwise, replace top. */ + if (YY_CURRENT_BUFFER) + yyg->yy_buffer_stack_top++; + YY_CURRENT_BUFFER_LVALUE = new_buffer; + + /* copied from libconfig_yy_switch_to_buffer. */ + libconfig_yy_load_buffer_state(yyscanner ); + yyg->yy_did_buffer_switch_on_eof = 1; +} + +/** Removes and deletes the top of the stack, if present. + * The next element becomes the new top. + * @param yyscanner The scanner object. + */ +void libconfig_yypop_buffer_state (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if (!YY_CURRENT_BUFFER) + return; + + libconfig_yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner); + YY_CURRENT_BUFFER_LVALUE = NULL; + if (yyg->yy_buffer_stack_top > 0) + --yyg->yy_buffer_stack_top; + + if (YY_CURRENT_BUFFER) { + libconfig_yy_load_buffer_state(yyscanner ); + yyg->yy_did_buffer_switch_on_eof = 1; + } +} + +/* Allocates the stack if it does not exist. + * Guarantees space for at least one push. + */ +static void libconfig_yyensure_buffer_stack (yyscan_t yyscanner) +{ + int num_to_alloc; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (!yyg->yy_buffer_stack) { + + /* First allocation is just for 2 elements, since we don't know if this + * scanner will even need a stack. We use 2 instead of 1 to avoid an + * immediate realloc on the next call. + */ + num_to_alloc = 1; + yyg->yy_buffer_stack = (struct yy_buffer_state**)libconfig_yyalloc + (num_to_alloc * sizeof(struct yy_buffer_state*) + , yyscanner); + if ( ! yyg->yy_buffer_stack ) + YY_FATAL_ERROR( "out of dynamic memory in libconfig_yyensure_buffer_stack()" ); + + memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*)); + + yyg->yy_buffer_stack_max = num_to_alloc; + yyg->yy_buffer_stack_top = 0; + return; + } + + if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){ + + /* Increase the buffer to prepare for a possible push. */ + int grow_size = 8 /* arbitrary grow size */; + + num_to_alloc = yyg->yy_buffer_stack_max + grow_size; + yyg->yy_buffer_stack = (struct yy_buffer_state**)libconfig_yyrealloc + (yyg->yy_buffer_stack, + num_to_alloc * sizeof(struct yy_buffer_state*) + , yyscanner); + if ( ! yyg->yy_buffer_stack ) + YY_FATAL_ERROR( "out of dynamic memory in libconfig_yyensure_buffer_stack()" ); + + /* zero only the new slots.*/ + memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, grow_size * sizeof(struct yy_buffer_state*)); + yyg->yy_buffer_stack_max = num_to_alloc; + } +} + +/** Setup the input buffer state to scan directly from a user-specified character buffer. + * @param base the character buffer + * @param size the size in bytes of the character buffer + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE libconfig_yy_scan_buffer (char * base, yy_size_t size , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + + if ( size < 2 || + base[size-2] != YY_END_OF_BUFFER_CHAR || + base[size-1] != YY_END_OF_BUFFER_CHAR ) + /* They forgot to leave room for the EOB's. */ + return 0; + + b = (YY_BUFFER_STATE) libconfig_yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in libconfig_yy_scan_buffer()" ); + + b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ + b->yy_buf_pos = b->yy_ch_buf = base; + b->yy_is_our_buffer = 0; + b->yy_input_file = 0; + b->yy_n_chars = b->yy_buf_size; + b->yy_is_interactive = 0; + b->yy_at_bol = 1; + b->yy_fill_buffer = 0; + b->yy_buffer_status = YY_BUFFER_NEW; + + libconfig_yy_switch_to_buffer(b ,yyscanner ); + + return b; +} + +/** Setup the input buffer state to scan a string. The next call to libconfig_yylex() will + * scan from a @e copy of @a str. + * @param yystr a NUL-terminated string to scan + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + * @note If you want to scan bytes that may contain NUL values, then use + * libconfig_yy_scan_bytes() instead. + */ +YY_BUFFER_STATE libconfig_yy_scan_string (yyconst char * yystr , yyscan_t yyscanner) +{ + + return libconfig_yy_scan_bytes(yystr,strlen(yystr) ,yyscanner); +} + +/** Setup the input buffer state to scan the given bytes. The next call to libconfig_yylex() will + * scan from a @e copy of @a bytes. + * @param yybytes the byte buffer to scan + * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes. + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE libconfig_yy_scan_bytes (yyconst char * yybytes, int _yybytes_len , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + char *buf; + yy_size_t n; + int i; + + /* Get memory for full buffer, including space for trailing EOB's. */ + n = _yybytes_len + 2; + buf = (char *) libconfig_yyalloc(n ,yyscanner ); + if ( ! buf ) + YY_FATAL_ERROR( "out of dynamic memory in libconfig_yy_scan_bytes()" ); + + for ( i = 0; i < _yybytes_len; ++i ) + buf[i] = yybytes[i]; + + buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; + + b = libconfig_yy_scan_buffer(buf,n ,yyscanner); + if ( ! b ) + YY_FATAL_ERROR( "bad buffer in libconfig_yy_scan_bytes()" ); + + /* It's okay to grow etc. this buffer, and we should throw it + * away when we're done. + */ + b->yy_is_our_buffer = 1; + + return b; +} + +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 +#endif + +static void yy_fatal_error (yyconst char* msg , yyscan_t yyscanner) +{ + (void) fprintf( stderr, "%s\n", msg ); + exit( YY_EXIT_FAILURE ); +} + +/* Redefine yyless() so it works in section 3 code. */ + +#undef yyless +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + yytext[yyleng] = yyg->yy_hold_char; \ + yyg->yy_c_buf_p = yytext + yyless_macro_arg; \ + yyg->yy_hold_char = *yyg->yy_c_buf_p; \ + *yyg->yy_c_buf_p = '\0'; \ + yyleng = yyless_macro_arg; \ + } \ + while ( 0 ) + +/* Accessor methods (get/set functions) to struct members. */ + +/** Get the user-defined data for this scanner. + * @param yyscanner The scanner object. + */ +YY_EXTRA_TYPE libconfig_yyget_extra (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyextra; +} + +/** Get the current line number. + * @param yyscanner The scanner object. + */ +int libconfig_yyget_lineno (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (! YY_CURRENT_BUFFER) + return 0; + + return yylineno; +} + +/** Get the current column number. + * @param yyscanner The scanner object. + */ +int libconfig_yyget_column (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (! YY_CURRENT_BUFFER) + return 0; + + return yycolumn; +} + +/** Get the input stream. + * @param yyscanner The scanner object. + */ +FILE *libconfig_yyget_in (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyin; +} + +/** Get the output stream. + * @param yyscanner The scanner object. + */ +FILE *libconfig_yyget_out (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyout; +} + +/** Get the length of the current token. + * @param yyscanner The scanner object. + */ +int libconfig_yyget_leng (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyleng; +} + +/** Get the current token. + * @param yyscanner The scanner object. + */ + +char *libconfig_yyget_text (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yytext; +} + +/** Set the user-defined data. This data is never touched by the scanner. + * @param user_defined The data to be associated with this scanner. + * @param yyscanner The scanner object. + */ +void libconfig_yyset_extra (YY_EXTRA_TYPE user_defined , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyextra = user_defined ; +} + +/** Set the current line number. + * @param line_number + * @param yyscanner The scanner object. + */ +void libconfig_yyset_lineno (int line_number , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* lineno is only valid if an input buffer exists. */ + if (! YY_CURRENT_BUFFER ) + yy_fatal_error( "libconfig_yyset_lineno called with no buffer" , yyscanner); + + yylineno = line_number; +} + +/** Set the current column. + * @param line_number + * @param yyscanner The scanner object. + */ +void libconfig_yyset_column (int column_no , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* column is only valid if an input buffer exists. */ + if (! YY_CURRENT_BUFFER ) + yy_fatal_error( "libconfig_yyset_column called with no buffer" , yyscanner); + + yycolumn = column_no; +} + +/** Set the input stream. This does not discard the current + * input buffer. + * @param in_str A readable stream. + * @param yyscanner The scanner object. + * @see libconfig_yy_switch_to_buffer + */ +void libconfig_yyset_in (FILE * in_str , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyin = in_str ; +} + +void libconfig_yyset_out (FILE * out_str , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyout = out_str ; +} + +int libconfig_yyget_debug (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yy_flex_debug; +} + +void libconfig_yyset_debug (int bdebug , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yy_flex_debug = bdebug ; +} + +/* Accessor methods for yylval and yylloc */ + +YYSTYPE * libconfig_yyget_lval (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yylval; +} + +void libconfig_yyset_lval (YYSTYPE * yylval_param , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yylval = yylval_param; +} + +/* User-visible API */ + +/* libconfig_yylex_init is special because it creates the scanner itself, so it is + * the ONLY reentrant function that doesn't take the scanner as the last argument. + * That's why we explicitly handle the declaration, instead of using our macros. + */ + +int libconfig_yylex_init(yyscan_t* ptr_yy_globals) + +{ + if (ptr_yy_globals == NULL){ + errno = EINVAL; + return 1; + } + + *ptr_yy_globals = (yyscan_t) libconfig_yyalloc ( sizeof( struct yyguts_t ), NULL ); + + if (*ptr_yy_globals == NULL){ + errno = ENOMEM; + return 1; + } + + /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */ + memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); + + return yy_init_globals ( *ptr_yy_globals ); +} + +/* libconfig_yylex_init_extra has the same functionality as libconfig_yylex_init, but follows the + * convention of taking the scanner as the last argument. Note however, that + * this is a *pointer* to a scanner, as it will be allocated by this call (and + * is the reason, too, why this function also must handle its own declaration). + * The user defined value in the first argument will be available to libconfig_yyalloc in + * the yyextra field. + */ + +int libconfig_yylex_init_extra(YY_EXTRA_TYPE yy_user_defined,yyscan_t* ptr_yy_globals ) + +{ + struct yyguts_t dummy_yyguts; + + libconfig_yyset_extra (yy_user_defined, &dummy_yyguts); + + if (ptr_yy_globals == NULL){ + errno = EINVAL; + return 1; + } + + *ptr_yy_globals = (yyscan_t) libconfig_yyalloc ( sizeof( struct yyguts_t ), &dummy_yyguts ); + + if (*ptr_yy_globals == NULL){ + errno = ENOMEM; + return 1; + } + + /* By setting to 0xAA, we expose bugs in + yy_init_globals. Leave at 0x00 for releases. */ + memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); + + libconfig_yyset_extra (yy_user_defined, *ptr_yy_globals); + + return yy_init_globals ( *ptr_yy_globals ); +} + +static int yy_init_globals (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + /* Initialization is the same as for the non-reentrant scanner. + * This function is called from libconfig_yylex_destroy(), so don't allocate here. + */ + + yyg->yy_buffer_stack = 0; + yyg->yy_buffer_stack_top = 0; + yyg->yy_buffer_stack_max = 0; + yyg->yy_c_buf_p = (char *) 0; + yyg->yy_init = 0; + yyg->yy_start = 0; + + yyg->yy_start_stack_ptr = 0; + yyg->yy_start_stack_depth = 0; + yyg->yy_start_stack = NULL; + +/* Defined in main.c */ +#ifdef YY_STDINIT + yyin = stdin; + yyout = stdout; +#else + yyin = (FILE *) 0; + yyout = (FILE *) 0; +#endif + + /* For future reference: Set errno on error, since we are called by + * libconfig_yylex_init() + */ + return 0; +} + +/* libconfig_yylex_destroy is for both reentrant and non-reentrant scanners. */ +int libconfig_yylex_destroy (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* Pop the buffer stack, destroying each element. */ + while(YY_CURRENT_BUFFER){ + libconfig_yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner ); + YY_CURRENT_BUFFER_LVALUE = NULL; + libconfig_yypop_buffer_state(yyscanner); + } + + /* Destroy the stack itself. */ + libconfig_yyfree(yyg->yy_buffer_stack ,yyscanner); + yyg->yy_buffer_stack = NULL; + + /* Destroy the start condition stack. */ + libconfig_yyfree(yyg->yy_start_stack ,yyscanner ); + yyg->yy_start_stack = NULL; + + /* Reset the globals. This is important in a non-reentrant scanner so the next time + * libconfig_yylex() is called, initialization will occur. */ + yy_init_globals( yyscanner); + + /* Destroy the main struct (reentrant only). */ + libconfig_yyfree ( yyscanner , yyscanner ); + yyscanner = NULL; + return 0; +} + +/* + * Internal utility routines. + */ + +#ifndef yytext_ptr +static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yyscanner) +{ + register int i; + for ( i = 0; i < n; ++i ) + s1[i] = s2[i]; +} +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner) +{ + register int n; + for ( n = 0; s[n]; ++n ) + ; + + return n; +} +#endif + +void *libconfig_yyalloc (yy_size_t size , yyscan_t yyscanner) +{ + return (void *) malloc( size ); +} + +void *libconfig_yyrealloc (void * ptr, yy_size_t size , yyscan_t yyscanner) +{ + /* The cast to (char *) in the following accommodates both + * implementations that use char* generic pointers, and those + * that use void* generic pointers. It works with the latter + * because both ANSI C and C++ allow castless assignment from + * any pointer type to void*, and deal with argument conversions + * as though doing an assignment. + */ + return (void *) realloc( (char *) ptr, size ); +} + +void libconfig_yyfree (void * ptr , yyscan_t yyscanner) +{ + free( (char *) ptr ); /* see libconfig_yyrealloc() for (char *) cast */ +} + +#define YYTABLES_NAME "yytables" + +#line 191 "scanner.l" diff --git a/3rdparty/libconfig/scanner.h b/3rdparty/libconfig/scanner.h new file mode 100644 index 000000000..baa6f771f --- /dev/null +++ b/3rdparty/libconfig/scanner.h @@ -0,0 +1,326 @@ +#ifndef libconfig_yyHEADER_H +#define libconfig_yyHEADER_H 1 +#define libconfig_yyIN_HEADER 1 + +#line 6 "scanner.h" + +#line 8 "scanner.h" + +#define YY_INT_ALIGNED short int + +/* A lexical scanner generated by flex */ + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 5 +#define YY_FLEX_SUBMINOR_VERSION 33 +#if YY_FLEX_SUBMINOR_VERSION > 0 +#define FLEX_BETA +#endif + +/* First, we deal with platform-specific or compiler-specific issues. */ + +/* begin standard C headers. */ +#include +#include +#include +#include + +/* end standard C headers. */ + +/* flex integer type definitions */ + +#ifndef FLEXINT_H +#define FLEXINT_H + +/* C99 systems have . Non-C99 systems may or may not. */ + +#if __STDC_VERSION__ >= 199901L + +/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, + * if you want the limit (max/min) macros for int types. + */ +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS 1 +#endif + +#include +typedef int8_t flex_int8_t; +typedef uint8_t flex_uint8_t; +typedef int16_t flex_int16_t; +typedef uint16_t flex_uint16_t; +typedef int32_t flex_int32_t; +typedef uint32_t flex_uint32_t; +#else +typedef signed char flex_int8_t; +typedef short int flex_int16_t; +typedef int flex_int32_t; +typedef unsigned char flex_uint8_t; +typedef unsigned short int flex_uint16_t; +typedef unsigned int flex_uint32_t; +#endif /* ! C99 */ + +/* Limits of integral types. */ +#ifndef INT8_MIN +#define INT8_MIN (-128) +#endif +#ifndef INT16_MIN +#define INT16_MIN (-32767-1) +#endif +#ifndef INT32_MIN +#define INT32_MIN (-2147483647-1) +#endif +#ifndef INT8_MAX +#define INT8_MAX (127) +#endif +#ifndef INT16_MAX +#define INT16_MAX (32767) +#endif +#ifndef INT32_MAX +#define INT32_MAX (2147483647) +#endif +#ifndef UINT8_MAX +#define UINT8_MAX (255U) +#endif +#ifndef UINT16_MAX +#define UINT16_MAX (65535U) +#endif +#ifndef UINT32_MAX +#define UINT32_MAX (4294967295U) +#endif + +#endif /* ! FLEXINT_H */ + +#ifdef __cplusplus + +/* The "const" storage-class-modifier is valid. */ +#define YY_USE_CONST + +#else /* ! __cplusplus */ + +#if __STDC__ + +#define YY_USE_CONST + +#endif /* __STDC__ */ +#endif /* ! __cplusplus */ + +#ifdef YY_USE_CONST +#define yyconst const +#else +#define yyconst +#endif + +/* An opaque pointer. */ +#ifndef YY_TYPEDEF_YY_SCANNER_T +#define YY_TYPEDEF_YY_SCANNER_T +typedef void* yyscan_t; +#endif + +/* For convenience, these vars (plus the bison vars far below) + are macros in the reentrant scanner. */ +#define yyin yyg->yyin_r +#define yyout yyg->yyout_r +#define yyextra yyg->yyextra_r +#define yyleng yyg->yyleng_r +#define yytext yyg->yytext_r +#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno) +#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column) +#define yy_flex_debug yyg->yy_flex_debug_r + +int libconfig_yylex_init (yyscan_t* scanner); + +#ifndef YY_TYPEDEF_YY_BUFFER_STATE +#define YY_TYPEDEF_YY_BUFFER_STATE +typedef struct yy_buffer_state *YY_BUFFER_STATE; +#endif + +/* The following is because we cannot portably get our hands on size_t + * (without autoconf's help, which isn't available because we want + * flex-generated scanners to compile on their own). + */ + +#ifndef YY_TYPEDEF_YY_SIZE_T +#define YY_TYPEDEF_YY_SIZE_T +typedef unsigned int yy_size_t; +#endif + +#ifndef YY_STRUCT_YY_BUFFER_STATE +#define YY_STRUCT_YY_BUFFER_STATE +struct yy_buffer_state + { + FILE *yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + yy_size_t yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + int yy_bs_lineno; /**< The line count. */ + int yy_bs_column; /**< The column count. */ + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; + + }; +#endif /* !YY_STRUCT_YY_BUFFER_STATE */ + +void libconfig_yyrestart (FILE *input_file ,yyscan_t yyscanner ); +void libconfig_yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner ); +YY_BUFFER_STATE libconfig_yy_create_buffer (FILE *file,int size ,yyscan_t yyscanner ); +void libconfig_yy_delete_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner ); +void libconfig_yy_flush_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner ); +void libconfig_yypush_buffer_state (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner ); +void libconfig_yypop_buffer_state (yyscan_t yyscanner ); + +YY_BUFFER_STATE libconfig_yy_scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner ); +YY_BUFFER_STATE libconfig_yy_scan_string (yyconst char *yy_str ,yyscan_t yyscanner ); +YY_BUFFER_STATE libconfig_yy_scan_bytes (yyconst char *bytes,int len ,yyscan_t yyscanner ); + +void *libconfig_yyalloc (yy_size_t ,yyscan_t yyscanner ); +void *libconfig_yyrealloc (void *,yy_size_t ,yyscan_t yyscanner ); +void libconfig_yyfree (void * ,yyscan_t yyscanner ); + +#define libconfig_yywrap(n) 1 +#define YY_SKIP_YYWRAP + +#define yytext_ptr yytext_r + +#ifdef YY_HEADER_EXPORT_START_CONDITIONS +#define INITIAL 0 +#define COMMENT 1 + +#endif + +#ifndef YY_EXTRA_TYPE +#define YY_EXTRA_TYPE void * +#endif + +/* Accessor methods to globals. + These are made visible to non-reentrant scanners for convenience. */ + +int libconfig_yylex_destroy (yyscan_t yyscanner ); + +int libconfig_yyget_debug (yyscan_t yyscanner ); + +void libconfig_yyset_debug (int debug_flag ,yyscan_t yyscanner ); + +YY_EXTRA_TYPE libconfig_yyget_extra (yyscan_t yyscanner ); + +void libconfig_yyset_extra (YY_EXTRA_TYPE user_defined ,yyscan_t yyscanner ); + +FILE *libconfig_yyget_in (yyscan_t yyscanner ); + +void libconfig_yyset_in (FILE * in_str ,yyscan_t yyscanner ); + +FILE *libconfig_yyget_out (yyscan_t yyscanner ); + +void libconfig_yyset_out (FILE * out_str ,yyscan_t yyscanner ); + +int libconfig_yyget_leng (yyscan_t yyscanner ); + +char *libconfig_yyget_text (yyscan_t yyscanner ); + +int libconfig_yyget_lineno (yyscan_t yyscanner ); + +void libconfig_yyset_lineno (int line_number ,yyscan_t yyscanner ); + +YYSTYPE * libconfig_yyget_lval (yyscan_t yyscanner ); + +void libconfig_yyset_lval (YYSTYPE * yylval_param ,yyscan_t yyscanner ); + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int libconfig_yywrap (yyscan_t yyscanner ); +#else +extern int libconfig_yywrap (yyscan_t yyscanner ); +#endif +#endif + +#ifndef yytext_ptr +static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner); +#endif + +#ifndef YY_NO_INPUT + +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#define YY_READ_BUF_SIZE 8192 +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL_IS_OURS 1 + +extern int libconfig_yylex (YYSTYPE * yylval_param ,yyscan_t yyscanner); + +#define YY_DECL int libconfig_yylex (YYSTYPE * yylval_param , yyscan_t yyscanner) +#endif /* !YY_DECL */ + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + +#undef YY_NEW_FILE +#undef YY_FLUSH_BUFFER +#undef yy_set_bol +#undef yy_new_buffer +#undef yy_set_interactive +#undef YY_DO_BEFORE_ACTION + +#ifdef YY_DECL_IS_OURS +#undef YY_DECL_IS_OURS +#undef YY_DECL +#endif + +#line 130 "scanner.l" + +#line 325 "scanner.h" +#undef libconfig_yyIN_HEADER +#endif /* libconfig_yyHEADER_H */ diff --git a/3rdparty/libconfig/strbuf.c b/3rdparty/libconfig/strbuf.c new file mode 100644 index 000000000..d2a667a7c --- /dev/null +++ b/3rdparty/libconfig/strbuf.c @@ -0,0 +1,57 @@ +/* ---------------------------------------------------------------------------- + libconfig - A library for processing structured configuration files + Copyright (C) 2005-2010 Mark A Lindner + + This file is part of libconfig. + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this library. If not, see . + ---------------------------------------------------------------------------- +*/ + +#include "strbuf.h" + +#include +#include + +#define STRING_BLOCK_SIZE 64 + +/* ------------------------------------------------------------------------- */ + +char *strbuf_release(strbuf_t *buf) +{ + char *r = buf->string; + memset(buf, 0, sizeof(strbuf_t)); + return(r); +} + +/* ------------------------------------------------------------------------- */ + +void strbuf_append(strbuf_t *buf, const char *text) +{ + static const size_t mask = ~(STRING_BLOCK_SIZE - 1); + size_t len = strlen(text); + size_t newlen = buf->length + len + 1; /* add 1 for NUL */ + + if(newlen > buf->capacity) + { + buf->capacity = (newlen + (STRING_BLOCK_SIZE - 1)) & mask; + buf->string = (char *)realloc(buf->string, buf->capacity); + } + + strcpy(buf->string + buf->length, text); + buf->length += len; +} + +/* ------------------------------------------------------------------------- */ +/* eof */ diff --git a/3rdparty/libconfig/strbuf.h b/3rdparty/libconfig/strbuf.h new file mode 100644 index 000000000..90afd44c8 --- /dev/null +++ b/3rdparty/libconfig/strbuf.h @@ -0,0 +1,39 @@ +/* ---------------------------------------------------------------------------- + libconfig - A library for processing structured configuration files + Copyright (C) 2005-2010 Mark A Lindner + + This file is part of libconfig. + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this library. If not, see . + ---------------------------------------------------------------------------- +*/ + +#ifndef __libconfig_strbuf_h +#define __libconfig_strbuf_h + +#include +#include + +typedef struct +{ + char *string; + size_t length; + size_t capacity; +} strbuf_t; + +char *strbuf_release(strbuf_t *buf); + +void strbuf_append(strbuf_t *buf, const char *text); + +#endif /* __libconfig_strbuf_h */ diff --git a/3rdparty/libconfig/wincompat.h b/3rdparty/libconfig/wincompat.h new file mode 100644 index 000000000..cfea2ec33 --- /dev/null +++ b/3rdparty/libconfig/wincompat.h @@ -0,0 +1,89 @@ +/* ---------------------------------------------------------------------------- + libconfig - A library for processing structured configuration files + Copyright (C) 2005-2010 Mark A Lindner + + This file is part of libconfig. + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this library. If not, see . + ---------------------------------------------------------------------------- +*/ + +#ifndef __wincompat_h +#define __wincompat_h + +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) + +#ifdef _MSC_VER +#pragma warning (disable: 4996) +#endif + +#define WIN32_LEAN_AND_MEAN +#include + +#define snprintf _snprintf + +#ifndef __MINGW32__ +#define atoll _atoi64 +#define strtoull _strtoui64 +#endif /* __MINGW32__ */ + +#endif + +#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__) \ + || defined(__MINGW32__)) + +/* Why does gcc on MinGW use the Visual C++ style format directives + * for 64-bit integers? Inquiring minds want to know.... + */ + +#define INT64_FMT "%I64d" +#define UINT64_FMT "%I64u" + +#define INT64_HEX_FMT "%I64X" + +#define FILE_SEPARATOR "\\" + +#else /* defined(WIN32) || defined(__MINGW32__) */ + +#define INT64_FMT "%lld" +#define UINT64_FMT "%llu" + +#define INT64_HEX_FMT "%llX" + +#define FILE_SEPARATOR "/" + +#endif /* defined(WIN32) || defined(__MINGW32__) */ + +#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__)) \ + && ! defined(__MINGW32__) + +#define INT64_CONST(I) (I ## i64) +#define UINT64_CONST(I) (I ## Ui64) + +#ifndef INT32_MAX +#define INT32_MAX (2147483647) +#endif + +#ifndef INT32_MIN +#define INT32_MIN (-2147483647-1) +#endif + +#else /* defined(WIN32) && ! defined(__MINGW32__) */ + +#define INT64_CONST(I) (I ## LL) +#define UINT64_CONST(I) (I ## ULL) + +#endif /* defined(WIN32) && ! defined(__MINGW32__) */ + +#endif /* __wincompat_h */ diff --git a/Makefile.in b/Makefile.in index 02ca9b987..6fd5fff26 100644 --- a/Makefile.in +++ b/Makefile.in @@ -4,10 +4,10 @@ HAVE_MYSQL=@HAVE_MYSQL@ ifeq ($(HAVE_MYSQL),yes) ALL_DEPENDS=common_sql login_sql char_sql map_sql tools import SQL_DEPENDS=common_sql login_sql char_sql map_sql import - COMMON_SQL_DEPENDS=mt19937ar - LOGIN_SQL_DEPENDS=mt19937ar common_sql - CHAR_SQL_DEPENDS=mt19937ar common_sql - MAP_SQL_DEPENDS=mt19937ar common_sql + COMMON_SQL_DEPENDS=mt19937ar libconfig + LOGIN_SQL_DEPENDS=mt19937ar libconfig common_sql + CHAR_SQL_DEPENDS=mt19937ar libconfig common_sql + MAP_SQL_DEPENDS=mt19937ar libconfig common_sql CONVERTERS_DEPENDS=common_sql else ALL_DEPENDS=needs_mysql @@ -47,6 +47,9 @@ common_sql: $(COMMON_SQL_DEPENDS) mt19937ar: @$(MAKE) -C 3rdparty/mt19937ar +libconfig: + @$(MAKE) -C 3rdparty/libconfig + login_sql: $(LOGIN_SQL_DEPENDS) @$(MAKE) -C src/login sql @@ -74,6 +77,7 @@ import: clean: @$(MAKE) -C src/common $@ @$(MAKE) -C 3rdparty/mt19937ar $@ + @$(MAKE) -C 3rdparty/libconfig $@ @$(MAKE) -C src/login $@ @$(MAKE) -C src/char $@ @$(MAKE) -C src/map $@ @@ -85,6 +89,7 @@ help: @echo "possible targets are:" @echo "'common_sql' - builds object files used in SQL servers" @echo "'mt19937ar' - builds object file of Mersenne Twister MT19937" + @echo "'libconfig' - builds object files of libconfig @echo "'login_sql' - builds login server (SQL version)" @echo "'char_sql' - builds char server (SQL version)" @echo "'map_sql' - builds map server (SQL version)" diff --git a/conf/atcommand_athena.conf b/conf/atcommand_athena.conf index ce06e2b37..58813c1c7 100644 --- a/conf/atcommand_athena.conf +++ b/conf/atcommand_athena.conf @@ -1,753 +1,60 @@ -サソ//-------------------------------------------------------------- -// rAthena atcommand/charcommand Configuration File -//-------------------------------------------------------------- - -// The symbol that will be used to recognize commands. -// You can set any one character except control-characters (0x00-0x1f), -// '%', '$' (party/guild chat speaking) and '/' (standard client commands). -// command_symbol represents @commands used locally -// char_symbol represents #commands used on other players. -command_symbol:@ -char_symbol:# - -// The following settings in this file use the format ": level(@),level(#)". -// They define the minimum GM level required to execute the associated command. -// @ = atcommand. most work only on yourself. -// # = charcommand. remote usage only. GMs will be able to use these on other players. -// Adjust values as you like. Note that to activate commands for normal players, -// (GM level 0), you also need to change the 'atcommand_gm_only' option to 'no'. -// To completely disable a command, set its required GM level to 100. - -// Default levels were chosen so that they form the following hierarchy: -// 0: Normal player -// -> no commands accessible -// 1: Super player -// -> some minor advantage: storage, petrename, etc... -// 10: Super player+ -// -> more powerful commands, like mobsearch and changegm -// 20: Mediator -// -> GM commands for finding players and moving to them (also kicking them) -// 40: Sub-GM -// -> GM commands for basic tasks, no significant impact on other players -// 50: Sub-GM+ -// -> GM commands to spawn mobs and create guilds -// 60: GM -// -> almost all commands available (except administration and mass commands) -// 80: GM Chief -// -> can do anything, except administration commands -// 99: Administrator -// -> can do anything! -// 100: Disabled -// -> commands that will not be available to anyone - -// Syntax of file: -// command: @level,#level [] - -// Syntax Example: -// command: 40,40 [alias,alias2,alias3,alias4] -// If it has more than 4 aliases you can keep adding, just like in the example below: - -// Example: -// blvl: 60,60 [lvup,blevel,baselvl,baselvup,baselevel,baselvlup] - -//-------------------------- -// 0: normal player commands -// None for security purposes. - -//------------------------- -// 1: Super player commands - -// Displays a list of @ commands available to the player. -commands: 1,1 - -// Displays a list of # commands available to the player. -charcommands: 1,1 - -// Displays the server rates. -rates: 1,1 - -// Show server uptime since last map server restart -uptime: 1,1 - -// Shows/Hides the "there is a delay after a skill" message. -showdelay: 1,1 - -// Displays current levels and % progress. -exp: 1,40 - -// To change your (own) email -// note: this command doesn't check email itself, but check structure of the email (xxx@xxx) -// if you want be sure of each e-mail disable this option (value: 100) -email: 1,60 - -// Show Monster info (rates, stats, drops, MVP stuff) -monsterinfo: 1,1 [mobinfo, mi] - -// Show Item info (type, price, etc) -iteminfo: 1,1 [ii] - -// Show who drops an item (mobs with highest drop rate) -whodrops: 1,1 - -// Syncs the player's position on the client with the one stored on the server. -refresh: 1,40 - -// Give server time. (4 same commands) -time: 1,1 [date,serverdate,servertime] - -// Displays SVN version of the server. -version: 1,1 - -// Suicide your character. -die: 1,1 - -// Enables you to rename your pet. -petrename: 1,50 - -// Organize a new party, with you as the party leader -party: 1,1 - -// Opens your Kafra storage wherever you are -storage: 1,1 - -// Opens your mailbox -mail: 1,1 - -// Opens auctions window -auction: 1,1 - -// Locate someone on a map, returns your coordinates if the person isn't on. -where: 1,1 - -// Duel organizing commands -duel: 1,1 -invite: 1,1 -accept: 1,1 -reject: 1,1 -leave: 1,1 - -// Main chat -main: 1,1 - -// Autorejecting Deals/Invites -noask: 1,1 - -// Displays remaining jail time -jailtime: 1,40 - -// Homunculus commands for players -hominfo: 1,40 -homstats: 1,40 - -// Kill Steal Protection -noks: 1,1 - -// Set Font -font: 1,1 - -//--------------------------- -// 10: Super player+ commands - -// Displays/Hides Experience gained messages -showexp: 10,10 - -// Displays/Hides Zeny gained messages -showzeny: 10,10 - -// Warps you to predefined locations in major cities. -go: 10,10 - -// Enables/disables autolooting from killed mobs. -autoloot: 10,10 - -// Enables/disables autolooting an item. -alootid: 10,10 - -// Allows you continue vending offline. -autotrade: 10,10 [at] - -// Change Guild Master of your Guild -changegm: 10,10 - -// Change the leader of your party. -changeleader: 10,10 - -// Change the party exp- and item share rules. -partyoption: 10,10 - -// Command what the player's pet will say. -pettalk: 10,10 - -// Command what the player's homunculus will say. -homtalk: 10,10 - -// Locates and displays the position of a certain mob on the current map. -mobsearch: 10,10 -// Locates and displays the position of a certain mob on your mini-map -showmobs: 10,10 -// Prints out in which maps a monster normally spawns at (does not count script-invoked mobs) -whereis: 10,10 - -// Resets a Star Gladiator's marked maps -feelreset: 10,60 - -//---------------------- -// 20: Mediator commands - -// Displays helpfile in rAthena base directory (2 same commands). -help: 20,20 [h] -help2: 20,20 [h2] - -// Warp yourself to a person (3 same commands + /shift). -goto: 20,20 [jumpto,warpto] - -// Displays the motd file to all players -gmotd: 20,20 - -// Follow a player (including warping to them) -follow: 20,20 - -// Sends a request to all connected GMs (via the gm whisper system) -request: 20,100 - -// Disconnects a user from the server (1 command + right click menu for GM "(name) force to quit"). -kick: 20,20 - -// Changes your appearance. -model: 20,50 - -// To get a peco to (un)ride (2 same commands). -mount: 20,50 [mountpeco] - -// Returns list of logged in characters with their position (2 same commands). -who: 20,20 [whois] - -// Returns list of logged in characters with their job. -who2: 20,20 - -// Returns list of logged in characters with their party/guild. -who3: 20,20 - -// Returns list of logged in characters with their position in a specifical map. -whomap: 20,20 - -// Returns list of logged in characters with their job in a specifical map. -whomap2: 20,20 - -// Returns list of logged in characters with their party/guild in a specifical map. -whomap3: 20,20 - -// Displays GMs online. For those who are higher GM level than yourself, -// only the name is shown, for the rest, it displays the same info of -// @who+@who2+who3 -whogm: 20,20 - -// Change your appearence to other players to a mob. -disguise: 20,60 - -// Restore your normal appearance. -undisguise: 20,20 - -// Displays the text as a normal message with the format "*name message*" -// instead of "name : message" (Like the /me command in IRC) -me: 20,20 - -// Changes your name to your choice temporarily. -fakename: 20,50 - -// Changes your size. -size: 20,50 - -// Can command what other npcs (by name) can say. -npctalk: 20,100 [npctalkc] - -//-------------------- -// 40: Sub-GM commands - -// Broadcast to the whole server. Using (1 command + /nb, /b). -broadcast: 40,40 - -// Broadcast to the map you are on (1 command + /lb, /nlb). -localbroadcast: 40,40 - -// Broadcast (with or without name) -kami: 40,40 -// Same as kami but with blue color -kamib: 40,40 -// Same as kami but you can choose the color (uses different packet) -kamic: 40,40 - -// Enables GvG on a map (2 same commands). -gvgon: 40,100 [gpvpon] - -// Turns GvG (Guild vs. Guild) off on a map (2 same commands). -gvgoff: 40,100 [gpvpoff] - -// Activate/Deactivate kill steal protection on a map -allowks: 40,100 - -// Modifies your HP/SP. -heal: 40,60 - -// GM Hide (total invisibility to characters and monsters) (1 command + /hide). -hide: 40,60 - -// Changes your job to one you specify (2 same commands). -job: 40,60 [jobchange] - -// Enables you to to jump randomly on a map (that you are already on). -jump: 40,40 - -// Warps you to your last save point (2 same commands). -load: 40,60 [return] - -// Warps you to a specific npc -tonpc: 40,40 - -// Saves a warp point. -memo: 40,40 - -// Set your character display options. (Visual effects of your character) -option: 40,60 - -// Sets the level of intemecy of your pet. -petfriendly: 40,50 - -// Sets hunger level of your pet. -pethungry: 40,50 - -// Turns PvP (Person vs. Person) off on a map. -pvpoff: 40,100 - -// Enables PvP on a map. -pvpon: 40,100 - -// Permanently adds a quest skill -questskill: 40,60 - -// Permanently removes a quest skill -lostskill: 40,60 - -// Sets the speed you can walk/attack at. Default is 150. -speed: 40,60 - -// Summons spirit spheres around you. -spiritball: 40,60 - -// Warp yourself to a certain map, at (x,y) coordinates (2 same commands) + also /mm or /mapmove. -warp: 40,60 [rura,mapmove] - -// Changes GM clothes color (2 same commands) -dye: 40,50 [ccolor] - -// Changes GM hair style (2 same commands) -hairstyle: 40,40 [hstyle] - -// Changes GM hair color (2 same commands) -haircolor: 40,50 [hcolor] - -// Deletes all your items. -itemreset: 40,60 - -// Does a skill/stat reset. -reset: 40,60 - -// Displays distribution of players on the server per map (% on each map which has players) -users: 40,40 - -// Deletes floor items in your range of sight -cleanmap: 40,40 - -// Kill all monsters in map (without drops) -killmonster2: 40,40 - -// Sets your spawn point (aka save point). -save: 40,60 - -// Do some visual effect on your character -effect: 40,40 - -// Do some visual effect on your character (misceffect) -misceffect: 40,40 - -// GM's magnifier -identify: 40,40 - -// Drop all your items -dropall: 40,60 - -// Store all your items -storeall: 40,60 - -// Allow other players to hit you out of PvP -killable: 40,60 - -// Look up a skill by name -skillid: 40,40 - -// Use a skill by id -useskill: 40,40 - -// What skills are required to get this skill -skilltree: 40,40 - -// Marriage commands -marry: 40,40 -divorce: 40,40 - -// Adopt a novice into a family -adopt: 40,40 - -// Play a Sound! -sound: 40,40 - -// Displays a player's storage -storagelist: 40,40 - -// Displays a player's cart contents -cartlist: 40,40 - -// Displays a player's items -itemlist: 40,40 - -// Displays a player's stats -stats: 40,40 - -//--------------------- -// 50: Sub-GM+ commands - -// Creates a new guild, with you as the guildmaster. -guild: 50,50 - -// Brings up your guild storage wherever you are. -gstorage: 50,60 - -// Spawns a monster, and a certain amount (2 same commands + /monster). -monster: 50,50 [spawn] - -// Spawns a smaller sized version of a monster. -monstersmall: 50,50 - -// Spawns a larger sized version of a monster. -monsterbig: 50,50 - -// Spawns mobs that treat you as their master (they disappear after some time) -summon: 50,50 - -// It will spawn a supportive clone of the given player. -clone: 50,50 - -// It will spawn a supportive clone of the given player that follows the creator around. -slaveclone: 50,50 - -// It will spawn an aggresive clone of the given player. -evilclone: 50,50 - -//---------------- -// 60: GM commands - -// Add or Remove Cash Points to/from yourself -cash: 60,60 - -// Add or Remove Kafra Points to/from yourself -points: 60,60 - -// Starts Guild Wars -agitstart: 60,100 - -// Ends Guild Wars -agitend: 60,100 - -// Resurects yourself. -alive: 60,60 - -// Raises your base level by specified amount (7 same commands). -blvl: 60,60 [lvup,blevel,baselvl,baselvup,baselevel,baselvlup] - -// Raises your job level by specified amount (6 same commands). -jlvl: 60,60 [jlevel,joblvl,joblvup,joblevel,joblvlup] - -// Changes the sex of yourself -changesex: 60,60 - -// Raises your guild level by specified amount (6 same commands). -glvl: 60,60 [glevel,guildlvl,guildlvup,guildlevel,guildlvlup] - -// Find an itemID based on item name -idsearch: 60,60 - -// Creates an item of your choosing, either Item ID or Name (1 command + /item). -item: 60,60 - -// Creates a complet item (card, etc...) of your choosing, either Item ID or Name. -item2: 60,60 - -// Deletes an item of your choosing, either Item ID or Name. -delitem: 60,60 - -// Kill another character without hitting them. -kill: 60,60 - -// Kill all monsters in map (with drops) -killmonster: 60,60 - -// Creates yourself a pet egg. -makeegg: 60,60 - -// Hatches an egg -hatch: 60,60 - -// Instantly kills player whose name is entered and deals insane damage to everything around -nuke: 60,60 - -// Enable hitting a player even when not in PvP -killer: 60,60 - -// Creates weapon of desired element. -produce: 60,60 - -// Warps a character to you (1 command + /recall). -recall: 60,60 - -// Refines all weapons in your items list. -refine: 60,80 - -// Will repair all broken items in inventory. -repairall: 60,60 - -// Change Status of your character -str: 60,60 -agi: 60,60 -vit: 60,60 -int: 60,60 -dex: 60,60 -luk: 60,60 - -// Gives all skills -allskill: 60,60 [allskills,skillall,skillsall] - -// Sets GM stats to maximum -allstats: 60,60 [allstat,statall,statsall] - -// Gives you stat points. -stpoint: 60,60 - -// Gives you skill points of desired amount. -skpoint: 60,60 - -// Warps all online character of a guild to you. (at least one member of that guild must be on.) -guildrecall: 60,60 - -// Warps all online character of a party to you. -// (at least one party member must be online.) -partyrecall: 60,60 - -// Allows you to spy on any Guilds Guild chat. -// (at least one member of that guild must be on.) -// NOTE: map server needs to be configured to enable spying to use this command (enable_spy: yes) -guildspy: 60,60 - -// Allows you to spy on any party's party chat. -// (at least one party member must be online.) -// NOTE: map server needs to be configured to enable spying to use this command (enable_spy: yes) -partyspy: 60,60 - -// Gives you zeny (or subtracts, if amount is negative) -zeny: 60,80 - -// Block a player indefinitely -block: 60,100 [charblock] - -// Unblock a player -unblock: 60,100 [charunblock] - -// Ban a player for a limited time -ban: 60,100 [banish,charban,charbanish] - -// Unban a player -unban: 60,100 [unbanish,charunban,charunbanish] - -// To send specified character in jails -jail: 60,100 - -// To discharge a jailed character (2 same commands) -unjail: 60,100 [discharge] - -// Timed jailing -jailfor: 60,60 - -// Create a static warp portal that lasts until the next reboot -addwarp: 60,60 - -// Open a trade window with any player -trade: 60,60 - -// Changes the player's appearance (headgear) -changelook: 60,60 - -// Homunculus commands for GMs -hlvl: 60,60 [homlevel,hlevel,homlvl,homlvup] -homevolve: 60,60 [homevolution] -makehomun: 60,60 -homfriendly: 60,60 -homhungry: 60,60 -// Re-calculates stats, as if the homun was sent back to level 1 and re-leveled -homshuffle: 60,60 - -// WoE 2 start/stop commands -agitstart2: 60,100 -agitend2: 60,100 - -// Resets player stats -streset: 60,60 - -// Resets player skills -skreset: 60,60 - -//---------------------- -// 80: GM Chief commands - -// Set the server to day. -day: 80,100 - -// Set the server to night. -night: 80,100 - -// Kills everyone on the server. -doom: 80,100 - -// Kills everyone on the map you are on. -doommap: 80,80 - -// Recalls Everyone To Your Coordinates -recallall: 80,80 - -// Revives all players on the map. -raisemap: 80,80 - -// Revives all players on the server. -raise: 80,100 - -// Hides a NPC. -hidenpc: 80,100 - -// Unhides a NPC. -shownpc: 80,100 - -// Loads an NPC script by path -loadnpc: 80,100 - -// Unloads a NPC -unloadnpc: 80,100 - -// Move a NPC -npcmove: 80,100 - -// turn skills on for a map -skillon: 80,100 - -// turn skills off for a map -skilloff: 80,100 - -// Mute a player (prevents talking, usage of skills and commands) -mute: 80,100 - -// Unmute a player -unmute: 80,100 - -//--------------------------- -// 99: Administrator commands - -// Disconnect all users from the server -kickall: 99,100 - -// Closes Map-Server -mapexit: 99,100 - -// Used for testing packet sends from the client (debug function) -send: 99,100 - -// Give information about terrain/area (debug function) -gat: 99,100 - -// Displays a status change without really applying it (debug function) -displaystatus: 99,100 - -// Displays the animation of a skill without really using it (debug function) -displayskill: 99,100 - -// Shows information about the map -mapinfo: 99,100 - -// Set Map Flags -mapflag: 99,100 - -// Re-load item database (admin command) -reloaditemdb: 99,100 - -// Re-load monsters database (admin command) -reloadmobdb: 99,100 - -// Re-load skills database (admin command) -reloadskilldb: 99,100 - -// Re-load scripts (admin command) -reloadscript: 99,100 - -// Change a battle_config flag without rebooting server -setbattleflag: 99,100 - -// Re-load gm command config (admin command) -reloadatcommand: 99,100 - -// Re-load battle config (admin command) -// Note that some player config settings won't take effect until relog -// (display exp, display zeny, display skill delay fail, ...) -reloadbattleconf: 99,100 - -// Re-load status database (admin command) -reloadstatusdb: 99,100 - -// Re-load player info database (admin command) -reloadpcdb: 99,100 - -// Re-load the Message of the Day (admin command) -reloadmotd: 99,100 - -// Changes the GM level of another character -// (lasts until reboot, or gm list reload) -adjgmlvl: 99,100 - -// Changes the required GM level of an @ command -// (effect lasts until restart or command reload) -adjcmdlvl: 99,100 - -// [Un]Disguise All Players (admin command) -disguiseall: 99,100 -undisguiseall: 99,100 - -// Mutes every player on screen (admin command) -mutearea: 99,100 [stfu] - -// Makes you immune to attacks (monsters/players/skills cannot target/hit you, admin command) -battleignore: 99,100 [monsterignore] - -//--------------------------------------------------------------- -// 99: Weather effects -snow: 99,100 -clouds: 99,100 -clouds2: 99,100 -fog: 99,100 -fireworks: 99,100 -sakura: 99,100 -leaves: 99,100 - -// Stop all weather effects -clearweather: 99,100 - -//--------------------------------------------------------------- -// 100: Disabled commands - -//--------------------- -// OTHER: not a command -import:conf/import/atcommand_conf.txt \ No newline at end of file +/* Atcommands and charcommands configuration file */ + +/* The symbol that will be used to recognize commands. +You can set any one character except: + - control-characters (0x00-0x1f), + - '%' (party chat symbol) + - '$' (guild chat symbol) + - '/' (client commands symbol) +atcommand_symbol represents @commands used locally. +charcommand_symbol represents #commands used on other players. +*/ + +atcommand_symbol : "@" +charcommand_symbol: "#" + +/* Command aliases +You can define aliases for any command. Aliases work just like original +command. +Format is + : ["", ...] +*/ + +aliases: { + mobinfo: ["monsterinfo", "mi"] + iteminfo: ["ii"] + time: ["date", "serverdate", "servertime"] + autotrade: ["at"] + help: ["h"] + jumpto: ["goto", "warpto"] + mount: ["mountpeco"] + who: ["whois"] + npctalk: ["npctalkc"] + gvgon: ["gpvpon"] + gvgoff: ["gpvpoff"] + jobchange: ["job"] + load: ["return"] + warp: ["rura", "mapmove"] + dye: ["ccolor"] + hairstyle: ["hstyle"] + haircolor: ["hcolor"] + monster: ["spawn"] + blvl: ["lvup", "blevel", "baselvl", "baselvup", "baselevel", "baselvlup"] + jlvl: ["jlevel", "joblvl", "joblvup", "joblevel", "joblvlup"] + glvl: ["glevel", "guildlvl", "guildlvup", "guildlevel", "guildlvlup"] + allskill: ["allskills", "skillall", "skillsall"] + allstats: ["allstat", "statall", "statsall"] + ban: ["banish"] + unban: ["unbanish"] + unjail: ["discharge"] + homlevel: ["hlvl", "hlevel", "homlvl", "homlvup"] + homevolution: ["homevolve"] + mutearea: ["stfu"] + monsterignore: ["battleignore"] + raise: ["revive"] +} + +/* Commands help file */ +help: { + @include "conf/help.txt" +} \ No newline at end of file diff --git a/conf/battle/gm.conf b/conf/battle/gm.conf index b7dc81909..fe07a6fc4 100644 --- a/conf/battle/gm.conf +++ b/conf/battle/gm.conf @@ -18,97 +18,10 @@ atcommand_slave_clone_limit: 25 // current map server. partial_name_scan: yes -// The level at which a player with access is considered a GM. -// An account with an access level lower than this is not effected -// by gm_can_drop_lv (battle_athena.conf). -lowest_gm_level: 1 - -// [GM] Can use all skills? (No or mimimum GM level) -gm_all_skill: no - -// [GM] Can equip anything? (No or minimum GM level, can cause client errors.) -gm_all_equipment: no - -// [GM] Can use skills without meeting the required conditions (items, etc...)? -// 'no' or minimum GM level to bypass requirements. -gm_skill_unconditional: no - -// [GM] Can join a password protected chat? (No or mimimum GM level) -gm_join_chat: no - -// [GM] Can't be kicked from a chat? (No or mimimum GM level) -gm_kick_chat: no - -// (@) GM Commands available only to GM's? (Note 1) -// set to 'No', Normal players (gm level 0) can use GM commands _IF_ you set the command level to 0. -// set to 'Yes', Normal players (gm level 0) can never use a GM command even if you set the command level to 0. -atcommand_gm_only: no - // (@) @allstats/@str/@agi/@vit/@int/@dex/@luk // allow gms to bypass the maximum stat parameter? ( if yes gm stats can go up to 32k ) default: no atcommand_max_stat_bypass: no -// Is the character of a GM account set as the object of a display by @ command etc. or not? -hide_GM_session: no - -// At what GM level can you see GMs and Account/Char IDs in the @who command? -who_display_aid: 40 - // Ban people that try trade dupe. // Duration of the ban, in minutes (default: 5). To disable the ban, set 0. ban_hack_trade: 5 - -// Set here minimum level of a (online) GM that can receive all informations about any player that try to hack, spoof a name, etc. -// Values are from 0 to 100. -// 100: disable information -// 0: send to any people, including normal players -// default: 60, according to GM definition in atcommand_athena.conf -hack_info_GM_level: 60 - -// The minimum GM level to bypass nowarp and nowarpto mapflags. -// This option is mainly used in commands which modify a character's -// map/coordinates (like @memo, @warp, @charwarp, @go, @jump, etc...). -// default: 20 (first level after normal player or super'normal' player) -any_warp_GM_min_level: 20 - -// The minimum level for a GM to be unable to distribute items. -// You should set this to the same level @item is set to in the atcommand.conf -// NEVER SET THIS VALUE TO 0, or you will block drop/trade for normal players -gm_cant_drop_min_lv: 1 - -//The trust level for your GMs. Any GMs ABOVE this level will be able to distribute items -//ie: Use Storage/Guild Storage, Drop Items, Use Vend, Trade items. -gm_cant_drop_max_lv: 0 - -// Minimum GM level to see the hp of every player? (Default: 60) -// no/0 can be used to disable it. -disp_hpmeter: 0 - -// Minimum GM level to view players equip regardless of their setting. -// (Default: 0 = Disabled). -gm_viewequip_min_lv: 0 - -// Can GMs invite non GMs to a party? (Note 1) -// set to 'No', GMs under the party invite trust level may not invite non GMs to a party. -// set to 'Yes', All GMs can invite any player to a party. -// Also, as long as this is off, players cannot invite GMs to a party as well. -gm_can_party: no - -//The trust level for GMs to invite to a party. Any GMs ABOVE OR EQUAL TO this level will be able to invite normal -//players into their party in addittion to other GMs. (regardless of gm_can_party) -gm_cant_party_min_lv: 20 - -// Players Titles (check msg_athena.conf for title strings) -// You may assign different titles for your Players and GMs -title_lvl1: 1 -title_lvl2: 10 -title_lvl3: 20 -title_lvl4: 40 -title_lvl5: 50 -title_lvl6: 60 -title_lvl7: 80 -title_lvl8: 99 - -// Minimum GM level required for client command /check (display character status) to work. -// Default: 60 -gm_check_minlevel: 60 diff --git a/conf/char_athena.conf b/conf/char_athena.conf index bc9e1ab1c..1b5e96a16 100644 --- a/conf/char_athena.conf +++ b/conf/char_athena.conf @@ -93,8 +93,10 @@ char_new_display: 0 // Maximum users able to connect to the server. Set to 0 for unlimited. max_connect_user: 0 -// Minimum GM level that is allowed to bypass the server limit of users. -gm_allow_level: 99 +// Group ID that is allowed to bypass the server limit of users. +// Default: -1 = nobody (there are no groups with ID < 0) +// See: conf/groups.conf +gm_allow_group: -1 // How often should the server save all files? (In seconds) // Note: Applies to all data files on TXT servers. diff --git a/conf/groups.conf b/conf/groups.conf new file mode 100644 index 000000000..d93d2aa09 --- /dev/null +++ b/conf/groups.conf @@ -0,0 +1,274 @@ +/* + +Player groups configuration file +--------------------------------- + +This file defines "player groups" and their privileges. + +Each group has its id and name, lists of available commands and other +permissions, and a list of other groups it inherits from. + + +Group settings +-------------- + +Unique group number. The only required field. + + +Any string. If empty, defaults to "Group ". It is used in several @who +commands. + + +Equivalent of GM level, which was used in revisions before r xxxxx. You can +set it to any number, but usually it's between 0 (default) and 99. Members of +groups with lower level can not perform some actions/commands (like @kick) on +members of groups with higher level. It is what script command getgmlevel() +returns. Group level can also be used to override trade restrictions +(db/item_trade.txt). + + +A group of settings + : +or + : [ , ] +First boolean value is for atcommand, second one for charcommand. If set to +true, group can use command. If only atcommand value is provided, false is +assumed for charcommand. If a command name is not included, false is assumed for +both atcommand and charcommand. +For a full list of available commands, see: doc/atcommands.txt. +Command names must not be aliases. + + +Boolean value. If true then all commands used by the group will be logged to +atcommandlog. If setting is omitted in a group definition, false is assumed. +Requires 'log_commands' to be enabled in 'conf/log_athena.conf'. + + +A group of settings + : +If a permission is not included, false is assumed. +For a full list of available permissions, see: doc/permissions.txt + + +A list of group names that given group will inherit commands and permissions +from. Group names are case-sensitive. + +Inheritance results +------------------- +Both multiple inheritance (Group 2 -> Group 1 and Group 3 -> Group 1) and +recursive inheritance (Group 3 -> Group 2 -> Group 1) are allowed. + +Inheritance rules should not create cycles (eg Group 1 inherits from Group 2, +and Group inherits from Group 1 at the same time). Configuration with cycles is +considered faulty and can't be processed fully by server. + +Command or permission is inherited ONLY if it's not already defined for the +group. +If group inherits from multiple groups, and the same command or permission is +defined for more than one of these groups, it's undefined which one will be +inherited. + +Syntax +------ +This config file uses libconfig syntax: +http://www.hyperrealm.com/libconfig/libconfig_manual.html#Configuration-Files + + +Upgrading from revisions before XXXXX +------------------------------------- + +*/ + +groups: ( +{ + id: 0 /* group 0 is the default group for every new account */ + name: "Player" + level: 0 + inherit: ( /*empty list*/ ) + commands: { + /* no commands by default */ + } + permissions: { + /* without this basic permissions regular players could not + trade or party */ + can_trade: true + can_party: true + } +}, +{ + id: 1 + name: "Super Player" + inherit: ( "Player" ) /* can do everything Players can and more */ + level: 0 + commands: { + /* informational commands */ + commands: true + charcommands: true + help: true + rates: true + uptime: true + showdelay: true + exp: true + mobinfo: true + iteminfo: true + whodrops: true + time: true + jailtime: true + hominfo: true + homstats: true + showexp: true + showzeny: true + whereis: true + /* feature commands */ + refresh: true + noask: true + noks: true + main: true + autoloot: true + alootid: true + autotrade: true + request: true + go: true + } + permissions: { + } +}, +{ + id: 2 + name: "Support" + inherit: ( "Super Player" ) + level: 1 + commands: { + version: true + where: true + jumpto: true + who: true + who2: true + who3: true + whomap: true + whomap2: true + whomap3: true + users: true + broadcast: true + localbroadcast: true + } + log_commands: true + permissions: { + receive_requests: true + view_equipment: true + } +}, +{ + id: 3 + name: "Script Manager" + inherit: ( "Support" ) + level: 1 + commands: { + tonpc: true + hidenpc: true + shownpc: true + loadnpc: true + unloadnpc: true + npcmove: true + addwarp: true + } + log_commands: true + permissions: { + any_warp: true + } +}, +{ + id: 4 + name: "Event Manager" + inherit: ( "Support" ) + level: 1 + commands: { + monster: true + monstersmall: true + monsterbig: true + killmonster2: true + cleanmap: true + item: [true, true] + zeny: [true, true] + disguise: [true, true] + undisguise: [true, true] + size: [true, true] + raise: true + raisemap: true + day: true + night: true + skillon: true + skilloff: true + pvpon: true + pvpoff: true + gvgon: true + gvgoff: true + allowks: true + me: true + marry: true + divorce: true + } + log_commands: true + permissions: { + can_trade: false + any_warp: true + } +}, +{ + id: 10 + name: "Law Enforcement" + inherit: ( "Support" ) + level: 2 + commands: { + hide: true + follow: true + kick: true + disguise: true + fakename: true + option: true + speed: true + warp: true + kill: true + recall: true + ban: true + block: true + jail: true + jailfor: true + mute: true + storagelist: true + cartlist: true + itemlist: true + stats: true + } + log_commands: true + permissions: { + join_chat: true + kick_chat: true + hide_session: true + who_display_aid: true + hack_info: true + any_warp: true + view_hpmeter: true + } +}, +{ + id: 99 + name: "Admin" + level: 99 + inherit: ( "Support", "Law Enforcement" ) + commands: { + } + log_commands: true + permissions: { + can_trade: true + can_party: true + all_skill: true + all_equipment: true + skill_unconditional: true + use_check: true + use_changemaptype: true + all_commands: true + } +} +) + diff --git a/conf/help.txt b/conf/help.txt index 13a958798..5a8f5871f 100644 --- a/conf/help.txt +++ b/conf/help.txt @@ -1,172 +1,230 @@ -// put at first, the minimum level to display the line - 1:To use one command, type it inside the message window where you usually type to chat. - 20:@h/@help - display this help guide. - 20:@h2/@help2 - displays the second help guide. - 1: - 1:--- MESSAGE CMD --- - 1:@main [on|off|message] - Turns on or off global chat (@main must be on to see global chat messages) - 1:@noask - Auto rejects Deals/Invites - 20:@gmotd - Broadcasts the Message of The Day file to all players. - 20:@me - Displays normal text as a message in this format: *name message* (like /me in mIRC) - 20:@fakename [Name] - Changes your name to your choice temporarly. - 20:@npctalk [NPC Name],[Message] - Forces a NPC to display a message in normal chat. - 40:/b/@broadcast - Broadcasts a GM message with name of the GM (in yellow) - 40:/nb /@kami - Broadcasts a GM message without name of the GM (in yellow) - 40:@kamib - Broadcasts a GM message without name of the GM (in blue) - 40:/lb/@localbroadcast - Broadcasts a GM message with name of the GM (in yellow) ONLY on your map - 40:/nlb - Broadcasts a GM message without name of the GM (in yellow) ONLY on your map - 1: - 1:--- INFORMATION CMD --- - 1:@commands - Displays a list of commands that you can use. - 1:@rates - Displays the server's current rates. - 1:@uptime - Displays how long the server has been online. - 1:@showdelay - Shows/Hides the "there is a delay after this skill" message. - 1:@exp - Displays current levels and % progress - 1:@mobinfo/@monsterinfo/@mi [Mob ID|Part of monster name] - Shows Monster Info (rates, stats, drops, MVP stuff) - 1:@iteminfo/@ii [Item ID|Part of item name] - Shows Item info (type, price, etc) - 1:@whodrops [Item ID|Part of item name] - Shows who drops an item (mobs with highest drop rates) - 1:@version - Displays SVN version of the server - 1:@email - to change your e-mail (characters protection) - 1:@where [char name] - Tells you the location of a character - 1:@time/@date/@server_date/@serverdate/@server_time/@servertime - Display the date/time of the server - 10:@showexp - Displays/Hides Experience gained. - 10:@showzeny - Displays/Hides Zeny gained. - 10:@mobsearch [Mob ID|Monster Name] - Shows the location of a certain mob on the current map. - 20:@who/@whois/@w [match_text] - Display a listing of who is online and their party/guild. - 20:@who2 [match_text] - Display a listing of who is online and their job. - 20:@who3 [match_text] - Display a listing of who is online and where. - 20:@whomap/@whomap2/@whomap3 [map] - like @who/@who2/@who3 but only for specifical map. - 20:@whogm [match_text] - Like @who+@who2+who3, but only for GM. - 40:@charcartlist - Displays all items of a player's cart. - 60: - 60:@guildspy - You will receive all messages of the guild channel (Chat logging must be enabled) - 60:@partyspy - You will receive all messages of the party channel (Chat logging must be enabled) - 99:@mapinfo [<0-3> [map]] - Give information about a map (general info +: 0: no more, 1: players, 2: NPC, 3: shops/chat). - 1: - 1:--- CHANGE GM STATE CMD --- - 1:@die - Kills yourself - 10:@go - Warps you to a city. - 10: -3: (Memo point 2) 1: morocc 5: izlude 9: yuno 13: niflheim - 10: -2: (Memo point 1) 2: geffen 6: aldebaran 10: amatsu 14: louyang - 10: -1: (Memo point 0) 3: payon 7: xmas (lutie) 11: gonryun 15: start point - 10: 0: prontera 4: alberta 8: comodo 12: umbala 16: prison/jail - 10: - 20:/shift/@jumpto/@warpto/@goto - Warps you to selected character - 20:@follow - follow a player - 20:@mountpeco - Give/remove you a peco (Class is required, but not skill) - 20:@disguise - Change your appearence to other players to a mob. - 20:@undisguise - Restore your normal appearance. - 20:@model - Changes your characters appearence. - 20:@size <1-3> Changes your size (1-Smallest 2-Biggest 3-Normal) - 40:/hide/@hide - Makes you character invisible (GM invisibility). Type /hide or@hide again become visible. - 40:@save - Sets respawn point to current spot - 40:@load/@return - Warps you to your save point - 40:/mm//mapmove/@warp/@rura/@mapmove - Warps you to the selected position - 40:@jump [x [y]]- Randomly warps you like a flywing. - 40:@job/@jobchange - Changes your job - 40: 0: Novice 18: Alchemist 4015: Paladin - 40: 1: Swordman 19: Bard 4016: Champion - 40: 2: Mage 20: Dancer 4017: Professor - 40: 3: Archer 23: Super Novice 4018: Stalker - 40: 4: Acolyte 4001: High Novice 4019: Creator - 40: 5: Merchant 4002: High Swordman 4020: Clown - 40: 6: Thief 4003: High Mage 4021: Gypsy - 40: 7: Knight 4004: High Archer 4046: Taekwon - 40: 8: Priest 4005: High Acolyte 4047: Star Gladiator - 40: 9: Wizard 4006: High Merchant 4049: Soul Linker - 40: 10: Blacksmith 4007: High Thief 24: Gunslinger - 40: 11: Hunter 4008: Lord Knight 25: Ninja - 40: 12: Assassin 4009: High Priest - 40: 14: Crusader 4010: High Wizard - 40: 15: Monk 4011: Whitesmith - 40: 16: Sage 4012: Sniper - 40: 17: Rogue 4013: Assassin Cross - 40: ---- Baby Classes ---- - 40: 4023: Baby 4024: Baby Swordman 4025: Baby Mage - 40: 4026: Baby Archer 4027: Baby Acolyte 4028: Baby Merchant - 40: 4029: Baby Thief 4030: Baby Knight 4031: Baby Priest - 40: 4032: Baby Wizard 4033: Baby Blacksmith 4034: Baby Hunter - 40: 4035: Baby Assassin 4037: Baby Crusader 4038: Baby Monk - 40: 4039: Baby Sage 4040: Baby Rogue 4041: Baby Alchemist - 40: 4042: Baby Bard 4043: Baby Dancer 4045: Super Baby - 40: - 40: (stackable) - 40: 1 Petrified (stackable) 01 Sight 32 Peco Peco riding 2048 Orc Head - 40: 2 Frozen 01 Poison 02 Hide 64 GM Perfect Hide 4096 Wedding Sprites - 40: 3 Stunned 02 Cursed 04 Cloak 128 Level 2 Cart 8192 Ruwach - 40: 4 Sleeping 04 Silenced 08 Level 1 Cart 256 Level 3 Cart - 40: 6 darkness 08 ??? 16 Falcon 512 Level 4 Cart - 40: 16 darkness 1024 Level 5 Cart - 40: - 40:@heal [ ] - Heals the desired amount of HP and SP. No value specified will do a full heal. - 40:@option - Adds different visual effects on or around your character - 40:@dye/@ccolor - Changes your characters appearence (only clothes color). - 40:@hairstyle/@hstyle - Changes your characters appearence (only hair style). - 40:@haircolor/@hcolor - Changes your characters appearence (only hair color). - 40:@speed <1-1000> - Changes you walking speed. 1 being the fastest and 1000 the slowest. Default 150. - 40:@effect [flag] - Give an efect to your character. - 40:@dropall - throws all your possession on the ground - 40:@storeall - puts all your possessions in storage - 40:@killable - make your character killable - 40:@memo [memo_position] - set/change a memo location (no position: display memo points). - 40:@spiritball - Gives you "spirit spheres" like from the skill "Call Spirits" - 40: (If the number you use is > 1000, your server may become instable or crash) - 40:@questskill <#> - Gives you the specified quest skill - 40:@lostskill <#> - Takes away the specified quest skill from you - 40:@skillid - look up a skill by name - 40:@useskill - use a skill on target - 40: Novice Swordsman Thief Merchant - 40: 142 = Emergency Care 144 = Moving HP Recovery 149 = Throw Sand 153 = Cart Revolution - 40: 143 = Act dead 145 = Attack Weak Point 150 = Back Sliding 154 = Change Cart - 40: Archer 146 = Auto Berserk 151 = Take Stone 155 = Crazy Uproar/Loud Voice - 40: 147 = Arrow Creation Acolyte 152 = Stone Throw Magician - 40: 148 = Charge Arrows 156 = Holy Light 157 = Energy Coat - 40: @skilltree < - 40: @marry , - marry two players - 40: @divorce - divorces the two players (you need just one name of them) - 60:@alive - Revives yourself from death - 60:@lvup/@blevel/@baselvlup - Raises your base level the desired number of levels. The max is 255 (User Defined). - 60:@joblvup/@jlevel/@joblvlup -Raises your job level the desired number of levels. The max is 50 For Basic Classes. For Super Novice and Advanced Classes it is 70. - 60:@allskill/@allskills/@skillall/@skillsall - Give you all skills. - 60:@stpoint - Gives you the desired number of stat points. - 60:@skpoint - Gives you the desired number of skill points. - 60:@zeny - Gives you desired amount of Zeny. - 60:@cash - Gives you the specified amount of cash points. - 60:@points - Gives you the specified amount of Kafra Points. - 60:@str,@agi,@vit,@int,@dex,@luk - Adds desired amount to any stat. For example "@str 10" raises your str by 10 - 60:@statall/@statsall/@allstats/@allstat [value] - Adds value in all stats (maximum if no value). - 60: @addwarp - 40: - 40:--- MONSTERS CMD --- - 40:@killmonster2 - kill all monsters of your map (without drops) - 50:/monster - Spawns 1 of the desired monster. - 50:@spawn/@monster/@summon [ [ [ []]]] - 50:@monster2 [ [ []]] - 50:@spawn/@monster/@summon/@monster2 "desired monster name" [ [ []]] - 50:@spawn/@monster/@summon/@monster2 "desired monster name" [ [ []]] - 50: Spawns the desired monster with any desired name. - 50:@monstersmall [Mob ID|Mob Name] - Spawns a smaller version of a monster. - 50:@monsterbig [Mob ID|Mob Name] - Spawns a larger version of a monster. - 60:@killmonster [map] - kill all monsters of the map (they drop) - 40: - 10:--- MISC CMD --- - 10:@autoloot [on|off|#] - Makes items go straight into your inventory. - 10:@autotrade/@at - Allows you to vend while you are offline. - 10:@changegm [Player Name] - Changes the leader of your guild (You must be guild leader) - 10:@changeleader [Player Name] - Changes the leader of your party (You must be party leader) - 20:@request [Message] - Sends a message to all connected GMs (via the gm whisper system) - 40:@sound [Path way to file in Data or GRF file] - Plays a sound from the data or grf file located on the client. - 50:@clone [Player Name] - Spawns a supportive clone of the given player. - 50:@slaveclone [Player Name] - Spawns a supportive clone of the given player that follows the creator around. - 50:@evilclone [Player Name] - Spawns an agressive clone of the given player. - 60:@changesex - Changes your gender. - 10: - 1:--- DUEL CMD --- - 1:@duel - Starts a duel. - 1:@invite - Invites a player to a duel. - 1:@accept - Accepts an invitation to a duel. - 1:@reject - Rejects an invitation to a duel. - 1:@leave - Leaves a duel. - 1: - 1:--- MAIL SYSTEM --- (SQL Only) - 1:@mail - Open mail box. +// This is help file that contains help messages for atcommands/charcommands. + +// Format: +// : "" + +// This file uses libconfig syntax. + +help: "Params: \n" "Shows help for specified command." +main: "Params: [on|off|]\n" "Turns on or off main (server-wide) chat. Sends message to main chat." +noask: "Auto rejects deals/invites." +gmotd: "Broadcasts the Message of The Day to all players." +me: "Params: \n" "Displays normal text as a message in this format: *name message* (like /me in mIRC)." +fakename: "Params: \n" "Changes your name to your choice temporarily." +npctalk: "Params: \n" "Forces a NPC to display a message in normal chat." +broadcast: "Params: \n" "Broadcasts a message with your name (in yellow)." +kami: "Params: \n" "Broadcasts a message without your name (in yellow)." +kamib: "Params: \n" "Broadcasts a message without your name (in blue)." +localbroadcast: "Params: \n" "Broadcasts a message with your name (in yellow) only on your map." +commands: "Displays a list of commands that you can use." +rates: "Displays the server's current rates." +uptime: "Displays how long the server has been online." +showdelay: "Shows/hides the \"There is a delay after this skill\" message." +exp: "Displays current levels and % progress." +mobinfo: "Params: |\n" "Shows monster info (stats, exp, drops etc)." +iteminfo: "Params: |\n" "Shows item info (type, price etc)." +whodrops: "Params: |\n" "Shows who drops an item (monster with highest drop rates)." +version: "Displays SVN version of the server." +email: "Params: \n" "Changes your account e-mail address." +where: "Params: \n" "Tells you the location of a character." +time: "Shows the date and time of the server." +showexp: "Displays/hides experience gained." +showzeny: "Displays/hides Zeny gained." +mobsearch: "Params: |\n" "Shows the location of a certain mob on the current map." +who: "Params: []\n" "Shows a list of online players and their party and guild." +who2: "Params: []\n" "Shows a list of online players and their job." +who3: "Params: []\n" "Shows a list of online players and their location." +whomap: "@whomap/@whomap2/@whomap3 [map] - like @who/@who2/@who3 but only for specifical map." +whogm: "Params: [match_text] - Like @who+@who2+who3, but only for GM." +guildspy: "Params: - You will receive all messages of the guild channel (Chat logging must be enabled)" +partyspy: "@partyspy - You will receive all messages of the party channel (Chat logging must be enabled)" +mapinfo: "Params: [<0-3> [map]] - Give information about a map (general info +: 0: no more, 1: players, 2: NPC, 3: shops/chat)." +die: "Kills yourself." +go: "Params: \n" "Warps you to a city.\n" + " -3: (Memo point 2) 1: morocc 5: izlude 9: yuno 13: niflheim \n" + " -2: (Memo point 1) 2: geffen 6: aldebaran 10: amatsu 14: louyang\n" + " -1: (Memo point 0) 3: payon 7: xmas (lutie) 11: gonryun 15: start point\n" + " 0: prontera 4: alberta 8: comodo 12: umbala 16: prison/jail\n" +jumpto: "Params: \n" "Warps you to selected character." +follow: "Params: \n" "Follow a player." +mount: "Give/remove you a peco (Class is required, but not skill)" +disguise: "Params: \n" "Change your appearence to other players to a mob." +undisguise: "Restore your normal appearance." +model: "Params: - Changes your characters appearence." +size: "Params: <1-3> Changes your size (1-Smallest 2-Biggest 3-Normal)" +hide: "Makes you character invisible (GM invisibility). Type again to become visible." +save: "Sets respawn point to current spot." +load: "Warps you to your save point." +warp: "Params: [ ]\n" "Warps you to the selected map and position." +jump: "Params: [ []]\n" "Randomly warps you like a flywing." +jobchange: "Params: \n" "Changes your job.\n" +" 0: Novice 18: Alchemist 4015: Paladin\n" +" 1: Swordman 19: Bard 4016: Champion\n" +" 2: Mage 20: Dancer 4017: Professor\n" +" 3: Archer 23: Super Novice 4018: Stalker\n" +" 4: Acolyte 4001: High Novice 4019: Creator\n" +" 5: Merchant 4002: High Swordman 4020: Clown\n" +" 6: Thief 4003: High Mage 4021: Gypsy\n" +" 7: Knight 4004: High Archer 4046: Taekwon\n" +" 8: Priest 4005: High Acolyte 4047: Star Gladiator\n" +" 9: Wizard 4006: High Merchant 4049: Soul Linker\n" +" 10: Blacksmith 4007: High Thief 24: Gunslinger\n" +" 11: Hunter 4008: Lord Knight 25: Ninja\n" +" 12: Assassin 4009: High Priest\n" +" 14: Crusader 4010: High Wizard\n" +" 15: Monk 4011: Whitesmith\n" +" 16: Sage 4012: Sniper\n" +" 17: Rogue 4013: Assassin Cross\n" +" ---- Baby Classes ----\n" +" 4023: Baby 4024: Baby Swordman 4025: Baby Mage\n" +" 4026: Baby Archer 4027: Baby Acolyte 4028: Baby Merchant\n" +" 4029: Baby Thief 4030: Baby Knight 4031: Baby Priest\n" +" 4032: Baby Wizard 4033: Baby Blacksmith 4034: Baby Hunter\n" +" 4035: Baby Assassin 4037: Baby Crusader 4038: Baby Monk\n" +" 4039: Baby Sage 4040: Baby Rogue 4041: Baby Alchemist\n" +" 4042: Baby Bard 4043: Baby Dancer 4045: Super Baby\n" +option: "Params: \n" "Adds different visual effects on or around your character.\n" +" (stackable) \n" +"1 Petrified (stackable) 01 Sight 32 Peco Peco riding 2048 Orc Head\n" +"2 Frozen 01 Poison 02 Hide 64 GM Perfect Hide 4096 Wedding Sprites\n" +"3 Stunned 02 Cursed 04 Cloak 128 Level 2 Cart 8192 Ruwach\n" +"4 Sleeping 04 Silenced 08 Level 1 Cart 256 Level 3 Cart\n" +"6 darkness 08 ??? 16 Falcon 512 Level 4 Cart\n" +" 16 darkness 1024 Level 5 Cart\n" +heal: "Params: [ ]\n" "Heals the desired amount of HP and SP. No value specified will do a full heal." +dye: "Params: \n" "Changes your characters clothes color." +hairstyle: "Params: \n" "Changes your hair style." +haircolor: "Params \n" "Changes your hair color." +speed: "Params: <1-1000>\n" "Changes you walking speed. 1 being the fastest and 1000 the slowest. Default is 150." +effect: "Params: []\n" "Give an effect to your character." +dropall: "Throws all your possession on the ground." +storeall: "Puts all your possessions in storage." +killable: "Make your character killable." +memo: "Params: [memo position]\n" "Set/change a memo location (no position: display memo points)." +spiritball: "Params: <1-100>\n" "Gives you \"spirit spheres\" like from the skill \"Call Spirits\".\n" +questskill: "Params: <#>\n" "Gives you the specified quest skill" +lostskill: "Params: <#>\n" "Takes away the specified quest skill from you\n" +" Novice Swordsman Thief Merchant\n" +" 142 = Emergency Care 144 = Moving HP Recovery 149 = Throw Sand 153 = Cart Revolution\n" +" 143 = Act dead 145 = Attack Weak Point 150 = Back Sliding 154 = Change Cart\n" +" Archer 146 = Auto Berserk 151 = Take Stone 155 = Crazy Uproar/Loud Voice\n" +" 147 = Arrow Creation Acolyte 152 = Stone Throw Magician\n" +" 148 = Charge Arrows 156 = Holy Light 157 = Energy Coat\n" +skillid: "Params: \n" "Look up a skill by name" +useskill: "Params: \n" "Use a skill on target" +skilltree: "Params: <" +marry: "Params: ,\n" "Marry two players." +divorce: "Params: \n" "Divorces the two players (you need just one name of them)" +alive: "Revives yourself from death." +blvl: "Params: \n" "Raises your base level the desired number of levels." +jlvl: "Params: \n" "Raises your job level the desired number of levels." +allskill: "Give you all skills." +stpoint: "Params: - Gives you the desired number of stat points." +skpoint: "Params: - Gives you the desired number of skill points." +zeny: "Params: - Gives you desired amount of Zeny." +cash: "Params: - Gives you the specified amount of cash points." +points: "Params: - Gives you the specified amount of Kafra Points." +str: "Params: \n" "Raises STR by given amount." +agi: "Params: \n" "Raises AGI by given amount." +dex: "Params: \n" "Raises DEX by given amount." +vit: "Params: \n" "Raises VIT by given amount." +int: "Params: \n" "Raises INT by given amount." +luk: "Params: \n" "Raises LUK by given amount." +allstats: "Params: \n" "Adds value in all stats (maximum if no value)." +addwarp: "Params: \n" +killmonster2: "Kills all monsters of your map (without drops)." +monster: "Params: [ [ [ []]]]\n" + "@monster2 [ [ []]]\n" +"@spawn/@monster/@summon/@monster2 \"desired monster name\" [ [ []]]\n" +"@spawn/@monster/@summon/@monster2 \"desired monster name\" [ [ []]]\n" +" Spawns the desired monster with any desired name." +monstersmall: "Params: [Mob ID|Mob Name]\n" "Spawns a smaller version of a monster." +monsterbig: "Params: [Mob ID|Mob Name]\n" "Spawns a larger version of a monster." +killmonster: "Params: [map]\n" "Kill all monsters of the map (they drop)" +autoloot: "Params: [on|off|#]\n" "Makes items go straight into your inventory." +autotrade: "Allows you to vend while you are offline." +changegm: "Params: [Player Name]\n" "Changes the leader of your guild (You must be guild leader)" +changeleader: "Params: [Player Name]\n" "Changes the leader of your party (You must be party leader)" +request: "Params: [Message]\n" "Sends a message to all connected GMs (via the gm whisper system)" +sound: "Params: [Path way to file in Data or GRF file]\n" "Plays a sound from the data or grf file located on the client." +clone: "Params: [Player Name]\n" "Spawns a supportive clone of the given player." +slaveclone: "Params: [Player Name]\n" "Spawns a supportive clone of the given player that follows the creator around." +evilclone: "Params: [Player Name]\n" "Spawns an agressive clone of the given player." +changesex: "Changes your gender." +duel: "Starts a duel." +invite: "Invites a player to a duel." +accept: "Accepts an invitation to a duel." +reject: "Rejects an invitation to a duel." +leave: "Leaves a duel." +mail: "Open mail box." +storage: "Opens storage." +itemreset: "Remove all your items." +guildstorage: "Opens guild storage." +idsearch: "Params: \n" "Search all items that name have part_of_item_name" +refine: "Params: <+/- amount>" +produce: "Params: <# of very's>\n" +" Element: 0=None 1=Ice 2=Earth 3=Fire 4=Wind\n" +" You can add up to 3 Star Crumbs and 1 element\n" +repairall: "Repair all items of your inventory" +item: "Params: \n" "Gives you the desired item." +item2: "Params: \n" "Gives you the desired item." +pvpon: "Turns pvp on on the current map" +pvpoff: "Turns pvp off on the current map" +gvgon: "Turns gvg on on the current map" +gvgoff: "Turns gvg off on the current map" +agitstart: "Starts War of Emperium" +agitend: "End War of Emperium" +party: "Params: \n" "Create a party." +guild: "Params: \n" "Create a guild." +glvl: "Params: <# of levels>\n" "Raise Guild by desired number of levels" +guildrecall: "Params: \n" "Warps all online characters of a guild to you." +partyrecall: "Params: \n" "Warps all online characters of a party to you." +petrename: "Re-enable pet rename" +pettalk: "Params: [Message]\n" "Makes your pet say a message." +petfriendly: "Params: <#>\n" "Set pet friendly amount (0-1000) 1000 = Max" +pethungry: "Params: <#>\n" "Set pet hungry amount (0-100) 100 = Max" +hatch: "Create a pet from your inventory eggs list." +makeegg: "Params: \n" "Gives pet egg for monster number in pet DB" +kick: "Params: \n" "Kicks specified character off the server" +unjail: "Params: \n" "Discharges specified character/prisoner" +kill: "Params: \n" "Kills specified character." +recall: "Params: \n" "Warps target character to you." +raise: "Params: \n" "Revives target character." +block: "Params: \n" "Blocks definitively a account" +unblock: "Params: \n" "Unblocks a account" +ban: "Params: