Bläddra i källkod

* Merged changes from trunk [14827:14894/trunk].

git-svn-id: https://svn.code.sf.net/p/rathena/svn/branches/renewal@14895 54d463be-8e91-2dee-dedb-b68131a5f0ec
ai4rei 14 år sedan
förälder
incheckning
f0d5c981e1
100 ändrade filer med 3588 tillägg och 864 borttagningar
  1. 54 0
      3rdparty/CMakeLists.txt
  2. 8 0
      3rdparty/msinttypes/CMakeLists.txt
  3. 16 0
      3rdparty/mt19937ar/CMakeLists.txt
  4. 24 0
      3rdparty/mt19937ar/Makefile.in
  5. 175 0
      3rdparty/mt19937ar/mt19937ar.c
  6. 72 0
      3rdparty/mt19937ar/mt19937ar.h
  7. 403 0
      3rdparty/mt19937ar/mt19937ar.out
  8. 65 0
      3rdparty/mt19937ar/mtTest.c
  9. 79 0
      3rdparty/mt19937ar/readme-mt.txt
  10. 69 0
      3rdparty/mysql/CMakeLists.txt
  11. 35 0
      3rdparty/mysql/FindMYSQL.cmake
  12. 66 0
      3rdparty/pcre/CMakeLists.txt
  13. 35 0
      3rdparty/pcre/FindPCRE.cmake
  14. 64 0
      3rdparty/zlib/CMakeLists.txt
  15. 265 0
      CMakeLists.txt
  16. 2 0
      Changelog-Renewal.txt
  17. 21 11
      Makefile.in
  18. 2 0
      conf/Changelog.txt
  19. 2 2
      conf/msg_athena.conf
  20. 3 1
      configure
  21. 1 0
      configure.in
  22. 1 1
      db/packet_db.txt
  23. 1 1
      doc/ea_job_system.txt
  24. 39 4
      doc/script_commands.txt
  25. 42 6
      eAthena-6.dsw
  26. 5 5
      npc/quests/quests_lighthalzen.txt
  27. 9 0
      src/CMakeLists.txt
  28. 51 0
      src/char/CMakeLists.txt
  29. 14 7
      src/char/Makefile.in
  30. 283 114
      src/char/char.c
  31. 10 0
      src/char/char.h
  32. 1 1
      src/char/int_homun.c
  33. 57 0
      src/char_sql/CMakeLists.txt
  34. 14 7
      src/char_sql/Makefile.in
  35. 284 114
      src/char_sql/char.c
  36. 11 0
      src/char_sql/char.h
  37. 2 2
      src/char_sql/int_auction.c
  38. 1 1
      src/char_sql/int_guild.c
  39. 144 0
      src/common/CMakeLists.txt
  40. 17 8
      src/common/Makefile.in
  41. 36 75
      src/common/cbasetypes.h
  42. 11 3
      src/common/core.c
  43. 13 0
      src/common/core.h
  44. 68 23
      src/common/db.c
  45. 15 5
      src/common/db.h
  46. 0 2
      src/common/ers.h
  47. 26 10
      src/common/grfio.c
  48. 3 2
      src/common/grfio.h
  49. 3 7
      src/common/malloc.c
  50. 12 7
      src/common/mmo.h
  51. 0 2
      src/common/plugin.h
  52. 0 3
      src/common/plugins.h
  53. 83 0
      src/common/random.c
  54. 18 0
      src/common/random.h
  55. 4 1
      src/common/socket.c
  56. 0 2
      src/common/socket.h
  57. 2 2
      src/common/sql.c
  58. 0 2
      src/common/sql.h
  59. 89 47
      src/common/strlib.c
  60. 21 2
      src/common/strlib.h
  61. 2 2
      src/common/timer.c
  62. 4 6
      src/common/timer.h
  63. 0 3
      src/common/utils.h
  64. 12 0
      src/login/CMakeLists.txt
  65. 22 11
      src/login/Makefile.in
  66. 3 3
      src/login/account_txt.c
  67. 2 2
      src/login/ipban_sql.c
  68. 102 28
      src/login/login.c
  69. 8 0
      src/login/login.h
  70. 43 0
      src/login/sql/CMakeLists.txt
  71. 43 0
      src/login/txt/CMakeLists.txt
  72. 12 0
      src/map/CMakeLists.txt
  73. 20 10
      src/map/Makefile.in
  74. 4 18
      src/map/atcommand.c
  75. 3 3
      src/map/battle.c
  76. 13 14
      src/map/battle.h
  77. 1 1
      src/map/battleground.c
  78. 1 1
      src/map/buyingstore.c
  79. 74 40
      src/map/chrif.c
  80. 1 1
      src/map/chrif.h
  81. 101 59
      src/map/clif.c
  82. 4 4
      src/map/clif.h
  83. 5 5
      src/map/guild.c
  84. 3 3
      src/map/homunculus.c
  85. 43 20
      src/map/instance.c
  86. 7 4
      src/map/instance.h
  87. 33 8
      src/map/map.c
  88. 12 4
      src/map/map.h
  89. 1 1
      src/map/mapreg_sql.c
  90. 1 1
      src/map/mapreg_txt.c
  91. 1 1
      src/map/mercenary.c
  92. 31 26
      src/map/mob.c
  93. 2 2
      src/map/mob.h
  94. 20 18
      src/map/npc.c
  95. 1 1
      src/map/npc.h
  96. 12 4
      src/map/party.c
  97. 1 1
      src/map/party.h
  98. 74 65
      src/map/pc.c
  99. 6 6
      src/map/pc.h
  100. 9 8
      src/map/pet.c

+ 54 - 0
3rdparty/CMakeLists.txt

@@ -0,0 +1,54 @@
+
+# macro to configure the use of local or system version of a package
+# Uses:
+#	HAVE_LOCAL_${name} - is local version available?
+#	${name}_LOCAL_LIBRARIES - libraries of the local version
+#	${name}_LOCAL_INCLUDE_DIRS - include directories of the local version
+#	HAVE_SYSTEM_${name} - is system version available?
+#	${name}_SYSTEM_LIBRARIES - libraries of the system version
+#	${name}_SYSTEM_INCLUDE_DIRS - include directories of the system version
+# Generates:
+#	WITH_LOCAL_${name} - use the local version of the package (only when local is available)
+#	WITH_${name} - use this package
+#	${name}_LIBRARIES - libraries
+#	${name}_INCLUDE_DIRS - include directories
+macro( CONFIGURE_WITH_LOCAL_OR_SYSTEM name )
+	unset( ${name}_LIBRARIES CACHE )
+	unset( ${name}_INCLUDE_DIRS CACHE )
+	if( HAVE_LOCAL_${name} )
+		set( WITH_LOCAL_${name} ON
+			CACHE BOOL "use local version of ${name}" )
+	else()
+		unset( WITH_LOCAL_${name} CACHE )
+	endif()
+	if( WITH_LOCAL_${name} )
+		message( STATUS "Configuring for local ${name}" )
+		set( ${name}_LIBRARIES ${${name}_LOCAL_LIBRARIES} )
+		set( ${name}_INCLUDE_DIRS ${${name}_LOCAL_INCLUDE_DIRS} )
+		message( STATUS "Configuring for local ${name} - done" )
+	elseif( HAVE_SYSTEM_${name} )
+		message( STATUS "Configuring for system ${name}" )
+		set( ${name}_LIBRARIES ${${name}_SYSTEM_LIBRARIES} )
+		set( ${name}_INCLUDE_DIRS ${${name}_SYSTEM_INCLUDE_DIRS} )
+		message( STATUS "Configuring for system ${name} - done" )
+	endif()
+	if( WITH_LOCAL_${name} OR HAVE_SYSTEM_${name} )
+		set( WITH_${name} ON
+			CACHE BOOL "use ${name}" )
+	else()
+		unset( WITH_${name} CACHE )
+	endif()
+	set( ${name}_LIBRARIES ${${name}_LIBRARIES}
+		CACHE PATH "${name} libraries" )
+	set( ${name}_INCLUDE_DIRS ${${name}_INCLUDE_DIRS}
+		CACHE PATH "${name} include directories" )
+	mark_as_advanced( ${name}_LIBRARIES )
+	mark_as_advanced( ${name}_INCLUDE_DIRS )
+endmacro( CONFIGURE_WITH_LOCAL_OR_SYSTEM )
+
+
+add_subdirectory( msinttypes )
+add_subdirectory( mt19937ar )
+add_subdirectory( mysql )
+add_subdirectory( pcre )
+add_subdirectory( zlib )

+ 8 - 0
3rdparty/msinttypes/CMakeLists.txt

@@ -0,0 +1,8 @@
+
+if( WIN32 )
+find_path( MSINTTYPES_INCLUDE_DIRS "inttypes.h"
+	PATHS "${CMAKE_CURRENT_SOURCE_DIR}/include"
+	NO_DEFAULT_PATH )
+mark_as_advanced( MSINTTYPES_INCLUDE_DIRS )
+set( GLOBAL_INCLUDE_DIRS ${GLOBAL_INCLUDE_DIRS} ${MSINTTYPES_INCLUDE_DIRS} CACHE INTERNAL "" )
+endif()

+ 16 - 0
3rdparty/mt19937ar/CMakeLists.txt

@@ -0,0 +1,16 @@
+
+find_path( MT19937AR_INCLUDE_DIRS "mt19937ar.h"
+	PATHS "${CMAKE_CURRENT_SOURCE_DIR}"
+	NO_DEFAULT_PATH )
+find_path( MT19937AR_SOURCE_DIR "mt19937ar.c"
+	PATHS "${CMAKE_CURRENT_SOURCE_DIR}"
+	NO_DEFAULT_PATH )
+mark_as_advanced( MT19937AR_INCLUDE_DIRS )
+mark_as_advanced( MT19937AR_SOURCE_DIR )
+
+set( MT19937AR_HEADERS
+	"${CMAKE_CURRENT_SOURCE_DIR}/mt19937ar.h"
+	CACHE INTERNAL "mt19937ar headers" )
+set( MT19937AR_SOURCES
+	"${CMAKE_CURRENT_SOURCE_DIR}/mt19937ar.c"
+	CACHE INTERNAL "mt19937ar sources" )

+ 24 - 0
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) $<

+ 175 - 0
3rdparty/mt19937ar/mt19937ar.c

@@ -0,0 +1,175 @@
+/* 
+   A C-program for MT19937, with initialization improved 2002/1/26.
+   Coded by Takuji Nishimura and Makoto Matsumoto.
+
+   Before using, initialize the state by using init_genrand(seed)  
+   or init_by_array(init_key, key_length).
+
+   Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura,
+   All rights reserved.                          
+   Copyright (C) 2005, Mutsuo Saito,
+   All rights reserved.                          
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+     1. Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+
+     2. Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+
+     3. The names of its contributors may not be used to endorse or promote 
+        products derived from this software without specific prior written 
+        permission.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+   Any feedback is very welcome.
+   http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html
+   email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space)
+*/
+
+#include <stdio.h>
+#include "mt19937ar.h"
+
+/* Period parameters */  
+#define N 624
+#define M 397
+#define MATRIX_A 0x9908b0dfUL   /* constant vector a */
+#define UPPER_MASK 0x80000000UL /* most significant w-r bits */
+#define LOWER_MASK 0x7fffffffUL /* least significant r bits */
+
+static unsigned long mt[N]; /* the array for the state vector  */
+static int mti=N+1; /* mti==N+1 means mt[N] is not initialized */
+
+/* initializes mt[N] with a seed */
+void init_genrand(unsigned long s)
+{
+    mt[0]= s & 0xffffffffUL;
+    for (mti=1; mti<N; mti++) {
+        mt[mti] = 
+	    (1812433253UL * (mt[mti-1] ^ (mt[mti-1] >> 30)) + mti); 
+        /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */
+        /* In the previous versions, MSBs of the seed affect   */
+        /* only MSBs of the array mt[].                        */
+        /* 2002/01/09 modified by Makoto Matsumoto             */
+        mt[mti] &= 0xffffffffUL;
+        /* for >32 bit machines */
+    }
+}
+
+/* initialize by an array with array-length */
+/* init_key is the array for initializing keys */
+/* key_length is its length */
+/* slight change for C++, 2004/2/26 */
+void init_by_array(unsigned long init_key[], int key_length)
+{
+    int i, j, k;
+    init_genrand(19650218UL);
+    i=1; j=0;
+    k = (N>key_length ? N : key_length);
+    for (; k; k--) {
+        mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1664525UL))
+          + init_key[j] + j; /* non linear */
+        mt[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */
+        i++; j++;
+        if (i>=N) { mt[0] = mt[N-1]; i=1; }
+        if (j>=key_length) j=0;
+    }
+    for (k=N-1; k; k--) {
+        mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1566083941UL))
+          - i; /* non linear */
+        mt[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */
+        i++;
+        if (i>=N) { mt[0] = mt[N-1]; i=1; }
+    }
+
+    mt[0] = 0x80000000UL; /* MSB is 1; assuring non-zero initial array */ 
+}
+
+/* generates a random number on [0,0xffffffff]-interval */
+unsigned long genrand_int32(void)
+{
+    unsigned long y;
+    static unsigned long mag01[2]={0x0UL, MATRIX_A};
+    /* mag01[x] = x * MATRIX_A  for x=0,1 */
+
+    if (mti >= N) { /* generate N words at one time */
+        int kk;
+
+        if (mti == N+1)   /* if init_genrand() has not been called, */
+            init_genrand(5489UL); /* a default initial seed is used */
+
+        for (kk=0;kk<N-M;kk++) {
+            y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
+            mt[kk] = mt[kk+M] ^ (y >> 1) ^ mag01[y & 0x1UL];
+        }
+        for (;kk<N-1;kk++) {
+            y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
+            mt[kk] = mt[kk+(M-N)] ^ (y >> 1) ^ mag01[y & 0x1UL];
+        }
+        y = (mt[N-1]&UPPER_MASK)|(mt[0]&LOWER_MASK);
+        mt[N-1] = mt[M-1] ^ (y >> 1) ^ mag01[y & 0x1UL];
+
+        mti = 0;
+    }
+  
+    y = mt[mti++];
+
+    /* Tempering */
+    y ^= (y >> 11);
+    y ^= (y << 7) & 0x9d2c5680UL;
+    y ^= (y << 15) & 0xefc60000UL;
+    y ^= (y >> 18);
+
+    return y;
+}
+
+/* generates a random number on [0,0x7fffffff]-interval */
+long genrand_int31(void)
+{
+    return (long)(genrand_int32()>>1);
+}
+
+/* generates a random number on [0,1]-real-interval */
+double genrand_real1(void)
+{
+    return genrand_int32()*(1.0/4294967295.0); 
+    /* divided by 2^32-1 */ 
+}
+
+/* generates a random number on [0,1)-real-interval */
+double genrand_real2(void)
+{
+    return genrand_int32()*(1.0/4294967296.0); 
+    /* divided by 2^32 */
+}
+
+/* generates a random number on (0,1)-real-interval */
+double genrand_real3(void)
+{
+    return (((double)genrand_int32()) + 0.5)*(1.0/4294967296.0); 
+    /* divided by 2^32 */
+}
+
+/* generates a random number on [0,1) with 53-bit resolution*/
+double genrand_res53(void) 
+{ 
+    unsigned long a=genrand_int32()>>5, b=genrand_int32()>>6; 
+    return(a*67108864.0+b)*(1.0/9007199254740992.0); 
+} 
+/* These real versions are due to Isaku Wada, 2002/01/09 added */

+ 72 - 0
3rdparty/mt19937ar/mt19937ar.h

@@ -0,0 +1,72 @@
+/* 
+   A C-program for MT19937, with initialization improved 2002/1/26.
+   Coded by Takuji Nishimura and Makoto Matsumoto.
+
+   Before using, initialize the state by using init_genrand(seed)  
+   or init_by_array(init_key, key_length).
+
+   Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura,
+   All rights reserved.
+   Copyright (C) 2005, Mutsuo Saito
+   All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+     1. Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+
+     2. Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+
+     3. The names of its contributors may not be used to endorse or promote 
+        products derived from this software without specific prior written 
+        permission.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+   Any feedback is very welcome.
+   http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html
+   email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space)
+*/
+
+/* initializes mt[N] with a seed */
+void init_genrand(unsigned long s);
+
+/* initialize by an array with array-length */
+/* init_key is the array for initializing keys */
+/* key_length is its length */
+/* slight change for C++, 2004/2/26 */
+void init_by_array(unsigned long init_key[], int key_length);
+
+/* generates a random number on [0,0xffffffff]-interval */
+unsigned long genrand_int32(void);
+
+/* generates a random number on [0,0x7fffffff]-interval */
+long genrand_int31(void);
+
+/* These real versions are due to Isaku Wada, 2002/01/09 added */
+/* generates a random number on [0,1]-real-interval */
+double genrand_real1(void);
+
+/* generates a random number on [0,1)-real-interval */
+double genrand_real2(void);
+
+/* generates a random number on (0,1)-real-interval */
+double genrand_real3(void);
+
+/* generates a random number on [0,1) with 53-bit resolution*/
+double genrand_res53(void);

+ 403 - 0
3rdparty/mt19937ar/mt19937ar.out

@@ -0,0 +1,403 @@
+1000 outputs of genrand_int32()
+1067595299  955945823  477289528 4107218783 4228976476 
+3344332714 3355579695  227628506  810200273 2591290167 
+2560260675 3242736208  646746669 1479517882 4245472273 
+1143372638 3863670494 3221021970 1773610557 1138697238 
+1421897700 1269916527 2859934041 1764463362 3874892047 
+3965319921   72549643 2383988930 2600218693 3237492380 
+2792901476  725331109  605841842  271258942  715137098 
+3297999536 1322965544 4229579109 1395091102 3735697720 
+2101727825 3730287744 2950434330 1661921839 2895579582 
+2370511479 1004092106 2247096681 2111242379 3237345263 
+4082424759  219785033 2454039889 3709582971  835606218 
+2411949883 2735205030  756421180 2175209704 1873865952 
+2762534237 4161807854 3351099340  181129879 3269891896 
+ 776029799 2218161979 3001745796 1866825872 2133627728 
+  34862734 1191934573 3102311354 2916517763 1012402762 
+2184831317 4257399449 2899497138 3818095062 3030756734 
+1282161629  420003642 2326421477 2741455717 1278020671 
+3744179621  271777016 2626330018 2560563991 3055977700 
+4233527566 1228397661 3595579322 1077915006 2395931898 
+1851927286 3013683506 1999971931 3006888962 1049781534 
+1488758959 3491776230  104418065 2448267297 3075614115 
+3872332600  891912190 3936547759 2269180963 2633455084 
+1047636807 2604612377 2709305729 1952216715  207593580 
+2849898034  670771757 2210471108  467711165  263046873 
+3569667915 1042291111 3863517079 1464270005 2758321352 
+3790799816 2301278724 3106281430    7974801 2792461636 
+ 555991332  621766759 1322453093  853629228  686962251 
+1455120532  957753161 1802033300 1021534190 3486047311 
+1902128914 3701138056 4176424663 1795608698  560858864 
+3737752754 3141170998 1553553385 3367807274  711546358 
+2475125503  262969859  251416325 2980076994 1806565895 
+ 969527843 3529327173 2736343040 2987196734 1649016367 
+2206175811 3048174801 3662503553 3138851612 2660143804 
+1663017612 1816683231  411916003 3887461314 2347044079 
+1015311755 1203592432 2170947766 2569420716  813872093 
+1105387678 1431142475  220570551 4243632715 4179591855 
+2607469131 3090613241  282341803 1734241730 1391822177 
+1001254810  827927915 1886687171 3935097347 2631788714 
+3905163266  110554195 2447955646 3717202975 3304793075 
+3739614479 3059127468  953919171 2590123714 1132511021 
+3795593679 2788030429  982155079 3472349556  859942552 
+2681007391 2299624053  647443547  233600422  608168955 
+3689327453 1849778220 1608438222 3968158357 2692977776 
+2851872572  246750393 3582818628 3329652309 4036366910 
+1012970930  950780808 3959768744 2538550045  191422718 
+2658142375 3276369011 2927737484 1234200027 1920815603 
+3536074689 1535612501 2184142071 3276955054  428488088 
+2378411984 4059769550 3913744741 2732139246   64369859 
+3755670074  842839565 2819894466 2414718973 1010060670 
+1839715346 2410311136  152774329 3485009480 4102101512 
+2852724304  879944024 1785007662 2748284463 1354768064 
+3267784736 2269127717 3001240761 3179796763  895723219 
+ 865924942 4291570937   89355264 1471026971 4114180745 
+3201939751 2867476999 2460866060 3603874571 2238880432 
+3308416168 2072246611 2755653839 3773737248 1709066580 
+4282731467 2746170170 2832568330  433439009 3175778732 
+  26248366 2551382801  183214346 3893339516 1928168445 
+1337157619 3429096554 3275170900 1782047316 4264403756 
+1876594403 4289659572 3223834894 1728705513 4068244734 
+2867840287 1147798696  302879820 1730407747 1923824407 
+1180597908 1569786639  198796327  560793173 2107345620 
+2705990316 3448772106 3678374155  758635715  884524671 
+ 486356516 1774865603 3881226226 2635213607 1181121587 
+1508809820 3178988241 1594193633 1235154121  326117244 
+2304031425  937054774 2687415945 3192389340 2003740439 
+1823766188 2759543402   10067710 1533252662 4132494984 
+  82378136  420615890 3467563163  541562091 3535949864 
+2277319197 3330822853 3215654174 4113831979 4204996991 
+2162248333 3255093522 2219088909 2978279037  255818579 
+2859348628 3097280311 2569721123 1861951120 2907080079 
+2719467166  998319094 2521935127 2404125338  259456032 
+2086860995 1839848496 1893547357 2527997525 1489393124 
+2860855349   76448234 2264934035  744914583 2586791259 
+1385380501   66529922 1819103258 1899300332 2098173828 
+1793831094  276463159  360132945 4178212058  595015228 
+ 177071838 2800080290 1573557746 1548998935  378454223 
+1460534296 1116274283 3112385063 3709761796  827999348 
+3580042847 1913901014  614021289 4278528023 1905177404 
+  45407939 3298183234 1184848810 3644926330 3923635459 
+1627046213 3677876759  969772772 1160524753 1522441192 
+ 452369933 1527502551  832490847 1003299676 1071381111 
+2891255476  973747308 4086897108 1847554542 3895651598 
+2227820339 1621250941 2881344691 3583565821 3510404498 
+ 849362119  862871471  797858058 2867774932 2821282612 
+3272403146 3997979905  209178708 1805135652    6783381 
+2823361423  792580494 4263749770  776439581 3798193823 
+2853444094 2729507474 1071873341 1329010206 1289336450 
+3327680758 2011491779   80157208  922428856 1158943220 
+1667230961 2461022820 2608845159  387516115 3345351910 
+1495629111 4098154157 3156649613 3525698599 4134908037 
+ 446713264 2137537399 3617403512  813966752 1157943946 
+3734692965 1680301658 3180398473 3509854711 2228114612 
+1008102291  486805123  863791847 3189125290 1050308116 
+3777341526 4291726501  844061465 1347461791 2826481581 
+ 745465012 2055805750 4260209475 2386693097 2980646741 
+ 447229436 2077782664 1232942813 4023002732 1399011509 
+3140569849 2579909222 3794857471  900758066 2887199683 
+1720257997 3367494931 2668921229  955539029 3818726432 
+1105704962 3889207255 2277369307 2746484505 1761846513 
+2413916784 2685127085 4240257943 1166726899 4215215715 
+3082092067 3960461946 1663304043 2087473241 4162589986 
+2507310778 1579665506  767234210  970676017  492207530 
+1441679602 1314785090 3262202570 3417091742 1561989210 
+3011406780 1146609202 3262321040 1374872171 1634688712 
+1280458888 2230023982  419323804 3262899800   39783310 
+1641619040 1700368658 2207946628 2571300939 2424079766 
+ 780290914 2715195096 3390957695  163151474 2309534542 
+1860018424  555755123  280320104 1604831083 2713022383 
+1728987441 3639955502  623065489 3828630947 4275479050 
+3516347383 2343951195 2430677756  635534992 3868699749 
+ 808442435 3070644069 4282166003 2093181383 2023555632 
+1568662086 3422372620 4134522350 3016979543 3259320234 
+2888030729 3185253876 4258779643 1267304371 1022517473 
+ 815943045  929020012 2995251018 3371283296 3608029049 
+2018485115  122123397 2810669150 1411365618 1238391329 
+1186786476 3155969091 2242941310 1765554882  279121160 
+4279838515 1641578514 3796324015   13351065  103516986 
+1609694427  551411743 2493771609 1316337047 3932650856 
+4189700203  463397996 2937735066 1855616529 2626847990 
+  55091862 3823351211  753448970 4045045500 1274127772 
+1124182256   92039808 2126345552  425973257  386287896 
+2589870191 1987762798 4084826973 2172456685 3366583455 
+3602966653 2378803535 2901764433 3716929006 3710159000 
+2653449155 3469742630 3096444476 3932564653 2595257433 
+ 318974657 3146202484  853571438  144400272 3768408841 
+ 782634401 2161109003  570039522 1886241521   14249488 
+2230804228 1604941699 3928713335 3921942509 2155806892 
+ 134366254  430507376 1924011722  276713377  196481886 
+3614810992 1610021185 1785757066  851346168 3761148643 
+2918835642 3364422385 3012284466 3735958851 2643153892 
+3778608231 1164289832  205853021 2876112231 3503398282 
+3078397001 3472037921 1748894853 2740861475  316056182 
+1660426908  168885906  956005527 3984354789  566521563 
+1001109523 1216710575 2952284757 3834433081 3842608301 
+2467352408 3974441264 3256601745 1409353924 1329904859 
+2307560293 3125217879 3622920184 3832785684 3882365951 
+2308537115 2659155028 1450441945 3532257603 3186324194 
+1225603425 1124246549  175808705 3009142319 2796710159 
+3651990107  160762750 1902254979 1698648476 1134980669 
+ 497144426 3302689335 4057485630 3603530763 4087252587 
+ 427812652  286876201  823134128 1627554964 3745564327 
+2589226092 4202024494   62878473 3275585894 3987124064 
+2791777159 1916869511 2585861905 1375038919 1403421920 
+  60249114 3811870450 3021498009 2612993202  528933105 
+2757361321 3341402964 2621861700  273128190 4015252178 
+3094781002 1621621288 2337611177 1796718448 1258965619 
+4241913140 2138560392 3022190223 4174180924  450094611 
+3274724580  617150026 2704660665 1469700689 1341616587 
+ 356715071 1188789960 2278869135 1766569160 2795896635 
+  57824704 2893496380 1235723989 1630694347 3927960522 
+ 428891364 1814070806 2287999787 4125941184 3968103889 
+3548724050 1025597707 1404281500 2002212197   92429143 
+2313943944 2403086080 3006180634 3561981764 1671860914 
+1768520622 1803542985  844848113 3006139921 1410888995 
+1157749833 2125704913 1789979528 1799263423  741157179 
+2405862309  767040434 2655241390 3663420179 2172009096 
+2511931187 1680542666  231857466 1154981000  157168255 
+1454112128 3505872099 1929775046 2309422350 2143329496 
+2960716902  407610648 2938108129 2581749599  538837155 
+2342628867  430543915  740188568 1937713272 3315215132 
+2085587024 4030765687  766054429 3517641839  689721775 
+1294158986 1753287754 4202601348 1974852792   33459103 
+3568087535 3144677435 1686130825 4134943013 3005738435 
+3599293386  426570142  754104406 3660892564 1964545167 
+ 829466833  821587464 1746693036 1006492428 1595312919 
+1256599985 1024482560 1897312280 2902903201  691790057 
+1037515867 3176831208 1968401055 2173506824 1089055278 
+1748401123 2941380082  968412354 1818753861 2973200866 
+3875951774 1119354008 3988604139 1647155589 2232450826 
+3486058011 3655784043 3759258462  847163678 1082052057 
+ 989516446 2871541755 3196311070 3929963078  658187585 
+3664944641 2175149170 2203709147 2756014689 2456473919 
+3890267390 1293787864 2830347984 3059280931 4158802520 
+1561677400 2586570938  783570352 1355506163   31495586 
+3789437343 3340549429 2092501630  896419368  671715824 
+3530450081 3603554138 1055991716 3442308219 1499434728 
+3130288473 3639507000   17769680 2259741420  487032199 
+4227143402 3693771256 1880482820 3924810796  381462353 
+4017855991 2452034943 2736680833 2209866385 2128986379 
+ 437874044  595759426  641721026 1636065708 3899136933 
+ 629879088 3591174506  351984326 2638783544 2348444281 
+2341604660 2123933692  143443325 1525942256  364660499 
+ 599149312  939093251 1523003209  106601097  376589484 
+1346282236 1297387043  764598052 3741218111  933457002 
+1886424424 3219631016  525405256 3014235619  323149677 
+2038881721 4100129043 2851715101 2984028078 1888574695 
+2014194741 3515193880 4180573530 3461824363 2641995497 
+3179230245 2902294983 2217320456 4040852155 1784656905 
+3311906931   87498458 2752971818 2635474297 2831215366 
+3682231106 2920043893 3772929704 2816374944  309949752 
+2383758854  154870719  385111597 1191604312 1840700563 
+ 872191186 2925548701 1310412747 2102066999 1504727249 
+3574298750 1191230036 3330575266 3180292097 3539347721 
+ 681369118 3305125752 3648233597  950049240 4173257693 
+1760124957  512151405  681175196  580563018 1169662867 
+4015033554 2687781101  699691603 2673494188 1137221356 
+ 123599888  472658308 1053598179 1012713758 3481064843 
+3759461013 3981457956 3830587662 1877191791 3650996736 
+ 988064871 3515461600 4089077232 2225147448 1249609188 
+2643151863 3896204135 2416995901 1397735321 3460025646 
+
+1000 outputs of genrand_real2()
+0.76275443 0.99000644 0.98670464 0.10143112 0.27933125 
+0.69867227 0.94218740 0.03427201 0.78842173 0.28180608 
+0.92179002 0.20785655 0.54534773 0.69644020 0.38107718 
+0.23978165 0.65286910 0.07514568 0.22765211 0.94872929 
+0.74557914 0.62664415 0.54708246 0.90959343 0.42043116 
+0.86334511 0.19189126 0.14718544 0.70259889 0.63426346 
+0.77408121 0.04531601 0.04605807 0.88595519 0.69398270 
+0.05377184 0.61711170 0.05565708 0.10133577 0.41500776 
+0.91810699 0.22320679 0.23353705 0.92871862 0.98897234 
+0.19786706 0.80558809 0.06961067 0.55840445 0.90479405 
+0.63288060 0.95009721 0.54948447 0.20645042 0.45000959 
+0.87050869 0.70806991 0.19406895 0.79286390 0.49332866 
+0.78483914 0.75145146 0.12341941 0.42030252 0.16728160 
+0.59906494 0.37575460 0.97815160 0.39815952 0.43595080 
+0.04952478 0.33917805 0.76509902 0.61034321 0.90654701 
+0.92915732 0.85365931 0.18812377 0.65913428 0.28814566 
+0.59476081 0.27835931 0.60722542 0.68310435 0.69387186 
+0.03699800 0.65897714 0.17527003 0.02889304 0.86777366 
+0.12352068 0.91439461 0.32022990 0.44445731 0.34903686 
+0.74639273 0.65918367 0.92492794 0.31872642 0.77749724 
+0.85413832 0.76385624 0.32744211 0.91326300 0.27458185 
+0.22190155 0.19865383 0.31227402 0.85321225 0.84243342 
+0.78544200 0.71854080 0.92503892 0.82703064 0.88306297 
+0.47284073 0.70059042 0.48003761 0.38671694 0.60465770 
+0.41747204 0.47163243 0.72750808 0.65830223 0.10955369 
+0.64215401 0.23456345 0.95944940 0.72822249 0.40888451 
+0.69980355 0.26677428 0.57333635 0.39791582 0.85377858 
+0.76962816 0.72004885 0.90903087 0.51376506 0.37732665 
+0.12691640 0.71249738 0.81217908 0.37037313 0.32772374 
+0.14238259 0.05614811 0.74363008 0.39773267 0.94859135 
+0.31452454 0.11730313 0.62962618 0.33334237 0.45547255 
+0.10089665 0.56550662 0.60539371 0.16027624 0.13245301 
+0.60959939 0.04671662 0.99356286 0.57660859 0.40269560 
+0.45274629 0.06699735 0.85064246 0.87742744 0.54508392 
+0.87242982 0.29321385 0.67660627 0.68230715 0.79052073 
+0.48592054 0.25186266 0.93769755 0.28565487 0.47219067 
+0.99054882 0.13155240 0.47110470 0.98556600 0.84397623 
+0.12875246 0.90953202 0.49129015 0.23792727 0.79481194 
+0.44337770 0.96564297 0.67749118 0.55684872 0.27286897 
+0.79538393 0.61965356 0.22487929 0.02226018 0.49248200 
+0.42247006 0.91797788 0.99250134 0.23449967 0.52531508 
+0.10246337 0.78685622 0.34310922 0.89892996 0.40454552 
+0.68608407 0.30752487 0.83601319 0.54956031 0.63777550 
+0.82199797 0.24890696 0.48801123 0.48661910 0.51223987 
+0.32969635 0.31075073 0.21393155 0.73453207 0.15565705 
+0.58584522 0.28976728 0.97621478 0.61498701 0.23891470 
+0.28518540 0.46809591 0.18371914 0.37597910 0.13492176 
+0.66849449 0.82811466 0.56240330 0.37548956 0.27562998 
+0.27521910 0.74096121 0.77176757 0.13748143 0.99747138 
+0.92504502 0.09175241 0.21389176 0.21766512 0.31183245 
+0.23271221 0.21207367 0.57903312 0.77523344 0.13242613 
+0.31037988 0.01204835 0.71652949 0.84487594 0.14982178 
+0.57423142 0.45677888 0.48420169 0.53465428 0.52667473 
+0.46880526 0.49849733 0.05670710 0.79022476 0.03872047 
+0.21697212 0.20443086 0.28949326 0.81678186 0.87629474 
+0.92297064 0.27373097 0.84625273 0.51505586 0.00582792 
+0.33295971 0.91848412 0.92537226 0.91760033 0.07541125 
+0.71745848 0.61158698 0.00941650 0.03135554 0.71527471 
+0.24821915 0.63636652 0.86159918 0.26450229 0.60160194 
+0.35557725 0.24477500 0.07186456 0.51757096 0.62120362 
+0.97981062 0.69954667 0.21065616 0.13382753 0.27693186 
+0.59644095 0.71500764 0.04110751 0.95730081 0.91600724 
+0.47704678 0.26183479 0.34706971 0.07545431 0.29398385 
+0.93236070 0.60486023 0.48015011 0.08870451 0.45548581 
+0.91872718 0.38142712 0.10668643 0.01397541 0.04520355 
+0.93822273 0.18011940 0.57577277 0.91427606 0.30911399 
+0.95853475 0.23611214 0.69619891 0.69601980 0.76765372 
+0.58515930 0.49479057 0.11288752 0.97187699 0.32095365 
+0.57563608 0.40760618 0.78703383 0.43261152 0.90877651 
+0.84686346 0.10599030 0.72872803 0.19315490 0.66152912 
+0.10210518 0.06257876 0.47950688 0.47062066 0.72701157 
+0.48915116 0.66110261 0.60170685 0.24516994 0.12726050 
+0.03451185 0.90864994 0.83494878 0.94800035 0.91035206 
+0.14480751 0.88458997 0.53498312 0.15963215 0.55378627 
+0.35171349 0.28719791 0.09097957 0.00667896 0.32309622 
+0.87561479 0.42534520 0.91748977 0.73908457 0.41793223 
+0.99279792 0.87908370 0.28458072 0.59132853 0.98672190 
+0.28547393 0.09452165 0.89910674 0.53681109 0.37931425 
+0.62683489 0.56609740 0.24801549 0.52948179 0.98328855 
+0.66403523 0.55523786 0.75886666 0.84784685 0.86829981 
+0.71448906 0.84670080 0.43922919 0.20771016 0.64157936 
+0.25664246 0.73055695 0.86395782 0.65852932 0.99061803 
+0.40280575 0.39146298 0.07291005 0.97200603 0.20555729 
+0.59616495 0.08138254 0.45796388 0.33681125 0.33989127 
+0.18717090 0.53545811 0.60550838 0.86520709 0.34290701 
+0.72743276 0.73023855 0.34195926 0.65019733 0.02765254 
+0.72575740 0.32709576 0.03420866 0.26061893 0.56997511 
+0.28439072 0.84422744 0.77637570 0.55982168 0.06720327 
+0.58449067 0.71657369 0.15819609 0.58042821 0.07947911 
+0.40193792 0.11376012 0.88762938 0.67532159 0.71223735 
+0.27829114 0.04806073 0.21144026 0.58830274 0.04140071 
+0.43215628 0.12952729 0.94668759 0.87391019 0.98382450 
+0.27750768 0.90849647 0.90962737 0.59269720 0.96102026 
+0.49544979 0.32007095 0.62585546 0.03119821 0.85953001 
+0.22017528 0.05834068 0.80731217 0.53799961 0.74166948 
+0.77426600 0.43938444 0.54862081 0.58575513 0.15886492 
+0.73214332 0.11649057 0.77463977 0.85788827 0.17061997 
+0.66838056 0.96076133 0.07949296 0.68521946 0.89986254 
+0.05667410 0.12741385 0.83470977 0.63969104 0.46612929 
+0.10200126 0.01194925 0.10476340 0.90285217 0.31221221 
+0.32980614 0.46041971 0.52024973 0.05425470 0.28330912 
+0.60426543 0.00598243 0.97244013 0.21135841 0.78561597 
+0.78428734 0.63422849 0.32909934 0.44771136 0.27380750 
+0.14966697 0.18156268 0.65686758 0.28726350 0.97074787 
+0.63676171 0.96649494 0.24526295 0.08297372 0.54257548 
+0.03166785 0.33735355 0.15946671 0.02102971 0.46228045 
+0.11892296 0.33408336 0.29875681 0.29847692 0.73767569 
+0.02080745 0.62980060 0.08082293 0.22993106 0.25031439 
+0.87787525 0.45150053 0.13673441 0.63407612 0.97907688 
+0.52241942 0.50580158 0.06273902 0.05270283 0.77031811 
+0.05113352 0.24393329 0.75036441 0.37436336 0.22877652 
+0.59975358 0.85707591 0.88691457 0.85547165 0.36641027 
+0.58720133 0.45462835 0.09243817 0.32981586 0.07820411 
+0.25421519 0.36004706 0.60092307 0.46192412 0.36758683 
+0.98424170 0.08019934 0.68594024 0.45826386 0.29962317 
+0.79365413 0.89231296 0.49478547 0.87645944 0.23590734 
+0.28106737 0.75026285 0.08136314 0.79582424 0.76010628 
+0.82792971 0.27947652 0.72482861 0.82191216 0.46171689 
+0.79189752 0.96043686 0.51609668 0.88995725 0.28998963 
+0.55191845 0.03934737 0.83033700 0.49553013 0.98009549 
+0.19017594 0.98347750 0.33452066 0.87144372 0.72106301 
+0.71272114 0.71465963 0.88361677 0.85571283 0.73782329 
+0.20920458 0.34855153 0.46766817 0.02780062 0.74898344 
+0.03680650 0.44866557 0.77426312 0.91025891 0.25195236 
+0.87319953 0.63265037 0.25552148 0.27422476 0.95217406 
+0.39281839 0.66441573 0.09158900 0.94515992 0.07800798 
+0.02507888 0.39901462 0.17382573 0.12141278 0.85502334 
+0.19902911 0.02160210 0.44460522 0.14688742 0.68020336 
+0.71323733 0.60922473 0.95400380 0.99611159 0.90897777 
+0.41073520 0.66206647 0.32064685 0.62805003 0.50677209 
+0.52690101 0.87473387 0.73918362 0.39826974 0.43683919 
+0.80459118 0.32422684 0.01958019 0.95319576 0.98326137 
+0.83931735 0.69060863 0.33671416 0.68062550 0.65152380 
+0.33392969 0.03451730 0.95227244 0.68200635 0.85074171 
+0.64721009 0.51234433 0.73402047 0.00969637 0.93835057 
+0.80803854 0.31485260 0.20089527 0.01323282 0.59933780 
+0.31584602 0.20209563 0.33754800 0.68604181 0.24443049 
+0.19952227 0.78162632 0.10336988 0.11360736 0.23536740 
+0.23262256 0.67803776 0.48749791 0.74658435 0.92156640 
+0.56706407 0.36683221 0.99157136 0.23421374 0.45183767 
+0.91609720 0.85573315 0.37706276 0.77042618 0.30891908 
+0.40709595 0.06944866 0.61342849 0.88817388 0.58734506 
+0.98711323 0.14744128 0.63242656 0.87704136 0.68347125 
+0.84446569 0.43265239 0.25146321 0.04130111 0.34259839 
+0.92697368 0.40878778 0.56990338 0.76204273 0.19820348 
+0.66314909 0.02482844 0.06669207 0.50205581 0.26084093 
+0.65139159 0.41650223 0.09733904 0.56344203 0.62651696 
+0.67332139 0.58037374 0.47258086 0.21010758 0.05713135 
+0.89390629 0.10781246 0.32037450 0.07628388 0.34227964 
+0.42190597 0.58201860 0.77363549 0.49595133 0.86031236 
+0.83906769 0.81098161 0.26694195 0.14215941 0.88210306 
+0.53634237 0.12090720 0.82480459 0.75930318 0.31847147 
+0.92768077 0.01037616 0.56201727 0.88107122 0.35925856 
+0.85860762 0.61109408 0.70408301 0.58434977 0.92192494 
+0.62667915 0.75988365 0.06858761 0.36156496 0.58057195 
+0.13636150 0.57719713 0.59340255 0.63530602 0.22976282 
+0.71915530 0.41162531 0.63979565 0.09931342 0.79344045 
+0.10893790 0.84450224 0.23122236 0.99485593 0.73637397 
+0.17276368 0.13357764 0.74965804 0.64991737 0.61990341 
+0.41523170 0.05878239 0.05687301 0.05497131 0.42868366 
+0.42571090 0.25810502 0.89642955 0.30439758 0.39310223 
+0.11357431 0.04288255 0.23397550 0.11200634 0.85621396 
+0.89733974 0.37508865 0.42077265 0.68597384 0.72781399 
+0.19296476 0.61699087 0.31667128 0.67756410 0.00177323 
+0.05725176 0.79474693 0.18885238 0.06724856 0.68193156 
+0.42202167 0.22082041 0.28554673 0.64995708 0.87851940 
+0.29124547 0.61009521 0.87374537 0.05743712 0.69902994 
+0.81925115 0.45653873 0.37236821 0.31118709 0.52734307 
+0.39672836 0.38185294 0.30163915 0.17374510 0.04913278 
+0.90404879 0.25742801 0.58266467 0.97663209 0.79823377 
+0.36437958 0.15206043 0.26529938 0.22690047 0.05839021 
+0.84721160 0.18622435 0.37809403 0.55706977 0.49828704 
+0.47659049 0.24289680 0.88477595 0.07807463 0.56245739 
+0.73490635 0.21099431 0.13164942 0.75840044 0.66877037 
+0.28988183 0.44046090 0.24967434 0.80048356 0.26029740 
+0.30416821 0.64151867 0.52067892 0.12880774 0.85465381 
+0.02690525 0.19149288 0.49630295 0.79682619 0.43566145 
+0.00288078 0.81484193 0.03763639 0.68529083 0.01339574 
+0.38405386 0.30537067 0.22994703 0.44000045 0.27217985 
+0.53831243 0.02870435 0.86282045 0.61831306 0.09164956 
+0.25609707 0.07445781 0.72185784 0.90058883 0.30070608 
+0.94476583 0.56822213 0.21933909 0.96772793 0.80063440 
+0.26307906 0.31183306 0.16501252 0.55436179 0.68562285 
+0.23829083 0.86511559 0.57868991 0.81888344 0.20126869 
+0.93172350 0.66028129 0.21786948 0.78515828 0.10262106 
+0.35390326 0.79303876 0.63427924 0.90479631 0.31024934 
+0.60635447 0.56198079 0.63573813 0.91854197 0.99701497 
+0.83085849 0.31692291 0.01925964 0.97446405 0.98751283 
+0.60944293 0.13751018 0.69519957 0.68956636 0.56969015 
+0.46440193 0.88341765 0.36754434 0.89223647 0.39786427 
+0.85055280 0.12749961 0.79452122 0.89449784 0.14567830 
+0.45716830 0.74822309 0.28200437 0.42546044 0.17464886 
+0.68308746 0.65496587 0.52935411 0.12736159 0.61523955 
+0.81590528 0.63107864 0.39786553 0.20102294 0.53292914 
+0.75485590 0.59847044 0.32861691 0.12125866 0.58917183 
+0.07638293 0.86845380 0.29192617 0.03989733 0.52180460 
+0.32503407 0.64071852 0.69516575 0.74254998 0.54587026 
+0.48713246 0.32920155 0.08719954 0.63497059 0.54328459 
+0.64178757 0.45583809 0.70694291 0.85212760 0.86074305 
+0.33163422 0.85739792 0.59908488 0.74566046 0.72157152 

+ 65 - 0
3rdparty/mt19937ar/mtTest.c

@@ -0,0 +1,65 @@
+/* 
+   A C-program for MT19937, with initialization improved 2002/1/26.
+   Coded by Takuji Nishimura and Makoto Matsumoto.
+
+   Before using, initialize the state by using init_genrand(seed)  
+   or init_by_array(init_key, key_length).
+
+   Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura,
+   All rights reserved.
+   Copyright (C) 2005, Mutsuo Saito,
+   All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+     1. Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+
+     2. Redistributions in binary form must reproduce the above copyright
+        notice, this list of conditions and the following disclaimer in the
+        documentation and/or other materials provided with the distribution.
+
+     3. The names of its contributors may not be used to endorse or promote 
+        products derived from this software without specific prior written 
+        permission.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+   Any feedback is very welcome.
+   http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html
+   email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space)
+*/
+
+#include <stdio.h>
+#include "mt19937ar.h"
+
+int main(void)
+{
+    int i;
+    unsigned long init[4]={0x123, 0x234, 0x345, 0x456}, length=4;
+    init_by_array(init, length);
+    printf("1000 outputs of genrand_int32()\n");
+    for (i=0; i<1000; i++) {
+      printf("%10lu ", genrand_int32());
+      if (i%5==4) printf("\n");
+    }
+    printf("\n1000 outputs of genrand_real2()\n");
+    for (i=0; i<1000; i++) {
+      printf("%10.8f ", genrand_real2());
+      if (i%5==4) printf("\n");
+    }
+    return 0;
+}

+ 79 - 0
3rdparty/mt19937ar/readme-mt.txt

@@ -0,0 +1,79 @@
+This is a Mersenne Twister pseudorandom number generator
+with period 2^19937-1 with improved initialization scheme,
+modified on 2002/1/26 by Takuji Nishimura and Makoto Matsumoto. 
+modified on 2005/4/26 by Mutsuo Saito
+
+Contents of this tar ball:
+readme-mt.txt	 this file
+mt19937ar.c	 the C source (ar: initialize by ARray)
+mt19937ar.h      the C header file for mt19937ar
+mtTest.c         the C test main program of mt19937ar.c
+mt19937ar.out	 Test outputs of six types generators. 1000 for each
+
+1. Initialization
+  The initialization scheme for the previous versions of MT
+(e.g. 1999/10/28 version or earlier) has a tiny problem, that
+the most significant bits of the seed is not well reflected 
+to the state vector of MT.
+
+This version (2002/1/26) has two initialization schemes:
+init_genrand(seed) and init_by_array(init_key, key_length).
+
+init_genrand(seed) initializes the state vector by using
+one unsigned 32-bit integer "seed", which may be zero.
+
+init_by_array(init_key, key_length) initializes the state vector 
+by using an array init_key[] of unsigned 32-bit integers
+of length key_kength. If key_length is smaller than 624,
+then each array of 32-bit integers gives distinct initial
+state vector. This is useful if you want a larger seed space
+than 32-bit word.
+
+2. Generation
+After initialization, the following type of pseudorandom numbers
+are available. 
+
+genrand_int32() generates unsigned 32-bit integers.
+genrand_int31() generates unsigned 31-bit integers.
+genrand_real1() generates uniform real in [0,1] (32-bit resolution). 
+genrand_real2() generates uniform real in [0,1) (32-bit resolution). 
+genrand_real3() generates uniform real in (0,1) (32-bit resolution).
+genrand_res53() generates uniform real in [0,1) with 53-bit resolution.
+
+Note: the last five functions call the first one. 
+if you need more speed for these five functions, you may
+suppress the function call by copying genrand_int32() and
+replacing the last return(), following to these five functions.
+
+3. main()
+main() is an example to initialize with an array of length 4,
+then 1000 outputs of unsigned 32-bit integers, 
+then 1000 outputs of real [0,1) numbers. 
+
+4. The outputs
+The output of the mt19937ar.c is in the file mt19937ar.out.
+If you revise or translate the code, check the output
+by using this file. 
+
+5. Cryptography
+This generator is not cryptoraphically secure. 
+You need to use a one-way (or hash) function to obtain 
+a secure random sequence.
+
+6. Correspondence
+See:
+URL http://www.math.keio.ac.jp/matumoto/emt.html
+email matumoto@math.keio.ac.jp, nisimura@sci.kj.yamagata-u.ac.jp
+
+7. Reference
+M. Matsumoto and T. Nishimura,
+"Mersenne Twister: A 623-Dimensionally Equidistributed Uniform  
+Pseudo-Random Number Generator",
+ACM Transactions on Modeling and Computer Simulation,
+Vol. 8, No. 1, January 1998, pp 3--30.
+
+-------
+Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura,
+All rights reserved.
+Copyright (C) 2005, Mutsuo Saito
+All rights reserved.

+ 69 - 0
3rdparty/mysql/CMakeLists.txt

@@ -0,0 +1,69 @@
+
+#
+# local copy
+#
+if( WIN32 )
+message( STATUS "Detecting local MYSQL" )
+find_path( MYSQL_LOCAL_INCLUDE_DIRS "mysql.h"
+	PATHS "${CMAKE_CURRENT_SOURCE_DIR}/include"
+	NO_DEFAULT_PATH )
+find_library( MYSQL_LOCAL_LIBRARIES
+	NAMES libmysql
+	PATHS "${CMAKE_CURRENT_SOURCE_DIR}/lib"
+	NO_DEFAULT_PATH )
+mark_as_advanced( MYSQL_LOCAL_LIBRARIES )
+mark_as_advanced( MYSQL_LOCAL_INCLUDE_DIRS )
+
+if( MYSQL_LOCAL_LIBRARIES AND MYSQL_LOCAL_INCLUDE_DIRS )
+	if( EXISTS "${MYSQL_LOCAL_INCLUDE_DIRS}/mysql_version.h" )
+		file( STRINGS "${MYSQL_LOCAL_INCLUDE_DIRS}/mysql_version.h" MYSQL_VERSION_H REGEX "^#define MYSQL_SERVER_VERSION[ \t]+\"[^\"]+\".*$" )
+		string( REGEX REPLACE "^.*MYSQL_SERVER_VERSION[ \t]+\"([^\"]+)\".*$" "\\1" MYSQL_SERVER_VERSION "${MYSQL_VERSION_H}" )
+		message( STATUS "Found MYSQL: ${MYSQL_LOCAL_LIBRARIES} (found version ${MYSQL_SERVER_VERSION})" )
+	else()
+		message( STATUS "Found MYSQL: ${MYSQL_LOCAL_LIBRARIES}" )
+	endif()
+	set( HAVE_LOCAL_MYSQL ON
+		CACHE BOOL "mysql client is available as a local copy")
+	mark_as_advanced( HAVE_LOCAL_MYSQL )
+else()
+	foreach( _VAR MYSQL_LOCAL_LIBRARIES MYSQL_LOCAL_INCLUDE_DIRS )
+		if( NOT "${_VAR}" )
+			set( MISSING_VARS ${MISSING_VARS} ${_VAR} )
+		endif()
+	endforeach()
+	message( STATUS "Could NOT find MYSQL (missing: ${MISSING_VARS})" )
+	unset( HAVE_LOCAL_MYSQL CACHE )
+endif()
+message( STATUS "Detecting local MYSQL - done" )
+endif( WIN32 )
+
+
+#
+# system
+#
+message( STATUS "Detecting system MYSQL" )
+unset( MYSQL_LIBRARIES CACHE )
+unset( MYSQL_INCLUDE_DIRS CACHE )
+set( CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_MODULE_PATH} )
+find_package( MYSQL )
+set( MYSQL_SYSTEM_LIBRARIES "${MYSQL_LIBRARIES}"
+	CACHE PATH "system mysql libraries" )
+set( MYSQL_SYSTEM_INCLUDE_DIRS "${MYSQL_INCLUDE_DIRS}"
+	CACHE PATH "system mysql include directories" )
+mark_as_advanced( MYSQL_SYSTEM_LIBRARIES )
+mark_as_advanced( MYSQL_SYSTEM_INCLUDE_DIRS )
+
+if( MYSQL_SYSTEM_LIBRARIES AND MYSQL_SYSTEM_INCLUDE_DIRS )
+	set( HAVE_SYSTEM_MYSQL ON
+		CACHE BOOL "mysql client is available on the system" )
+	mark_as_advanced( HAVE_SYSTEM_MYSQL )
+else()
+	unset( HAVE_SYSTEM_MYSQL CACHE )
+endif()
+message( STATUS "Detecting system MYSQL - done" )
+
+
+#
+# configure
+#
+CONFIGURE_WITH_LOCAL_OR_SYSTEM( MYSQL )

+ 35 - 0
3rdparty/mysql/FindMYSQL.cmake

@@ -0,0 +1,35 @@
+# - Find mysqlclient
+# Find the native MySQL includes and library
+#
+#  MYSQL_INCLUDE_DIRS - where to find mysql.h, etc.
+#  MYSQL_LIBRARIES   - mysqlclient library.
+#  MYSQL_FOUND       - True if mysqlclient is found.
+#
+
+find_path( MYSQL_INCLUDE_DIRS "mysql.h"
+	PATHS
+		"/usr/include/mysql"
+		"/usr/local/include/mysql"
+		"$ENV{PROGRAMFILES}/MySQL/*/include"
+		"$ENV{SYSTEMDRIVE}/MySQL/*/include" )
+
+find_library( MYSQL_LIBRARIES
+	NAMES "mysqlclient" "mysqlclient_r"
+	PATHS
+		"/usr/lib/mysql"
+		"/usr/local/lib/mysql"
+		"$ENV{PROGRAMFILES}/MySQL/*/lib"
+		"$ENV{SYSTEMDRIVE}/MySQL/*/lib" )
+mark_as_advanced( MYSQL_LIBRARIES  MYSQL_INCLUDE_DIRS )
+
+if( MYSQL_INCLUDE_DIRS AND EXISTS "${MYSQL_INCLUDE_DIRS}/mysql_version.h" )
+	file( STRINGS "${MYSQL_INCLUDE_DIRS}/mysql_version.h" MYSQL_VERSION_H REGEX "^#define[ \t]+MYSQL_SERVER_VERSION[ \t]+\"[^\"]+\".*$" )
+	string( REGEX REPLACE "^.*MYSQL_SERVER_VERSION[ \t]+\"([^\"]+)\".*$" "\\1" MYSQL_VERSION_STRING "${MYSQL_VERSION_H}" )
+endif()
+
+# handle the QUIETLY and REQUIRED arguments and set MYSQL_FOUND to TRUE if 
+# all listed variables are TRUE
+include( FindPackageHandleStandardArgs )
+FIND_PACKAGE_HANDLE_STANDARD_ARGS( MYSQL
+	REQUIRED_VARS MYSQL_LIBRARIES MYSQL_INCLUDE_DIRS
+	VERSION_VAR MYSQL_VERSION_STRING )

+ 66 - 0
3rdparty/pcre/CMakeLists.txt

@@ -0,0 +1,66 @@
+
+#
+# local copy
+#
+if( WIN32 )
+message( STATUS "Detecting local PCRE" )
+find_path( PCRE_LOCAL_INCLUDE_DIRS "pcre.h"
+	PATHS "${CMAKE_CURRENT_SOURCE_DIR}/include"
+	NO_DEFAULT_PATH )
+find_library( PCRE_LOCAL_LIBRARIES
+	NAMES pcre
+	PATHS "${CMAKE_CURRENT_SOURCE_DIR}/lib"
+	NO_DEFAULT_PATH )
+mark_as_advanced( PCRE_LOCAL_LIBRARIES )
+mark_as_advanced( PCRE_LOCAL_INCLUDE_DIRS )
+
+if( PCRE_LOCAL_LIBRARIES AND PCRE_LOCAL_INCLUDE_DIRS )
+	file( STRINGS "${PCRE_LOCAL_INCLUDE_DIRS}/pcre.h" PCRE_H REGEX "^#define[ \t]+PCRE_M[A-Z]+[ \t]+[0-9]+.*$" )
+	string( REGEX REPLACE "^.*PCRE_MAJOR[ \t]+([0-9]+).*$" "\\1" PCRE_MAJOR "${PCRE_H}" )
+	string( REGEX REPLACE "^.*PCRE_MINOR[ \t]+([0-9]+).*$" "\\1" PCRE_MINOR  "${PCRE_H}" )
+	message( STATUS "Found PCRE: ${PCRE_LOCAL_LIBRARIES} (found version ${PCRE_MAJOR}.${PCRE_MINOR})" )
+	set( HAVE_LOCAL_PCRE ON
+		CACHE BOOL "pcre is available as a local copy" )
+	mark_as_advanced( HAVE_LOCAL_PCRE )
+else()
+	foreach( _VAR PCRE_LOCAL_LIBRARIES PCRE_LOCAL_INCLUDE_DIRS )
+		if( NOT "${_VAR}" )
+			set( MISSING_VARS ${MISSING_VARS} ${_VAR} )
+		endif()
+	endforeach()
+	message( STATUS "Could NOT find PCRE (missing: ${MISSING_VARS})" )
+	unset( HAVE_LOCAL_PCRE CACHE )
+endif()
+message( STATUS "Detecting local PCRE - done" )
+endif( WIN32 )
+
+
+#
+# system
+#
+message( STATUS "Detecting system PCRE" )
+set( CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_MODULE_PATH} )
+unset( PCRE_LIBRARIES CACHE )
+unset( PCRE_INCLUDE_DIRS CACHE )
+find_package( PCRE )
+set( PCRE_SYSTEM_LIBRARIES ${PCRE_LIBRARIES}
+	CACHE PATH "system pcre libraries" )
+set( PCRE_SYSTEM_INCLUDE_DIRS ${PCRE_INCLUDE_DIRS}
+	CACHE PATH "system pcre include directories" )
+mark_as_advanced( PCRE_SYSTEM_LIBRARIES )
+mark_as_advanced( PCRE_SYSTEM_INCLUDE_DIRS )
+
+if( PCRE_SYSTEM_LIBRARIES AND PCRE_SYSTEM_INCLUDE_DIRS )
+	set( HAVE_SYSTEM_PCRE ON
+		CACHE BOOL "pcre is available on the system" )
+	mark_as_advanced( HAVE_SYSTEM_PCRE )
+else()
+	unset( HAVE_SYSTEM_PCRE CACHE )
+endif()
+message( STATUS "Detecting system PCRE - done" )
+
+
+#
+# configure
+#
+CONFIGURE_WITH_LOCAL_OR_SYSTEM( PCRE )

+ 35 - 0
3rdparty/pcre/FindPCRE.cmake

@@ -0,0 +1,35 @@
+# - Find pcre
+# Find the native PCRE includes and library
+#
+#  PCRE_INCLUDE_DIRS - where to find pcre.h
+#  PCRE_LIBRARIES    - List of libraries when using pcre.
+#  PCRE_FOUND        - True if pcre found.
+
+
+find_path( PCRE_INCLUDE_DIR pcre.h )
+
+set( PCRE_NAMES pcre )
+find_library( PCRE_LIBRARY NAMES ${PCRE_NAMES} )
+mark_as_advanced( PCRE_LIBRARY PCRE_INCLUDE_DIR )
+
+if( PCRE_INCLUDE_DIR AND EXISTS "${PCRE_INCLUDE_DIR}/pcre.h" )
+	file( STRINGS "${PCRE_INCLUDE_DIR}/pcre.h" PCRE_H REGEX "^#define[ \t]+PCRE_M[A-Z]+[ \t]+[0-9]+.*$" )
+	string( REGEX REPLACE "^.*PCRE_MAJOR[ \t]+([0-9]+).*$" "\\1" PCRE_MAJOR "${PCRE_H}" )
+	string( REGEX REPLACE "^.*PCRE_MINOR[ \t]+([0-9]+).*$" "\\1" PCRE_MINOR  "${PCRE_H}" )
+
+	set( PCRE_VERSION_STRING "${PCRE_MAJOR}.${PCRE_MINOR}" )
+	set( PCRE_VERSION_MAJOR "${PCRE_MAJOR}" )
+	set( PCRE_VERSION_MINOR "${PCRE_MINOR}" )
+endif()
+
+# handle the QUIETLY and REQUIRED arguments and set PCRE_FOUND to TRUE if 
+# all listed variables are TRUE
+include( FindPackageHandleStandardArgs )
+FIND_PACKAGE_HANDLE_STANDARD_ARGS( PCRE
+	REQUIRED_VARS PCRE_LIBRARY PCRE_INCLUDE_DIR
+	VERSION_VAR PCRE_VERSION_STRING )
+
+if( PCRE_FOUND )
+	set( PCRE_LIBRARIES ${PCRE_LIBRARY} )
+	set( PCRE_INCLUDE_DIRS ${PCRE_INCLUDE_DIR} )
+endif()

+ 64 - 0
3rdparty/zlib/CMakeLists.txt

@@ -0,0 +1,64 @@
+
+#
+# local copy
+#
+if( WIN32 )
+message( STATUS "Detecting local ZLIB" )
+find_path( ZLIB_LOCAL_INCLUDE_DIRS "zlib.h"
+	PATHS "${CMAKE_CURRENT_SOURCE_DIR}/include"
+	NO_DEFAULT_PATH )
+find_library( ZLIB_LOCAL_LIBRARIES
+	NAMES zdll
+	PATHS "${CMAKE_CURRENT_SOURCE_DIR}/lib"
+	NO_DEFAULT_PATH )
+mark_as_advanced( ZLIB_LOCAL_LIBRARIES )
+mark_as_advanced( ZLIB_LOCAL_INCLUDE_DIRS )
+
+if( ZLIB_LOCAL_LIBRARIES AND ZLIB_LOCAL_INCLUDE_DIRS )
+	file( STRINGS "${ZLIB_LOCAL_INCLUDE_DIRS}/zlib.h" ZLIB_H REGEX "^#define[ \t]+ZLIB_VERSION[ \t]+\"[^\"]+\".*$" )
+	string( REGEX REPLACE "^.*ZLIB_VERSION[ \t]+\"([^\"]+)\".*$" "\\1" ZLIB_VERSION "${ZLIB_H}" )
+	message( STATUS "Found local ZLIB: ${ZLIB_LOCAL_LIBRARIES} (found version ${ZLIB_VERSION})" )
+	set( HAVE_LOCAL_ZLIB ON
+		CACHE BOOL "zlib is available as a local copy" )
+	mark_as_advanced( HAVE_LOCAL_ZLIB )
+else()
+	foreach( _VAR ZLIB_LOCAL_LIBRARIES ZLIB_LOCAL_INCLUDE_DIRS )
+		if( NOT "${_VAR}" )
+			set( MISSING_VARS ${MISSING_VARS} ${_VAR} )
+		endif()
+	endforeach()
+	message( STATUS "Could NOT find local ZLIB (missing: ${MISSING_VARS})" )
+	unset( HAVE_LOCAL_ZLIB CACHE )
+endif()
+message( STATUS "Detecting local ZLIB - done" )
+endif( WIN32 )
+
+
+#
+# system
+#
+message( STATUS "Detecting system ZLIB" )
+unset( ZLIB_LIBRARIES CACHE )
+unset( ZLIB_INCLUDE_DIRS CACHE )
+find_package( ZLIB )
+set( ZLIB_SYSTEM_LIBRARIES ${ZLIB_LIBRARIES}
+	CACHE PATH "system zlib libraries" )
+set( ZLIB_SYSTEM_INCLUDE_DIRS ${ZLIB_INCLUDE_DIRS}
+	CACHE PATH "system zlib include directories" )
+mark_as_advanced( ZLIB_SYSTEM_LIBRARIES )
+mark_as_advanced( ZLIB_SYSTEM_INCLUDE_DIRS )
+
+if( ZLIB_SYSTEM_LIBRARIES AND ZLIB_SYSTEM_INCLUDE_DIRS )
+	set( HAVE_SYSTEM_ZLIB ON
+		CACHE BOOL "zlib is available on the system" )
+	mark_as_advanced( HAVE_SYSTEM_ZLIB )
+else()
+	unset( HAVE_SYSTEM_ZLIB CACHE )
+endif()
+message( STATUS "Detecting system ZLIB - done" )
+
+
+#
+# configure
+#
+CONFIGURE_WITH_LOCAL_OR_SYSTEM( ZLIB )

+ 265 - 0
CMakeLists.txt

@@ -0,0 +1,265 @@
+# "Getting Started with CMake", a tutorial video by Eric Wing.
+#   Part 1 of 6: http://www.youtube.com/watch?v=CLvZTyji_Uw
+#   Part 2 of 6: http://www.youtube.com/watch?v=gUW-RrRQjEg
+#   Part 3 of 6: http://www.youtube.com/watch?v=sz6cPhbuTk4
+#   Part 4 of 6: http://www.youtube.com/watch?v=JICZOkyNXbg
+#   Part 5 of 6: http://www.youtube.com/watch?v=lAiuLHy4dCk
+#   Part 6 of 6: http://www.youtube.com/watch?v=fAtJNzDZdH8
+#
+# You can use notepad++ for syntax highlighting.
+# Naming conventions:
+#   WITH_*   : option to use an external package or not
+#   ENABLE_* : option to use an internal feature/code or not
+#   HAVE_*   : internal variable indicating if we have and are using something
+cmake_minimum_required( VERSION 2.8.4 )
+project( eAthena )
+
+
+#
+# Prevent building in the source directory by default
+#
+if( ALLOW_SAME_DIRECTORY )
+elseif( "${CMAKE_CURRENT_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_BINARY_DIR}" )
+	option( ALLOW_SAME_DIRECTORY "Allow CMake to build in the source directory." OFF )
+	message( FATAL_ERROR "Do not use the source directory to build your files, instead create a separate folder and build there.\nExample:\n  mkdir build\n  cd build\n  cmake -G\"Unix Makefiles\" ..\n  make install\nTo skip this check, set ALLOW_SAME_DIRECTORY to 1 or ON" )
+endif()
+
+
+#
+# Global stuff
+#
+set( GLOBAL_LIBRARIES CACHE INTERNAL "" )
+set( GLOBAL_INCLUDE_DIRS CACHE INTERNAL "" )
+set( GLOBAL_DEFINITIONS CACHE INTERNAL "" )
+mark_as_advanced( GLOBAL_LIBRARIES  GLOBAL_INCLUDE_DIRS  GLOBAL_DEFINITIONS )
+if( WIN32 )
+	list( APPEND GLOBAL_DEFINITIONS  FD_SETSIZE=4096 )
+	list( APPEND GLOBAL_LIBRARIES  "oldnames.lib" "ws2_32.lib" )
+endif()
+if( MSVC )
+	list( APPEND GLOBAL_DEFINITIONS  _CRT_SECURE_NO_DEPRECATE _CRT_NONSTDC_NO_DEPRECATE DB_MANUAL_CAST_TO_UNION )
+endif()
+
+
+#
+# Find svnversion
+#
+message( STATUS "Detecting svnversion" )
+find_program( SVNVERSION_EXECUTABLE svnversion )
+mark_as_advanced( SVNVERSION_EXECUTABLE )
+if( SVNVERSION_EXECUTABLE )
+	message( STATUS "Found svnversion: ${SVNVERSION_EXECUTABLE}" )
+endif()
+message( STATUS "Detecting svnversion - done" )
+
+
+#
+# Find Subversion
+#
+message( STATUS "Detecting Subversion" )
+find_package( Subversion )
+message( STATUS "Detecting Subversion - done" )
+
+
+#
+# Find math library (FreeBSD)
+#
+message( STATUS "Detecting math library" )
+find_library( M_LIBRARIES m )
+mark_as_advanced( M_LIBRARIES )
+if( M_LIBRARIES )
+	message( STATUS "Found m: ${M_LIBRARIES}" )
+	list( APPEND GLOBAL_LIBRARIES ${M_LIBRARIES} )
+endif()
+message( STATUS "Detecting math library - done" )
+
+
+#
+# PACKETVER
+#
+set( PACKETVER CACHE STRING "Sets the PACKETVER define of the servers. (see src/common/mmo.h)" )
+if( PACKETVER )
+	list( APPEND GLOBAL_DEFINITIONS  PACKETVER=${PACKETVER} )
+endif()
+
+
+#
+# SVNVERSION
+#
+if( SVNVERSION_EXECUTABLE )
+	execute_process( COMMAND ${SVNVERSION_EXECUTABLE} ${PROJECT_SOURCE_DIR}
+		OUTPUT_VARIABLE SVNVERSION
+		OUTPUT_STRIP_TRAILING_WHITESPACE )
+	string( REGEX REPLACE "[^1234567890MSexported]" "_" SVNVERSION ${SVNVERSION} )
+endif()
+if( Subversion_FOUND AND SVNVERSION )
+	Subversion_WC_INFO( ${PROJECT_SOURCE_DIR} eAthena )
+	if( eAthena_WC_URL )
+		string( REGEX MATCH "[^/]+$" BRANCH ${eAthena_WC_URL} )
+		set( SVNVERSION "${BRANCH}-${SVNVERSION}" )
+	endif()
+endif()
+
+
+#####################################################################
+# package stuff
+#
+set( CPACK_PACKAGE_NAME "eAthena" )
+set( CPACK_PACKAGE_DESCRIPTION_SUMMARY "MMORPG server package" )
+set( CPACK_PACKAGE_VERSION ${SVNVERSION} )
+set( CPACK_RESOURCE_FILE_LICENSE ${CMAKE_CURRENT_SOURCE_DIR}/LICENSE )
+#set( CPACK_MONOLITHIC_INSTALL ON )
+include( CPACK  OPTIONAL  RESULT_VARIABLE HAVE_CPACK )
+if( NOT HAVE_CPACK )
+	# empty replacements
+	macro( cpack_add_component_group )
+	endmacro()
+	macro( cpack_add_component )
+	endmacro()
+	message( STATUS "CPACK not found, package creation disabled" )
+endif()
+
+set( Runtime "Runtime files"  CACHE INTERNAL "" )
+set( Runtime_base "configurations, dbs, npcs, docs, ..."  CACHE INTERNAL "" )
+set( Runtime_templates "conf/import and save (generated from conf/import-tmpl and save-tmpl)"  CACHE INTERNAL "" )
+cpack_add_component_group( Runtime DESCRIPTION ${Runtime} DISPLAY_NAME "Runtime" )
+cpack_add_component( Runtime_base DESCRIPTION ${Runtime_base} DISPLAY_NAME "Base files" GROUP Runtime )
+cpack_add_component( Runtime_templates DESCRIPTION ${Runtime_templates} DISPLAY_NAME "Base templates" GROUP Runtime )
+
+set( Development "Development files"  CACHE INTERNAL "" )
+set( Development_base "projects, 3rdparty, sources, templates"  CACHE INTERNAL "" )
+cpack_add_component_group( Development DESCRIPTION ${Development} DISPLAY_NAME "Development" )
+cpack_add_component( Development_base DESCRIPTION ${Development_base} DISPLAY_NAME "Base files" GROUP Development )
+
+
+#
+# install stuff
+#
+option( WITH_COMPONENT_RUNTIME "install/package files needed to run the project" ON )
+option( WITH_COMPONENT_DEVELOPMENT "install/package files needed to build the project" OFF )
+option( INSTALL_TO_PATH "copy files to INSTALL_PATH" OFF )
+option( INSTALL_TO_SOURCE "copy files to source directory, skips what is already there (${CMAKE_CURRENT_SOURCE_DIR})" OFF )
+option( INSTALL_TO_SUBDIR "copy files to subdirectory (${CMAKE_CURRENT_BINARY_DIR}/install)" OFF )
+set( INSTALL_PATH "${CMAKE_INSTALL_PREFIX}"  CACHE STRING "install path (only used when INSTALL_TO_PATH is set)" )
+mark_as_advanced( CMAKE_INSTALL_PREFIX )
+if( INSTALL_TO_PATH AND NOT ("${INSTALL_TO}" STREQUAL "path") )# changed to path
+	set_property( CACHE INSTALL_TO_SOURCE INSTALL_TO_SUBDIR  PROPERTY VALUE OFF )
+elseif( INSTALL_TO_SOURCE AND NOT ("${INSTALL_TO}" STREQUAL "source") )# changed to source
+	set_property( CACHE INSTALL_TO_PATH INSTALL_TO_SUBDIR  PROPERTY VALUE OFF )
+elseif( INSTALL_TO_SUBDIR AND NOT ("${INSTALL_TO}" STREQUAL "subdir") )# changed to subdir
+	set_property( CACHE INSTALL_TO_PATH INSTALL_TO_SOURCE  PROPERTY VALUE OFF )
+elseif( NOT INSTALL_TO_PATH AND NOT INSTALL_TO_SOURCE AND NOT INSTALL_TO_SUBDIR )# default
+	set_property( CACHE INSTALL_TO_SUBDIR  PROPERTY VALUE ON )
+endif()
+if( INSTALL_TO_PATH )
+	set( INSTALL_TO "path"  CACHE INTERNAL "" )
+	set_property( CACHE CMAKE_INSTALL_PREFIX  PROPERTY VALUE "${INSTALL_PATH}" )
+elseif( INSTALL_TO_SOURCE )
+	set( INSTALL_TO "source"  CACHE INTERNAL "" )
+	set_property( CACHE CMAKE_INSTALL_PREFIX  PROPERTY VALUE "${CMAKE_CURRENT_SOURCE_DIR}" )
+elseif( INSTALL_TO_SUBDIR )
+	set( INSTALL_TO "subdir"  CACHE INTERNAL "" )
+	set_property( CACHE CMAKE_INSTALL_PREFIX  PROPERTY VALUE "${CMAKE_CURRENT_BINARY_DIR}/install" )
+endif()
+set( SVN_FOLDER_PATTERN "[\\.]svn"  CACHE STRING "pattern of svn folder that we exclude from instalations" )
+mark_as_advanced( SVN_FOLDER_PATTERN )
+set( DEVELOPMENT_FILES
+	"${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt"
+	"${CMAKE_CURRENT_SOURCE_DIR}/configure"
+	"${CMAKE_CURRENT_SOURCE_DIR}/configure.in"
+	"${CMAKE_CURRENT_SOURCE_DIR}/eAthena-6.dsw"
+	"${CMAKE_CURRENT_SOURCE_DIR}/eAthena-7.1.sln"
+	"${CMAKE_CURRENT_SOURCE_DIR}/eAthena-8.sln"
+	"${CMAKE_CURRENT_SOURCE_DIR}/eAthena-9.sln"
+	"${CMAKE_CURRENT_SOURCE_DIR}/eAthena-10.sln"
+	)
+set( DEVELOPMENT_DIRECTORIES
+	"3rdparty"
+	"conf/import-tmpl"
+	"save-tmpl"
+	"src"
+	"vcproj-6"
+	"vcproj-7.1"
+	"vcproj-8"
+	"vcproj-9"
+	"vcproj-10"
+	)
+set( RUNTIME_FILES
+	"${CMAKE_CURRENT_SOURCE_DIR}/athena-start"
+	"${CMAKE_CURRENT_SOURCE_DIR}/Changelog-Trunk.txt"
+	"${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"
+	)
+set( RUNTIME_DIRECTORIES
+	"conf"
+	"db"
+	"doc"
+	"log"
+	"npc"
+	"plugins"
+	"readme"
+	"sql-files"
+	"tools"
+	)
+if( INSTALL_TO_SOURCE )# skip, already in the source dir
+else()
+	if( WITH_COMPONENT_RUNTIME )
+		install( FILES ${RUNTIME_FILES}
+			DESTINATION "."
+			COMPONENT Runtime_base )
+		foreach( DIR IN ITEMS ${RUNTIME_DIRECTORIES} )
+			install( DIRECTORY "${DIR}/"
+				DESTINATION "${DIR}"
+				COMPONENT Runtime_base
+				PATTERN ${SVN_FOLDER_PATTERN} EXCLUDE
+				PATTERN "conf/import-tmpl" EXCLUDE )
+		endforeach()
+	endif()
+	if( WITH_COMPONENT_DEVELOPMENT )
+		install( FILES ${DEVELOPMENT_FILES}
+			DESTINATION "."
+			COMPONENT Development_base )
+		foreach( DIR IN ITEMS ${DEVELOPMENT_DIRECTORIES} )
+			install( DIRECTORY "${DIR}/"
+				DESTINATION "${DIR}"
+				COMPONENT Development_base
+				PATTERN ${SVN_FOLDER_PATTERN} EXCLUDE )
+		endforeach()
+	endif()
+endif()
+if( WITH_COMPONENT_RUNTIME )
+	# templates
+	install( DIRECTORY "save-tmpl/"
+		DESTINATION "save"
+		COMPONENT Runtime_templates
+		PATTERN ${SVN_FOLDER_PATTERN} EXCLUDE )
+	install( DIRECTORY "conf/import-tmpl/"
+		DESTINATION "conf/import"
+		COMPONENT Runtime_templates
+		PATTERN ${SVN_FOLDER_PATTERN} EXCLUDE )
+endif()
+
+
+#
+# subdirectories
+#
+add_subdirectory( 3rdparty )
+add_subdirectory( src )

+ 2 - 0
Changelog-Renewal.txt

@@ -1,5 +1,7 @@
 Date	Added
 
+2011/07/10
+	* Merged changes from trunk [14827:14894/trunk]. [Ai4rei]
 2011/06/13
 	* Fixed 3rd classes not being able to level up after Base Level reset. [Gepard]
 2011/05/15

+ 21 - 11
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)"

+ 2 - 0
conf/Changelog.txt

@@ -1,5 +1,7 @@
 Date	Added
 
+2011/07/09
+	* Rev. 14892 Removed 'msg_athena.conf' messages 619 and 620 (duplicates to 572 and 573) (since r5506). [Ai4rei]
 2011/05/13
 	* Rev. 14812 Added settings 'cashshop_show_points' and 'mail_show_status', both disabled by default, as the messages they control are custom (follow up to r11548 and r12264). [Ai4rei]
 	- Moved custom cash point update messages to 'msg_athena.conf' (IDs 504~506).

+ 2 - 2
conf/msg_athena.conf

@@ -529,8 +529,8 @@
 616: Taekwon
 617: Star Gladiator
 618: Soul Linker
-619: Gunslinger
-620: Ninja
+//619: FREE
+//620: FREE
 621: Summer
 //...
 625: Rune Knight

+ 3 - 1
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"

+ 1 - 0
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])

+ 1 - 1
db/packet_db.txt

@@ -1438,7 +1438,7 @@ packet_ver: 25
 0x07fa,8
 
 //2009-11-24aRagexeRE
-//0x07fb,25
+0x07fb,25
 
 //2009-12-01aRagexeRE
 //0x07fc,10

+ 1 - 1
doc/ea_job_system.txt

@@ -102,7 +102,7 @@ EAJL_UPPER:
 
 EAJL_BABY:
 	Check if a class is an adopted class.
-	if (@job&EAJ_BABY)
+	if (@job&EAJL_BABY)
 		mes "Don't you hate being weak?";
 
 EAJ_UPPERMASK:

+ 39 - 4
doc/script_commands.txt

@@ -4,7 +4,7 @@
 //= A reference manual for the eAthena scripting language.
 //= Commands are sorted depending on their functionality.
 //===== Version ===========================================
-//= 3.42.20110508
+//= 3.45.20110709
 //=========================================================
 //= 1.0 - First release, filled will as much info as I could
 //=       remember or figure out, most likely there are errors,
@@ -174,6 +174,13 @@
 //= 3.42.20110508
 //=       Updated description of all instance commands to reflect actual behavior.
 //=       [Ai4rei]
+//= 3.43.20110529
+//=       Updated 'npcshopitem', 'npcshopadditem' and 'npcshopdelitem' to support
+//=       cashshops as well. [Ai4rei]
+//= 3.44.20110530
+//=       Documented special map names recognized by 'warpguild'. [Ai4rei]
+//= 3.45.20110709
+//=       Added 'getmercinfo' command. [Ai4rei]
 //=========================================================
 
 This document is a reference manual for all the scripting commands and functions 
@@ -3689,6 +3696,13 @@ warpchar "prontera",150,100,20000001;
 Warps a guild to specified map and coordinate given the guild id, which you can get with 
 getcharid(2). You can also request another guild id given the member's name with getcharid(2,<player_name>).
  
+You can use the following "map names" for special warping behavior:
+Random:       All party members are randomly warped in their current map (as if they
+              all used a fly wing)
+SavePointAll: All party members are warped to their respective save point.
+SavePoint:    All party members are warped to the save point of the currently
+              attached player (will fail if there's no player attached).
+
 Example:
  
 warpguild "prontera",x,y,Guild_ID;
@@ -5660,7 +5674,7 @@ npcshopitem was used. After rechecking the source, I found what caused this.
 
 *npcshopitem "<name>",<item id>,<price>{,<item id>,<price>{,<item id>,<price>{,...}}}
 
-This command lets you override the contents of an existing NPC shop. The
+This command lets you override the contents of an existing NPC shop or cashshop. The
 current sell list will be wiped, and only the items specified with the price
 specified will be for sale.
 
@@ -5673,7 +5687,7 @@ Note that you cannot use -1 to specify default selling price!
 *npcshopadditem "<name>",<item id>,<price>{,<item id>,<price>{,<item id>,<price>{,...}}}
 
 This command will add more items at the end of the selling list for the
-specified NPC shop. If you specify an item already for sell, that item will
+specified NPC shop or cashshop. If you specify an item already for sell, that item will
 appear twice on the sell list.
 
 The function returns 1 if shop was updated successfully, or 0 if not found.
@@ -5684,7 +5698,7 @@ Note that you cannot use -1 to specify default selling price!
 
 *npcshopdelitem "<name>",<item id>{,<item id>{,<item id>{,...}}}
 
-This command will remove items from the specified NPC shop.
+This command will remove items from the specified NPC shop or cashshop.
 If the item to remove exists more than once on the shop, all instances will be
 removed.
 
@@ -7160,5 +7174,26 @@ attached character. Guild can be one or the following constants:
 
 ---------------------------------------
 
+*getmercinfo(<type>{,<char id>});
+
+Retrieves information about mercenary of the currently attached
+character. If char id is given, the information of that character is
+retrieved instead. Type specifies what information to retrieve and
+can be one of the following:
+
+    0 - Database ID
+    1 - Class
+    2 - Name
+    3 - Faith value for this mercenary's guild, if any
+    4 - Calls value for this mercenary's guild, if any
+    5 - Kill count
+    6 - Remaining life time in msec
+    7 - Level
+
+If the character does not have a mercenary, the command returns ""
+for name and 0 for all other types.
+
+----------------------------------------
+
 Whew.
 That's about all of them.

+ 42 - 6
eAthena-6.dsw

@@ -3,7 +3,19 @@ Microsoft Developer Studio Workspace File, Format Version 6.00
 
 ###############################################################################
 
-Project: "login_txt"=".\vcproj-6\login-server_txt.dsp" - Package Owner=<4>
+Project: "char_sql"=".\vcproj-6\char-server_sql.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "char_txt"=".\vcproj-6\char-server_txt.dsp" - Package Owner=<4>
 
 Package=<5>
 {{{
@@ -27,7 +39,7 @@ Package=<4>
 
 ###############################################################################
 
-Project: "char_txt"=".\vcproj-6\char-server_txt.dsp" - Package Owner=<4>
+Project: "login_txt"=".\vcproj-6\login-server_txt.dsp" - Package Owner=<4>
 
 Package=<5>
 {{{
@@ -39,7 +51,7 @@ Package=<4>
 
 ###############################################################################
 
-Project: "char_sql"=".\vcproj-6\char-server_sql.dsp" - Package Owner=<4>
+Project: "map_sql"=".\vcproj-6\map-server_sql.dsp" - Package Owner=<4>
 
 Package=<5>
 {{{
@@ -63,7 +75,31 @@ Package=<4>
 
 ###############################################################################
 
-Project: "map_sql"=".\vcproj-6\map-server_sql.dsp" - Package Owner=<4>
+Project: "mapcache"=".\vcproj-6\mapcache.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "plugin_console"=".\vcproj-6\plugin-console.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "plugin_pid"=".\vcproj-6\plugin-pid.dsp" - Package Owner=<4>
 
 Package=<5>
 {{{
@@ -75,7 +111,7 @@ Package=<4>
 
 ###############################################################################
 
-Project: "console"=".\vcproj-6\plugin-console.dsp" - Package Owner=<4>
+Project: "txt_converter_char"=".\vcproj-6\txt-converter-char.dsp" - Package Owner=<4>
 
 Package=<5>
 {{{
@@ -87,7 +123,7 @@ Package=<4>
 
 ###############################################################################
 
-Project: "pid"=".\vcproj-6\plugin-pid.dsp" - Package Owner=<4>
+Project: "txt_converter_login"=".\vcproj-6\txt-converter-login.dsp" - Package Owner=<4>
 
 Package=<5>
 {{{

+ 5 - 5
npc/quests/quests_lighthalzen.txt

@@ -3807,7 +3807,7 @@ OnTouch_:
 			soundeffect "tao_gunka_stand.wav",0;
 			sc_end SC_Blind;
 			sc_start SC_Curse,3000,0;
-			if (!lhz_curse == 6) set lhz_curse,7;
+			if (lhz_curse == 6) set lhz_curse,7;
 		}
 	}
 	end;
@@ -3887,7 +3887,7 @@ OnTouch_:
 			mes "............";
 			next;
 			mes "............";
-			close;
+			close2;
 			soundeffect "tao_gunka_stand.wav",0;
 			sc_end SC_Blind;
 			sc_start SC_Curse,3000,0;
@@ -4191,7 +4191,7 @@ lhz_in01,282,166,0	script	#kiz10	-1,3,3,{
 OnTouch_:
 	if (countitem(7345) > 0) {
 		if (lhz_curse == 16) {
-			if (checkweight(1201,1) == 1) {
+			if (checkweight(1201,1) == 0) {
 				mes "^3355FFThere's something on";
 				mes "the floor, but you can't";
 				mes "really take a good look at";
@@ -5283,7 +5283,7 @@ OnTouch_:
 		else if ((BaseLevel > 89) && (BaseLevel < 151))
 			getexp 200000,100000;
 	}
-	end;
+	close;
 }
 
 lhz_in01,114,181,5	script	Representative#li_01	71,{
@@ -6220,7 +6220,7 @@ lhz_in01,286,226,3	script	Secretary Slierre#li	831,{
 	else if (lhz_curse == 30) {
 		set .@li_keka,rand(1,10);
 		if (.@li_keka > 7) {
-			if (checkweight(1201,1) == 1) {
+			if (checkweight(1201,1) == 0) {
 				mes "[Sueii Slierre]";
 				mes "Oh, I'd like to have";
 				mes "a word with you. Would";

+ 9 - 0
src/CMakeLists.txt

@@ -0,0 +1,9 @@
+
+add_subdirectory( common )
+add_subdirectory( login )
+add_subdirectory( char )
+add_subdirectory( char_sql )
+add_subdirectory( map )
+add_subdirectory( tool )
+#add_subdirectory( txt-converter )
+#add_subdirectory( plugins )

+ 51 - 0
src/char/CMakeLists.txt

@@ -0,0 +1,51 @@
+
+#
+# char txt
+#
+if( HAVE_common_base )
+message( STATUS "Creating target char-server" )
+set( TXT_CHAR_HEADERS
+	"${CMAKE_CURRENT_SOURCE_DIR}/char.h"
+	"${CMAKE_CURRENT_SOURCE_DIR}/int_guild.h"
+	"${CMAKE_CURRENT_SOURCE_DIR}/int_homun.h"
+	"${CMAKE_CURRENT_SOURCE_DIR}/int_party.h"
+	"${CMAKE_CURRENT_SOURCE_DIR}/int_pet.h"
+	"${CMAKE_CURRENT_SOURCE_DIR}/int_status.h"
+	"${CMAKE_CURRENT_SOURCE_DIR}/int_storage.h"
+	"${CMAKE_CURRENT_SOURCE_DIR}/inter.h"
+	)
+set( TXT_CHAR_SOURCES
+	"${CMAKE_CURRENT_SOURCE_DIR}/char.c"
+	"${CMAKE_CURRENT_SOURCE_DIR}/int_guild.c"
+	"${CMAKE_CURRENT_SOURCE_DIR}/int_homun.c"
+	"${CMAKE_CURRENT_SOURCE_DIR}/int_party.c"
+	"${CMAKE_CURRENT_SOURCE_DIR}/int_pet.c"
+	"${CMAKE_CURRENT_SOURCE_DIR}/int_status.c"
+	"${CMAKE_CURRENT_SOURCE_DIR}/int_storage.c"
+	"${CMAKE_CURRENT_SOURCE_DIR}/inter.c"
+	)
+set( DEPENDENCIES common_base )
+set( LIBRARIES ${GLOBAL_LIBRARIES} )
+set( INCLUDE_DIRS ${GLOBAL_INCLUDE_DIRS} )
+set( DEFINITIONS ${GLOBAL_DEFINITIONS} TXT_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} )
+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_DEFINITIONS "${DEFINITIONS}" )
+if( WITH_COMPONENT_RUNTIME )
+	cpack_add_component( Runtime_charserver_txt DESCRIPTION "char-server (txt version)" DISPLAY_NAME "char-server" GROUP Runtime )
+	install( TARGETS char-server
+		DESTINATION "."
+		COMPONENT Runtime_charserver_txt )
+endif()
+message( STATUS "Creating target char-server - done" )
+set( HAVE_char-server ON  CACHE BOOL "char-server target is available" )
+mark_as_advanced( HAVE_char-server )
+else()
+message( STATUS "Skipping target char-server (requires common_base)" )
+unset( HAVE_char-server CACHE )
+endif()

+ 14 - 7
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

+ 283 - 114
src/char/char.c

@@ -176,7 +176,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 data);
+static int chardb_waiting_disconnect(int tid, unsigned int tick, int id, intptr_t data);
 
 static void* create_online_char_data(DBKey key, va_list args)
 {
@@ -571,8 +571,8 @@ int mmo_char_tostr(char *str, struct mmo_charstatus *p, struct global_reg *reg,
 	*(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);
+		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);
 		}
 	*(str_p++) = '\t';
 
@@ -1229,7 +1229,7 @@ void mmo_char_sync(void)
 //----------------------------------------------------
 // Function to save (in a periodic way) datas in files
 //----------------------------------------------------
-int mmo_char_sync_timer(int tid, unsigned int tick, int id, intptr data)
+int mmo_char_sync_timer(int tid, unsigned int tick, int id, intptr_t data)
 {
 	if (save_log)
 		ShowInfo("Saving all files...\n");
@@ -1782,7 +1782,7 @@ int count_users(void)
 	int i, users;
 
 	users = 0;
-	for(i = 0; i < MAX_MAP_SERVERS; i++) {
+	for(i = 0; i < ARRAYLENGTH(server); i++) {
 		if (server[i].fd > 0) {
 			users += server[i].users;
 		}
@@ -2060,24 +2060,74 @@ static void char_auth_ok(int fd, struct char_session_data *sd)
 	// continues when account data is received...
 }
 
-int send_accounts_tologin(int tid, unsigned int tick, int id, intptr data);
+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.
+/// 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;
-	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.
+	// only process data from the login-server
 	if( fd != login_fd )
-		set_eof(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) {
-		if (fd == login_fd) {
-			ShowWarning("Connection to login-server lost (connection #%d).\n", fd);
-			login_fd = -1;
-		}
+	if( session[fd]->flag.eof )
+	{
 		do_close(fd);
+		login_fd = -1;
+		loginif_on_disconnect();
 		return 0;
 	}
 
@@ -2101,16 +2151,11 @@ int parse_fromlogin(int fd)
 				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("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);
-				
-				//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, MAX_MAP_SERVERS, i, server[i].fd > 0 && server[i].map[0] );
-				if( i == MAX_MAP_SERVERS )
-					ShowStatus("Awaiting maps from map-server.\n");
+				loginif_on_ready();
 			}
 			RFIFOSKIP(fd,3);
 		break;
@@ -2226,7 +2271,7 @@ int parse_fromlogin(int fd)
 						}
 						// 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[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;
@@ -2234,7 +2279,7 @@ int parse_fromlogin(int fd)
 						}
 						// 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[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;
@@ -2377,6 +2422,34 @@ int parse_fromlogin(int 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) {
@@ -2592,36 +2665,76 @@ int char_loadName(int char_id, char* name)
 
 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));
+	}
+	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);
+}
+
+
+/// 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, 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));
-			}
-			memset(&server[id], 0, sizeof(struct mmo_map_server));
-			server[id].fd = -1;
-			online_char_db->foreach(online_char_db,char_db_setoffline,id); //Tag relevant chars as 'in disconnected' server.
-		}
+	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);
-		create_online_files();
+		return 0;
+	}
+	if( session[fd]->flag.eof )
+	{
+		do_close(fd);
+		server[id].fd = -1;
+		mapif_on_disconnect(id);
 		return 0;
 	}
 
@@ -2672,14 +2785,14 @@ int parse_frommap(int fd)
 				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++) {
+			for(x = 0; x < ARRAYLENGTH(server); x++) {
 				if (server[x].fd > 0 && x != id) {
-					WFIFOHEAD(fd,10 +4*MAX_MAP_PER_SERVER);
+					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 < MAX_MAP_PER_SERVER; i++)
+					for(i = 0; i < ARRAYLENGTH(server); i++)
 						if (server[x].map[i])
 							WFIFOW(fd,10+(j++)*4) = server[x].map[i];
 					if (j > 0) {
@@ -2802,26 +2915,37 @@ int parse_frommap(int fd)
 			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)
-			//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) = 0;
-			WFIFOSET(fd,7);
+			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;
 
@@ -2839,7 +2963,9 @@ int parse_frommap(int fd)
 
 			char_data = search_character(RFIFOL(fd,2), RFIFOL(fd,14));
 
-			if (map_fd >= 0 && session[map_fd] && char_data) 
+			if( runflag == CHARSERVER_ST_RUNNING &&
+				session_isActive(map_fd) &&
+				char_data )
 			{	//Send the map server the auth of this player.
 				struct auth_node* node;
 
@@ -3140,7 +3266,9 @@ int parse_frommap(int fd)
 
 			node = (struct auth_node*)idb_get(auth_db, account_id);
 			cd = search_character(account_id, char_id);
-			if( node != NULL && cd != NULL &&
+			if( runflag == CHARSERVER_ST_RUNNING &&
+				cd != NULL &&
+				node != NULL &&
 				node->account_id == account_id &&
 				node->char_id == char_id &&
 				node->login_id1 == login_id1 &&
@@ -3204,13 +3332,27 @@ int parse_frommap(int fd)
 	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 < MAX_MAP_SERVERS; i++)
+	for(i = 0; i < ARRAYLENGTH(server); i++)
 	{
 		if (server[i].fd > 0
 		&& (ip == (uint32)-1 || server[i].ip == ip)
@@ -3526,6 +3668,15 @@ int parse_char(int fd)
 			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 &&
@@ -3602,8 +3753,8 @@ int parse_char(int fd)
 			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) {
+				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;
@@ -3927,8 +4078,12 @@ int parse_char(int fd)
 			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)) {
+			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;
@@ -3991,7 +4146,7 @@ int mapif_sendall(unsigned char *buf, unsigned int len)
 	int i, c;
 
 	c = 0;
-	for(i = 0; i < MAX_MAP_SERVERS; i++) {
+	for(i = 0; i < ARRAYLENGTH(server); i++) {
 		int fd;
 		if ((fd = server[i].fd) > 0) {
 			WFIFOHEAD(fd,len);
@@ -4009,7 +4164,7 @@ int mapif_sendallwos(int sfd, unsigned char *buf, unsigned int len)
 	int i, c;
 
 	c = 0;
-	for(i = 0; i < MAX_MAP_SERVERS; i++) {
+	for(i = 0; i < ARRAYLENGTH(server); i++) {
 		int fd;
 		if ((fd = server[i].fd) > 0 && fd != sfd) {
 			WFIFOHEAD(fd,len);
@@ -4027,8 +4182,8 @@ int mapif_send(int fd, unsigned char *buf, unsigned int len)
 	int i;
 
 	if (fd >= 0) {
-		ARR_FIND( 0, MAX_MAP_SERVERS, i, fd == server[i].fd );
-		if( i < MAX_MAP_SERVERS )
+		ARR_FIND( 0, ARRAYLENGTH(server), i, fd == server[i].fd );
+		if( i < ARRAYLENGTH(server) )
 		{
 			WFIFOHEAD(fd,len);
 			memcpy(WFIFOP(fd,0), buf, len);
@@ -4039,7 +4194,7 @@ int mapif_send(int fd, unsigned char *buf, unsigned int len)
 	return 0;
 }
 
-int broadcast_user_count(int tid, unsigned int tick, int id, intptr data)
+int broadcast_user_count(int tid, unsigned int tick, int id, intptr_t data)
 {
 	uint8 buf[6];
 	int users = count_users();
@@ -4085,7 +4240,7 @@ static int send_accounts_tologin_sub(DBKey key, void* data, va_list ap)
 	return 0;
 }
 
-int send_accounts_tologin(int tid, unsigned int tick, int id, intptr data)
+int send_accounts_tologin(int tid, unsigned int tick, int id, intptr_t data)
 {
 	if (login_fd > 0 && session[login_fd])
 	{
@@ -4103,7 +4258,7 @@ int send_accounts_tologin(int tid, unsigned int tick, int id, intptr data)
 	return 0;
 }
 
-int check_connect_login_server(int tid, unsigned int tick, int id, intptr data)
+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;
@@ -4136,7 +4291,7 @@ int check_connect_login_server(int tid, unsigned int tick, int id, intptr data)
 }
 
 // sends a ping packet to login server (will receive pong 0x2718)
-int ping_login_server(int tid, unsigned int tick, int id, intptr data)
+int ping_login_server(int tid, unsigned int tick, int id, intptr_t data)
 {
 	if (login_fd > 0 && session[login_fd] != NULL)
 	{
@@ -4151,7 +4306,7 @@ int ping_login_server(int tid, unsigned int tick, int id, intptr data)
 //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 data)
+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)
@@ -4175,7 +4330,7 @@ static int online_data_cleanup_sub(DBKey key, void *data, va_list ap)
 	return 0;
 }
 
-static int online_data_cleanup(int tid, unsigned int tick, int id, intptr data)
+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;
@@ -4431,12 +4586,16 @@ int char_config_read(const char *cfgName)
 #ifndef TXT_SQL_CONVERT
 void do_final(void)
 {
-	ShowStatus("Terminating server.\n");
+	ShowStatus("Terminating...\n");
 
 	mmo_char_sync();
 	inter_save();
 	set_all_offline(-1);
 	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();
@@ -4445,11 +4604,12 @@ void do_final(void)
 	auth_db->destroy(auth_db, NULL);
 	
 	if(char_dat) aFree(char_dat);
-
-	if (login_fd > 0)
-		do_close(login_fd);
-	if (char_fd > 0)
+	
+	if( char_fd != -1 )
+	{
 		do_close(char_fd);
+		char_fd = -1;
+	}
 
 #ifdef ENABLE_SC_SAVING
 	status_final();
@@ -4458,6 +4618,7 @@ void do_final(void)
 	mapindex_final();
 
 	char_log("----End of char-server (normal end with closing of all files).\n");
+	ShowStatus("Finished.\n");
 }
 
 //------------------------------
@@ -4473,15 +4634,27 @@ 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;
+/// 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");
@@ -4512,8 +4685,6 @@ int do_init(int argc, char **argv)
 	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];
@@ -4533,22 +4704,13 @@ int do_init(int argc, char **argv)
 		}
 	}
 
-	// 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);
+	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);
 
-	// 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");
 
@@ -4564,10 +4726,17 @@ int do_init(int argc, char **argv)
 	{
 		//##TODO invoke a CONSOLE_START plugin event
 	}
-
+	
+	set_defaultparse(parse_char);
 	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 )
+	{
+		shutdown_callback = do_shutdown;
+		runflag = CHARSERVER_ST_RUNNING;
+	}
 
 	return 0;
 }

+ 10 - 0
src/char/char.h

@@ -4,8 +4,18 @@
 #ifndef _CHAR_H_
 #define _CHAR_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
+
 #define MAX_MAP_SERVERS 30
 
 #define DEFAULT_AUTOSAVE_INTERVAL 300*1000

+ 1 - 1
src/char/int_homun.c

@@ -36,7 +36,7 @@ int inter_homun_tostr(char *str,struct s_homunculus *p)
 
 	for (i = 0; i < MAX_HOMUNSKILL; i++)
 	{
-		if (p->hskill[i].id && !p->hskill[i].flag)
+		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);
 	}
 

+ 57 - 0
src/char_sql/CMakeLists.txt

@@ -0,0 +1,57 @@
+
+#
+# char sql
+#
+if( HAVE_common_sql )
+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_DEFINITIONS "${DEFINITIONS}" )
+if( WITH_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()
+message( STATUS "Creating target char-server_sql - done" )
+set( HAVE_char-server_sql ON  CACHE BOOL "char-server_sql target is available" )
+mark_as_advanced( HAVE_char-server_sql )
+else()
+message( STATUS "Skipping target char-server_sql (requires common_sql)" )
+unset( HAVE_char-server_sql CACHE )
+endif()

+ 14 - 7
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

+ 284 - 114
src/char_sql/char.c

@@ -194,7 +194,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 data);
+static int chardb_waiting_disconnect(int tid, unsigned int tick, int id, intptr_t data);
 
 static void* create_online_char_data(DBKey key, va_list args)
 {
@@ -590,11 +590,11 @@ int mmo_char_tosql(int char_id, struct mmo_charstatus* p)
 		//insert here.
 		for( i = 0, count = 0; i < MAX_SKILL; ++i )
 		{
-			if(p->skill[i].id && p->skill[i].flag!=1)
+			if(p->skill[i].id != 0 && p->skill[i].flag != SKILL_FLAG_TEMPORARY)
 			{
 				if( count )
 					StringBuf_AppendStr(&buf, ",");
-				StringBuf_Printf(&buf, "('%d','%d','%d')", char_id, p->skill[i].id, (p->skill[i].flag == 0 ? p->skill[i].lv : p->skill[i].flag - 2));
+				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;
 			}
 		}
@@ -1107,7 +1107,7 @@ int mmo_char_fromsql(int char_id, struct mmo_charstatus* p, bool load_everything
 	||	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 = 0;
+	tmp_skill.flag = SKILL_FLAG_PERMANENT;
 
 	for( i = 0; i < MAX_SKILL && SQL_SUCCESS == SqlStmt_NextRow(stmt); ++i )
 	{
@@ -1543,7 +1543,7 @@ int count_users(void)
 	int i, users;
 
 	users = 0;
-	for(i = 0; i < MAX_MAP_SERVERS; i++) {
+	for(i = 0; i < ARRAYLENGTH(server); i++) {
 		if (server[i].fd > 0) {
 			users += server[i].users;
 		}
@@ -1778,24 +1778,75 @@ static void char_auth_ok(int fd, struct char_session_data *sd)
 	// continues when account data is received...
 }
 
-int send_accounts_tologin(int tid, unsigned int tick, int id, intptr data);
+int send_accounts_tologin(int tid, unsigned int tick, int id, intptr_t data);
+void mapif_server_reset(int id);
 
-int parse_fromlogin(int fd)
+
+/// 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;
-	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.
+	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 )
-		set_eof(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) {
-		if (fd == login_fd) {
-			ShowWarning("Connection to login-server lost (connection #%d).\n", fd);
-			login_fd = -1;
-		}
+	if( session[fd]->flag.eof )
+	{
 		do_close(fd);
+		login_fd = -1;
+		loginif_on_disconnect();
 		return 0;
 	}
 
@@ -1819,16 +1870,11 @@ int parse_fromlogin(int fd)
 				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);
-				
-				//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, MAX_MAP_SERVERS, i, server[i].fd > 0 && server[i].map[0] );
-				if( i == MAX_MAP_SERVERS )
-					ShowStatus("Awaiting maps from map-server.\n");
+				loginif_on_ready();
 			}
 			RFIFOSKIP(fd,3);
 		break;
@@ -2096,6 +2142,34 @@ int parse_fromlogin(int 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) {
@@ -2252,39 +2326,79 @@ int char_loadName(int char_id, char* name)
 
 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, 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));
-			}
-			memset(&server[id], 0, sizeof(struct mmo_map_server));
-			if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `ragsrvinfo` WHERE `index`='%d'", server[id].fd) )
-				Sql_ShowDebug(sql_handle);
-			server[id].fd = -1;
-			online_char_db->foreach(online_char_db,char_db_setoffline,id); //Tag relevant chars as 'in disconnected' server.
-		}
+	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)
 	{
@@ -2330,14 +2444,14 @@ int parse_frommap(int fd)
 				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++) {
+			for(x = 0; x < ARRAYLENGTH(server); x++) {
 				if (server[x].fd > 0 && x != id) {
-					WFIFOHEAD(fd,10 +4*MAX_MAP_PER_SERVER);
+					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 < MAX_MAP_PER_SERVER; i++)
+					for(i = 0; i < ARRAYLENGTH(server); i++)
 						if (server[x].map[i])
 							WFIFOW(fd,10+(j++)*4) = server[x].map[i];
 					if (j > 0) {
@@ -2491,27 +2605,38 @@ int parse_frommap(int fd)
 			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)
-			//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) = 0;
-			WFIFOSET(fd,7);
+			
+			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;
 
@@ -2534,8 +2659,10 @@ int parse_frommap(int fd)
 				mmo_char_fromsql(RFIFOL(fd,14), &char_dat, true);
 				char_data = (struct mmo_charstatus*)uidb_get(char_db_,RFIFOL(fd,14));
 			}
-
-			if (map_fd >= 0 && session[map_fd] && char_data) 
+			
+			if( runflag == CHARSERVER_ST_RUNNING &&
+				session_isActive(map_fd) &&
+				char_data )
 			{	//Send the map server the auth of this player.
 				struct auth_node* node;
 
@@ -2879,7 +3006,9 @@ int parse_frommap(int fd)
 				mmo_char_fromsql(char_id, &char_dat, true);
 				cd = (struct mmo_charstatus*)uidb_get(char_db_,char_id);
 			}
-			if( node != NULL && cd != NULL &&
+			if( runflag == CHARSERVER_ST_RUNNING &&
+				cd != NULL &&
+				node != NULL && 
 				node->account_id == account_id &&
 				node->char_id == char_id &&
 				node->login_id1 == login_id1 &&
@@ -2942,13 +3071,27 @@ int parse_frommap(int fd)
 	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 < MAX_MAP_SERVERS; i++)
+	for(i = 0; i < ARRAYLENGTH(server); i++)
 	{
 		if (server[i].fd > 0
 		&& (ip == (uint32)-1 || server[i].ip == ip)
@@ -3276,6 +3419,15 @@ int parse_char(int fd)
 			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 &&
@@ -3361,8 +3513,8 @@ int parse_char(int fd)
 			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) {
+				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;
@@ -3665,8 +3817,12 @@ int parse_char(int fd)
 			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)) {
+			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;
@@ -3729,7 +3885,7 @@ int mapif_sendall(unsigned char *buf, unsigned int len)
 	int i, c;
 
 	c = 0;
-	for(i = 0; i < MAX_MAP_SERVERS; i++) {
+	for(i = 0; i < ARRAYLENGTH(server); i++) {
 		int fd;
 		if ((fd = server[i].fd) > 0) {
 			WFIFOHEAD(fd,len);
@@ -3747,7 +3903,7 @@ int mapif_sendallwos(int sfd, unsigned char *buf, unsigned int len)
 	int i, c;
 
 	c = 0;
-	for(i = 0; i < MAX_MAP_SERVERS; i++) {
+	for(i = 0; i < ARRAYLENGTH(server); i++) {
 		int fd;
 		if ((fd = server[i].fd) > 0 && fd != sfd) {
 			WFIFOHEAD(fd,len);
@@ -3765,8 +3921,8 @@ int mapif_send(int fd, unsigned char *buf, unsigned int len)
 	int i;
 
 	if (fd >= 0) {
-		ARR_FIND( 0, MAX_MAP_SERVERS, i, fd == server[i].fd );
-		if( i < MAX_MAP_SERVERS )
+		ARR_FIND( 0, ARRAYLENGTH(server), i, fd == server[i].fd );
+		if( i < ARRAYLENGTH(server) )
 		{
 			WFIFOHEAD(fd,len);
 			memcpy(WFIFOP(fd,0), buf, len);
@@ -3777,7 +3933,7 @@ int mapif_send(int fd, unsigned char *buf, unsigned int len)
 	return 0;
 }
 
-int broadcast_user_count(int tid, unsigned int tick, int id, intptr data)
+int broadcast_user_count(int tid, unsigned int tick, int id, intptr_t data)
 {
 	uint8 buf[6];
 	int users = count_users();
@@ -3820,7 +3976,7 @@ static int send_accounts_tologin_sub(DBKey key, void* data, va_list ap)
 	return 0;
 }
 
-int send_accounts_tologin(int tid, unsigned int tick, int id, intptr data)
+int send_accounts_tologin(int tid, unsigned int tick, int id, intptr_t data)
 {
 	if (login_fd > 0 && session[login_fd])
 	{
@@ -3838,7 +3994,7 @@ int send_accounts_tologin(int tid, unsigned int tick, int id, intptr data)
 	return 0;
 }
 
-int check_connect_login_server(int tid, unsigned int tick, int id, intptr data)
+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;
@@ -3871,7 +4027,7 @@ int check_connect_login_server(int tid, unsigned int tick, int id, intptr data)
 }
 
 // sends a ping packet to login server (will receive pong 0x2718)
-int ping_login_server(int tid, unsigned int tick, int id, intptr data)
+int ping_login_server(int tid, unsigned int tick, int id, intptr_t data)
 {
 	if (login_fd > 0 && session[login_fd] != NULL)
 	{
@@ -3886,7 +4042,7 @@ int ping_login_server(int tid, unsigned int tick, int id, intptr data)
 //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 data)
+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)
@@ -3910,7 +4066,7 @@ static int online_data_cleanup_sub(DBKey key, void *data, va_list ap)
 	return 0;
 }
 
-static int online_data_cleanup(int tid, unsigned int tick, int id, intptr data)
+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;
@@ -4211,7 +4367,7 @@ int char_config_read(const char* cfgName)
 
 void do_final(void)
 {
-	ShowStatus("Terminating server.\n");
+	ShowStatus("Terminating...\n");
 
 	set_all_offline(-1);
 	set_all_offline_sql();
@@ -4219,6 +4375,9 @@ void do_final(void)
 	inter_final();
 
 	flush_fifos();
+	
+	do_final_mapif();
+	do_final_loginif();
 
 	if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `ragsrvinfo`") )
 		Sql_ShowDebug(sql_handle);
@@ -4227,13 +4386,16 @@ void do_final(void)
 	online_char_db->destroy(online_char_db, NULL);
 	auth_db->destroy(auth_db, NULL);
 
-	if (login_fd > 0)
-		do_close(login_fd);
-	if (char_fd > 0)
+	if( char_fd != -1 )
+	{
 		do_close(char_fd);
+		char_fd = -1;
+	}
 
 	Sql_Free(sql_handle);
 	mapindex_final();
+
+	ShowStatus("Finished.\n");
 }
 
 //------------------------------
@@ -4249,15 +4411,27 @@ 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;
+/// 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");
@@ -4284,8 +4458,6 @@ int do_init(int argc, char **argv)
 	char_read_fame_list(); //Read fame lists.
 	ShowInfo("char server initialized.\n");
 
-	set_defaultparse(parse_char);
-
 	if ((naddr_ != 0) && (!login_ip || !char_ip))
 	{
 		char ip_str[16];
@@ -4305,22 +4477,13 @@ int do_init(int argc, char **argv)
 		}
 	}
 
-	// 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);
+	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);
 
-	// 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");
 
@@ -4351,9 +4514,16 @@ int do_init(int argc, char **argv)
 
 	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;
 }

+ 11 - 0
src/char_sql/char.h

@@ -4,6 +4,17 @@
 #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

+ 2 - 2
src/char_sql/int_auction.c

@@ -21,7 +21,7 @@
 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 data);
+static int auction_end_timer(int tid, unsigned int tick, int id, intptr_t data);
 
 static int auction_count(int char_id, bool buy)
 {
@@ -136,7 +136,7 @@ static void mapif_Auction_message(int char_id, unsigned char result)
 	mapif_sendall(buf,7);
 }
 
-static int auction_end_timer(int tid, unsigned int tick, int id, intptr data)
+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 )

+ 1 - 1
src/char_sql/int_guild.c

@@ -47,7 +47,7 @@ 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 data)
+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.

+ 144 - 0
src/common/CMakeLists.txt

@@ -0,0 +1,144 @@
+
+#
+# Create svnversion.h
+#
+message( STATUS "Creating svnversion.h" )
+if( SVNVERSION )
+	file( WRITE ${CMAKE_CURRENT_BINARY_DIR}/svnversion.h
+		"#ifndef SVNVERSION\n#define SVNVERSION ${SVNVERSION}\n#endif\n" )
+else()
+	file( WRITE ${CMAKE_CURRENT_BINARY_DIR}/svnversion.h "" )
+endif()
+set( GLOBAL_INCLUDE_DIRS ${GLOBAL_INCLUDE_DIRS} ${CMAKE_CURRENT_BINARY_DIR} CACHE INTERNAL "" )
+set( SVNVERSION ${SVNVERSION}
+	CACHE STRING "SVN version of the source code" )
+if( WITH_COMPONENT_DEVELOPMENT )
+	install( FILES ${CMAKE_CURRENT_BINARY_DIR}/svnversion.h
+		DESTINATION "src/common"
+		COMPONENT Development_base )
+endif()
+message( STATUS "Creating svnversion.h - done" )
+
+
+#####################################################################
+# setup
+#
+set( COMMON_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}"
+	CACHE PATH "common source directory" )
+mark_as_advanced( COMMON_SOURCE_DIR )
+
+set( COMMON_ALL_HEADERS
+	"${CMAKE_CURRENT_BINARY_DIR}/svnversion.h"
+	"${COMMON_SOURCE_DIR}/cbasetypes.h"
+	"${COMMON_SOURCE_DIR}/mmo.h"
+	"${COMMON_SOURCE_DIR}/plugin.h"
+	"${COMMON_SOURCE_DIR}/version.h"
+	)
+
+set( COMMON_MINI_HEADERS
+	${COMMON_ALL_HEADERS}
+	"${COMMON_SOURCE_DIR}/core.h"
+	"${COMMON_SOURCE_DIR}/malloc.h"
+	"${COMMON_SOURCE_DIR}/showmsg.h"
+	"${COMMON_SOURCE_DIR}/strlib.h"
+	CACHE INTERNAL "" )
+set( COMMON_MINI_SOURCES
+	"${COMMON_SOURCE_DIR}/core.c"
+	"${COMMON_SOURCE_DIR}/malloc.c"
+	"${COMMON_SOURCE_DIR}/showmsg.c"
+	"${COMMON_SOURCE_DIR}/strlib.c"
+	CACHE INTERNAL "" )
+set( COMMON_MINI_DEFINITIONS MINICORE CACHE INTERNAL "" )
+
+
+#
+# common_base
+#
+if( WITH_ZLIB )
+message( STATUS "Creating target common_base" )
+set( COMMON_BASE_HEADERS
+	${COMMON_ALL_HEADERS}
+	"${COMMON_SOURCE_DIR}/core.h"
+	"${COMMON_SOURCE_DIR}/db.h"
+	"${COMMON_SOURCE_DIR}/ers.h"
+	"${COMMON_SOURCE_DIR}/grfio.h"
+	"${COMMON_SOURCE_DIR}/lock.h"
+	"${COMMON_SOURCE_DIR}/malloc.h"
+	"${COMMON_SOURCE_DIR}/mapindex.h"
+	"${COMMON_SOURCE_DIR}/md5calc.h"
+	"${COMMON_SOURCE_DIR}/nullpo.h"
+	"${COMMON_SOURCE_DIR}/plugins.h"
+	"${COMMON_SOURCE_DIR}/random.h"
+	"${COMMON_SOURCE_DIR}/showmsg.h"
+	"${COMMON_SOURCE_DIR}/socket.h"
+	"${COMMON_SOURCE_DIR}/strlib.h"
+	"${COMMON_SOURCE_DIR}/timer.h"
+	"${COMMON_SOURCE_DIR}/utils.h"
+	CACHE INTERNAL "common_base headers" )
+set( COMMON_BASE_SOURCES
+	"${COMMON_SOURCE_DIR}/core.c"
+	"${COMMON_SOURCE_DIR}/db.c"
+	"${COMMON_SOURCE_DIR}/ers.c"
+	"${COMMON_SOURCE_DIR}/grfio.c"
+	"${COMMON_SOURCE_DIR}/lock.c"
+	"${COMMON_SOURCE_DIR}/malloc.c"
+	"${COMMON_SOURCE_DIR}/mapindex.c"
+	"${COMMON_SOURCE_DIR}/md5calc.c"
+	"${COMMON_SOURCE_DIR}/nullpo.c"
+	"${COMMON_SOURCE_DIR}/plugins.c"
+	"${COMMON_SOURCE_DIR}/random.c"
+	"${COMMON_SOURCE_DIR}/showmsg.c"
+	"${COMMON_SOURCE_DIR}/socket.c"
+	"${COMMON_SOURCE_DIR}/strlib.c"
+	"${COMMON_SOURCE_DIR}/timer.c"
+	"${COMMON_SOURCE_DIR}/utils.c"
+	CACHE INTERNAL "common_base sources" )
+set( LIBRARIES ${ZLIB_LIBRARIES} )
+set( INCLUDE_DIRS ${GLOBAL_INCLUDE_DIRS} ${MT19937AR_INCLUDE_DIRS} ${ZLIB_INCLUDE_DIRS} )
+set( DEFINITIONS ${GLOBAL_DEFINITIONS} )
+set( SOURCE_FILES ${MT19937AR_HEADERS} ${MT19937AR_SOURCES} ${COMMON_BASE_HEADERS} ${COMMON_BASE_SOURCES} )
+source_group( mt19937ar FILES ${MT19937AR_HEADERS} ${MT19937AR_SOURCES} )
+source_group( common FILES ${COMMON_BASE_HEADERS} ${COMMON_BASE_SOURCES} )
+add_library( common_base ${SOURCE_FILES} )
+target_link_libraries( common_base ${LIBRARIES} )
+set_target_properties( common_base PROPERTIES COMPILE_DEFINITIONS "${DEFINITIONS}" )
+include_directories( ${INCLUDE_DIRS} )
+message( STATUS "Creating target common_base - done" )
+set( HAVE_common_base ON  CACHE BOOL "common_base target is available" )
+mark_as_advanced( HAVE_common_base )
+else()
+message( STATUS "Skipping target common_base (requires ZLIB)" )
+unset( HAVE_common_base CACHE )
+endif()
+
+
+#
+# common_sql
+#
+if( HAVE_common_base AND WITH_MYSQL )
+message( STATUS "Creating target common_sql" )
+set( COMMON_SQL_HEADERS
+	${COMMON_ALL_HEADERS}
+	"${CMAKE_CURRENT_SOURCE_DIR}/sql.h"
+	CACHE INTERNAL "common_sql headers" )
+set( COMMON_SQL_SOURCES
+	"${CMAKE_CURRENT_SOURCE_DIR}/sql.c"
+	CACHE INTERNAL "common_sql sources" )
+set( DEPENDENCIES common_base )
+set( LIBRARIES ${MYSQL_LIBRARIES} )
+set( INCLUDE_DIRS ${GLOBAL_INCLUDE_DIRS} ${MYSQL_INCLUDE_DIRS} )
+set( DEFINITIONS ${GLOBAL_DEFINITIONS} )
+set( SOURCE_FILES ${COMMON_SQL_HEADERS} ${COMMON_SQL_SOURCES} )
+source_group( common FILES ${COMMON_SQL_HEADERS} ${COMMON_SQL_SOURCES} )
+add_library( common_sql ${SOURCE_FILES} )
+add_dependencies( common_sql ${DEPENDENCIES} )
+target_link_libraries( common_sql ${LIBRARIES} ${DEPENDENCIES} )
+set_target_properties( common_sql PROPERTIES COMPILE_DEFINITIONS "${DEFINITIONS}" )
+include_directories( ${INCLUDE_DIRS} )
+message( STATUS "Creating target common_sql - done" )
+set( HAVE_common_sql ON  CACHE BOOL "common_sql target is available" )
+mark_as_advanced( HAVE_common_sql )
+else()
+message( STATUS "Skipping target common_sql (requires common_base and MYSQL)" )
+unset( HAVE_common_sql CACHE )
+endif()

+ 17 - 8
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

+ 36 - 75
src/common/cbasetypes.h

@@ -78,14 +78,9 @@
 // NOTE: Visual C++ uses <inttypes.h> and <stdint.h> provided in /3rdparty
 //////////////////////////////////////////////////////////////////////////
 #include <inttypes.h>
-
-//////////////////////////////////////////////////////////////////////////
-// typedefs to compensate type size change from 32bit to 64bit
-// MS implements LLP64 model, normal unix does LP64,
-// only Silicon Graphics/Cray goes ILP64 so don't care (and don't support)
-//////////////////////////////////////////////////////////////////////////
-
+#include <stdint.h>
 #include <limits.h>
+
 // ILP64 isn't supported, so always 32 bits?
 #ifndef UINT_MAX
 #define UINT_MAX 0xffffffff
@@ -95,49 +90,56 @@
 // Integers with guaranteed _exact_ size.
 //////////////////////////////////////////////////////////////////////////
 
-#define SIZEOF_LONG 4
-#define SIZEOF_INT 4
-#define HAVE_INT_8_16_32
+typedef int8_t		int8;
+typedef int16_t		int16;
+typedef int32_t		int32;
+typedef int64_t		int64;
 
-typedef char				int8;
-typedef short				int16;
-typedef int					int32;
+typedef int8_t		sint8;
+typedef int16_t		sint16;
+typedef int32_t		sint32;
+typedef int64_t		sint64;
 
-typedef signed char			sint8;
-typedef signed short		sint16;
-typedef signed int			sint32;
-
-typedef unsigned char		uint8;
-typedef unsigned short		uint16;
-typedef unsigned int		uint32;
+typedef uint8_t		uint8;
+typedef uint16_t	uint16;
+typedef uint32_t	uint32;
+typedef uint64_t	uint64;
 
 #undef UINT8_MIN
 #undef UINT16_MIN
 #undef UINT32_MIN
-#define UINT8_MIN	((uint8) 0)
-#define UINT16_MIN	((uint16)0)
-#define UINT32_MIN	((uint32)0)
+#undef UINT64_MIN
+#define UINT8_MIN	((uint8) UINT8_C(0x00))
+#define UINT16_MIN	((uint16)UINT16_C(0x0000))
+#define UINT32_MIN	((uint32)UINT32_C(0x00000000))
+#define UINT64_MIN	((uint64)UINT64_C(0x0000000000000000))
 
 #undef UINT8_MAX
 #undef UINT16_MAX
 #undef UINT32_MAX
-#define UINT8_MAX	((uint8) 0xFF)
-#define UINT16_MAX	((uint16)0xFFFF)
-#define UINT32_MAX	((uint32)0xFFFFFFFF)
+#undef UINT64_MAX
+#define UINT8_MAX	((uint8) UINT8_C(0xFF))
+#define UINT16_MAX	((uint16)UINT16_C(0xFFFF))
+#define UINT32_MAX	((uint32)UINT32_C(0xFFFFFFFF))
+#define UINT64_MAX	((uint64)UINT64_C(0xFFFFFFFFFFFFFFFF))
 
 #undef SINT8_MIN
 #undef SINT16_MIN
 #undef SINT32_MIN
-#define SINT8_MIN	((sint8) 0x80)
-#define SINT16_MIN	((sint16)0x8000)
-#define SINT32_MIN	((sint32)0x80000000)
+#undef SINT64_MIN
+#define SINT8_MIN	((sint8) INT8_C(0x80))
+#define SINT16_MIN	((sint16)INT16_C(0x8000))
+#define SINT32_MIN	((sint32)INT32_C(0x80000000))
+#define SINT64_MIN	((sint32)INT64_C(0x8000000000000000))
 
 #undef SINT8_MAX
 #undef SINT16_MAX
 #undef SINT32_MAX
-#define SINT8_MAX	((sint8) 0x7F)
-#define SINT16_MAX	((sint16)0x7FFF)
-#define SINT32_MAX	((sint32)0x7FFFFFFF)
+#undef SINT64_MAX
+#define SINT8_MAX	((sint8) INT8_C(0x7F))
+#define SINT16_MAX	((sint16)INT16_C(0x7FFF))
+#define SINT32_MAX	((sint32)INT32_C(0x7FFFFFFF))
+#define SINT64_MAX	((sint64)INT64_C(0x7FFFFFFFFFFFFFFF))
 
 //////////////////////////////////////////////////////////////////////////
 // Integers with guaranteed _minimum_ size.
@@ -172,52 +174,11 @@ typedef int				ssize_t;
 //////////////////////////////
 
 
-//////////////////////////////////////////////////////////////////////////
-// portable 64-bit integers
-//////////////////////////////////////////////////////////////////////////
-#if defined(_MSC_VER) || defined(__BORLANDC__)
-typedef __int64				int64;
-typedef signed __int64		sint64;
-typedef unsigned __int64	uint64;
-#else
-typedef long long			int64;
-typedef signed long long	sint64;
-typedef unsigned long long	uint64;
-#endif
-
-#ifndef INT64_MIN
-#define INT64_MIN  (INT64_C(-9223372036854775807)-1)
-#endif
-#ifndef INT64_MAX
-#define INT64_MAX  (INT64_C(9223372036854775807))
-#endif
-#ifndef UINT64_MAX
-#define UINT64_MAX (UINT64_C(18446744073709551615))
-#endif
-
-
 //////////////////////////////////////////////////////////////////////////
 // pointer sized integers
 //////////////////////////////////////////////////////////////////////////
-#undef UINTPTR_MIN
-#undef UINTPTR_MAX
-#undef INTPTR_MIN
-#undef INTPTR_MAX
-#ifdef __64BIT__
-typedef uint64 uintptr;
-typedef int64 intptr;
-#define UINTPTR_MIN UINT64_MIN
-#define UINTPTR_MAX UINT64_MAX
-#define INTPTR_MIN INT64_MIN
-#define INTPTR_MAX INT64_MAX
-#else
-typedef uint32 uintptr;
-typedef int32 intptr;
-#define UINTPTR_MIN UINT32_MIN
-#define UINTPTR_MAX UINT32_MAX
-#define INTPTR_MIN INT32_MIN
-#define INTPTR_MAX INT32_MAX
-#endif
+typedef intptr_t intptr;
+typedef uintptr_t uintptr;
 
 
 //////////////////////////////////////////////////////////////////////////

+ 11 - 3
src/common/core.c

@@ -24,7 +24,12 @@
 #include <unistd.h>
 #endif
 
-int runflag = 1;
+
+/// Called when a terminate signal is received.
+void (*shutdown_callback)(void) = NULL;
+
+
+int runflag = CORE_ST_RUN;
 int arg_c = 0;
 char **arg_v = NULL;
 
@@ -78,7 +83,10 @@ static void sig_proc(int sn)
 	case SIGTERM:
 		if (++is_called > 3)
 			exit(EXIT_SUCCESS);
-		runflag = 0;
+		if( shutdown_callback != NULL )
+			shutdown_callback();
+		else
+			runflag = CORE_ST_STOP;// auto-shutdown
 		break;
 	case SIGSEGV:
 	case SIGFPE:
@@ -249,7 +257,7 @@ int main (int argc, char **argv)
 
 	{// Main runtime cycle
 		int next;
-		while (runflag) {
+		while (runflag != CORE_ST_STOP) {
 			next = do_timer(gettick_nocache());
 			do_sockets(next);
 		}

+ 13 - 0
src/common/core.h

@@ -7,6 +7,7 @@
 extern int arg_c;
 extern char **arg_v;
 
+/// @see E_CORE_ST
 extern int runflag;
 extern char *SERVER_NAME;
 extern char SERVER_TYPE;
@@ -18,4 +19,16 @@ extern void set_server_type(void);
 extern void do_abort(void);
 extern void do_final(void);
 
+/// The main loop continues until runflag is CORE_ST_STOP
+enum E_CORE_ST
+{
+	CORE_ST_STOP = 0,
+	CORE_ST_RUN,
+	CORE_ST_LAST
+};
+
+/// Called when a terminate signal is received. (Ctrl+C pressed)
+/// If NULL, runflag is set to CORE_ST_STOP instead.
+extern void (*shutdown_callback)(void);
+
 #endif /* _CORE_H_ */

+ 68 - 23
src/common/db.c

@@ -67,13 +67,13 @@
 \*****************************************************************************/
 #include <stdio.h>
 #include <stdlib.h>
-#include <string.h>
 
 #include "db.h"
 #include "../common/mmo.h"
 #include "../common/malloc.h"
 #include "../common/showmsg.h"
 #include "../common/ers.h"
+#include "../common/strlib.h"
 
 /*****************************************************************************\
  *  (1) Private typedefs, enums, structures, defines and global variables of *
@@ -271,6 +271,7 @@ static struct db_stats {
 	uint32 dbit_remove;
 	uint32 dbit_destroy;
 	uint32 db_iterator;
+	uint32 db_exists;
 	uint32 db_get;
 	uint32 db_getall;
 	uint32 db_vgetall;
@@ -304,7 +305,7 @@ static struct db_stats {
 	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
 };
 #define DB_COUNTSTAT(token) if (stats. ## token != UINT32_MAX) ++stats. ## token
 #else /* !defined(DB_ENABLE_STATS) */
@@ -630,19 +631,17 @@ static int db_is_key_null(DBType type, DBKey key)
 static DBKey db_dup_key(DBMap_impl* db, DBKey key)
 {
 	char *str;
+	size_t len;
 
 	DB_COUNTSTAT(db_dup_key);
 	switch (db->type) {
 		case DB_STRING:
 		case DB_ISTRING:
-			if (db->maxlen) {
-				CREATE(str, char, db->maxlen +1);
-				strncpy(str, key.str, db->maxlen);
-				str[db->maxlen] = '\0';
-				key.str = str;
-			} else {
-				key.str = (char *)aStrdup(key.str);
-			}
+			len = strnlen(key.str, db->maxlen);
+			str = (char*)aMalloc(len + 1);
+			memcpy(str, key.str, len);
+			str[len] = '\0';
+			key.str = str;
 			return key;
 
 		default:
@@ -888,8 +887,6 @@ static int db_uint_cmp(DBKey key1, DBKey key2, unsigned short maxlen)
 static int db_string_cmp(DBKey key1, DBKey key2, unsigned short maxlen)
 {
 	DB_COUNTSTAT(db_string_cmp);
-	if (maxlen == 0)
-		maxlen = UINT16_MAX;
 	return strncmp((const char *)key1.str, (const char *)key2.str, maxlen);
 }
 
@@ -908,8 +905,6 @@ static int db_string_cmp(DBKey key1, DBKey key2, unsigned short maxlen)
 static int db_istring_cmp(DBKey key1, DBKey key2, unsigned short maxlen)
 {
 	DB_COUNTSTAT(db_istring_cmp);
-	if (maxlen == 0)
-		maxlen = UINT16_MAX;
 	return strncasecmp((const char *)key1.str, (const char *)key2.str, maxlen);
 }
 
@@ -951,7 +946,6 @@ static unsigned int db_uint_hash(DBKey key, unsigned short maxlen)
 
 /**
  * Default hasher for DB_STRING databases.
- * If maxlen if 0, the maximum number of maxlen is used instead.
  * @param key Key to be hashed
  * @param maxlen Maximum length of the key to hash
  * @return hash of the key
@@ -966,8 +960,6 @@ static unsigned int db_string_hash(DBKey key, unsigned short maxlen)
 	unsigned short i;
 
 	DB_COUNTSTAT(db_string_hash);
-	if (maxlen == 0)
-		maxlen = UINT16_MAX;
 
 	for (i = 0; *k; ++i) {
 		hash = (hash*33 + ((unsigned char)*k))^(hash>>24);
@@ -981,7 +973,6 @@ static unsigned int db_string_hash(DBKey key, unsigned short maxlen)
 
 /**
  * Default hasher for DB_ISTRING databases.
- * If maxlen if 0, the maximum number of maxlen is used instead.
  * @param key Key to be hashed
  * @param maxlen Maximum length of the key to hash
  * @return hash of the key
@@ -995,8 +986,6 @@ static unsigned int db_istring_hash(DBKey key, unsigned short maxlen)
 	unsigned short i;
 
 	DB_COUNTSTAT(db_istring_hash);
-	if (maxlen == 0)
-		maxlen = UINT16_MAX;
 
 	for (i = 0; *k; i++) {
 		hash = (hash*33 + ((unsigned char)TOLOWER(*k)))^(hash>>24);
@@ -1087,6 +1076,7 @@ static void db_release_both(DBKey key, void *data, DBRelease which)
  *  dbit_obj_destroy - Destroys the iterator, unlocking the database and     *
  *           freeing used memory.                                            *
  *  db_obj_iterator - Return a new databse iterator.                         *
+ *  db_obj_exists   - Checks if an entry exists.                             *
  *  db_obj_get      - Get the data identified by the key.                    *
  *  db_obj_vgetall  - Get the data of the matched entries.                   *
  *  db_obj_getall   - Get the data of the matched entries.                   *
@@ -1401,6 +1391,57 @@ static DBIterator* db_obj_iterator(DBMap* self)
 	return &it->vtable;
 }
 
+/**
+ * Returns true if the entry exists.
+ * @param self Interface of the database
+ * @param key Key that identifies the entry
+ * @return true is the entry exists
+ * @protected
+ * @see DBMap#exists
+ */
+static bool db_obj_exists(DBMap* self, DBKey key)
+{
+	DBMap_impl* db = (DBMap_impl*)self;
+	DBNode node;
+	int c;
+	bool found = false;
+
+	DB_COUNTSTAT(db_exists);
+	if (db == NULL) return false; // nullpo candidate
+	if (!(db->options&DB_OPT_ALLOW_NULL_KEY) && db_is_key_null(db->type, key)) {
+		return false; // nullpo candidate
+	}
+
+	if (db->cache && db->cmp(key, db->cache->key, db->maxlen) == 0) {
+#if defined(DEBUG)
+		if (db->cache->deleted) {
+			ShowDebug("db_exists: Cache contains a deleted node. Please report this!!!\n");
+			return false;
+		}
+#endif
+		return true; // cache hit
+	}
+
+	db_free_lock(db);
+	node = db->ht[db->hash(key, db->maxlen)%HASH_SIZE];
+	while (node) {
+		c = db->cmp(key, node->key, db->maxlen);
+		if (c == 0) {
+			if (!(node->deleted)) {
+				db->cache = node;
+				found = true;
+			}
+			break;
+		}
+		if (c < 0)
+			node = node->left;
+		else
+			node = node->right;
+	}
+	db_free_unlock(db);
+	return found;
+}
+
 /**
  * Get the data of the entry identifid by the key.
  * @param self Interface of the database
@@ -2326,7 +2367,7 @@ DBReleaser db_custom_release(DBRelease which)
  * @param type Type of database
  * @param options Options of the database
  * @param maxlen Maximum length of the string to be used as key in string 
- *          databases
+ *          databases. If 0, the maximum number of maxlen is used (64K).
  * @return The interface of the database
  * @public
  * @see #DBMap_impl
@@ -2351,6 +2392,7 @@ DBMap* db_alloc(const char *file, int line, DBType type, DBOptions options, unsi
 	options = db_fix_options(type, options);
 	/* Interface of the database */
 	db->vtable.iterator = db_obj_iterator;
+	db->vtable.exists   = db_obj_exists;
 	db->vtable.get      = db_obj_get;
 	db->vtable.getall   = db_obj_getall;
 	db->vtable.vgetall  = db_obj_vgetall;
@@ -2389,6 +2431,9 @@ DBMap* db_alloc(const char *file, int line, DBType type, DBOptions options, unsi
 	db->maxlen = maxlen;
 	db->global_lock = 0;
 
+	if( db->maxlen == 0 && (type == DB_STRING || type == DB_ISTRING) )
+		db->maxlen = UINT16_MAX;
+
 	return &db->vtable;
 }
 
@@ -2493,7 +2538,7 @@ void db_final(void)
 			"dbit_next          %10u, dbit_prev          %10u,\n"
 			"dbit_exists        %10u, dbit_remove        %10u,\n"
 			"dbit_destroy       %10u, db_iterator        %10u,\n"
-			"db_get             %10u,\n"
+			"db_exits           %10u, db_get             %10u,\n"
 			"db_getall          %10u, db_vgetall         %10u,\n"
 			"db_ensure          %10u, db_vensure         %10u,\n"
 			"db_put             %10u, db_remove          %10u,\n"
@@ -2523,7 +2568,7 @@ void db_final(void)
 			stats.dbit_next,          stats.dbit_prev,
 			stats.dbit_exists,        stats.dbit_remove,
 			stats.dbit_destroy,       stats.db_iterator,
-			stats.db_get,
+			stats.db_exists,          stats.db_get,
 			stats.db_getall,          stats.db_vgetall,
 			stats.db_ensure,          stats.db_vensure,
 			stats.db_put,             stats.db_remove,

+ 15 - 5
src/common/db.h

@@ -205,8 +205,6 @@ typedef int (*DBMatcher)(DBKey key, void* data, va_list args);
 /**
  * Format of the comparators used internally by the database system.
  * Compares key1 to key2.
- * <code>maxlen</code> is the maximum number of character used in DB_STRING and 
- * DB_ISTRING databases. If 0, the maximum number of maxlen is used (64K).
  * Returns 0 is equal, negative if lower and positive is higher.
  * @param key1 Key being compared
  * @param key2 Key we are comparing to
@@ -221,8 +219,6 @@ typedef int (*DBComparator)(DBKey key1, DBKey key2, unsigned short maxlen);
 /**
  * Format of the hashers used internally by the database system.
  * Creates the hash of the key.
- * <code>maxlen</code> is the maximum number of character used in DB_STRING and 
- * DB_ISTRING databases. If 0, the maximum number of maxlen is used (64K).
  * @param key Key being hashed
  * @param maxlen Maximum number of characters used in DB_STRING and DB_ISTRING
  *          databases.
@@ -359,6 +355,15 @@ struct DBMap {
 	 */
 	DBIterator* (*iterator)(DBMap* self);
 
+	/**
+	 * Returns true if the entry exists.
+	 * @param self Database
+	 * @param key Key that identifies the entry
+	 * @return true is the entry exists
+	 * @protected
+	 */
+	bool (*exists)(DBMap* self, DBKey key);
+
 	/**
 	 * Get the data of the entry identifid by the key.
 	 * @param self Database
@@ -580,6 +585,11 @@ struct DBMap {
 #	define str2key(k) ((DBKey)(const char *)(k))
 #endif /* not DB_MANUAL_CAST_TO_UNION */
 
+#define db_exists(db,k)    ( (db)->exists((db),(k)) )
+#define idb_exists(db,k)   ( (db)->exists((db),i2key(k)) )
+#define uidb_exists(db,k)  ( (db)->exists((db),ui2key(k)) )
+#define strdb_exists(db,k) ( (db)->exists((db),str2key(k)) )
+
 #define db_get(db,k)    ( (db)->get((db),(k)) )
 #define idb_get(db,k)   ( (db)->get((db),i2key(k)) )
 #define uidb_get(db,k)  ( (db)->get((db),ui2key(k)) )
@@ -707,7 +717,7 @@ DBReleaser db_custom_release(DBRelease which);
  * @param type Type of database
  * @param options Options of the database
  * @param maxlen Maximum length of the string to be used as key in string 
- *          databases
+ *          databases. If 0, the maximum number of maxlen is used (64K).
  * @return The interface of the database
  * @public
  * @see #DBType

+ 0 - 2
src/common/ers.h

@@ -40,9 +40,7 @@
 #ifndef _ERS_H_
 #define _ERS_H_
 
-#ifndef _CBASETYPES_H_
 #include "../common/cbasetypes.h"
-#endif
 
 /*****************************************************************************\
  *  (1) All public parts of the Entry Reusage System.                        *

+ 26 - 10
src/common/grfio.c

@@ -1,19 +1,18 @@
 // Copyright (c) Athena Dev Teams - Licensed under GNU GPL
 // For more information, see LICENCE in the main folder
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-
-#include "grfio.h"
-
 #include "../common/cbasetypes.h"
 #include "../common/showmsg.h"
 #include "../common/malloc.h"
 #include "../common/strlib.h"
 #include "../common/utils.h"
+#include "grfio.h"
 
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <zlib.h>
 
 //----------------------------
 //	file entry table struct
@@ -221,6 +220,23 @@ unsigned long grfio_crc32 (const unsigned char* buf, unsigned int len)
 	return crc32(crc32(0L, Z_NULL, 0), buf, len);
 }
 
+
+///////////////////////////////////////////////////////////////////////////////
+///	Grf data sub : zip decode
+int decode_zip(unsigned char* dest, unsigned long* destLen, const unsigned char* source, unsigned long sourceLen)
+{
+	return uncompress(dest, destLen, source, sourceLen);
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+///	Grf data sub : zip encode 
+int encode_zip(unsigned char* dest, unsigned long* destLen, const unsigned char* source, unsigned long sourceLen)
+{
+	return compress(dest, destLen, source, sourceLen);
+}
+
+
 /***********************************************************
  ***                File List Subroutines                ***
  ***********************************************************/
@@ -431,9 +447,9 @@ void* grfio_reads(char* fname, int* size)
 				if (entry->cycle >= 0)
 					decode_des_etc(buf, entry->srclen_aligned, entry->cycle == 0, entry->cycle);
 				len = entry->declen;
-				uncompress(buf2, &len, buf, entry->srclen);
+				decode_zip(buf2, &len, buf, entry->srclen);
 				if (len != (uLong)entry->declen) {
-					ShowError("uncompress size mismatch err: %d != %d\n", (int)len, entry->declen);
+					ShowError("decode_zip size mismatch err: %d != %d\n", (int)len, entry->declen);
 					aFree(buf);
 					aFree(buf2);
 					return NULL;
@@ -580,7 +596,7 @@ static int grfio_entryread(char* grfname, int gentry)
 		grf_filelist = (unsigned char *)aMallocA(eSize);	// Get a Extend Size
 		fread(rBuf,1,rSize,fp);
 		fclose(fp);
-		uncompress(grf_filelist, &eSize, rBuf, rSize);	// Decode function
+		decode_zip(grf_filelist, &eSize, rBuf, rSize);	// Decode function
 		list_size = eSize;
 		aFree(rBuf);
 

+ 3 - 2
src/common/grfio.h

@@ -4,8 +4,6 @@
 #ifndef	_GRFIO_H_
 #define	_GRFIO_H_
 
-#include <zlib.h>
-
 void grfio_init(char*);			// GRFIO Initialize
 void grfio_final(void);			// GRFIO Finalize
 void* grfio_reads(char*,int*);	// GRFIO data file read & size get
@@ -16,4 +14,7 @@ char *grfio_find_file(char *fname);
 int grfio_size(char*);			// GRFIO data file size get
 unsigned long grfio_crc32(const unsigned char *buf, unsigned int len);
 
+int decode_zip(unsigned char* dest, unsigned long* destLen, const unsigned char* source, unsigned long sourceLen);
+int encode_zip(unsigned char* dest, unsigned long* destLen, const unsigned char* source, unsigned long sourceLen);
+
 #endif /* _GRFIO_H_ */

+ 3 - 7
src/common/malloc.c

@@ -222,7 +222,7 @@ void* _mmalloc(size_t size, const char *file, int line, const char *func )
 
 	if (((long) size) < 0) {
 		ShowError("_mmalloc: %d\n", size);
-		return 0;
+		return NULL;
 	}
 	
 	if(size == 0) {
@@ -380,7 +380,7 @@ void _mfree(void *ptr, const char *file, int line, const char *func )
 		{
 			ShowError("Memory manager: args of aFree 0x%p is overflowed pointer %s line %d\n", ptr, file, line);
 		} else {
-			head->size = -1;
+			head->size = 0xFFFF;
 			if(head_large->prev) {
 				head_large->prev->next = head_large->next;
 			} else {
@@ -428,7 +428,7 @@ void _mfree(void *ptr, const char *file, int line, const char *func )
 					hash_unfill[ block->unit_hash ] = block;
 				}
 				head->size     = block->unit_unfill;
-				block->unit_unfill = (unsigned short)(((uintptr)head - (uintptr)block->data) / block->unit_size);
+				block->unit_unfill = (unsigned short)(((uintptr_t)head - (uintptr_t)block->data) / block->unit_size);
 			}
 		}
 	}
@@ -636,7 +636,6 @@ static void memmgr_final (void)
 		fclose(log_fp);
 	}
 #endif /* LOG_MEMMGR */
-	return;
 }
 
 static void memmgr_init (void)
@@ -646,7 +645,6 @@ static void memmgr_init (void)
 	ShowStatus("Memory manager initialised: "CL_WHITE"%s"CL_RESET"\n", memmer_logfile);
 	memset(hash_unfill, 0, sizeof(hash_unfill));
 #endif /* LOG_MEMMGR */
-	return;
 }
 #endif /* USE_MEMMGR */
 
@@ -679,7 +677,6 @@ void malloc_final (void)
 #ifdef USE_MEMMGR
 	memmgr_final ();
 #endif
-	return;
 }
 
 void malloc_init (void)
@@ -687,5 +684,4 @@ void malloc_init (void)
 #ifdef USE_MEMMGR
 	memmgr_init ();
 #endif
-	return;
 }

+ 12 - 7
src/common/mmo.h

@@ -207,8 +207,19 @@ struct point {
 	short x,y;
 };
 
+enum e_skill_flag
+{
+	SKILL_FLAG_PERMANENT,
+	SKILL_FLAG_TEMPORARY,
+	SKILL_FLAG_PLAGIARIZED,
+	SKILL_FLAG_REPLACED_LV_0, // temporary skill overshadowing permanent skill of level 'N - SKILL_FLAG_REPLACED_LV_0'
+	//...
+};
+
 struct s_skill {
-	unsigned short id,lv,flag;
+	unsigned short id;
+	unsigned short lv;
+	unsigned short flag; // see enum e_skill_flag
 };
 
 struct global_reg {
@@ -508,12 +519,6 @@ struct guild_castle {
 	int temp_guardians_max;
 };
 
-// for Brandish Spear calculations
-struct square {
-	int val1[5];
-	int val2[5];
-};
-
 struct fame_list {
 	int id;
 	int fame;

+ 0 - 2
src/common/plugin.h

@@ -4,9 +4,7 @@
 #ifndef	_PLUGIN_H_
 #define _PLUGIN_H_
 
-#ifndef _CBASETYPES_H_
 #include "../common/cbasetypes.h"
-#endif
 
 ////// Plugin functions ///////////////
 

+ 0 - 3
src/common/plugins.h

@@ -4,10 +4,7 @@
 #ifndef	_PLUGINS_H_
 #define _PLUGINS_H_
 
-#ifndef _CBASETYPES_H_
 #include "../common/cbasetypes.h"
-#endif
-
 #include "../common/plugin.h"
 
 ////// Dynamic Link Library functions ///////////////

+ 83 - 0
src/common/random.c

@@ -0,0 +1,83 @@
+// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
+// For more information, see LICENCE in the main folder
+
+#include "../common/timer.h" // gettick
+#include "random.h"
+#if defined(WIN32)
+	#define WIN32_LEAN_AND_MEAN
+	#include <windows.h>
+#elif defined(HAVE_GETPID) || defined(HAVE_GETTID)
+	#include <sys/types.h>
+	#include <unistd.h>
+#endif
+#include <time.h> // time
+#include <mt19937ar.h> // init_genrand, genrand_int32, genrand_res53
+
+
+/// Initializes the random number generator with an appropriate seed.
+void rnd_init(void)
+{
+	uint32 seed = gettick();
+	seed += (uint32)time(NULL);
+#if defined(WIN32)
+	seed += GetCurrentProcessId();
+	seed += GetCurrentThreadId();
+#else
+#if defined(HAVE_GETPID)
+	seed += (uint32)getpid();
+#endif // HAVE_GETPID
+#if defined(HAVE_GETTID)
+	seed += (uint32)gettid();
+#endif // HAVE_GETTID
+#endif
+	init_genrand(seed);
+}
+
+
+/// Initializes the random number generator.
+void rnd_seed(uint32 seed)
+{
+	init_genrand(seed);
+}
+
+
+/// Generates a random number in the interval [0, UINT32_MAX]
+uint32 rnd(void)
+{
+	return (uint32)genrand_int32();
+}
+
+
+/// Generates a random number in the interval [0, dice_faces)
+/// NOTE: interval is open ended, so dice_faces is excluded (unless it's 0)
+uint32 rnd_roll(uint32 dice_faces)
+{
+	return (uint32)(rnd_uniform()*dice_faces);
+}
+
+
+/// Generates a random number in the interval [min, max]
+/// Returns min if range is invalid.
+int32 rnd_value(int32 min, int32 max)
+{
+	if( min >= max )
+		return min;
+	return min + (int32)(rnd_uniform()*(max-min+1));
+}
+
+
+/// Generates a random number in the interval [0.0, 1.0)
+/// NOTE: interval is open ended, so 1.0 is excluded
+double rnd_uniform(void)
+{
+	return ((uint32)genrand_int32())*(1.0/4294967296.0);// divided by 2^32
+}
+
+
+/// Generates a random number in the interval [0.0, 1.0) with 53-bit resolution
+/// NOTE: interval is open ended, so 1.0 is excluded
+/// NOTE: 53 bits is the maximum precision of a double
+double rnd_uniform53(void)
+{
+	return genrand_res53();
+}

+ 18 - 0
src/common/random.h

@@ -0,0 +1,18 @@
+// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
+// For more information, see LICENCE in the main folder
+
+#ifndef _RANDOM_H_
+#define _RANDOM_H_
+
+#include "../common/cbasetypes.h"
+
+void rnd_init(void);
+void rnd_seed(uint32);
+
+uint32 rnd(void);// [0, UINT32_MAX]
+uint32 rnd_roll(uint32 dice_faces);// [0, dice_faces)
+int32 rnd_value(int32 min, int32 max);// [min, max]
+double rnd_uniform(void);// [0.0, 1.0)
+double rnd_uniform53(void);// [0.0, 1.0)
+
+#endif /* _RANDOM_H_ */

+ 4 - 1
src/common/socket.c

@@ -938,7 +938,7 @@ static int connect_check_(uint32 ip)
 
 /// Timer function.
 /// Deletes old connection history records.
-static int connect_check_clear(int tid, unsigned int tick, int id, intptr data)
+static int connect_check_clear(int tid, unsigned int tick, int id, intptr_t data)
 {
 	int i;
 	int clear = 0;
@@ -1118,6 +1118,9 @@ void socket_final(void)
 /// Closes a socket.
 void do_close(int fd)
 {
+	if( fd <= 0 ||fd >= FD_SETSIZE )
+		return;// invalid
+
 	flush_fifo(fd); // Try to send what's left (although it might not succeed since it's a nonblocking socket)
 	sFD_CLR(fd, &readfds);// this needs to be done before closing the socket
 	sShutdown(fd, SHUT_RDWR); // Disallow further reads/writes

+ 0 - 2
src/common/socket.h

@@ -4,9 +4,7 @@
 #ifndef	_SOCKET_H_
 #define _SOCKET_H_
 
-#ifndef _CBASETYPES_H_
 #include "../common/cbasetypes.h"
-#endif
 
 #ifdef WIN32
 	#define WIN32_LEAN_AND_MEAN  // otherwise winsock2.h includes full windows.h

+ 2 - 2
src/common/sql.c

@@ -182,7 +182,7 @@ int Sql_Ping(Sql* self)
 /// Wrapper function for Sql_Ping.
 ///
 /// @private
-static int Sql_P_KeepaliveTimer(int tid, unsigned int tick, int id, intptr data)
+static int Sql_P_KeepaliveTimer(int tid, unsigned int tick, int id, intptr_t data)
 {
 	Sql* self = (Sql*)data;
 	ShowInfo("Pinging SQL server to keep connection alive...\n");
@@ -212,7 +212,7 @@ static int Sql_P_Keepalive(Sql* self)
 	// establish keepalive
 	ping_interval = timeout - 30; // 30-second reserve
 	//add_timer_func_list(Sql_P_KeepaliveTimer, "Sql_P_KeepaliveTimer");
-	return add_timer_interval(gettick() + ping_interval*1000, Sql_P_KeepaliveTimer, 0, (intptr)self, ping_interval*1000);
+	return add_timer_interval(gettick() + ping_interval*1000, Sql_P_KeepaliveTimer, 0, (intptr_t)self, ping_interval*1000);
 }
 
 

+ 0 - 2
src/common/sql.h

@@ -4,9 +4,7 @@
 #ifndef _COMMON_SQL_H_
 #define _COMMON_SQL_H_
 
-#ifndef _CBASETYPES_H_
 #include "../common/cbasetypes.h"
-#endif
 #include <stdarg.h>// va_list
 
 

+ 89 - 47
src/common/strlib.c

@@ -441,30 +441,13 @@ bool bin2hex(char* output, unsigned char* input, size_t count)
 
 
 /////////////////////////////////////////////////////////////////////
-/// Parses a delim-separated string.
-/// Starts parsing at startoff and fills the pos array with position pairs.
-/// out_pos[0] and out_pos[1] are the start and end of line.
-/// Other position pairs are the start and end of fields.
-/// Returns the number of fields found or -1 if an error occurs.
-/// 
-/// out_pos can be NULL.
-/// If a line terminator is found, the end position is placed there.
-/// out_pos[2] and out_pos[3] for the first field, out_pos[4] and out_pos[5] 
-/// for the seconds field and so on.
-/// Unfilled positions are set to -1.
-/// 
-/// @param str String to parse
-/// @param len Length of the string
-/// @param startoff Where to start parsing
-/// @param delim Field delimiter
-/// @param out_pos Array of resulting positions
-/// @param npos Size of the pos array
-/// @param opt Options that determine the parsing behaviour
-/// @return Number of fields found in the string or -1 if an error occured
-int sv_parse(const char* str, int len, int startoff, char delim, int* out_pos, int npos, enum e_svopt opt)
+/// Parses a single field in a delim-separated string.
+/// The delimiter after the field is skipped.
+///
+/// @param sv Parse state
+/// @return 1 if a field was parsed, 0 if already done, -1 on error.
+int sv_parse_next(struct s_svstate* sv)
 {
-	int i;
-	int count;
 	enum {
 		START_OF_FIELD,
 		PARSING_FIELD,
@@ -473,27 +456,37 @@ int sv_parse(const char* str, int len, int startoff, char delim, int* out_pos, i
 		TERMINATE,
 		END
 	} state;
+	const char* str;
+	int len;
+	enum e_svopt opt;
+	char delim;
+	int i;
 
-	// check pos/npos
-	if( out_pos == NULL ) npos = 0;
-	for( i = 0; i < npos; ++i )
-		out_pos[i] = -1;
+	if( sv == NULL )
+		return -1;// error
+
+	str = sv->str;
+	len = sv->len;
+	opt = sv->opt;
+	delim = sv->delim;
 
 	// check opt
 	if( delim == '\n' && (opt&(SV_TERMINATE_CRLF|SV_TERMINATE_LF)) )
 	{
-		ShowError("sv_parse: delimiter '\\n' is not compatible with options SV_TERMINATE_LF or SV_TERMINATE_CRLF.\n");
+		ShowError("sv_parse_next: delimiter '\\n' is not compatible with options SV_TERMINATE_LF or SV_TERMINATE_CRLF.\n");
 		return -1;// error
 	}
 	if( delim == '\r' && (opt&(SV_TERMINATE_CRLF|SV_TERMINATE_CR)) )
 	{
-		ShowError("sv_parse: delimiter '\\r' is not compatible with options SV_TERMINATE_CR or SV_TERMINATE_CRLF.\n");
+		ShowError("sv_parse_next: delimiter '\\r' is not compatible with options SV_TERMINATE_CR or SV_TERMINATE_CRLF.\n");
 		return -1;// error
 	}
 
-	// check str
-	if( str == NULL )
+	if( sv->done || str == NULL )
+	{
+		sv->done = true;
 		return 0;// nothing to parse
+	}
 
 #define IS_END() ( i >= len )
 #define IS_DELIM() ( str[i] == delim )
@@ -502,16 +495,13 @@ int sv_parse(const char* str, int len, int startoff, char delim, int* out_pos, i
 	((opt&SV_TERMINATE_CR) && str[i] == '\r') || \
 	((opt&SV_TERMINATE_CRLF) && i+1 < len && str[i] == '\r' && str[i+1] == '\n') )
 #define IS_C_ESCAPE() ( (opt&SV_ESCAPE_C) && str[i] == '\\' )
-#define SET_FIELD_START() if( npos > count*2+2 ) out_pos[count*2+2] = i
-#define SET_FIELD_END() if( npos > count*2+3 ) out_pos[count*2+3] = i; ++count
+#define SET_FIELD_START() sv->start = i
+#define SET_FIELD_END() sv->end = i
 
-	i = startoff;
-	count = 0;
+	i = sv->off;
 	state = START_OF_FIELD;
-	if( npos > 0 ) out_pos[0] = startoff;// start
 	while( state != END )
 	{
-		if( npos > 1 ) out_pos[1] = i;// end
 		switch( state )
 		{
 		case START_OF_FIELD:// record start of field and start parsing it
@@ -533,7 +523,7 @@ int sv_parse(const char* str, int len, int startoff, char delim, int* out_pos, i
 				++i;// '\\'
 				if( IS_END() )
 				{
-					ShowError("sv_parse: empty escape sequence\n");
+					ShowError("sv_parse_next: empty escape sequence\n");
 					return -1;
 				}
 				if( str[i] == 'x' )
@@ -541,7 +531,7 @@ int sv_parse(const char* str, int len, int startoff, char delim, int* out_pos, i
 					++i;// 'x'
 					if( IS_END() || !ISXDIGIT(str[i]) )
 					{
-						ShowError("sv_parse: \\x with no following hex digits\n");
+						ShowError("sv_parse_next: \\x with no following hex digits\n");
 						return -1;
 					}
 					do{
@@ -562,26 +552,22 @@ int sv_parse(const char* str, int len, int startoff, char delim, int* out_pos, i
 				}
 				else
 				{
-					ShowError("sv_parse: unknown escape sequence \\%c\n", str[i]);
+					ShowError("sv_parse_next: unknown escape sequence \\%c\n", str[i]);
 					return -1;
 				}
 				state = PARSING_FIELD;
 				break;
 			}
 
-		case END_OF_FIELD:// record end of field and continue
+		case END_OF_FIELD:// record end of field and stop
 			SET_FIELD_END();
+			state = END;
 			if( IS_END() )
-				state = END;
+				;// nothing else
 			else if( IS_DELIM() )
-			{
 				++i;// delim
-				state = START_OF_FIELD;
-			}
 			else if( IS_TERMINATOR() )
 				state = TERMINATE;
-			else
-				state = START_OF_FIELD;
 			break;
 
 		case TERMINATE:
@@ -592,10 +578,14 @@ int sv_parse(const char* str, int len, int startoff, char delim, int* out_pos, i
 			else
 				++i;// CR or LF
 #endif
+			sv->done = true;
 			state = END;
 			break;
 		}
 	}
+	if( IS_END() )
+		sv->done = true;
+	sv->off = i;
 
 #undef IS_END
 #undef IS_DELIM
@@ -604,6 +594,58 @@ int sv_parse(const char* str, int len, int startoff, char delim, int* out_pos, i
 #undef SET_FIELD_START
 #undef SET_FIELD_END
 
+	return 1;
+}
+
+
+/// Parses a delim-separated string.
+/// Starts parsing at startoff and fills the pos array with position pairs.
+/// out_pos[0] and out_pos[1] are the start and end of line.
+/// Other position pairs are the start and end of fields.
+/// Returns the number of fields found or -1 if an error occurs.
+/// 
+/// out_pos can be NULL.
+/// If a line terminator is found, the end position is placed there.
+/// out_pos[2] and out_pos[3] for the first field, out_pos[4] and out_pos[5] 
+/// for the seconds field and so on.
+/// Unfilled positions are set to -1.
+/// 
+/// @param str String to parse
+/// @param len Length of the string
+/// @param startoff Where to start parsing
+/// @param delim Field delimiter
+/// @param out_pos Array of resulting positions
+/// @param npos Size of the pos array
+/// @param opt Options that determine the parsing behaviour
+/// @return Number of fields found in the string or -1 if an error occured
+int sv_parse(const char* str, int len, int startoff, char delim, int* out_pos, int npos, enum e_svopt opt)
+{
+	struct s_svstate sv;
+	int count;
+
+	// initialize
+	if( out_pos == NULL ) npos = 0;
+	for( count = 0; count < npos; ++count )
+		out_pos[count] = -1;
+	sv.str = str;
+	sv.len = len;
+	sv.off = startoff;
+	sv.opt = opt;
+	sv.delim = delim;
+	sv.done = false;
+
+	// parse
+	count = 0;
+	if( npos > 0 ) out_pos[0] = startoff;
+	while( !sv.done )
+	{
+		++count;
+		if( sv_parse_next(&sv) <= 0 )
+			return -1;// error
+		if( npos > count*2 ) out_pos[count*2] = sv.start;
+		if( npos > count*2+1 ) out_pos[count*2+1] = sv.end;
+	}
+	if( npos > 1 ) out_pos[1] = sv.off;
 	return count;
 }
 

+ 21 - 2
src/common/strlib.h

@@ -4,9 +4,7 @@
 #ifndef _STRLIB_H_
 #define _STRLIB_H_
 
-#ifndef _CBASETYPES_H_
 #include "../common/cbasetypes.h"
-#endif
 #include <stdarg.h>
 
 #define __USE_GNU  // required to enable strnlen on some platforms
@@ -78,6 +76,27 @@ typedef enum e_svopt
 /// Other escape sequences supported by the C compiler.
 #define SV_ESCAPE_C_SUPPORTED "abtnvfr\?\"'\\"
 
+/// Parse state.
+/// The field is [start,end[
+struct s_svstate
+{
+	const char* str; //< string to parse
+	int len; //< string length
+	int off; //< current offset in the string
+	int start; //< where the field starts
+	int end; //< where the field ends
+	enum e_svopt opt; //< parse options
+	char delim; //< field delimiter
+	bool done; //< if all the text has been parsed
+};
+
+/// Parses a single field in a delim-separated string.
+/// The delimiter after the field is skipped.
+///
+/// @param sv Parse state
+/// @return 1 if a field was parsed, 0 if done, -1 on error.
+int sv_parse_next(struct s_svstate* sv);
+
 /// Parses a delim-separated string.
 /// Starts parsing at startoff and fills the pos array with position pairs.
 /// out_pos[0] and out_pos[1] are the start and end of line.

+ 2 - 2
src/common/timer.c

@@ -241,7 +241,7 @@ static int acquire_timer(void)
 
 /// Starts a new timer that is deleted once it expires (single-use).
 /// Returns the timer's id.
-int add_timer(unsigned int tick, TimerFunc func, int id, intptr data)
+int add_timer(unsigned int tick, TimerFunc func, int id, intptr_t data)
 {
 	int tid;
 	
@@ -259,7 +259,7 @@ int add_timer(unsigned int tick, TimerFunc func, int id, intptr data)
 
 /// Starts a new timer that automatically restarts itself (infinite loop until manually removed).
 /// Returns the timer's id, or INVALID_TIMER if it fails.
-int add_timer_interval(unsigned int tick, TimerFunc func, int id, intptr data, int interval)
+int add_timer_interval(unsigned int tick, TimerFunc func, int id, intptr_t data, int interval)
 {
 	int tid;
 

+ 4 - 6
src/common/timer.h

@@ -4,9 +4,7 @@
 #ifndef	_TIMER_H_
 #define	_TIMER_H_
 
-#ifndef _CBASETYPES_H_
 #include "../common/cbasetypes.h"
-#endif
 
 #define DIFF_TICK(a,b) ((int)((a)-(b)))
 
@@ -19,7 +17,7 @@
 
 // Struct declaration
 
-typedef int (*TimerFunc)(int tid, unsigned int tick, int id, intptr data);
+typedef int (*TimerFunc)(int tid, unsigned int tick, int id, intptr_t data);
 
 struct TimerData {
 	unsigned int tick;
@@ -30,7 +28,7 @@ struct TimerData {
 
 	// general-purpose storage
 	int id; 
-	intptr data;
+	intptr_t data;
 };
 
 // Function prototype declaration
@@ -38,8 +36,8 @@ struct TimerData {
 unsigned int gettick(void);
 unsigned int gettick_nocache(void);
 
-int add_timer(unsigned int tick, TimerFunc func, int id, intptr data);
-int add_timer_interval(unsigned int tick, TimerFunc func, int id, intptr data, int interval);
+int add_timer(unsigned int tick, TimerFunc func, int id, intptr_t data);
+int add_timer_interval(unsigned int tick, TimerFunc func, int id, intptr_t data, int interval);
 const struct TimerData* get_timer(int tid);
 int delete_timer(int tid, TimerFunc func);
 

+ 0 - 3
src/common/utils.h

@@ -4,10 +4,7 @@
 #ifndef _UTILS_H_
 #define _UTILS_H_
 
-#ifndef _CBASETYPES_H_
 #include "../common/cbasetypes.h"
-#endif
-
 #include <stdio.h> // FILE*
 
 // generate a hex dump of the first 'length' bytes of 'buffer'

+ 12 - 0
src/login/CMakeLists.txt

@@ -0,0 +1,12 @@
+
+#
+# setup
+#
+set( LOGIN_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR} )
+
+
+#
+# targets
+#
+add_subdirectory( txt )
+add_subdirectory( sql )

+ 22 - 11
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

+ 3 - 3
src/login/account_txt.c

@@ -58,7 +58,7 @@ static bool account_db_txt_iter_next(AccountDBIterator* self, struct mmo_account
 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 data);
+static int mmo_auth_sync_timer(int tid, unsigned int tick, int id, intptr_t data);
 
 /// public constructor
 AccountDB* account_db_txt(void)
@@ -183,7 +183,7 @@ static bool account_db_txt_init(AccountDB* self)
 
 	// 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)db, AUTH_SAVING_INTERVAL);
+	db->save_timer = add_timer_interval(gettick() + AUTH_SAVING_INTERVAL, mmo_auth_sync_timer, 0, (intptr_t)db, AUTH_SAVING_INTERVAL);
 
 	return true;
 }
@@ -634,7 +634,7 @@ static void mmo_auth_sync(AccountDB_TXT* db)
 	db->auths_before_save = AUTHS_BEFORE_SAVE;
 }
 
-static int mmo_auth_sync_timer(int tid, unsigned int tick, int id, intptr data)
+static int mmo_auth_sync_timer(int tid, unsigned int tick, int id, intptr_t data)
 {
 	AccountDB_TXT* db = (AccountDB_TXT*)data;
 

+ 2 - 2
src/login/ipban_sql.c

@@ -35,7 +35,7 @@ static Sql* sql_handle = NULL;
 static int cleanup_timer_id = INVALID_TIMER;
 static bool ipban_inited = false;
 
-int ipban_cleanup(int tid, unsigned int tick, int id, intptr data);
+int ipban_cleanup(int tid, unsigned int tick, int id, intptr_t data);
 
 
 // initialize
@@ -246,7 +246,7 @@ void ipban_log(uint32 ip)
 }
 
 // remove expired bans
-int ipban_cleanup(int tid, unsigned int tick, int id, intptr data)
+int ipban_cleanup(int tid, unsigned int tick, int id, intptr_t data)
 {
 	if( !login_config.ipban )
 		return 0;// ipban disabled

+ 102 - 28
src/login/login.c

@@ -101,7 +101,7 @@ struct online_login_data {
 };
 
 static DBMap* online_db; // int account_id -> struct online_login_data*
-static int waiting_disconnect_timer(int tid, unsigned int tick, int id, intptr data);
+static int waiting_disconnect_timer(int tid, unsigned int tick, int id, intptr_t data);
 
 static void* create_online_user(DBKey key, va_list args)
 {
@@ -138,7 +138,7 @@ void remove_online_user(int account_id)
 	idb_remove(online_db, account_id);
 }
 
-static int waiting_disconnect_timer(int tid, unsigned int tick, int id, intptr data)
+static int waiting_disconnect_timer(int tid, unsigned int tick, int id, intptr_t 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 )
@@ -176,7 +176,7 @@ static int online_data_cleanup_sub(DBKey key, void *data, va_list ap)
 	return 0;
 }
 
-static int online_data_cleanup(int tid, unsigned int tick, int id, intptr data)
+static int online_data_cleanup(int tid, unsigned int tick, int id, intptr_t data)
 {
 	online_db->foreach(online_db, online_data_cleanup_sub);
 	return 0;
@@ -190,7 +190,7 @@ int charif_sendallwos(int sfd, uint8* buf, size_t len)
 {
 	int i, c;
 
-	for( i = 0, c = 0; i < MAX_SERVERS; ++i )
+	for( i = 0, c = 0; i < ARRAYLENGTH(server); ++i )
 	{
 		int fd = server[i].fd;
 		if( session_isValid(fd) && fd != sfd )
@@ -206,10 +206,46 @@ int charif_sendallwos(int sfd, uint8* buf, size_t len)
 }
 
 
+/// Initializes a server structure.
+void chrif_server_init(int id)
+{
+	memset(&server[id], 0, sizeof(server[id]));
+	server[id].fd = -1;
+}
+
+
+/// Destroys a server structure.
+void chrif_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 chrif_server_reset(int id)
+{
+	online_db->foreach(online_db, online_db_setoffline, id); //Set all chars from this char server to offline.
+	chrif_server_destroy(id);
+	chrif_server_init(id);
+}
+
+
+/// Called when the connection to Char Server is disconnected.
+void chrif_on_disconnect(int id)
+{
+	ShowStatus("Char-server '%s' has disconnected.\n", server[id].name);
+	chrif_server_reset(id);
+}
+
+
 //-----------------------------------------------------
 // periodic ip address synchronization
 //-----------------------------------------------------
-static int sync_ip_addresses(int tid, unsigned int tick, int id, intptr data)
+static int sync_ip_addresses(int tid, unsigned int tick, int id, intptr_t data)
 {
 	uint8 buf[2];
 	ShowInfo("IP Sync in progress...\n");
@@ -381,9 +417,10 @@ int parse_fromchar(int fd)
 	uint32 ipl;
 	char ip[16];
 
-	ARR_FIND( 0, MAX_SERVERS, id, server[id].fd == fd );
-	if( id == MAX_SERVERS )
+	ARR_FIND( 0, ARRAYLENGTH(server), id, server[id].fd == fd );
+	if( id == ARRAYLENGTH(server) )
 	{// not a char server
+		ShowDebug("parse_fromchar: Disconnecting invalid session #%d (is not a char-server)\n", fd);
 		set_eof(fd);
 		do_close(fd);
 		return 0;
@@ -391,11 +428,9 @@ int parse_fromchar(int fd)
 
 	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);
+		server[id].fd = -1;
+		chrif_on_disconnect(id);
 		return 0;
 	}
 
@@ -424,8 +459,9 @@ int parse_fromchar(int fd)
 			RFIFOSKIP(fd,23);
 
 			node = (struct auth_node*)idb_get(auth_db, account_id);
-			if( node != NULL &&
-			    node->account_id == account_id &&
+			if( runflag == LOGINSERVER_ST_RUNNING &&
+				node != NULL &&
+				node->account_id == account_id &&
 				node->login_id1  == login_id1 &&
 				node->login_id2  == login_id2 &&
 				node->sex        == sex_num2str(sex) /*&&
@@ -1059,6 +1095,16 @@ void login_auth_ok(struct login_session_data* sd)
 	struct auth_node* node;
 	int i;
 
+	if( runflag != LOGINSERVER_ST_RUNNING )
+	{
+		// players can only login while running
+		WFIFOHEAD(fd,3);
+		WFIFOW(fd,0) = 0x81;
+		WFIFOB(fd,2) = 1;// server closed
+		WFIFOSET(fd,3);
+		return;
+	}
+
 	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);
@@ -1070,8 +1116,8 @@ void login_auth_ok(struct login_session_data* sd)
 	}
 
 	server_num = 0;
-	for( i = 0; i < MAX_SERVERS; ++i )
-		if( session_isValid(server[i].fd) )
+	for( i = 0; i < ARRAYLENGTH(server); ++i )
+		if( session_isActive(server[i].fd) )
 			server_num++;
 
 	if( server_num == 0 )
@@ -1133,7 +1179,7 @@ void login_auth_ok(struct login_session_data* sd)
 	memset(WFIFOP(fd,20), 0, 24);
 	WFIFOW(fd,44) = 0; // unknown
 	WFIFOB(fd,46) = sex_str2num(sd->sex);
-	for( i = 0, n = 0; i < MAX_SERVERS; ++i )
+	for( i = 0, n = 0; i < ARRAYLENGTH(server); ++i )
 	{
 		if( !session_isValid(server[i].fd) )
 			continue;
@@ -1404,7 +1450,11 @@ int parse_login(int fd)
 			login_log(session[fd]->client_addr, sd->userid, 100, message);
 
 			result = mmo_auth(sd);
-			if( result == -1 && sd->sex == 'S' && sd->account_id < MAX_SERVERS && server[sd->account_id].fd == -1 )
+			if( runflag == LOGINSERVER_ST_RUNNING &&
+				result == -1 &&
+				sd->sex == 'S' &&
+				sd->account_id >= 0 && sd->account_id < ARRAYLENGTH(server) &&
+				!session_isValid(server[sd->account_id].fd) )
 			{
 				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));
@@ -1592,7 +1642,7 @@ static AccountDB* get_account_engine(void)
 //--------------------------------------
 void do_final(void)
 {
-	int i, fd;
+	int i;
 
 	login_log(0, "login server", 100, "login server shutdown");
 	ShowStatus("Terminating...\n");
@@ -1614,15 +1664,15 @@ void do_final(void)
 	accounts = NULL; // destroyed in account_engines
 	online_db->destroy(online_db, NULL);
 	auth_db->destroy(auth_db, NULL);
+	
+	for( i = 0; i < ARRAYLENGTH(server); ++i )
+		chrif_server_destroy(i);
 
-	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);
-		}
+	if( login_fd != -1 )
+	{
+		do_close(login_fd);
+		login_fd = -1;
 	}
-	do_close(login_fd);
 
 	ShowStatus("Finished.\n");
 }
@@ -1640,6 +1690,24 @@ void set_server_type(void)
 	SERVER_TYPE = ATHENA_SERVER_LOGIN;
 }
 
+
+/// Called when a terminate signal is received.
+void do_shutdown(void)
+{
+	if( runflag != LOGINSERVER_ST_SHUTDOWN )
+	{
+		int id;
+		runflag = LOGINSERVER_ST_SHUTDOWN;
+		ShowStatus("Shutting down...\n");
+		// TODO proper shutdown procedure; kick all characters, wait for acks, ...  [FlavioJS]
+		for( id = 0; id < ARRAYLENGTH(server); ++id )
+			chrif_server_reset(id);
+		flush_fifos();
+		runflag = CORE_ST_STOP;
+	}
+}
+
+
 //------------------------------
 // Login server initialization
 //------------------------------
@@ -1657,9 +1725,9 @@ int do_init(int argc, char** argv)
 	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;
+	
+	for( i = 0; i < ARRAYLENGTH(server); ++i )
+		chrif_server_init(i);
 
 	// initialize logging
 	if( login_config.log_login )
@@ -1713,6 +1781,12 @@ int do_init(int argc, char** argv)
 
 	// server port open & binding
 	login_fd = make_listen_bind(login_config.login_ip, login_config.login_port);
+	
+	if( runflag != CORE_ST_STOP )
+	{
+		shutdown_callback = do_shutdown;
+		runflag = LOGINSERVER_ST_RUNNING;
+	}
 
 	ShowStatus("The login-server is "CL_GREEN"ready"CL_RESET" (Server is listening on the port %u).\n\n", login_config.login_port);
 	login_log(0, "login server", 100, "login server started");

+ 8 - 0
src/login/login.h

@@ -5,6 +5,14 @@
 #define _LOGIN_H_
 
 #include "../common/mmo.h" // NAME_LENGTH,SEX_*
+#include "../common/core.h" // CORE_ST_LAST
+
+enum E_LOGINSERVER_ST
+{
+	LOGINSERVER_ST_RUNNING = CORE_ST_LAST,
+	LOGINSERVER_ST_SHUTDOWN,
+	LOGINSERVER_ST_LAST
+};
 
 #define LOGIN_CONF_NAME "conf/login_athena.conf"
 #define LAN_CONF_NAME "conf/subnet_athena.conf"

+ 43 - 0
src/login/sql/CMakeLists.txt

@@ -0,0 +1,43 @@
+
+#
+# login sql
+#
+if( HAVE_common_sql )
+message( STATUS "Creating target login-server_sql" )
+set( SQL_LOGIN_HEADERS
+	"${LOGIN_SOURCE_DIR}/account.h"
+	"${LOGIN_SOURCE_DIR}/ipban.h"
+	"${LOGIN_SOURCE_DIR}/login.h"
+	"${LOGIN_SOURCE_DIR}/loginlog.h"
+	)
+set( SQL_LOGIN_SOURCES
+	"${LOGIN_SOURCE_DIR}/account_sql.c"
+	"${LOGIN_SOURCE_DIR}/ipban_sql.c"
+	"${LOGIN_SOURCE_DIR}/login.c"
+	"${LOGIN_SOURCE_DIR}/loginlog_sql.c"
+	)
+set( DEPENDENCIES common_sql )
+set( LIBRARIES ${GLOBAL_LIBRARIES} )
+set( INCLUDE_DIRS ${GLOBAL_INCLUDE_DIRS} )
+set( DEFINITIONS ${GLOBAL_DEFINITIONS} WITH_SQL )
+set( SOURCE_FILES ${COMMON_BASE_HEADERS} ${COMMON_SQL_HEADERS} ${SQL_LOGIN_HEADERS} ${SQL_LOGIN_SOURCES} )
+source_group( common FILES ${COMMON_BASE_HEADERS} ${COMMON_SQL_HEADERS} )
+source_group( login FILES ${SQL_LOGIN_HEADERS} ${SQL_LOGIN_SOURCES} )
+include_directories( ${INCLUDE_DIRS} )
+add_executable( login-server_sql ${SOURCE_FILES} )
+add_dependencies( login-server_sql ${DEPENDENCIES} )
+target_link_libraries( login-server_sql ${LIBRARIES} ${DEPENDENCIES} )
+set_target_properties( login-server_sql PROPERTIES COMPILE_DEFINITIONS "${DEFINITIONS}" )
+if( WITH_COMPONENT_RUNTIME )
+	cpack_add_component( Runtime_loginserver_sql DESCRIPTION "login-server (sql version)" DISPLAY_NAME "login-server_sql" GROUP Runtime )
+	install( TARGETS login-server_sql
+		DESTINATION "."
+		COMPONENT Runtime_loginserver_sql )
+endif()
+message( STATUS "Creating target login-server_sql - done" )
+set( HAVE_login-server_sql ON  CACHE BOOL "login-server_sql target is available" )
+mark_as_advanced( HAVE_login-server_sql )
+else()
+message( STATUS "Skipping target login-server_sql (requires common_sql)" )
+unset( HAVE_login-server_sql CACHE )
+endif()

+ 43 - 0
src/login/txt/CMakeLists.txt

@@ -0,0 +1,43 @@
+
+#
+# login txt
+#
+if( HAVE_common_base )
+message( STATUS "Creating target login-server" )
+set( TXT_LOGIN_HEADERS
+	"${LOGIN_SOURCE_DIR}/account.h"
+	"${LOGIN_SOURCE_DIR}/ipban.h"
+	"${LOGIN_SOURCE_DIR}/login.h"
+	"${LOGIN_SOURCE_DIR}/loginlog.h"
+	)
+set( TXT_LOGIN_SOURCES
+	"${LOGIN_SOURCE_DIR}/account_txt.c"
+	"${LOGIN_SOURCE_DIR}/ipban_txt.c"
+	"${LOGIN_SOURCE_DIR}/login.c"
+	"${LOGIN_SOURCE_DIR}/loginlog_txt.c"
+	)
+set( DEPENDENCIES common_base )
+set( LIBRARIES ${GLOBAL_LIBRARIES} )
+set( INCLUDE_DIRS ${GLOBAL_INCLUDE_DIRS} )
+set( DEFINITIONS ${GLOBAL_DEFINITIONS} WITH_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_DEFINITIONS "${DEFINITIONS}" )
+if( WITH_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()
+message( STATUS "Creating target login-server - done" )
+set( HAVE_login-server ON  CACHE BOOL "login-server target is available" )
+mark_as_advanced( HAVE_login-server )
+else()
+message( STATUS "Skipping target login-server (requires common_base)" )
+unset( HAVE_login-server CACHE )
+endif()

+ 12 - 0
src/map/CMakeLists.txt

@@ -0,0 +1,12 @@
+
+#
+# setup
+#
+set( MAP_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR} )
+
+
+#
+# targets
+#
+add_subdirectory( txt )
+add_subdirectory( sql )

+ 20 - 10
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

+ 4 - 18
src/map/atcommand.c

@@ -3988,23 +3988,9 @@ ACMD_FUNC(agitend2)
  *------------------------------------------*/
 ACMD_FUNC(mapexit)
 {
-	struct map_session_data* pl_sd;
-	struct s_mapiterator* iter;
-
 	nullpo_retr(-1, sd);
 
-	iter = mapit_getallusers();
-	for( pl_sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); pl_sd = (TBL_PC*)mapit_next(iter) )
-		if (sd->status.account_id != pl_sd->status.account_id)
-			clif_GM_kick(NULL, pl_sd);
-	mapit_free(iter);
-
-	clif_GM_kick(NULL, sd);
-	
-	flush_fifos();
-
-	runflag = 0;
-
+	do_shutdown();
 	return 0;
 }
 
@@ -7098,9 +7084,9 @@ ACMD_FUNC(mobinfo)
 				if (mob->mvpitem[i].p > 0) {
 					j++;
 					if (j == 1)
-						sprintf(atcmd_output2, " %s  %02.02f%%", item_data->name, (float)mob->mvpitem[i].p / 100);
+						sprintf(atcmd_output2, " %s  %02.02f%%", item_data->jname, (float)mob->mvpitem[i].p / 100);
 					else
-						sprintf(atcmd_output2, " - %s  %02.02f%%", item_data->name, (float)mob->mvpitem[i].p / 100);
+						sprintf(atcmd_output2, " - %s  %02.02f%%", item_data->jname, (float)mob->mvpitem[i].p / 100);
 					strcat(atcmd_output, atcmd_output2);
 				}
 			}
@@ -7117,7 +7103,7 @@ ACMD_FUNC(mobinfo)
 * @showmobs by KarLaeda
 * => For 5 sec displays the mobs on minimap
 *------------------------------------------*/
-int atshowmobs_timer(int tid, unsigned int tick, int id, intptr data)
+int atshowmobs_timer(int tid, unsigned int tick, int id, intptr_t data)
 {
 	struct map_session_data* sd = map_id2sd(id);
 	if( sd == NULL )

+ 3 - 3
src/map/battle.c

@@ -154,7 +154,7 @@ struct delay_damage {
 	unsigned short attack_type;
 };
 
-int battle_delay_damage_sub(int tid, unsigned int tick, int id, intptr data)
+int battle_delay_damage_sub(int tid, unsigned int tick, int id, intptr_t data)
 {
 	struct delay_damage *dat = (struct delay_damage *)data;
 	struct block_list *target = map_id2bl(dat->target);
@@ -208,7 +208,7 @@ int battle_delay_damage (unsigned int tick, int amotion, struct block_list *src,
 	dat->distance = distance_bl(src, target)+10; //Attack should connect regardless unless you teleported.
 	if (src->type != BL_PC && amotion > 1000)
 		amotion = 1000; //Aegis places a damage-delay cap of 1 sec to non player attacks. [Skotlex]
-	add_timer(tick+amotion, battle_delay_damage_sub, src->id, (intptr)dat);
+	add_timer(tick+amotion, battle_delay_damage_sub, src->id, (intptr_t)dat);
 	
 	return 0;
 }
@@ -1620,7 +1620,7 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo
 				case AS_SPLASHER:
 					skillratio += 400+50*skill_lv;
 					if(sd)
-						skillratio += 30 * pc_checkskill(sd,AS_POISONREACT);
+						skillratio += 20 * pc_checkskill(sd,AS_POISONREACT);
 					break;
 				case ASC_BREAKER:
 					skillratio += 100*skill_lv-100;

+ 13 - 14
src/map/battle.h

@@ -72,20 +72,19 @@ struct block_list* battle_getenemy(struct block_list *target, int type, int rang
 int battle_gettarget(struct block_list *bl);
 int battle_getcurrentskill(struct block_list *bl);
 
-//New definitions [Skotlex]
-#define BCT_ENEMY 0x020000
-//This should be (~BCT_ENEMY&BCT_ALL)
-#define BCT_NOENEMY 0x1d0000
-#define BCT_PARTY	0x040000
-//This should be (~BCT_PARTY&BCT_ALL)
-#define BCT_NOPARTY 0x1b0000
-#define BCT_GUILD	0x080000
-//This should be (~BCT_GUILD&BCT_ALL)
-#define BCT_NOGUILD 0x170000
-#define BCT_ALL 0x1f0000
-#define BCT_NOONE 0x000000
-#define BCT_SELF 0x010000
-#define BCT_NEUTRAL 0x100000
+enum e_battle_check_target
+{//New definitions [Skotlex]
+	BCT_ENEMY   = 0x020000,
+	BCT_NOENEMY = 0x1d0000, //This should be (~BCT_ENEMY&BCT_ALL)
+	BCT_PARTY	= 0x040000,
+	BCT_NOPARTY = 0x1b0000, //This should be (~BCT_PARTY&BCT_ALL)
+	BCT_GUILD	= 0x080000,
+	BCT_NOGUILD = 0x170000, //This should be (~BCT_GUILD&BCT_ALL)
+	BCT_ALL     = 0x1f0000,
+	BCT_NOONE   = 0x000000,
+	BCT_SELF    = 0x010000,
+	BCT_NEUTRAL = 0x100000,
+};
 
 #define	is_boss(bl)	(status_get_mode(bl)&MD_BOSS)	// Can refine later [Aru]
 

+ 1 - 1
src/map/battleground.c

@@ -236,7 +236,7 @@ int bg_send_xy_timer_sub(DBKey key, void *data, va_list ap)
 	return 0;
 }
 
-int bg_send_xy_timer(int tid, unsigned int tick, int id, intptr data)
+int bg_send_xy_timer(int tid, unsigned int tick, int id, intptr_t data)
 {
 	bg_team_db->foreach(bg_team_db, bg_send_xy_timer_sub, tick);
 	return 0;

+ 1 - 1
src/map/buyingstore.c

@@ -145,7 +145,7 @@ void buyingstore_create(struct map_session_data* sd, int zenylimit, unsigned cha
 
 		if( i )
 		{// duplicate check. as the client does this too, only malicious intent should be caught here
-			ARR_FIND( 0, i, listidx, sd->buyingstore.items[i].nameid == nameid );
+			ARR_FIND( 0, i, listidx, sd->buyingstore.items[listidx].nameid == nameid );
 			if( listidx != i )
 			{// duplicate
 				ShowWarning("buyingstore_create: Found duplicate item on buying list (nameid=%hu, amount=%hu, account_id=%d, char_id=%d).\n", nameid, amount, sd->status.account_id, sd->status.char_id);

+ 74 - 40
src/map/chrif.c

@@ -31,6 +31,8 @@
 #include <sys/types.h>
 #include <time.h>
 
+static int check_connect_char_server(int tid, unsigned int tick, int id, intptr_t data);
+
 static struct eri *auth_db_ers; //For reutilizing player login structures.
 static DBMap* auth_db; // int id -> struct auth_node*
 
@@ -94,7 +96,7 @@ static const int packet_len_table[0x3d] = { // U - used, F - free
 //2b27: Incoming, chrif_authfail -> 'client authentication failed'
 
 int chrif_connected = 0;
-int char_fd = 0; //Using 0 instead of -1 is safer against crashes. [Skotlex]
+int char_fd = -1;
 int srvinfo;
 static char char_ip_str[128];
 static uint32 char_ip = 0;
@@ -110,6 +112,28 @@ int other_mapserver_count=0; //Holds count of how many other map servers are onl
 //This define should spare writing the check in every function. [Skotlex]
 #define chrif_check(a) { if(!chrif_isconnected()) return a; }
 
+
+/// Resets all the data.
+void chrif_reset(void)
+{
+	// TODO kick everyone out and reset everything [FlavioJS]
+	exit(EXIT_FAILURE);
+}
+
+
+/// Checks the conditions for the server to stop.
+/// Releases the cookie when all characters are saved.
+/// If all the conditions are met, it stops the core loop.
+void chrif_check_shutdown(void)
+{
+	if( runflag != MAPSERVER_ST_SHUTDOWN )
+		return;
+	if( auth_db->size(auth_db) > 0 )
+		return;
+	runflag = CORE_ST_STOP;
+}
+
+
 struct auth_node* chrif_search(int account_id)
 {
 	return (struct auth_node*)idb_get(auth_db, account_id);
@@ -244,9 +268,8 @@ int chrif_save(struct map_session_data *sd, int flag)
 {
 	nullpo_retr(-1, sd);
 
-	if (!flag) //The flag check is needed to prevent 'nosave' taking effect when a jailed player logs out.
-		pc_makesavestatus(sd);
-	
+	pc_makesavestatus(sd);
+
 	if (flag && sd->state.active) //Store player data which is quitting.
 	{
 		//FIXME: SC are lost if there's no connection at save-time because of the way its related data is cleared immediately after this function. [Skotlex]
@@ -363,6 +386,7 @@ int chrif_removemap(int fd)
 static void chrif_save_ack(int fd)
 {
 	chrif_auth_delete(RFIFOL(fd,2), RFIFOL(fd,6), ST_LOGOUT);
+	chrif_check_shutdown();
 }
 
 // request to move a character between mapservers
@@ -472,19 +496,13 @@ static int chrif_reconnect(DBKey key,void *data,va_list ap)
 	return 0;
 }
 
-/*==========================================
- *
- *------------------------------------------*/
-int chrif_sendmapack(int fd)
-{
-	if (RFIFOB(fd,2)) {
-		ShowFatalError("chrif : send map list to char server failed %d\n", RFIFOB(fd,2));
-		exit(EXIT_FAILURE);
-	}
 
-	memcpy(wisp_server_name, RFIFOP(fd,3), NAME_LENGTH);
-	ShowStatus("Map sending complete. Map Server is now online.\n");
+/// Called when all the connection steps are completed.
+void chrif_on_ready(void)
+{
+	ShowStatus("Map Server is now online.\n");
 	chrif_state = 2;
+	chrif_check_shutdown();
 
 	//If there are players online, send them to the char-server. [Skotlex]
 	send_users_tochar();
@@ -494,7 +512,21 @@ int chrif_sendmapack(int fd)
 
 	//Re-save any storages that were modified in the disconnection time. [Skotlex]
 	do_reconnect_storage();
+}
 
+
+/*==========================================
+ *
+ *------------------------------------------*/
+int chrif_sendmapack(int fd)
+{
+	if (RFIFOB(fd,2)) {
+		ShowFatalError("chrif : send map list to char server failed %d\n", RFIFOB(fd,2));
+		exit(EXIT_FAILURE);
+	}
+
+	memcpy(wisp_server_name, RFIFOP(fd,3), NAME_LENGTH);
+	chrif_on_ready();
 	return 0;
 }
 
@@ -592,7 +624,8 @@ void chrif_authok(int fd)
 	}
 
 	sd = node->sd;
-	if(node->char_dat == NULL &&
+	if( runflag == MAPSERVER_ST_RUNNING &&
+		node->char_dat == NULL &&
 		node->account_id == account_id &&
 		node->char_id == char_id &&
 		node->login_id1 == login_id1 )
@@ -661,7 +694,7 @@ int auth_db_cleanup_sub(DBKey key,void *data,va_list ap)
 	return 0;
 }
 
-int auth_db_cleanup(int tid, unsigned int tick, int id, intptr data)
+int auth_db_cleanup(int tid, unsigned int tick, int id, intptr_t data)
 {
 	if(!chrif_isconnected()) return 0;
 	auth_db->foreach(auth_db, auth_db_cleanup_sub);
@@ -838,7 +871,7 @@ int chrif_changedsex(int fd)
 		if ((sd->class_&MAPID_UPPERMASK) == MAPID_BARDDANCER) {
 			// remove specifical skills of Bard classes 
 			for(i = 315; i <= 322; i++) {
-				if (sd->status.skill[i].id > 0 && !sd->status.skill[i].flag) {
+				if (sd->status.skill[i].id > 0 && sd->status.skill[i].flag == SKILL_FLAG_PERMANENT) {
 					sd->status.skill_point += sd->status.skill[i].lv;
 					sd->status.skill[i].id = 0;
 					sd->status.skill[i].lv = 0;
@@ -846,7 +879,7 @@ int chrif_changedsex(int fd)
 			}
 			// remove specifical skills of Dancer classes 
 			for(i = 323; i <= 330; i++) {
-				if (sd->status.skill[i].id > 0 && !sd->status.skill[i].flag) {
+				if (sd->status.skill[i].id > 0 && sd->status.skill[i].flag == SKILL_FLAG_PERMANENT) {
 					sd->status.skill_point += sd->status.skill[i].lv;
 					sd->status.skill[i].id = 0;
 					sd->status.skill[i].lv = 0;
@@ -1292,22 +1325,22 @@ int chrif_char_online(struct map_session_data *sd)
 	return 0;
 }
 
-int chrif_disconnect(int fd)
+
+/// Called when the connection to Char Server is disconnected.
+void chrif_on_disconnect(void)
 {
-	if(fd == char_fd) {
-		char_fd = 0;
-		ShowWarning("Map Server disconnected from Char Server.\n\n");
-		chrif_connected = 0;
-		
-	 	other_mapserver_count=0; //Reset counter. We receive ALL maps from all map-servers on reconnect.
-		map_eraseallipport();
+	if( chrif_connected != 1 )
+		ShowWarning("Connection to Char Server lost.\n\n");
+	chrif_connected = 0;
+	
+ 	other_mapserver_count = 0; //Reset counter. We receive ALL maps from all map-servers on reconnect.
+	map_eraseallipport();
 
-		//Attempt to reconnect in a second. [Skotlex]
-		add_timer(gettick() + 1000, check_connect_char_server, 0, 0);
-	}
-	return 0;
+	//Attempt to reconnect in a second. [Skotlex]
+	add_timer(gettick() + 1000, check_connect_char_server, 0, 0);
 }
 
+
 void chrif_update_ip(int fd)
 {
 	uint32 new_ip;
@@ -1352,10 +1385,9 @@ int chrif_parse(int fd)
 
 	if (session[fd]->flag.eof)
 	{
-		if (chrif_connected == 1)
-			chrif_disconnect(fd);
-
 		do_close(fd);
+		char_fd = -1;
+		chrif_on_disconnect();
 		return 0;
 	}
 
@@ -1393,7 +1425,7 @@ int chrif_parse(int fd)
 		case 0x2afb: chrif_sendmapack(fd); break;
 		case 0x2afd: chrif_authok(fd); break;
 		case 0x2b00: map_setusers(RFIFOL(fd,2)); chrif_keepalive(fd); break;
-		case 0x2b03: clif_charselectok(RFIFOL(fd,2)); break;
+		case 0x2b03: clif_charselectok(RFIFOL(fd,2), RFIFOB(fd,6)); break;
 		case 0x2b04: chrif_recvmap(fd); break;
 		case 0x2b06: chrif_changemapserverack(RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10), RFIFOL(fd,14), RFIFOW(fd,18), RFIFOW(fd,20), RFIFOW(fd,22), RFIFOL(fd,24), RFIFOW(fd,28)); break;
 		case 0x2b09: map_addnickdb(RFIFOL(fd,2), (char*)RFIFOP(fd,6)); break;
@@ -1423,7 +1455,7 @@ int chrif_parse(int fd)
 	return 0;
 }
 
-int ping_char_server(int tid, unsigned int tick, int id, intptr data)
+int ping_char_server(int tid, unsigned int tick, int id, intptr_t data)
 {
 	chrif_check(-1);
 	chrif_keepalive(char_fd);
@@ -1431,7 +1463,7 @@ int ping_char_server(int tid, unsigned int tick, int id, intptr data)
 }
 
 // unused
-int send_usercount_tochar(int tid, unsigned int tick, int id, intptr data)
+int send_usercount_tochar(int tid, unsigned int tick, int id, intptr_t data)
 {
 	chrif_check(-1);
 
@@ -1476,7 +1508,7 @@ int send_users_tochar(void)
  * timer関数
  * char鯖との接続を確認し、もし切れていたら再度接続する
  *------------------------------------------*/
-int check_connect_char_server(int tid, unsigned int tick, int id, intptr data)
+static int check_connect_char_server(int tid, unsigned int tick, int id, intptr_t data)
 {
 	static int displayed = 0;
 	if (char_fd <= 0 || session[char_fd] == NULL)
@@ -1491,7 +1523,6 @@ int check_connect_char_server(int tid, unsigned int tick, int id, intptr data)
 		char_fd = make_connection(char_ip, char_port);
 		if (char_fd == -1)
 		{	//Attempt to connect later. [Skotlex]
-			char_fd = 0;
 			return 0;
 		}
 
@@ -1532,8 +1563,11 @@ int auth_db_final(DBKey k,void *d,va_list ap)
  *------------------------------------------*/
 int do_final_chrif(void)
 {
-	if (char_fd > 0)
+	if( char_fd != -1 )
+	{
 		do_close(char_fd);
+		char_fd = -1;
+	}
 
 	auth_db->destroy(auth_db, auth_db_final);
 	ers_destroy(auth_db_ers);

+ 1 - 1
src/map/chrif.h

@@ -25,6 +25,7 @@ int chrif_setip(const char* ip);
 void chrif_setport(uint16 port);
 
 int chrif_isconnected(void);
+void chrif_check_shutdown(void);
 
 extern int chrif_connected;
 extern int other_mapserver_count;
@@ -55,7 +56,6 @@ int send_users_tochar(void);
 int chrif_char_online(struct map_session_data *sd);
 int chrif_changesex(struct map_session_data *sd);
 int chrif_chardisconnect(struct map_session_data *sd);
-int check_connect_char_server(int tid, unsigned int tick, int id, intptr data);
 int chrif_divorce(int partner_id1, int partner_id2);
 
 int do_final_chrif(void);

+ 101 - 59
src/map/clif.c

@@ -581,10 +581,10 @@ int clif_authfail_fd(int fd, int type)
 	return 0;
 }
 
-/*==========================================
- *
- *------------------------------------------*/
-int clif_charselectok(int id)
+/// Reply from char-server.
+/// Tells the player if it can connect to the char-server to select a character.
+/// ok=1 : client disconnects and tries to connect to the char-server
+int clif_charselectok(int id, uint8 ok)
 {
 	struct map_session_data* sd;
 	int fd;
@@ -595,7 +595,7 @@ int clif_charselectok(int id)
 	fd = sd->fd;
 	WFIFOHEAD(fd,packet_len(0xb3));
 	WFIFOW(fd,0) = 0xb3;
-	WFIFOB(fd,2) = 1;
+	WFIFOB(fd,2) = ok;
 	WFIFOSET(fd,packet_len(0xb3));
 
 	return 0;
@@ -700,7 +700,7 @@ int clif_clearunit_area(struct block_list* bl, clr_type type)
 	return 0;
 }
 
-static int clif_clearunit_delayed_sub(int tid, unsigned int tick, int id, intptr data)
+static int clif_clearunit_delayed_sub(int tid, unsigned int tick, int id, intptr_t data)
 {
 	struct block_list *bl = (struct block_list *)data;
 	clif_clearunit_area(bl, CLR_OUTSIGHT);
@@ -713,7 +713,7 @@ int clif_clearunit_delayed(struct block_list* bl, unsigned int tick)
 	struct block_list *tbl;
 	tbl = (struct block_list*)aMalloc(sizeof (struct block_list));
 	memcpy (tbl, bl, sizeof (struct block_list));
-	add_timer(tick, clif_clearunit_delayed_sub, 0, (intptr)tbl);
+	add_timer(tick, clif_clearunit_delayed_sub, 0, (intptr_t)tbl);
 	return 0;
 }
 
@@ -1376,6 +1376,12 @@ static void clif_move2(struct block_list *bl, struct view_data *vd, struct unit_
 				clif_specialeffect(&md->bl,421,AREA);
 		}
 		break;
+	case BL_PET:
+		if( vd->head_bottom )
+		{// needed to display pet equip properly
+			clif_pet_equip_area((TBL_PET*)bl); 
+		}
+		break;
 	}
 	return;
 }
@@ -1415,7 +1421,7 @@ void clif_move(struct unit_data *ud)
 /*==========================================
  * Delays the map_quit of a player after they are disconnected. [Skotlex]
  *------------------------------------------*/
-static int clif_delayquit(int tid, unsigned int tick, int id, intptr data)
+static int clif_delayquit(int tid, unsigned int tick, int id, intptr_t data)
 {
 	struct map_session_data *sd = NULL;
 
@@ -4192,7 +4198,7 @@ int clif_skillinfoblock(struct map_session_data *sd)
 			WFIFOW(fd,len+8) = skill_get_sp(id,sd->status.skill[i].lv);
 			WFIFOW(fd,len+10)= skill_get_range2(&sd->bl, id,sd->status.skill[i].lv);
 			safestrncpy((char*)WFIFOP(fd,len+12), skill_get_name(id), NAME_LENGTH);
-			if(sd->status.skill[i].flag == 0)
+			if(sd->status.skill[i].flag == SKILL_FLAG_PERMANENT)
 				WFIFOB(fd,len+36) = (sd->status.skill[i].lv < skill_tree_get_max(id, sd->status.class_))? 1:0;
 			else
 				WFIFOB(fd,len+36) = 0;
@@ -4229,7 +4235,7 @@ int clif_addskill(struct map_session_data *sd, int id )
 	WFIFOW(fd,10) = skill_get_sp(id,sd->status.skill[id].lv);
     WFIFOW(fd,12)= skill_get_range2(&sd->bl, id,sd->status.skill[id].lv);
     safestrncpy((char*)WFIFOP(fd,14), skill_get_name(id), NAME_LENGTH);
-    if( sd->status.skill[id].flag == 0 )
+    if( sd->status.skill[id].flag == SKILL_FLAG_PERMANENT )
         WFIFOB(fd,38) = (sd->status.skill[id].lv < skill_tree_get_max(id, sd->status.class_))? 1:0;
     else
         WFIFOB(fd,38) = 0;
@@ -4279,38 +4285,49 @@ int clif_skillup(struct map_session_data *sd,int skill_num)
 	return 0;
 }
 
-/*==========================================
- * スキル詠唱エフェクトを送信する
- * pl:
- * 0 = Yellow cast aura
- * 1 = Water elemental cast aura
- * 2 = Earth elemental cast aura
- * 3 = Fire elemental cast aura
- * 4 = Wind elemental cast aura
- * 5 = Poison elemental cast aura
- * 6 = White cast aura
- * ? = like 0
- *------------------------------------------*/
-int clif_skillcasting(struct block_list* bl,
-	int src_id,int dst_id,int dst_x,int dst_y,int skill_num,int pl, int casttime)
+
+/// Notifies clients, that an object is about to use a skill (ZC_USESKILL_ACK/ZC_USESKILL_ACK2)
+/// 013e <src id>.L <dst id>.L <x pos>.W <y pos>.W <skill id>.W <property>.L <delaytime>.L
+/// 07fb <src id>.L <dst id>.L <x pos>.W <y pos>.W <skill id>.W <property>.L <delaytime>.L <is disposable>.B
+/// property:
+///     0 = Yellow cast aura
+///     1 = Water elemental cast aura
+///     2 = Earth elemental cast aura
+///     3 = Fire elemental cast aura
+///     4 = Wind elemental cast aura
+///     5 = Poison elemental cast aura
+///     6 = Holy elemental cast aura
+///     ? = like 0
+/// is disposable:
+///     0 = yellow chat text "[src name] will use skill [skill name]."
+///     1 = no text
+void clif_skillcasting(struct block_list* bl, int src_id, int dst_id, int dst_x, int dst_y, int skill_num, int property, int casttime)
 {
+#if PACKETVER < 20091124
+	const int cmd = 0x13e;
+#else
+	const int cmd = 0x7fb;
+#endif
 	unsigned char buf[32];
-	WBUFW(buf,0) = 0x13e;
+
+	WBUFW(buf,0) = cmd;
 	WBUFL(buf,2) = src_id;
 	WBUFL(buf,6) = dst_id;
 	WBUFW(buf,10) = dst_x;
 	WBUFW(buf,12) = dst_y;
 	WBUFW(buf,14) = skill_num;
-	WBUFL(buf,16) = pl<0?0:pl; //Avoid sending negatives as element [Skotlex]
+	WBUFL(buf,16) = property<0?0:property; //Avoid sending negatives as element [Skotlex]
 	WBUFL(buf,20) = casttime;
+#if PACKETVER >= 20091124
+	WBUFB(buf,24) = 1;  // isDisposable
+#endif
+
 	if (disguised(bl)) {
-		clif_send(buf,packet_len(0x13e), bl, AREA_WOS);
+		clif_send(buf,packet_len(cmd), bl, AREA_WOS);
 		WBUFL(buf,2) = -src_id;
-		clif_send(buf,packet_len(0x13e), bl, SELF);
+		clif_send(buf,packet_len(cmd), bl, SELF);
 	} else
-		clif_send(buf,packet_len(0x13e), bl, AREA);
-
-	return 0;
+		clif_send(buf,packet_len(cmd), bl, AREA);
 }
 
 /*==========================================
@@ -5821,28 +5838,32 @@ void clif_partyinvitationstate(struct map_session_data* sd)
 	WFIFOSET(fd, packet_len(0x2c9));
 }
 
-/*==========================================
- * パーティ勧誘
- *------------------------------------------*/
-int clif_party_invite(struct map_session_data *sd,struct map_session_data *tsd)
+/// Party invitation request (ZC_REQ_JOIN_GROUP/ZC_PARTY_JOIN_REQ)
+/// 00fe <party id>.L <party name>.24B
+/// 02c6 <party id>.L <party name>.24B
+void clif_party_invite(struct map_session_data *sd,struct map_session_data *tsd)
 {
+#if PACKETVER < 20070821
+	const int cmd = 0xfe;
+#else
+	const int cmd = 0x2c6;
+#endif
 	int fd;
 	struct party_data *p;
 
-	nullpo_ret(sd);
-	nullpo_ret(tsd);
+	nullpo_retv(sd);
+	nullpo_retv(tsd);
 
 	fd=tsd->fd;
 
 	if( (p=party_search(sd->status.party_id))==NULL )
-		return 0;
+		return;
 
-	WFIFOHEAD(fd,packet_len(0xfe));
-	WFIFOW(fd,0)=0xfe;
-	WFIFOL(fd,2)=sd->status.account_id;  // FIXME: This is party_id
+	WFIFOHEAD(fd,packet_len(cmd));
+	WFIFOW(fd,0)=cmd;
+	WFIFOL(fd,2)=sd->status.party_id;
 	memcpy(WFIFOP(fd,6),p->party.name,NAME_LENGTH);
-	WFIFOSET(fd,packet_len(0xfe));
-	return 0;
+	WFIFOSET(fd,packet_len(cmd));
 }
 
 /*==========================================
@@ -7643,6 +7664,8 @@ int clif_refresh(struct map_session_data *sd)
 	clif_weather_check(sd);
 	if( sd->chatID )
 		chat_leavechat(sd,0);
+	if( sd->state.vending )
+		clif_openvending(sd, sd->bl.id, sd->vending);
 	if( pc_issit(sd) )
 		clif_sitting(&sd->bl); // FIXME: just send to self, not area
 	if( pc_isdead(sd) ) //When you refresh, resend the death packet.
@@ -7650,6 +7673,9 @@ int clif_refresh(struct map_session_data *sd)
 	else
 		clif_changed_dir(&sd->bl, SELF);
 
+	// unlike vending, resuming buyingstore crashes the client.
+	buyingstore_close(sd);
+
 #ifndef TXT_ONLY
 	mail_clear(sd);
 #endif
@@ -8371,6 +8397,12 @@ void clif_parse_WantToConnection(int fd, TBL_PC* sd)
 		return;
 	}
 
+	if( runflag != MAPSERVER_ST_RUNNING )
+	{// not allowed
+		clif_authfail_fd(fd,1);// server closed
+		return;
+	}
+
 	//Check for double login.
 	bl = map_id2bl(account_id);
 	if(bl && bl->type != BL_PC) {
@@ -10620,12 +10652,12 @@ void clif_parse_PartyInvite2(int fd, struct map_session_data *sd)
 	party_invite(sd, t_sd);
 }
 
-/*==========================================
- * Party invitation reply
- * S 00ff <account ID>.L <flag>.L
- * S 02c7 <account ID>.L <flag>.B
- * flag: 0-reject, 1-accept
- *------------------------------------------*/
+/// Party invitation reply (CZ_JOIN_GROUP/CZ_PARTY_JOIN_REQ_ACK)
+/// 00ff <party id>.L <flag>.L
+/// 02c7 <party id>.L <flag>.B
+/// flag:
+///     0 = reject
+///     1 = accept
 void clif_parse_ReplyPartyInvite(int fd,struct map_session_data *sd)
 {
 	party_reply_invite(sd,RFIFOL(fd,2),RFIFOL(fd,6));
@@ -11995,6 +12027,11 @@ void clif_parse_FriendsListAdd(int fd, struct map_session_data *sd)
 		return;
 	}
 
+	if( sd->bl.id == f_sd->bl.id )
+	{// adding oneself as friend
+		return;
+	}
+
 	// @noask [LuzZza]
 	if(f_sd->state.noask) {
 		clif_noask_sub(sd, f_sd, 5);
@@ -12037,6 +12074,11 @@ void clif_parse_FriendsListReply(int fd, struct map_session_data *sd)
 	char_id = RFIFOL(fd,6);
 	reply = RFIFOB(fd,10);
 
+	if( sd->bl.id == account_id )
+	{// adding oneself as friend
+		return;
+	}
+
 	f_sd = map_id2sd(account_id); //The account id is the same as the bl.id of players.
 	if (f_sd == NULL)
 		return;
@@ -12305,10 +12347,8 @@ void clif_parse_FeelSaveOk(int fd,struct map_session_data *sd)
 	sd->menuskill_val = sd->menuskill_id = 0;
 }
 
-/*==========================================
- * Question about Star Glaldiator save map [Komurka]
- *------------------------------------------*/
-void clif_parse_ReqFeel(int fd, struct map_session_data *sd, int skilllv)
+/// Star Gladiator's Feeling map confirmation prompt (ZC_STARPLACE)
+void clif_feel_req(int fd, struct map_session_data *sd, int skilllv)
 {
 	WFIFOHEAD(fd,packet_len(0x253));
 	WFIFOW(fd,0)=0x253;
@@ -13957,11 +13997,11 @@ int clif_instance(int instance_id, int type, int flag)
 	switch( type )
 	{
 	case 1:
-		// S 0x2cb <Instance name>.63B <Standby Position>.W
+		// S 0x2cb <Instance name>.61B <Standby Position>.W
 		// Required to start the instancing information window on Client
 		// This window re-appear each "refresh" of client automatically until type 4 is send to client.
 		WBUFW(buf,0) = 0x02CB;
-		memcpy(WBUFP(buf,2),instance[instance_id].name,61);
+		memcpy(WBUFP(buf,2),instance[instance_id].name,INSTANCE_NAME_LENGTH);
 		WBUFW(buf,63) = flag;
 		clif_send(buf,packet_len(0x02CB),&sd->bl,PARTY);
 		break;
@@ -13989,14 +14029,16 @@ int clif_instance(int instance_id, int type, int flag)
 		}
 		clif_send(buf,packet_len(0x02CD),&sd->bl,PARTY);
 		break;
-	case 5: // R 02CE <message ID>.L
+	case 5:
 		// S 0x2ce <Message ID>.L
+		// 0 = Notification (EnterLimitDate update?)
 		// 1 = The Memorial Dungeon expired; it has been destroyed
 		// 2 = The Memorial Dungeon's entry time limit expired; it has been destroyed
 		// 3 = The Memorial Dungeon has been removed.
-		// 4 = Just remove the window, maybe party/guild leave
+		// 4 = Create failure (removes the instance window)
 		WBUFW(buf,0) = 0x02CE;
 		WBUFL(buf,2) = flag;
+		//WBUFL(buf,6) = EnterLimitDate;
 		clif_send(buf,packet_len(0x02CE),&sd->bl,PARTY);
 		break;
 	}
@@ -14911,7 +14953,7 @@ static int packetdb_readdb(void)
 	    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
 	   85, -1, -1,107,  6, -1,  7,  7, 22,191,  0,  0,  0,  0,  0,  0,
 	//#0x02C0
-	    0,  0,  0,  0,  0, 30,  0,  0,  0,  3,  0, 65,  4, 71, 10,  0,
+	    0,  0,  0,  0,  0, 30, 30,  0,  0,  3,  0, 65,  4, 71, 10,  0,
 	    0,  0,  0,  0, 29,  0,  6, -1, 10, 10,  3,  0, -1, 32,  6,  0,
 	    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 67, 59, 60,  8,
 	   10,  2,  2,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
@@ -15018,7 +15060,7 @@ static int packetdb_readdb(void)
 	    6,  2, -1,  4,  4,  4,  4,  8,  8,268,  6,  8,  6, 54, 30, 54,
 #endif
 	    0,  0,  0,  0,  0,  8,  8, 32, -1,  5,  0,  0,  0,  0,  0,  0,
-	    0,  0,  0,  0,  0,  0, 14, -1, -1, -1,  8,  0,  0,  0, 26,  0,
+	    0,  0,  0,  0,  0,  0, 14, -1, -1, -1,  8, 25,  0,  0, 26,  0,
 	//#0x0800
 #if PACKETVER < 20091229
  	   -1, -1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 14, 20,

+ 4 - 4
src/map/clif.h

@@ -220,7 +220,7 @@ uint16 clif_getport(void);
 
 int clif_authok(struct map_session_data *);
 int clif_authfail_fd(int fd,int type);
-int clif_charselectok(int);
+int clif_charselectok(int id, uint8 ok);
 int clif_dropflooritem(struct flooritem_data *);
 int clif_clearflooritem(struct flooritem_data *,int);
 
@@ -326,7 +326,7 @@ int clif_skillup(struct map_session_data *sd,int skill_num);
 int clif_addskill(struct map_session_data *sd, int skill);
 int clif_deleteskill(struct map_session_data *sd, int skill);
 
-int clif_skillcasting(struct block_list* bl,int src_id,int dst_id,int dst_x,int dst_y,int skill_num,int pl,int casttime);
+void clif_skillcasting(struct block_list* bl, int src_id, int dst_id, int dst_x, int dst_y, int skill_num, int property, int casttime);
 int clif_skillcastcancel(struct block_list* bl);
 int clif_skill_fail(struct map_session_data *sd,int skill_id,int type,int btype);
 int clif_skill_cooldown(struct map_session_data *sd, int skillid, unsigned int tick);
@@ -404,7 +404,7 @@ int clif_movetoattack(struct map_session_data *sd,struct block_list *bl);
 int clif_party_created(struct map_session_data *sd,int result);
 int clif_party_member_info(struct party_data *p, struct map_session_data *sd);
 int clif_party_info(struct party_data *p, struct map_session_data *sd);
-int clif_party_invite(struct map_session_data *sd,struct map_session_data *tsd);
+void clif_party_invite(struct map_session_data *sd,struct map_session_data *tsd);
 void clif_party_inviteack(struct map_session_data* sd, const char* nick, int flag);
 int clif_party_option(struct party_data *p,struct map_session_data *sd,int flag);
 int clif_party_withdraw(struct party_data* p, struct map_session_data* sd, int account_id, const char* name, int flag);
@@ -515,7 +515,7 @@ void clif_get_weapon_view(struct map_session_data* sd, unsigned short *rhand, un
 
 int clif_party_xy_remove(struct map_session_data *sd); //Fix for minimap [Kevin]
 void clif_gospel_info(struct map_session_data *sd, int type);
-void clif_parse_ReqFeel(int fd, struct map_session_data *sd, int skilllv); 
+void clif_feel_req(int fd, struct map_session_data *sd, int skilllv); 
 void clif_starskill(struct map_session_data* sd, const char* mapname, int monster_id, unsigned char star, unsigned char result);
 void clif_feel_info(struct map_session_data *sd, unsigned char feel_level, unsigned char type);
 void clif_hate_info(struct map_session_data *sd, unsigned char hate_level,int class_, unsigned char type);

+ 5 - 5
src/map/guild.c

@@ -61,8 +61,8 @@ struct{
 	}need[6];
 } guild_skill_tree[MAX_GUILDSKILL];
 
-int guild_payexp_timer(int tid, unsigned int tick, int id, intptr data);
-static int guild_send_xy_timer(int tid, unsigned int tick, int id, intptr data);
+int guild_payexp_timer(int tid, unsigned int tick, int id, intptr_t data);
+static int guild_send_xy_timer(int tid, unsigned int tick, int id, intptr_t data);
 
 /*==========================================
  * Retrieves and validates the sd pointer for this guild member [Skotlex]
@@ -308,7 +308,7 @@ int guild_payexp_timer_sub(DBKey dataid, void *data, va_list ap)
 	return 0;
 }
 
-int guild_payexp_timer(int tid, unsigned int tick, int id, intptr data)
+int guild_payexp_timer(int tid, unsigned int tick, int id, intptr_t data)
 {
 	guild_expcache_db->clear(guild_expcache_db,guild_payexp_timer_sub);
 	return 0;
@@ -336,7 +336,7 @@ int guild_send_xy_timer_sub(DBKey key,void *data,va_list ap)
 }
 
 //Code from party_send_xy_timer [Skotlex]
-static int guild_send_xy_timer(int tid, unsigned int tick, int id, intptr data)
+static int guild_send_xy_timer(int tid, unsigned int tick, int id, intptr_t data)
 {
 	guild_db->foreach(guild_db,guild_send_xy_timer_sub,tick);
 	return 0;
@@ -1840,7 +1840,7 @@ int guild_castlealldataload(int len,struct guild_castle *gc)
 		}
 
 		// update mapserver castle data with new info
-		memcpy(&c->guild_id, &gc->guild_id, sizeof(struct guild_castle) - ((uintptr)&c->guild_id - (uintptr)c));
+		memcpy(&c->guild_id, &gc->guild_id, sizeof(struct guild_castle) - ((uintptr_t)&c->guild_id - (uintptr_t)c));
 
 		if( c->guild_id )
 		{

+ 3 - 3
src/map/homunculus.c

@@ -45,7 +45,7 @@
 struct s_homunculus_db homunculus_db[MAX_HOMUNCULUS_CLASS];	//[orn]
 struct skill_tree_entry hskill_tree[MAX_HOMUNCULUS_CLASS][MAX_SKILL_TREE];
 
-static int merc_hom_hungry(int tid, unsigned int tick, int id, intptr data);
+static int merc_hom_hungry(int tid, unsigned int tick, int id, intptr_t data);
 
 static unsigned int hexptbl[MAX_LEVEL];
 
@@ -196,7 +196,7 @@ void merc_hom_skillup(struct homun_data *hd,int skillnum)
 	i = skillnum - HM_SKILLBASE;
 	if(hd->homunculus.skillpts > 0 &&
 		hd->homunculus.hskill[i].id &&
-		hd->homunculus.hskill[i].flag == 0 && //Don't allow raising while you have granted skills. [Skotlex]
+		hd->homunculus.hskill[i].flag == SKILL_FLAG_PERMANENT && //Don't allow raising while you have granted skills. [Skotlex]
 		hd->homunculus.hskill[i].lv < merc_skill_tree_get_max(skillnum, hd->homunculus.class_)
 		)
 	{
@@ -480,7 +480,7 @@ int merc_hom_food(struct map_session_data *sd, struct homun_data *hd)
 	return 0;
 }
 
-static int merc_hom_hungry(int tid, unsigned int tick, int id, intptr data)
+static int merc_hom_hungry(int tid, unsigned int tick, int id, intptr_t data)
 {
 	struct map_session_data *sd;
 	struct homun_data *hd;

+ 43 - 20
src/map/instance.c

@@ -28,6 +28,24 @@
 int instance_start = 0; // To keep the last index + 1 of normal map inserted in the map[ARRAY]
 struct s_instance instance[MAX_INSTANCE];
 
+
+/// Checks whether given instance id is valid or not.
+static bool instance_is_valid(int instance_id)
+{
+	if( instance_id < 1 || instance_id >= ARRAYLENGTH(instance) )
+	{// out of range
+		return false;
+	}
+
+	if( instance[instance_id].state == INSTANCE_FREE )
+	{// uninitialized/freed instance slot
+		return false;
+	}
+
+	return true;
+}
+
+
 /*--------------------------------------
  * name : instance name
  * Return value could be
@@ -62,13 +80,13 @@ int instance_create(int party_id, const char *name)
 	instance[i].idle_timer = INVALID_TIMER;
 	instance[i].idle_timeout = instance[i].idle_timeoutval = 0;
 	instance[i].progress_timer = INVALID_TIMER;
-	instance[i].progress_timeout = instance[i].progress_timeoutval = 0;
+	instance[i].progress_timeout = 0;
 	instance[i].users = 0;
 	instance[i].party_id = party_id;
 	instance[i].ivar = NULL;
 	instance[i].svar = NULL;
 
-	memcpy( instance[i].name, name, sizeof(instance[i].name) );
+	safestrncpy( instance[i].name, name, sizeof(instance[i].name) );
 	memset( instance[i].map, 0x00, sizeof(instance[i].map) );
 	p->instance_id = i;
 
@@ -88,7 +106,7 @@ int instance_add_map(const char *name, int instance_id, bool usebasename)
 	if( m < 0 )
 		return -1; // source map not found
 		
-	if( instance[instance_id].state == INSTANCE_FREE )
+	if( !instance_is_valid(instance_id) )
 	{
 		ShowError("instance_add_map: trying to attach '%s' map to non-existing instance %d.\n", name, instance_id);
 		return -1;
@@ -158,6 +176,12 @@ int instance_add_map(const char *name, int instance_id, bool usebasename)
 int instance_map2imap(int m, int instance_id)
 {
  	int i;
+
+	if( !instance_is_valid(instance_id) )
+	{
+		return -1;
+	}
+	
 	for( i = 0; i < instance[instance_id].num_map; i++ )
  	{
 		if( instance[instance_id].map[i] && map[instance[instance_id].map[i]].instance_src_map == m )
@@ -173,7 +197,6 @@ int instance_map2imap(int m, int instance_id)
  *--------------------------------------*/
 int instance_mapid2imapid(int m, int instance_id)
 {
-	int i, max;
 	if( map[m].flag.src4instance == 0 )
 		return m; // not instances found for this map
 	else if( map[m].instance_id )
@@ -182,16 +205,10 @@ int instance_mapid2imapid(int m, int instance_id)
 		return -1;
 	}
 
-	if( instance_id <= 0 )
+	if( !instance_is_valid(instance_id) )
 		return -1;
 
-	max = instance[instance_id].num_map;
-
-	for( i = 0; i < max; i++ )
-		if( map[instance[instance_id].map[i]].instance_src_map == m )
-			return instance[instance_id].map[i];
-
-	return -1;
+	return instance_map2imap(m, instance_id);
 }
 
 /*--------------------------------------
@@ -214,13 +231,13 @@ void instance_init(int instance_id)
 {
 	int i;
 
-	if( !instance_id )
+	if( !instance_is_valid(instance_id) )
 		return; // nothing to do
 
 	for( i = 0; i < instance[instance_id].num_map; i++ )
 		map_foreachinmap(instance_map_npcsub, map[instance[instance_id].map[i]].instance_src_map, BL_NPC, instance[instance_id].map[i]);
 
-	instance[instance_id].state = INSTANCE_BUSSY;
+	instance[instance_id].state = INSTANCE_BUSY;
 	ShowInfo("[Instance] Initialized %s.\n", instance[instance_id].name);
 }
 
@@ -294,7 +311,7 @@ void instance_destroy_freesvar(void *key, void *data, va_list args)
 /*--------------------------------------
  * Timer to destroy instance by process or idle
  *--------------------------------------*/
-int instance_destroy_timer(int tid, unsigned int tick, int id, intptr data)
+int instance_destroy_timer(int tid, unsigned int tick, int id, intptr_t data)
 {
 	instance_destroy(id);
 	return 0;
@@ -309,7 +326,7 @@ void instance_destroy(int instance_id)
 	struct party_data *p;
 	time_t now = time(NULL);
 
-	if( !instance_id || instance[instance_id].state == INSTANCE_FREE )
+	if( !instance_is_valid(instance_id) )
 		return; // nothing to do
 
 	if( instance[instance_id].progress_timeout && instance[instance_id].progress_timeout <= now )
@@ -361,7 +378,7 @@ void instance_check_idle(int instance_id)
 	bool idle = true;
 	time_t now = time(NULL);
 
-	if( !instance_id || instance[instance_id].idle_timeoutval == 0 )
+	if( !instance_is_valid(instance_id) || instance[instance_id].idle_timeoutval == 0 )
 		return;
 
 	if( instance[instance_id].users )
@@ -389,7 +406,7 @@ void instance_set_timeout(int instance_id, unsigned int progress_timeout, unsign
 {
 	time_t now = time(0);
 
-	if( !instance_id )
+	if( !instance_is_valid(instance_id) )
 		return;
 		
 	if( instance[instance_id].progress_timer != INVALID_TIMER )
@@ -399,13 +416,11 @@ void instance_set_timeout(int instance_id, unsigned int progress_timeout, unsign
 
 	if( progress_timeout )
 	{
-		instance[instance_id].progress_timeoutval = progress_timeout;
 		instance[instance_id].progress_timeout = now + progress_timeout;
 		instance[instance_id].progress_timer = add_timer( gettick() + progress_timeout * 1000, instance_destroy_timer, instance_id, 0);
 	}
 	else
 	{
-		instance[instance_id].progress_timeoutval = 0;
 		instance[instance_id].progress_timeout = 0;
 		instance[instance_id].progress_timer = INVALID_TIMER;
 	}
@@ -444,6 +459,14 @@ void instance_check_kick(struct map_session_data *sd)
 	}
 }
 
+void do_final_instance(void)
+{
+	int i;
+
+	for( i = 1; i < MAX_INSTANCE; i++ )
+		instance_destroy(i);
+}
+
 void do_init_instance(void)
 {
 	memset(instance, 0x00, sizeof(instance));

+ 7 - 4
src/map/instance.h

@@ -7,10 +7,12 @@
 #define MAX_MAP_PER_INSTANCE 10
 #define MAX_INSTANCE 500
 
-typedef enum instance_state { INSTANCE_FREE, INSTANCE_IDLE, INSTANCE_BUSSY } instance_state;
+#define INSTANCE_NAME_LENGTH (60+1)
+
+typedef enum instance_state { INSTANCE_FREE, INSTANCE_IDLE, INSTANCE_BUSY } instance_state;
 
 struct s_instance {
-	char name[61]; // Instance Name - required for clif functions.
+	char name[INSTANCE_NAME_LENGTH]; // Instance Name - required for clif functions.
 	instance_state state;
 	short instance_id;
 	int party_id;
@@ -22,7 +24,7 @@ struct s_instance {
 	struct linkdb_node *ivar, *svar; // Instance Variable for scripts
 	
 	int progress_timer;
-	time_t progress_timeout, progress_timeoutval;
+	time_t progress_timeout;
 
 	int idle_timer;
 	time_t idle_timeout, idle_timeoutval;
@@ -43,6 +45,7 @@ void instance_check_idle(int instance_id);
 void instance_check_kick(struct map_session_data *sd);
 void instance_set_timeout(int instance_id, unsigned int progress_timeout, unsigned int idle_timeout);
 
-void do_init_instance();
+void do_final_instance(void);
+void do_init_instance(void);
 
 #endif

+ 33 - 8
src/map/map.c

@@ -240,7 +240,7 @@ int map_freeblock_unlock (void)
 // この関数は、do_timer() のトップレベルから呼ばれるので、
 // block_free_lock を直接いじっても支障無いはず。
 
-int map_freeblock_timer(int tid, unsigned int tick, int id, intptr data)
+int map_freeblock_timer(int tid, unsigned int tick, int id, intptr_t data)
 {
 	if (block_free_lock > 0) {
 		ShowError("map_freeblock_timer: block_free_lock(%d) is invalid.\n", block_free_lock);
@@ -1217,7 +1217,7 @@ int map_get_new_object_id(void)
  * 後者は、map_clearflooritem(id)へ
  * map.h?で#defineしてある
  *------------------------------------------*/
-int map_clearflooritem_timer(int tid, unsigned int tick, int id, intptr data)
+int map_clearflooritem_timer(int tid, unsigned int tick, int id, intptr_t data)
 {
 	struct flooritem_data* fitem = (struct flooritem_data*)idb_get(id_db, id);
 	if( fitem==NULL || fitem->bl.type!=BL_ITEM || (!data && fitem->cleartimer != tid) )
@@ -2146,7 +2146,7 @@ int map_removemobs_sub(struct block_list *bl, va_list ap)
 	return 1;
 }
 
-int map_removemobs_timer(int tid, unsigned int tick, int id, intptr data)
+int map_removemobs_timer(int tid, unsigned int tick, int id, intptr_t data)
 {
 	int count;
 	const int m = id;
@@ -2727,7 +2727,7 @@ int map_readfromcache(struct map_data *m, char *buffer, char *decode_buffer)
 		}
 
 		// TO-DO: Maybe handle the scenario, if the decoded buffer isn't the same size as expected? [Shinryo]
-		uncompress(decode_buffer, &size, p+sizeof(struct map_cache_map_info), info->len);
+		decode_zip(decode_buffer, &size, p+sizeof(struct map_cache_map_info), info->len);
 
 		CREATE(m->cell, struct mapcell, size);
 
@@ -3436,9 +3436,6 @@ void do_final(void)
 	for( sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); sd = (TBL_PC*)mapit_next(iter) )
 		map_quit(sd);
 	mapit_free(iter);
-	
-	for( i = 0; i < MAX_INSTANCE; i++ )
-		instance_destroy(i);
 
 	id_db->foreach(id_db,cleanup_db_sub);
 	chrif_char_reset_offline();
@@ -3449,6 +3446,7 @@ void do_final(void)
 	do_final_chrif();
 	do_final_npc();
 	do_final_script();
+	do_final_instance();
 	do_final_itemdb();
 	do_final_storage();
 	do_final_guild();
@@ -3491,7 +3489,7 @@ void do_final(void)
 #ifndef TXT_ONLY
     map_sql_close();
 #endif /* not TXT_ONLY */
-	ShowStatus("Successfully terminated.\n");
+	ShowStatus("Finished.\n");
 }
 
 static int map_abort_sub(struct map_session_data* sd, va_list ap)
@@ -3573,6 +3571,27 @@ void set_server_type(void)
 	SERVER_TYPE = ATHENA_SERVER_MAP;
 }
 
+
+/// Called when a terminate signal is received.
+void do_shutdown(void)
+{
+	if( runflag != MAPSERVER_ST_SHUTDOWN )
+	{
+		runflag = MAPSERVER_ST_SHUTDOWN;
+		ShowStatus("Shutting down...\n");
+		{
+			struct map_session_data* sd;
+			struct s_mapiterator* iter = mapit_getallusers();
+			for( sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); sd = (TBL_PC*)mapit_next(iter) )
+				clif_GM_kick(NULL, sd);
+			mapit_free(iter);
+			flush_fifos();
+		}
+		chrif_check_shutdown();
+	}
+}
+
+
 int do_init(int argc, char *argv[])
 {
 	int i;
@@ -3710,6 +3729,12 @@ int do_init(int argc, char *argv[])
 		ShowNotice("Server is running on '"CL_WHITE"PK Mode"CL_RESET"'.\n");
 
 	ShowStatus("Server is '"CL_GREEN"ready"CL_RESET"' and listening on port '"CL_WHITE"%d"CL_RESET"'.\n\n", map_port);
+	
+	if( runflag != CORE_ST_STOP )
+	{
+		shutdown_callback = do_shutdown;
+		runflag = MAPSERVER_ST_RUNNING;
+	}
 
 	return 0;
 }

+ 12 - 4
src/map/map.h

@@ -4,9 +4,8 @@
 #ifndef _MAP_H_
 #define _MAP_H_
 
-#ifndef _CBASETYPES_H_
 #include "../common/cbasetypes.h"
-#endif
+#include "../common/core.h" // CORE_ST_LAST
 #include "../common/mmo.h"
 #include "../common/mapindex.h"
 #include "../common/db.h"
@@ -16,6 +15,13 @@
 struct npc_data;
 struct item_data;
 
+enum E_MAPSERVER_ST
+{
+	MAPSERVER_ST_RUNNING = CORE_ST_LAST,
+	MAPSERVER_ST_SHUTDOWN,
+	MAPSERVER_ST_LAST
+};
+
 //Uncomment to enable the Cell Stack Limit mod.
 //It's only config is the battle_config cell_stack_limit.
 //Only chars affected are those defined in BL_CHAR (mobs and players currently)
@@ -615,8 +621,8 @@ int map_quit(struct map_session_data *);
 bool map_addnpc(int,struct npc_data *);
 
 // �°ƒAƒCƒeƒ€ŠÖ˜A
-int map_clearflooritem_timer(int tid, unsigned int tick, int id, intptr data);
-int map_removemobs_timer(int tid, unsigned int tick, int id, intptr data);
+int map_clearflooritem_timer(int tid, unsigned int tick, int id, intptr_t data);
+int map_removemobs_timer(int tid, unsigned int tick, int id, intptr_t data);
 #define map_clearflooritem(id) map_clearflooritem_timer(0,0,id,1)
 int map_addflooritem(struct item *item_data,int amount,int m,int x,int y,int first_charid,int second_charid,int third_charid,int flags);
 
@@ -739,4 +745,6 @@ extern char mob_db2_db[32];
 
 #endif /* not TXT_ONLY */
 
+void do_shutdown(void);
+
 #endif /* _MAP_H_ */

+ 1 - 1
src/map/mapreg_sql.c

@@ -184,7 +184,7 @@ static void script_save_mapreg(void)
 	mapreg_dirty = false;
 }
 
-static int script_autosave_mapreg(int tid, unsigned int tick, int id, intptr data)
+static int script_autosave_mapreg(int tid, unsigned int tick, int id, intptr_t data)
 {
 	if( mapreg_dirty )
 		script_save_mapreg();

+ 1 - 1
src/map/mapreg_txt.c

@@ -151,7 +151,7 @@ static void script_save_mapreg(void)
 	mapreg_dirty = false;
 }
 
-static int script_autosave_mapreg(int tid, unsigned int tick, int id, intptr data)
+static int script_autosave_mapreg(int tid, unsigned int tick, int id, intptr_t data)
 {
 	if( mapreg_dirty )
 		script_save_mapreg();

+ 1 - 1
src/map/mercenary.c

@@ -215,7 +215,7 @@ int mercenary_save(struct mercenary_data *md)
 	return 1;
 }
 
-static int merc_contract_end(int tid, unsigned int tick, int id, intptr data)
+static int merc_contract_end(int tid, unsigned int tick, int id, intptr_t data)
 {
 	struct map_session_data *sd;
 	struct mercenary_data *md;

+ 31 - 26
src/map/mob.c

@@ -81,7 +81,7 @@ const int mob_splendide[5] = { 1991, 1992, 1993, 1994, 1995 };
  * Local prototype declaration   (only required thing)
  *------------------------------------------*/
 static int mob_makedummymobdb(int);
-static int mob_spawn_guardian_sub(int tid, unsigned int tick, int id, intptr data);
+static int mob_spawn_guardian_sub(int tid, unsigned int tick, int id, intptr_t data);
 int mob_skillid2skillidx(int class_,int skillid);
 
 /*==========================================
@@ -507,7 +507,7 @@ int mob_once_spawn_area(struct map_session_data* sd,int m,int x0,int y0,int x1,i
 /*==========================================
  * Set a Guardian's guild data [Skotlex]
  *------------------------------------------*/
-static int mob_spawn_guardian_sub(int tid, unsigned int tick, int id, intptr data)
+static int mob_spawn_guardian_sub(int tid, unsigned int tick, int id, intptr_t data)
 {	//Needed because the guild_data may not be available at guardian spawn time.
 	struct block_list* bl = map_id2bl(id);
 	struct mob_data* md; 
@@ -766,7 +766,7 @@ int mob_linksearch(struct block_list *bl,va_list ap)
 /*==========================================
  * mob spawn with delay (timer function)
  *------------------------------------------*/
-int mob_delayspawn(int tid, unsigned int tick, int id, intptr data)
+int mob_delayspawn(int tid, unsigned int tick, int id, intptr_t data)
 {
 	struct block_list* bl = map_id2bl(id);
 	struct mob_data* md = BL_CAST(BL_MOB, bl);
@@ -1636,7 +1636,7 @@ static int mob_ai_sub_lazy(struct mob_data *md, va_list args)
 /*==========================================
  * Negligent processing for mob outside PC field of view   (interval timer function)
  *------------------------------------------*/
-static int mob_ai_lazy(int tid, unsigned int tick, int id, intptr data)
+static int mob_ai_lazy(int tid, unsigned int tick, int id, intptr_t data)
 {
 	map_foreachmob(mob_ai_sub_lazy,tick);
 	return 0;
@@ -1645,7 +1645,7 @@ static int mob_ai_lazy(int tid, unsigned int tick, int id, intptr data)
 /*==========================================
  * Serious processing for mob in PC field of view   (interval timer function)
  *------------------------------------------*/
-static int mob_ai_hard(int tid, unsigned int tick, int id, intptr data)
+static int mob_ai_hard(int tid, unsigned int tick, int id, intptr_t data)
 {
 
 	if (battle_config.mob_ai&0x20)
@@ -1684,7 +1684,7 @@ static struct item_drop* mob_setlootitem(struct item* item)
 /*==========================================
  * item drop with delay (timer function)
  *------------------------------------------*/
-static int mob_delay_item_drop(int tid, unsigned int tick, int id, intptr data)
+static int mob_delay_item_drop(int tid, unsigned int tick, int id, intptr_t data)
 {
 	struct item_drop_list *list;
 	struct item_drop *ditem, *ditem_prev;
@@ -1744,7 +1744,7 @@ static void mob_item_drop(struct mob_data *md, struct item_drop_list *dlist, str
 	dlist->item = ditem;
 }
 
-int mob_timer_delete(int tid, unsigned int tick, int id, intptr data)
+int mob_timer_delete(int tid, unsigned int tick, int id, intptr_t data)
 {
 	struct block_list* bl = map_id2bl(id);
 	struct mob_data* md = BL_CAST(BL_MOB, bl);
@@ -1791,7 +1791,7 @@ int mob_deleteslave(struct mob_data *md)
 	return 0;
 }
 // Mob respawning through KAIZEL or NPC_REBIRTH [Skotlex]
-int mob_respawn(int tid, unsigned int tick, int id, intptr data)
+int mob_respawn(int tid, unsigned int tick, int id, intptr_t data)
 {
 	struct block_list *bl = map_id2bl(id);
 
@@ -2296,7 +2296,7 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
 				mob_item_drop(md, dlist, mob_setlootitem(&md->lootitem[i]), 1, 10000, homkillonly);
 		}
 		if (dlist->item) //There are drop items.
-			add_timer(tick + (!battle_config.delay_battle_damage?500:0), mob_delay_item_drop, 0, (intptr)dlist);
+			add_timer(tick + (!battle_config.delay_battle_damage?500:0), mob_delay_item_drop, 0, (intptr_t)dlist);
 		else //No drops
 			ers_free(item_drop_list_ers, dlist);
 	} else if (md->lootitem && md->lootitem_count) {	//Loot MUST drop!
@@ -2310,7 +2310,7 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
 		dlist->item = NULL;
 		for(i = 0; i < md->lootitem_count; i++)
 			mob_item_drop(md, dlist, mob_setlootitem(&md->lootitem[i]), 1, 10000, homkillonly);
-		add_timer(tick + (!battle_config.delay_battle_damage?500:0), mob_delay_item_drop, 0, (intptr)dlist);
+		add_timer(tick + (!battle_config.delay_battle_damage?500:0), mob_delay_item_drop, 0, (intptr_t)dlist);
 	}
 
 	if(mvp_sd && md->db->mexp > 0 && !md->special_state.ai)
@@ -3407,7 +3407,7 @@ static unsigned int mob_drop_adjust(int baserate, int rate_adjust, unsigned shor
  *------------------------------------------*/
 static bool mob_parse_dbrow(char** str)
 {
-	struct mob_db *db;
+	struct mob_db *db, entry;
 	struct status_data *status;
 	int class_, i, k;
 	double exp, maxhp;
@@ -3416,29 +3416,28 @@ static bool mob_parse_dbrow(char** str)
 	class_ = atoi(str[0]);
 	
 	if (class_ <= 1000 || class_ > MAX_MOB_DB) {
-		ShowWarning("Mob with ID: %d not loaded. ID must be in range [%d-%d]\n", class_, 1000, MAX_MOB_DB);
+		ShowError("mob_parse_dbrow: Invalid monster ID %d, must be in range %d-%d.\n", class_, 1000, MAX_MOB_DB);
 		return false;
 	}
 	if (pcdb_checkid(class_)) {
-		ShowWarning("Mob with ID: %d not loaded. That ID is reserved for player classes.\n", class_);
+		ShowError("mob_parse_dbrow: Invalid monster ID %d, reserved for player classes.\n", class_);
 		return false;
 	}
 	
 	if (class_ >= MOB_CLONE_START && class_ < MOB_CLONE_END) {
-		ShowWarning("Mob with ID: %d not loaded. Range %d-%d is reserved for player clones. Please increase MAX_MOB_DB (%d)\n", class_, MOB_CLONE_START, MOB_CLONE_END-1, MAX_MOB_DB);
+		ShowError("mob_parse_dbrow: Invalid monster ID %d. Range %d-%d is reserved for player clones. Please increase MAX_MOB_DB (%d).\n", class_, MOB_CLONE_START, MOB_CLONE_END-1, MAX_MOB_DB);
 		return false;
 	}
 
-	if (mob_db_data[class_] == NULL)
-		mob_db_data[class_] = (struct mob_db*)aCalloc(1, sizeof (struct mob_db));
+	memset(&entry, 0, sizeof(entry));
 	
-	db = mob_db_data[class_];
+	db = &entry;
 	status = &db->status;
 	
 	db->vd.class_ = class_;
-	strncpy(db->sprite, str[1], NAME_LENGTH);
-	strncpy(db->jname, str[2], NAME_LENGTH);
-	strncpy(db->name, str[3], NAME_LENGTH);
+	safestrncpy(db->sprite, str[1], sizeof(db->sprite));
+	safestrncpy(db->jname, str[2], sizeof(db->jname));
+	safestrncpy(db->name, str[3], sizeof(db->name));
 	db->lv = atoi(str[4]);
 	db->lv = cap_value(db->lv, 1, USHRT_MAX);
 	status->max_hp = atoi(str[5]);
@@ -3489,12 +3488,12 @@ static bool mob_parse_dbrow(char** str)
 	status->def_ele = i%10;
 	status->ele_lv = i/20;
 	if (status->def_ele >= ELE_MAX) {
-		ShowWarning("Mob with ID: %d has invalid element type %d (max element is %d)\n", class_, status->def_ele, ELE_MAX-1);
-		status->def_ele = ELE_NEUTRAL;
+		ShowError("mob_parse_dbrow: Invalid element type %d for monster ID %d (max=%d).\n", status->def_ele, class_, ELE_MAX-1);
+		return false;
 	}
 	if (status->ele_lv < 1 || status->ele_lv > 4) {
-		ShowWarning("Mob with ID: %d has invalid element level %d (max is 4)\n", class_, status->ele_lv);
-		status->ele_lv = 1;
+		ShowError("mob_parse_dbrow: Invalid element level %d for monster ID %d, must be in range 1-4.\n", status->ele_lv, class_);
+		return false;
 	}
 	
 	status->mode = (int)strtol(str[25], NULL, 0);
@@ -3512,7 +3511,8 @@ static bool mob_parse_dbrow(char** str)
 	status->dmotion = atoi(str[29]);
 	if(battle_config.monster_damage_delay_rate != 100)
 		status->dmotion = status->dmotion * battle_config.monster_damage_delay_rate / 100;
-	
+
+	// Fill in remaining status data by using a dummy monster.
 	data.bl.type = BL_MOB;
 	data.level = db->lv;
 	memcpy(&data.status, status, sizeof(struct status_data));
@@ -3632,7 +3632,12 @@ static bool mob_parse_dbrow(char** str)
 			id->mob[k].id = class_;
 		}
 	}
-	
+
+	// Finally insert monster's data into the database.
+	if (mob_db_data[class_] == NULL)
+		mob_db_data[class_] = (struct mob_db*)aCalloc(1, sizeof(struct mob_db));
+
+	memcpy(mob_db_data[class_], db, sizeof(struct mob_db));
 	return true;
 }
 

+ 2 - 2
src/map/mob.h

@@ -239,7 +239,7 @@ int mob_target(struct mob_data *md,struct block_list *bl,int dist);
 int mob_unlocktarget(struct mob_data *md, unsigned int tick);
 struct mob_data* mob_spawn_dataset(struct spawn_data *data);
 int mob_spawn(struct mob_data *md);
-int mob_delayspawn(int tid, unsigned int tick, int id, intptr data);
+int mob_delayspawn(int tid, unsigned int tick, int id, intptr_t data);
 int mob_setdelayspawn(struct mob_data *md);
 int mob_parse_dataset(struct spawn_data *data);
 void mob_log_damage(struct mob_data *md, struct block_list *src, int damage);
@@ -256,7 +256,7 @@ void mob_clear_spawninfo();
 int do_init_mob(void);
 int do_final_mob(void);
 
-int mob_timer_delete(int tid, unsigned int tick, int id, intptr data);
+int mob_timer_delete(int tid, unsigned int tick, int id, intptr_t data);
 int mob_deleteslave(struct mob_data *md);
 
 int mob_random_class (int *value, size_t count);

+ 20 - 18
src/map/npc.c

@@ -356,7 +356,7 @@ bool npc_event_isspecial(const char* eventname)
 /*==========================================
  * ŽžŒvƒCƒxƒ“ƒgŽÀ�s
  *------------------------------------------*/
-int npc_event_do_clock(int tid, unsigned int tick, int id, intptr data)
+int npc_event_do_clock(int tid, unsigned int tick, int id, intptr_t data)
 {
 	static struct tm ev_tm_b; // tracks previous execution time
 	time_t timer;
@@ -455,7 +455,7 @@ struct timer_event_data {
 /*==========================================
  * triger 'OnTimerXXXX' events
  *------------------------------------------*/
-int npc_timerevent(int tid, unsigned int tick, int id, intptr data)
+int npc_timerevent(int tid, unsigned int tick, int id, intptr_t data)
 {
 	int next;
 	int old_rid, old_timer;
@@ -498,9 +498,9 @@ int npc_timerevent(int tid, unsigned int tick, int id, intptr data)
 		next = nd->u.scr.timer_event[ ted->next ].timer - nd->u.scr.timer_event[ ted->next - 1 ].timer;
 		ted->time += next;
 		if( sd )
-			sd->npc_timer_id = add_timer(tick+next,npc_timerevent,id,(intptr)ted);
+			sd->npc_timer_id = add_timer(tick+next,npc_timerevent,id,(intptr_t)ted);
 		else
-			nd->u.scr.timerid = add_timer(tick+next,npc_timerevent,id,(intptr)ted);
+			nd->u.scr.timerid = add_timer(tick+next,npc_timerevent,id,(intptr_t)ted);
 	}
 	else
 	{
@@ -570,13 +570,13 @@ int npc_timerevent_start(struct npc_data* nd, int rid)
 	if( sd )
 	{
 		ted->rid = sd->bl.id; // Attach only the player if attachplayerrid was used.
-		sd->npc_timer_id = add_timer(tick+next,npc_timerevent,nd->bl.id,(intptr)ted);
+		sd->npc_timer_id = add_timer(tick+next,npc_timerevent,nd->bl.id,(intptr_t)ted);
 	}
 	else
 	{
 		ted->rid = 0;
 		nd->u.scr.timertick = tick; // Set when timer is started
-		nd->u.scr.timerid = add_timer(tick+next,npc_timerevent,nd->bl.id,(intptr)ted);
+		nd->u.scr.timerid = add_timer(tick+next,npc_timerevent,nd->bl.id,(intptr_t)ted);
 	}
 
 	return 0;
@@ -1164,8 +1164,8 @@ static int npc_buylist_sub(struct map_session_data* sd, int n, unsigned short* i
 	// save list of bought items
 	for( i = 0; i < n; i++ )
 	{
-		script_setarray_pc(sd, "@bought_nameid", i, (void*)(intptr)item_list[i*2+1], &key_nameid);
-		script_setarray_pc(sd, "@bought_quantity", i, (void*)(intptr)item_list[i*2], &key_amount);
+		script_setarray_pc(sd, "@bought_nameid", i, (void*)(intptr_t)item_list[i*2+1], &key_nameid);
+		script_setarray_pc(sd, "@bought_quantity", i, (void*)(intptr_t)item_list[i*2], &key_amount);
 	}
 
 	// invoke event
@@ -1369,8 +1369,9 @@ int npc_buylist(struct map_session_data* sd, int n, unsigned short* item_list)
 	// custom merchant shop exp bonus
 	if( battle_config.shop_exp > 0 && z > 0 && (skill = pc_checkskill(sd,MC_DISCOUNT)) > 0 )
 	{
-		if( sd->status.skill[MC_DISCOUNT].flag != 0 )
-			skill = sd->status.skill[MC_DISCOUNT].flag - 2;
+		if( sd->status.skill[MC_DISCOUNT].flag >= SKILL_FLAG_REPLACED_LV_0 )
+			skill = sd->status.skill[MC_DISCOUNT].flag - SKILL_FLAG_REPLACED_LV_0;
+
 		if( skill > 0 )
 		{
 			z = z * (double)skill * (double)battle_config.shop_exp/10000.;
@@ -1401,8 +1402,8 @@ static int npc_selllist_sub(struct map_session_data* sd, int n, unsigned short*
 	{
 		idx = item_list[i*2]-2;
 
-		script_setarray_pc(sd, "@sold_nameid", i, (void*)(intptr)sd->status.inventory[idx].nameid, &key_nameid);
-		script_setarray_pc(sd, "@sold_quantity", i, (void*)(intptr)item_list[i*2+1], &key_amount);
+		script_setarray_pc(sd, "@sold_nameid", i, (void*)(intptr_t)sd->status.inventory[idx].nameid, &key_nameid);
+		script_setarray_pc(sd, "@sold_quantity", i, (void*)(intptr_t)item_list[i*2+1], &key_amount);
 	}
 
 	// invoke event
@@ -1505,8 +1506,9 @@ int npc_selllist(struct map_session_data* sd, int n, unsigned short* item_list)
 	// custom merchant shop exp bonus
 	if( battle_config.shop_exp > 0 && z > 0 && ( skill = pc_checkskill(sd,MC_OVERCHARGE) ) > 0)
 	{
-		if( sd->status.skill[MC_OVERCHARGE].flag != 0 )
-			skill = sd->status.skill[MC_OVERCHARGE].flag - 2;
+		if( sd->status.skill[MC_OVERCHARGE].flag >= SKILL_FLAG_REPLACED_LV_0 )
+			skill = sd->status.skill[MC_OVERCHARGE].flag - SKILL_FLAG_REPLACED_LV_0;
+
 		if( skill > 0 )
 		{
 			z = z * (double)skill * (double)battle_config.shop_exp/10000.;
@@ -2734,13 +2736,13 @@ static const char* npc_parse_mob(char* w1, char* w2, char* w3, char* w4, const c
 	// check monster ID if exists!
 	if( mobdb_checkid(class_) == 0 )
 	{
-		ShowError("npc_parse_mob: Unknown mob ID : %s %s (file '%s', line '%d').\n", w3, w4, filepath, strline(buffer,start-buffer));
+		ShowError("npc_parse_mob: Unknown mob ID %d (file '%s', line '%d').\n", class_, filepath, strline(buffer,start-buffer));
 		return strchr(start,'\n');// skip and continue
 	}
 
 	if( num < 1 || num > 1000 )
 	{
-		ShowError("npc_parse_mob: Invalid number of monsters (must be inside the range [1,1000]) : %s %s (file '%s', line '%d').\n", w3, w4, filepath, strline(buffer,start-buffer));
+		ShowError("npc_parse_mob: Invalid number of monsters %d, must be inside the range [1,1000] (file '%s', line '%d').\n", num, filepath, strline(buffer,start-buffer));
 		return strchr(start,'\n');// skip and continue
 	}
 
@@ -2786,7 +2788,7 @@ static const char* npc_parse_mob(char* w1, char* w2, char* w3, char* w4, const c
 	}
 
 	if(mob.delay1>0xfffffff || mob.delay2>0xfffffff) {
-		ShowError("npc_parse_mob: wrong monsters spawn delays : %s %s (file '%s', line '%d').\n", w3, w4, filepath, strline(buffer,start-buffer));
+		ShowError("npc_parse_mob: Invalid spawn delays %u %u (file '%s', line '%d').\n", mob.delay1, mob.delay2, filepath, strline(buffer,start-buffer));
 		return strchr(start,'\n');// skip and continue
 	}
 
@@ -2801,7 +2803,7 @@ static const char* npc_parse_mob(char* w1, char* w2, char* w3, char* w4, const c
 	//Verify dataset.
 	if( !mob_parse_dataset(&mob) )
 	{
-		ShowError("npc_parse_mob: Invalid dataset : %s %s (file '%s', line '%d').\n", w3, w4, filepath, strline(buffer,start-buffer));
+		ShowError("npc_parse_mob: Invalid dataset for monster ID %d (file '%s', line '%d').\n", class_, filepath, strline(buffer,start-buffer));
 		return strchr(start,'\n');// skip and continue
 	}
 

+ 1 - 1
src/map/npc.h

@@ -77,7 +77,7 @@ struct npc_data {
 #define MAX_NPC_CLASS 1000
 //Checks if a given id is a valid npc id. [Skotlex]
 //Since new npcs are added all the time, the max valid value is the one before the first mob (Scorpion = 1001)
-#define npcdb_checkid(id) ((id >=  46 && id <= 125) || id == 139 || (id >= 400 && id <= MAX_NPC_CLASS) || id == INVISIBLE_CLASS)
+#define npcdb_checkid(id) ( ( (id) >= 46 && (id) <= 125) || (id) == 139 || ( (id) > 400 && (id) < MAX_NPC_CLASS ) || (id) == INVISIBLE_CLASS )
 
 #ifdef PCRE_SUPPORT
 void npc_chat_finalize(struct npc_data* nd);

+ 12 - 4
src/map/party.c

@@ -32,7 +32,7 @@ static DBMap* party_db; // int party_id -> struct party_data*
 static DBMap* party_booking_db; // Party Booking [Spiria]
 static unsigned long party_booking_nextid = 1;
 
-int party_send_xy_timer(int tid, unsigned int tick, int id, intptr data);
+int party_send_xy_timer(int tid, unsigned int tick, int id, intptr_t data);
 
 /*==========================================
  * Fills the given party_member structure according to the sd provided. 
@@ -369,11 +369,19 @@ int party_invite(struct map_session_data *sd,struct map_session_data *tsd)
 	return 1;
 }
 
-void party_reply_invite(struct map_session_data *sd,int account_id,int flag)
+void party_reply_invite(struct map_session_data *sd,int party_id,int flag)
 {
-	struct map_session_data *tsd= map_id2sd(account_id);
+	struct map_session_data* tsd;
 	struct party_member member;
 
+	if( sd->party_invite != party_id )
+	{// forged
+		sd->party_invite = 0;
+		sd->party_invite_account = 0;
+		return;
+	}
+	tsd = map_id2sd(sd->party_invite_account);
+
 	if( flag == 1 && !sd->party_creating && !sd->party_joining )
 	{// accepted and allowed
 		sd->party_joining = true;
@@ -832,7 +840,7 @@ int party_skill_check(struct map_session_data *sd, int party_id, int skillid, in
 	return 0;
 }
 
-int party_send_xy_timer(int tid, unsigned int tick, int id, intptr data)
+int party_send_xy_timer(int tid, unsigned int tick, int id, intptr_t data)
 {
 	struct party_data* p;
 

+ 1 - 1
src/map/party.h

@@ -62,7 +62,7 @@ int party_member_added(int party_id,int account_id,int char_id,int flag);
 int party_leave(struct map_session_data *sd);
 int party_removemember(struct map_session_data *sd,int account_id,char *name);
 int party_member_withdraw(int party_id,int account_id,int char_id);
-void party_reply_invite(struct map_session_data *sd,int account_id,int flag);
+void party_reply_invite(struct map_session_data *sd,int party_id,int flag);
 int party_recv_noinfo(int party_id);
 int party_recv_info(struct party *sp);
 int party_recv_movemap(int party_id,int account_id,int char_id, unsigned short map,int online,int lv);

+ 74 - 65
src/map/pc.c

@@ -85,7 +85,7 @@ int pc_isGM(struct map_session_data* sd)
 	return sd->gmlevel;
 }
 
-static int pc_invincible_timer(int tid, unsigned int tick, int id, intptr data)
+static int pc_invincible_timer(int tid, unsigned int tick, int id, intptr_t data)
 {
 	struct map_session_data *sd;
 
@@ -123,7 +123,7 @@ void pc_delinvincibletimer(struct map_session_data* sd)
 	}
 }
 
-static int pc_spiritball_timer(int tid, unsigned int tick, int id, intptr data)
+static int pc_spiritball_timer(int tid, unsigned int tick, int id, intptr_t data)
 {
 	struct map_session_data *sd;
 	int i;
@@ -295,7 +295,7 @@ int pc_setrestartvalue(struct map_session_data *sd,int type)
 /*==========================================
 	Rental System
  *------------------------------------------*/
-static int pc_inventory_rental_end(int tid, unsigned int tick, int id, intptr data)
+static int pc_inventory_rental_end(int tid, unsigned int tick, int id, intptr_t data)
 {
 	struct map_session_data *sd = map_id2sd(id);
 	if( sd == NULL )
@@ -695,7 +695,7 @@ bool pc_can_Adopt(struct map_session_data *p1_sd, struct map_session_data *p2_sd
 		return false;
 	}
 
-	if( !(b_sd->status.class_ >= JOB_NOVICE && b_sd->status.class_ <= JOB_THIEF) )
+	if( !( ( b_sd->status.class_ >= JOB_NOVICE && b_sd->status.class_ <= JOB_THIEF ) || b_sd->status.class_ == JOB_SUPER_NOVICE ) )
 		return false;
 
 	return true;
@@ -1061,9 +1061,9 @@ int pc_reg_received(struct map_session_data *sd)
 		if (sd->cloneskill_id > 0) {
 			sd->status.skill[sd->cloneskill_id].id = sd->cloneskill_id;
 			sd->status.skill[sd->cloneskill_id].lv = pc_readglobalreg(sd,"CLONE_SKILL_LV");
-			if (i < sd->status.skill[sd->cloneskill_id].lv)
+			if (sd->status.skill[sd->cloneskill_id].lv > i)
 				sd->status.skill[sd->cloneskill_id].lv = i;
-			sd->status.skill[sd->cloneskill_id].flag = 13;	//cloneskill flag			
+			sd->status.skill[sd->cloneskill_id].flag = SKILL_FLAG_PLAGIARIZED;
 		}
 	}
 
@@ -1124,11 +1124,11 @@ static int pc_calc_skillpoint(struct map_session_data* sd)
 			if((!(inf2&INF2_QUEST_SKILL) || battle_config.quest_skill_learn) &&
 				!(inf2&(INF2_WEDDING_SKILL|INF2_SPIRIT_SKILL)) //Do not count wedding/link skills. [Skotlex]
 				) {
-				if(!sd->status.skill[i].flag)
+				if(sd->status.skill[i].flag == SKILL_FLAG_PERMANENT)
 					skill_point += skill;
-				else if(sd->status.skill[i].flag > 2 && sd->status.skill[i].flag != 13) {
-					skill_point += (sd->status.skill[i].flag - 2);
-				}
+				else
+				if(sd->status.skill[i].flag >= SKILL_FLAG_REPLACED_LV_0)
+					skill_point += (sd->status.skill[i].flag - SKILL_FLAG_REPLACED_LV_0);
 			}
 		}
 	}
@@ -1157,16 +1157,16 @@ int pc_calc_skilltree(struct map_session_data *sd)
 
 	for( i = 0; i < MAX_SKILL; i++ )
 	{ 
-		if( sd->status.skill[i].flag != 13 ) //Don't touch plagiarized skills
+		if( sd->status.skill[i].flag != SKILL_FLAG_PLAGIARIZED ) //Don't touch plagiarized skills
 			sd->status.skill[i].id = 0; //First clear skills.
 	}
 
 	for( i = 0; i < MAX_SKILL; i++ )
 	{ 
-		if( sd->status.skill[i].flag && sd->status.skill[i].flag != 13 )
+		if( sd->status.skill[i].flag != SKILL_FLAG_PERMANENT && sd->status.skill[i].flag != SKILL_FLAG_PLAGIARIZED )
 		{ // Restore original level of skills after deleting earned skills.	
-			sd->status.skill[i].lv = (sd->status.skill[i].flag == 1)?0:sd->status.skill[i].flag-2;
-			sd->status.skill[i].flag = 0;
+			sd->status.skill[i].lv = (sd->status.skill[i].flag == SKILL_FLAG_TEMPORARY) ? 0 : sd->status.skill[i].flag - SKILL_FLAG_REPLACED_LV_0;
+			sd->status.skill[i].flag = SKILL_FLAG_PERMANENT;
 		}
 
 		if( sd->sc.count && sd->sc.data[SC_SPIRIT] && sd->sc.data[SC_SPIRIT]->val2 == SL_BARDDANCER && i >= DC_HUMMING && i<= DC_SERVICEFORYOU )
@@ -1177,7 +1177,7 @@ int pc_calc_skilltree(struct map_session_data *sd)
 					continue;
 				sd->status.skill[i].id = i;
 				sd->status.skill[i].lv = sd->status.skill[i-8].lv; // Set the level to the same as the linking skill
-				sd->status.skill[i].flag = 1; // Tag it as a non-savable, non-uppable, bonus skill
+				sd->status.skill[i].flag = SKILL_FLAG_TEMPORARY; // Tag it as a non-savable, non-uppable, bonus skill
 			}
 			else
 			{ //Link bard skills to dancer.
@@ -1185,7 +1185,7 @@ int pc_calc_skilltree(struct map_session_data *sd)
 					continue;
 				sd->status.skill[i-8].id = i - 8;
 				sd->status.skill[i-8].lv = sd->status.skill[i].lv; // Set the level to the same as the linking skill
-				sd->status.skill[i-8].flag = 1; // Tag it as a non-savable, non-uppable, bonus skill
+				sd->status.skill[i-8].flag = SKILL_FLAG_TEMPORARY; // Tag it as a non-savable, non-uppable, bonus skill
 			}
 		}
 	}
@@ -1216,10 +1216,11 @@ int pc_calc_skilltree(struct map_session_data *sd)
 				for(j = 0; j < MAX_PC_SKILL_REQUIRE; j++) {
 					if((k=skill_tree[c][i].need[j].id))
 					{
-						if (!sd->status.skill[k].id || sd->status.skill[k].flag == 13)
+						if (sd->status.skill[k].id == 0 || sd->status.skill[k].flag == SKILL_FLAG_TEMPORARY || sd->status.skill[k].flag == SKILL_FLAG_PLAGIARIZED)
 							k = 0; //Not learned.
-						else if (sd->status.skill[k].flag) //Real lerned level
-							k = sd->status.skill[skill_tree[c][i].need[j].id].flag-2;
+						else
+						if (sd->status.skill[k].flag >= SKILL_FLAG_REPLACED_LV_0) //Real lerned level
+							k = sd->status.skill[skill_tree[c][i].need[j].id].flag - SKILL_FLAG_REPLACED_LV_0;
 						else
 							k = pc_checkskill(sd,k);
 						if (k < skill_tree[c][i].need[j].lv)
@@ -1249,7 +1250,7 @@ int pc_calc_skilltree(struct map_session_data *sd)
 				if(inf2&INF2_SPIRIT_SKILL)
 				{	//Spirit skills cannot be learned, they will only show up on your tree when you get buffed.
 					sd->status.skill[id].lv = 1; // need to manually specify a skill level
-					sd->status.skill[id].flag = 1; //So it is not saved, and tagged as a "bonus" skill.
+					sd->status.skill[id].flag = SKILL_FLAG_TEMPORARY; //So it is not saved, and tagged as a "bonus" skill.
 				}
 				flag = 1; // skill list has changed, perform another pass
 			}
@@ -1273,10 +1274,12 @@ int pc_calc_skilltree(struct map_session_data *sd)
 			if( sd->status.skill[id].id == 0 )
 			{
 				sd->status.skill[id].id = id;
-				sd->status.skill[id].flag = 1; // So it is not saved, and tagged as a "bonus" skill.
+				sd->status.skill[id].flag = SKILL_FLAG_TEMPORARY; // So it is not saved, and tagged as a "bonus" skill.
 			}
 			else
-				sd->status.skill[id].flag = sd->status.skill[id].lv+2;
+			{
+				sd->status.skill[id].flag = SKILL_FLAG_REPLACED_LV_0 + sd->status.skill[id].lv; // Remember original level
+			}
 
 			sd->status.skill[id].lv = skill_tree_get_max(id, sd->status.class_);
 		}
@@ -1314,10 +1317,11 @@ static void pc_check_skilltree(struct map_session_data *sd, int skill)
 			{
 				if( (k = skill_tree[c][i].need[j].id) )
 				{
-					if( !sd->status.skill[k].id || sd->status.skill[k].flag == 13 )
+					if( sd->status.skill[k].id == 0 || sd->status.skill[k].flag == SKILL_FLAG_TEMPORARY || sd->status.skill[k].flag == SKILL_FLAG_PLAGIARIZED )
 						k = 0; //Not learned.
-					else if( sd->status.skill[k].flag ) //Real lerned level
-						k = sd->status.skill[skill_tree[c][i].need[j].id].flag - 2;
+					else
+					if( sd->status.skill[k].flag >= SKILL_FLAG_REPLACED_LV_0) //Real lerned level
+						k = sd->status.skill[skill_tree[c][i].need[j].id].flag - SKILL_FLAG_REPLACED_LV_0;
 					else
 						k = pc_checkskill(sd,k);
 					if( k < skill_tree[c][i].need[j].lv )
@@ -1352,13 +1356,15 @@ int pc_clean_skilltree(struct map_session_data *sd)
 {
 	int i;
 	for (i = 0; i < MAX_SKILL; i++){
-		if (sd->status.skill[i].flag == 13 || sd->status.skill[i].flag == 1)
+		if (sd->status.skill[i].flag == SKILL_FLAG_TEMPORARY || sd->status.skill[i].flag == SKILL_FLAG_PLAGIARIZED)
 		{
 			sd->status.skill[i].id = 0;
 			sd->status.skill[i].lv = 0;
 			sd->status.skill[i].flag = 0;
-		} else if (sd->status.skill[i].flag){
-			sd->status.skill[i].lv = sd->status.skill[i].flag-2;
+		}
+		else
+		if (sd->status.skill[i].flag >= SKILL_FLAG_REPLACED_LV_0){
+			sd->status.skill[i].lv = sd->status.skill[i].flag - SKILL_FLAG_REPLACED_LV_0;
 			sd->status.skill[i].flag = 0;
 		}
 	}
@@ -1716,14 +1722,14 @@ int pc_exeautobonus(struct map_session_data *sd,struct s_autobonus *autobonus)
 			script_run_autobonus(autobonus->other_script,sd->bl.id,sd->equip_index[j]);
 	}
 
-	autobonus->active = add_timer(gettick()+autobonus->duration, pc_endautobonus, sd->bl.id, (intptr)autobonus);
+	autobonus->active = add_timer(gettick()+autobonus->duration, pc_endautobonus, sd->bl.id, (intptr_t)autobonus);
 	sd->state.autobonus |= autobonus->pos;
 	status_calc_pc(sd,0);
 
 	return 0;
 }
 
-int pc_endautobonus(int tid, unsigned int tick, int id, intptr data)
+int pc_endautobonus(int tid, unsigned int tick, int id, intptr_t data)
 {
 	struct map_session_data *sd = map_id2sd(id);
 	struct s_autobonus *autobonus = (struct s_autobonus *)data;
@@ -2321,8 +2327,8 @@ int pc_bonus(struct map_session_data *sd,int type,int val)
 			sd->right_weapon.hp_drain[RC_BOSS].value += val;
 		}
 		else if(sd->state.lr_flag == 1) {
-			sd->right_weapon.hp_drain[RC_NONBOSS].value += val;
-			sd->right_weapon.hp_drain[RC_BOSS].value += val;
+			sd->left_weapon.hp_drain[RC_NONBOSS].value += val;
+			sd->left_weapon.hp_drain[RC_BOSS].value += val;
 		}
 		break;
 	case SP_SP_DRAIN_VALUE:
@@ -3060,8 +3066,8 @@ int pc_skill(TBL_PC* sd, int id, int level, int flag)
 	case 0: //Set skill data overwriting whatever was there before.
 		sd->status.skill[id].id   = id;
 		sd->status.skill[id].lv   = level;
-		sd->status.skill[id].flag = 0;
-		if( !level ) //Remove skill.
+		sd->status.skill[id].flag = SKILL_FLAG_PERMANENT;
+		if( level == 0 ) //Remove skill.
 		{
 			sd->status.skill[id].id = 0;
 			clif_deleteskill(sd,id);
@@ -3075,21 +3081,21 @@ int pc_skill(TBL_PC* sd, int id, int level, int flag)
 		if( sd->status.skill[id].id == id ){
 			if( sd->status.skill[id].lv >= level )
 				return 0;
-			if( !sd->status.skill[id].flag ) //Non-granted skill, store it's level.
-				sd->status.skill[id].flag = sd->status.skill[id].lv + 2;
+			if( sd->status.skill[id].flag == SKILL_FLAG_PERMANENT ) //Non-granted skill, store it's level.
+				sd->status.skill[id].flag = SKILL_FLAG_REPLACED_LV_0 + sd->status.skill[id].lv;
 		} else {
 			sd->status.skill[id].id   = id;
-			sd->status.skill[id].flag = 1;
+			sd->status.skill[id].flag = SKILL_FLAG_TEMPORARY;
 		}
 		sd->status.skill[id].lv = level;
 	break;
 	case 2: //Add skill bonus on top of what you had.
 		if( sd->status.skill[id].id == id ){
-			if( !sd->status.skill[id].flag ) // Store previous level.
-				sd->status.skill[id].flag = sd->status.skill[id].lv + 2;
+			if( sd->status.skill[id].flag == SKILL_FLAG_PERMANENT )
+				sd->status.skill[id].flag = SKILL_FLAG_REPLACED_LV_0 + sd->status.skill[id].lv; // Store previous level.
 		} else {
 			sd->status.skill[id].id   = id;
-			sd->status.skill[id].flag = 1; //Set that this is a bonus skill.
+			sd->status.skill[id].flag = SKILL_FLAG_TEMPORARY; //Set that this is a bonus skill.
 		}
 		sd->status.skill[id].lv += level;
 	break;
@@ -4789,7 +4795,8 @@ const char* job_name(int class_)
 		
 	case JOB_WEDDING:
 	case JOB_SUPER_NOVICE:
-
+	case JOB_GUNSLINGER:
+	case JOB_NINJA:
 	case JOB_XMAS:
 		return msg_txt(570 - JOB_WEDDING+class_);
 
@@ -4870,11 +4877,6 @@ const char* job_name(int class_)
 		return msg_txt(617);
 	case JOB_SOUL_LINKER:
 		return msg_txt(618);
-		
-	case JOB_GUNSLINGER:
-		return msg_txt(619);
-	case JOB_NINJA:
-		return msg_txt(620);
 
 	case JOB_RUNE_KNIGHT:
 	case JOB_WARLOCK:
@@ -4958,7 +4960,7 @@ const char* job_name(int class_)
 	}
 }
 
-int pc_follow_timer(int tid, unsigned int tick, int id, intptr data)
+int pc_follow_timer(int tid, unsigned int tick, int id, intptr_t data)
 {
 	struct map_session_data *sd;
 	struct block_list *tbl;
@@ -5507,7 +5509,7 @@ int pc_skillup(struct map_session_data *sd,int skill_num)
 
 	if( sd->status.skill_point > 0 &&
 		sd->status.skill[skill_num].id &&
-		sd->status.skill[skill_num].flag == 0 && //Don't allow raising while you have granted skills. [Skotlex]
+		sd->status.skill[skill_num].flag == SKILL_FLAG_PERMANENT && //Don't allow raising while you have granted skills. [Skotlex]
 		sd->status.skill[skill_num].lv < skill_tree_get_max(skill_num, sd->status.class_) )
 	{
 		sd->status.skill[skill_num].lv++;
@@ -5537,11 +5539,11 @@ int pc_allskillup(struct map_session_data *sd)
 	nullpo_ret(sd);
 
 	for(i=0;i<MAX_SKILL;i++){
-		if (sd->status.skill[i].flag && sd->status.skill[i].flag != 13){
-			sd->status.skill[i].lv=(sd->status.skill[i].flag==1)?0:sd->status.skill[i].flag-2;
-			sd->status.skill[i].flag=0;
-			if (!sd->status.skill[i].lv)
-				sd->status.skill[i].id=0;
+		if (sd->status.skill[i].flag != SKILL_FLAG_PERMANENT && sd->status.skill[i].flag != SKILL_FLAG_PLAGIARIZED) {
+			sd->status.skill[i].lv = (sd->status.skill[i].flag == SKILL_FLAG_TEMPORARY) ? 0 : sd->status.skill[i].flag - SKILL_FLAG_REPLACED_LV_0;
+			sd->status.skill[i].flag = SKILL_FLAG_PERMANENT;
+			if (sd->status.skill[i].lv == 0)
+				sd->status.skill[i].id = 0;
 		}
 	}
 
@@ -5771,7 +5773,7 @@ int pc_resetskill(struct map_session_data* sd, int flag)
 		if( i == NV_BASIC && (sd->class_&MAPID_UPPERMASK) != MAPID_NOVICE && (sd->class_&MAPID_UPPERMASK) != MAPID_BABY )
 		{ // Official server does not include Basic Skill to be resetted. [Jobbie]
 			sd->status.skill[i].lv = 9;
-			sd->status.skill[i].flag = 0;
+			sd->status.skill[i].flag = SKILL_FLAG_PERMANENT;
 			continue;
 		}
 
@@ -5784,13 +5786,14 @@ int pc_resetskill(struct map_session_data* sd, int flag)
 			}
 			continue;
 		}
-		if( !sd->status.skill[i].flag )
+		if( sd->status.skill[i].flag == SKILL_FLAG_PERMANENT )
 			skill_point += lv;
-		else if( sd->status.skill[i].flag > 2 && sd->status.skill[i].flag != 13 )
-			skill_point += (sd->status.skill[i].flag - 2);
+		else
+		if( sd->status.skill[i].flag >= SKILL_FLAG_REPLACED_LV_0 )
+			skill_point += (sd->status.skill[i].flag - SKILL_FLAG_REPLACED_LV_0);
 
 		if( !(flag&2) )
-		{
+		{// reset
 			sd->status.skill[i].lv = 0;
 			sd->status.skill[i].flag = 0;
 		}
@@ -5896,7 +5899,7 @@ void pc_respawn(struct map_session_data* sd, clr_type clrtype)
 		clif_resurrection(&sd->bl, 1); //If warping fails, send a normal stand up packet.
 }
 
-static int pc_respawn_timer(int tid, unsigned int tick, int id, intptr data)
+static int pc_respawn_timer(int tid, unsigned int tick, int id, intptr_t data)
 {
 	struct map_session_data *sd = map_id2sd(id);
 	if( sd != NULL )
@@ -6602,6 +6605,12 @@ int pc_jobchange(struct map_session_data *sd,int job, int upper)
 	}
 
 	if(sd->cloneskill_id) {
+		if( sd->status.skill[sd->cloneskill_id].flag == SKILL_FLAG_PLAGIARIZED ) {
+			sd->status.skill[sd->cloneskill_id].id = 0;
+			sd->status.skill[sd->cloneskill_id].lv = 0;
+			sd->status.skill[sd->cloneskill_id].flag = 0;
+			clif_deleteskill(sd,sd->cloneskill_id);
+		}
 		sd->cloneskill_id = 0;
 		pc_setglobalreg(sd, "CLONE_SKILL", 0);
 		pc_setglobalreg(sd, "CLONE_SKILL_LV", 0);
@@ -7261,7 +7270,7 @@ int pc_setregistry_str(struct map_session_data *sd,const char *reg,const char *v
 /*==========================================
  * イベントタイマ??理
  *------------------------------------------*/
-static int pc_eventtimer(int tid, unsigned int tick, int id, intptr data)
+static int pc_eventtimer(int tid, unsigned int tick, int id, intptr_t data)
 {
 	struct map_session_data *sd=map_id2sd(id);
 	char *p = (char *)data;
@@ -7295,7 +7304,7 @@ int pc_addeventtimer(struct map_session_data *sd,int tick,const char *name)
 	if( i == MAX_EVENTTIMER )
 		return 0;
 
-	sd->eventtimer[i] = add_timer(gettick()+tick, pc_eventtimer, sd->bl.id, (intptr)aStrdup(name));
+	sd->eventtimer[i] = add_timer(gettick()+tick, pc_eventtimer, sd->bl.id, (intptr_t)aStrdup(name));
 	sd->eventcount++;
 
 	return 1;
@@ -7761,7 +7770,7 @@ int pc_calc_pvprank(struct map_session_data *sd)
 /*==========================================
  * PVP順位計算(timer)
  *------------------------------------------*/
-int pc_calc_pvprank_timer(int tid, unsigned int tick, int id, intptr data)
+int pc_calc_pvprank_timer(int tid, unsigned int tick, int id, intptr_t data)
 {
 	struct map_session_data *sd=NULL;
 
@@ -7960,7 +7969,7 @@ int pc_setsavepoint(struct map_session_data *sd, short mapindex,int x,int y)
 /*==========================================
  * 自動セ?ブ (timer??)
  *------------------------------------------*/
-int pc_autosave(int tid, unsigned int tick, int id, intptr data)
+int pc_autosave(int tid, unsigned int tick, int id, intptr_t data)
 {
 	int interval;
 	struct s_mapiterator* iter;
@@ -8014,7 +8023,7 @@ static int pc_daynight_timer_sub(struct map_session_data *sd,va_list ap)
  * timer to do the day [Yor]
  * data: 0 = called by timer, 1 = gmcommand/script
  *------------------------------------------------*/
-int map_day_timer(int tid, unsigned int tick, int id, intptr data)
+int map_day_timer(int tid, unsigned int tick, int id, intptr_t data)
 {
 	char tmp_soutput[1024];
 
@@ -8035,7 +8044,7 @@ int map_day_timer(int tid, unsigned int tick, int id, intptr data)
  * timer to do the night [Yor]
  * data: 0 = called by timer, 1 = gmcommand/script
  *------------------------------------------------*/
-int map_night_timer(int tid, unsigned int tick, int id, intptr data)
+int map_night_timer(int tid, unsigned int tick, int id, intptr_t data)
 {
 	char tmp_soutput[1024];
 

+ 6 - 6
src/map/pc.h

@@ -582,8 +582,8 @@ int pc_calc_skilltree(struct map_session_data *sd);
 int pc_calc_skilltree_normalize_job(struct map_session_data *sd);
 int pc_clean_skilltree(struct map_session_data *sd);
 
-#define pc_checkoverhp(sd) (sd->battle_status.hp == sd->battle_status.max_hp)
-#define pc_checkoversp(sd) (sd->battle_status.sp == sd->battle_status.max_sp)
+#define pc_checkoverhp(sd) ((sd)->battle_status.hp == (sd)->battle_status.max_hp)
+#define pc_checkoversp(sd) ((sd)->battle_status.sp == (sd)->battle_status.max_sp)
 
 int pc_setpos(struct map_session_data* sd, unsigned short mapindex, int x, int y, clr_type clrtype);
 int pc_setsavepoint(struct map_session_data*,short,int,int);
@@ -621,7 +621,7 @@ int pc_updateweightstatus(struct map_session_data *sd);
 
 int pc_addautobonus(struct s_autobonus *bonus,char max,const char *script,short rate,unsigned int dur,short atk_type,const char *o_script,unsigned short pos,bool onskill);
 int pc_exeautobonus(struct map_session_data* sd,struct s_autobonus *bonus);
-int pc_endautobonus(int tid, unsigned int tick, int id, intptr data);
+int pc_endautobonus(int tid, unsigned int tick, int id, intptr_t data);
 int pc_delautobonus(struct map_session_data* sd,struct s_autobonus *bonus,char max,bool restore);
 
 int pc_bonus(struct map_session_data*,int,int);
@@ -715,7 +715,7 @@ int pc_cleareventtimer(struct map_session_data *sd);
 int pc_addeventtimercount(struct map_session_data *sd,const char *name,int tick);
 
 int pc_calc_pvprank(struct map_session_data *sd);
-int pc_calc_pvprank_timer(int tid, unsigned int tick, int id, intptr data);
+int pc_calc_pvprank_timer(int tid, unsigned int tick, int id, intptr_t data);
 
 int pc_ismarried(struct map_session_data *sd);
 int pc_marriage(struct map_session_data *sd,struct map_session_data *dstsd);
@@ -779,8 +779,8 @@ enum {ADDITEM_EXIST,ADDITEM_NEW,ADDITEM_OVERAMOUNT};
 // timer for night.day
 extern int day_timer_tid;
 extern int night_timer_tid;
-int map_day_timer(int tid, unsigned int tick, int id, intptr data); // by [yor]
-int map_night_timer(int tid, unsigned int tick, int id, intptr data); // by [yor]
+int map_day_timer(int tid, unsigned int tick, int id, intptr_t data); // by [yor]
+int map_night_timer(int tid, unsigned int tick, int id, intptr_t data); // by [yor]
 
 // Rental System
 void pc_inventory_rentals(struct map_session_data *sd);

+ 9 - 8
src/map/pet.c

@@ -189,7 +189,7 @@ int pet_sc_check(struct map_session_data *sd, int type)
 	return 0;
 }
 
-static int pet_hungry(int tid, unsigned int tick, int id, intptr data)
+static int pet_hungry(int tid, unsigned int tick, int id, intptr_t data)
 {
 	struct map_session_data *sd;
 	struct pet_data *pd;
@@ -858,6 +858,7 @@ static int pet_ai_sub_hard(struct pet_data *pd, struct map_session_data *sd, uns
 		if (pd->ud.walktimer != INVALID_TIMER)
 			return 0; //Wait until the pet finishes walking back to master.
 		pd->status.speed = pd->petDB->speed;
+		pd->ud.state.change_walk_target = pd->ud.state.speed_changed = 1;
 	}
 	
 	if (pd->target_id) {
@@ -934,7 +935,7 @@ static int pet_ai_sub_foreachclient(struct map_session_data *sd,va_list ap)
 	return 0;
 }
 
-static int pet_ai_hard(int tid, unsigned int tick, int id, intptr data)
+static int pet_ai_hard(int tid, unsigned int tick, int id, intptr_t data)
 {
 	map_foreachpc(pet_ai_sub_foreachclient,tick);
 
@@ -968,7 +969,7 @@ static int pet_ai_sub_hard_lootsearch(struct block_list *bl,va_list ap)
 	return 0;
 }
 
-static int pet_delay_item_drop(int tid, unsigned int tick, int id, intptr data)
+static int pet_delay_item_drop(int tid, unsigned int tick, int id, intptr_t data)
 {
 	struct item_drop_list *list;
 	struct item_drop *ditem, *ditem_prev;
@@ -1029,7 +1030,7 @@ int pet_lootitem_drop(struct pet_data *pd,struct map_session_data *sd)
 	pd->ud.canact_tick = gettick()+10000;	//	10*1000ms‚ÌŠÔ�E‚í‚È‚¢
 
 	if (dlist->item)
-		add_timer(gettick()+540,pet_delay_item_drop,0,(intptr)dlist);
+		add_timer(gettick()+540,pet_delay_item_drop,0,(intptr_t)dlist);
 	else
 		ers_free(item_drop_list_ers, dlist);
 	return 1;
@@ -1038,7 +1039,7 @@ int pet_lootitem_drop(struct pet_data *pd,struct map_session_data *sd)
 /*==========================================
  * pet bonus giving skills [Valaris] / Rewritten by [Skotlex]
  *------------------------------------------*/ 
-int pet_skill_bonus_timer(int tid, unsigned int tick, int id, intptr data)
+int pet_skill_bonus_timer(int tid, unsigned int tick, int id, intptr_t data)
 {
 	struct map_session_data *sd=map_id2sd(id);
 	struct pet_data *pd;
@@ -1080,7 +1081,7 @@ int pet_skill_bonus_timer(int tid, unsigned int tick, int id, intptr data)
 /*==========================================
  * pet recovery skills [Valaris] / Rewritten by [Skotlex]
  *------------------------------------------*/ 
-int pet_recovery_timer(int tid, unsigned int tick, int id, intptr data)
+int pet_recovery_timer(int tid, unsigned int tick, int id, intptr_t data)
 {
 	struct map_session_data *sd=map_id2sd(id);
 	struct pet_data *pd;
@@ -1108,7 +1109,7 @@ int pet_recovery_timer(int tid, unsigned int tick, int id, intptr data)
 	return 0;
 }
 
-int pet_heal_timer(int tid, unsigned int tick, int id, intptr data)
+int pet_heal_timer(int tid, unsigned int tick, int id, intptr_t data)
 {
 	struct map_session_data *sd=map_id2sd(id);
 	struct status_data *status;
@@ -1146,7 +1147,7 @@ int pet_heal_timer(int tid, unsigned int tick, int id, intptr data)
 /*==========================================
  * pet support skills [Skotlex]
  *------------------------------------------*/ 
-int pet_skill_support_timer(int tid, unsigned int tick, int id, intptr data)
+int pet_skill_support_timer(int tid, unsigned int tick, int id, intptr_t data)
 {
 	struct map_session_data *sd=map_id2sd(id);
 	struct pet_data *pd;

Vissa filer visades inte eftersom för många filer har ändrats